summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
Diffstat (limited to 'vcl')
-rw-r--r--vcl/aqua/inc/aqua11yfactory.h47
-rw-r--r--vcl/aqua/inc/aqua11yfocustracker.hxx108
-rw-r--r--vcl/aqua/inc/aqua11ylistener.hxx65
-rw-r--r--vcl/aqua/inc/aqua11ywrapper.h119
-rwxr-xr-xvcl/aqua/inc/aquaprintview.h67
-rw-r--r--vcl/aqua/inc/aquavclevents.hxx96
-rw-r--r--vcl/aqua/inc/aquavcltypes.h36
-rw-r--r--vcl/aqua/inc/keyboardfocuslistener.hxx47
-rw-r--r--vcl/aqua/inc/salatsuifontutils.hxx63
-rw-r--r--vcl/aqua/inc/salbmp.h107
-rwxr-xr-xvcl/aqua/inc/salcolorutils.hxx52
-rwxr-xr-xvcl/aqua/inc/salconst.h68
-rw-r--r--vcl/aqua/inc/saldata.hxx138
-rw-r--r--vcl/aqua/inc/salfontutils.hxx66
-rw-r--r--vcl/aqua/inc/salframe.h220
-rwxr-xr-xvcl/aqua/inc/salframeview.h208
-rw-r--r--vcl/aqua/inc/salgdi.h417
-rw-r--r--vcl/aqua/inc/salinst.h202
-rwxr-xr-xvcl/aqua/inc/salmathutils.hxx87
-rw-r--r--vcl/aqua/inc/salmenu.h121
-rwxr-xr-xvcl/aqua/inc/salnativewidgets.h71
-rwxr-xr-xvcl/aqua/inc/salnsmenu.h68
-rwxr-xr-xvcl/aqua/inc/salnstimer.h40
-rw-r--r--vcl/aqua/inc/salobj.h86
-rw-r--r--vcl/aqua/inc/salprn.h171
-rw-r--r--vcl/aqua/inc/salsys.h70
-rw-r--r--vcl/aqua/inc/saltimer.h54
-rw-r--r--vcl/aqua/inc/salvd.h94
-rw-r--r--vcl/aqua/inc/svsys.h35
-rwxr-xr-xvcl/aqua/inc/vclnsapp.h70
-rw-r--r--vcl/aqua/source/a11y/aqua11yactionwrapper.h41
-rw-r--r--vcl/aqua/source/a11y/aqua11yactionwrapper.mm83
-rw-r--r--vcl/aqua/source/a11y/aqua11ycomponentwrapper.h45
-rw-r--r--vcl/aqua/source/a11y/aqua11ycomponentwrapper.mm110
-rw-r--r--vcl/aqua/source/a11y/aqua11yfactory.mm198
-rw-r--r--vcl/aqua/source/a11y/aqua11yfocuslistener.cxx118
-rw-r--r--vcl/aqua/source/a11y/aqua11yfocuslistener.hxx62
-rw-r--r--vcl/aqua/source/a11y/aqua11yfocustracker.cxx278
-rw-r--r--vcl/aqua/source/a11y/aqua11ylistener.cxx158
-rw-r--r--vcl/aqua/source/a11y/aqua11yrolehelper.h42
-rw-r--r--vcl/aqua/source/a11y/aqua11yrolehelper.mm272
-rw-r--r--vcl/aqua/source/a11y/aqua11yselectionwrapper.h43
-rw-r--r--vcl/aqua/source/a11y/aqua11yselectionwrapper.mm91
-rw-r--r--vcl/aqua/source/a11y/aqua11ytablewrapper.h44
-rw-r--r--vcl/aqua/source/a11y/aqua11ytablewrapper.mm211
-rw-r--r--vcl/aqua/source/a11y/aqua11ytextattributeswrapper.h39
-rw-r--r--vcl/aqua/source/a11y/aqua11ytextattributeswrapper.mm254
-rw-r--r--vcl/aqua/source/a11y/aqua11ytextwrapper.h64
-rw-r--r--vcl/aqua/source/a11y/aqua11ytextwrapper.mm289
-rw-r--r--vcl/aqua/source/a11y/aqua11yutil.h39
-rw-r--r--vcl/aqua/source/a11y/aqua11yutil.mm53
-rw-r--r--vcl/aqua/source/a11y/aqua11yvaluewrapper.h46
-rw-r--r--vcl/aqua/source/a11y/aqua11yvaluewrapper.mm95
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapper.mm1142
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperbutton.h41
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperbutton.mm61
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrappercheckbox.h41
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrappercheckbox.mm65
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrappercombobox.h50
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrappercombobox.mm161
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrappergroup.h40
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrappergroup.mm57
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperlist.h39
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperlist.mm48
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperradiobutton.h41
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperradiobutton.mm65
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperradiogroup.h39
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperradiogroup.mm48
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperrow.h40
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperrow.mm56
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperscrollarea.h41
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperscrollarea.mm84
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperscrollbar.h39
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperscrollbar.mm49
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrappersplitter.h39
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrappersplitter.mm48
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperstatictext.h40
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrapperstatictext.mm56
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrappertabgroup.h39
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrappertabgroup.mm50
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrappertextarea.h39
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrappertextarea.mm48
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrappertoolbar.h39
-rw-r--r--vcl/aqua/source/a11y/aqua11ywrappertoolbar.mm50
-rw-r--r--vcl/aqua/source/a11y/documentfocuslistener.cxx253
-rw-r--r--vcl/aqua/source/a11y/documentfocuslistener.hxx101
-rw-r--r--vcl/aqua/source/a11y/makefile.mk88
-rw-r--r--vcl/aqua/source/a11y/readme.txt8
-rw-r--r--vcl/aqua/source/app/makefile.mk63
-rw-r--r--vcl/aqua/source/app/saldata.cxx293
-rw-r--r--vcl/aqua/source/app/salinst.cxx1313
-rwxr-xr-xvcl/aqua/source/app/salnstimer.mm56
-rw-r--r--vcl/aqua/source/app/salsys.cxx131
-rw-r--r--vcl/aqua/source/app/saltimer.cxx135
-rwxr-xr-xvcl/aqua/source/app/vclnsapp.mm518
-rw-r--r--vcl/aqua/source/dtrans/DataFlavorMapping.cxx732
-rw-r--r--vcl/aqua/source/dtrans/DataFlavorMapping.hxx143
-rw-r--r--vcl/aqua/source/dtrans/DragActionConversion.cxx92
-rw-r--r--vcl/aqua/source/dtrans/DragActionConversion.hxx46
-rw-r--r--vcl/aqua/source/dtrans/DragSource.cxx363
-rw-r--r--vcl/aqua/source/dtrans/DragSource.hxx140
-rw-r--r--vcl/aqua/source/dtrans/DragSourceContext.cxx74
-rw-r--r--vcl/aqua/source/dtrans/DragSourceContext.hxx72
-rw-r--r--vcl/aqua/source/dtrans/DropTarget.cxx599
-rw-r--r--vcl/aqua/source/dtrans/DropTarget.hxx169
-rw-r--r--vcl/aqua/source/dtrans/HtmlFmtFlt.cxx147
-rw-r--r--vcl/aqua/source/dtrans/HtmlFmtFlt.hxx20
-rw-r--r--vcl/aqua/source/dtrans/OSXTransferable.cxx215
-rw-r--r--vcl/aqua/source/dtrans/OSXTransferable.hxx100
-rw-r--r--vcl/aqua/source/dtrans/PictToBmpFlt.cxx201
-rw-r--r--vcl/aqua/source/dtrans/PictToBmpFlt.hxx37
-rw-r--r--vcl/aqua/source/dtrans/aqua_clipboard.cxx387
-rw-r--r--vcl/aqua/source/dtrans/aqua_clipboard.hxx181
-rw-r--r--vcl/aqua/source/dtrans/aqua_service.cxx108
-rw-r--r--vcl/aqua/source/dtrans/makefile.mk68
-rw-r--r--vcl/aqua/source/dtrans/service_entry.cxx64
-rw-r--r--vcl/aqua/source/dtrans/test_aquacb.cxx208
-rw-r--r--vcl/aqua/source/gdi/aquaprintaccessoryview.mm1241
-rwxr-xr-xvcl/aqua/source/gdi/aquaprintview.mm82
-rw-r--r--vcl/aqua/source/gdi/makefile.mk74
-rwxr-xr-xvcl/aqua/source/gdi/salatslayout.cxx1264
-rw-r--r--vcl/aqua/source/gdi/salatsuifontutils.cxx552
-rw-r--r--vcl/aqua/source/gdi/salbmp.cxx904
-rwxr-xr-xvcl/aqua/source/gdi/salcolorutils.cxx50
-rw-r--r--vcl/aqua/source/gdi/salgdi.cxx2672
-rwxr-xr-xvcl/aqua/source/gdi/salgdiutils.cxx300
-rwxr-xr-xvcl/aqua/source/gdi/salmathutils.cxx163
-rw-r--r--vcl/aqua/source/gdi/salnativewidgets.cxx1525
-rw-r--r--vcl/aqua/source/gdi/salprn.cxx875
-rw-r--r--vcl/aqua/source/gdi/salvd.cxx236
-rw-r--r--vcl/aqua/source/res/MainMenu.nib/classes.nib4
-rw-r--r--vcl/aqua/source/res/MainMenu.nib/info.nib21
-rw-r--r--vcl/aqua/source/res/MainMenu.nib/keyedobjects.nibbin0 -> 3615 bytes
-rw-r--r--vcl/aqua/source/res/cursors/airbrush.pngbin0 -> 253 bytes
-rw-r--r--vcl/aqua/source/res/cursors/ase.pngbin0 -> 214 bytes
-rw-r--r--vcl/aqua/source/res/cursors/asn.pngbin0 -> 212 bytes
-rw-r--r--vcl/aqua/source/res/cursors/asne.pngbin0 -> 240 bytes
-rw-r--r--vcl/aqua/source/res/cursors/asns.pngbin0 -> 234 bytes
-rw-r--r--vcl/aqua/source/res/cursors/asnswe.pngbin0 -> 285 bytes
-rw-r--r--vcl/aqua/source/res/cursors/asnw.pngbin0 -> 246 bytes
-rw-r--r--vcl/aqua/source/res/cursors/ass.pngbin0 -> 222 bytes
-rw-r--r--vcl/aqua/source/res/cursors/asse.pngbin0 -> 243 bytes
-rw-r--r--vcl/aqua/source/res/cursors/assw.pngbin0 -> 236 bytes
-rw-r--r--vcl/aqua/source/res/cursors/asw.pngbin0 -> 212 bytes
-rw-r--r--vcl/aqua/source/res/cursors/aswe.pngbin0 -> 228 bytes
-rw-r--r--vcl/aqua/source/res/cursors/chain.pngbin0 -> 344 bytes
-rw-r--r--vcl/aqua/source/res/cursors/chainnot.pngbin0 -> 390 bytes
-rw-r--r--vcl/aqua/source/res/cursors/chart.pngbin0 -> 270 bytes
-rw-r--r--vcl/aqua/source/res/cursors/copydata.pngbin0 -> 336 bytes
-rw-r--r--vcl/aqua/source/res/cursors/copydlnk.pngbin0 -> 340 bytes
-rw-r--r--vcl/aqua/source/res/cursors/copyf.pngbin0 -> 329 bytes
-rw-r--r--vcl/aqua/source/res/cursors/copyf2.pngbin0 -> 344 bytes
-rw-r--r--vcl/aqua/source/res/cursors/copyflnk.pngbin0 -> 339 bytes
-rw-r--r--vcl/aqua/source/res/cursors/crook.pngbin0 -> 291 bytes
-rw-r--r--vcl/aqua/source/res/cursors/crop.pngbin0 -> 239 bytes
-rw-r--r--vcl/aqua/source/res/cursors/darc.pngbin0 -> 172 bytes
-rw-r--r--vcl/aqua/source/res/cursors/dbezier.pngbin0 -> 185 bytes
-rw-r--r--vcl/aqua/source/res/cursors/dcapt.pngbin0 -> 183 bytes
-rw-r--r--vcl/aqua/source/res/cursors/dcirccut.pngbin0 -> 185 bytes
-rw-r--r--vcl/aqua/source/res/cursors/dconnect.pngbin0 -> 183 bytes
-rw-r--r--vcl/aqua/source/res/cursors/dellipse.pngbin0 -> 176 bytes
-rw-r--r--vcl/aqua/source/res/cursors/detectiv.pngbin0 -> 268 bytes
-rw-r--r--vcl/aqua/source/res/cursors/dfree.pngbin0 -> 188 bytes
-rw-r--r--vcl/aqua/source/res/cursors/dline.pngbin0 -> 177 bytes
-rw-r--r--vcl/aqua/source/res/cursors/dpie.pngbin0 -> 183 bytes
-rw-r--r--vcl/aqua/source/res/cursors/dpolygon.pngbin0 -> 191 bytes
-rw-r--r--vcl/aqua/source/res/cursors/drect.pngbin0 -> 172 bytes
-rw-r--r--vcl/aqua/source/res/cursors/dtext.pngbin0 -> 174 bytes
-rw-r--r--vcl/aqua/source/res/cursors/fill.pngbin0 -> 255 bytes
-rw-r--r--vcl/aqua/source/res/cursors/help.pngbin0 -> 303 bytes
-rw-r--r--vcl/aqua/source/res/cursors/hourglass.pngbin0 -> 246 bytes
-rw-r--r--vcl/aqua/source/res/cursors/hshear.pngbin0 -> 223 bytes
-rw-r--r--vcl/aqua/source/res/cursors/linkdata.pngbin0 -> 348 bytes
-rw-r--r--vcl/aqua/source/res/cursors/linkf.pngbin0 -> 336 bytes
-rw-r--r--vcl/aqua/source/res/cursors/magnify.pngbin0 -> 282 bytes
-rw-r--r--vcl/aqua/source/res/cursors/mirror.pngbin0 -> 304 bytes
-rw-r--r--vcl/aqua/source/res/cursors/movebw.pngbin0 -> 320 bytes
-rw-r--r--vcl/aqua/source/res/cursors/movedata.pngbin0 -> 290 bytes
-rw-r--r--vcl/aqua/source/res/cursors/movedlnk.pngbin0 -> 318 bytes
-rw-r--r--vcl/aqua/source/res/cursors/movef.pngbin0 -> 294 bytes
-rw-r--r--vcl/aqua/source/res/cursors/movef2.pngbin0 -> 314 bytes
-rw-r--r--vcl/aqua/source/res/cursors/moveflnk.pngbin0 -> 307 bytes
-rw-r--r--vcl/aqua/source/res/cursors/movept.pngbin0 -> 275 bytes
-rw-r--r--vcl/aqua/source/res/cursors/neswsize.pngbin0 -> 312 bytes
-rw-r--r--vcl/aqua/source/res/cursors/notallow.pngbin0 -> 297 bytes
-rw-r--r--vcl/aqua/source/res/cursors/nullptr.pngbin0 -> 150 bytes
-rw-r--r--vcl/aqua/source/res/cursors/nwsesize.pngbin0 -> 313 bytes
-rw-r--r--vcl/aqua/source/res/cursors/pen.pngbin0 -> 351 bytes
-rw-r--r--vcl/aqua/source/res/cursors/pivotcol.pngbin0 -> 293 bytes
-rw-r--r--vcl/aqua/source/res/cursors/pivotdel.pngbin0 -> 264 bytes
-rw-r--r--vcl/aqua/source/res/cursors/pivotfld.pngbin0 -> 272 bytes
-rw-r--r--vcl/aqua/source/res/cursors/pivotrow.pngbin0 -> 295 bytes
-rw-r--r--vcl/aqua/source/res/cursors/pntbrsh.pngbin0 -> 268 bytes
-rw-r--r--vcl/aqua/source/res/cursors/rotate.pngbin0 -> 274 bytes
-rw-r--r--vcl/aqua/source/res/cursors/tblsele.pngbin0 -> 174 bytes
-rw-r--r--vcl/aqua/source/res/cursors/tblsels.pngbin0 -> 171 bytes
-rw-r--r--vcl/aqua/source/res/cursors/tblselse.pngbin0 -> 183 bytes
-rw-r--r--vcl/aqua/source/res/cursors/tblselsw.pngbin0 -> 183 bytes
-rw-r--r--vcl/aqua/source/res/cursors/tblselw.pngbin0 -> 174 bytes
-rw-r--r--vcl/aqua/source/res/cursors/timemove.pngbin0 -> 249 bytes
-rw-r--r--vcl/aqua/source/res/cursors/timesize.pngbin0 -> 241 bytes
-rw-r--r--vcl/aqua/source/res/cursors/vshear.pngbin0 -> 228 bytes
-rw-r--r--vcl/aqua/source/res/cursors/vtext.pngbin0 -> 162 bytes
-rw-r--r--vcl/aqua/source/res/delzip0
-rw-r--r--vcl/aqua/source/res/makefile.mk54
-rw-r--r--vcl/aqua/source/window/makefile.mk63
-rw-r--r--vcl/aqua/source/window/salframe.cxx1636
-rwxr-xr-xvcl/aqua/source/window/salframeview.mm1609
-rw-r--r--vcl/aqua/source/window/salmenu.cxx958
-rwxr-xr-xvcl/aqua/source/window/salnsmenu.mm213
-rw-r--r--vcl/aqua/source/window/salobj.cxx239
-rw-r--r--vcl/inc/cupsmgr.hxx108
-rw-r--r--vcl/inc/list.h99
-rw-r--r--vcl/inc/makefile.mk49
-rw-r--r--vcl/inc/pch/precompiled_vcl.cxx29
-rw-r--r--vcl/inc/pch/precompiled_vcl.hxx33
-rw-r--r--vcl/inc/sft.hxx630
-rw-r--r--vcl/inc/vcl/ImageListProvider.hxx54
-rwxr-xr-xvcl/inc/vcl/abstdlg.hxx93
-rw-r--r--vcl/inc/vcl/accel.h59
-rw-r--r--vcl/inc/vcl/accel.hxx128
-rw-r--r--vcl/inc/vcl/accmgr.hxx64
-rw-r--r--vcl/inc/vcl/alpha.hxx111
-rw-r--r--vcl/inc/vcl/animate.hxx254
-rw-r--r--vcl/inc/vcl/apptypes.hxx79
-rw-r--r--vcl/inc/vcl/arrange.hxx422
-rw-r--r--vcl/inc/vcl/bitmap.hxx854
-rw-r--r--vcl/inc/vcl/bitmapex.hxx400
-rw-r--r--vcl/inc/vcl/bmpacc.hxx545
-rw-r--r--vcl/inc/vcl/bmpfast.hxx51
-rw-r--r--vcl/inc/vcl/brdwin.hxx352
-rw-r--r--vcl/inc/vcl/btndlg.hxx117
-rw-r--r--vcl/inc/vcl/button.hxx564
-rw-r--r--vcl/inc/vcl/canvasbitmap.hxx129
-rw-r--r--vcl/inc/vcl/canvastools.hxx253
-rw-r--r--vcl/inc/vcl/cmdevt.h63
-rw-r--r--vcl/inc/vcl/cmdevt.hxx526
-rw-r--r--vcl/inc/vcl/combobox.h37
-rw-r--r--vcl/inc/vcl/combobox.hxx229
-rw-r--r--vcl/inc/vcl/configsettings.hxx73
-rw-r--r--vcl/inc/vcl/controldata.hxx62
-rw-r--r--vcl/inc/vcl/controllayout.hxx85
-rw-r--r--vcl/inc/vcl/ctrl.hxx201
-rw-r--r--vcl/inc/vcl/cursor.hxx119
-rw-r--r--vcl/inc/vcl/cvtgrf.hxx70
-rw-r--r--vcl/inc/vcl/cvtsvm.hxx117
-rw-r--r--vcl/inc/vcl/dbggui.hxx74
-rw-r--r--vcl/inc/vcl/decoview.hxx110
-rw-r--r--vcl/inc/vcl/dialog.hxx162
-rw-r--r--vcl/inc/vcl/dllapi.h40
-rw-r--r--vcl/inc/vcl/dndhelp.hxx126
-rw-r--r--vcl/inc/vcl/dockingarea.hxx65
-rw-r--r--vcl/inc/vcl/dockwin.hxx452
-rw-r--r--vcl/inc/vcl/edit.hxx260
-rw-r--r--vcl/inc/vcl/event.hxx479
-rw-r--r--vcl/inc/vcl/evntpost.hxx59
-rw-r--r--vcl/inc/vcl/extoutdevdata.hxx47
-rw-r--r--vcl/inc/vcl/field.hxx884
-rw-r--r--vcl/inc/vcl/fixbrd.hxx82
-rw-r--r--vcl/inc/vcl/fixed.hxx199
-rw-r--r--vcl/inc/vcl/fldunit.hxx33
-rw-r--r--vcl/inc/vcl/floatwin.hxx161
-rw-r--r--vcl/inc/vcl/fntstyle.hxx53
-rw-r--r--vcl/inc/vcl/font.hxx140
-rw-r--r--vcl/inc/vcl/fontcache.hxx99
-rw-r--r--vcl/inc/vcl/fontmanager.hxx745
-rw-r--r--vcl/inc/vcl/fontsubset.hxx97
-rw-r--r--vcl/inc/vcl/gdimtf.hxx249
-rw-r--r--vcl/inc/vcl/gfxlink.hxx188
-rw-r--r--vcl/inc/vcl/glyphcache.hxx381
-rw-r--r--vcl/inc/vcl/gradient.hxx132
-rw-r--r--vcl/inc/vcl/graph.h81
-rw-r--r--vcl/inc/vcl/graph.hxx222
-rw-r--r--vcl/inc/vcl/graphictools.hxx462
-rw-r--r--vcl/inc/vcl/graphite_adaptors.hxx152
-rw-r--r--vcl/inc/vcl/graphite_cache.hxx269
-rw-r--r--vcl/inc/vcl/graphite_features.hxx75
-rw-r--r--vcl/inc/vcl/graphite_layout.hxx175
-rw-r--r--vcl/inc/vcl/graphite_serverfont.hxx100
-rw-r--r--vcl/inc/vcl/group.hxx67
-rw-r--r--vcl/inc/vcl/hatch.hxx96
-rw-r--r--vcl/inc/vcl/help.hxx123
-rw-r--r--vcl/inc/vcl/helper.hxx65
-rw-r--r--vcl/inc/vcl/helpwin.hxx92
-rw-r--r--vcl/inc/vcl/i18nhelp.hxx97
-rw-r--r--vcl/inc/vcl/idlemgr.hxx60
-rw-r--r--vcl/inc/vcl/ilstbox.hxx641
-rw-r--r--vcl/inc/vcl/image.h182
-rw-r--r--vcl/inc/vcl/image.hxx178
-rw-r--r--vcl/inc/vcl/imagerepository.hxx70
-rw-r--r--vcl/inc/vcl/imgcons.hxx105
-rw-r--r--vcl/inc/vcl/imgctrl.hxx67
-rw-r--r--vcl/inc/vcl/impbmp.hxx108
-rw-r--r--vcl/inc/vcl/impbmpconv.hxx39
-rw-r--r--vcl/inc/vcl/impdel.hxx87
-rw-r--r--vcl/inc/vcl/impfont.hxx243
-rw-r--r--vcl/inc/vcl/impgraph.hxx176
-rw-r--r--vcl/inc/vcl/impimagetree.hxx96
-rw-r--r--vcl/inc/vcl/impoct.hxx176
-rw-r--r--vcl/inc/vcl/impprn.hxx140
-rw-r--r--vcl/inc/vcl/inputctx.hxx88
-rw-r--r--vcl/inc/vcl/introwin.hxx53
-rw-r--r--vcl/inc/vcl/javachild.hxx57
-rw-r--r--vcl/inc/vcl/jobdata.hxx85
-rw-r--r--vcl/inc/vcl/jobset.h79
-rw-r--r--vcl/inc/vcl/jobset.hxx83
-rw-r--r--vcl/inc/vcl/keycod.hxx157
-rw-r--r--vcl/inc/vcl/keycodes.hxx191
-rw-r--r--vcl/inc/vcl/lazydelete.hxx262
-rw-r--r--vcl/inc/vcl/lineinfo.hxx132
-rw-r--r--vcl/inc/vcl/longcurr.hxx162
-rw-r--r--vcl/inc/vcl/lstbox.h65
-rw-r--r--vcl/inc/vcl/lstbox.hxx266
-rw-r--r--vcl/inc/vcl/mapmod.hxx116
-rw-r--r--vcl/inc/vcl/mapunit.hxx33
-rw-r--r--vcl/inc/vcl/menu.hxx534
-rw-r--r--vcl/inc/vcl/menubtn.hxx98
-rw-r--r--vcl/inc/vcl/metaact.hxx1546
-rw-r--r--vcl/inc/vcl/metric.hxx163
-rw-r--r--vcl/inc/vcl/mnemonic.hxx88
-rw-r--r--vcl/inc/vcl/mnemonicengine.hxx158
-rw-r--r--vcl/inc/vcl/morebtn.hxx95
-rw-r--r--vcl/inc/vcl/msgbox.hxx190
-rw-r--r--vcl/inc/vcl/octree.hxx161
-rw-r--r--vcl/inc/vcl/oldprintadaptor.hxx52
-rw-r--r--vcl/inc/vcl/outdata.hxx49
-rw-r--r--vcl/inc/vcl/outdev.h264
-rw-r--r--vcl/inc/vcl/outdev.hxx1226
-rw-r--r--vcl/inc/vcl/outfont.hxx406
-rw-r--r--vcl/inc/vcl/pdfextoutdevdata.hxx518
-rw-r--r--vcl/inc/vcl/pdfwriter.hxx1298
-rw-r--r--vcl/inc/vcl/pngread.hxx70
-rw-r--r--vcl/inc/vcl/pngwrite.hxx67
-rw-r--r--vcl/inc/vcl/pointr.hxx59
-rw-r--r--vcl/inc/vcl/polyscan.hxx155
-rw-r--r--vcl/inc/vcl/popupmenuwindow.hxx47
-rw-r--r--vcl/inc/vcl/ppdparser.hxx343
-rw-r--r--vcl/inc/vcl/print.h81
-rw-r--r--vcl/inc/vcl/print.hxx679
-rw-r--r--vcl/inc/vcl/printergfx.hxx442
-rw-r--r--vcl/inc/vcl/printerinfomanager.hxx241
-rw-r--r--vcl/inc/vcl/printerjob.hxx149
-rw-r--r--vcl/inc/vcl/prndlg.hxx335
-rw-r--r--vcl/inc/vcl/prntypes.hxx95
-rw-r--r--vcl/inc/vcl/ptrstyle.hxx142
-rw-r--r--vcl/inc/vcl/regband.hxx150
-rw-r--r--vcl/inc/vcl/region.h134
-rw-r--r--vcl/inc/vcl/region.hxx155
-rw-r--r--vcl/inc/vcl/salatype.hxx47
-rw-r--r--vcl/inc/vcl/salbmp.hxx65
-rw-r--r--vcl/inc/vcl/salbtype.hxx900
-rw-r--r--vcl/inc/vcl/salctrlhandle.hxx48
-rw-r--r--vcl/inc/vcl/salctype.hxx80
-rw-r--r--vcl/inc/vcl/saldatabasic.hxx53
-rw-r--r--vcl/inc/vcl/salframe.hxx293
-rw-r--r--vcl/inc/vcl/salgdi.hxx494
-rw-r--r--vcl/inc/vcl/salgeom.hxx51
-rw-r--r--vcl/inc/vcl/salgtype.hxx90
-rw-r--r--vcl/inc/vcl/salimestatus.hxx45
-rw-r--r--vcl/inc/vcl/salinst.hxx216
-rwxr-xr-xvcl/inc/vcl/sallayout.hxx390
-rw-r--r--vcl/inc/vcl/salmenu.hxx101
-rw-r--r--vcl/inc/vcl/salnativewidgets.hxx447
-rw-r--r--vcl/inc/vcl/salobj.hxx90
-rw-r--r--vcl/inc/vcl/salprn.hxx137
-rw-r--r--vcl/inc/vcl/salptype.hxx60
-rw-r--r--vcl/inc/vcl/salsession.hxx117
-rw-r--r--vcl/inc/vcl/salsys.hxx146
-rw-r--r--vcl/inc/vcl/saltimer.hxx69
-rw-r--r--vcl/inc/vcl/salvd.hxx58
-rw-r--r--vcl/inc/vcl/salwtype.hxx346
-rw-r--r--vcl/inc/vcl/scrbar.hxx170
-rw-r--r--vcl/inc/vcl/seleng.hxx253
-rw-r--r--vcl/inc/vcl/settings.hxx1298
-rw-r--r--vcl/inc/vcl/slider.hxx132
-rwxr-xr-xvcl/inc/vcl/smartid.hxx87
-rw-r--r--vcl/inc/vcl/sndstyle.hxx46
-rw-r--r--vcl/inc/vcl/sound.hxx51
-rw-r--r--vcl/inc/vcl/spin.h51
-rw-r--r--vcl/inc/vcl/spin.hxx117
-rw-r--r--vcl/inc/vcl/spinfld.hxx115
-rw-r--r--vcl/inc/vcl/split.hxx126
-rw-r--r--vcl/inc/vcl/splitwin.hxx268
-rw-r--r--vcl/inc/vcl/status.hxx226
-rw-r--r--vcl/inc/vcl/stdtext.hxx53
-rw-r--r--vcl/inc/vcl/strhelper.hxx83
-rw-r--r--vcl/inc/vcl/subedit.hxx48
-rw-r--r--vcl/inc/vcl/sv.h33
-rw-r--r--vcl/inc/vcl/svapp.hxx517
-rw-r--r--vcl/inc/vcl/svcompat.hxx70
-rw-r--r--vcl/inc/vcl/svdata.hxx453
-rw-r--r--vcl/inc/vcl/svids.hrc261
-rw-r--r--vcl/inc/vcl/symbol.hxx81
-rw-r--r--vcl/inc/vcl/syschild.hxx67
-rw-r--r--vcl/inc/vcl/sysdata.hxx189
-rw-r--r--vcl/inc/vcl/syswin.hxx281
-rw-r--r--vcl/inc/vcl/tabctrl.hxx219
-rw-r--r--vcl/inc/vcl/tabdlg.hxx70
-rw-r--r--vcl/inc/vcl/tabpage.hxx62
-rw-r--r--vcl/inc/vcl/taskpanelist.hxx57
-rw-r--r--vcl/inc/vcl/textlayout.hxx136
-rw-r--r--vcl/inc/vcl/threadex.hxx288
-rw-r--r--vcl/inc/vcl/timer.hxx89
-rw-r--r--vcl/inc/vcl/toolbox.h182
-rw-r--r--vcl/inc/vcl/toolbox.hxx682
-rw-r--r--vcl/inc/vcl/unobrok.hxx39
-rw-r--r--vcl/inc/vcl/unohelp.hxx70
-rw-r--r--vcl/inc/vcl/unohelp2.hxx84
-rw-r--r--vcl/inc/vcl/unowrap.hxx91
-rw-r--r--vcl/inc/vcl/vclenum.hxx328
-rw-r--r--vcl/inc/vcl/vclevent.hxx301
-rw-r--r--vcl/inc/vcl/virdev.hxx129
-rw-r--r--vcl/inc/vcl/waitobj.hxx53
-rw-r--r--vcl/inc/vcl/wall.hxx143
-rw-r--r--vcl/inc/vcl/wall2.hxx60
-rw-r--r--vcl/inc/vcl/windata.hxx49
-rw-r--r--vcl/inc/vcl/window.h372
-rw-r--r--vcl/inc/vcl/window.hxx1109
-rw-r--r--vcl/inc/vcl/wintypes.hxx33
-rw-r--r--vcl/inc/vcl/wrkwin.hxx108
-rw-r--r--vcl/inc/vcl/xconnection.hxx70
-rw-r--r--vcl/os2/howto.txt13
-rw-r--r--vcl/os2/inc/salbmp.h109
-rw-r--r--vcl/os2/inc/saldata.hxx307
-rw-r--r--vcl/os2/inc/salframe.h166
-rw-r--r--vcl/os2/inc/salgdi.h373
-rw-r--r--vcl/os2/inc/salids.hrc109
-rw-r--r--vcl/os2/inc/salinst.h103
-rw-r--r--vcl/os2/inc/sallang.hxx70
-rw-r--r--vcl/os2/inc/sallayout.h69
-rw-r--r--vcl/os2/inc/salmenu.h65
-rw-r--r--vcl/os2/inc/salobj.h69
-rw-r--r--vcl/os2/inc/salprn.h146
-rw-r--r--vcl/os2/inc/salsound.h94
-rw-r--r--vcl/os2/inc/salsound.hxx84
-rw-r--r--vcl/os2/inc/salsys.h44
-rw-r--r--vcl/os2/inc/saltimer.h44
-rw-r--r--vcl/os2/inc/salvd.h65
-rw-r--r--vcl/os2/inc/svsys.h35
-rw-r--r--vcl/os2/inc/wingdi.h70
-rw-r--r--vcl/os2/inc/xwphook.h620
-rw-r--r--vcl/os2/source/app/makefile.mk59
-rw-r--r--vcl/os2/source/app/printf.c284
-rw-r--r--vcl/os2/source/app/salinfo.cxx182
-rw-r--r--vcl/os2/source/app/salinst.cxx863
-rw-r--r--vcl/os2/source/app/sallang.cxx117
-rw-r--r--vcl/os2/source/app/salshl.cxx123
-rw-r--r--vcl/os2/source/app/saltimer.cxx140
-rw-r--r--vcl/os2/source/gdi/makefile.mk56
-rw-r--r--vcl/os2/source/gdi/os2layout.cxx1056
-rw-r--r--vcl/os2/source/gdi/salbmp.cxx737
-rw-r--r--vcl/os2/source/gdi/salgdi.cxx1044
-rw-r--r--vcl/os2/source/gdi/salgdi2.cxx786
-rw-r--r--vcl/os2/source/gdi/salgdi3.cxx1769
-rw-r--r--vcl/os2/source/gdi/salprn.cxx1833
-rw-r--r--vcl/os2/source/gdi/salvd.cxx200
-rw-r--r--vcl/os2/source/src/airbrush.ptrbin0 -> 2106 bytes
-rwxr-xr-xvcl/os2/source/src/ase.ptrbin0 -> 1190 bytes
-rwxr-xr-xvcl/os2/source/src/asn.ptrbin0 -> 1190 bytes
-rwxr-xr-xvcl/os2/source/src/asne.ptrbin0 -> 1190 bytes
-rwxr-xr-xvcl/os2/source/src/asns.ptrbin0 -> 1190 bytes
-rwxr-xr-xvcl/os2/source/src/asnswe.ptrbin0 -> 1190 bytes
-rwxr-xr-xvcl/os2/source/src/asnw.ptrbin0 -> 1190 bytes
-rwxr-xr-xvcl/os2/source/src/ass.ptrbin0 -> 1190 bytes
-rwxr-xr-xvcl/os2/source/src/asse.ptrbin0 -> 1190 bytes
-rwxr-xr-xvcl/os2/source/src/assw.ptrbin0 -> 1190 bytes
-rwxr-xr-xvcl/os2/source/src/asw.ptrbin0 -> 1190 bytes
-rwxr-xr-xvcl/os2/source/src/aswe.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/chain.ptrbin0 -> 16 bytes
-rw-r--r--vcl/os2/source/src/chainnot.ptrbin0 -> 16 bytes
-rw-r--r--vcl/os2/source/src/chart.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/copydata.ptrbin0 -> 1191 bytes
-rw-r--r--vcl/os2/source/src/copydlnk.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/copyf.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/copyf2.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/copyflnk.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/crook.ptrbin0 -> 1191 bytes
-rw-r--r--vcl/os2/source/src/crop.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/cross.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/darc.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/data.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/dbezier.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/dcapt.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/dcirccut.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/dconnect.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/dellipse.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/detectiv.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/dfree.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/dline.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/dpie.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/dpolygon.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/drect.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/dtext.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/fill.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/hand.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/help.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/hshear.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/hsizebar.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/hsplit.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/linkdata.ptrbin0 -> 1191 bytes
-rw-r--r--vcl/os2/source/src/linkf.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/magnify.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/makefile.mk111
-rw-r--r--vcl/os2/source/src/mirror.ptrbin0 -> 1191 bytes
-rw-r--r--vcl/os2/source/src/move.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/movebw.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/movedata.ptrbin0 -> 1191 bytes
-rw-r--r--vcl/os2/source/src/movedlnk.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/movef.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/movef2.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/moveflnk.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/movept.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/nullptr.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/pen.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/pivotcol.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/pivotfld.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/pivotrow.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/pntbrsh.ptrbin0 -> 2106 bytes
-rw-r--r--vcl/os2/source/src/refhand.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/rotate.ptrbin0 -> 1191 bytes
-rw-r--r--vcl/os2/source/src/salsrc.rc108
-rw-r--r--vcl/os2/source/src/sd.icobin0 -> 3344 bytes
-rw-r--r--vcl/os2/source/src/sd2.icobin0 -> 5604 bytes
-rw-r--r--vcl/os2/source/src/tblsele.ptrbin0 -> 2106 bytes
-rw-r--r--vcl/os2/source/src/tblsels.ptrbin0 -> 2106 bytes
-rw-r--r--vcl/os2/source/src/tblselse.ptrbin0 -> 2106 bytes
-rw-r--r--vcl/os2/source/src/tblselsw.ptrbin0 -> 2106 bytes
-rw-r--r--vcl/os2/source/src/tblselw.ptrbin0 -> 2106 bytes
-rwxr-xr-xvcl/os2/source/src/timemove.ptrbin0 -> 1190 bytes
-rwxr-xr-xvcl/os2/source/src/timesize.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/vshear.ptrbin0 -> 1201 bytes
-rw-r--r--vcl/os2/source/src/vsizebar.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/vsplit.ptrbin0 -> 1190 bytes
-rw-r--r--vcl/os2/source/src/vtext.ptrbin0 -> 2106 bytes
-rw-r--r--vcl/os2/source/window/makefile53
-rw-r--r--vcl/os2/source/window/makefile.mk47
-rw-r--r--vcl/os2/source/window/salframe.cxx3774
-rw-r--r--vcl/os2/source/window/salmenu.cxx132
-rw-r--r--vcl/os2/source/window/salobj.cxx568
-rw-r--r--vcl/prj/build.lst50
-rw-r--r--vcl/prj/d.lst156
-rw-r--r--vcl/qa/complex/memCheck/CheckMemoryUsage.java340
-rw-r--r--vcl/qa/complex/memCheck/CheckMemoryUsage.props14
-rwxr-xr-xvcl/qa/complex/memCheck/makefile.mk89
-rw-r--r--vcl/qa/complex/persistent_window_states/DocumentHandle.java169
-rw-r--r--vcl/qa/complex/persistent_window_states/PersistentWindowTest.java393
-rw-r--r--vcl/qa/complex/persistent_window_states/PersistentWindowTest.props10
-rw-r--r--vcl/qa/complex/persistent_window_states/makefile.mk81
-rwxr-xr-xvcl/qa/testdocuments/CalcDoc.sxcbin0 -> 9547 bytes
-rwxr-xr-xvcl/qa/testdocuments/ImpressDoc.sxibin0 -> 35135 bytes
-rwxr-xr-xvcl/qa/testdocuments/WriterDoc.sxwbin0 -> 5754 bytes
-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.cxx2080
-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.cxx4510
-rw-r--r--vcl/source/control/combobox.cxx1584
-rw-r--r--vcl/source/control/ctrl.cxx587
-rw-r--r--vcl/source/control/edit.cxx3141
-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.cxx3234
-rw-r--r--vcl/source/control/imgctrl.cxx269
-rw-r--r--vcl/source/control/longcurr.cxx859
-rw-r--r--vcl/source/control/lstbox.cxx1639
-rw-r--r--vcl/source/control/makefile.mk79
-rw-r--r--vcl/source/control/menubtn.cxx242
-rw-r--r--vcl/source/control/morebtn.cxx280
-rw-r--r--vcl/source/control/scrbar.cxx1655
-rw-r--r--vcl/source/control/slider.cxx1093
-rw-r--r--vcl/source/control/spinbtn.cxx550
-rw-r--r--vcl/source/control/spinfld.cxx1098
-rw-r--r--vcl/source/control/tabctrl.cxx2361
-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.cxx3354
-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.cxx512
-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/imgcons.cxx574
-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.mk122
-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.cxx2278
-rw-r--r--vcl/source/gdi/outdev3.cxx8021
-rw-r--r--vcl/source/gdi/outdev4.cxx1421
-rw-r--r--vcl/source/gdi/outdev5.cxx313
-rw-r--r--vcl/source/gdi/outdev6.cxx1231
-rw-r--r--vcl/source/gdi/outdevnative.cxx290
-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.cxx12304
-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
-rw-r--r--vcl/source/gdi/print3.cxx1866
-rw-r--r--vcl/source/gdi/regband.cxx969
-rw-r--r--vcl/source/gdi/region.cxx2932
-rw-r--r--vcl/source/gdi/salgdilayout.cxx823
-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.cxx326
-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.cxx1487
-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.hxx130
-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.cxx2354
-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/dndevdis.hxx114
-rw-r--r--vcl/source/window/dndlcon.cxx567
-rw-r--r--vcl/source/window/dndlcon.hxx124
-rw-r--r--vcl/source/window/dockingarea.cxx248
-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.cxx2601
-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.cxx1795
-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.cxx6336
-rw-r--r--vcl/source/window/toolbox2.cxx2437
-rw-r--r--vcl/source/window/window.cxx9973
-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
-rw-r--r--vcl/test/canvasbitmaptest.cxx1046
-rwxr-xr-xvcl/test/dndtest.cxx447
-rw-r--r--vcl/test/makefile.mk78
-rw-r--r--vcl/unx/gtk/a11y/TODO49
-rw-r--r--vcl/unx/gtk/a11y/atkaction.cxx278
-rw-r--r--vcl/unx/gtk/a11y/atkbridge.cxx78
-rw-r--r--vcl/unx/gtk/a11y/atkcomponent.cxx382
-rw-r--r--vcl/unx/gtk/a11y/atkeditabletext.cxx202
-rw-r--r--vcl/unx/gtk/a11y/atkfactory.cxx183
-rw-r--r--vcl/unx/gtk/a11y/atkfactory.hxx41
-rw-r--r--vcl/unx/gtk/a11y/atkhypertext.cxx291
-rw-r--r--vcl/unx/gtk/a11y/atkimage.cxx138
-rw-r--r--vcl/unx/gtk/a11y/atklistener.cxx537
-rw-r--r--vcl/unx/gtk/a11y/atklistener.hxx79
-rw-r--r--vcl/unx/gtk/a11y/atkregistry.cxx71
-rw-r--r--vcl/unx/gtk/a11y/atkregistry.hxx40
-rw-r--r--vcl/unx/gtk/a11y/atkselection.cxx195
-rw-r--r--vcl/unx/gtk/a11y/atktable.cxx721
-rw-r--r--vcl/unx/gtk/a11y/atktext.cxx876
-rw-r--r--vcl/unx/gtk/a11y/atktextattributes.cxx1456
-rw-r--r--vcl/unx/gtk/a11y/atktextattributes.hxx54
-rw-r--r--vcl/unx/gtk/a11y/atkutil.cxx802
-rw-r--r--vcl/unx/gtk/a11y/atkutil.hxx37
-rw-r--r--vcl/unx/gtk/a11y/atkvalue.cxx147
-rw-r--r--vcl/unx/gtk/a11y/atkwindow.cxx331
-rw-r--r--vcl/unx/gtk/a11y/atkwindow.hxx38
-rw-r--r--vcl/unx/gtk/a11y/atkwrapper.cxx953
-rw-r--r--vcl/unx/gtk/a11y/atkwrapper.hxx125
-rw-r--r--vcl/unx/gtk/a11y/makefile.mk93
-rw-r--r--vcl/unx/gtk/app/gtkdata.cxx988
-rw-r--r--vcl/unx/gtk/app/gtkinst.cxx352
-rw-r--r--vcl/unx/gtk/app/gtksys.cxx96
-rw-r--r--vcl/unx/gtk/app/makefile.mk76
-rw-r--r--vcl/unx/gtk/gdi/makefile.mk67
-rw-r--r--vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx4129
-rw-r--r--vcl/unx/gtk/window/gtkframe.cxx3778
-rw-r--r--vcl/unx/gtk/window/gtkobject.cxx211
-rw-r--r--vcl/unx/gtk/window/makefile.mk79
-rw-r--r--vcl/unx/headless/makefile.mk66
-rw-r--r--vcl/unx/headless/svpbmp.cxx323
-rw-r--r--vcl/unx/headless/svpbmp.hxx66
-rw-r--r--vcl/unx/headless/svpdummies.cxx116
-rw-r--r--vcl/unx/headless/svpdummies.hxx94
-rw-r--r--vcl/unx/headless/svpelement.cxx291
-rw-r--r--vcl/unx/headless/svpelement.hxx46
-rw-r--r--vcl/unx/headless/svpframe.cxx449
-rw-r--r--vcl/unx/headless/svpframe.hxx126
-rw-r--r--vcl/unx/headless/svpgdi.cxx587
-rw-r--r--vcl/unx/headless/svpgdi.hxx173
-rw-r--r--vcl/unx/headless/svpinst.cxx537
-rw-r--r--vcl/unx/headless/svpinst.hxx200
-rw-r--r--vcl/unx/headless/svpprn.cxx1075
-rw-r--r--vcl/unx/headless/svpprn.hxx120
-rw-r--r--vcl/unx/headless/svppspgraphics.cxx1368
-rw-r--r--vcl/unx/headless/svppspgraphics.hxx193
-rw-r--r--vcl/unx/headless/svptext.cxx501
-rw-r--r--vcl/unx/headless/svpvd.cxx110
-rw-r--r--vcl/unx/headless/svpvd.hxx59
-rw-r--r--vcl/unx/inc/XIM.h137
-rw-r--r--vcl/unx/inc/Xproto.h49
-rw-r--r--vcl/unx/inc/cdeint.hxx44
-rw-r--r--vcl/unx/inc/dtint.hxx78
-rw-r--r--vcl/unx/inc/i18n_cb.hxx95
-rw-r--r--vcl/unx/inc/i18n_ic.hxx100
-rw-r--r--vcl/unx/inc/i18n_im.hxx69
-rw-r--r--vcl/unx/inc/i18n_keysym.hxx71
-rw-r--r--vcl/unx/inc/i18n_status.hxx125
-rw-r--r--vcl/unx/inc/i18n_xkb.hxx115
-rw-r--r--vcl/unx/inc/plugins/gtk/atkbridge.hxx36
-rw-r--r--vcl/unx/inc/plugins/gtk/gtkdata.hxx89
-rw-r--r--vcl/unx/inc/plugins/gtk/gtkframe.hxx403
-rw-r--r--vcl/unx/inc/plugins/gtk/gtkgdi.hxx187
-rw-r--r--vcl/unx/inc/plugins/gtk/gtkinst.hxx105
-rw-r--r--vcl/unx/inc/plugins/gtk/gtkobject.hxx69
-rw-r--r--vcl/unx/inc/plugins/kde/kdedata.hxx110
-rw-r--r--vcl/unx/inc/pspgraphics.h193
-rw-r--r--vcl/unx/inc/salbmp.h237
-rw-r--r--vcl/unx/inc/saldata.hxx132
-rw-r--r--vcl/unx/inc/saldisp.hxx567
-rw-r--r--vcl/unx/inc/salfont.h180
-rw-r--r--vcl/unx/inc/salframe.h286
-rw-r--r--vcl/unx/inc/salgdi.h405
-rw-r--r--vcl/unx/inc/salinst.h131
-rw-r--r--vcl/unx/inc/salmenu.h65
-rw-r--r--vcl/unx/inc/salobj.h103
-rw-r--r--vcl/unx/inc/salprn.h120
-rw-r--r--vcl/unx/inc/salstd.hxx77
-rw-r--r--vcl/unx/inc/salsys.h67
-rw-r--r--vcl/unx/inc/saltimer.h44
-rw-r--r--vcl/unx/inc/salunx.h128
-rw-r--r--vcl/unx/inc/salvd.h101
-rw-r--r--vcl/unx/inc/sm.hxx91
-rw-r--r--vcl/unx/inc/soicon.hxx37
-rw-r--r--vcl/unx/inc/strhelper.hxx41
-rw-r--r--vcl/unx/inc/svsys.h32
-rw-r--r--vcl/unx/inc/svunx.h35
-rw-r--r--vcl/unx/inc/wmadaptor.hxx350
-rw-r--r--vcl/unx/inc/xfont.hxx162
-rw-r--r--vcl/unx/kde/kdedata.cxx274
-rw-r--r--vcl/unx/kde/makefile.mk81
-rw-r--r--vcl/unx/kde/salnativewidgets-kde.cxx2116
-rw-r--r--vcl/unx/kde4/KDEData.cxx54
-rw-r--r--vcl/unx/kde4/KDEData.hxx42
-rw-r--r--vcl/unx/kde4/KDESalDisplay.cxx45
-rw-r--r--vcl/unx/kde4/KDESalDisplay.hxx37
-rw-r--r--vcl/unx/kde4/KDESalFrame.cxx405
-rw-r--r--vcl/unx/kde4/KDESalFrame.hxx58
-rw-r--r--vcl/unx/kde4/KDESalGraphics.cxx881
-rw-r--r--vcl/unx/kde4/KDESalGraphics.hxx113
-rw-r--r--vcl/unx/kde4/KDESalInstance.cxx35
-rw-r--r--vcl/unx/kde4/KDESalInstance.hxx41
-rw-r--r--vcl/unx/kde4/KDEXLib.cxx175
-rw-r--r--vcl/unx/kde4/KDEXLib.hxx48
-rw-r--r--vcl/unx/kde4/VCLKDEApplication.cxx52
-rw-r--r--vcl/unx/kde4/VCLKDEApplication.hxx53
-rw-r--r--vcl/unx/kde4/main.cxx93
-rw-r--r--vcl/unx/kde4/makefile.mk88
-rw-r--r--vcl/unx/source/app/i18n_cb.cxx664
-rw-r--r--vcl/unx/source/app/i18n_ic.cxx786
-rw-r--r--vcl/unx/source/app/i18n_im.cxx628
-rw-r--r--vcl/unx/source/app/i18n_keysym.cxx365
-rw-r--r--vcl/unx/source/app/i18n_status.cxx733
-rw-r--r--vcl/unx/source/app/i18n_wrp.cxx259
-rw-r--r--vcl/unx/source/app/i18n_xkb.cxx163
-rw-r--r--vcl/unx/source/app/keysymnames.cxx688
-rw-r--r--vcl/unx/source/app/makefile.mk110
-rw-r--r--vcl/unx/source/app/randrwrapper.cxx360
-rw-r--r--vcl/unx/source/app/saldata.cxx871
-rw-r--r--vcl/unx/source/app/saldisp.cxx3446
-rw-r--r--vcl/unx/source/app/salinst.cxx433
-rw-r--r--vcl/unx/source/app/salsys.cxx225
-rw-r--r--vcl/unx/source/app/saltimer.cxx96
-rw-r--r--vcl/unx/source/app/sm.cxx800
-rw-r--r--vcl/unx/source/app/soicon.cxx115
-rw-r--r--vcl/unx/source/app/wmadaptor.cxx2504
-rw-r--r--vcl/unx/source/desktopdetect/desktopdetector.cxx343
-rw-r--r--vcl/unx/source/desktopdetect/makefile.mk57
-rw-r--r--vcl/unx/source/dtrans/X11_clipboard.cxx293
-rw-r--r--vcl/unx/source/dtrans/X11_clipboard.hxx151
-rw-r--r--vcl/unx/source/dtrans/X11_dndcontext.cxx138
-rw-r--r--vcl/unx/source/dtrans/X11_dndcontext.hxx104
-rw-r--r--vcl/unx/source/dtrans/X11_droptarget.cxx228
-rw-r--r--vcl/unx/source/dtrans/X11_selection.cxx4129
-rw-r--r--vcl/unx/source/dtrans/X11_selection.hxx531
-rw-r--r--vcl/unx/source/dtrans/X11_service.cxx135
-rw-r--r--vcl/unx/source/dtrans/X11_transferable.cxx134
-rw-r--r--vcl/unx/source/dtrans/X11_transferable.hxx72
-rw-r--r--vcl/unx/source/dtrans/bmp.cxx739
-rw-r--r--vcl/unx/source/dtrans/bmp.hxx105
-rw-r--r--vcl/unx/source/dtrans/config.cxx148
-rw-r--r--vcl/unx/source/dtrans/copydata_curs.h42
-rw-r--r--vcl/unx/source/dtrans/copydata_mask.h42
-rw-r--r--vcl/unx/source/dtrans/linkdata_curs.h42
-rw-r--r--vcl/unx/source/dtrans/linkdata_mask.h42
-rw-r--r--vcl/unx/source/dtrans/makefile.mk68
-rw-r--r--vcl/unx/source/dtrans/movedata_curs.h42
-rw-r--r--vcl/unx/source/dtrans/movedata_mask.h42
-rw-r--r--vcl/unx/source/dtrans/nodrop_curs.h42
-rw-r--r--vcl/unx/source/dtrans/nodrop_mask.h42
-rw-r--r--vcl/unx/source/fontmanager/adobeenc.tab1087
-rwxr-xr-xvcl/unx/source/fontmanager/afm_hash.cpp245
-rwxr-xr-xvcl/unx/source/fontmanager/afm_keyword_list58
-rw-r--r--vcl/unx/source/fontmanager/fontcache.cxx811
-rw-r--r--vcl/unx/source/fontmanager/fontconfig.cxx1244
-rw-r--r--vcl/unx/source/fontmanager/fontmanager.cxx4099
-rw-r--r--vcl/unx/source/fontmanager/helper.cxx404
-rw-r--r--vcl/unx/source/fontmanager/makefile.mk72
-rw-r--r--vcl/unx/source/fontmanager/parseAFM.cxx1577
-rw-r--r--vcl/unx/source/fontmanager/parseAFM.hxx334
-rw-r--r--vcl/unx/source/gdi/cdeint.cxx241
-rw-r--r--vcl/unx/source/gdi/dtint.cxx139
-rw-r--r--vcl/unx/source/gdi/dtsetenum.hxx146
-rw-r--r--vcl/unx/source/gdi/gcach_xpeer.cxx682
-rw-r--r--vcl/unx/source/gdi/gcach_xpeer.hxx94
-rw-r--r--vcl/unx/source/gdi/makefile.mk111
-rw-r--r--vcl/unx/source/gdi/pspgraphics.cxx1500
-rw-r--r--vcl/unx/source/gdi/salbmp.cxx1093
-rw-r--r--vcl/unx/source/gdi/salcvt.cxx341
-rw-r--r--vcl/unx/source/gdi/salcvt.hxx92
-rw-r--r--vcl/unx/source/gdi/salgdi.cxx1285
-rw-r--r--vcl/unx/source/gdi/salgdi2.cxx1149
-rw-r--r--vcl/unx/source/gdi/salgdi3.cxx2264
-rw-r--r--vcl/unx/source/gdi/salprnpsp.cxx1167
-rw-r--r--vcl/unx/source/gdi/salvd.cxx272
-rw-r--r--vcl/unx/source/gdi/xfont.cxx780
-rw-r--r--vcl/unx/source/gdi/xlfd_attr.cxx686
-rw-r--r--vcl/unx/source/gdi/xlfd_attr.hxx228
-rw-r--r--vcl/unx/source/gdi/xlfd_extd.cxx1001
-rw-r--r--vcl/unx/source/gdi/xlfd_extd.hxx272
-rw-r--r--vcl/unx/source/gdi/xlfd_smpl.cxx268
-rw-r--r--vcl/unx/source/gdi/xlfd_smpl.hxx92
-rw-r--r--vcl/unx/source/gdi/xrender_peer.cxx246
-rw-r--r--vcl/unx/source/gdi/xrender_peer.hxx387
-rw-r--r--vcl/unx/source/inc/airbrush_curs.h40
-rw-r--r--vcl/unx/source/inc/airbrush_mask.h40
-rw-r--r--vcl/unx/source/inc/ase_curs.h40
-rw-r--r--vcl/unx/source/inc/ase_mask.h40
-rw-r--r--vcl/unx/source/inc/asn_curs.h40
-rw-r--r--vcl/unx/source/inc/asn_mask.h40
-rw-r--r--vcl/unx/source/inc/asne_curs.h40
-rw-r--r--vcl/unx/source/inc/asne_mask.h40
-rw-r--r--vcl/unx/source/inc/asns_curs.h40
-rw-r--r--vcl/unx/source/inc/asns_mask.h40
-rw-r--r--vcl/unx/source/inc/asnswe_curs.h40
-rw-r--r--vcl/unx/source/inc/asnswe_mask.h40
-rw-r--r--vcl/unx/source/inc/asnw_curs.h40
-rw-r--r--vcl/unx/source/inc/asnw_mask.h40
-rw-r--r--vcl/unx/source/inc/ass_curs.h40
-rw-r--r--vcl/unx/source/inc/ass_mask.h40
-rw-r--r--vcl/unx/source/inc/asse_curs.h40
-rw-r--r--vcl/unx/source/inc/asse_mask.h40
-rw-r--r--vcl/unx/source/inc/assw_curs.h40
-rw-r--r--vcl/unx/source/inc/assw_mask.h40
-rw-r--r--vcl/unx/source/inc/asw_curs.h40
-rw-r--r--vcl/unx/source/inc/asw_mask.h40
-rw-r--r--vcl/unx/source/inc/aswe_curs.h40
-rw-r--r--vcl/unx/source/inc/aswe_mask.h40
-rw-r--r--vcl/unx/source/inc/chain_curs.h40
-rw-r--r--vcl/unx/source/inc/chain_mask.h38
-rw-r--r--vcl/unx/source/inc/chainnot_curs.h40
-rw-r--r--vcl/unx/source/inc/chainnot_mask.h38
-rw-r--r--vcl/unx/source/inc/chart_curs.h40
-rw-r--r--vcl/unx/source/inc/chart_mask.h40
-rw-r--r--vcl/unx/source/inc/copydata_curs.h42
-rw-r--r--vcl/unx/source/inc/copydata_mask.h42
-rw-r--r--vcl/unx/source/inc/copydlnk_curs.h42
-rw-r--r--vcl/unx/source/inc/copydlnk_mask.h42
-rw-r--r--vcl/unx/source/inc/copyfile_curs.h42
-rw-r--r--vcl/unx/source/inc/copyfile_mask.h42
-rw-r--r--vcl/unx/source/inc/copyfiles_curs.h42
-rw-r--r--vcl/unx/source/inc/copyfiles_mask.h42
-rw-r--r--vcl/unx/source/inc/copyflnk_curs.h42
-rw-r--r--vcl/unx/source/inc/copyflnk_mask.h42
-rw-r--r--vcl/unx/source/inc/crook_curs.h42
-rw-r--r--vcl/unx/source/inc/crook_mask.h40
-rw-r--r--vcl/unx/source/inc/crop_curs.h42
-rw-r--r--vcl/unx/source/inc/crop_mask.h40
-rw-r--r--vcl/unx/source/inc/detective_curs.h40
-rw-r--r--vcl/unx/source/inc/detective_mask.h40
-rw-r--r--vcl/unx/source/inc/drawarc_curs.h42
-rw-r--r--vcl/unx/source/inc/drawarc_mask.h40
-rw-r--r--vcl/unx/source/inc/drawbezier_curs.h42
-rw-r--r--vcl/unx/source/inc/drawbezier_mask.h40
-rw-r--r--vcl/unx/source/inc/drawcaption_curs.h42
-rw-r--r--vcl/unx/source/inc/drawcaption_mask.h40
-rw-r--r--vcl/unx/source/inc/drawcirclecut_curs.h42
-rw-r--r--vcl/unx/source/inc/drawcirclecut_mask.h40
-rw-r--r--vcl/unx/source/inc/drawconnect_curs.h42
-rw-r--r--vcl/unx/source/inc/drawconnect_mask.h40
-rw-r--r--vcl/unx/source/inc/drawcrook_curs.h42
-rw-r--r--vcl/unx/source/inc/drawcrook_mask.h40
-rw-r--r--vcl/unx/source/inc/drawcrop_curs.h42
-rw-r--r--vcl/unx/source/inc/drawcrop_mask.h40
-rw-r--r--vcl/unx/source/inc/drawellipse_curs.h42
-rw-r--r--vcl/unx/source/inc/drawellipse_mask.h40
-rw-r--r--vcl/unx/source/inc/drawfreehand_curs.h42
-rw-r--r--vcl/unx/source/inc/drawfreehand_mask.h40
-rw-r--r--vcl/unx/source/inc/drawline_curs.h42
-rw-r--r--vcl/unx/source/inc/drawline_mask.h40
-rw-r--r--vcl/unx/source/inc/drawmirror_curs.h42
-rw-r--r--vcl/unx/source/inc/drawmirror_mask.h40
-rw-r--r--vcl/unx/source/inc/drawpie_curs.h42
-rw-r--r--vcl/unx/source/inc/drawpie_mask.h40
-rw-r--r--vcl/unx/source/inc/drawpolygon_curs.h42
-rw-r--r--vcl/unx/source/inc/drawpolygon_mask.h40
-rw-r--r--vcl/unx/source/inc/drawrect_curs.h42
-rw-r--r--vcl/unx/source/inc/drawrect_mask.h40
-rw-r--r--vcl/unx/source/inc/drawtext_curs.h42
-rw-r--r--vcl/unx/source/inc/drawtext_mask.h40
-rw-r--r--vcl/unx/source/inc/fill_curs.h40
-rw-r--r--vcl/unx/source/inc/fill_mask.h40
-rw-r--r--vcl/unx/source/inc/hshear_curs.h42
-rw-r--r--vcl/unx/source/inc/hshear_mask.h40
-rw-r--r--vcl/unx/source/inc/invert50.h65
-rw-r--r--vcl/unx/source/inc/linkdata_curs.h42
-rw-r--r--vcl/unx/source/inc/linkdata_mask.h42
-rw-r--r--vcl/unx/source/inc/linkfile_curs.h42
-rw-r--r--vcl/unx/source/inc/linkfile_mask.h42
-rw-r--r--vcl/unx/source/inc/magnify_curs.h40
-rw-r--r--vcl/unx/source/inc/magnify_mask.h40
-rw-r--r--vcl/unx/source/inc/mirror_curs.h42
-rw-r--r--vcl/unx/source/inc/mirror_mask.h40
-rw-r--r--vcl/unx/source/inc/movebezierweight_curs.h42
-rw-r--r--vcl/unx/source/inc/movebezierweight_mask.h40
-rw-r--r--vcl/unx/source/inc/movedata_curs.h42
-rw-r--r--vcl/unx/source/inc/movedata_mask.h42
-rw-r--r--vcl/unx/source/inc/movedlnk_curs.h42
-rw-r--r--vcl/unx/source/inc/movedlnk_mask.h42
-rw-r--r--vcl/unx/source/inc/movefile_curs.h42
-rw-r--r--vcl/unx/source/inc/movefile_mask.h42
-rw-r--r--vcl/unx/source/inc/movefiles_curs.h42
-rw-r--r--vcl/unx/source/inc/movefiles_mask.h42
-rw-r--r--vcl/unx/source/inc/moveflnk_curs.h42
-rw-r--r--vcl/unx/source/inc/moveflnk_mask.h42
-rw-r--r--vcl/unx/source/inc/movepoint_curs.h42
-rw-r--r--vcl/unx/source/inc/movepoint_mask.h40
-rw-r--r--vcl/unx/source/inc/nodrop_curs.h42
-rw-r--r--vcl/unx/source/inc/nodrop_mask.h42
-rw-r--r--vcl/unx/source/inc/null_curs.h31
-rw-r--r--vcl/unx/source/inc/null_mask.h29
-rw-r--r--vcl/unx/source/inc/paintbrush_curs.h8
-rw-r--r--vcl/unx/source/inc/paintbrush_mask.h7
-rw-r--r--vcl/unx/source/inc/pivotcol_curs.h42
-rw-r--r--vcl/unx/source/inc/pivotcol_mask.h42
-rw-r--r--vcl/unx/source/inc/pivotdel_curs.h42
-rw-r--r--vcl/unx/source/inc/pivotdel_mask.h42
-rw-r--r--vcl/unx/source/inc/pivotfld_curs.h42
-rw-r--r--vcl/unx/source/inc/pivotfld_mask.h42
-rw-r--r--vcl/unx/source/inc/pivotrow_curs.h42
-rw-r--r--vcl/unx/source/inc/pivotrow_mask.h42
-rw-r--r--vcl/unx/source/inc/rotate_curs.h42
-rw-r--r--vcl/unx/source/inc/rotate_mask.h40
-rw-r--r--vcl/unx/source/inc/salcursors.h162
-rw-r--r--vcl/unx/source/inc/tblsele_curs.h8
-rw-r--r--vcl/unx/source/inc/tblsele_mask.h7
-rw-r--r--vcl/unx/source/inc/tblsels_curs.h9
-rw-r--r--vcl/unx/source/inc/tblsels_mask.h7
-rw-r--r--vcl/unx/source/inc/tblselse_curs.h8
-rw-r--r--vcl/unx/source/inc/tblselse_mask.h7
-rw-r--r--vcl/unx/source/inc/tblselsw_curs.h8
-rw-r--r--vcl/unx/source/inc/tblselsw_mask.h7
-rw-r--r--vcl/unx/source/inc/tblselw_curs.h8
-rw-r--r--vcl/unx/source/inc/tblselw_mask.h6
-rw-r--r--vcl/unx/source/inc/timemove_curs.h40
-rw-r--r--vcl/unx/source/inc/timemove_mask.h40
-rw-r--r--vcl/unx/source/inc/timesize_curs.h40
-rw-r--r--vcl/unx/source/inc/timesize_mask.h40
-rw-r--r--vcl/unx/source/inc/vertcurs_curs.h8
-rw-r--r--vcl/unx/source/inc/vertcurs_mask.h8
-rw-r--r--vcl/unx/source/inc/vshear_curs.h42
-rw-r--r--vcl/unx/source/inc/vshear_mask.h40
-rw-r--r--vcl/unx/source/plugadapt/makefile.mk59
-rw-r--r--vcl/unx/source/plugadapt/salplug.cxx300
-rw-r--r--vcl/unx/source/printer/cupsmgr.cxx1141
-rw-r--r--vcl/unx/source/printer/jobdata.cxx226
-rw-r--r--vcl/unx/source/printer/makefile.mk70
-rw-r--r--vcl/unx/source/printer/ppdparser.cxx2164
-rw-r--r--vcl/unx/source/printer/printerinfomanager.cxx1404
-rw-r--r--vcl/unx/source/printergfx/bitmap_gfx.cxx732
-rw-r--r--vcl/unx/source/printergfx/common_gfx.cxx1284
-rw-r--r--vcl/unx/source/printergfx/glyphset.cxx942
-rw-r--r--vcl/unx/source/printergfx/glyphset.hxx135
-rw-r--r--vcl/unx/source/printergfx/makefile.mk65
-rw-r--r--vcl/unx/source/printergfx/printerjob.cxx1199
-rw-r--r--vcl/unx/source/printergfx/psheader.ps368
-rw-r--r--vcl/unx/source/printergfx/psputil.cxx268
-rw-r--r--vcl/unx/source/printergfx/psputil.hxx78
-rw-r--r--vcl/unx/source/printergfx/text_gfx.cxx862
-rw-r--r--vcl/unx/source/window/FWS.cxx280
-rw-r--r--vcl/unx/source/window/FWS.hxx64
-rw-r--r--vcl/unx/source/window/makefile.mk59
-rw-r--r--vcl/unx/source/window/salframe.cxx4388
-rw-r--r--vcl/unx/source/window/salmenu.cxx132
-rw-r--r--vcl/unx/source/window/salobj.cxx561
-rw-r--r--vcl/util/hidother.src31
-rw-r--r--vcl/util/linksvp/makefile.mk65
-rw-r--r--vcl/util/makefile.mk460
-rw-r--r--vcl/util/makefile.pmk34
-rw-r--r--vcl/util/makefile2.pmk41
-rw-r--r--vcl/util/target.pmk44
-rw-r--r--vcl/win/inc/salbmp.h88
-rw-r--r--vcl/win/inc/saldata.hxx372
-rw-r--r--vcl/win/inc/salframe.h150
-rw-r--r--vcl/win/inc/salgdi.h403
-rw-r--r--vcl/win/inc/salids.hrc120
-rw-r--r--vcl/win/inc/salinst.h103
-rw-r--r--vcl/win/inc/salmenu.h78
-rw-r--r--vcl/win/inc/salnativewidgets.h54
-rw-r--r--vcl/win/inc/salobj.h69
-rw-r--r--vcl/win/inc/salprn.h130
-rw-r--r--vcl/win/inc/salsys.h92
-rw-r--r--vcl/win/inc/saltimer.h44
-rw-r--r--vcl/win/inc/salvd.h61
-rw-r--r--vcl/win/inc/svsys.h33
-rw-r--r--vcl/win/inc/wincomp.hxx264
-rw-r--r--vcl/win/source/app/MAKEFILE.MK53
-rw-r--r--vcl/win/source/app/saldata.cxx190
-rw-r--r--vcl/win/source/app/salinfo.cxx301
-rw-r--r--vcl/win/source/app/salinst.cxx1173
-rw-r--r--vcl/win/source/app/salshl.cxx164
-rw-r--r--vcl/win/source/app/saltimer.cxx154
-rw-r--r--vcl/win/source/gdi/MAKEFILE.MK69
-rw-r--r--vcl/win/source/gdi/salbmp.cxx632
-rw-r--r--vcl/win/source/gdi/salgdi.cxx1798
-rw-r--r--vcl/win/source/gdi/salgdi2.cxx821
-rw-r--r--vcl/win/source/gdi/salgdi3.cxx3229
-rw-r--r--vcl/win/source/gdi/salgdi_gdiplus.cxx265
-rw-r--r--vcl/win/source/gdi/salnativewidgets-luna.cxx1288
-rw-r--r--vcl/win/source/gdi/salprn.cxx2364
-rw-r--r--vcl/win/source/gdi/salvd.cxx256
-rw-r--r--vcl/win/source/gdi/winlayout.cxx3203
-rw-r--r--vcl/win/source/gdi/wntgdi.cxx67
-rw-r--r--vcl/win/source/src/50.bmpbin0 -> 94 bytes
-rw-r--r--vcl/win/source/src/50.pngbin0 -> 125 bytes
-rw-r--r--vcl/win/source/src/MAKEFILE.MK130
-rw-r--r--vcl/win/source/src/airbrush.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/src/ase.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/src/asn.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/src/asne.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/src/asns.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/src/asnswe.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/src/asnw.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/src/ass.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/src/asse.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/src/assw.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/src/asw.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/src/aswe.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/src/chain.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/src/chainnot.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/chart.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/copydata.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/copydlnk.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/copyf.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/copyf2.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/copyflnk.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/crook.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/crop.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/cross.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/darc.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/dbezier.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/dcapt.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/dcirccut.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/dconnect.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/dellipse.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/detectiv.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/dfree.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/dline.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/dpie.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/dpolygon.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/drect.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/dtext.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/fill.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/hand.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/help.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/hshear.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/hsize.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/hsizebar.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/hsplit.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/linkdata.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/linkf.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/magnify.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/mirror.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/move.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/movebw.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/movedata.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/movedlnk.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/movef.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/movef2.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/moveflnk.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/movept.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/neswsize.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/notallow.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/nullptr.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/nwsesize.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/pen.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/pivotcol.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/pivotdel.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/pivotfld.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/pivotrow.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/pntbrsh.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/refhand.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/rotate.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/salsrc.rc121
-rw-r--r--vcl/win/source/src/sd.icobin0 -> 3310 bytes
-rw-r--r--vcl/win/source/src/tblsele.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/tblsels.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/tblselse.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/tblselsw.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/tblselw.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/src/timemove.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/src/timesize.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/vshear.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/vsize.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/vsizebar.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/vsplit.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/vtext.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/window/MAKEFILE.MK60
-rw-r--r--vcl/win/source/window/salframe.cxx6440
-rw-r--r--vcl/win/source/window/salmenu.cxx410
-rw-r--r--vcl/win/source/window/salobj.cxx838
-rw-r--r--vcl/workben/makefile.mk151
-rwxr-xr-xvcl/workben/outdevgrind.cxx974
-rw-r--r--vcl/workben/svdem.cxx148
-rw-r--r--vcl/workben/svpclient.cxx346
-rw-r--r--vcl/workben/svptest.cxx379
-rw-r--r--vcl/workben/vcldemo.cxx187
1250 files changed, 434452 insertions, 0 deletions
diff --git a/vcl/aqua/inc/aqua11yfactory.h b/vcl/aqua/inc/aqua11yfactory.h
new file mode 100644
index 000000000000..1982093f8bba
--- /dev/null
+++ b/vcl/aqua/inc/aqua11yfactory.h
@@ -0,0 +1,47 @@
+/*************************************************************************
+ *
+ * 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_AQUA11FACTORY_H
+#define _SV_AQUA11FACTORY_H
+
+#include "aquavcltypes.h"
+#include "aqua11ywrapper.h"
+#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+
+@interface AquaA11yFactory : NSObject
+{
+}
++(void)insertIntoWrapperRepository: (NSView *) viewElement forAccessibleContext: (::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleContext >) rxAccessibleContext;
++(AquaA11yWrapper *)wrapperForAccessible: (::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessible >) rxAccessible;
++(AquaA11yWrapper *)wrapperForAccessibleContext: (::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleContext >) rxAccessibleContext;
++(AquaA11yWrapper *)wrapperForAccessibleContext: (::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleContext >) rxAccessibleContext createIfNotExists:(MacOSBOOL) bCreate;
++(AquaA11yWrapper *)wrapperForAccessibleContext: (::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleContext >) rxAccessibleContext createIfNotExists:(MacOSBOOL) bCreate asRadioGroup:(MacOSBOOL) asRadioGroup;
++(void)removeFromWrapperRepositoryFor: (::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleContext >) rxAccessibleContext;
++(void)registerView: (NSView *) theView;
++(void)revokeView: (NSView *) theViewt;
+@end
+#endif // _SV_AQUA11FACTORY_H
diff --git a/vcl/aqua/inc/aqua11yfocustracker.hxx b/vcl/aqua/inc/aqua11yfocustracker.hxx
new file mode 100644
index 000000000000..1dbf68c4a5ef
--- /dev/null
+++ b/vcl/aqua/inc/aqua11yfocustracker.hxx
@@ -0,0 +1,108 @@
+/*************************************************************************
+ *
+ * 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 _AQUA11YFOCUSTRACKER_HXX_
+#define _AQUA11YFOCUSTRACKER_HXX_
+
+#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLE_HPP_
+#include <com/sun/star/accessibility/XAccessible.hpp>
+#endif
+
+#include "keyboardfocuslistener.hxx"
+
+#include <rtl/instance.hxx>
+
+#include <tools/link.hxx>
+#include <vcl/vclevent.hxx>
+#include <set>
+
+class Window;
+class ToolBox;
+class DocumentFocusListener;
+
+// ------------------------
+// - AquaA11yFocusTracker -
+// ------------------------
+
+class AquaA11yFocusTracker : public rtl::Static< AquaA11yFocusTracker, AquaA11yFocusTracker>
+{
+
+public:
+ AquaA11yFocusTracker();
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > getFocusedObject() { return m_xFocusedObject; };
+
+ // sets the currently focus object and notifies the FocusEventListener (if any)
+ void setFocusedObject(const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& xAccessible);
+
+ // may evolve to add/remove later
+ void setFocusListener(const rtl::Reference< KeyboardFocusListener >& aFocusListener) { m_aFocusListener = aFocusListener; };
+
+protected:
+
+ // received a WINDOW_GETFOCUS event for this window
+ virtual void window_got_focus(Window *pWindow);
+
+ // received a TOOLBOX_HIGHLIGHT event for this window
+ virtual void toolbox_highlight_on(Window *pWindow);
+
+ // received a TOOLBOX_HIGHLIGHTOFF event for this window
+ virtual void toolbox_highlight_off(Window *pWindow);
+
+ // received a TABPAGE_ACTIVATE event for this window
+ virtual void tabpage_activated(Window *pWindow);
+
+ // received a MENU_HIGHLIGHT event for this window
+ virtual void menu_highlighted(const ::VclMenuEvent *pEvent);
+
+ // toolbox items are widgets in gtk+ and Cocoa
+ virtual void notify_toolbox_item_focus(ToolBox *pToolBox);
+
+ // toolbox item opened a floating window (e.g. color chooser)
+ virtual void toolbox_open_floater(Window *pWindow);
+
+ // callback function for Application::addEventListener
+ static long WindowEventHandler(AquaA11yFocusTracker *pFocusTracker, ::VclSimpleEvent const *pEvent);
+
+private:
+ // the accessible object that has the keyboard focus (if any)
+ ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > m_xFocusedObject;
+
+ // the listener for focus events
+ rtl::Reference< KeyboardFocusListener > m_aFocusListener;
+
+ // the list of Windows that need deeper (focus) investigation
+ std::set< Window *> m_aDocumentWindowList;
+
+ // the link object needed for Application::addEventListener
+ Link m_aWindowEventLink;
+
+ // the UNO XAccessibilityEventListener for Documents and other non VCL objects
+ const ::com::sun::star::uno::Reference< DocumentFocusListener > m_xDocumentFocusListener;
+};
+
+#endif // _AQUA11YFOCUSTRACKER_HXX_
diff --git a/vcl/aqua/inc/aqua11ylistener.hxx b/vcl/aqua/inc/aqua11ylistener.hxx
new file mode 100644
index 000000000000..461b149e4650
--- /dev/null
+++ b/vcl/aqua/inc/aqua11ylistener.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _AQUA11YLISTENER_HXX_
+#define _AQUA11YLISTENER_HXX_
+
+#include <com/sun/star/accessibility/XAccessibleEventListener.hpp>
+#include <cppuhelper/implbase1.hxx>
+
+#include "aqua11yfocustracker.hxx"
+#include "aquavcltypes.h"
+#include <set>
+#include <com/sun/star/awt/Rectangle.hpp>
+
+// -------------------------
+// - AquaA11yEventListener -
+// -------------------------
+
+class AquaA11yEventListener :
+ public ::cppu::WeakImplHelper1< ::com::sun::star::accessibility::XAccessibleEventListener >
+{
+
+public:
+ AquaA11yEventListener(id wrapperObject, sal_Int16 role);
+ virtual ~AquaA11yEventListener();
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source )
+ throw (::com::sun::star::uno::RuntimeException);
+
+ // XAccessibleEventListener
+ virtual void SAL_CALL notifyEvent( const ::com::sun::star::accessibility::AccessibleEventObject& aEvent )
+ throw( ::com::sun::star::uno::RuntimeException );
+
+private:
+ const id m_wrapperObject;
+ const sal_Int16 m_role;
+ ::com::sun::star::awt::Rectangle m_oldBounds;
+};
+
+#endif // _AQUA11YLISTENER_HXX_ \ No newline at end of file
diff --git a/vcl/aqua/inc/aqua11ywrapper.h b/vcl/aqua/inc/aqua11ywrapper.h
new file mode 100644
index 000000000000..079dcfe7f112
--- /dev/null
+++ b/vcl/aqua/inc/aqua11ywrapper.h
@@ -0,0 +1,119 @@
+/*************************************************************************
+ *
+ * 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_AQUA11WRAPPER_H
+#define _SV_AQUA11WRAPPER_H
+
+#include "aquavcltypes.h"
+#include <com/sun/star/accessibility/XAccessibleAction.hpp>
+#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+#include <com/sun/star/accessibility/XAccessibleComponent.hpp>
+#include <com/sun/star/accessibility/XAccessibleExtendedComponent.hpp>
+#include <com/sun/star/accessibility/XAccessibleSelection.hpp>
+#include <com/sun/star/accessibility/XAccessibleTable.hpp>
+#include <com/sun/star/accessibility/XAccessibleText.hpp>
+#include <com/sun/star/accessibility/XAccessibleTextAttributes.hpp>
+#include <com/sun/star/accessibility/XAccessibleEditableText.hpp>
+#include <com/sun/star/accessibility/XAccessibleValue.hpp>
+#include <com/sun/star/accessibility/XAccessibleMultiLineText.hpp>
+
+// rAccessibleXYZ as a field in an Objective-C-Class would not call Con-/Destructor, so use a struct instead
+struct ReferenceWrapper
+{
+ ::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleAction > rAccessibleAction;
+ ::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleContext > rAccessibleContext;
+ ::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleComponent > rAccessibleComponent;
+ ::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleExtendedComponent > rAccessibleExtendedComponent;
+ ::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleSelection > rAccessibleSelection;
+ ::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleTable > rAccessibleTable;
+ ::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleText > rAccessibleText;
+ ::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleEditableText > rAccessibleEditableText;
+ ::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleValue > rAccessibleValue;
+ ::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleTextAttributes > rAccessibleTextAttributes;
+ ::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleMultiLineText > rAccessibleMultiLineText;
+};
+
+@interface AquaA11yWrapper : NSView
+{
+ ReferenceWrapper * mpReferenceWrapper;
+ NSString * mpDefaultFontname;
+ float mDefaultFontsize;
+ MacOSBOOL mActsAsRadioGroup;
+ MacOSBOOL mIsTableCell;
+}
+// NSAccessibility Protocol
+-(id)accessibilityAttributeValue:(NSString *)attribute;
+-(MacOSBOOL)accessibilityIsIgnored;
+-(NSArray *)accessibilityAttributeNames;
+-(MacOSBOOL)accessibilityIsAttributeSettable:(NSString *)attribute;
+-(NSArray *)accessibilityParameterizedAttributeNames;
+-(MacOSBOOL)accessibilitySetOverrideValue:(id)value forAttribute:(NSString *)attribute;
+-(void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute;
+-(id)accessibilityAttributeValue:(NSString *)attribute forParameter:(id)parameter;
+-(id)accessibilityFocusedUIElement;
+-(NSString *)accessibilityActionDescription:(NSString *)action;
+-(void)accessibilityPerformAction:(NSString *)action;
+-(NSArray *)accessibilityActionNames;
+-(id)accessibilityHitTest:(NSPoint)point;
+// Attribute values
+-(id)parentAttribute;
+-(id)valueAttribute;
+-(id)titleAttribute;
+-(id)helpAttribute;
+-(id)numberOfCharactersAttribute;
+-(id)selectedTextAttribute;
+-(id)selectedTextRangeAttribute;
+-(id)visibleCharacterRangeAttribute;
+-(id)childrenAttribute;
+-(id)orientationAttribute;
+-(id)windowAttribute;
+// Wrapper-specific
+-(void)setActsAsRadioGroup:(MacOSBOOL)actsAsRadioGroup;
+-(MacOSBOOL)actsAsRadioGroup;
+-(NSView *)viewElementForParent;
+-(id)initWithAccessibleContext: (::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleContext >) anAccessibleContext;
+-(void) setDefaults: (::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleContext >) rxAccessibleContext;
+-(void) dealloc;
+-(void)setDefaultFontname:(NSString *)fontname;
+-(NSString *)defaultFontname;
+-(void)setDefaultFontsize:(float)fontsize;
+-(float)defaultFontsize;
++(void)setPopupMenuOpen:(MacOSBOOL)popupMenuOpen;
+-(::com::sun::star::accessibility::XAccessibleAction *)accessibleAction;
+-(::com::sun::star::accessibility::XAccessibleContext *)accessibleContext;
+-(::com::sun::star::accessibility::XAccessibleComponent *)accessibleComponent;
+-(::com::sun::star::accessibility::XAccessibleExtendedComponent *)accessibleExtendedComponent;
+-(::com::sun::star::accessibility::XAccessibleSelection *)accessibleSelection;
+-(::com::sun::star::accessibility::XAccessibleTable *)accessibleTable;
+-(::com::sun::star::accessibility::XAccessibleText *)accessibleText;
+-(::com::sun::star::accessibility::XAccessibleEditableText *)accessibleEditableText;
+-(::com::sun::star::accessibility::XAccessibleValue *)accessibleValue;
+-(::com::sun::star::accessibility::XAccessibleTextAttributes *)accessibleTextAttributes;
+-(::com::sun::star::accessibility::XAccessibleMultiLineText *)accessibleMultiLineText;
+@end
+
+#endif // _SV_AQUA11WRAPPER_H
diff --git a/vcl/aqua/inc/aquaprintview.h b/vcl/aqua/inc/aquaprintview.h
new file mode 100755
index 000000000000..84d9dd54d6aa
--- /dev/null
+++ b/vcl/aqua/inc/aquaprintview.h
@@ -0,0 +1,67 @@
+/*************************************************************************
+ *
+ * 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_AQUAPRINTVIEW_H
+#define _VCL_AQUAPRINTVIEW_H
+
+#include "premac.h"
+#include <Cocoa/Cocoa.h>
+#include "postmac.h"
+
+#include "vcl/print.hxx"
+
+class AquaSalInfoPrinter;
+
+struct PrintAccessoryViewState
+{
+ bool bNeedRestart;
+ sal_Int32 nLastPage;
+
+ PrintAccessoryViewState()
+ : bNeedRestart( false ), nLastPage( 0 ) {}
+};
+
+@interface AquaPrintView : NSView
+{
+ vcl::PrinterController* mpController;
+ AquaSalInfoPrinter* mpInfoPrinter;
+}
+-(id)initWithController: (vcl::PrinterController*)pController withInfoPrinter: (AquaSalInfoPrinter*)pInfoPrinter;
+-(MacOSBOOL)knowsPageRange: (NSRangePointer)range;
+-(NSRect)rectForPage: (int)page;
+-(NSPoint)locationOfPrintRect: (NSRect)aRect;
+-(void)drawRect: (NSRect)rect;
+@end
+
+@interface AquaPrintAccessoryView : NSObject
+{
+}
++(NSObject*)setupPrinterPanel: (NSPrintOperation*)pOp withController: (vcl::PrinterController*)pController withState: (PrintAccessoryViewState*)pState;
+@end
+
+
+#endif
diff --git a/vcl/aqua/inc/aquavclevents.hxx b/vcl/aqua/inc/aquavclevents.hxx
new file mode 100644
index 000000000000..8e03c59d0954
--- /dev/null
+++ b/vcl/aqua/inc/aquavclevents.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 INCLUDED_AQUAVCLEVENTS_HXX
+#define INCLUDED_AQUAVCLEVENTS_HXX
+
+#include <premac.h>
+#include <Carbon/Carbon.h>
+#include <postmac.h>
+
+/* Definition of custom OpenOffice.org events.
+
+ Avoid conflict with Apple defined event class and type
+ definitions by using uppercase letters. Lowercase
+ letter definitions are reserved for Apple!
+ */
+enum {
+ cOOoSalUserEventClass = 'OOUE'
+};
+
+enum {
+ cOOoSalEventUser = 'UEVT',
+ cOOoSalEventTimer = 'EVTT',
+ cOOoSalEventData = 'EVTD',
+ cOOoSalEventParamTypePtr = 'EPPT'
+};
+
+/* Definition of all necessary EventTypeSpec's */
+
+const EventTypeSpec cWindowBoundsChangedEvent = { kEventClassWindow, kEventWindowBoundsChanged };
+const EventTypeSpec cWindowCloseEvent = { kEventClassWindow, kEventWindowClose };
+const EventTypeSpec cOOoSalUserEvent = { cOOoSalUserEventClass, cOOoSalEventUser };
+const EventTypeSpec cOOoSalTimerEvent = { cOOoSalUserEventClass, cOOoSalEventTimer };
+const EventTypeSpec cWindowActivatedEvent[] = { { kEventClassWindow, kEventWindowActivated },
+ { kEventClassWindow, kEventWindowDeactivated } };
+const EventTypeSpec cWindowPaintEvent = { kEventClassWindow, kEventWindowPaint };
+const EventTypeSpec cWindowDrawContentEvent = { kEventClassWindow, kEventWindowDrawContent };
+
+const EventTypeSpec cWindowFocusEvent[] = { { kEventClassWindow, kEventWindowFocusAcquired },
+ { kEventClassWindow, kEventWindowFocusRelinquish } };
+
+const EventTypeSpec cMouseEnterExitEvent[] = { { kEventClassControl, kEventControlTrackingAreaEntered },
+ { kEventClassControl, kEventControlTrackingAreaExited } };
+
+const EventTypeSpec cMouseEvent[] = { { kEventClassMouse, kEventMouseDown },
+ { kEventClassMouse, kEventMouseUp },
+ { kEventClassMouse, kEventMouseMoved },
+ { kEventClassMouse, kEventMouseDragged } };
+const EventTypeSpec cMouseWheelMovedEvent = { kEventClassMouse, kEventMouseWheelMoved };
+const EventTypeSpec cWindowResizeStarted = { kEventClassWindow, kEventWindowResizeStarted };
+const EventTypeSpec cWindowResizeCompleted = { kEventClassWindow, kEventWindowResizeCompleted };
+
+/* Events for native menus */
+const EventTypeSpec cCommandProcessEvent = { kEventClassCommand, kEventCommandProcess };
+const EventTypeSpec cMenuPopulateEvent = { kEventClassMenu, kEventMenuPopulate };
+const EventTypeSpec cMenuClosedEvent = { kEventClassMenu, kEventMenuClosed };
+const EventTypeSpec cMenuTargetItemEvent = { kEventClassMenu, kEventMenuTargetItem };
+
+/* Events for keyboard */
+const EventTypeSpec cKeyboardRawKeyEvents[] = { { kEventClassKeyboard, kEventRawKeyDown},
+ { kEventClassKeyboard, kEventRawKeyUp},
+ { kEventClassKeyboard, kEventRawKeyRepeat},
+ { kEventClassKeyboard, kEventRawKeyModifiersChanged} };
+
+const EventTypeSpec cTextInputEvents[] = { { kEventClassTextInput, kEventTextInputUpdateActiveInputArea},
+ { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent},
+ { kEventClassTextInput, kEventTextInputOffsetToPos} };
+
+/* Events for scrollbar */
+
+const EventTypeSpec cAppearanceScrollbarVariantChangedEvent = { kEventClassAppearance, kEventAppearanceScrollBarVariantChanged };
+
+#endif // INCLUDED_AQUAVCLEVENTS_HXX
diff --git a/vcl/aqua/inc/aquavcltypes.h b/vcl/aqua/inc/aquavcltypes.h
new file mode 100644
index 000000000000..7346282963d7
--- /dev/null
+++ b/vcl/aqua/inc/aquavcltypes.h
@@ -0,0 +1,36 @@
+/*************************************************************************
+ *
+ * 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 _AQUAVCLTYPES_H
+#define _AQUAVCLTYPES_H
+
+#include "premac.h"
+#import <Cocoa/Cocoa.h>
+#import <AppKit/NSEvent.h>
+#include "postmac.h"
+
+#endif _AQUAVCLTYPES_H
diff --git a/vcl/aqua/inc/keyboardfocuslistener.hxx b/vcl/aqua/inc/keyboardfocuslistener.hxx
new file mode 100644
index 000000000000..71eba2f46c02
--- /dev/null
+++ b/vcl/aqua/inc/keyboardfocuslistener.hxx
@@ -0,0 +1,47 @@
+/*************************************************************************
+ *
+ * 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 _KEYBOARDFOCUSLISTENER_HXX_
+#define _KEYBOARDFOCUSLISTENER_HXX_
+
+#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLE_HPP_
+#include <com/sun/star/accessibility/XAccessible.hpp>
+#endif
+
+#include <rtl/ref.hxx>
+
+// -------------------------
+// - KeyboardFocusListener -
+// -------------------------
+
+class KeyboardFocusListener : public rtl::IReference
+{
+public:
+ virtual void SAL_CALL focusedObjectChanged(const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& xAccessible) = 0;
+};
+
+#endif // _KEYBOARDFOCUSLISTENER_HXX_ \ No newline at end of file
diff --git a/vcl/aqua/inc/salatsuifontutils.hxx b/vcl/aqua/inc/salatsuifontutils.hxx
new file mode 100644
index 000000000000..81e60871ae86
--- /dev/null
+++ b/vcl/aqua/inc/salatsuifontutils.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_SALATSUIFONTUTILS_HXX
+#define _SV_SALATSUIFONTUTILS_HXX
+
+class ImplMacFontData;
+class ImplDevFontList;
+
+#include <premac.h>
+#include <ApplicationServices/ApplicationServices.h>
+#include <postmac.h>
+
+#include <map>
+
+/* This class has the responsibility of assembling a list
+ of atsui compatible fonts available on the system and
+ enabling access to that list.
+ */
+class SystemFontList
+{
+public:
+ SystemFontList();
+ ~SystemFontList();
+
+ void AnnounceFonts( ImplDevFontList& ) const;
+ ImplMacFontData* GetFontDataFromId( ATSUFontID ) const;
+
+ ATSUFontFallbacks maFontFallbacks;
+
+private:
+ typedef std::hash_map<ATSUFontID,ImplMacFontData*> MacFontContainer;
+ MacFontContainer maFontContainer;
+
+ void InitGlyphFallbacks();
+};
+
+#endif // _SV_SALATSUIFONTUTILS_HXX
+
diff --git a/vcl/aqua/inc/salbmp.h b/vcl/aqua/inc/salbmp.h
new file mode 100644
index 000000000000..1c427cce0cd5
--- /dev/null
+++ b/vcl/aqua/inc/salbmp.h
@@ -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.
+ *
+************************************************************************/
+
+#ifndef _SV_SALBMP_H
+#define _SV_SALBMP_H
+
+#include "tools/gen.hxx"
+#include "vcl/sv.h"
+#include "vcl/salbtype.hxx"
+#include "saldata.hxx"
+#include "vcl/salinst.hxx"
+#include "salconst.h"
+#include "vcl/salvd.hxx"
+#include "salcolorutils.hxx"
+#include "vcl/salbmp.hxx"
+#include "salgdi.h"
+#include "basebmp/bitmapdevice.hxx"
+
+// --------------
+// - SalBitmap -
+// --------------
+
+struct BitmapBuffer;
+class BitmapColor;
+class BitmapPalette;
+class AquaSalVirtualDevice;
+class AquaSalGraphics;
+
+class AquaSalBitmap : public SalBitmap
+{
+public:
+ CGContextRef mxGraphicContext;
+ mutable CGImageRef mxCachedImage;
+ BitmapPalette maPalette;
+ basebmp::RawMemorySharedArray maUserBuffer;
+ basebmp::RawMemorySharedArray maContextBuffer;
+ sal_uInt16 mnBits;
+ int mnWidth;
+ int mnHeight;
+ sal_uInt32 mnBytesPerRow;
+
+public:
+ AquaSalBitmap();
+ virtual ~AquaSalBitmap();
+
+public:
+
+ // SalBitmap methods
+ bool Create( const Size& rSize, USHORT nBitCount, const BitmapPalette& rPal );
+ bool Create( const SalBitmap& rSalBmp );
+ bool Create( const SalBitmap& rSalBmp, SalGraphics* pGraphics );
+ bool Create( const SalBitmap& rSalBmp, USHORT nNewBitCount );
+
+ void Destroy();
+
+ Size GetSize() const;
+ USHORT GetBitCount() const;
+
+ BitmapBuffer *AcquireBuffer( bool bReadOnly );
+ void ReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly );
+
+ bool GetSystemData( BitmapSystemData& rData );
+
+private:
+ // quartz helper
+ bool CreateContext();
+ void DestroyContext();
+ bool AllocateUserData();
+
+ void ConvertBitmapData( sal_uInt32 nWidth, sal_uInt32 nHeight,
+ sal_uInt16 nDestBits, sal_uInt32 nDestBytesPerRow, const BitmapPalette& rDestPalette, sal_uInt8* pDestData,
+ sal_uInt16 nSrcBits, sal_uInt32 nSrcBytesPerRow, const BitmapPalette& rSrcPalette, sal_uInt8* pSrcData );
+
+public:
+ bool Create( CGLayerRef xLayer, int nBitCount, int nX, int nY, int nWidth, int nHeight, bool bMirrorVert = true );
+
+public:
+ CGImageRef CreateWithMask( const AquaSalBitmap& rMask, int nX, int nY, int nWidth, int nHeight ) const;
+ CGImageRef CreateColorMask( int nX, int nY, int nWidth, int nHeight, SalColor nMaskColor ) const;
+ CGImageRef CreateCroppedImage( int nX, int nY, int nWidth, int nHeight ) const;
+};
+
+#endif // _SV_SALBMP_HXX
diff --git a/vcl/aqua/inc/salcolorutils.hxx b/vcl/aqua/inc/salcolorutils.hxx
new file mode 100755
index 000000000000..74ccb69756fd
--- /dev/null
+++ b/vcl/aqua/inc/salcolorutils.hxx
@@ -0,0 +1,52 @@
+/*************************************************************************
+ *
+ * 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_SALCOLORUTILS_HXX
+#define _SV_SALCOLORUTILS_HXX
+
+#ifndef _LIMITS_H
+ #include <limits.h>
+#endif
+
+#include "premac.h"
+#include <ApplicationServices/ApplicationServices.h>
+#include "postmac.h"
+
+#include "vcl/salbtype.hxx"
+#include "vcl/salgtype.hxx"
+#include "salconst.h"
+#include "salmathutils.hxx"
+
+// ------------------------------------------------------------------
+
+SalColor GetSalColor( const float* pQuartzColor );
+
+void SetSalColor( const SalColor& rColor, float* pQuartzColor );
+
+// ------------------------------------------------------------------
+
+#endif // _SV_SALCOLORUTILS_HXX
diff --git a/vcl/aqua/inc/salconst.h b/vcl/aqua/inc/salconst.h
new file mode 100755
index 000000000000..2046ec20a806
--- /dev/null
+++ b/vcl/aqua/inc/salconst.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALCONST_H
+#define _SV_SALCONST_H
+
+// -------------------
+// - Constants -
+// -------------------
+
+static const unsigned short kByteMask = 0xFF;
+
+static const unsigned short kOneByte = 8;
+static const unsigned short kTwoBytes = 16;
+
+static const unsigned short kOneBit = 1;
+static const unsigned short kFiveBits = 5;
+static const unsigned short kEightBits = 8;
+static const unsigned short kTenBits = 10;
+static const unsigned short kElevenBits = 11;
+
+static const unsigned short kBlackAndWhite = 1;
+static const unsigned short kFourBitColor = 4;
+static const unsigned short kEightBitColor = 8;
+static const unsigned short kThousandsColor = 16;
+static const unsigned short kTrueColor = 32;
+
+static const unsigned long k16BitRedColorMask = 0x00007c00;
+static const unsigned long k16BitGreenColorMask = 0x000003e0;
+static const unsigned long k16BitBlueColorMask = 0x0000001f;
+
+static const unsigned long k32BitRedColorMask = 0x00ff0000;
+static const unsigned long k32BitGreenColorMask = 0x0000ff00;
+static const unsigned long k32BitBlueColorMask = 0x000000ff;
+
+static const unsigned short kPixMapCmpSizeOneBit = 1;
+static const unsigned short kPixMapCmpSizeFourBits = 4;
+static const unsigned short kPixMapCmpSizeFiveBits = 5;
+static const unsigned short kPixMapCmpSizeEightBits = 8;
+
+static const long kPixMapHRes = 72;
+static const long kPixMapVRes = 72;
+
+#endif // _SV_SALCONST_H
diff --git a/vcl/aqua/inc/saldata.hxx b/vcl/aqua/inc/saldata.hxx
new file mode 100644
index 000000000000..fb7c8cddd6d4
--- /dev/null
+++ b/vcl/aqua/inc/saldata.hxx
@@ -0,0 +1,138 @@
+/*************************************************************************
+ *
+ * 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_SALDATA_HXX
+#define _SV_SALDATA_HXX
+
+#include "premac.h"
+#include <Cocoa/Cocoa.h>
+#include "postmac.h"
+
+#include "com/sun/star/uno/Reference.hxx"
+
+#include "vcl/sv.h"
+#include "vcl/svdata.hxx"
+#include "vcl/salwtype.hxx"
+#include "vcl/ptrstyle.hxx"
+
+#include <list>
+#include <vector>
+#include <map>
+#include <hash_set>
+
+#include <cstdio>
+#include <cstdarg>
+
+#include "apple_remote/RemoteMainController.h"
+
+class AquaSalInstance;
+class SalObject;
+class SalFrame;
+class SalVirtualDevice;
+class SalPrinter;
+class SystemFontList;
+
+// ------------------
+// - Some constants -
+// ------------------
+
+#define SAL_CLIPRECT_COUNT 16
+
+#define VER_TIGER 0x1040
+#define VER_LEOPARD 0x1050
+
+// -----------
+// - SalData -
+// -----------
+
+class AquaSalFrame;
+struct FrameHash : public std::hash<sal_IntPtr>
+{
+ size_t operator()(const AquaSalFrame* frame) const
+ { return std::hash<sal_IntPtr>::operator()( reinterpret_cast<const sal_IntPtr>(frame) ); }
+};
+
+#define INVALID_CURSOR_PTR (NSCursor*)0xdeadbeef
+
+struct SalData
+{
+
+ SALTIMERPROC mpTimerProc; // timer callback proc
+ AquaSalInstance *mpFirstInstance; // pointer of first instance
+ std::list<AquaSalFrame*> maFrames; // pointer of first frame
+ std::hash_set<const AquaSalFrame*,FrameHash> maFrameCheck; // for fast check of frame existance
+ SalObject *mpFirstObject; // pointer of first object window
+ SalVirtualDevice *mpFirstVD; // first VirDev
+ SalPrinter *mpFirstPrinter; // first printing printer
+ SystemFontList *mpFontList;
+ NSStatusItem* mpStatusItem; // one status item that draws all our stati
+ // at the moment this is only one add menu button
+
+ CGColorSpaceRef mxRGBSpace;
+ CGColorSpaceRef mxGraySpace;
+ CGColorSpaceRef mxP50Space;
+ CGPatternRef mxP50Pattern;
+
+ std::vector< NSCursor* > maCursors;
+ std::vector< NSMenuItem* > maFallbackMenu;
+ std::map< NSEvent*, bool > maKeyEventAnswer;
+
+ static oslThreadKey s_aAutoReleaseKey;
+
+ bool mbIsScrollbarDoubleMax; // TODO: support DoubleMin and DoubleBoth too
+ SInt32 mnSystemVersion; // Store System Version
+ MainController* mpMainController; // Apple Remote
+
+ NSObject* mpDockIconClickHandler;
+ long mnDPIX; // #i100617# read DPI only once per office life
+ long mnDPIY; // #i100617# read DPI only once per office life
+
+ com::sun::star::uno::Reference< com::sun::star::uno::XInterface >
+ mxClipboard;
+
+ SalData();
+ ~SalData();
+
+ NSCursor* getCursor( PointerStyle i_eStyle );
+
+ static void ensureThreadAutoreleasePool();
+ static void drainThreadAutoreleasePool();
+
+ static NSStatusItem* getStatusItem();
+};
+
+inline void SetSalData( SalData* pData ) { ImplGetSVData()->mpSalData = (void*)pData; }
+inline SalData *GetSalData() { return (SalData*)ImplGetSVData()->mpSalData; }
+inline SalData *GetAppSalData() { return (SalData*)ImplGetAppSVData()->mpSalData; }
+
+// --- Prototypes ---
+
+BOOL ImplSalYieldMutexTryToAcquire();
+void ImplSalYieldMutexAcquire();
+void ImplSalYieldMutexRelease();
+
+#endif // _SV_SALDATA_HXX
diff --git a/vcl/aqua/inc/salfontutils.hxx b/vcl/aqua/inc/salfontutils.hxx
new file mode 100644
index 000000000000..6f9f61efda70
--- /dev/null
+++ b/vcl/aqua/inc/salfontutils.hxx
@@ -0,0 +1,66 @@
+/*************************************************************************
+ *
+ * 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_SALFONTUTILS_HXX
+#define _SV_SALFONTUTILS_HXX
+
+#include "vcl/outfont.hxx"
+
+static const char *kFontWeightThin1 = "Thin";
+static const char *kFontWeightThin2 = "thin";
+
+static const char *kFontWeightLight1 = "Light";
+static const char *kFontWeightLight2 = "light";
+
+static const char *kFontWeightBold1 = "Bold";
+static const char *kFontWeightBold2 = "bold";
+
+static const char *kFontWeightUltra1 = "Ultra";
+static const char *kFontWeightUltra2 = "ultra";
+
+static const char *kFontWeightSemi1 = "Semi";
+static const char *kFontWeightSemi2 = "semi";
+
+static const char *kFontWeightNormal1 = "Normal";
+static const char *kFontWeightNormal2 = "normal";
+
+static const char *kFontWeightMedium1 = "Medium";
+static const char *kFontWeightMedium2 = "medium";
+
+static const char *kFontWeightBlack1 = "Black";
+static const char *kFontWeightBlack2 = "black";
+
+static const char *kFontWeightRoman1 = "Roman";
+static const char *kFontWeightRoman2 = "roman";
+
+static const char *kFontWeightRegular1 = "Regular";
+static const char *kFontWeightRegular2 = "regular";
+
+
+#endif // _SV_SALFONTUTILS_HXX
+
diff --git a/vcl/aqua/inc/salframe.h b/vcl/aqua/inc/salframe.h
new file mode 100644
index 000000000000..c2ded3267f45
--- /dev/null
+++ b/vcl/aqua/inc/salframe.h
@@ -0,0 +1,220 @@
+/*************************************************************************
+ *
+ * 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_SALFRAME_H
+#define _SV_SALFRAME_H
+
+
+#include "vcl/sv.h"
+#include "vcl/salframe.hxx"
+#include "vcl/sysdata.hxx"
+
+#include "salmenu.h"
+#include "saldata.hxx"
+#include "aquavcltypes.h"
+
+#include <vector>
+#include <utility>
+#include <stdexcept>
+
+#include <boost/shared_ptr.hpp>
+
+class AquaSalGraphics;
+class AquaSalFrame;
+class AquaSalTimer;
+class AquaSalInstance;
+class AquaSalMenu;
+class AquaBlinker;
+
+typedef struct SalFrame::SalPointerState SalPointerState;
+
+// ----------------
+// - AquaSalFrame -
+// ----------------
+
+class AquaSalFrame : public SalFrame
+{
+public:
+ NSWindow* mpWindow; // Cocoa window
+ NSView* mpView; // Cocoa view (actually a custom view, see below
+ NSMenuItem* mpDockMenuEntry; // entry in the dynamic dock menu
+ NSRect maScreenRect; // for mirroring purposes
+ AquaSalGraphics* mpGraphics; // current frame graphics
+ AquaSalFrame* mpParent; // pointer to parent frame
+ SystemEnvData maSysData; // system data
+ int mnMinWidth; // min. client width in pixels
+ int mnMinHeight; // min. client height in pixels
+ int mnMaxWidth; // max. client width in pixels
+ int mnMaxHeight; // max. client height in pixels
+ NSRect maFullScreenRect; // old window size when in FullScreen
+ bool mbGraphics:1; // is Graphics used?
+ bool mbFullScreen:1; // is Window in FullScreen?
+ bool mbShown:1;
+ bool mbInitShow:1;
+ bool mbPositioned:1;
+ bool mbSized:1;
+ bool mbPresentation:1;
+
+ ULONG mnStyle;
+ unsigned int mnStyleMask; // our style mask from NSWindow creation
+
+ ULONG mnLastEventTime;
+ unsigned int mnLastModifierFlags;
+ AquaSalMenu* mpMenu;
+
+ SalExtStyle mnExtStyle; // currently document frames are marked this way
+
+ PointerStyle mePointerStyle; // currently active pointer style
+
+ NSTrackingRectTag mnTrackingRectTag; // used to get enter/leave messages
+
+ CGMutablePathRef mrClippingPath; // used for "shaping"
+ std::vector< CGRect > maClippingRects;
+
+ std::list<AquaBlinker*> maBlinkers;
+
+ Rectangle maInvalidRect;
+
+ ULONG mnICOptions;
+
+ boost::shared_ptr< Timer > mpActivityTimer; // Timer to prevent system sleep during presentation
+public:
+ /** Constructor
+
+ Creates a system window and connects this frame with it.
+
+ @throws std::runtime_error in case window creation fails
+ */
+ AquaSalFrame( SalFrame* pParent, ULONG salFrameStyle );
+
+ virtual ~AquaSalFrame();
+
+ virtual SalGraphics* GetGraphics();
+ virtual void ReleaseGraphics( SalGraphics* pGraphics );
+ virtual BOOL PostEvent( void* pData );
+ virtual void SetTitle( const XubString& rTitle );
+ virtual void SetIcon( USHORT nIcon );
+ virtual void SetRepresentedURL( const rtl::OUString& );
+ virtual void SetMenu( SalMenu* pSalMenu );
+ virtual void DrawMenuBar();
+ virtual void Show( BOOL bVisible, BOOL bNoActivate = FALSE );
+ virtual void Enable( BOOL bEnable );
+ virtual void SetMinClientSize( long nWidth, long nHeight );
+ virtual void SetMaxClientSize( long nWidth, long nHeight );
+ virtual void SetPosSize( long nX, long nY, long nWidth, long nHeight, USHORT nFlags );
+ virtual void GetClientSize( long& rWidth, long& rHeight );
+ virtual void GetWorkArea( Rectangle& rRect );
+ virtual SalFrame* GetParent() const;
+ virtual void SetWindowState( const SalFrameState* pState );
+ virtual BOOL GetWindowState( SalFrameState* pState );
+ virtual void ShowFullScreen( BOOL bFullScreen, sal_Int32 nDisplay );
+ virtual void StartPresentation( BOOL bStart );
+ virtual void SetAlwaysOnTop( BOOL bOnTop );
+ virtual void ToTop( USHORT nFlags );
+ virtual void SetPointer( PointerStyle ePointerStyle );
+ virtual void CaptureMouse( BOOL bMouse );
+ virtual void SetPointerPos( long nX, long nY );
+ virtual void Flush( void );
+ virtual void Flush( const Rectangle& );
+ virtual void Sync();
+ virtual void SetInputContext( SalInputContext* pContext );
+ virtual void EndExtTextInput( USHORT nFlags );
+ virtual String GetKeyName( USHORT nKeyCode );
+ virtual String GetSymbolKeyName( const XubString& rFontName, USHORT nKeyCode );
+ virtual BOOL MapUnicodeToKeyCode( sal_Unicode aUnicode, LanguageType aLangType, KeyCode& rKeyCode );
+ virtual LanguageType GetInputLanguage();
+ virtual SalBitmap* SnapShot();
+ virtual void UpdateSettings( AllSettings& rSettings );
+ virtual void Beep( SoundType eSoundType );
+ virtual const SystemEnvData* GetSystemData() const;
+ virtual SalPointerState GetPointerState();
+ virtual void SetParent( SalFrame* pNewParent );
+ virtual bool SetPluginParent( SystemParentData* pNewParent );
+ virtual void SetExtendedFrameStyle( SalExtStyle );
+ virtual void SetBackgroundBitmap( SalBitmap* );
+ virtual void SetScreenNumber(unsigned int);
+
+ // shaped system windows
+ // set clip region to none (-> rectangular windows, normal state)
+ virtual void ResetClipRegion();
+ // start setting the clipregion consisting of nRects rectangles
+ virtual void BeginSetClipRegion( ULONG nRects );
+ // add a rectangle to the clip region
+ virtual void UnionClipRegion( long nX, long nY, long nWidth, long nHeight );
+ // done setting up the clipregion
+ virtual void EndSetClipRegion();
+
+ virtual void SetClientSize( long nWidth, long nHeight );
+
+ void UpdateFrameGeometry();
+
+ // trigger painting of the window
+ void SendPaintEvent( const Rectangle* pRect = NULL );
+
+ static bool isAlive( const AquaSalFrame* pFrame )
+ { return GetSalData()->maFrameCheck.find( pFrame ) != GetSalData()->maFrameCheck.end(); }
+
+ static AquaSalFrame* GetCaptureFrame() { return s_pCaptureFrame; }
+
+ NSWindow* getWindow() const { return mpWindow; }
+ NSView* getView() const { return mpView; }
+ unsigned int getStyleMask() const { return mnStyleMask; }
+
+ void getResolution( long& o_rDPIX, long& o_rDPIY );
+
+ // actually the follwing methods do the same thing: flipping y coordinates
+ // but having two of them makes clearer what the coordinate system
+ // is supposed to be before and after
+ void VCLToCocoa( NSRect& io_rRect, bool bRelativeToScreen = true );
+ void CocoaToVCL( NSRect& io_rRect, bool bRelativeToScreen = true );
+
+ void VCLToCocoa( NSPoint& io_rPoint, bool bRelativeToScreen = true );
+ void CocoaToVCL( NSPoint& io_Point, bool bRelativeToScreen = true );
+
+ NSCursor* getCurrentCursor() const;
+
+ CGMutablePathRef getClipPath() const { return mrClippingPath; }
+
+ // called by VCL_NSApplication to indicate screen settings have changed
+ void screenParametersChanged();
+
+ private: // methods
+ /** do things on initial show (like centering on parent or on screen)
+ */
+ void initShow();
+
+ void initWindowAndView();
+
+ private: // data
+ static AquaSalFrame* s_pCaptureFrame;
+
+ // make AquaSalFrame non copyable
+ AquaSalFrame( const AquaSalFrame& );
+ AquaSalFrame& operator=(const AquaSalFrame&);
+};
+
+#endif // _SV_SALFRAME_H
diff --git a/vcl/aqua/inc/salframeview.h b/vcl/aqua/inc/salframeview.h
new file mode 100755
index 000000000000..0174c1a68832
--- /dev/null
+++ b/vcl/aqua/inc/salframeview.h
@@ -0,0 +1,208 @@
+/*************************************************************************
+ *
+ * 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_SALFRAMEVIEW_H
+#define _VCL_SALFRAMEVIEW_H
+
+#include "aqua11ywrapper.h"
+
+@interface SalFrameWindow : NSWindow
+{
+ AquaSalFrame* mpFrame;
+ id mDraggingDestinationHandler;
+}
+-(id)initWithSalFrame: (AquaSalFrame*)pFrame;
+-(MacOSBOOL)canBecomeKeyWindow;
+-(void)windowDidBecomeKey: (NSNotification*)pNotification;
+-(void)windowDidResignKey: (NSNotification*)pNotification;
+-(void)windowDidChangeScreen: (NSNotification*)pNotification;
+-(void)windowDidMove: (NSNotification*)pNotification;
+-(void)windowDidResize: (NSNotification*)pNotification;
+-(void)windowDidMiniaturize: (NSNotification*)pNotification;
+-(void)windowDidDeminiaturize: (NSNotification*)pNotification;
+-(MacOSBOOL)windowShouldClose: (NSNotification*)pNotification;
+-(void)dockMenuItemTriggered: (id)sender;
+-(AquaSalFrame*)getSalFrame;
+-(MacOSBOOL)containsMouse;
+-(::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleContext >)accessibleContext;
+
+/* NSDraggingDestination protocol methods
+ */
+-(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender;
+-(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender;
+-(void)draggingExited:(id <NSDraggingInfo>)sender;
+-(MacOSBOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender;
+-(MacOSBOOL)performDragOperation:(id <NSDraggingInfo>)sender;
+-(void)concludeDragOperation:(id <NSDraggingInfo>)sender;
+
+-(void)registerDraggingDestinationHandler:(id)theHandler;
+-(void)unregisterDraggingDestinationHandler:(id)theHandler;
+@end
+
+@interface SalFrameView : AquaA11yWrapper <NSTextInput>
+{
+ AquaSalFrame* mpFrame;
+
+ // for NSTextInput
+ NSEvent* mpLastEvent;
+ BOOL mbNeedSpecialKeyHandle;
+ BOOL mbInKeyInput;
+ BOOL mbKeyHandled;
+ NSRange mMarkedRange;
+ NSRange mSelectedRange;
+ id mpMouseEventListener;
+ id mDraggingDestinationHandler;
+ NSEvent* mpLastSuperEvent;
+}
++(void)unsetMouseFrame: (AquaSalFrame*)pFrame;
+-(id)initWithSalFrame: (AquaSalFrame*)pFrame;
+-(MacOSBOOL)acceptsFirstResponder;
+-(MacOSBOOL)acceptsFirstMouse: (NSEvent *)pEvent;
+-(MacOSBOOL)isOpaque;
+-(void)drawRect: (NSRect)aRect;
+-(void)mouseDown: (NSEvent*)pEvent;
+-(void)mouseDragged: (NSEvent*)pEvent;
+-(void)mouseUp: (NSEvent*)pEvent;
+-(void)mouseMoved: (NSEvent*)pEvent;
+-(void)mouseEntered: (NSEvent*)pEvent;
+-(void)mouseExited: (NSEvent*)pEvent;
+-(void)rightMouseDown: (NSEvent*)pEvent;
+-(void)rightMouseDragged: (NSEvent*)pEvent;
+-(void)rightMouseUp: (NSEvent*)pEvent;
+-(void)otherMouseDown: (NSEvent*)pEvent;
+-(void)otherMouseDragged: (NSEvent*)pEvent;
+-(void)otherMouseUp: (NSEvent*)pEvent;
+-(void)scrollWheel: (NSEvent*)pEvent;
+-(void)magnifyWithEvent: (NSEvent*)pEvent;
+-(void)rotateWithEvent: (NSEvent*)pEvent;
+-(void)swipeWithEvent: (NSEvent*)pEvent;
+-(void)keyDown: (NSEvent*)pEvent;
+-(void)flagsChanged: (NSEvent*)pEvent;
+-(void)sendMouseEventToFrame:(NSEvent*)pEvent button:(USHORT)nButton eventtype:(USHORT)nEvent;
+-(MacOSBOOL)sendKeyInputAndReleaseToFrame: (USHORT)nKeyCode character: (sal_Unicode)aChar;
+-(MacOSBOOL)sendKeyInputAndReleaseToFrame: (USHORT)nKeyCode character: (sal_Unicode)aChar modifiers: (unsigned int)nMod;
+-(MacOSBOOL)sendKeyToFrameDirect: (USHORT)nKeyCode character: (sal_Unicode)aChar modifiers: (unsigned int)nMod;
+-(MacOSBOOL)sendSingleCharacter:(NSEvent*)pEvent;
+-(MacOSBOOL)handleKeyDownException:(NSEvent*)pEvent;
+-(void)clearLastEvent;
+/*
+ text action methods
+*/
+-(void)insertText:(id)aString;
+-(void)insertTab: (id)aSender;
+-(void)insertBacktab: (id)aSender;
+-(void)moveLeft: (id)aSender;
+-(void)moveLeftAndModifySelection: (id)aSender;
+-(void)moveBackwardAndModifySelection: (id)aSender;
+-(void)moveRight: (id)aSender;
+-(void)moveRightAndModifySelection: (id)aSender;
+-(void)moveForwardAndModifySelection: (id)aSender;
+-(void)moveUp: (id)aSender;
+-(void)moveDown: (id)aSender;
+-(void)moveWordBackward: (id)aSender;
+-(void)moveWordBackwardAndModifySelection: (id)aSender;
+-(void)moveWordLeftAndModifySelection: (id)aSender;
+-(void)moveWordForward: (id)aSender;
+-(void)moveWordForwardAndModifySelection: (id)aSender;
+-(void)moveWordRightAndModifySelection: (id)aSender;
+-(void)moveToEndOfLine: (id)aSender;
+-(void)moveToRightEndOfLine: (id)aSender;
+-(void)moveToLeftEndOfLine: (id)aSender;
+-(void)moveToEndOfLineAndModifySelection: (id)aSender;
+-(void)moveToRightEndOfLineAndModifySelection: (id)aSender;
+-(void)moveToLeftEndOfLineAndModifySelection: (id)aSender;
+-(void)moveToBeginningOfLine: (id)aSender;
+-(void)moveToBeginningOfLineAndModifySelection: (id)aSender;
+-(void)moveToEndOfParagraph: (id)aSender;
+-(void)moveToEndOfParagraphAndModifySelection: (id)aSender;
+-(void)moveToBeginningOfParagraph: (id)aSender;
+-(void)moveToBeginningOfParagraphAndModifySelection: (id)aSender;
+-(void)moveParagraphForward: (id)aSender;
+-(void)moveParagraphForwardAndModifySelection: (id)aSender;
+-(void)moveParagraphBackward: (id)aSender;
+-(void)moveParagraphBackwardAndModifySelection: (id)aSender;
+-(void)moveToEndOfDocument: (id)aSender;
+-(void)scrollToEndOfDocument: (id)aSender;
+-(void)moveToEndOfDocumentAndModifySelection: (id)aSender;
+-(void)moveToBeginningOfDocument: (id)aSender;
+-(void)scrollToBeginningOfDocument: (id)aSender;
+-(void)moveToBeginningOfDocumentAndModifySelection: (id)aSender;
+-(void)insertNewline: (id)aSender;
+-(void)deleteBackward: (id)aSender;
+-(void)deleteForward: (id)aSender;
+-(void)cancelOperation: (id)aSender;
+-(void)deleteBackwardByDecomposingPreviousCharacter: (id)aSender;
+-(void)deleteWordBackward: (id)aSender;
+-(void)deleteWordForward: (id)aSender;
+-(void)deleteToBeginningOfLine: (id)aSender;
+-(void)deleteToEndOfLine: (id)aSender;
+-(void)deleteToBeginningOfParagraph: (id)aSender;
+-(void)deleteToEndOfParagraph: (id)aSender;
+-(void)insertLineBreak: (id)aSender;
+-(void)insertParagraphSeparator: (id)aSender;
+-(void)selectWord: (id)aSender;
+-(void)selectLine: (id)aSender;
+-(void)selectParagraph: (id)aSender;
+-(void)selectAll: (id)aSender;
+-(void)noop: (id)aSender;
+/* set the correct pointer for our view */
+-(void)resetCursorRects;
+-(::com::sun::star::accessibility::XAccessibleContext *)accessibleContext;
+-(id)parentAttribute;
+-(NSView *)viewElementForParent;
+/*
+ Event hook for D&D service.
+
+ A drag operation will be invoked on a NSView using
+ the method 'dragImage'. This method requires the
+ actual mouse event initiating this drag operation.
+ Mouse events can only be received by subclassing
+ NSView and overriding methods like 'mouseDown' etc.
+ hence we implement a event hook here so that the
+ D&D service can register as listener for mouse
+ messages and use the last 'mouseDown' or
+ 'mouseDragged' message to initiate the drag
+ operation.
+*/
+-(void)registerMouseEventListener: (id)theListener;
+-(void)unregisterMouseEventListener: (id)theListener;
+
+/* NSDraggingDestination protocol methods
+ */
+-(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender;
+-(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender;
+-(void)draggingExited:(id <NSDraggingInfo>)sender;
+-(MacOSBOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender;
+-(MacOSBOOL)performDragOperation:(id <NSDraggingInfo>)sender;
+-(void)concludeDragOperation:(id <NSDraggingInfo>)sender;
+
+-(void)registerDraggingDestinationHandler:(id)theHandler;
+-(void)unregisterDraggingDestinationHandler:(id)theHandler;
+
+@end
+
+#endif
diff --git a/vcl/aqua/inc/salgdi.h b/vcl/aqua/inc/salgdi.h
new file mode 100644
index 000000000000..1948018806e1
--- /dev/null
+++ b/vcl/aqua/inc/salgdi.h
@@ -0,0 +1,417 @@
+/*************************************************************************
+ *
+ * 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_SALGDI_H
+#define _SV_SALGDI_H
+
+#include "premac.h"
+#include <ApplicationServices/ApplicationServices.h>
+#include "postmac.h"
+
+#include "vcl/sv.h"
+#include "vcl/outfont.hxx"
+#include "vcl/salgdi.hxx"
+#include "aquavcltypes.h"
+
+#include "basegfx/polygon/b2dpolypolygon.hxx"
+
+#include <vector>
+
+class AquaSalFrame;
+class AquaSalBitmap;
+class ImplDevFontAttributes;
+
+class CGRect;
+
+// mac specific physically available font face
+class ImplMacFontData : public ImplFontData
+{
+public:
+ ImplMacFontData( const ImplDevFontAttributes&, ATSUFontID );
+
+ virtual ~ImplMacFontData();
+
+ virtual ImplFontData* Clone() const;
+ virtual ImplFontEntry* CreateFontInstance( ImplFontSelectData& ) const;
+ virtual sal_IntPtr GetFontId() const;
+
+ ImplFontCharMap* GetImplFontCharMap() const;
+ bool HasChar( sal_uInt32 cChar ) const;
+
+ void ReadOs2Table() const;
+ void ReadMacCmapEncoding() const;
+ bool HasCJKSupport() const;
+
+private:
+ const ATSUFontID mnFontId;
+ mutable ImplFontCharMap* mpCharMap;
+ mutable bool mbOs2Read; // true if OS2-table related info is valid
+ mutable bool mbHasOs2Table;
+ mutable bool mbCmapEncodingRead; // true if cmap encoding of Mac font is read
+ mutable bool mbHasCJKSupport; // #i78970# CJK fonts need extra leading
+};
+
+// abstracting quartz color instead of having to use an CGFloat[] array
+class RGBAColor
+{
+public:
+ RGBAColor( SalColor );
+ RGBAColor( float fRed, float fGreen, float fBlue, float fAlpha ); //NOTUSEDYET
+ const float* AsArray() const { return &mfRed; }
+ bool IsVisible() const { return (mfAlpha > 0); }
+ void SetAlpha( float fAlpha ) { mfAlpha = fAlpha; }
+private:
+ float mfRed, mfGreen, mfBlue, mfAlpha;
+};
+
+// -------------------
+// - AquaSalGraphics -
+// -------------------
+class AquaSalGraphics : public SalGraphics
+{
+ friend class ATSLayout;
+protected:
+ AquaSalFrame* mpFrame;
+ CGLayerRef mxLayer; // Quartz graphics layer
+ CGContextRef mrContext; // Quartz drawing context
+ class XorEmulation* mpXorEmulation;
+ int mnXorMode; // 0: off 1: on 2: invert only
+ int mnWidth;
+ int mnHeight;
+ int mnBitmapDepth; // zero unless bitmap
+ /// device resolution of this graphics
+ long mnRealDPIX;
+ long mnRealDPIY;
+ /// some graphics implementations (e.g. AquaSalInfoPrinter) scale
+ /// everything down by a factor (see SetupPrinterGraphics for details)
+ /// so we have to compensate for it with the inverse factor
+ double mfFakeDPIScale;
+
+ /// path representing current clip region
+ CGMutablePathRef mxClipPath;
+
+ /// Drawing colors
+ /// pen color RGBA
+ RGBAColor maLineColor;
+ /// brush color RGBA
+ RGBAColor maFillColor;
+
+ // Device Font settings
+ const ImplMacFontData* mpMacFontData;
+ /// ATSU style object which carries all font attributes
+ ATSUStyle maATSUStyle;
+ /// text rotation as ATSU angle
+ Fixed mnATSUIRotation;
+ /// workaround to prevent ATSU overflows for huge font sizes
+ float mfFontScale;
+ /// <1.0: font is squeezed, >1.0 font is stretched, else 1.0
+ float mfFontStretch;
+ /// allows text to be rendered without antialiasing
+ bool mbNonAntialiasedText;
+
+ // Graphics types
+
+ /// is this a printer graphics
+ bool mbPrinter;
+ /// is this a virtual device graphics
+ bool mbVirDev;
+ /// is this a window graphics
+ bool mbWindow;
+
+public:
+ AquaSalGraphics();
+ virtual ~AquaSalGraphics();
+
+ bool IsPenVisible() const { return maLineColor.IsVisible(); }
+ bool IsBrushVisible() const { return maFillColor.IsVisible(); }
+
+ void SetWindowGraphics( AquaSalFrame* pFrame );
+ void SetPrinterGraphics( CGContextRef, long nRealDPIX, long nRealDPIY, double fFakeScale );
+ void SetVirDevGraphics( CGLayerRef, CGContextRef, int nBitDepth = 0 );
+
+ void initResolution( NSWindow* );
+ void copyResolution( AquaSalGraphics& );
+ void updateResolution();
+
+ bool IsWindowGraphics() const { return mbWindow; }
+ bool IsPrinterGraphics() const { return mbPrinter; }
+ bool IsVirDevGraphics() const { return mbVirDev; }
+ AquaSalFrame* getGraphicsFrame() const { return mpFrame; }
+ void setGraphicsFrame( AquaSalFrame* pFrame ) { mpFrame = pFrame; }
+
+ void ImplDrawPixel( long nX, long nY, const RGBAColor& ); // helper to draw single pixels
+
+ bool CheckContext();
+ void UpdateWindow( NSRect& ); // delivered in NSView coordinates
+ void RefreshRect( const CGRect& );
+ void RefreshRect( const NSRect& );
+ void RefreshRect(float lX, float lY, float lWidth, float lHeight);
+
+ void SetState();
+ void UnsetState();
+ // InvalidateContext does an UnsetState and sets mrContext to 0
+ void InvalidateContext();
+
+ virtual BOOL unionClipRegion( long nX, long nY, long nWidth, long nHeight );
+ virtual bool unionClipRegion( const ::basegfx::B2DPolyPolygon& );
+
+ // draw --> LineColor and FillColor and RasterOp and ClipRegion
+ virtual void drawPixel( long nX, long nY );
+ virtual void drawPixel( long nX, long nY, SalColor nSalColor );
+ virtual void drawLine( long nX1, long nY1, long nX2, long nY2 );
+ virtual void drawRect( long nX, long nY, long nWidth, long nHeight );
+ virtual void drawPolyLine( ULONG nPoints, const SalPoint* pPtAry );
+ virtual void drawPolygon( ULONG nPoints, const SalPoint* pPtAry );
+ virtual void drawPolyPolygon( ULONG nPoly, const ULONG* pPoints, PCONSTSALPOINT* pPtAry );
+ virtual bool drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double fTransparency );
+ virtual sal_Bool drawPolyLineBezier( ULONG nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry );
+ virtual sal_Bool drawPolygonBezier( ULONG nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry );
+ virtual sal_Bool drawPolyPolygonBezier( ULONG nPoly, const ULONG* pPoints, const SalPoint* const* pPtAry, const BYTE* const* pFlgAry );
+ virtual bool drawPolyLine( const ::basegfx::B2DPolygon&, double fTransparency, const ::basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin );
+
+ // CopyArea --> No RasterOp, but ClipRegion
+ virtual void copyArea( long nDestX, long nDestY, long nSrcX, long nSrcY, long nSrcWidth,
+ long nSrcHeight, USHORT nFlags );
+
+ // CopyBits and DrawBitmap --> RasterOp and ClipRegion
+ // CopyBits() --> pSrcGraphics == NULL, then CopyBits on same Graphics
+ virtual void copyBits( const SalTwoRect* pPosAry, SalGraphics* pSrcGraphics );
+ virtual void drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap );
+ virtual void drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ SalColor nTransparentColor );
+ virtual void drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ const SalBitmap& rTransparentBitmap );
+ virtual void drawMask( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ SalColor nMaskColor );
+
+ virtual SalBitmap* getBitmap( long nX, long nY, long nWidth, long nHeight );
+ virtual SalColor getPixel( long nX, long nY );
+
+ // invert --> ClipRegion (only Windows or VirDevs)
+ virtual void invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags);
+ virtual void invert( ULONG nPoints, const SalPoint* pPtAry, SalInvert nFlags );
+
+ virtual BOOL drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, ULONG nSize );
+
+ virtual bool drawAlphaBitmap( const SalTwoRect&,
+ const SalBitmap& rSourceBitmap,
+ const SalBitmap& rAlphaBitmap );
+
+ virtual bool drawAlphaRect( long nX, long nY, long nWidth,
+ long nHeight, sal_uInt8 nTransparency );
+
+ CGPoint* makeCGptArray(ULONG nPoints, const SalPoint* pPtAry);
+ // native widget rendering methods that require mirroring
+ virtual BOOL hitTestNativeControl( ControlType nType, ControlPart nPart, const Region& rControlRegion,
+ const Point& aPos, BOOL& rIsInside );
+ virtual BOOL drawNativeControl( ControlType nType, ControlPart nPart, const Region& rControlRegion,
+ ControlState nState, const ImplControlValue& aValue,
+ const rtl::OUString& aCaption );
+ virtual BOOL drawNativeControlText( ControlType nType, ControlPart nPart, const Region& rControlRegion,
+ ControlState nState, const ImplControlValue& aValue,
+ const rtl::OUString& aCaption );
+ virtual BOOL getNativeControlRegion( ControlType nType, ControlPart nPart, const Region& rControlRegion, ControlState nState,
+ const ImplControlValue& aValue, const rtl::OUString& aCaption,
+ Region &rNativeBoundingRegion, Region &rNativeContentRegion );
+
+ // get device resolution
+ virtual void GetResolution( long& rDPIX, long& rDPIY );
+ // get the depth of the device
+ virtual USHORT GetBitCount();
+ // get the width of the device
+ virtual long GetGraphicsWidth() const;
+
+ // set the clip region to empty
+ virtual void ResetClipRegion();
+ // begin setting the clip region, add rectangles to the
+ // region with the UnionClipRegion call
+ virtual void BeginSetClipRegion( ULONG nCount );
+ // all rectangles were added and the clip region should be set now
+ virtual void EndSetClipRegion();
+
+ // set the line color to transparent (= don't draw lines)
+ virtual void SetLineColor();
+ // set the line color to a specific color
+ virtual void SetLineColor( SalColor nSalColor );
+ // set the fill color to transparent (= don't fill)
+ virtual void SetFillColor();
+ // set the fill color to a specific color, shapes will be
+ // filled accordingly
+ virtual void SetFillColor( SalColor nSalColor );
+ // enable/disable XOR drawing
+ virtual void SetXORMode( bool bSet, bool bInvertOnly );
+ // set line color for raster operations
+ virtual void SetROPLineColor( SalROPColor nROPColor );
+ // set fill color for raster operations
+ virtual void SetROPFillColor( SalROPColor nROPColor );
+ // set the text color to a specific color
+ virtual void SetTextColor( SalColor nSalColor );
+ // set the font
+ virtual USHORT SetFont( ImplFontSelectData*, int nFallbackLevel );
+ // get the current font's etrics
+ virtual void GetFontMetric( ImplFontMetricData* );
+ // get kernign pairs of the current font
+ // return only PairCount if (pKernPairs == NULL)
+ virtual ULONG GetKernPairs( ULONG nPairs, ImplKernPairData* pKernPairs );
+ // get the repertoire of the current font
+ virtual ImplFontCharMap* GetImplFontCharMap() const;
+ // graphics must fill supplied font list
+ virtual void GetDevFontList( ImplDevFontList* );
+ // graphics should call ImplAddDevFontSubstitute on supplied
+ // OutputDevice for all its device specific preferred font substitutions
+ virtual void GetDevFontSubstList( OutputDevice* );
+ virtual bool AddTempDevFont( ImplDevFontList*, const String& rFileURL, const String& rFontName );
+ // CreateFontSubset: a method to get a subset of glyhps of a font
+ // inside a new valid font file
+ // returns TRUE if creation of subset was successfull
+ // parameters: rToFile: contains a osl file URL to write the subset to
+ // pFont: describes from which font to create a subset
+ // pGlyphIDs: the glyph ids to be extracted
+ // pEncoding: the character code corresponding to each glyph
+ // pWidths: the advance widths of the correspoding glyphs (in PS font units)
+ // nGlyphs: the number of glyphs
+ // rInfo: additional outgoing information
+ // implementation note: encoding 0 with glyph id 0 should be added implicitly
+ // as "undefined character"
+ virtual BOOL CreateFontSubset( const rtl::OUString& rToFile,
+ const ImplFontData* pFont,
+ long* pGlyphIDs,
+ sal_uInt8* pEncoding,
+ sal_Int32* pWidths,
+ int nGlyphs,
+ FontSubsetInfo& rInfo // out parameter
+ );
+
+ // GetFontEncodingVector: a method to get the encoding map Unicode
+ // to font encoded character; this is only used for type1 fonts and
+ // may return NULL in case of unknown encoding vector
+ // if ppNonEncoded is set and non encoded characters (that is type1
+ // glyphs with only a name) exist it is set to the corresponding
+ // map for non encoded glyphs; the encoding vector contains -1
+ // as encoding for these cases
+ virtual const Ucs2SIntMap* GetFontEncodingVector( const ImplFontData*, const Ucs2OStrMap** ppNonEncoded );
+
+ // GetEmbedFontData: gets the font data for a font marked
+ // embeddable by GetDevFontList or NULL in case of error
+ // parameters: pFont: describes the font in question
+ // pWidths: the widths of all glyphs from char code 0 to 255
+ // pWidths MUST support at least 256 members;
+ // rInfo: additional outgoing information
+ // pDataLen: out parameter, contains the byte length of the returned buffer
+ virtual const void* GetEmbedFontData( const ImplFontData*,
+ const sal_Ucs* pUnicodes,
+ sal_Int32* pWidths,
+ FontSubsetInfo& rInfo,
+ long* pDataLen );
+ // frees the font data again
+ virtual void FreeEmbedFontData( const void* pData, long nDataLen );
+
+ virtual void GetGlyphWidths( const ImplFontData*,
+ bool bVertical,
+ Int32Vector& rWidths,
+ Ucs2UIntMap& rUnicodeEnc );
+
+ virtual BOOL GetGlyphBoundRect( long nIndex, Rectangle& );
+ virtual BOOL GetGlyphOutline( long nIndex, basegfx::B2DPolyPolygon& );
+
+ virtual SalLayout* GetTextLayout( ImplLayoutArgs&, int nFallbackLevel );
+ virtual void DrawServerFontLayout( const ServerFontLayout& );
+ virtual bool supportsOperation( OutDevSupportType ) const;
+
+ // Query the platform layer for control support
+ virtual BOOL IsNativeControlSupported( ControlType nType, ControlPart nPart );
+
+ virtual SystemGraphicsData GetGraphicsData() const;
+ virtual SystemFontData GetSysFontData( int /* nFallbacklevel */ ) const;
+
+private:
+ // differences between VCL, Quartz and kHiThemeOrientation coordinate systems
+ // make some graphics seem to be vertically-mirrored from a VCL perspective
+ bool IsFlipped() const { return mbWindow; }
+
+ void ApplyXorContext();
+ void Pattern50Fill();
+ UInt32 getState( ControlState nState );
+ UInt32 getTrackState( ControlState nState );
+};
+
+class XorEmulation
+{
+public:
+ XorEmulation();
+ /*final*/ ~XorEmulation();
+
+ void SetTarget( int nWidth, int nHeight, int nBitmapDepth, CGContextRef, CGLayerRef );
+ bool UpdateTarget();
+ void Enable() { mbIsEnabled = true; }
+ void Disable() { mbIsEnabled = false; }
+ bool IsEnabled() const { return mbIsEnabled; }
+ CGContextRef GetTargetContext() const { return mxTargetContext; }
+ CGContextRef GetMaskContext() const { return (mbIsEnabled ? mxMaskContext : NULL); }
+
+private:
+ CGLayerRef mxTargetLayer;
+ CGContextRef mxTargetContext;
+ CGContextRef mxMaskContext;
+ CGContextRef mxTempContext;
+ ULONG* mpMaskBuffer;
+ ULONG* mpTempBuffer;
+ int mnBufferLongs;
+ bool mbIsEnabled;
+};
+
+
+// --- some trivial inlines
+
+inline void AquaSalGraphics::RefreshRect( const CGRect& rRect )
+{
+ RefreshRect( rRect.origin.x, rRect.origin.y, rRect.size.width, rRect.size.height );
+}
+
+inline void AquaSalGraphics::RefreshRect( const NSRect& rRect )
+{
+ RefreshRect( rRect.origin.x, rRect.origin.y, rRect.size.width, rRect.size.height );
+}
+
+inline RGBAColor::RGBAColor( SalColor nSalColor )
+: mfRed( SALCOLOR_RED(nSalColor) * (1.0/255))
+, mfGreen( SALCOLOR_GREEN(nSalColor) * (1.0/255))
+, mfBlue( SALCOLOR_BLUE(nSalColor) * (1.0/255))
+, mfAlpha( 1.0 ) // opaque
+{}
+
+inline RGBAColor::RGBAColor( float fRed, float fGreen, float fBlue, float fAlpha )
+: mfRed( fRed )
+, mfGreen( fGreen )
+, mfBlue( fBlue )
+, mfAlpha( fAlpha )
+{}
+
+#endif // _SV_SALGDI_H
diff --git a/vcl/aqua/inc/salinst.h b/vcl/aqua/inc/salinst.h
new file mode 100644
index 000000000000..0bceb99d1d0e
--- /dev/null
+++ b/vcl/aqua/inc/salinst.h
@@ -0,0 +1,202 @@
+/*************************************************************************
+ *
+ * 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_SALINST_H
+#define _SV_SALINST_H
+
+#include "vcl/sv.h"
+#include "vos/mutex.hxx"
+#include "vos/thread.hxx"
+#include "vcl/salinst.hxx"
+#include "osl/conditn.h"
+
+#include "aquavcltypes.h"
+
+#include <list>
+
+class AquaSalFrame;
+class ApplicationEvent;
+class Image;
+
+// -----------------
+// - SalYieldMutex -
+// -----------------
+
+class SalYieldMutex : public vos::OMutex
+{
+ ULONG mnCount;
+ vos::OThread::TThreadIdentifier mnThreadId;
+
+public:
+ SalYieldMutex();
+ virtual void acquire();
+ virtual void release();
+ virtual sal_Bool tryToAcquire();
+ ULONG GetAcquireCount() const { return mnCount; }
+ vos::OThread::TThreadIdentifier GetThreadId() const { return mnThreadId; }
+};
+
+#define YIELD_GUARD vos::OGuard aGuard( GetSalData()->mpFirstInstance->GetYieldMutex() )
+
+
+// -------------------
+// - SalInstanceData -
+// -------------------
+
+//struct SalInstanceData
+//{
+//public:
+//};
+
+// ------------------
+// - AquaSalInstance -
+// ------------------
+
+class AquaSalInstance : public SalInstance
+{
+ struct SalUserEvent
+ {
+ AquaSalFrame* mpFrame;
+ void* mpData;
+ USHORT mnType;
+
+ SalUserEvent( AquaSalFrame* pFrame, void* pData, USHORT nType ) :
+ mpFrame( pFrame ), mpData( pData ), mnType( nType )
+ {}
+ };
+
+public:
+ SalYieldMutex* mpSalYieldMutex; // Sal-Yield-Mutex
+ rtl::OUString maDefaultPrinter;
+ vos::OThread::TThreadIdentifier maMainThread;
+ bool mbWaitingYield;
+ int mnActivePrintJobs;
+ std::list< SalUserEvent > maUserEvents;
+ oslMutex maUserEventListMutex;
+ oslCondition maWaitingYieldCond;
+
+ typedef std::list<const ApplicationEvent*> AppEventList;
+ static AppEventList aAppEventList;
+
+public:
+ AquaSalInstance();
+ virtual ~AquaSalInstance();
+
+ virtual SalSystem* CreateSystem();
+ virtual void DestroySystem(SalSystem*);
+ virtual SalFrame* CreateChildFrame( SystemParentData* pParent, ULONG nStyle );
+ virtual SalFrame* CreateFrame( SalFrame* pParent, ULONG nStyle );
+ virtual void DestroyFrame( SalFrame* pFrame );
+ virtual SalObject* CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, BOOL bShow = TRUE );
+ virtual void DestroyObject( SalObject* pObject );
+ virtual SalVirtualDevice* CreateVirtualDevice( SalGraphics* pGraphics,
+ long nDX, long nDY,
+ USHORT nBitCount, const SystemGraphicsData *pData );
+ virtual void DestroyVirtualDevice( SalVirtualDevice* pDevice );
+
+ virtual SalInfoPrinter* CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
+ ImplJobSetup* pSetupData );
+ virtual void DestroyInfoPrinter( SalInfoPrinter* pPrinter );
+ virtual SalPrinter* CreatePrinter( SalInfoPrinter* pInfoPrinter );
+ virtual void DestroyPrinter( SalPrinter* pPrinter );
+ virtual void GetPrinterQueueInfo( ImplPrnQueueList* pList );
+ virtual void GetPrinterQueueState( SalPrinterQueueInfo* pInfo );
+ virtual void DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo );
+ virtual String GetDefaultPrinter();
+ virtual SalTimer* CreateSalTimer();
+ virtual SalI18NImeStatus* CreateI18NImeStatus();
+ virtual SalSystem* CreateSalSystem();
+ virtual SalBitmap* CreateSalBitmap();
+ virtual vos::IMutex* GetYieldMutex();
+ virtual ULONG ReleaseYieldMutex();
+ virtual void AcquireYieldMutex( ULONG nCount );
+ virtual void Yield( bool bWait, bool bHandleAllCurrentEvents );
+ virtual bool AnyInput( USHORT nType );
+ virtual SalMenu* CreateMenu( BOOL bMenuBar );
+ virtual void DestroyMenu( SalMenu* );
+ virtual SalMenuItem* CreateMenuItem( const SalItemParams* pItemData );
+ virtual void DestroyMenuItem( SalMenuItem* );
+ virtual SalSession* CreateSalSession();
+ virtual void* GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes );
+ virtual void AddToRecentDocumentList(const rtl::OUString& rFileUrl, const rtl::OUString& rMimeType);
+ virtual void SetEventCallback( void* pInstance, bool(*pCallback)(void*,void*,int) );
+ virtual void SetErrorEventCallback( void* pInstance, bool(*pCallback)(void*,void*,int) );
+
+ // dtrans implementation
+ virtual com::sun::star::uno::Reference< com::sun::star::uno::XInterface >
+ CreateClipboard( const com::sun::star::uno::Sequence< com::sun::star::uno::Any >& i_rArguments );
+ virtual com::sun::star::uno::Reference< com::sun::star::uno::XInterface > CreateDragSource();
+ virtual com::sun::star::uno::Reference< com::sun::star::uno::XInterface > CreateDropTarget();
+
+ static void handleAppDefinedEvent( NSEvent* pEvent );
+
+ // check whether a particular string is passed on the command line
+ // this is needed to avoid duplicate open events through a) command line and b) NSApp's openFile
+ static bool isOnCommandLine( const rtl::OUString& );
+
+ void wakeupYield();
+
+ public:
+ friend class AquaSalFrame;
+
+ void PostUserEvent( AquaSalFrame* pFrame, USHORT nType, void* pData );
+ void delayedSettingsChanged( bool bInvalidate );
+
+ bool isNSAppThread() const;
+
+ void startedPrintJob() { mnActivePrintJobs++; }
+ void endedPrintJob() { mnActivePrintJobs--; }
+
+ // event subtypes for NSApplicationDefined events
+ static const short AppExecuteSVMain = 0x7fff;
+ static const short AppEndLoopEvent = 1;
+ static const short AppStartTimerEvent = 10;
+ static const short AppleRemoteEvent = 15;
+ static const short YieldWakeupEvent = 20;
+
+ static NSMenu* GetDynamicDockMenu();
+};
+
+// helper class: inverted solar guard
+class YieldMutexReleaser
+{
+ ULONG mnCount;
+ public:
+ YieldMutexReleaser();
+ ~YieldMutexReleaser();
+};
+
+// helper class
+rtl::OUString GetOUString( CFStringRef );
+rtl::OUString GetOUString( NSString* );
+CFStringRef CreateCFString( const rtl::OUString& );
+NSString* CreateNSString( const rtl::OUString& );
+
+CGImageRef CreateCGImage( const Image& );
+NSImage* CreateNSImage( const Image& );
+
+#endif // _SV_SALINST_H
diff --git a/vcl/aqua/inc/salmathutils.hxx b/vcl/aqua/inc/salmathutils.hxx
new file mode 100755
index 000000000000..6106dc328740
--- /dev/null
+++ b/vcl/aqua/inc/salmathutils.hxx
@@ -0,0 +1,87 @@
+/*************************************************************************
+ *
+ * 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_SALMATHUTILS_HXX
+#define _SV_SALMATHUTILS_HXX
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// ------------------------------------------------------------------
+//
+// Structures
+//
+// ------------------------------------------------------------------
+
+// LRectCoor is an abreviation for rectangular coordinates
+// represented as long integers
+
+struct LRectCoor
+{
+ long x;
+ long y;
+ long z;
+};
+
+// ------------------------------------------------------------------
+//
+// Type Definitions
+//
+// ------------------------------------------------------------------
+
+// LRectCoorVec is an abreviation for vectors in rectangular
+// coordinates represented as long integers
+
+typedef struct LRectCoor LRectCoor;
+typedef LRectCoor *LRectCoorVector;
+typedef LRectCoorVector *LRectCoorTensor;
+
+// ------------------------------------------------------------------
+//
+// Function Headers
+//
+// ------------------------------------------------------------------
+
+void CSwap ( char &rX, char &rY );
+void UCSwap ( unsigned char &rX, unsigned char &rY );
+void SSwap ( short &rX, short &rY );
+void USSwap ( unsigned short &rX, unsigned short &rY );
+void LSwap ( long &rX, long &rY );
+void ULSwap ( unsigned long &rX, unsigned long &rY );
+
+// ------------------------------------------------------------------
+
+unsigned long Euclidian2Norm ( const LRectCoorVector pVec );
+
+// ------------------------------------------------------------------
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _SV_SALMATHUTILS_HXX
diff --git a/vcl/aqua/inc/salmenu.h b/vcl/aqua/inc/salmenu.h
new file mode 100644
index 000000000000..100e8c22972c
--- /dev/null
+++ b/vcl/aqua/inc/salmenu.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALMENU_H
+#define _SV_SALMENU_H
+
+#include "premac.h"
+#include <Cocoa/Cocoa.h>
+#include "postmac.h"
+
+#include "vcl/sv.h"
+#include "vcl/salmenu.hxx"
+
+#include <vector>
+
+class AquaSalFrame;
+class AquaSalMenuItem;
+
+class AquaSalMenu : public SalMenu
+{
+ std::vector< AquaSalMenuItem* > maItems;
+
+public: // for OOStatusView
+ struct MenuBarButtonEntry
+ {
+ SalMenuButtonItem maButton;
+ NSImage* mpNSImage; // cached image
+ NSString* mpToolTipString;
+
+ MenuBarButtonEntry() : mpNSImage( nil ), mpToolTipString( nil ) {}
+ MenuBarButtonEntry( const SalMenuButtonItem& i_rItem )
+ : maButton( i_rItem), mpNSImage( nil ), mpToolTipString( nil ) {}
+ };
+private:
+ std::vector< MenuBarButtonEntry > maButtons;
+
+ MenuBarButtonEntry* findButtonItem( USHORT i_nItemId );
+ void releaseButtonEntry( MenuBarButtonEntry& i_rEntry );
+ static void statusLayout();
+public:
+ AquaSalMenu( bool bMenuBar );
+ virtual ~AquaSalMenu();
+
+ virtual BOOL VisibleMenuBar(); // must return TRUE to actually DISPLAY native menu bars
+ // otherwise only menu messages are processed (eg, OLE on Windows)
+
+ virtual void InsertItem( SalMenuItem* pSalMenuItem, unsigned nPos );
+ virtual void RemoveItem( unsigned nPos );
+ virtual void SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos );
+ virtual void SetFrame( const SalFrame* pFrame );
+ virtual void CheckItem( unsigned nPos, BOOL bCheck );
+ virtual void EnableItem( unsigned nPos, BOOL bEnable );
+ virtual void SetItemText( unsigned nPos, SalMenuItem* pSalMenuItem, const XubString& rText );
+ virtual void SetItemImage( unsigned nPos, SalMenuItem* pSalMenuItem, const Image& rImage);
+ virtual void SetAccelerator( unsigned nPos, SalMenuItem* pSalMenuItem, const KeyCode& rKeyCode, const XubString& rKeyName );
+ virtual void GetSystemMenuData( SystemMenuData* pData );
+ virtual bool ShowNativePopupMenu(FloatingWindow * pWin, const Rectangle& rRect, ULONG nFlags);
+ virtual bool AddMenuBarButton( const SalMenuButtonItem& );
+ virtual void RemoveMenuBarButton( USHORT nId );
+ virtual Rectangle GetMenuBarButtonRectPixel( USHORT i_nItemId, SalFrame* i_pReferenceFrame );
+
+ int getItemIndexByPos( USHORT nPos ) const;
+ const AquaSalFrame* getFrame() const;
+
+ void setMainMenu();
+ static void unsetMainMenu();
+ static void setDefaultMenu();
+ static void enableMainMenu( bool bEnable );
+ static void addFallbackMenuItem( NSMenuItem* NewItem );
+ static void removeFallbackMenuItem( NSMenuItem* pOldItem );
+
+ const std::vector< MenuBarButtonEntry >& getButtons() const { return maButtons; }
+
+ bool mbMenuBar; // true - Menubar, false - Menu
+ NSMenu* mpMenu; // The Carbon reference to this menu
+ Menu* mpVCLMenu; // the corresponding vcl Menu object
+ const AquaSalFrame* mpFrame; // the frame to dispatch the menu events to
+ AquaSalMenu* mpParentSalMenu; // the parent menu that contains us (and perhaps has a frame)
+
+ static const AquaSalMenu* pCurrentMenuBar;
+
+};
+
+class AquaSalMenuItem : public SalMenuItem
+{
+public:
+ AquaSalMenuItem( const SalItemParams* );
+ virtual ~AquaSalMenuItem();
+
+ USHORT mnId; // Item ID
+ Menu* mpVCLMenu; // VCL Menu into which this MenuItem is inserted
+ AquaSalMenu* mpParentMenu; // The menu in which this menu item is inserted
+ AquaSalMenu* mpSubMenu; // Sub menu of this item (if defined)
+ NSMenuItem* mpMenuItem; // The NSMenuItem
+};
+
+#endif // _SV_SALMENU_H
diff --git a/vcl/aqua/inc/salnativewidgets.h b/vcl/aqua/inc/salnativewidgets.h
new file mode 100755
index 000000000000..11d4ea5c1c62
--- /dev/null
+++ b/vcl/aqua/inc/salnativewidgets.h
@@ -0,0 +1,71 @@
+/*************************************************************************
+ *
+ * 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_NATIVEWIDGETS_H
+#define _SV_NATIVEWIDGETS_H
+
+// since 10.4 ... no metrics are returned, and we have to fix the values
+#define BUTTON_WIDTH 16
+#define BUTTON_HEIGHT 17
+
+//standard height of the AHIG
+//tabs
+#define TAB_HEIGHT_NORMAL 20
+#define TAB_HEIGHT_SMALL 17
+#define TAB_HEIGHT_MINI 15
+
+#define TAB_TEXT_OFFSET 12
+#define VCL_TAB_TEXT_OFFSET 2
+
+//listboxes, comboboxes (they have the same dimensions)
+#define COMBOBOX_HEIGHT_NORMAL 20
+#define DROPDOWN_BUTTON_WIDTH 20
+
+//text edit
+#define TEXT_EDIT_HEIGHT_NORMAL 22
+
+//spin box
+#define SPIN_BUTTON_SPACE 2
+#define SPIN_BUTTON_WIDTH 13
+#define SPIN_UPPER_BUTTON_HEIGHT 11
+#define SPIN_LOWER_BUTTON_HEIGHT 10
+#define SPIN_TWO_BUTTONS_HEIGHT 21
+
+// progress bar
+#define INTRO_PROGRESS_HEIGHT 9
+
+// for some controls, like spinbuttons + spinboxes, or listboxes
+// we need it to adjust text position beside radio and check buttons
+
+#define TEXT_SEPARATOR 3
+
+// extra border for focus ring
+#define FOCUS_RING_WIDTH 4
+
+#define CLIP_FUZZ 1
+
+#endif // _SV_NATIVEWIDGETS_H
diff --git a/vcl/aqua/inc/salnsmenu.h b/vcl/aqua/inc/salnsmenu.h
new file mode 100755
index 000000000000..e9b2cbe922b8
--- /dev/null
+++ b/vcl/aqua/inc/salnsmenu.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _VCL_SALNSMENU_H
+#define _VCL_SALNSMENU_H
+
+class AquaSalMenu;
+class AquaSalMenuItem;
+
+@interface OOStatusItemView : NSView
+{
+}
+-(void)drawRect: (NSRect)aRect;
+-(void)layout;
+-(void)mouseUp: (NSEvent *)pEvent;
+@end
+
+@interface SalNSMenu : NSMenu
+{
+ /* Caution: SalNSMenu instances occasionally are binary copied
+ in AquaSalMenu::ShowNativePopupMenu. If any members are added,
+ please take this into account !
+ */
+ AquaSalMenu* mpMenu;
+}
+-(id)initWithMenu: (AquaSalMenu*)pMenu;
+-(void)menuNeedsUpdate: (NSMenu*)pMenu;
+-(void)setSalMenu: (AquaSalMenu*)pMenu;
+@end
+
+@interface SalNSMenuItem : NSMenuItem
+{
+ /* Caution: SalNSMenuItem instances occasionally are binary copied
+ in AquaSalMenu::ShowNativePopupMenu. If any members are added,
+ please take this into account !
+ */
+ AquaSalMenuItem* mpMenuItem;
+}
+-(id)initWithMenuItem: (AquaSalMenuItem*)pMenuItem;
+-(void)menuItemTriggered: (id)aSender;
+@end
+
+
+#endif
diff --git a/vcl/aqua/inc/salnstimer.h b/vcl/aqua/inc/salnstimer.h
new file mode 100755
index 000000000000..e29fef43b6b4
--- /dev/null
+++ b/vcl/aqua/inc/salnstimer.h
@@ -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.
+ *
+ ************************************************************************/
+#ifndef _VCL_SALNSTIMER_H
+#define _VCL_SALNSTIMER_H
+
+#include "premac.h"
+#include "Cocoa/Cocoa.h"
+#include "postmac.h"
+
+@interface TimerCallbackCaller : NSObject
+{
+}
+-(void)timerElapsed:(NSTimer*)pTimer;
+@end
+
+#endif
diff --git a/vcl/aqua/inc/salobj.h b/vcl/aqua/inc/salobj.h
new file mode 100644
index 000000000000..0041b22c16a0
--- /dev/null
+++ b/vcl/aqua/inc/salobj.h
@@ -0,0 +1,86 @@
+/*************************************************************************
+ *
+ * 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_SALOBJ_H
+#define _SV_SALOBJ_H
+
+#include "vcl/sv.h"
+#include "vcl/sysdata.hxx"
+#include "vcl/salobj.hxx"
+
+class AquaSalFrame;
+class AquaSalObject;
+
+
+// -----------------
+// - SalObjectData -
+// -----------------
+
+struct SalObjectData
+{
+};
+
+class AquaSalObject : public SalObject
+{
+public:
+ AquaSalFrame* mpFrame; // parent frame
+ NSClipView* mpClipView;
+ SystemEnvData maSysData;
+
+ long mnClipX;
+ long mnClipY;
+ long mnClipWidth;
+ long mnClipHeight;
+ bool mbClip;
+
+ long mnX;
+ long mnY;
+ long mnWidth;
+ long mnHeight;
+
+
+ void setClippedPosSize();
+
+
+ AquaSalObject( AquaSalFrame* pFrame );
+ virtual ~AquaSalObject();
+
+ virtual void ResetClipRegion();
+ virtual USHORT GetClipRegionType();
+ virtual void BeginSetClipRegion( ULONG nRects );
+ virtual void UnionClipRegion( long nX, long nY, long nWidth, long nHeight );
+ virtual void EndSetClipRegion();
+ virtual void SetPosSize( long nX, long nY, long nWidth, long nHeight );
+ virtual void Show( BOOL bVisible );
+ virtual void Enable( BOOL nEnable );
+ virtual void GrabFocus();
+ virtual void SetBackground();
+ virtual void SetBackground( SalColor nSalColor );
+ virtual const SystemEnvData* GetSystemData() const;
+};
+
+#endif // _SV_SALOBJ_H
diff --git a/vcl/aqua/inc/salprn.h b/vcl/aqua/inc/salprn.h
new file mode 100644
index 000000000000..6bcafa2ee2e3
--- /dev/null
+++ b/vcl/aqua/inc/salprn.h
@@ -0,0 +1,171 @@
+/*************************************************************************
+ *
+ * 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_SALPRN_H
+#define _SV_SALPRN_H
+
+#include "vcl/sv.h"
+#include "aquavcltypes.h"
+#include "vcl/salprn.hxx"
+
+#include <boost/shared_array.hpp>
+
+
+// ---------------------
+// - AquaSalInfoPrinter -
+// ---------------------
+
+class AquaSalGraphics;
+
+class AquaSalInfoPrinter : public SalInfoPrinter
+{
+ /// Printer graphics
+ AquaSalGraphics* mpGraphics;
+ /// is Graphics used
+ bool mbGraphics;
+ /// job active ?
+ bool mbJob;
+
+ /// cocoa printer object
+ NSPrinter* mpPrinter;
+ /// cocoa print info object
+ NSPrintInfo* mpPrintInfo;
+
+ /// FIXME: get real printer context for infoprinter if possible
+ /// fake context for info printer
+ /// graphics context for Quartz 2D
+ CGContextRef mrContext;
+ /// memory for graphics bitmap context for querying metrics
+ boost::shared_array< sal_uInt8 > maContextMemory;
+
+ // since changes to NSPrintInfo during a job are ignored
+ // we have to care for some settings ourselves
+ // currently we do this for orientation;
+ // really needed however is a solution for paper formats
+ Orientation mePageOrientation;
+
+ int mnStartPageOffsetX;
+ int mnStartPageOffsetY;
+ sal_Int32 mnCurPageRangeStart;
+ sal_Int32 mnCurPageRangeCount;
+
+ public:
+ AquaSalInfoPrinter( const SalPrinterQueueInfo& pInfo );
+ virtual ~AquaSalInfoPrinter();
+
+ void SetupPrinterGraphics( CGContextRef i_xContext ) const;
+
+ virtual SalGraphics* GetGraphics();
+ virtual void ReleaseGraphics( SalGraphics* i_pGraphics );
+ virtual BOOL Setup( SalFrame* i_pFrame, ImplJobSetup* i_pSetupData );
+ virtual BOOL SetPrinterData( ImplJobSetup* pSetupData );
+ virtual BOOL SetData( ULONG i_nFlags, ImplJobSetup* i_pSetupData );
+ virtual void GetPageInfo( const ImplJobSetup* i_pSetupData,
+ long& o_rOutWidth, long& o_rOutHeight,
+ long& o_rPageOffX, long& o_rPageOffY,
+ long& o_rPageWidth, long& o_rPageHeight );
+ virtual ULONG GetCapabilities( const ImplJobSetup* i_pSetupData, USHORT i_nType );
+ virtual ULONG GetPaperBinCount( const ImplJobSetup* i_pSetupData );
+ virtual String GetPaperBinName( const ImplJobSetup* i_pSetupData, ULONG i_nPaperBin );
+ virtual void InitPaperFormats( const ImplJobSetup* i_pSetupData );
+ virtual int GetLandscapeAngle( const ImplJobSetup* i_pSetupData );
+
+ // the artificial separation between InfoPrinter and Printer
+ // is not really useful for us
+ // so let's make AquaSalPrinter just a forwarder to AquaSalInfoPrinter
+ // and concentrate the real work in one class
+ // implement pull model print system
+ BOOL StartJob( const String* i_pFileName,
+ const String& rJobName,
+ const String& i_rAppName,
+ ImplJobSetup* i_pSetupData,
+ vcl::PrinterController& i_rController );
+ BOOL EndJob();
+ BOOL AbortJob();
+ SalGraphics* StartPage( ImplJobSetup* i_pSetupData, BOOL i_bNewJobData );
+ BOOL EndPage();
+ ULONG GetErrorCode() const;
+
+ NSPrintInfo* getPrintInfo() const { return mpPrintInfo; }
+ void setStartPageOffset( int nOffsetX, int nOffsetY ) { mnStartPageOffsetX = nOffsetX; mnStartPageOffsetY = nOffsetY; }
+ sal_Int32 getCurPageRangeStart() const { return mnCurPageRangeStart; }
+ sal_Int32 getCurPageRangeCount() const { return mnCurPageRangeCount; }
+
+ // match width/height against known paper formats, possibly switching orientation
+ const PaperInfo* matchPaper( long i_nWidth, long i_nHeight, Orientation& o_rOrientation ) const;
+ void setPaperSize( long i_nWidth, long i_nHeight, Orientation i_eSetOrientation );
+
+ private:
+ AquaSalInfoPrinter( const AquaSalInfoPrinter& );
+ AquaSalInfoPrinter& operator=(const AquaSalInfoPrinter&);
+};
+
+// -----------------
+// - AquaSalPrinter -
+// -----------------
+
+class AquaSalPrinter : public SalPrinter
+{
+ AquaSalInfoPrinter* mpInfoPrinter; // pointer to the compatible InfoPrinter
+ public:
+ AquaSalPrinter( AquaSalInfoPrinter* i_pInfoPrinter );
+ virtual ~AquaSalPrinter();
+
+ virtual BOOL StartJob( const XubString* i_pFileName,
+ const XubString& i_rJobName,
+ const XubString& i_rAppName,
+ ULONG i_nCopies,
+ bool i_bCollate,
+ bool i_bDirect,
+ ImplJobSetup* i_pSetupData );
+ // implement pull model print system
+ virtual BOOL StartJob( const String* i_pFileName,
+ const String& rJobName,
+ const String& i_rAppName,
+ ImplJobSetup* i_pSetupData,
+ vcl::PrinterController& i_rListener );
+
+ virtual BOOL EndJob();
+ virtual BOOL AbortJob();
+ virtual SalGraphics* StartPage( ImplJobSetup* i_pSetupData, BOOL i_bNewJobData );
+ virtual BOOL EndPage();
+ virtual ULONG GetErrorCode();
+
+ private:
+ AquaSalPrinter( const AquaSalPrinter& );
+ AquaSalPrinter& operator=(const AquaSalPrinter&);
+};
+
+const double fPtTo100thMM = 35.27777778;
+
+inline int PtTo10Mu( double nPoints ) { return (int)(((nPoints)*fPtTo100thMM)+0.5); }
+
+inline double TenMuToPt( double nUnits ) { return floor(((nUnits)/fPtTo100thMM)+0.5); }
+
+
+
+#endif // _SV_SALPRN_H
diff --git a/vcl/aqua/inc/salsys.h b/vcl/aqua/inc/salsys.h
new file mode 100644
index 000000000000..6f5c45880e68
--- /dev/null
+++ b/vcl/aqua/inc/salsys.h
@@ -0,0 +1,70 @@
+/*************************************************************************
+ *
+ * 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_SALSYS_H
+#define _SV_SALSYS_H
+
+#include "vcl/sv.h"
+#include "vcl/salsys.hxx"
+
+#include <list>
+
+// -----------------
+// - SalSystemData -
+// -----------------
+
+//struct SalSystemData
+//{
+//};
+
+class VCL_DLLPUBLIC AquaSalSystem : public SalSystem
+{
+public:
+ AquaSalSystem() {}
+ virtual ~AquaSalSystem();
+
+ // get info about the display
+ virtual unsigned int GetDisplayScreenCount();
+ virtual bool IsMultiDisplay();
+ virtual unsigned int GetDefaultDisplayNumber();
+ virtual Rectangle GetDisplayScreenPosSizePixel( unsigned int nScreen );
+ virtual Rectangle GetDisplayWorkAreaPosSizePixel( unsigned int nScreen );
+
+ virtual rtl::OUString GetScreenName( unsigned int nScreen );
+ // overload pure virtual methods
+ virtual int ShowNativeDialog( const String& rTitle,
+ const String& rMessage,
+ const std::list< String >& rButtons,
+ int nDefButton );
+ virtual int ShowNativeMessageBox( const String& rTitle,
+ const String& rMessage,
+ int nButtonCombination,
+ int nDefaultButton);
+};
+
+
+#endif // _SV_SALSYS_H
diff --git a/vcl/aqua/inc/saltimer.h b/vcl/aqua/inc/saltimer.h
new file mode 100644
index 000000000000..374b9c5a45c5
--- /dev/null
+++ b/vcl/aqua/inc/saltimer.h
@@ -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.
+ *
+************************************************************************/
+
+#ifndef _SV_SALTIMER_H
+#define _SV_SALTIMER_H
+
+#include "premac.h"
+#include <Cocoa/Cocoa.h>
+#include "postmac.h"
+
+#include "vcl/saltimer.hxx"
+
+class AquaSalTimer : public SalTimer
+{
+ public:
+
+ AquaSalTimer();
+ virtual ~AquaSalTimer();
+
+ void Start( ULONG nMS );
+ void Stop();
+
+ static void handleStartTimerEvent( NSEvent* pEvent );
+
+
+ static NSTimer* pRunningTimer;
+ static bool bDispatchTimer;
+};
+
+#endif
diff --git a/vcl/aqua/inc/salvd.h b/vcl/aqua/inc/salvd.h
new file mode 100644
index 000000000000..865cb7b5b766
--- /dev/null
+++ b/vcl/aqua/inc/salvd.h
@@ -0,0 +1,94 @@
+/*************************************************************************
+ *
+ * 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_SALVD_H
+#define _SV_SALVD_H
+
+#include "premac.h"
+#include <ApplicationServices/ApplicationServices.h>
+#include "postmac.h"
+
+#include "vcl/sv.h"
+#include "vcl/salgdi.hxx"
+#include "salconst.h"
+#include "salcolorutils.hxx"
+#include "vcl/salvd.hxx"
+#include "salgdi.h"
+
+#if PRAGMA_ONCE
+ #pragma once
+#endif
+
+// =======================================================================
+
+// =======================================================================
+
+// -----------------
+// - SalVirDevData -
+// -----------------
+
+struct SalVirDevData
+{
+};
+
+typedef struct SalVirDevData SalVirDevData;
+typedef SalVirDevData *SalVirDevDataPtr;
+typedef SalVirDevDataPtr *SalVirDevDataHandle;
+
+// =======================================================================
+
+class AquaSalGraphics;
+
+// -----------------
+// - SalVirDevData -
+// -----------------
+
+class AquaSalVirtualDevice : public SalVirtualDevice
+{
+private:
+ bool mbGraphicsUsed; // is Graphics used
+ bool mbForeignContext; // is mxContext from outside VCL
+ CGContextRef mxBitmapContext;
+ int mnBitmapDepth;
+ CGLayerRef mxLayer; // Quartz layer
+ AquaSalGraphics* mpGraphics; // current VirDev graphics
+
+ void Destroy();
+
+public:
+ AquaSalVirtualDevice( AquaSalGraphics* pGraphic, long nDX, long nDY, USHORT nBitCount, const SystemGraphicsData *pData );
+ virtual ~AquaSalVirtualDevice();
+
+ virtual SalGraphics* GetGraphics();
+ virtual void ReleaseGraphics( SalGraphics* pGraphics );
+ virtual BOOL SetSize( long nNewDX, long nNewDY );
+ virtual void GetSize( long& rWidth, long& rHeight );
+};
+
+// =======================================================================
+
+#endif // _SV_SALVD_H
diff --git a/vcl/aqua/inc/svsys.h b/vcl/aqua/inc/svsys.h
new file mode 100644
index 000000000000..1edce25cea28
--- /dev/null
+++ b/vcl/aqua/inc/svsys.h
@@ -0,0 +1,35 @@
+/*************************************************************************
+ *
+ * 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_SVSYS_H
+#define _SV_SVSYS_H
+
+#include "premac.h"
+#include "Cocoa/Cocoa.h"
+#include "postmac.h"
+
+#endif // _SV_SVSYS_H
diff --git a/vcl/aqua/inc/vclnsapp.h b/vcl/aqua/inc/vclnsapp.h
new file mode 100755
index 000000000000..59b070b421ea
--- /dev/null
+++ b/vcl/aqua/inc/vclnsapp.h
@@ -0,0 +1,70 @@
+/*************************************************************************
+ *
+ * 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_VCLNSAPP_H
+#define _VCL_VCLNSAPP_H
+
+#include "premac.h"
+#include "Cocoa/Cocoa.h"
+#include "postmac.h"
+
+class AquaSalFrame;
+
+@interface CocoaThreadEnabler : NSObject
+{
+}
+-(void)enableCocoaThreads:(id)param;
+@end
+
+// our very own application
+@interface VCL_NSApplication : NSApplication
+{
+}
+-(void)sendEvent:(NSEvent*)pEvent;
+-(void)sendSuperEvent:(NSEvent*)pEvent;
+-(NSMenu*)applicationDockMenu:(NSApplication *)sender;
+-(MacOSBOOL)application: (NSApplication*) app openFile: (NSString*)file;
+-(void)application: (NSApplication*) app openFiles: (NSArray*)files;
+-(MacOSBOOL)application: (NSApplication*) app printFile: (NSString*)file;
+-(NSApplicationPrintReply)application: (NSApplication *) app printFiles:(NSArray *)files withSettings: (NSDictionary *)printSettings showPrintPanels:(MacOSBOOL)bShowPrintPanels;
+-(NSApplicationTerminateReply)applicationShouldTerminate: (NSApplication *) app;
+-(void)systemColorsChanged: (NSNotification*) pNotification;
+-(void)screenParametersChanged: (NSNotification*) pNotification;
+-(void)scrollbarVariantChanged: (NSNotification*) pNotification;
+-(void)scrollbarSettingsChanged: (NSNotification*) pNotification;
+-(void)addFallbackMenuItem: (NSMenuItem*)pNewItem;
+-(void)removeFallbackMenuItem: (NSMenuItem*)pOldItem;
+-(void)addDockMenuItem: (NSMenuItem*)pNewItem;
+-(void)applicationWillBecomeActive: (NSNotification *)pNotification;
+-(void)applicationWillResignActive: (NSNotification *)pNotification;
+-(MacOSBOOL)applicationShouldHandleReopen: (NSApplication*)pApp hasVisibleWindows: (MacOSBOOL)bWinVisible;
+-(void)setDockIconClickHandler: (NSObject*)pHandler;
+-(void)cycleFrameForward: (AquaSalFrame*)pCurFrame;
+-(void)cycleFrameBackward: (AquaSalFrame*)pCurFrame;
+@end
+
+#endif
diff --git a/vcl/aqua/source/a11y/aqua11yactionwrapper.h b/vcl/aqua/source/a11y/aqua11yactionwrapper.h
new file mode 100644
index 000000000000..3a7f13f8a545
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11yactionwrapper.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11ACTIONWRAPPER_H
+#define _SV_AQUA11ACTIONWRAPPER_H
+
+#include "aquavcltypes.h"
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yActionWrapper : NSObject
+{
+}
++(NSArray *)actionNamesForElement:(AquaA11yWrapper *)wrapper;
++(void)doAction:(NSString *)action ofElement:(AquaA11yWrapper *)wrapper;
+@end
+
+#endif // _SV_AQUA11ACTIONWRAPPER_H
diff --git a/vcl/aqua/source/a11y/aqua11yactionwrapper.mm b/vcl/aqua/source/a11y/aqua11yactionwrapper.mm
new file mode 100644
index 000000000000..fcd49fd67ff4
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11yactionwrapper.mm
@@ -0,0 +1,83 @@
+/*************************************************************************
+ *
+ * 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 "salinst.h"
+#include "aqua11yactionwrapper.h"
+
+// Wrapper for XAccessibleAction
+
+@implementation AquaA11yActionWrapper : NSObject
+
++(NSString *)nativeActionNameFor:(NSString *)actionName {
+ // TODO: Optimize ?
+ // Use NSAccessibilityActionDescription
+ if ( [ actionName isEqualToString: @"click" ] ) {
+ return NSAccessibilityPressAction;
+ } else if ( [ actionName isEqualToString: @"togglePopup" ] ) {
+ return NSAccessibilityShowMenuAction;
+ } else if ( [ actionName isEqualToString: @"select" ] ) {
+ return NSAccessibilityPickAction;
+ } else if ( [ actionName isEqualToString: @"incrementLine" ] ) {
+ return NSAccessibilityIncrementAction;
+ } else if ( [ actionName isEqualToString: @"decrementLine" ] ) {
+ return NSAccessibilityDecrementAction;
+ } else if ( [ actionName isEqualToString: @"incrementBlock" ] ) {
+ return NSAccessibilityIncrementAction; // TODO ?
+ } else if ( [ actionName isEqualToString: @"decrementBlock" ] ) {
+ return NSAccessibilityDecrementAction; // TODO ?
+ } else if ( [ actionName isEqualToString: @"Browse" ] ) {
+ return NSAccessibilityPressAction; // TODO ?
+ } else {
+ return [ NSString string ];
+ }
+}
+
++(NSArray *)actionNamesForElement:(AquaA11yWrapper *)wrapper {
+ NSMutableArray * actionNames = [ [ NSMutableArray alloc ] init ];
+ if ( [ wrapper accessibleAction ] != nil ) {
+ for ( int cnt = 0; cnt < [ wrapper accessibleAction ] -> getAccessibleActionCount(); cnt++ ) {
+ [ actionNames addObject: [ AquaA11yActionWrapper nativeActionNameFor: CreateNSString ( [ wrapper accessibleAction ] -> getAccessibleActionDescription ( cnt ) ) ] ];
+ }
+ }
+ return actionNames;
+}
+
++(void)doAction:(NSString *)action ofElement:(AquaA11yWrapper *)wrapper {
+ if ( [ wrapper accessibleAction ] != nil ) {
+ for ( int cnt = 0; cnt < [ wrapper accessibleAction ] -> getAccessibleActionCount(); cnt++ ) {
+ if ( [ action isEqualToString: [ AquaA11yActionWrapper nativeActionNameFor: CreateNSString ( [ wrapper accessibleAction ] -> getAccessibleActionDescription ( cnt ) ) ] ] ) {
+ [ wrapper accessibleAction ] -> doAccessibleAction ( cnt );
+ break;
+ }
+ }
+ }
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ycomponentwrapper.h b/vcl/aqua/source/a11y/aqua11ycomponentwrapper.h
new file mode 100644
index 000000000000..c1806054e253
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ycomponentwrapper.h
@@ -0,0 +1,45 @@
+/*************************************************************************
+ *
+ * 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_AQUA11COMPONENTWRAPPER_H
+#define _SV_AQUA11COMPONENTWRAPPER_H
+
+#include "aquavcltypes.h"
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yComponentWrapper : NSObject
+{
+}
++(id)sizeAttributeForElement:(AquaA11yWrapper *)wrapper;
++(id)positionAttributeForElement:(AquaA11yWrapper *)wrapper;
++(id)descriptionAttributeForElement:(AquaA11yWrapper *)wrapper;
++(void)addAttributeNamesTo:(NSMutableArray *)attributeNames;
++(MacOSBOOL)isAttributeSettable:(NSString *)attribute forElement:(AquaA11yWrapper *)wrapper;
++(void)setFocusedAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value;
+@end
+
+#endif // _SV_AQUA11COMPONENTWRAPPER_H
diff --git a/vcl/aqua/source/a11y/aqua11ycomponentwrapper.mm b/vcl/aqua/source/a11y/aqua11ycomponentwrapper.mm
new file mode 100644
index 000000000000..a700b0b89ae9
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ycomponentwrapper.mm
@@ -0,0 +1,110 @@
+/*************************************************************************
+ *
+ * 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 "aqua11ycomponentwrapper.h"
+#include "aqua11yrolehelper.h"
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::uno;
+
+// Wrapper for XAccessibleComponent and XAccessibleExtendedComponent
+
+@implementation AquaA11yComponentWrapper : NSObject
+
++(id)sizeAttributeForElement:(AquaA11yWrapper *)wrapper {
+ Size size = [ wrapper accessibleComponent ] -> getSize();
+ NSSize nsSize = NSMakeSize ( (float) size.Width, (float) size.Height );
+ return [ NSValue valueWithSize: nsSize ];
+}
+
+// TODO: should be merged with AquaSalFrame::VCLToCocoa... to a general helper method
++(id)positionAttributeForElement:(AquaA11yWrapper *)wrapper {
+ // VCL coordinates are in upper-left-notation, Cocoa likes it the Cartesian way (lower-left)
+ NSRect screenRect = [ [ NSScreen mainScreen ] frame ];
+ Size size = [ wrapper accessibleComponent ] -> getSize();
+ Point location = [ wrapper accessibleComponent ] -> getLocationOnScreen();
+ NSPoint nsPoint = NSMakePoint ( (float) location.X, (float) ( screenRect.size.height - size.Height - location.Y ) );
+ return [ NSValue valueWithPoint: nsPoint ];
+}
+
++(id)descriptionAttributeForElement:(AquaA11yWrapper *)wrapper {
+ if ( [ wrapper accessibleExtendedComponent ] != nil ) {
+ return CreateNSString ( [ wrapper accessibleExtendedComponent ] -> getToolTipText() );
+ } else {
+ return nil;
+ }
+}
+
++(void)addAttributeNamesTo:(NSMutableArray *)attributeNames {
+ NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ];
+ [ attributeNames addObjectsFromArray: [ NSArray arrayWithObjects:
+ NSAccessibilitySizeAttribute,
+ NSAccessibilityPositionAttribute,
+ NSAccessibilityFocusedAttribute,
+ NSAccessibilityEnabledAttribute,
+ nil ] ];
+ [ pool release ];
+}
+
++(MacOSBOOL)isAttributeSettable:(NSString *)attribute forElement:(AquaA11yWrapper *)wrapper {
+ MacOSBOOL isSettable = NO;
+ NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ];
+ if ( [ attribute isEqualToString: NSAccessibilityFocusedAttribute ]
+ && ! [ [ AquaA11yRoleHelper getNativeRoleFrom: [ wrapper accessibleContext ] ] isEqualToString: NSAccessibilityScrollBarRole ]
+ && ! [ [ AquaA11yRoleHelper getNativeRoleFrom: [ wrapper accessibleContext ] ] isEqualToString: NSAccessibilityStaticTextRole ] ) {
+ isSettable = YES;
+ }
+ [ pool release ];
+ return isSettable;
+}
+
++(void)setFocusedAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value {
+ if ( [ value boolValue ] == YES ) {
+ if ( [ wrapper accessibleContext ] -> getAccessibleRole() == AccessibleRole::COMBO_BOX ) {
+ // special treatment for comboboxes: find the corresponding PANEL and set focus to it
+ Reference < XAccessible > rxParent = [ wrapper accessibleContext ] -> getAccessibleParent();
+ if ( rxParent.is() ) {
+ Reference < XAccessibleContext > rxContext = rxParent->getAccessibleContext();
+ if ( rxContext.is() && rxContext -> getAccessibleRole() == AccessibleRole::PANEL ) {
+ Reference < XAccessibleComponent > rxComponent = Reference < XAccessibleComponent > ( rxParent -> getAccessibleContext(), UNO_QUERY );
+ if ( rxComponent.is() ) {
+ rxComponent -> grabFocus();
+ }
+ }
+ }
+ } else {
+ [ wrapper accessibleComponent ] -> grabFocus();
+ }
+ }
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11yfactory.mm b/vcl/aqua/source/a11y/aqua11yfactory.mm
new file mode 100644
index 000000000000..7732ce202cd2
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11yfactory.mm
@@ -0,0 +1,198 @@
+/*************************************************************************
+ *
+ * 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 "salinst.h"
+#include "aqua11yfactory.h"
+#include "aqua11yfocuslistener.hxx"
+#include "aqua11yfocustracker.hxx"
+#include "aqua11yrolehelper.h"
+#include "aqua11ywrapperbutton.h"
+#include "aqua11ywrapperstatictext.h"
+#include "aqua11ywrappertextarea.h"
+#include "aqua11ywrappercheckbox.h"
+#include "aqua11ywrappercombobox.h"
+#include "aqua11ywrappergroup.h"
+#include "aqua11ywrapperlist.h"
+#include "aqua11ywrapperradiobutton.h"
+#include "aqua11ywrapperradiogroup.h"
+#include "aqua11ywrapperrow.h"
+#include "aqua11ywrapperscrollarea.h"
+#include "aqua11ywrapperscrollbar.h"
+#include "aqua11ywrappersplitter.h"
+#include "aqua11ywrappertabgroup.h"
+#include "aqua11ywrappertoolbar.h"
+#include "aqua11ytablewrapper.h"
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::uno;
+
+static bool enabled = false;
+
+@implementation AquaA11yFactory : NSObject
+
+#pragma mark -
+#pragma mark Wrapper Repository
+
++(NSMutableDictionary *)allWrapper {
+ static NSMutableDictionary * mdAllWrapper = nil;
+ if ( mdAllWrapper == nil ) {
+ mdAllWrapper = [ [ [ NSMutableDictionary alloc ] init ] retain ];
+ // initialize keyboard focus tracker
+ rtl::Reference< AquaA11yFocusListener > listener( AquaA11yFocusListener::get() );
+ AquaA11yFocusTracker::get().setFocusListener(listener.get());
+ enabled = true;
+ }
+ return mdAllWrapper;
+}
+
++(NSValue *)keyForAccessibleContext: (Reference < XAccessibleContext >) rxAccessibleContext {
+ return [ NSValue valueWithPointer: rxAccessibleContext.get() ];
+}
+
++(NSValue *)keyForAccessibleContextAsRadioGroup: (Reference < XAccessibleContext >) rxAccessibleContext {
+ return [ NSValue valueWithPointer: ( rxAccessibleContext.get() + 2 ) ];
+}
+
++(AquaA11yWrapper *)wrapperForAccessible: (Reference < XAccessible >) rxAccessible {
+ if ( rxAccessible.is() ) {
+ Reference< XAccessibleContext > xAccessibleContext = rxAccessible->getAccessibleContext();
+ if( xAccessibleContext.is() ) {
+ return [ AquaA11yFactory wrapperForAccessibleContext: xAccessibleContext ];
+ }
+ }
+ return nil;
+}
+
++(AquaA11yWrapper *)wrapperForAccessibleContext: (Reference < XAccessibleContext >) rxAccessibleContext {
+ return [ AquaA11yFactory wrapperForAccessibleContext: rxAccessibleContext createIfNotExists: YES asRadioGroup: NO ];
+}
+
++(AquaA11yWrapper *)wrapperForAccessibleContext: (Reference < XAccessibleContext >) rxAccessibleContext createIfNotExists:(MacOSBOOL) bCreate {
+ return [ AquaA11yFactory wrapperForAccessibleContext: rxAccessibleContext createIfNotExists: bCreate asRadioGroup: NO ];
+}
+
++(AquaA11yWrapper *)wrapperForAccessibleContext: (Reference < XAccessibleContext >) rxAccessibleContext createIfNotExists:(MacOSBOOL) bCreate asRadioGroup:(MacOSBOOL) asRadioGroup{
+ NSMutableDictionary * dAllWrapper = [ AquaA11yFactory allWrapper ];
+ NSValue * nKey = nil;
+ if ( asRadioGroup ) {
+ nKey = [ AquaA11yFactory keyForAccessibleContextAsRadioGroup: rxAccessibleContext ];
+ } else {
+ nKey = [ AquaA11yFactory keyForAccessibleContext: rxAccessibleContext ];
+ }
+ AquaA11yWrapper * aWrapper = (AquaA11yWrapper *) [ dAllWrapper objectForKey: nKey ];
+ if ( aWrapper != nil ) {
+ [ aWrapper retain ];
+ } else if ( bCreate ) {
+ NSString * nativeRole = [ AquaA11yRoleHelper getNativeRoleFrom: rxAccessibleContext.get() ];
+ // TODO: reflection
+ if ( [ nativeRole isEqualToString: NSAccessibilityButtonRole ] ) {
+ aWrapper = [ [ AquaA11yWrapperButton alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else if ( [ nativeRole isEqualToString: NSAccessibilityTextAreaRole ] ) {
+ aWrapper = [ [ AquaA11yWrapperTextArea alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else if ( [ nativeRole isEqualToString: NSAccessibilityStaticTextRole ] ) {
+ aWrapper = [ [ AquaA11yWrapperStaticText alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else if ( [ nativeRole isEqualToString: NSAccessibilityComboBoxRole ] ) {
+ aWrapper = [ [ AquaA11yWrapperComboBox alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else if ( [ nativeRole isEqualToString: NSAccessibilityGroupRole ] ) {
+ aWrapper = [ [ AquaA11yWrapperGroup alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else if ( [ nativeRole isEqualToString: NSAccessibilityToolbarRole ] ) {
+ aWrapper = [ [ AquaA11yWrapperToolbar alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else if ( [ nativeRole isEqualToString: NSAccessibilityScrollAreaRole ] ) {
+ aWrapper = [ [ AquaA11yWrapperScrollArea alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else if ( [ nativeRole isEqualToString: NSAccessibilityTabGroupRole ] ) {
+ aWrapper = [ [ AquaA11yWrapperTabGroup alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else if ( [ nativeRole isEqualToString: NSAccessibilityScrollBarRole ] ) {
+ aWrapper = [ [ AquaA11yWrapperScrollBar alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else if ( [ nativeRole isEqualToString: NSAccessibilityCheckBoxRole ] ) {
+ aWrapper = [ [ AquaA11yWrapperCheckBox alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else if ( [ nativeRole isEqualToString: NSAccessibilityRadioGroupRole ] ) {
+ aWrapper = [ [ AquaA11yWrapperRadioGroup alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else if ( [ nativeRole isEqualToString: NSAccessibilityRadioButtonRole ] ) {
+ aWrapper = [ [ AquaA11yWrapperRadioButton alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else if ( [ nativeRole isEqualToString: NSAccessibilityRowRole ] ) {
+ aWrapper = [ [ AquaA11yWrapperRow alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else if ( [ nativeRole isEqualToString: NSAccessibilityListRole ] ) {
+ aWrapper = [ [ AquaA11yWrapperList alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else if ( [ nativeRole isEqualToString: NSAccessibilitySplitterRole ] ) {
+ aWrapper = [ [ AquaA11yWrapperSplitter alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else if ( [ nativeRole isEqualToString: NSAccessibilityTableRole ] ) {
+ aWrapper = [ [ AquaA11yTableWrapper alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ } else {
+ aWrapper = [ [ AquaA11yWrapper alloc ] initWithAccessibleContext: rxAccessibleContext ];
+ }
+ [ nativeRole release ];
+ [ aWrapper setActsAsRadioGroup: asRadioGroup ];
+ #if 0
+ /* #i102033# NSAccessibility does not seemt to know an equivalent for transient children.
+ That means we need to cache this, else e.g. tree list boxes are not accessible (moreover
+ it crashes by notifying dead objects - which would seemt o be another bug)
+
+ FIXME:
+ Unfortunately this can increase memory consumption drastically until the non transient parent
+ is destroyed an finally all the transients are released.
+ */
+ if ( ! rxAccessibleContext -> getAccessibleStateSet() -> contains ( AccessibleStateType::TRANSIENT ) )
+ #endif
+ {
+ [ dAllWrapper setObject: aWrapper forKey: nKey ];
+ }
+ }
+ return aWrapper;
+}
+
++(void)insertIntoWrapperRepository: (NSView *) viewElement forAccessibleContext: (Reference < XAccessibleContext >) rxAccessibleContext {
+ NSMutableDictionary * dAllWrapper = [ AquaA11yFactory allWrapper ];
+ [ dAllWrapper setObject: viewElement forKey: [ AquaA11yFactory keyForAccessibleContext: rxAccessibleContext ] ];
+}
+
++(void)removeFromWrapperRepositoryFor: (::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleContext >) rxAccessibleContext {
+ // TODO: when RADIO_BUTTON search for associated RadioGroup-wrapper and delete that as well
+ AquaA11yWrapper * theWrapper = [ AquaA11yFactory wrapperForAccessibleContext: rxAccessibleContext createIfNotExists: NO ];
+ if ( theWrapper != nil ) {
+ [ [ AquaA11yFactory allWrapper ] removeObjectForKey: [ AquaA11yFactory keyForAccessibleContext: rxAccessibleContext ] ];
+ [ theWrapper release ];
+ }
+}
+
++(void)registerView: (NSView *) theView {
+ if ( enabled && [ theView isKindOfClass: [ AquaA11yWrapper class ] ] ) {
+ // insertIntoWrapperRepository gets called from SalFrameView itself to bootstrap the bridge initially
+ [ (AquaA11yWrapper *) theView accessibleContext ];
+ }
+}
+
++(void)revokeView: (NSView *) theView {
+ if ( enabled && [ theView isKindOfClass: [ AquaA11yWrapper class ] ] ) {
+ [ AquaA11yFactory removeFromWrapperRepositoryFor: [ (AquaA11yWrapper *) theView accessibleContext ] ];
+ }
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11yfocuslistener.cxx b/vcl/aqua/source/a11y/aqua11yfocuslistener.cxx
new file mode 100644
index 000000000000..9ac9401abd62
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11yfocuslistener.cxx
@@ -0,0 +1,118 @@
+/*************************************************************************
+ *
+ * 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 "aqua11yfocuslistener.hxx"
+#include "aqua11yfocustracker.hxx"
+#include "aqua11yfactory.h"
+
+#include <salhelper/refobj.hxx>
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::uno;
+
+
+rtl::Reference< AquaA11yFocusListener > AquaA11yFocusListener::theListener;
+
+//------------------------------------------------------------------------------
+
+rtl::Reference< AquaA11yFocusListener > AquaA11yFocusListener::get()
+{
+ if ( ! theListener.is() )
+ theListener = new AquaA11yFocusListener();
+
+ return theListener;
+}
+
+//------------------------------------------------------------------------------
+
+AquaA11yFocusListener::AquaA11yFocusListener() : m_focusedObject(nil)
+{
+}
+
+//------------------------------------------------------------------------------
+
+id AquaA11yFocusListener::getFocusedUIElement()
+{
+ if ( nil == m_focusedObject ) {
+ Reference< XAccessible > xAccessible( AquaA11yFocusTracker::get().getFocusedObject() );
+ try {
+ if( xAccessible.is() ) {
+ Reference< XAccessibleContext > xContext(xAccessible->getAccessibleContext());
+ if( xContext.is() )
+ m_focusedObject = [ AquaA11yFactory wrapperForAccessibleContext: xContext ];
+ }
+ } catch( RuntimeException ) {
+ // intentionally do nothing ..
+ }
+ }
+
+ return m_focusedObject;
+}
+
+//------------------------------------------------------------------------------
+
+void SAL_CALL
+AquaA11yFocusListener::focusedObjectChanged(const Reference< XAccessible >& xAccessible)
+{
+ if ( nil != m_focusedObject ) {
+ [ m_focusedObject release ];
+ m_focusedObject = nil;
+ }
+
+ try {
+ if( xAccessible.is() ) {
+ Reference< XAccessibleContext > xContext(xAccessible->getAccessibleContext());
+ if( xContext.is() )
+ {
+ m_focusedObject = [ AquaA11yFactory wrapperForAccessibleContext: xContext ];
+ NSAccessibilityPostNotification(m_focusedObject, NSAccessibilityFocusedUIElementChangedNotification);
+ }
+ }
+ } catch( RuntimeException ) {
+ // intentionally do nothing ..
+ }
+}
+
+//------------------------------------------------------------------------------
+
+oslInterlockedCount SAL_CALL
+AquaA11yFocusListener::acquire() SAL_THROW(())
+{
+ return ReferenceObject::acquire();
+}
+
+//------------------------------------------------------------------------------
+
+oslInterlockedCount SAL_CALL
+AquaA11yFocusListener::release() SAL_THROW(())
+{
+ return ReferenceObject::release();
+}
+
diff --git a/vcl/aqua/source/a11y/aqua11yfocuslistener.hxx b/vcl/aqua/source/a11y/aqua11yfocuslistener.hxx
new file mode 100644
index 000000000000..1fdd340c698e
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11yfocuslistener.hxx
@@ -0,0 +1,62 @@
+/*************************************************************************
+ *
+ * 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 _AQUA11YFOCUSLISTENER_HXX_
+#define _AQUA11YFOCUSLISTENER_HXX_
+
+#include <salhelper/refobj.hxx>
+
+#include "keyboardfocuslistener.hxx"
+#include "aquavcltypes.h"
+
+// #include <com/sun/star/accessibility/XAccessibleContext.hpp>
+
+class AquaA11yFocusListener :
+ public KeyboardFocusListener,
+ public salhelper::ReferenceObject
+{
+ id m_focusedObject;
+
+ static rtl::Reference< AquaA11yFocusListener > theListener;
+
+ AquaA11yFocusListener::AquaA11yFocusListener();
+ virtual AquaA11yFocusListener::~AquaA11yFocusListener() {};
+public:
+
+ static rtl::Reference< AquaA11yFocusListener > get();
+
+ id getFocusedUIElement();
+
+ // KeyboardFocusListener
+ virtual void SAL_CALL focusedObjectChanged(const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& xAccessible);
+
+ // rtl::IReference
+ virtual oslInterlockedCount SAL_CALL acquire() SAL_THROW(());
+ virtual oslInterlockedCount SAL_CALL release() SAL_THROW(());
+};
+
+#endif // _AQUA11YFOCUSLISTENER_HXX_ \ No newline at end of file
diff --git a/vcl/aqua/source/a11y/aqua11yfocustracker.cxx b/vcl/aqua/source/a11y/aqua11yfocustracker.cxx
new file mode 100644
index 000000000000..2a8ebb39bd80
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11yfocustracker.cxx
@@ -0,0 +1,278 @@
+/*************************************************************************
+ *
+ * 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 "aqua11yfocustracker.hxx"
+#include "documentfocuslistener.hxx"
+
+#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+#include <com/sun/star/accessibility/XAccessibleSelection.hpp>
+#include <com/sun/star/accessibility/XAccessibleStateSet.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+
+#include "vcl/svapp.hxx"
+#include "vcl/window.hxx"
+#include "vcl/toolbox.hxx"
+#include "vcl/menu.hxx"
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::uno;
+
+//------------------------------------------------------------------------------
+
+static inline Window *
+getWindow(const ::VclSimpleEvent *pEvent)
+{
+ return static_cast< const ::VclWindowEvent *> (pEvent)->GetWindow();
+}
+
+
+//------------------------------------------------------------------------------
+
+// callback function for Application::addEventListener
+
+long AquaA11yFocusTracker::WindowEventHandler(AquaA11yFocusTracker *pFocusTracker, ::VclSimpleEvent const *pEvent)
+{
+ switch (pEvent->GetId())
+ {
+ case VCLEVENT_WINDOW_PAINT:
+ pFocusTracker-> toolbox_open_floater( getWindow(pEvent) );
+ break;
+ case VCLEVENT_WINDOW_GETFOCUS:
+ pFocusTracker->window_got_focus( getWindow(pEvent) );
+ break;
+ case VCLEVENT_OBJECT_DYING:
+ pFocusTracker->m_aDocumentWindowList.erase( getWindow(pEvent) );
+ // intentional pass through ..
+ case VCLEVENT_TOOLBOX_HIGHLIGHTOFF:
+ pFocusTracker->toolbox_highlight_off( getWindow(pEvent) );
+ break;
+ case VCLEVENT_TOOLBOX_HIGHLIGHT:
+ pFocusTracker->toolbox_highlight_on( getWindow(pEvent) );
+ break;
+ case VCLEVENT_TABPAGE_ACTIVATE:
+ pFocusTracker->tabpage_activated( getWindow(pEvent) );
+ break;
+ case VCLEVENT_MENU_HIGHLIGHT:
+ pFocusTracker->menu_highlighted( static_cast < const VclMenuEvent * > (pEvent) );
+ break;
+ default:
+ break;
+ };
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+
+AquaA11yFocusTracker::AquaA11yFocusTracker() :
+ m_aWindowEventLink(this, (PSTUB) WindowEventHandler),
+ m_xDocumentFocusListener(new DocumentFocusListener(*this))
+{
+ Application::AddEventListener(m_aWindowEventLink);
+ window_got_focus(Application::GetFocusWindow());
+}
+
+//------------------------------------------------------------------------------
+
+void AquaA11yFocusTracker::setFocusedObject(const Reference< XAccessible >& xAccessible)
+{
+ if( xAccessible != m_xFocusedObject )
+ {
+ m_xFocusedObject = xAccessible;
+
+ if( m_aFocusListener.is() )
+ m_aFocusListener->focusedObjectChanged(xAccessible);
+ }
+}
+
+//------------------------------------------------------------------------------
+
+void AquaA11yFocusTracker::notify_toolbox_item_focus(ToolBox *pToolBox)
+{
+ Reference< XAccessible > xAccessible( pToolBox->GetAccessible() );
+
+ if( xAccessible.is() )
+ {
+ Reference< XAccessibleContext > xContext(xAccessible->getAccessibleContext());
+
+ if( xContext.is() )
+ {
+ sal_Int32 nPos = pToolBox->GetItemPos( pToolBox->GetHighlightItemId() );
+ if( nPos != TOOLBOX_ITEM_NOTFOUND )
+ setFocusedObject( xContext->getAccessibleChild( nPos ) );
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+
+void AquaA11yFocusTracker::toolbox_open_floater(Window *pWindow)
+{
+ bool bToolboxFound = false;
+ bool bFloatingWindowFound = false;
+ Window * pFloatingWindow = NULL;
+ while ( pWindow != NULL ) {
+ if ( pWindow->GetType() == WINDOW_TOOLBOX ) {
+ bToolboxFound = true;
+ } else if ( pWindow->GetType() == WINDOW_FLOATINGWINDOW ) {
+ bFloatingWindowFound = true;
+ pFloatingWindow = pWindow;
+ }
+ pWindow = pWindow->GetParent();
+ }
+ if ( bToolboxFound && bFloatingWindowFound ) {
+ Reference < XAccessible > rxAccessible = pFloatingWindow -> GetAccessible();
+ if ( ! rxAccessible.is() ) {
+ return;
+ }
+ Reference < XAccessibleContext > rxContext = rxAccessible -> getAccessibleContext();
+ if ( ! rxContext.is() ) {
+ return;
+ }
+ if ( rxContext -> getAccessibleChildCount() > 0 ) {
+ Reference < XAccessible > rxAccessibleChild = rxContext -> getAccessibleChild( 0 );
+ if ( ! rxAccessibleChild.is() ) {
+ return;
+ }
+ setFocusedObject ( rxAccessibleChild );
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+
+void AquaA11yFocusTracker::toolbox_highlight_on(Window *pWindow)
+{
+ // Make sure either the toolbox or its parent toolbox has the focus
+ if ( ! pWindow->HasFocus() )
+ {
+ ToolBox* pToolBoxParent = dynamic_cast< ToolBox * >( pWindow->GetParent() );
+ if ( ! pToolBoxParent || ! pToolBoxParent->HasFocus() )
+ return;
+ }
+
+ notify_toolbox_item_focus(static_cast <ToolBox *> (pWindow));
+}
+
+//------------------------------------------------------------------------------
+
+void AquaA11yFocusTracker::toolbox_highlight_off(Window *pWindow)
+{
+ ToolBox* pToolBoxParent = dynamic_cast< ToolBox * >( pWindow->GetParent() );
+
+ // Notify when leaving sub toolboxes
+ if( pToolBoxParent && pToolBoxParent->HasFocus() )
+ notify_toolbox_item_focus( pToolBoxParent );
+}
+
+//------------------------------------------------------------------------------
+
+void AquaA11yFocusTracker::tabpage_activated(Window *pWindow)
+{
+ Reference< XAccessible > xAccessible( pWindow->GetAccessible() );
+
+ if( xAccessible.is() )
+ {
+ Reference< XAccessibleSelection > xSelection(xAccessible->getAccessibleContext(), UNO_QUERY);
+
+ if( xSelection.is() )
+ setFocusedObject( xSelection->getSelectedAccessibleChild(0) );
+ }
+}
+
+//------------------------------------------------------------------------------
+
+void AquaA11yFocusTracker::menu_highlighted(const VclMenuEvent *pEvent)
+{
+ Menu * pMenu = pEvent->GetMenu();
+
+ if( pMenu )
+ {
+ Reference< XAccessible > xAccessible( pMenu->GetAccessible() );
+
+ if( xAccessible.is() )
+ setFocusedObject( xAccessible );
+ }
+}
+
+//------------------------------------------------------------------------------
+
+void AquaA11yFocusTracker::window_got_focus(Window *pWindow)
+{
+ // The menu bar is handled through VCLEVENT_MENU_HIGHLIGHTED
+ if( ! pWindow || !pWindow->IsReallyVisible() || pWindow->GetType() == WINDOW_MENUBARWINDOW )
+ return;
+
+ // ToolBoxes are handled through VCLEVENT_TOOLBOX_HIGHLIGHT
+ if( pWindow->GetType() == WINDOW_TOOLBOX )
+ return;
+
+ if( pWindow->GetType() == WINDOW_TABCONTROL )
+ {
+ tabpage_activated( pWindow );
+ return;
+ }
+
+ Reference< XAccessible > xAccessible(pWindow->GetAccessible());
+
+ if( ! xAccessible.is() )
+ return;
+
+ Reference< XAccessibleContext > xContext = xAccessible->getAccessibleContext();
+
+ if( ! xContext.is() )
+ return;
+
+ Reference< XAccessibleStateSet > xStateSet = xContext->getAccessibleStateSet();
+
+ if( ! xStateSet.is() )
+ return;
+
+/* the UNO ToolBox wrapper does not (yet?) support XAccessibleSelection, so we
+ * need to add listeners to the children instead of re-using the tabpage stuff
+ */
+ if( xStateSet->contains(AccessibleStateType::FOCUSED) && (pWindow->GetType() != WINDOW_TREELISTBOX) )
+ {
+ setFocusedObject( xAccessible );
+ }
+ else
+ {
+ if( m_aDocumentWindowList.find(pWindow) == m_aDocumentWindowList.end() )
+ {
+ m_aDocumentWindowList.insert(pWindow);
+ m_xDocumentFocusListener->attachRecursive(xAccessible, xContext, xStateSet);
+ }
+#ifdef ENABLE_TRACING
+ else
+ fprintf(stderr, "Window %p already in the list\n", pWindow );
+#endif
+ }
+}
diff --git a/vcl/aqua/source/a11y/aqua11ylistener.cxx b/vcl/aqua/source/a11y/aqua11ylistener.cxx
new file mode 100644
index 000000000000..7f680f43b3a6
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ylistener.cxx
@@ -0,0 +1,158 @@
+/*************************************************************************
+ *
+ * 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 "aqua11ylistener.hxx"
+#include "aqua11yfactory.h"
+#include "aqua11yfocustracker.hxx"
+#include "aqua11ytextwrapper.h"
+#include "aqua11ywrapper.h"
+#include "salinst.h"
+
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleTableModelChange.hpp>
+#include <com/sun/star/accessibility/AccessibleTableModelChangeType.hpp>
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+
+NSString * getTableNotification( const AccessibleEventObject& aEvent )
+{
+ AccessibleTableModelChange aChange;
+ NSString * notification = nil;
+
+ if( (aEvent.NewValue >>= aChange) &&
+ ( AccessibleTableModelChangeType::INSERT == aChange.Type || AccessibleTableModelChangeType::DELETE == aChange.Type ) &&
+ aChange.FirstRow != aChange.LastRow )
+ {
+ notification = NSAccessibilityRowCountChangedNotification;
+ }
+
+ return notification;
+}
+
+//------------------------------------------------------------------------------
+
+AquaA11yEventListener::AquaA11yEventListener(id wrapperObject, sal_Int16 role) : m_wrapperObject(wrapperObject), m_role(role)
+{
+ [ m_wrapperObject retain ];
+}
+
+//------------------------------------------------------------------------------
+
+AquaA11yEventListener::~AquaA11yEventListener()
+{
+ [ m_wrapperObject release ];
+}
+
+//------------------------------------------------------------------------------
+
+void SAL_CALL
+AquaA11yEventListener::disposing( const EventObject& Source ) throw( RuntimeException )
+{
+ [ AquaA11yFactory removeFromWrapperRepositoryFor: [ (AquaA11yWrapper *) m_wrapperObject accessibleContext ] ];
+}
+
+//------------------------------------------------------------------------------
+
+void SAL_CALL
+AquaA11yEventListener::notifyEvent( const AccessibleEventObject& aEvent ) throw( RuntimeException )
+{
+ NSString * notification = nil;
+ id element = m_wrapperObject;
+ Rectangle bounds;
+
+ // TODO: NSAccessibilityValueChanged, NSAccessibilitySelectedRowsChangedNotification
+ switch( aEvent.EventId )
+ {
+ case AccessibleEventId::ACTIVE_DESCENDANT_CHANGED:
+ if( m_role != AccessibleRole::LIST ) {
+ Reference< XAccessible > xAccessible;
+ if( aEvent.NewValue >>= xAccessible )
+ AquaA11yFocusTracker::get().setFocusedObject( xAccessible );
+ }
+ break;
+
+ case AccessibleEventId::NAME_CHANGED:
+ notification = NSAccessibilityTitleChangedNotification;
+ break;
+
+ case AccessibleEventId::CHILD:
+ // only needed for tooltips (says Apple)
+ if ( m_role == AccessibleRole::TOOL_TIP ) {
+ if(aEvent.NewValue.hasValue()) {
+ notification = NSAccessibilityCreatedNotification;
+ } else if(aEvent.OldValue.hasValue()) {
+ notification = NSAccessibilityUIElementDestroyedNotification;
+ }
+ }
+ break;
+
+ case AccessibleEventId::INVALIDATE_ALL_CHILDREN:
+ // TODO: depricate or remember all children
+ break;
+
+ case AccessibleEventId::BOUNDRECT_CHANGED:
+ bounds = [ element accessibleComponent ] -> getBounds();
+ if ( m_oldBounds.X != 0 && ( bounds.X != m_oldBounds.X || bounds.Y != m_oldBounds.Y ) ) {
+ NSAccessibilityPostNotification(element, NSAccessibilityMovedNotification); // post directly since both cases can happen simultaneously
+ }
+ if ( m_oldBounds.X != 0 && ( bounds.Width != m_oldBounds.Width || bounds.Height != m_oldBounds.Height ) ) {
+ NSAccessibilityPostNotification(element, NSAccessibilityResizedNotification); // post directly since both cases can happen simultaneously
+ }
+ m_oldBounds = bounds;
+ break;
+
+ case AccessibleEventId::SELECTION_CHANGED:
+ notification = NSAccessibilitySelectedChildrenChangedNotification;
+ break;
+
+ case AccessibleEventId::TEXT_SELECTION_CHANGED:
+ notification = NSAccessibilitySelectedTextChangedNotification;
+ break;
+
+ case AccessibleEventId::TABLE_MODEL_CHANGED:
+ notification = getTableNotification(aEvent);
+ break;
+
+ case AccessibleEventId::CARET_CHANGED:
+ notification = NSAccessibilitySelectedTextChangedNotification;
+ break;
+
+ case AccessibleEventId::TEXT_CHANGED:
+ notification = NSAccessibilityValueChangedNotification;
+ break;
+
+ default:
+ break;
+ }
+
+ if( nil != notification )
+ NSAccessibilityPostNotification(element, notification);
+}
diff --git a/vcl/aqua/source/a11y/aqua11yrolehelper.h b/vcl/aqua/source/a11y/aqua11yrolehelper.h
new file mode 100644
index 000000000000..f847eb3f41c3
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11yrolehelper.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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_AQUA11ROLEHELPER_H
+#define _SV_AQUA11ROLEHELPER_H
+
+#include "salinst.h"
+#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+
+@interface AquaA11yRoleHelper : NSObject
+{
+}
++(id)getNativeRoleFrom: (::com::sun::star::accessibility::XAccessibleContext *) accessibleContext;
++(id)getNativeSubroleFrom: (sal_Int16) nRole;
++(id)getRoleDescriptionFrom: (NSString *) role with: (NSString *) subRole;
+@end
+
+#endif // _SV_AQUA11ROLEHELPER_H
diff --git a/vcl/aqua/source/a11y/aqua11yrolehelper.mm b/vcl/aqua/source/a11y/aqua11yrolehelper.mm
new file mode 100644
index 000000000000..b8ebdb08c3df
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11yrolehelper.mm
@@ -0,0 +1,272 @@
+/*************************************************************************
+ *
+ * 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 "aqua11yrolehelper.h"
+#include "aqua11yfactory.h"
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::uno;
+
+@implementation AquaA11yRoleHelper
+
++(id)simpleMapNativeRoleFrom: (XAccessibleContext *) accessibleContext {
+ id nativeRole = nil;
+ switch( accessibleContext -> getAccessibleRole() ) {
+#define MAP(a,b) \
+ case a: nativeRole = b; break
+
+ MAP( AccessibleRole::UNKNOWN, NSAccessibilityUnknownRole );
+ MAP( AccessibleRole::ALERT, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::COLUMN_HEADER, NSAccessibilityColumnRole );
+ MAP( AccessibleRole::CANVAS, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::CHECK_BOX, NSAccessibilityCheckBoxRole );
+ MAP( AccessibleRole::CHECK_MENU_ITEM, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::COLOR_CHOOSER, NSAccessibilityColorWellRole ); // FIXME
+ MAP( AccessibleRole::COMBO_BOX, NSAccessibilityComboBoxRole );
+ MAP( AccessibleRole::DATE_EDITOR, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::DESKTOP_ICON, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::DESKTOP_PANE, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::DIRECTORY_PANE, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::DIALOG, NSAccessibilityGroupRole );
+ MAP( AccessibleRole::DOCUMENT, NSAccessibilityGroupRole );
+ MAP( AccessibleRole::EMBEDDED_OBJECT, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::END_NOTE, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::FILE_CHOOSER, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::FILLER, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::FONT_CHOOSER, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::FOOTER, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::FOOTNOTE, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::FRAME, NSAccessibilityWindowRole );
+ MAP( AccessibleRole::GLASS_PANE, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::GRAPHIC, NSAccessibilityImageRole );
+ MAP( AccessibleRole::GROUP_BOX, NSAccessibilityGroupRole );
+ MAP( AccessibleRole::HEADER, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::HEADING, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::HYPER_LINK, NSAccessibilityLinkRole );
+ MAP( AccessibleRole::ICON, NSAccessibilityImageRole );
+ MAP( AccessibleRole::INTERNAL_FRAME, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::LABEL, NSAccessibilityStaticTextRole );
+ MAP( AccessibleRole::LAYERED_PANE, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::LIST, NSAccessibilityMenuRole );
+ MAP( AccessibleRole::LIST_ITEM, NSAccessibilityMenuItemRole );
+ MAP( AccessibleRole::MENU, NSAccessibilityMenuRole );
+ MAP( AccessibleRole::MENU_BAR, NSAccessibilityMenuBarRole );
+ MAP( AccessibleRole::MENU_ITEM, NSAccessibilityMenuItemRole );
+ MAP( AccessibleRole::OPTION_PANE, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::PAGE_TAB, NSAccessibilityButtonRole );
+ MAP( AccessibleRole::PAGE_TAB_LIST, NSAccessibilityTabGroupRole );
+ MAP( AccessibleRole::PANEL, NSAccessibilityGroupRole );
+ MAP( AccessibleRole::PARAGRAPH, NSAccessibilityTextAreaRole );
+ MAP( AccessibleRole::PASSWORD_TEXT, NSAccessibilityTextFieldRole );
+ MAP( AccessibleRole::POPUP_MENU, NSAccessibilityMenuRole );
+ MAP( AccessibleRole::PUSH_BUTTON, NSAccessibilityButtonRole );
+ MAP( AccessibleRole::PROGRESS_BAR, NSAccessibilityProgressIndicatorRole );
+ MAP( AccessibleRole::RADIO_BUTTON, NSAccessibilityRadioButtonRole );
+ MAP( AccessibleRole::RADIO_MENU_ITEM, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::ROW_HEADER, NSAccessibilityRowRole );
+ MAP( AccessibleRole::ROOT_PANE, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::SCROLL_BAR, NSAccessibilityScrollBarRole );
+ MAP( AccessibleRole::SCROLL_PANE, NSAccessibilityScrollAreaRole );
+ MAP( AccessibleRole::SHAPE, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::SEPARATOR, NSAccessibilitySplitterRole ); // FIXME
+ MAP( AccessibleRole::SLIDER, NSAccessibilitySliderRole );
+ MAP( AccessibleRole::SPIN_BOX, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::SPLIT_PANE, NSAccessibilitySplitterRole );
+ MAP( AccessibleRole::STATUS_BAR, NSAccessibilityGroupRole ); // FIXME
+ MAP( AccessibleRole::TABLE, NSAccessibilityTableRole );
+ MAP( AccessibleRole::TABLE_CELL, NSAccessibilityTextFieldRole );
+ MAP( AccessibleRole::TEXT, NSAccessibilityTextAreaRole );
+ MAP( AccessibleRole::TEXT_FRAME, NSAccessibilityGroupRole );
+ MAP( AccessibleRole::TOGGLE_BUTTON, NSAccessibilityCheckBoxRole );
+ MAP( AccessibleRole::TOOL_BAR, NSAccessibilityToolbarRole );
+ MAP( AccessibleRole::TOOL_TIP, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::TREE, NSAccessibilityGroupRole );
+ MAP( AccessibleRole::VIEW_PORT, NSAccessibilityUnknownRole ); // FIXME
+ MAP( AccessibleRole::WINDOW, NSAccessibilityWindowRole );
+
+ MAP( AccessibleRole::BUTTON_DROPDOWN, NSAccessibilityMenuButtonRole );
+ MAP( AccessibleRole::BUTTON_MENU, NSAccessibilityMenuButtonRole );
+ MAP( AccessibleRole::CAPTION, NSAccessibilityUnknownRole );
+ MAP( AccessibleRole::CHART, NSAccessibilityUnknownRole );
+ MAP( AccessibleRole::FORM, NSAccessibilityUnknownRole );
+ MAP( AccessibleRole::IMAGE_MAP, NSAccessibilityUnknownRole );
+ MAP( AccessibleRole::NOTE, NSAccessibilityUnknownRole );
+ MAP( AccessibleRole::PAGE, NSAccessibilityUnknownRole );
+ MAP( AccessibleRole::RULER, NSAccessibilityUnknownRole );
+ MAP( AccessibleRole::SECTION, NSAccessibilityUnknownRole );
+ MAP( AccessibleRole::TREE_ITEM, NSAccessibilityUnknownRole );
+ MAP( AccessibleRole::TREE_TABLE, NSAccessibilityUnknownRole );
+
+#undef MAP
+ default:
+ break;
+ }
+ return nativeRole;
+}
+
++(id)getNativeRoleFrom: (XAccessibleContext *) accessibleContext {
+ id nativeRole = [ AquaA11yRoleHelper simpleMapNativeRoleFrom: accessibleContext ];
+ if ( accessibleContext -> getAccessibleRole() == AccessibleRole::LABEL ) {
+ if ( accessibleContext -> getAccessibleChildCount() > 0 ) {
+ [ nativeRole release ];
+ nativeRole = NSAccessibilityOutlineRole;
+ } else if ( accessibleContext -> getAccessibleParent().is() ) {
+ Reference < XAccessibleContext > rxParentContext = accessibleContext -> getAccessibleParent() -> getAccessibleContext();
+ if ( rxParentContext.is() ) {
+ NSString * roleParent = (NSString *) [ AquaA11yRoleHelper simpleMapNativeRoleFrom: rxParentContext.get() ];
+ if ( [ roleParent isEqualToString: NSAccessibilityOutlineRole ] ) {
+ [ nativeRole release ];
+ nativeRole = NSAccessibilityRowRole;
+ }
+ [ roleParent release ];
+ }
+ }
+ } else if ( accessibleContext -> getAccessibleRole() == AccessibleRole::COMBO_BOX ) {
+ Reference < XAccessible > rxAccessible = accessibleContext -> getAccessibleChild(0);
+ if ( rxAccessible.is() ) {
+ Reference < XAccessibleContext > rxAccessibleContext = rxAccessible -> getAccessibleContext();
+ if ( rxAccessibleContext.is() && rxAccessibleContext -> getAccessibleRole() == AccessibleRole::TEXT ) {
+ if ( ! rxAccessibleContext -> getAccessibleStateSet() -> contains ( AccessibleStateType::EDITABLE ) ) {
+ [ nativeRole release ];
+ nativeRole = NSAccessibilityPopUpButtonRole;
+ }
+ }
+ }
+ }
+ return nativeRole;
+}
+
++(id)getNativeSubroleFrom: (sal_Int16) nRole {
+ id nativeSubrole = nil;
+ switch( nRole ) {
+#define MAP(a,b) \
+ case a: nativeSubrole = b; break
+
+ MAP( AccessibleRole::UNKNOWN, NSAccessibilityUnknownSubrole );
+ MAP( AccessibleRole::ALERT, NSAccessibilitySystemDialogSubrole );
+ MAP( AccessibleRole::COLUMN_HEADER, @"" );
+ MAP( AccessibleRole::CANVAS, @"" );
+ MAP( AccessibleRole::CHECK_BOX, @"" );
+ MAP( AccessibleRole::CHECK_MENU_ITEM, @"" );
+ MAP( AccessibleRole::COLOR_CHOOSER, @"" );
+ MAP( AccessibleRole::COMBO_BOX, @"" );
+ MAP( AccessibleRole::DATE_EDITOR, @"" );
+ MAP( AccessibleRole::DESKTOP_ICON, @"" );
+ MAP( AccessibleRole::DESKTOP_PANE, @"" );
+ MAP( AccessibleRole::DIRECTORY_PANE, @"" );
+ MAP( AccessibleRole::DIALOG, NSAccessibilityDialogSubrole );
+ MAP( AccessibleRole::DOCUMENT, @"" );
+ MAP( AccessibleRole::EMBEDDED_OBJECT, @"" );
+ MAP( AccessibleRole::END_NOTE, @"" );
+ MAP( AccessibleRole::FILE_CHOOSER, @"" );
+ MAP( AccessibleRole::FILLER, @"" );
+ MAP( AccessibleRole::FONT_CHOOSER, @"" );
+ MAP( AccessibleRole::FOOTER, @"" );
+ MAP( AccessibleRole::FOOTNOTE, @"" );
+ MAP( AccessibleRole::FRAME, @"" );
+ MAP( AccessibleRole::GLASS_PANE, @"" );
+ MAP( AccessibleRole::GRAPHIC, @"" );
+ MAP( AccessibleRole::GROUP_BOX, @"" );
+ MAP( AccessibleRole::HEADER, @"" );
+ MAP( AccessibleRole::HEADING, @"" );
+ MAP( AccessibleRole::HYPER_LINK, NSAccessibilityTextLinkSubrole );
+ MAP( AccessibleRole::ICON, @"" );
+ MAP( AccessibleRole::INTERNAL_FRAME, @"" );
+ MAP( AccessibleRole::LABEL, @"" );
+ MAP( AccessibleRole::LAYERED_PANE, @"" );
+ MAP( AccessibleRole::LIST, @"" );
+ MAP( AccessibleRole::LIST_ITEM, NSAccessibilityOutlineRowSubrole );
+ MAP( AccessibleRole::MENU, @"" );
+ MAP( AccessibleRole::MENU_BAR, @"" );
+ MAP( AccessibleRole::MENU_ITEM, @"" );
+ MAP( AccessibleRole::OPTION_PANE, @"" );
+ MAP( AccessibleRole::PAGE_TAB, @"" );
+ MAP( AccessibleRole::PAGE_TAB_LIST, @"" );
+ MAP( AccessibleRole::PANEL, @"" );
+ MAP( AccessibleRole::PARAGRAPH, @"" );
+ MAP( AccessibleRole::PASSWORD_TEXT, NSAccessibilitySecureTextFieldSubrole );
+ MAP( AccessibleRole::POPUP_MENU, @"" );
+ MAP( AccessibleRole::PUSH_BUTTON, @"" );
+ MAP( AccessibleRole::PROGRESS_BAR, @"" );
+ MAP( AccessibleRole::RADIO_BUTTON, @"" );
+ MAP( AccessibleRole::RADIO_MENU_ITEM, @"" );
+ MAP( AccessibleRole::ROW_HEADER, @"" );
+ MAP( AccessibleRole::ROOT_PANE, @"" );
+ MAP( AccessibleRole::SCROLL_BAR, @"" );
+ MAP( AccessibleRole::SCROLL_PANE, @"" );
+ MAP( AccessibleRole::SHAPE, @"" );
+ MAP( AccessibleRole::SEPARATOR, @"" );
+ MAP( AccessibleRole::SLIDER, @"" );
+ MAP( AccessibleRole::SPIN_BOX, @"" );
+ MAP( AccessibleRole::SPLIT_PANE, @"" );
+ MAP( AccessibleRole::STATUS_BAR, @"" );
+ MAP( AccessibleRole::TABLE, @"" );
+ MAP( AccessibleRole::TABLE_CELL, @"" );
+ MAP( AccessibleRole::TEXT, @"" );
+ MAP( AccessibleRole::TEXT_FRAME, @"" );
+ MAP( AccessibleRole::TOGGLE_BUTTON, @"" );
+ MAP( AccessibleRole::TOOL_BAR, @"" );
+ MAP( AccessibleRole::TOOL_TIP, @"" );
+ MAP( AccessibleRole::TREE, @"" );
+ MAP( AccessibleRole::VIEW_PORT, @"" );
+ MAP( AccessibleRole::WINDOW, NSAccessibilityStandardWindowSubrole );
+
+ MAP( AccessibleRole::BUTTON_DROPDOWN, @"" );
+ MAP( AccessibleRole::BUTTON_MENU, @"" );
+ MAP( AccessibleRole::CAPTION, @"" );
+ MAP( AccessibleRole::CHART, @"" );
+ MAP( AccessibleRole::FORM, @"" );
+ MAP( AccessibleRole::IMAGE_MAP, @"" );
+ MAP( AccessibleRole::NOTE, @"" );
+ MAP( AccessibleRole::PAGE, @"" );
+ MAP( AccessibleRole::RULER, @"" );
+ MAP( AccessibleRole::SECTION, @"" );
+ MAP( AccessibleRole::TREE_ITEM, @"" );
+ MAP( AccessibleRole::TREE_TABLE, @"" );
+
+#undef MAP
+ default:
+ break;
+ }
+ return nativeSubrole;
+}
+
++(id)getRoleDescriptionFrom: (NSString *) role with: (NSString *) subRole {
+ id roleDescription;
+ if ( [ subRole length ] == 0 )
+ roleDescription = NSAccessibilityRoleDescription( role, nil );
+ else
+ roleDescription = NSAccessibilityRoleDescription( role, subRole );
+ return roleDescription;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11yselectionwrapper.h b/vcl/aqua/source/a11y/aqua11yselectionwrapper.h
new file mode 100644
index 000000000000..a88e6c71c04b
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11yselectionwrapper.h
@@ -0,0 +1,43 @@
+/*************************************************************************
+ *
+ * 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_AQUA11SELECTIONWRAPPER_H
+#define _SV_AQUA11SELECTIONWRAPPER_H
+
+#include "aquavcltypes.h"
+#include "aqua11ywrapper.h"
+
+@interface AquaA11ySelectionWrapper : NSObject
+{
+}
++(id)selectedChildrenAttributeForElement:(AquaA11yWrapper *)wrapper;
++(void)addAttributeNamesTo:(NSMutableArray *)attributeNames;
++(MacOSBOOL)isAttributeSettable:(NSString *)attribute forElement:(AquaA11yWrapper *)wrapper;
++(void)setSelectedChildrenAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value;
+@end
+
+#endif // _SV_AQUA11SELECTIONWRAPPER_H
diff --git a/vcl/aqua/source/a11y/aqua11yselectionwrapper.mm b/vcl/aqua/source/a11y/aqua11yselectionwrapper.mm
new file mode 100644
index 000000000000..53ab6dd36128
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11yselectionwrapper.mm
@@ -0,0 +1,91 @@
+/*************************************************************************
+ *
+ * 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 "salinst.h"
+#include "aqua11yfactory.h"
+#include "aqua11yselectionwrapper.h"
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::uno;
+
+@implementation AquaA11ySelectionWrapper : NSObject
+
++(id)selectedChildrenAttributeForElement:(AquaA11yWrapper *)wrapper
+{
+ Reference< XAccessibleSelection > xAccessibleSelection = [ wrapper accessibleSelection ];
+ NSMutableArray * children = [ [ NSMutableArray alloc ] init ];
+
+ try {
+ sal_Int32 n = xAccessibleSelection -> getSelectedAccessibleChildCount();
+ for ( sal_Int32 i=0 ; i < n ; ++i ) {
+ [ children addObject: [ AquaA11yFactory wrapperForAccessible: xAccessibleSelection -> getSelectedAccessibleChild( i ) ] ];
+ }
+
+ return children;
+
+ } catch ( Exception& e) {
+ return nil;
+ }
+
+}
+
+
++(void)addAttributeNamesTo:(NSMutableArray *)attributeNames
+{
+ [ attributeNames addObject: NSAccessibilitySelectedChildrenAttribute ];
+}
+
++(MacOSBOOL)isAttributeSettable:(NSString *)attribute forElement:(AquaA11yWrapper *)wrapper
+{
+ if ( [ attribute isEqualToString: NSAccessibilitySelectedChildrenAttribute ] )
+ {
+ return YES;
+ }
+ else
+ {
+ return NO;
+ }
+}
+
++(void)setSelectedChildrenAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value
+{
+ Reference< XAccessibleSelection > xAccessibleSelection = [ wrapper accessibleSelection ];
+ try {
+ xAccessibleSelection -> clearAccessibleSelection();
+
+ unsigned c = [ value count ];
+ for ( unsigned i = 0 ; i < c ; ++i ) {
+ xAccessibleSelection -> selectAccessibleChild( [ [ value objectAtIndex: i ] accessibleContext ] -> getAccessibleIndexInParent() );
+ }
+ } catch ( Exception& e) {
+ }
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ytablewrapper.h b/vcl/aqua/source/a11y/aqua11ytablewrapper.h
new file mode 100644
index 000000000000..7bf3e44a2945
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ytablewrapper.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 _SV_AQUA11TABLEWRAPPER_H
+#define _SV_AQUA11TABLEWRAPPER_H
+
+#include "aqua11ywrapper.h"
+
+#define MAXIMUM_ACCESSIBLE_TABLE_CELLS 1000
+
+@interface AquaA11yTableWrapper : AquaA11yWrapper
+{
+}
++(id)childrenAttributeForElement:(AquaA11yTableWrapper *)wrapper;
++(void)addAttributeNamesTo: (NSMutableArray *)attributeNames object: (AquaA11yWrapper*)pObject;
+
+-(id)rowsAttribute;
+-(id)columnsAttribute;
+@end
+#endif // _SV_AQUA11TABLEWRAPPER_H
diff --git a/vcl/aqua/source/a11y/aqua11ytablewrapper.mm b/vcl/aqua/source/a11y/aqua11ytablewrapper.mm
new file mode 100644
index 000000000000..98454ab8d57b
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ytablewrapper.mm
@@ -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 "aqua11ytablewrapper.h"
+#include "aqua11yfactory.h"
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::uno;
+
+@implementation AquaA11yTableWrapper : AquaA11yWrapper
+
++(id)childrenAttributeForElement:(AquaA11yTableWrapper *)wrapper
+{
+ XAccessibleTable * accessibleTable = [ wrapper accessibleTable ];
+ NSArray* pResult = nil;
+ if( accessibleTable )
+ {
+ NSMutableArray * cells = [ [ NSMutableArray alloc ] init ];
+ try
+ {
+ sal_Int32 nRows = accessibleTable->getAccessibleRowCount();
+ sal_Int32 nCols = accessibleTable->getAccessibleColumnCount();
+
+ if( nRows * nCols < MAXIMUM_ACCESSIBLE_TABLE_CELLS )
+ {
+ // make all children visible to the hierarchy
+ for ( sal_Int32 rowCount = 0; rowCount < nRows; rowCount++ )
+ {
+ for ( sal_Int32 columnCount = 0; columnCount < nCols; columnCount++ )
+ {
+ Reference < XAccessible > rAccessibleCell = accessibleTable -> getAccessibleCellAt ( rowCount, columnCount );
+ if ( rAccessibleCell.is() )
+ {
+ id cell_wrapper = [ AquaA11yFactory wrapperForAccessibleContext: rAccessibleCell -> getAccessibleContext() ];
+ [ cells addObject: cell_wrapper ];
+ [ cell_wrapper release ];
+ }
+ }
+ }
+ }
+ else
+ {
+ XAccessibleComponent * accessibleComponent = [ wrapper accessibleComponent ];
+ // find out which cells are actually visible by determining the top-left-cell and the bottom-right-cell
+ Size tableSize = accessibleComponent -> getSize();
+ Point point;
+ point.X = 0;
+ point.Y = 0;
+ Reference < XAccessible > rAccessibleTopLeft = accessibleComponent -> getAccessibleAtPoint ( point );
+ point.X = tableSize.Width - 1;
+ point.Y = tableSize.Height - 1;
+ Reference < XAccessible > rAccessibleBottomRight = accessibleComponent -> getAccessibleAtPoint ( point );
+ if ( rAccessibleTopLeft.is() && rAccessibleBottomRight.is() )
+ {
+ sal_Int32 idxTopLeft = rAccessibleTopLeft -> getAccessibleContext() -> getAccessibleIndexInParent();
+ sal_Int32 idxBottomRight = rAccessibleBottomRight -> getAccessibleContext() -> getAccessibleIndexInParent();
+ sal_Int32 rowTopLeft = accessibleTable -> getAccessibleRow ( idxTopLeft );
+ sal_Int32 columnTopLeft = accessibleTable -> getAccessibleColumn ( idxTopLeft );
+ sal_Int32 rowBottomRight = accessibleTable -> getAccessibleRow ( idxBottomRight );
+ sal_Int32 columnBottomRight = accessibleTable -> getAccessibleColumn ( idxBottomRight );
+ // create an array containing the visible cells
+ for ( sal_Int32 rowCount = rowTopLeft; rowCount <= rowBottomRight; rowCount++ )
+ {
+ for ( sal_Int32 columnCount = columnTopLeft; columnCount <= columnBottomRight; columnCount++ )
+ {
+ Reference < XAccessible > rAccessibleCell = accessibleTable -> getAccessibleCellAt ( rowCount, columnCount );
+ if ( rAccessibleCell.is() )
+ {
+ id cell_wrapper = [ AquaA11yFactory wrapperForAccessibleContext: rAccessibleCell -> getAccessibleContext() ];
+ [ cells addObject: cell_wrapper ];
+ [ cell_wrapper release ];
+ }
+ }
+ }
+ }
+ }
+ pResult = NSAccessibilityUnignoredChildren( cells );
+ }
+ catch (const Exception &e)
+ {
+ }
+ [cells autorelease];
+ }
+
+ return pResult;
+}
+
++(void)addAttributeNamesTo: (NSMutableArray *)attributeNames object: (AquaA11yWrapper*)pObject
+{
+ XAccessibleTable * accessibleTable = [ pObject accessibleTable ];
+ if( accessibleTable )
+ {
+ sal_Int32 nRows = accessibleTable->getAccessibleRowCount();
+ sal_Int32 nCols = accessibleTable->getAccessibleColumnCount();
+
+
+ if( nRows*nCols < MAXIMUM_ACCESSIBLE_TABLE_CELLS )
+ {
+ [ attributeNames addObject: NSAccessibilityRowsAttribute ];
+ [ attributeNames addObject: NSAccessibilityColumnsAttribute ];
+ }
+ }
+}
+
+-(id)rowsAttribute
+{
+ NSArray* pResult = nil;
+
+ XAccessibleTable * accessibleTable = [ self accessibleTable ];
+ if( accessibleTable )
+ {
+ sal_Int32 nRows = accessibleTable->getAccessibleRowCount();
+ sal_Int32 nCols = accessibleTable->getAccessibleColumnCount();
+ if( nRows * nCols < MAXIMUM_ACCESSIBLE_TABLE_CELLS )
+ {
+ NSMutableArray * cells = [ [ NSMutableArray alloc ] init ];
+ try
+ {
+ // find out number of rows
+ sal_Int32 nRows = accessibleTable->getAccessibleRowCount();
+ for( sal_Int32 n = 0; n < nRows; n++ )
+ {
+ Reference < XAccessible > rAccessibleCell = accessibleTable -> getAccessibleCellAt ( n, 0 );
+ if ( rAccessibleCell.is() )
+ {
+ id cell_wrapper = [ AquaA11yFactory wrapperForAccessibleContext: rAccessibleCell -> getAccessibleContext() ];
+ [ cells addObject: cell_wrapper ];
+ [ cell_wrapper release ];
+ }
+ }
+ pResult = NSAccessibilityUnignoredChildren( cells );
+ }
+ catch (const Exception &e)
+ {
+ pResult = nil;
+ }
+ [ cells autorelease ];
+ }
+ }
+
+ return pResult;
+}
+
+-(id)columnsAttribute
+{
+ NSArray* pResult = nil;
+
+ XAccessibleTable * accessibleTable = [ self accessibleTable ];
+
+ if( accessibleTable )
+ {
+ sal_Int32 nRows = accessibleTable->getAccessibleRowCount();
+ sal_Int32 nCols = accessibleTable->getAccessibleColumnCount();
+ if( nRows * nCols < MAXIMUM_ACCESSIBLE_TABLE_CELLS )
+ {
+ NSMutableArray * cells = [ [ NSMutableArray alloc ] init ];
+ try
+ {
+ // find out number of columns
+ for( sal_Int32 n = 0; n < nCols; n++ )
+ {
+ Reference < XAccessible > rAccessibleCell = accessibleTable -> getAccessibleCellAt ( 0, n );
+ if ( rAccessibleCell.is() )
+ {
+ id cell_wrapper = [ AquaA11yFactory wrapperForAccessibleContext: rAccessibleCell -> getAccessibleContext() ];
+ [ cells addObject: cell_wrapper ];
+ [ cell_wrapper release ];
+ }
+ }
+ pResult = NSAccessibilityUnignoredChildren( cells );
+ }
+ catch (const Exception &e)
+ {
+ pResult = nil;
+ }
+ [ cells autorelease ];
+ }
+ }
+
+ return pResult;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ytextattributeswrapper.h b/vcl/aqua/source/a11y/aqua11ytextattributeswrapper.h
new file mode 100644
index 000000000000..fcf185ca5478
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ytextattributeswrapper.h
@@ -0,0 +1,39 @@
+/*************************************************************************
+ *
+ * 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_AQUA11TEXTATTRIBUTESWRAPPER_H
+#define _SV_AQUA11TEXTATTRIBUTESWRAPPER_H
+
+#include <com/sun/star/uno/Sequence.hxx>
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yTextAttributesWrapper : NSObject
+{
+}
++(NSMutableAttributedString *)createAttributedStringForElement:(AquaA11yWrapper *)wrapper inOrigRange:(id)origRange;
+@end
+#endif // _SV_AQUA11TEXTATTRIBUTESWRAPPER_H
diff --git a/vcl/aqua/source/a11y/aqua11ytextattributeswrapper.mm b/vcl/aqua/source/a11y/aqua11ytextattributeswrapper.mm
new file mode 100644
index 000000000000..6577cebf295e
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ytextattributeswrapper.mm
@@ -0,0 +1,254 @@
+/*************************************************************************
+ *
+ * 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 "aqua11ytextattributeswrapper.h"
+#include "salinst.h"
+#include <com/sun/star/accessibility/AccessibleTextType.hpp>
+#include <com/sun/star/awt/FontUnderline.hpp>
+#include <com/sun/star/awt/FontWeight.hpp>
+#include <com/sun/star/awt/FontStrikeout.hpp>
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+using namespace ::rtl;
+
+@implementation AquaA11yTextAttributesWrapper : NSObject
+
++(int)convertUnderlineStyle:(PropertyValue)property {
+ int underlineStyle = NSNoUnderlineStyle;
+ sal_Int16 value = 0;
+ property.Value >>= value;
+ if ( value != FontUnderline::NONE
+ && value != FontUnderline::DONTKNOW) {
+ underlineStyle = NSSingleUnderlineStyle;
+ }
+ return underlineStyle;
+}
+
++(int)convertBoldStyle:(PropertyValue)property {
+ int boldStyle = 0;
+ float value = 0;
+ property.Value >>= value;
+ if ( value == FontWeight::SEMIBOLD
+ || value == FontWeight::BOLD
+ || value == FontWeight::ULTRABOLD
+ || value == FontWeight::BLACK ) {
+ boldStyle = NSBoldFontMask;
+ }
+ return boldStyle;
+}
+
++(int)convertItalicStyle:(PropertyValue)property {
+ int italicStyle = 0;
+ sal_Int16 value = property.Value.get<FontSlant>();
+ if ( value == FontSlant_ITALIC ) {
+ italicStyle = NSItalicFontMask;
+ }
+ return italicStyle;
+}
+
++(MacOSBOOL)isStrikethrough:(PropertyValue)property {
+ MacOSBOOL strikethrough = NO;
+ sal_Int16 value = 0;
+ property.Value >>= value;
+ if ( value != FontStrikeout::NONE
+ && value != FontStrikeout::DONTKNOW ) {
+ strikethrough = YES;
+ }
+ return strikethrough;
+}
+
++(MacOSBOOL)convertBoolean:(PropertyValue)property {
+ MacOSBOOL myBoolean = NO;
+ bool value = sal_False;
+ property.Value >>= value;
+ if ( value ) {
+ myBoolean = YES;
+ }
+ return myBoolean;
+}
+
++(NSNumber *)convertShort:(PropertyValue)property {
+ sal_Int16 value = 0;
+ property.Value >>= value;
+ return [ NSNumber numberWithShort: value ];
+}
+
++(void)addColor:(sal_Int32)salColor forAttribute:(NSString *)attribute andRange:(NSRange)range toString:(NSMutableAttributedString *)string {
+ if ( salColor != -1 ) {
+ float elements[] = { salColor & 0x00ff0000, salColor & 0x0000ff00, salColor & 0x000000ff };
+ CGColorRef color = CGColorCreate ( CGColorSpaceCreateWithName ( kCGColorSpaceGenericRGB ), elements );
+ [ string addAttribute: attribute value: (id) color range: range ];
+ CGColorRelease ( color );
+ }
+}
+
++(void)addFont:(NSFont *)font toString:(NSMutableAttributedString *)string forRange:(NSRange)range {
+ if ( font != nil ) {
+ NSDictionary * fontDictionary = [ NSDictionary dictionaryWithObjectsAndKeys:
+ [ font fontName ], NSAccessibilityFontNameKey,
+ [ font familyName ], NSAccessibilityFontFamilyKey,
+ [ font displayName ], NSAccessibilityVisibleNameKey,
+ [ NSNumber numberWithFloat: [ font pointSize ] ], NSAccessibilityFontSizeKey,
+ nil
+ ];
+ [ string addAttribute: NSAccessibilityFontTextAttribute
+ value: fontDictionary
+ range: range
+ ];
+ }
+}
+
++(void)applyAttributesFrom:(Sequence < PropertyValue >)attributes toString:(NSMutableAttributedString *)string forRange:(NSRange)range storeDefaultsTo:(AquaA11yWrapper *)wrapperStore getDefaultsFrom:(AquaA11yWrapper *)wrapper {
+ NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ];
+ // constants
+ static const OUString attrUnderline = OUString::createFromAscii("CharUnderline");
+ static const OUString attrBold = OUString::createFromAscii("CharWeight");
+ static const OUString attrFontname = OUString::createFromAscii("CharFontName");
+ static const OUString attrItalic = OUString::createFromAscii("CharPosture");
+ static const OUString attrHeight = OUString::createFromAscii("CharHeight");
+ static const OUString attrStrikethrough = OUString::createFromAscii("CharStrikeout");
+ static const OUString attrShadow = OUString::createFromAscii("CharShadowed");
+ static const OUString attrUnderlineColor = OUString::createFromAscii("CharUnderlineColor");
+ static const OUString attrUnderlineHasColor = OUString::createFromAscii("CharUnderlineHasColor");
+ static const OUString attrForegroundColor = OUString::createFromAscii("CharColor");
+ static const OUString attrBackgroundColor = OUString::createFromAscii("CharBackColor");
+ static const OUString attrSuperscript = OUString::createFromAscii("CharEscapement");
+ // vars
+ OUString fontname;
+ int fonttraits = 0;
+ float fontsize = 0.0;
+ sal_Int32 underlineColor = 0;
+ MacOSBOOL underlineHasColor = NO;
+ // add attributes to string
+ for ( int attrIndex = 0; attrIndex < attributes.getLength(); attrIndex++ ) {
+ PropertyValue property = attributes [ attrIndex ];
+ // TODO: NSAccessibilityMisspelledTextAttribute, NSAccessibilityAttachmentTextAttribute, NSAccessibilityLinkTextAttribute
+ // NSAccessibilityStrikethroughColorTextAttribute is unsupported by UNP-API
+ if ( property.Value.hasValue() ) {
+ if ( property.Name.equals ( attrUnderline ) ) {
+ int style = [ AquaA11yTextAttributesWrapper convertUnderlineStyle: property ];
+ if ( style != NSNoUnderlineStyle ) {
+ [ string addAttribute: NSAccessibilityUnderlineTextAttribute value: [ NSNumber numberWithInt: style ] range: range ];
+ }
+ } else if ( property.Name.equals ( attrFontname ) ) {
+ property.Value >>= fontname;
+ } else if ( property.Name.equals ( attrBold ) ) {
+ fonttraits |= [ AquaA11yTextAttributesWrapper convertBoldStyle: property ];
+ } else if ( property.Name.equals ( attrItalic ) ) {
+ fonttraits |= [ AquaA11yTextAttributesWrapper convertItalicStyle: property ];
+ } else if ( property.Name.equals ( attrHeight ) ) {
+ property.Value >>= fontsize;
+ } else if ( property.Name.equals ( attrStrikethrough ) ) {
+ if ( [ AquaA11yTextAttributesWrapper isStrikethrough: property ] ) {
+ [ string addAttribute: NSAccessibilityStrikethroughTextAttribute value: [ NSNumber numberWithBool: YES ] range: range ];
+ }
+ } else if ( property.Name.equals ( attrShadow ) ) {
+ if ( [ AquaA11yTextAttributesWrapper convertBoolean: property ] ) {
+ [ string addAttribute: NSAccessibilityShadowTextAttribute value: [ NSNumber numberWithBool: YES ] range: range ];
+ }
+ } else if ( property.Name.equals ( attrUnderlineColor ) ) {
+ property.Value >>= underlineColor;
+ } else if ( property.Name.equals ( attrUnderlineHasColor ) ) {
+ underlineHasColor = [ AquaA11yTextAttributesWrapper convertBoolean: property ];
+ } else if ( property.Name.equals ( attrForegroundColor ) ) {
+ [ AquaA11yTextAttributesWrapper addColor: property.Value.get<sal_Int32>() forAttribute: NSAccessibilityForegroundColorTextAttribute andRange: range toString: string ];
+ } else if ( property.Name.equals ( attrBackgroundColor ) ) {
+ [ AquaA11yTextAttributesWrapper addColor: property.Value.get<sal_Int32>() forAttribute: NSAccessibilityBackgroundColorTextAttribute andRange: range toString: string ];
+ } else if ( property.Name.equals ( attrSuperscript ) ) {
+ // values < zero mean subscript
+ // values > zero mean superscript
+ // this is true for both NSAccessibility-API and UNO-API
+ NSNumber * number = [ AquaA11yTextAttributesWrapper convertShort: property ];
+ if ( [ number shortValue ] != 0 ) {
+ [ string addAttribute: NSAccessibilitySuperscriptTextAttribute value: number range: range ];
+ }
+ }
+ }
+ }
+ // add underline information
+ if ( underlineHasColor ) {
+ [ AquaA11yTextAttributesWrapper addColor: underlineColor forAttribute: NSAccessibilityUnderlineColorTextAttribute andRange: range toString: string ];
+ }
+ // add font information
+ if ( wrapperStore != nil ) { // default
+ [ wrapperStore setDefaultFontname: CreateNSString ( fontname ) ];
+ [ wrapperStore setDefaultFontsize: fontsize ];
+ NSFont * font = [ [ NSFontManager sharedFontManager ] fontWithFamily: CreateNSString ( fontname ) traits: fonttraits weight: 0 size: fontsize ];
+ [ AquaA11yTextAttributesWrapper addFont: font toString: string forRange: range ];
+ } else if ( wrapper != nil && fonttraits != 0 ) { // attribute run and bold and/or italic was found
+ NSFont * font = [ [ NSFontManager sharedFontManager ] fontWithFamily: [ wrapper defaultFontname ] traits: fonttraits weight: 0 size: [ wrapper defaultFontsize ] ];
+ [ AquaA11yTextAttributesWrapper addFont: font toString: string forRange: range ];
+ }
+ [ pool release ];
+}
+
++(NSMutableAttributedString *)createAttributedStringForElement:(AquaA11yWrapper *)wrapper inOrigRange:(id)origRange {
+ static const Sequence < OUString > emptySequence;
+ // vars
+ NSMutableAttributedString * string = nil;
+ int loc = [ origRange rangeValue ].location;
+ int len = [ origRange rangeValue ].length;
+ int endIndex = loc + len;
+ int currentIndex = loc;
+ try {
+ NSString * myString = CreateNSString ( [ wrapper accessibleText ] -> getText() ); // TODO: dirty fix for i87817
+ string = [ [ NSMutableAttributedString alloc ] initWithString: CreateNSString ( [ wrapper accessibleText ] -> getTextRange ( loc, loc + len ) ) ];
+ if ( [ wrapper accessibleTextAttributes ] != nil && [myString characterAtIndex:0] != 57361) { // TODO: dirty fix for i87817
+ [ string beginEditing ];
+ // add default attributes for whole string
+ Sequence < PropertyValue > defaultAttributes = [ wrapper accessibleTextAttributes ] -> getDefaultAttributes ( emptySequence );
+ [ AquaA11yTextAttributesWrapper applyAttributesFrom: defaultAttributes toString: string forRange: [ origRange rangeValue ] storeDefaultsTo: wrapper getDefaultsFrom: nil ];
+ // add attributes for attribute run(s)
+ while ( currentIndex < endIndex ) {
+ TextSegment textSegment = [ wrapper accessibleText ] -> getTextAtIndex ( currentIndex, AccessibleTextType::ATTRIBUTE_RUN );
+ int endOfRange = endIndex > textSegment.SegmentEnd ? textSegment.SegmentEnd : endIndex;
+ NSRange rangeForAttributeRun = NSMakeRange ( currentIndex, endOfRange - currentIndex );
+ // add run attributes
+ Sequence < PropertyValue > attributes = [ wrapper accessibleTextAttributes ] -> getRunAttributes ( currentIndex, emptySequence );
+ [ AquaA11yTextAttributesWrapper applyAttributesFrom: attributes toString: string forRange: rangeForAttributeRun storeDefaultsTo: nil getDefaultsFrom: wrapper ];
+ currentIndex = textSegment.SegmentEnd;
+ }
+ [ string endEditing ];
+ }
+ } catch ( IllegalArgumentException & e ) {
+ // empty
+ } catch ( IndexOutOfBoundsException & e ) {
+ // empty
+ } catch ( RuntimeException& ) {
+ // at least don't crash
+ }
+ return string;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ytextwrapper.h b/vcl/aqua/source/a11y/aqua11ytextwrapper.h
new file mode 100644
index 000000000000..dfdab349bafe
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ytextwrapper.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11TEXTWRAPPER_H
+#define _SV_AQUA11TEXTWRAPPER_H
+
+#include "aquavcltypes.h"
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yTextWrapper : NSObject
+{
+}
++(id)valueAttributeForElement:(AquaA11yWrapper *)wrapper;
++(id)numberOfCharactersAttributeForElement:(AquaA11yWrapper *)wrapper;
++(id)selectedTextAttributeForElement:(AquaA11yWrapper *)wrapper;
++(id)selectedTextRangeAttributeForElement:(AquaA11yWrapper *)wrapper;
++(id)visibleCharacterRangeAttributeForElement:(AquaA11yWrapper *)wrapper;
++(id)sharedTextUIElementsAttributeForElement:(AquaA11yWrapper *)wrapper;
++(id)sharedCharacterRangeAttributeForElement:(AquaA11yWrapper *)wrapper;
++(id)stringForRangeAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)range;
++(id)attributedStringForRangeAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)range;
++(id)rangeForIndexAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)index;
++(id)rangeForPositionAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)point;
++(id)boundsForRangeAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)range;
++(id)styleRangeForIndexAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)index;
++(id)rTFForRangeAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)range;
++(id)lineForIndexAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)index;
++(id)rangeForLineAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)line;
++(void)addAttributeNamesTo:(NSMutableArray *)attributeNames;
++(void)addParameterizedAttributeNamesTo:(NSMutableArray *)attributeNames;
++(NSArray *)specialAttributeNames;
++(NSArray *)specialParameterizedAttributeNames;
++(MacOSBOOL)isAttributeSettable:(NSString *)attribute forElement:(AquaA11yWrapper *)wrapper;
++(void)setVisibleCharacterRangeAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value;
++(void)setSelectedTextRangeAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value;
++(void)setSelectedTextAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value;
++(void)setValueAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value;
+@end
+
+#endif // _SV_AQUA11TEXTWRAPPER_H
diff --git a/vcl/aqua/source/a11y/aqua11ytextwrapper.mm b/vcl/aqua/source/a11y/aqua11ytextwrapper.mm
new file mode 100644
index 000000000000..2033135564d8
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ytextwrapper.mm
@@ -0,0 +1,289 @@
+/*************************************************************************
+ *
+ * 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 "salinst.h"
+#include "aqua11ytextwrapper.h"
+#include "aqua11ytextattributeswrapper.h"
+#include "aqua11yutil.h"
+#include <com/sun/star/accessibility/AccessibleTextType.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+using namespace ::rtl;
+
+// Wrapper for XAccessibleText, XAccessibleEditableText and XAccessibleMultiLineText
+
+@implementation AquaA11yTextWrapper : NSObject
+
++(id)valueAttributeForElement:(AquaA11yWrapper *)wrapper {
+ return CreateNSString ( [ wrapper accessibleText ] -> getText() );
+}
+
++(void)setValueAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value {
+ // TODO
+}
+
++(id)numberOfCharactersAttributeForElement:(AquaA11yWrapper *)wrapper {
+ return [ NSNumber numberWithLong: [ wrapper accessibleText ] -> getCharacterCount() ];
+}
+
++(id)selectedTextAttributeForElement:(AquaA11yWrapper *)wrapper {
+ return CreateNSString ( [ wrapper accessibleText ] -> getSelectedText() );
+}
+
++(void)setSelectedTextAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value {
+ if ( [ wrapper accessibleEditableText ] != nil ) {
+ NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ];
+ OUString newText = GetOUString ( (NSString *) value );
+ NSRange selectedTextRange = [ [ AquaA11yTextWrapper selectedTextRangeAttributeForElement: wrapper ] rangeValue ];
+ try {
+ [ wrapper accessibleEditableText ] -> replaceText ( selectedTextRange.location, selectedTextRange.location + selectedTextRange.length, newText );
+ } catch ( const Exception & e ) {
+ // empty
+ }
+ [ pool release ];
+ }
+}
+
++(id)selectedTextRangeAttributeForElement:(AquaA11yWrapper *)wrapper {
+ sal_Int32 start = [ wrapper accessibleText ] -> getSelectionStart();
+ sal_Int32 end = [ wrapper accessibleText ] -> getSelectionEnd();
+ if ( start != end ) {
+ return [ NSValue valueWithRange: NSMakeRange ( start, end - start ) ]; // true selection
+ } else {
+ long caretPos = [ wrapper accessibleText ] -> getCaretPosition();
+ if ( caretPos < 0 || caretPos > [ wrapper accessibleText ] -> getCharacterCount() ) {
+ return nil;
+ }
+ return [ NSValue valueWithRange: NSMakeRange ( caretPos, 0 ) ]; // insertion point
+ }
+}
+
++(void)setSelectedTextRangeAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value {
+ NSRange range = [ value rangeValue ];
+ try {
+ [ wrapper accessibleText ] -> setSelection ( range.location, range.location + range.length );
+ } catch ( const Exception & e ) {
+ // empty
+ }
+}
+
++(id)visibleCharacterRangeAttributeForElement:(AquaA11yWrapper *)wrapper {
+ // the OOo a11y API returns only the visible portion...
+ return [ NSValue valueWithRange: NSMakeRange ( 0, [ wrapper accessibleText ] -> getCharacterCount() ) ];
+}
+
++(void)setVisibleCharacterRangeAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value {
+ // do nothing
+}
+
++(id)sharedTextUIElementsAttributeForElement:(AquaA11yWrapper *)wrapper {
+ return [ [ NSArray alloc ] init ]; // unsupported
+}
+
++(id)sharedCharacterRangeAttributeForElement:(AquaA11yWrapper *)wrapper {
+ return [ NSValue valueWithRange: NSMakeRange ( 0, 0 ) ]; // unsupported
+}
+
++(void)addAttributeNamesTo:(NSMutableArray *)attributeNames {
+ [ attributeNames addObjectsFromArray: [ AquaA11yTextWrapper specialAttributeNames ] ];
+}
+
++(NSArray *)specialAttributeNames {
+ return [ NSArray arrayWithObjects:
+ NSAccessibilityValueAttribute,
+ NSAccessibilityNumberOfCharactersAttribute,
+ NSAccessibilitySelectedTextAttribute,
+ NSAccessibilitySelectedTextRangeAttribute,
+ NSAccessibilityVisibleCharacterRangeAttribute,
+ NSAccessibilitySharedTextUIElementsAttribute,
+ NSAccessibilitySharedCharacterRangeAttribute,
+ nil ];
+}
+
++(void)addParameterizedAttributeNamesTo:(NSMutableArray *)attributeNames {
+ [ attributeNames addObjectsFromArray: [ AquaA11yTextWrapper specialParameterizedAttributeNames ] ];
+}
+
++(NSArray *)specialParameterizedAttributeNames {
+ return [ NSArray arrayWithObjects:
+ NSAccessibilityStringForRangeParameterizedAttribute,
+ NSAccessibilityAttributedStringForRangeParameterizedAttribute,
+ NSAccessibilityRangeForIndexParameterizedAttribute,
+ NSAccessibilityRangeForPositionParameterizedAttribute,
+ NSAccessibilityBoundsForRangeParameterizedAttribute,
+ NSAccessibilityStyleRangeForIndexParameterizedAttribute,
+ NSAccessibilityRTFForRangeParameterizedAttribute,
+ NSAccessibilityLineForIndexParameterizedAttribute,
+ NSAccessibilityRangeForLineParameterizedAttribute,
+ nil ];
+}
+
++(id)lineForIndexAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)index {
+ NSNumber * lineNumber = nil;
+ try {
+ sal_Int32 line = [ wrapper accessibleMultiLineText ] -> getLineNumberAtIndex ( (sal_Int32) [ index intValue ] );
+ lineNumber = [ NSNumber numberWithInt: line ];
+ } catch ( IndexOutOfBoundsException & e ) {
+ // empty
+ }
+ return lineNumber;
+}
+
++(id)rangeForLineAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)line {
+ NSValue * range = nil;
+ try {
+ TextSegment textSegment = [ wrapper accessibleMultiLineText ] -> getTextAtLineNumber ( [ line intValue ] );
+ range = [ NSValue valueWithRange: NSMakeRange ( textSegment.SegmentStart, textSegment.SegmentEnd - textSegment.SegmentStart ) ];
+ } catch ( IndexOutOfBoundsException & e ) {
+ // empty
+ }
+ return range;
+}
+
++(id)stringForRangeAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)range {
+ int loc = [ range rangeValue ].location;
+ int len = [ range rangeValue ].length;
+ NSMutableString * textRange = [ [ NSMutableString alloc ] init ];
+ try {
+ [ textRange appendString: CreateNSString ( [ wrapper accessibleText ] -> getTextRange ( loc, loc + len ) ) ];
+ } catch ( IndexOutOfBoundsException & e ) {
+ // empty
+ }
+ return textRange;
+}
+
++(id)attributedStringForRangeAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)range {
+ return [ AquaA11yTextAttributesWrapper createAttributedStringForElement: wrapper inOrigRange: range ];
+}
+
++(id)rangeForIndexAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)index {
+ NSValue * range = nil;
+ try {
+ TextSegment textSegment = [ wrapper accessibleText ] -> getTextBeforeIndex ( [ index intValue ], AccessibleTextType::GLYPH );
+ range = [ NSValue valueWithRange: NSMakeRange ( textSegment.SegmentStart, textSegment.SegmentEnd - textSegment.SegmentStart ) ];
+ } catch ( IndexOutOfBoundsException & e ) {
+ // empty
+ } catch ( IllegalArgumentException & e ) {
+ // empty
+ }
+ return range;
+}
+
++(id)rangeForPositionAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)point {
+ NSValue * value = nil;
+ sal_Int32 index = [ wrapper accessibleText ] -> getIndexAtPoint ( [ AquaA11yUtil nsPointToVclPoint: point ] );
+ if ( index > -1 ) {
+ value = [ AquaA11yTextWrapper rangeForIndexAttributeForElement: wrapper forParameter: [ NSNumber numberWithLong: index ] ];
+ }
+ return value;
+}
+
++(id)boundsForRangeAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)range {
+ NSValue * rect = nil;
+ try {
+ // TODO: this is ugly!!!
+ // the UNP-API can only return the bounds for a single character, not for a range
+ int loc = [ range rangeValue ].location;
+ int len = [ range rangeValue ].length;
+ int minx = 0x7fffffff, miny = 0x7fffffff, maxx = 0, maxy = 0;
+ for ( int i = 0; i < len; i++ ) {
+ Rectangle vclRect = [ wrapper accessibleText ] -> getCharacterBounds ( loc + i );
+ if ( vclRect.X < minx ) {
+ minx = vclRect.X;
+ }
+ if ( vclRect.Y < miny ) {
+ miny = vclRect.Y;
+ }
+ if ( vclRect.Width + vclRect.X > maxx ) {
+ maxx = vclRect.Width + vclRect.X;
+ }
+ if ( vclRect.Height + vclRect.Y > maxy ) {
+ maxy = vclRect.Height + vclRect.Y;
+ }
+ }
+ if ( [ wrapper accessibleComponent ] != nil ) {
+ // get location on screen (must be added since get CharacterBounds returns values relative to parent)
+ Point screenPos = [ wrapper accessibleComponent ] -> getLocationOnScreen();
+ Point pos ( minx + screenPos.X, miny + screenPos.Y );
+ Point size ( maxx - minx, maxy - miny );
+ NSValue * nsPos = [ AquaA11yUtil vclPointToNSPoint: pos ];
+ rect = [ NSValue valueWithRect: NSMakeRect ( [ nsPos pointValue ].x, [ nsPos pointValue ].y - size.Y, size.X, size.Y ) ];
+ //printf("Range: %s --- Rect: %s\n", [ NSStringFromRange ( [ range rangeValue ] ) UTF8String ], [ NSStringFromRect ( [ rect rectValue ] ) UTF8String ]);
+ }
+ } catch ( IndexOutOfBoundsException & e ) {
+ // empty
+ }
+ return rect;
+}
+
++(id)styleRangeForIndexAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)index {
+ NSValue * range = nil;
+ try {
+ TextSegment textSegment = [ wrapper accessibleText ] -> getTextAtIndex ( [ index intValue ], AccessibleTextType::ATTRIBUTE_RUN );
+ range = [ NSValue valueWithRange: NSMakeRange ( textSegment.SegmentStart, textSegment.SegmentEnd - textSegment.SegmentStart ) ];
+ } catch ( IndexOutOfBoundsException & e ) {
+ // empty
+ } catch ( IllegalArgumentException & e ) {
+ // empty
+ }
+ return range;
+}
+
++(id)rTFForRangeAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)range {
+ NSData * rtfData = nil;
+ NSAttributedString * attrString = (NSAttributedString *) [ AquaA11yTextWrapper attributedStringForRangeAttributeForElement: wrapper forParameter: range ];
+ if ( attrString != nil ) {
+ @try {
+ rtfData = [ attrString RTFFromRange: [ range rangeValue ] documentAttributes: nil ];
+ } @catch ( NSException * e) {
+ // emtpy
+ }
+ }
+ return rtfData;
+}
+
++(MacOSBOOL)isAttributeSettable:(NSString *)attribute forElement:(AquaA11yWrapper *)wrapper {
+ MacOSBOOL isSettable = NO;
+ if ( [ attribute isEqualToString: NSAccessibilityValueAttribute ]
+ || [ attribute isEqualToString: NSAccessibilitySelectedTextAttribute ]
+ || [ attribute isEqualToString: NSAccessibilitySelectedTextRangeAttribute ]
+ || [ attribute isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute ] ) {
+ if ( ! [ [ wrapper accessibilityAttributeValue: NSAccessibilityRoleAttribute ] isEqualToString: NSAccessibilityStaticTextRole ] ) {
+ isSettable = YES;
+ }
+ }
+ return isSettable;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11yutil.h b/vcl/aqua/source/a11y/aqua11yutil.h
new file mode 100644
index 000000000000..adf565f4d9bb
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11yutil.h
@@ -0,0 +1,39 @@
+/*************************************************************************
+ *
+ * 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_AQUA11YUTIL_H
+#define _SV_AQUA11YUTIL_H
+
+#include <com/sun/star/awt/Point.hpp>
+
+@interface AquaA11yUtil : NSObject {
+}
++(NSValue *)vclPointToNSPoint:(::com::sun::star::awt::Point)vclPoint;
++(::com::sun::star::awt::Point)nsPointToVclPoint:(NSValue *)nsPoint;
+@end
+
+#endif // _SV_AQUA11YUTIL_H \ No newline at end of file
diff --git a/vcl/aqua/source/a11y/aqua11yutil.mm b/vcl/aqua/source/a11y/aqua11yutil.mm
new file mode 100644
index 000000000000..4749a3b40822
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11yutil.mm
@@ -0,0 +1,53 @@
+/*************************************************************************
+ *
+ * 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 "aquavcltypes.h"
+#include "aqua11yutil.h"
+
+using namespace ::com::sun::star::awt;
+
+@implementation AquaA11yUtil : NSObject
+
+// TODO: should be merged with AquaSalFrame::VCLToCocoa... to a general helper method
++(NSValue *)vclPointToNSPoint:(Point)vclPoint {
+ // VCL coordinates are in upper-left-notation, Cocoa likes it the Cartesian way (lower-left)
+ NSRect screenRect = [ [ NSScreen mainScreen ] frame ];
+ NSPoint nsPoint = NSMakePoint ( (float) vclPoint.X, (float) ( screenRect.size.height - vclPoint.Y ) );
+ return [ NSValue valueWithPoint: nsPoint ];
+}
+
+// TODO: should be merged with AquaSalFrame::VCLToCocoa... to a general helper method
++(Point)nsPointToVclPoint:(NSValue *)nsPoint {
+ // VCL coordinates are in upper-left-notation, Cocoa likes it the Cartesian way (lower-left)
+ NSRect screenRect = [ [ NSScreen mainScreen ] frame ];
+ return Point ( static_cast<long>([ nsPoint pointValue ].x), static_cast<long>(screenRect.size.height - [ nsPoint pointValue ].y) );
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11yvaluewrapper.h b/vcl/aqua/source/a11y/aqua11yvaluewrapper.h
new file mode 100644
index 000000000000..d3afebf7f828
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11yvaluewrapper.h
@@ -0,0 +1,46 @@
+/*************************************************************************
+ *
+ * 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_AQUA11VALUEWRAPPER_H
+#define _SV_AQUA11VALUEWRAPPER_H
+
+#include "salinst.h"
+#include "aquavcltypes.h"
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yValueWrapper : NSObject
+{
+}
++(id)valueAttributeForElement:(AquaA11yWrapper *)wrapper;
++(id)minValueAttributeForElement:(AquaA11yWrapper *)wrapper;
++(id)maxValueAttributeForElement:(AquaA11yWrapper *)wrapper;
++(void)addAttributeNamesTo:(NSMutableArray *)attributeNames;
++(MacOSBOOL)isAttributeSettable:(NSString *)attribute forElement:(AquaA11yWrapper *)wrapper;
++(void)setValueAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value;
+@end
+
+#endif // _SV_AQUA11VALUEWRAPPER_H
diff --git a/vcl/aqua/source/a11y/aqua11yvaluewrapper.mm b/vcl/aqua/source/a11y/aqua11yvaluewrapper.mm
new file mode 100644
index 000000000000..85ef0041da95
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11yvaluewrapper.mm
@@ -0,0 +1,95 @@
+/*************************************************************************
+ *
+ * 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 "aqua11yvaluewrapper.h"
+#include "aqua11ywrapperstatictext.h"
+
+using namespace ::com::sun::star::uno;
+
+// Wrapper for XAccessibleValue
+// Remember: A UNO-Value is a single numeric value. Regarding the Mac A11y-API, a value can be anything!
+
+@implementation AquaA11yValueWrapper : NSObject
+
++(id)valueAttributeForElement:(AquaA11yWrapper *)wrapper {
+ // TODO: Detect Type from Any
+ if ( [ wrapper accessibleValue ] != nil ) {
+ long value = 0;
+ [ wrapper accessibleValue ] -> getCurrentValue() >>= value;
+ return [ NSNumber numberWithLong: value ];
+ }
+ return [ NSNumber numberWithLong: 0 ];
+}
+
++(id)minValueAttributeForElement:(AquaA11yWrapper *)wrapper {
+ // TODO: Detect Type from Any
+ if ( [ wrapper accessibleValue ] != nil ) {
+ long value = 0;
+ [ wrapper accessibleValue ] -> getMinimumValue() >>= value;
+ return [ NSNumber numberWithLong: value ];
+ }
+ return [ NSNumber numberWithLong: 0 ];
+}
+
++(id)maxValueAttributeForElement:(AquaA11yWrapper *)wrapper {
+ // TODO: Detect Type from Any
+ if ( [ wrapper accessibleValue ] != nil ) {
+ long value = 0;
+ [ wrapper accessibleValue ] -> getMaximumValue() >>= value;
+ return [ NSNumber numberWithLong: value ];
+ }
+ return [ NSNumber numberWithLong: 0 ];
+}
+
++(void)setValueAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value {
+ // TODO: Detect Type from NSNumber
+ if ( [ value isKindOfClass: [ NSNumber class ] ]
+ && [ wrapper accessibleValue ] != nil ) {
+ NSNumber * number = (NSNumber *) value;
+ Any numberAny ( [ number longValue ] );
+ [ wrapper accessibleValue ] -> setCurrentValue ( numberAny );
+ }
+}
+
++(void)addAttributeNamesTo:(NSMutableArray *)attributeNames {
+ [ attributeNames addObject: NSAccessibilityValueAttribute ];
+}
+
++(MacOSBOOL)isAttributeSettable:(NSString *)attribute forElement:(AquaA11yWrapper *)wrapper {
+ MacOSBOOL isSettable = NO;
+ if ( [ wrapper accessibleValue ] != nil
+ && [ attribute isEqualToString: NSAccessibilityValueAttribute ]
+ && ! [ wrapper isKindOfClass: [ AquaA11yWrapperStaticText class ] ] ) {
+ isSettable = YES;
+ }
+ return isSettable;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrapper.mm b/vcl/aqua/source/a11y/aqua11ywrapper.mm
new file mode 100644
index 000000000000..e86676e725f2
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapper.mm
@@ -0,0 +1,1142 @@
+/*************************************************************************
+ *
+ * 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 "salinst.h"
+#include "saldata.hxx"
+
+#include "aqua11ywrapper.h"
+#include "aqua11yactionwrapper.h"
+#include "aqua11ycomponentwrapper.h"
+#include "aqua11ylistener.hxx"
+#include "aqua11yselectionwrapper.h"
+#include "aqua11ytablewrapper.h"
+#include "aqua11ytextwrapper.h"
+#include "aqua11yvaluewrapper.h"
+#include "aqua11yfactory.h"
+#include "aqua11yfocuslistener.hxx"
+#include "aqua11yfocustracker.hxx"
+#include "aqua11yrolehelper.h"
+
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/accessibility/XAccessibleRelationSet.hpp>
+#include <com/sun/star/accessibility/AccessibleRelationType.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+
+@interface SalFrameWindow : NSWindow
+{
+}
+-(Reference<XAccessibleContext>)accessibleContext;
+@end
+
+static MacOSBOOL isPopupMenuOpen = NO;
+
+@implementation AquaA11yWrapper : NSView
+
+#pragma mark -
+#pragma mark Init and dealloc
+
+-(id)initWithAccessibleContext: (Reference < XAccessibleContext >) rxAccessibleContext {
+ self = [ super init ];
+ if ( self != nil ) {
+ [ self setDefaults: rxAccessibleContext ];
+ }
+ return self;
+}
+
+-(void) setDefaults: (Reference < XAccessibleContext >) rxAccessibleContext {
+ mDefaultFontsize = 0.0;
+ mpDefaultFontname = nil;
+ mpReferenceWrapper = new ReferenceWrapper;
+ mActsAsRadioGroup = NO;
+ mpReferenceWrapper -> rAccessibleContext = rxAccessibleContext;
+ mIsTableCell = NO;
+ // Querying all supported interfaces
+ try {
+ // XAccessibleComponent
+ mpReferenceWrapper -> rAccessibleComponent = Reference < XAccessibleComponent > ( rxAccessibleContext, UNO_QUERY );
+ // XAccessibleExtendedComponent
+ mpReferenceWrapper -> rAccessibleExtendedComponent = Reference < XAccessibleExtendedComponent > ( rxAccessibleContext, UNO_QUERY );
+ // XAccessibleSelection
+ mpReferenceWrapper -> rAccessibleSelection = Reference< XAccessibleSelection > ( rxAccessibleContext, UNO_QUERY );
+ // XAccessibleTable
+ mpReferenceWrapper -> rAccessibleTable = Reference < XAccessibleTable > ( rxAccessibleContext, UNO_QUERY );
+ // XAccessibleText
+ mpReferenceWrapper -> rAccessibleText = Reference < XAccessibleText > ( rxAccessibleContext, UNO_QUERY );
+ // XAccessibleEditableText
+ mpReferenceWrapper -> rAccessibleEditableText = Reference < XAccessibleEditableText > ( rxAccessibleContext, UNO_QUERY );
+ // XAccessibleValue
+ mpReferenceWrapper -> rAccessibleValue = Reference < XAccessibleValue > ( rxAccessibleContext, UNO_QUERY );
+ // XAccessibleAction
+ mpReferenceWrapper -> rAccessibleAction = Reference < XAccessibleAction > ( rxAccessibleContext, UNO_QUERY );
+ // XAccessibleTextAttributes
+ mpReferenceWrapper -> rAccessibleTextAttributes = Reference < XAccessibleTextAttributes > ( rxAccessibleContext, UNO_QUERY );
+ // XAccessibleMultiLineText
+ mpReferenceWrapper -> rAccessibleMultiLineText = Reference < XAccessibleMultiLineText > ( rxAccessibleContext, UNO_QUERY );
+ // XAccessibleEventBroadcaster
+ #if 0
+ /* #i102033# NSAccessibility does not seemt to know an equivalent for transient children.
+ That means we need to cache this, else e.g. tree list boxes are not accessible (moreover
+ it crashes by notifying dead objects - which would seemt o be another bug)
+
+ FIXME:
+ Unfortunately this can increase memory consumption drastically until the non transient parent
+ is destroyed an finally all the transients are released.
+ */
+ if ( ! rxAccessibleContext -> getAccessibleStateSet() -> contains ( AccessibleStateType::TRANSIENT ) )
+ #endif
+ {
+ Reference< XAccessibleEventBroadcaster > xBroadcaster(rxAccessibleContext, UNO_QUERY);
+ if( xBroadcaster.is() ) {
+ /*
+ * We intentionally do not hold a reference to the event listener in the wrapper object,
+ * but let the listener control the life cycle of the wrapper instead ..
+ */
+ xBroadcaster->addEventListener( new AquaA11yEventListener( self, rxAccessibleContext -> getAccessibleRole() ) );
+ }
+ }
+ // TABLE_CELL
+ if ( rxAccessibleContext -> getAccessibleRole() == AccessibleRole::TABLE_CELL ) {
+ mIsTableCell = YES;
+ }
+ } catch ( const Exception ) {
+ }
+}
+
+-(void)dealloc {
+ if ( mpReferenceWrapper != nil ) {
+ delete mpReferenceWrapper;
+ }
+ if ( mpDefaultFontname != nil ) {
+ [ mpDefaultFontname release ];
+ }
+ [ super dealloc ];
+}
+
+#pragma mark -
+#pragma mark Utility Section
+
+// generates selectors for attribute name AXAttributeNameHere
+// (getter without parameter) attributeNameHereAttribute
+// (getter with parameter) attributeNameHereAttributeForParameter:
+// (setter) setAttributeNameHereAttributeForElement:to:
+-(SEL)selectorForAttribute:(NSString *)attribute asGetter:(MacOSBOOL)asGetter withGetterParameter:(MacOSBOOL)withGetterParameter {
+ SEL selector = nil;
+ NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ];
+ @try {
+ // step 1: create method name from attribute name
+ NSMutableString * methodName = [ NSMutableString string ];
+ if ( ! asGetter ) {
+ [ methodName appendString: @"set" ];
+ }
+ NSString * firstChar = [ attribute substringWithRange: NSMakeRange ( 2, 1 ) ]; // drop leading "AX" and get first char
+ if ( asGetter ) {
+ [ methodName appendString: [ firstChar lowercaseString ] ];
+ } else {
+ [ methodName appendString: firstChar ];
+ }
+ [ methodName appendString: [ attribute substringFromIndex: 3 ] ]; // append rest of attribute name
+ // append rest of method name
+ [ methodName appendString: @"Attribute" ];
+ if ( ! asGetter ) {
+ [ methodName appendString: @"ForElement:to:" ];
+ } else if ( asGetter && withGetterParameter ) {
+ [ methodName appendString: @"ForParameter:" ];
+ }
+ // step 2: create selector
+ selector = NSSelectorFromString ( methodName );
+ } @catch ( id exception ) {
+ selector = nil;
+ }
+ [ pool release ];
+ return selector;
+}
+
+-(Reference < XAccessible >)getFirstRadioButtonInGroup {
+ Reference < XAccessibleRelationSet > rxAccessibleRelationSet = [ self accessibleContext ] -> getAccessibleRelationSet();
+ if( rxAccessibleRelationSet.is() )
+ {
+ AccessibleRelation relationMemberOf = rxAccessibleRelationSet -> getRelationByType ( AccessibleRelationType::MEMBER_OF );
+ if ( relationMemberOf.RelationType == AccessibleRelationType::MEMBER_OF && relationMemberOf.TargetSet.hasElements() )
+ return Reference < XAccessible > ( relationMemberOf.TargetSet[0], UNO_QUERY );
+ }
+ return Reference < XAccessible > ();
+}
+
+-(MacOSBOOL)isFirstRadioButtonInGroup {
+ Reference < XAccessible > rFirstMateAccessible = [ self getFirstRadioButtonInGroup ];
+ if ( rFirstMateAccessible.is() && rFirstMateAccessible -> getAccessibleContext().get() == [ self accessibleContext ] ) {
+ return YES;
+ }
+ return NO;
+}
+
+#pragma mark -
+#pragma mark Attribute Value Getters
+// ( called via Reflection by accessibilityAttributeValue )
+
+/*
+ Radiobutton grouping is done differently in NSAccessibility and the UNO-API. In UNO related radio buttons share an entry in their
+ RelationSet. In NSAccessibility the relationship is axpressed through the hierarchy. A AXRadioGroup contains two or more AXRadioButton
+ objects. Since this group is not available in the UNO hierarchy, an extra wrapper is used for it. This wrapper shares almost all
+ attributes with the first radio button of the group, except for the role, subrole, role description, parent and children attributes.
+ So in this five methods there is a special treatment for radio buttons and groups.
+*/
+
+-(id)roleAttribute {
+ if ( mActsAsRadioGroup ) {
+ return NSAccessibilityRadioGroupRole;
+ }
+ else {
+ return [ AquaA11yRoleHelper getNativeRoleFrom: [ self accessibleContext ] ];
+ }
+}
+
+-(id)subroleAttribute {
+ if ( mActsAsRadioGroup ) {
+ return @"";
+ } else {
+ NSString * subRole = [ AquaA11yRoleHelper getNativeSubroleFrom: [ self accessibleContext ] -> getAccessibleRole() ];
+ if ( ! [ subRole isEqualToString: @"" ] ) {
+ return subRole;
+ } else {
+ [ subRole release ];
+ return [ super accessibilityAttributeValue: NSAccessibilitySubroleAttribute ];
+ }
+ }
+}
+
+-(id)titleAttribute {
+ return CreateNSString ( [ self accessibleContext ] -> getAccessibleName() );
+}
+
+-(id)descriptionAttribute {
+ if ( [ self accessibleContext ] -> getAccessibleRole() == AccessibleRole::COMBO_BOX ) {
+ return [ self titleAttribute ];
+ } else if ( [ self accessibleExtendedComponent ] != nil ) {
+ return [ AquaA11yComponentWrapper descriptionAttributeForElement: self ];
+ } else {
+ return CreateNSString ( [ self accessibleContext ] -> getAccessibleDescription() );
+ }
+}
+
+-(id)enabledAttribute {
+ if ( [ self accessibleContext ] -> getAccessibleStateSet().is() ) {
+ return [ NSNumber numberWithBool: [ self accessibleContext ] -> getAccessibleStateSet() -> contains ( AccessibleStateType::ENABLED ) ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)focusedAttribute {
+ if ( [ self accessibleContext ] -> getAccessibleRole() == AccessibleRole::COMBO_BOX ) {
+ id isFocused = nil;
+ Reference < XAccessible > rxParent = [ self accessibleContext ] -> getAccessibleParent();
+ if ( rxParent.is() ) {
+ Reference < XAccessibleContext > rxContext = rxParent -> getAccessibleContext();
+ if ( rxContext.is() && rxContext -> getAccessibleStateSet().is() ) {
+ isFocused = [ NSNumber numberWithBool: rxContext -> getAccessibleStateSet() -> contains ( AccessibleStateType::FOCUSED ) ];
+ }
+ }
+ return isFocused;
+ } else if ( [ self accessibleContext ] -> getAccessibleStateSet().is() ) {
+ return [ NSNumber numberWithBool: [ self accessibleContext ] -> getAccessibleStateSet() -> contains ( AccessibleStateType::FOCUSED ) ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)parentAttribute {
+ if ( [ self accessibleContext ] -> getAccessibleRole() == AccessibleRole::RADIO_BUTTON && ! mActsAsRadioGroup ) {
+ Reference < XAccessible > rxAccessible = [ self getFirstRadioButtonInGroup ];
+ if ( rxAccessible.is() && rxAccessible -> getAccessibleContext().is() ) {
+ Reference < XAccessibleContext > rxAccessibleContext = rxAccessible -> getAccessibleContext();
+ id parent_wrapper = [ AquaA11yFactory wrapperForAccessibleContext: rxAccessibleContext createIfNotExists: YES asRadioGroup: YES ];
+ [ parent_wrapper autorelease ];
+ return NSAccessibilityUnignoredAncestor( parent_wrapper );
+ }
+ return nil;
+ }
+ try {
+ Reference< XAccessible > xParent( [ self accessibleContext ] -> getAccessibleParent() );
+ if ( xParent.is() ) {
+ Reference< XAccessibleContext > xContext( xParent -> getAccessibleContext() );
+ if ( xContext.is() ) {
+ id parent_wrapper = [ AquaA11yFactory wrapperForAccessibleContext: xContext ];
+ [ parent_wrapper autorelease ];
+ return NSAccessibilityUnignoredAncestor( parent_wrapper );
+ }
+ }
+ } catch (const Exception&) {
+ }
+
+ OSL_ASSERT( 0 );
+ return nil;
+}
+
+-(id)childrenAttribute {
+ if ( mActsAsRadioGroup ) {
+ NSMutableArray * children = [ [ NSMutableArray alloc ] init ];
+ Reference < XAccessibleRelationSet > rxAccessibleRelationSet = [ self accessibleContext ] -> getAccessibleRelationSet();
+ AccessibleRelation relationMemberOf = rxAccessibleRelationSet -> getRelationByType ( AccessibleRelationType::MEMBER_OF );
+ if ( relationMemberOf.RelationType == AccessibleRelationType::MEMBER_OF && relationMemberOf.TargetSet.hasElements() ) {
+ for ( int index = 0; index < relationMemberOf.TargetSet.getLength(); index++ ) {
+ Reference < XAccessible > rMateAccessible = Reference < XAccessible > ( relationMemberOf.TargetSet[index], UNO_QUERY );
+ if ( rMateAccessible.is() ) {
+ Reference< XAccessibleContext > rMateAccessibleContext( rMateAccessible -> getAccessibleContext() );
+ if ( rMateAccessibleContext.is() ) {
+ id wrapper = [ AquaA11yFactory wrapperForAccessibleContext: rMateAccessibleContext ];
+ [ children addObject: wrapper ];
+ [ wrapper release ];
+ }
+ }
+ }
+ }
+ return children;
+ } else if ( [ self accessibleTable ] != nil )
+ {
+ AquaA11yTableWrapper* pTable = [self isKindOfClass: [AquaA11yTableWrapper class]] ? (AquaA11yTableWrapper*)self : nil;
+ return [ AquaA11yTableWrapper childrenAttributeForElement: pTable ];
+ } else {
+ try {
+ NSMutableArray * children = [ [ NSMutableArray alloc ] init ];
+ Reference< XAccessibleContext > xContext( [ self accessibleContext ] );
+
+ sal_Int32 cnt = xContext -> getAccessibleChildCount();
+ for ( sal_Int32 i = 0; i < cnt; i++ ) {
+ Reference< XAccessible > xChild( xContext -> getAccessibleChild( i ) );
+ if( xChild.is() ) {
+ Reference< XAccessibleContext > xChildContext( xChild -> getAccessibleContext() );
+ // the menubar is already accessible (including Apple- and Application-Menu) through NSApplication => omit it here
+ if ( xChildContext.is() && AccessibleRole::MENU_BAR != xChildContext -> getAccessibleRole() ) {
+ id wrapper = [ AquaA11yFactory wrapperForAccessibleContext: xChildContext ];
+ [ children addObject: wrapper ];
+ [ wrapper release ];
+ }
+ }
+ }
+
+ // if not already acting as RadioGroup now is the time to replace RadioButtons with RadioGroups and remove RadioButtons
+ if ( ! mActsAsRadioGroup ) {
+ NSEnumerator * enumerator = [ children objectEnumerator ];
+ AquaA11yWrapper * element;
+ while ( ( element = ( (AquaA11yWrapper *) [ enumerator nextObject ] ) ) ) {
+ if ( [ element accessibleContext ] -> getAccessibleRole() == AccessibleRole::RADIO_BUTTON ) {
+ if ( [ element isFirstRadioButtonInGroup ] ) {
+ id wrapper = [ AquaA11yFactory wrapperForAccessibleContext: [ element accessibleContext ] createIfNotExists: YES asRadioGroup: YES ];
+ [ children replaceObjectAtIndex: [ children indexOfObjectIdenticalTo: element ] withObject: wrapper ];
+ }
+ [ children removeObject: element ];
+ }
+ }
+ }
+
+ [ children autorelease ];
+ return NSAccessibilityUnignoredChildren( children );
+ } catch (const Exception &e) {
+ // TODO: Log
+ return nil;
+ }
+ }
+}
+
+-(id)windowAttribute {
+ // go upstairs until reaching the broken connection
+ AquaA11yWrapper * aWrapper = self;
+ while ( [ aWrapper accessibleContext ] -> getAccessibleParent().is() ) {
+ aWrapper = [ AquaA11yFactory wrapperForAccessibleContext: [ aWrapper accessibleContext ] -> getAccessibleParent() -> getAccessibleContext() ];
+ [ aWrapper autorelease ];
+ }
+ // get associated NSWindow
+ NSView * theView = [ aWrapper viewElementForParent ];
+ return theView;
+}
+
+-(id)topLevelUIElementAttribute {
+ return [ self windowAttribute ];
+}
+
+-(id)sizeAttribute {
+ if ( [ self accessibleComponent ] != nil ) {
+ return [ AquaA11yComponentWrapper sizeAttributeForElement: self ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)positionAttribute {
+ if ( [ self accessibleComponent ] != nil ) {
+ return [ AquaA11yComponentWrapper positionAttributeForElement: self ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)helpAttribute {
+ return CreateNSString ( [ self accessibleContext ] -> getAccessibleDescription() );
+}
+
+-(id)roleDescriptionAttribute {
+ if ( mActsAsRadioGroup ) {
+ return [ AquaA11yRoleHelper getRoleDescriptionFrom: NSAccessibilityRadioGroupRole with: @"" ];
+ } else if( [ self accessibleContext ] -> getAccessibleRole() == AccessibleRole::RADIO_BUTTON ) {
+ // FIXME: VO should read this because of hierarchy, this is just a workaround
+ // get parent and its children
+ AquaA11yWrapper * parent = [ self parentAttribute ];
+ NSArray * children = [ parent childrenAttribute ];
+ // find index of self
+ int index = 1;
+ NSEnumerator * enumerator = [ children objectEnumerator ];
+ AquaA11yWrapper * child = nil;
+ while ( ( child = [ enumerator nextObject ] ) ) {
+ if ( self == child ) {
+ break;
+ }
+ index++;
+ }
+ // build string
+ NSNumber * nIndex = [ NSNumber numberWithInt: index ];
+ NSNumber * nGroupsize = [ NSNumber numberWithInt: [ children count ] ];
+ NSMutableString * value = [ [ NSMutableString alloc ] init ];
+ [ value appendString: @"radio button " ];
+ [ value appendString: [ nIndex stringValue ] ];
+ [ value appendString: @" of " ];
+ [ value appendString: [ nGroupsize stringValue ] ];
+ // clean up and return string
+ [ nIndex release ];
+ [ nGroupsize release ];
+ [ children release ];
+ return value;
+ } else {
+ return [ AquaA11yRoleHelper getRoleDescriptionFrom:
+ [ AquaA11yRoleHelper getNativeRoleFrom: [ self accessibleContext ] ]
+ with: [ AquaA11yRoleHelper getNativeSubroleFrom: [ self accessibleContext ] -> getAccessibleRole() ] ];
+ }
+}
+
+-(id)valueAttribute {
+ if ( [ [ self roleAttribute ] isEqualToString: NSAccessibilityMenuItemRole ] ) {
+ return nil;
+ } else if ( [ self accessibleText ] != nil ) {
+ return [ AquaA11yTextWrapper valueAttributeForElement: self ];
+ } else if ( [ self accessibleValue ] != nil ) {
+ return [ AquaA11yValueWrapper valueAttributeForElement: self ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)minValueAttribute {
+ if ( [ self accessibleValue ] != nil ) {
+ return [ AquaA11yValueWrapper minValueAttributeForElement: self ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)maxValueAttribute {
+ if ( [ self accessibleValue ] != nil ) {
+ return [ AquaA11yValueWrapper maxValueAttributeForElement: self ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)contentsAttribute {
+ return [ self childrenAttribute ];
+}
+
+-(id)selectedChildrenAttribute {
+ return [ AquaA11ySelectionWrapper selectedChildrenAttributeForElement: self ];
+}
+
+-(id)numberOfCharactersAttribute {
+ if ( [ self accessibleText ] != nil ) {
+ return [ AquaA11yTextWrapper numberOfCharactersAttributeForElement: self ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)selectedTextAttribute {
+ if ( [ self accessibleText ] != nil ) {
+ return [ AquaA11yTextWrapper selectedTextAttributeForElement: self ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)selectedTextRangeAttribute {
+ if ( [ self accessibleText ] != nil ) {
+ return [ AquaA11yTextWrapper selectedTextRangeAttributeForElement: self ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)visibleCharacterRangeAttribute {
+ if ( [ self accessibleText ] != nil ) {
+ return [ AquaA11yTextWrapper visibleCharacterRangeAttributeForElement: self ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)tabsAttribute {
+ return self; // TODO ???
+}
+
+-(id)sharedTextUIElementsAttribute {
+ if ( [ self accessibleText ] != nil ) {
+ return [ AquaA11yTextWrapper sharedTextUIElementsAttributeForElement: self ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)sharedCharacterRangeAttribute {
+ if ( [ self accessibleText ] != nil ) {
+ return [ AquaA11yTextWrapper sharedCharacterRangeAttributeForElement: self ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)expandedAttribute {
+ return [ NSNumber numberWithBool: [ self accessibleContext ] -> getAccessibleStateSet() -> contains ( AccessibleStateType::EXPANDED ) ];
+}
+
+-(id)selectedAttribute {
+ return [ NSNumber numberWithBool: [ self accessibleContext ] -> getAccessibleStateSet() -> contains ( AccessibleStateType::SELECTED ) ];
+}
+
+-(id)stringForRangeAttributeForParameter:(id)range {
+ if ( [ self accessibleText ] != nil ) {
+ return [ AquaA11yTextWrapper stringForRangeAttributeForElement: self forParameter: range ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)attributedStringForRangeAttributeForParameter:(id)range {
+ if ( [ self accessibleText ] != nil ) {
+ return [ AquaA11yTextWrapper attributedStringForRangeAttributeForElement: self forParameter: range ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)rangeForIndexAttributeForParameter:(id)index {
+ if ( [ self accessibleText ] != nil ) {
+ return [ AquaA11yTextWrapper rangeForIndexAttributeForElement: self forParameter: index ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)rangeForPositionAttributeForParameter:(id)point {
+ if ( [ self accessibleText ] != nil ) {
+ return [ AquaA11yTextWrapper rangeForPositionAttributeForElement: self forParameter: point ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)boundsForRangeAttributeForParameter:(id)range {
+ if ( [ self accessibleText ] != nil ) {
+ return [ AquaA11yTextWrapper boundsForRangeAttributeForElement: self forParameter: range ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)styleRangeForIndexAttributeForParameter:(id)index {
+ if ( [ self accessibleText ] != nil ) {
+ return [ AquaA11yTextWrapper styleRangeForIndexAttributeForElement: self forParameter: index ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)rTFForRangeAttributeForParameter:(id)range {
+ if ( [ self accessibleText ] != nil ) {
+ return [ AquaA11yTextWrapper rTFForRangeAttributeForElement: self forParameter: range ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)orientationAttribute {
+ NSString * orientation = nil;
+ Reference < XAccessibleStateSet > stateSet = [ self accessibleContext ] -> getAccessibleStateSet();
+ if ( stateSet -> contains ( AccessibleStateType::HORIZONTAL ) ) {
+ orientation = NSAccessibilityHorizontalOrientationValue;
+ } else if ( stateSet -> contains ( AccessibleStateType::VERTICAL ) ) {
+ orientation = NSAccessibilityVerticalOrientationValue;
+ }
+ return orientation;
+}
+
+-(id)titleUIElementAttribute {
+ if ( [ self accessibleContext ] -> getAccessibleRelationSet().is() ) {
+ NSString * title = [ self titleAttribute ];
+ id titleElement = nil;
+ if ( [ title length ] == 0 ) {
+ AccessibleRelation relationLabeledBy = [ self accessibleContext ] -> getAccessibleRelationSet() -> getRelationByType ( AccessibleRelationType::LABELED_BY );
+ if ( relationLabeledBy.RelationType == AccessibleRelationType::LABELED_BY && relationLabeledBy.TargetSet.hasElements() ) {
+ Reference < XAccessible > rxAccessible ( relationLabeledBy.TargetSet[0], UNO_QUERY );
+ titleElement = [ AquaA11yFactory wrapperForAccessibleContext: rxAccessible -> getAccessibleContext() ];
+ }
+ }
+ if ( title != nil ) {
+ [ title release ];
+ }
+ return titleElement;
+ } else {
+ return nil;
+ }
+}
+
+-(id)servesAsTitleForUIElementsAttribute {
+ if ( [ self accessibleContext ] -> getAccessibleRelationSet().is() ) {
+ id titleForElement = nil;
+ AccessibleRelation relationLabelFor = [ self accessibleContext ] -> getAccessibleRelationSet() -> getRelationByType ( AccessibleRelationType::LABEL_FOR );
+ if ( relationLabelFor.RelationType == AccessibleRelationType::LABEL_FOR && relationLabelFor.TargetSet.hasElements() ) {
+ Reference < XAccessible > rxAccessible ( relationLabelFor.TargetSet[0], UNO_QUERY );
+ titleForElement = [ AquaA11yFactory wrapperForAccessibleContext: rxAccessible -> getAccessibleContext() ];
+ }
+ return titleForElement;
+ } else {
+ return nil;
+ }
+}
+
+-(id)lineForIndexAttributeForParameter:(id)index {
+ if ( [ self accessibleMultiLineText ] != nil ) {
+ return [ AquaA11yTextWrapper lineForIndexAttributeForElement: self forParameter: index ];
+ } else {
+ return nil;
+ }
+}
+
+-(id)rangeForLineAttributeForParameter:(id)line {
+ if ( [ self accessibleMultiLineText ] != nil ) {
+ return [ AquaA11yTextWrapper rangeForLineAttributeForElement: self forParameter: line ];
+ } else {
+ return nil;
+ }
+}
+
+#pragma mark -
+#pragma mark Accessibility Protocol
+
+-(id)accessibilityAttributeValue:(NSString *)attribute {
+ // #i90575# guard NSAccessibility protocol against unwanted access
+ if ( isPopupMenuOpen ) {
+ return nil;
+ }
+
+ id value = nil;
+ // if we are no longer in the wrapper repository, we have been disposed
+ AquaA11yWrapper * theWrapper = [ AquaA11yFactory wrapperForAccessibleContext: [ self accessibleContext ] createIfNotExists: NO ];
+ if ( theWrapper != nil || mIsTableCell ) {
+ try {
+ SEL methodSelector = [ self selectorForAttribute: attribute asGetter: YES withGetterParameter: NO ];
+ if ( [ self respondsToSelector: methodSelector ] ) {
+ value = [ self performSelector: methodSelector ];
+ }
+ } catch ( const DisposedException & e ) {
+ mIsTableCell = NO; // just to be sure
+ [ AquaA11yFactory removeFromWrapperRepositoryFor: [ self accessibleContext ] ];
+ return nil;
+ } catch ( const Exception & e ) {
+ // empty
+ }
+ }
+ if ( theWrapper != nil ) {
+ [ theWrapper release ]; // the above called method calls retain on the returned Wrapper
+ }
+ return value;
+}
+
+-(MacOSBOOL)accessibilityIsIgnored {
+ // #i90575# guard NSAccessibility protocol against unwanted access
+ if ( isPopupMenuOpen ) {
+ return nil;
+ }
+ MacOSBOOL ignored = NO;
+ sal_Int16 nRole = [ self accessibleContext ] -> getAccessibleRole();
+ switch ( nRole ) {
+ case AccessibleRole::PANEL:
+ case AccessibleRole::FRAME:
+ case AccessibleRole::ROOT_PANE:
+ case AccessibleRole::SEPARATOR:
+ case AccessibleRole::FILLER:
+ case AccessibleRole::DIALOG:
+ ignored = YES;
+ break;
+ default:
+ ignored = ! ( [ self accessibleContext ] -> getAccessibleStateSet() -> contains ( AccessibleStateType::VISIBLE ) );
+ break;
+ }
+ return ignored; // TODO: to be completed
+}
+
+-(NSArray *)accessibilityAttributeNames {
+ // #i90575# guard NSAccessibility protocol against unwanted access
+ if ( isPopupMenuOpen ) {
+ return nil;
+ }
+ NSString * nativeSubrole = nil;
+ NSString * title = nil;
+ NSMutableArray * attributeNames = nil;
+ sal_Int32 nAccessibleChildren = 0;
+ try {
+ // Default Attributes
+ attributeNames = [ NSMutableArray arrayWithObjects:
+ NSAccessibilityRoleAttribute,
+ NSAccessibilityDescriptionAttribute,
+ NSAccessibilityParentAttribute,
+ NSAccessibilityWindowAttribute,
+ NSAccessibilityHelpAttribute,
+ NSAccessibilityTopLevelUIElementAttribute,
+ NSAccessibilityRoleDescriptionAttribute,
+ nil ];
+ nativeSubrole = (NSString *) [ AquaA11yRoleHelper getNativeSubroleFrom: [ self accessibleContext ] -> getAccessibleRole() ];
+ title = (NSString *) [ self titleAttribute ];
+ Reference < XAccessibleRelationSet > rxRelationSet = [ self accessibleContext ] -> getAccessibleRelationSet();
+ // Special Attributes depending on attribute values
+ if ( nativeSubrole != nil && ! [ nativeSubrole isEqualToString: @"" ] ) {
+ [ attributeNames addObject: NSAccessibilitySubroleAttribute ];
+ }
+ try
+ {
+ nAccessibleChildren = [ self accessibleContext ] -> getAccessibleChildCount();
+ if ( nAccessibleChildren > 0 ) {
+ [ attributeNames addObject: NSAccessibilityChildrenAttribute ];
+ }
+ }
+ catch( DisposedException& ) {}
+ catch( RuntimeException& ) {}
+
+ if ( title != nil && ! [ title isEqualToString: @"" ] ) {
+ [ attributeNames addObject: NSAccessibilityTitleAttribute ];
+ }
+ if ( [ title length ] == 0 && rxRelationSet.is() && rxRelationSet -> containsRelation ( AccessibleRelationType::LABELED_BY ) ) {
+ [ attributeNames addObject: NSAccessibilityTitleUIElementAttribute ];
+ }
+ if ( rxRelationSet.is() && rxRelationSet -> containsRelation ( AccessibleRelationType::LABEL_FOR ) ) {
+ [ attributeNames addObject: NSAccessibilityServesAsTitleForUIElementsAttribute ];
+ }
+ // Special Attributes depending on interface
+ if( [self accessibleContext ] -> getAccessibleRole() == AccessibleRole::TABLE )
+ [AquaA11yTableWrapper addAttributeNamesTo: attributeNames object: self];
+
+ if ( [ self accessibleText ] != nil ) {
+ [ AquaA11yTextWrapper addAttributeNamesTo: attributeNames ];
+ }
+ if ( [ self accessibleComponent ] != nil ) {
+ [ AquaA11yComponentWrapper addAttributeNamesTo: attributeNames ];
+ }
+ if ( [ self accessibleSelection ] != nil ) {
+ [ AquaA11ySelectionWrapper addAttributeNamesTo: attributeNames ];
+ }
+ if ( [ self accessibleValue ] != nil ) {
+ [ AquaA11yValueWrapper addAttributeNamesTo: attributeNames ];
+ }
+ [ nativeSubrole release ];
+ [ title release ];
+ return attributeNames;
+ } catch ( DisposedException & e ) { // Object is no longer available
+ if ( nativeSubrole != nil ) {
+ [ nativeSubrole release ];
+ }
+ if ( title != nil ) {
+ [ title release ];
+ }
+ if ( attributeNames != nil ) {
+ [ attributeNames release ];
+ }
+ [ AquaA11yFactory removeFromWrapperRepositoryFor: [ self accessibleContext ] ];
+ return [ [ NSArray alloc ] init ];
+ }
+}
+
+-(MacOSBOOL)accessibilityIsAttributeSettable:(NSString *)attribute {
+ MacOSBOOL isSettable = NO;
+ if ( [ self accessibleText ] != nil ) {
+ isSettable = [ AquaA11yTextWrapper isAttributeSettable: attribute forElement: self ];
+ }
+ if ( ! isSettable && [ self accessibleComponent ] != nil ) {
+ isSettable = [ AquaA11yComponentWrapper isAttributeSettable: attribute forElement: self ];
+ }
+ if ( ! isSettable && [ self accessibleSelection ] != nil ) {
+ isSettable = [ AquaA11ySelectionWrapper isAttributeSettable: attribute forElement: self ];
+ }
+ if ( ! isSettable && [ self accessibleValue ] != nil ) {
+ isSettable = [ AquaA11yValueWrapper isAttributeSettable: attribute forElement: self ];
+ }
+ return isSettable; // TODO: to be completed
+}
+
+-(NSArray *)accessibilityParameterizedAttributeNames {
+ NSMutableArray * attributeNames = [ [ NSMutableArray alloc ] init ];
+ // Special Attributes depending on interface
+ if ( [ self accessibleText ] != nil ) {
+ [ AquaA11yTextWrapper addParameterizedAttributeNamesTo: attributeNames ];
+ }
+ return attributeNames; // TODO: to be completed
+}
+
+-(id)accessibilityAttributeValue:(NSString *)attribute forParameter:(id)parameter {
+ SEL methodSelector = [ self selectorForAttribute: attribute asGetter: YES withGetterParameter: YES ];
+ if ( [ self respondsToSelector: methodSelector ] ) {
+ return [ self performSelector: methodSelector withObject: parameter ];
+ }
+ return nil; // TODO: to be completed
+}
+
+-(MacOSBOOL)accessibilitySetOverrideValue:(id)value forAttribute:(NSString *)attribute {
+ return NO; // TODO
+}
+
+-(void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute {
+ SEL methodSelector = [ self selectorForAttribute: attribute asGetter: NO withGetterParameter: NO ];
+ if ( [ AquaA11yComponentWrapper respondsToSelector: methodSelector ] ) {
+ [ AquaA11yComponentWrapper performSelector: methodSelector withObject: self withObject: value ];
+ }
+ if ( [ AquaA11yTextWrapper respondsToSelector: methodSelector ] ) {
+ [ AquaA11yTextWrapper performSelector: methodSelector withObject: self withObject: value ];
+ }
+ if ( [ AquaA11ySelectionWrapper respondsToSelector: methodSelector ] ) {
+ [ AquaA11ySelectionWrapper performSelector: methodSelector withObject: self withObject: value ];
+ }
+ if ( [ AquaA11yValueWrapper respondsToSelector: methodSelector ] ) {
+ [ AquaA11yValueWrapper performSelector: methodSelector withObject: self withObject: value ];
+ }
+}
+
+-(id)accessibilityFocusedUIElement {
+ // #i90575# guard NSAccessibility protocol against unwanted access
+ if ( isPopupMenuOpen ) {
+ return nil;
+ }
+
+ // as this seems to be the first API call on a newly created SalFrameView object,
+ // make sure self gets registered in the repository ..
+ [ self accessibleContext ];
+
+ AquaA11yWrapper * focusedUIElement = AquaA11yFocusListener::get()->getFocusedUIElement();
+// AquaA11yWrapper * ancestor = focusedUIElement;
+
+ // Make sure the focused object is a descendant of self
+// do {
+// if( self == ancestor )
+ return focusedUIElement;
+
+// ancestor = [ ancestor accessibilityAttributeValue: NSAccessibilityParentAttribute ];
+// } while( nil != ancestor );
+
+ return self;
+}
+
+// TODO: hard-coded like the role descriptions. is there a better way?
+-(NSString *)accessibilityActionDescription:(NSString *)action {
+ if ( [ action isEqualToString: NSAccessibilityConfirmAction ] ) {
+ return @"confirm";
+ } else if ( [ action isEqualToString: NSAccessibilityDecrementAction ] ) {
+ return @"decrement";
+ } else if ( [ action isEqualToString: NSAccessibilityDeleteAction ] ) {
+ return @"delete";
+ } else if ( [ action isEqualToString: NSAccessibilityIncrementAction ] ) {
+ return @"increment";
+ } else if ( [ action isEqualToString: NSAccessibilityPickAction ] ) {
+ return @"pick";
+ } else if ( [ action isEqualToString: NSAccessibilityPressAction ] ) {
+ return @"press";
+ } else if ( [ action isEqualToString: NSAccessibilityCancelAction ] ) {
+ return @"cancel";
+ } else if ( [ action isEqualToString: NSAccessibilityRaiseAction ] ) {
+ return @"raise";
+ } else if ( [ action isEqualToString: NSAccessibilityShowMenuAction ] ) {
+ return @"show menu";
+ } else {
+ return [ NSString string ];
+ }
+}
+
+-(AquaA11yWrapper *)actionResponder {
+ AquaA11yWrapper * wrapper = nil;
+ // get some information
+ NSString * role = (NSString *) [ self accessibilityAttributeValue: NSAccessibilityRoleAttribute ];
+ id enabledAttr = [ self enabledAttribute ];
+ MacOSBOOL enabled = [ enabledAttr boolValue ];
+ NSView * parent = (NSView *) [ self accessibilityAttributeValue: NSAccessibilityParentAttribute ];
+ AquaA11yWrapper * parentAsWrapper = nil;
+ if ( [ parent isKindOfClass: [ AquaA11yWrapper class ] ] ) {
+ parentAsWrapper = (AquaA11yWrapper *) parent;
+ }
+ NSString * parentRole = (NSString *) [ parent accessibilityAttributeValue: NSAccessibilityRoleAttribute ];
+ // if we are a textarea inside a combobox, then the combobox is the action responder
+ if ( enabled
+ && [ role isEqualToString: NSAccessibilityTextAreaRole ]
+ && [ parentRole isEqualToString: NSAccessibilityComboBoxRole ]
+ && parentAsWrapper != nil ) {
+ wrapper = parentAsWrapper;
+ } else if ( enabled && [ self accessibleAction ] != nil ) {
+ wrapper = self ;
+ }
+ [ parentRole release ];
+ [ enabledAttr release ];
+ [ role release ];
+ return wrapper;
+}
+
+-(void)accessibilityPerformAction:(NSString *)action {
+ AquaA11yWrapper * actionResponder = [ self actionResponder ];
+ if ( actionResponder != nil ) {
+ [ AquaA11yActionWrapper doAction: action ofElement: actionResponder ];
+ }
+}
+
+-(NSArray *)accessibilityActionNames {
+ NSArray * actionNames = nil;
+ AquaA11yWrapper * actionResponder = [ self actionResponder ];
+ if ( actionResponder != nil ) {
+ actionNames = [ AquaA11yActionWrapper actionNamesForElement: actionResponder ];
+ } else {
+ actionNames = [ [ NSArray alloc ] init ];
+ }
+ return actionNames;
+}
+
+#pragma mark -
+#pragma mark Hit Test
+
+-(MacOSBOOL)isViewElement:(NSObject *)viewElement hitByPoint:(NSPoint)point {
+ MacOSBOOL hit = NO;
+ NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ];
+ NSValue * position = [ viewElement accessibilityAttributeValue: NSAccessibilityPositionAttribute ];
+ NSValue * size = [ viewElement accessibilityAttributeValue: NSAccessibilitySizeAttribute ];
+ if ( position != nil && size != nil ) {
+ float minX = [ position pointValue ].x;
+ float minY = [ position pointValue ].y;
+ float maxX = minX + [ size sizeValue ].width;
+ float maxY = minY + [ size sizeValue ].height;
+ if ( minX < point.x && maxX > point.x && minY < point.y && maxY > point.y ) {
+ hit = YES;
+ }
+ }
+ [ pool release ];
+ return hit;
+}
+
+Reference < XAccessibleContext > hitTestRunner ( com::sun::star::awt::Point point,
+ Reference < XAccessibleContext > rxAccessibleContext ) {
+ Reference < XAccessibleContext > hitChild;
+ Reference < XAccessibleContext > emptyReference;
+ try {
+ Reference < XAccessibleComponent > rxAccessibleComponent ( rxAccessibleContext, UNO_QUERY );
+ if ( rxAccessibleComponent.is() ) {
+ com::sun::star::awt::Point location = rxAccessibleComponent -> getLocationOnScreen();
+ com::sun::star::awt::Point hitPoint ( point.X - location.X , point.Y - location.Y);
+ Reference < XAccessible > rxAccessible = rxAccessibleComponent -> getAccessibleAtPoint ( hitPoint );
+ if ( rxAccessible.is() && rxAccessible -> getAccessibleContext().is() ) {
+ if ( rxAccessible -> getAccessibleContext() -> getAccessibleChildCount() > 0 ) {
+ hitChild = hitTestRunner ( point, rxAccessible -> getAccessibleContext() );
+ if ( ! hitChild.is() ) {
+ hitChild = rxAccessible -> getAccessibleContext();
+ }
+ } else {
+ hitChild = rxAccessible -> getAccessibleContext();
+ }
+ }
+ }
+ if ( !hitChild.is() && rxAccessibleContext -> getAccessibleChildCount() > 0 ) { // special treatment for e.g. comboboxes
+ for ( int i = 0; i < rxAccessibleContext -> getAccessibleChildCount(); i++ ) {
+ Reference < XAccessible > rxAccessibleChild = rxAccessibleContext -> getAccessibleChild ( i );
+ if ( rxAccessibleChild.is() && rxAccessibleChild -> getAccessibleContext().is() && rxAccessibleChild -> getAccessibleContext() -> getAccessibleRole() != AccessibleRole::LIST ) {
+ Reference < XAccessibleContext > myHitChild = hitTestRunner ( point, rxAccessibleChild -> getAccessibleContext() );
+ if ( myHitChild.is() ) {
+ hitChild = myHitChild;
+ break;
+ }
+ }
+ }
+ }
+ } catch ( RuntimeException ) {
+ return emptyReference;
+ }
+ return hitChild;
+}
+
+-(id)accessibilityHitTest:(NSPoint)point {
+ static id wrapper = nil;
+ if ( nil != wrapper ) {
+ [ wrapper release ];
+ wrapper = nil;
+ }
+ Reference < XAccessibleContext > hitChild;
+ NSRect screenRect = [ [ NSScreen mainScreen ] frame ];
+ com::sun::star::awt::Point hitPoint ( static_cast<long>(point.x) , static_cast<long>(screenRect.size.height - point.y) );
+ // check child windows first
+ NSWindow * window = (NSWindow *) [ self accessibilityAttributeValue: NSAccessibilityWindowAttribute ];
+ NSArray * childWindows = [ window childWindows ];
+ if ( [ childWindows count ] > 0 ) {
+ NSWindow * element = nil;
+ NSEnumerator * enumerator = [ childWindows objectEnumerator ];
+ while ( ( element = [ enumerator nextObject ] ) && hitChild == nil ) {
+ if ( [ element isKindOfClass: [ SalFrameWindow class ] ] && [ self isViewElement: element hitByPoint: point ] ) {
+ // we have a child window that is hit
+ Reference < XAccessibleRelationSet > relationSet = [ ( ( SalFrameWindow * ) element ) accessibleContext ] -> getAccessibleRelationSet();
+ if ( relationSet.is() && relationSet -> containsRelation ( AccessibleRelationType::SUB_WINDOW_OF )) {
+ // we have a valid relation to the parent element
+ AccessibleRelation relation = relationSet -> getRelationByType ( AccessibleRelationType::SUB_WINDOW_OF );
+ for ( int i = 0; i < relation.TargetSet.getLength() && !hitChild.is(); i++ ) {
+ Reference < XAccessible > rxAccessible ( relation.TargetSet [ i ], UNO_QUERY );
+ if ( rxAccessible.is() && rxAccessible -> getAccessibleContext().is() ) {
+ // hit test for children of parent
+ hitChild = hitTestRunner ( hitPoint, rxAccessible -> getAccessibleContext() );
+ }
+ }
+ }
+ }
+ }
+ }
+ // nothing hit yet, so check ourself
+ if ( ! hitChild.is() ) {
+ if ( mpReferenceWrapper == nil ) {
+ [ self setDefaults: [ self accessibleContext ] ];
+ }
+ hitChild = hitTestRunner ( hitPoint, mpReferenceWrapper -> rAccessibleContext );
+ }
+ if ( hitChild.is() ) {
+ wrapper = [ AquaA11yFactory wrapperForAccessibleContext: hitChild ];
+ }
+ if ( wrapper != nil ) {
+ [ wrapper retain ]; // TODO: retain only when transient ?
+ }
+ return wrapper;
+}
+
+#pragma mark -
+#pragma mark Access Methods
+
+-(XAccessibleAction *)accessibleAction {
+ return mpReferenceWrapper -> rAccessibleAction.get();
+}
+
+-(XAccessibleContext *)accessibleContext {
+ return mpReferenceWrapper -> rAccessibleContext.get();
+}
+
+-(XAccessibleComponent *)accessibleComponent {
+ return mpReferenceWrapper -> rAccessibleComponent.get();
+}
+
+-(XAccessibleExtendedComponent *)accessibleExtendedComponent {
+ return mpReferenceWrapper -> rAccessibleExtendedComponent.get();
+}
+
+-(XAccessibleSelection *)accessibleSelection {
+ return mpReferenceWrapper -> rAccessibleSelection.get();
+}
+
+-(XAccessibleTable *)accessibleTable {
+ return mpReferenceWrapper -> rAccessibleTable.get();
+}
+
+-(XAccessibleText *)accessibleText {
+ return mpReferenceWrapper -> rAccessibleText.get();
+}
+
+-(XAccessibleEditableText *)accessibleEditableText {
+ return mpReferenceWrapper -> rAccessibleEditableText.get();
+}
+
+-(XAccessibleValue *)accessibleValue {
+ return mpReferenceWrapper -> rAccessibleValue.get();
+}
+
+-(XAccessibleTextAttributes *)accessibleTextAttributes {
+ return mpReferenceWrapper -> rAccessibleTextAttributes.get();
+}
+
+-(XAccessibleMultiLineText *)accessibleMultiLineText {
+ return mpReferenceWrapper -> rAccessibleMultiLineText.get();
+}
+
+-(NSView *)viewElementForParent {
+ return self;
+}
+
+// These four are for AXTextAreas only. They are needed, because bold and italic
+// attributes have to be bound to a font on the Mac. Our UNO-API instead handles
+// and reports them independently. When they occur we bundle them to a font with
+// this information here to create a according NSFont.
+-(void)setDefaultFontname:(NSString *)fontname {
+ if ( mpDefaultFontname != nil ) {
+ [ mpDefaultFontname release ];
+ }
+ mpDefaultFontname = fontname;
+}
+
+-(NSString *)defaultFontname {
+ return mpDefaultFontname;
+}
+
+-(void)setDefaultFontsize:(float)fontsize {
+ mDefaultFontsize = fontsize;
+}
+
+-(float)defaultFontsize {
+ return mDefaultFontsize;
+}
+
+-(void)setActsAsRadioGroup:(MacOSBOOL)actsAsRadioGroup {
+ mActsAsRadioGroup = actsAsRadioGroup;
+}
+
+-(MacOSBOOL)actsAsRadioGroup {
+ return mActsAsRadioGroup;
+}
+
++(void)setPopupMenuOpen:(MacOSBOOL)popupMenuOpen {
+ isPopupMenuOpen = popupMenuOpen;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperbutton.h b/vcl/aqua/source/a11y/aqua11ywrapperbutton.h
new file mode 100644
index 000000000000..aa35062d15c4
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperbutton.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11WRAPPERBUTTON_H
+#define _SV_AQUA11WRAPPERBUTTON_H
+
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yWrapperButton : AquaA11yWrapper
+{
+}
+-(id)valueAttribute;
+-(id)descriptionAttribute;
+-(NSArray *)accessibilityAttributeNames;
+@end
+
+#endif // _SV_AQUA11WRAPPERBUTTON_H
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperbutton.mm b/vcl/aqua/source/a11y/aqua11ywrapperbutton.mm
new file mode 100644
index 000000000000..48f1804c58a2
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperbutton.mm
@@ -0,0 +1,61 @@
+/*************************************************************************
+ *
+ * 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 "salinst.h"
+#include "aqua11ywrapperbutton.h"
+#include "aqua11ytextwrapper.h"
+
+// Wrapper for AXButton role
+
+@implementation AquaA11yWrapperButton : AquaA11yWrapper
+
+-(id)valueAttribute {
+ return [ NSString string ]; // we propagate AXTitle, that's enough
+}
+
+-(id)descriptionAttribute {
+ return [ NSString string ]; // we propagate AXTitle, that's enough
+}
+
+-(NSArray *)accessibilityAttributeNames {
+ // Default Attributes
+ NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ];
+ // Special Attributes and removing unwanted attributes depending on role
+ if ( [ attributeNames containsObject: NSAccessibilityTitleAttribute ] ) {
+ [ attributeNames removeObject: NSAccessibilityDescriptionAttribute ];
+ } else {
+ [ attributeNames addObject: NSAccessibilityTitleAttribute ];
+ }
+ // Remove text-specific attributes
+ [ attributeNames removeObjectsInArray: [ AquaA11yTextWrapper specialAttributeNames ] ];
+ return attributeNames;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrappercheckbox.h b/vcl/aqua/source/a11y/aqua11ywrappercheckbox.h
new file mode 100644
index 000000000000..95fee9a3ec4b
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrappercheckbox.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11WRAPPERCHECKBOX_H
+#define _SV_AQUA11WRAPPERCHECKBOX_H
+
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yWrapperCheckBox : AquaA11yWrapper
+{
+}
+-(id)valueAttribute;
+-(MacOSBOOL)accessibilityIsAttributeSettable:(NSString *)attribute;
+-(NSArray *)accessibilityAttributeNames;
+@end
+
+#endif // _SV_AQUA11WRAPPERCHECKOBOX_H
diff --git a/vcl/aqua/source/a11y/aqua11ywrappercheckbox.mm b/vcl/aqua/source/a11y/aqua11ywrappercheckbox.mm
new file mode 100644
index 000000000000..c4ac34dc5bce
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrappercheckbox.mm
@@ -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 "salinst.h"
+#include "aqua11ywrappercheckbox.h"
+#include "aqua11yvaluewrapper.h"
+#include "aqua11ytextwrapper.h"
+
+// Wrapper for AXCheckbox role
+
+@implementation AquaA11yWrapperCheckBox : AquaA11yWrapper
+
+-(id)valueAttribute {
+ if ( [ self accessibleValue ] != nil ) {
+ return [ AquaA11yValueWrapper valueAttributeForElement: self ];
+ }
+ return [ NSNumber numberWithInt: 0 ];
+}
+
+-(MacOSBOOL)accessibilityIsAttributeSettable:(NSString *)attribute {
+ if ( [ attribute isEqualToString: NSAccessibilityValueAttribute ] ) {
+ return NO;
+ }
+ return [ super accessibilityIsAttributeSettable: attribute ];
+}
+
+-(NSArray *)accessibilityAttributeNames {
+ // Default Attributes
+ NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ];
+ // Remove text-specific attributes
+ [ attributeNames removeObjectsInArray: [ AquaA11yTextWrapper specialAttributeNames ] ];
+ [ attributeNames addObject: NSAccessibilityValueAttribute ];
+ [ attributeNames addObject: NSAccessibilityMinValueAttribute ];
+ [ attributeNames addObject: NSAccessibilityMaxValueAttribute ];
+ return attributeNames;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrappercombobox.h b/vcl/aqua/source/a11y/aqua11ywrappercombobox.h
new file mode 100644
index 000000000000..7ed76d607176
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrappercombobox.h
@@ -0,0 +1,50 @@
+/*************************************************************************
+ *
+ * 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_AQUA11WRAPPERCOMBOBOX_H
+#define _SV_AQUA11WRAPPERCOMBOBOX_H
+
+#include "aqua11ywrapper.h"
+#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+
+@interface AquaA11yWrapperComboBox : AquaA11yWrapper
+{
+ AquaA11yWrapper * textArea;
+}
+-(id)initWithAccessibleContext: (::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleContext >) anAccessibleContext;
+-(id)valueAttribute;
+-(id)numberOfCharactersAttribute;
+-(id)selectedTextAttribute;
+-(id)selectedTextRangeAttribute;
+-(id)visibleCharacterRangeAttribute;
+// Accessibility Protocol
+-(MacOSBOOL)accessibilityIsAttributeSettable:(NSString *)attribute;
+-(void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute;
+-(NSArray *)accessibilityAttributeNames;
+@end
+
+#endif // _SV_AQUA11WRAPPERCOMBOBOX_H
diff --git a/vcl/aqua/source/a11y/aqua11ywrappercombobox.mm b/vcl/aqua/source/a11y/aqua11ywrappercombobox.mm
new file mode 100644
index 000000000000..85aed320e470
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrappercombobox.mm
@@ -0,0 +1,161 @@
+/*************************************************************************
+ *
+ * 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 "salinst.h"
+#include "aqua11ywrappercombobox.h"
+#include "aqua11yrolehelper.h"
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::uno;
+
+// Wrapper for AXCombobox role
+
+@implementation AquaA11yWrapperComboBox : AquaA11yWrapper
+
+#pragma mark -
+#pragma mark Specialized Init Method
+
+-(id)initWithAccessibleContext: (Reference < XAccessibleContext >) rxAccessibleContext {
+ self = [ super initWithAccessibleContext: rxAccessibleContext ];
+ if ( self != nil )
+ {
+ textArea = nil;
+ }
+ return self;
+}
+
+#pragma mark -
+#pragma mark Private Helper Method
+
+-(AquaA11yWrapper *)textArea {
+ // FIXME: May cause problems when stored. Then get dynamically each time (bad performance!)
+ if ( textArea == nil ) {
+ NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ];
+ NSArray * elementChildren = [ super childrenAttribute ];
+ if ( [ elementChildren count ] > 0 ) {
+ NSEnumerator * enumerator = [ elementChildren objectEnumerator ];
+ id child;
+ while ( ( child = [ enumerator nextObject ] ) ) {
+ AquaA11yWrapper * element = ( AquaA11yWrapper * ) child;
+ if ( [ [ AquaA11yRoleHelper getNativeRoleFrom: [ element accessibleContext ] ] isEqualToString: NSAccessibilityTextAreaRole ] ) {
+ textArea = element;
+ break;
+ }
+ }
+ }
+ [ pool release ];
+ }
+ return textArea;
+}
+
+#pragma mark -
+#pragma mark Wrapped Attributes From Contained Text Area
+
+-(id)valueAttribute {
+ if ( [ self textArea ] != nil ) {
+ return [ [ self textArea ] valueAttribute ];
+ }
+ return @"";
+}
+
+-(id)numberOfCharactersAttribute {
+ if ( [ self textArea ] != nil ) {
+ return [ [ self textArea ] numberOfCharactersAttribute ];
+ }
+ return [ NSNumber numberWithInt: 0 ];
+}
+
+-(id)selectedTextAttribute {
+ if ( [ self textArea ] != nil ) {
+ return [ [ self textArea ] selectedTextAttribute ];
+ }
+ return @"";
+}
+
+-(id)selectedTextRangeAttribute {
+ if ( [ self textArea ] != nil ) {
+ return [ [ self textArea ] selectedTextRangeAttribute ];
+ }
+ return [ NSValue valueWithRange: NSMakeRange ( 0, 0 ) ];
+}
+
+-(id)visibleCharacterRangeAttribute {
+ if ( [ self textArea ] != nil ) {
+ return [ [ self textArea ] visibleCharacterRangeAttribute ];
+ }
+ return [ NSValue valueWithRange: NSMakeRange ( 0, 0 ) ];
+}
+
+#pragma mark -
+#pragma mark Accessibility Protocol
+
+-(MacOSBOOL)accessibilityIsAttributeSettable:(NSString *)attribute {
+ if ( [ self textArea ] != nil && (
+ [ attribute isEqualToString: NSAccessibilitySelectedTextAttribute ]
+ || [ attribute isEqualToString: NSAccessibilitySelectedTextRangeAttribute ]
+ || [ attribute isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute ] ) ) {
+ return [ [ self textArea ] accessibilityIsAttributeSettable: attribute ];
+ }
+ return [ super accessibilityIsAttributeSettable: attribute ];
+}
+
+-(void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute {
+ if ( [ self textArea ] != nil && (
+ [ attribute isEqualToString: NSAccessibilitySelectedTextAttribute ]
+ || [ attribute isEqualToString: NSAccessibilitySelectedTextRangeAttribute ]
+ || [ attribute isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute ] ) ) {
+ return [ [ self textArea ] accessibilitySetValue: value forAttribute: attribute ];
+ }
+ return [ super accessibilitySetValue: value forAttribute: attribute ];
+}
+
+-(NSArray *)accessibilityAttributeNames {
+ // Default Attributes
+ NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ];
+ // Special Attributes and removing unwanted attributes depending on role
+ [ attributeNames removeObjectsInArray: [ NSArray arrayWithObjects:
+ NSAccessibilityTitleAttribute,
+ NSAccessibilityChildrenAttribute,
+ nil ]
+ ];
+ [ attributeNames addObjectsFromArray: [ NSArray arrayWithObjects:
+ NSAccessibilityExpandedAttribute,
+ NSAccessibilityValueAttribute,
+ NSAccessibilityNumberOfCharactersAttribute,
+ NSAccessibilitySelectedTextAttribute,
+ NSAccessibilitySelectedTextRangeAttribute,
+ NSAccessibilityVisibleCharacterRangeAttribute,
+ nil ]
+ ];
+ return attributeNames;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrappergroup.h b/vcl/aqua/source/a11y/aqua11ywrappergroup.h
new file mode 100644
index 000000000000..7757e067ee22
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrappergroup.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11WRAPPERGROUP_H
+#define _SV_AQUA11WRAPPERGROUP_H
+
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yWrapperGroup : AquaA11yWrapper
+{
+}
+-(id)titleUIElementAttribute;
+-(NSArray *)accessibilityAttributeNames;
+@end
+
+#endif // _SV_AQUA11WRAPPERGROUP_H
diff --git a/vcl/aqua/source/a11y/aqua11ywrappergroup.mm b/vcl/aqua/source/a11y/aqua11ywrappergroup.mm
new file mode 100644
index 000000000000..42298f9c745b
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrappergroup.mm
@@ -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 "salinst.h"
+#include "aqua11ywrappergroup.h"
+
+// Wrapper for AXGroup role
+
+@implementation AquaA11yWrapperGroup : AquaA11yWrapper
+
+-(id)titleUIElementAttribute {
+ return self; // TODO
+}
+
+-(NSArray *)accessibilityAttributeNames {
+ // Default Attributes
+ NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ];
+ // Special Attributes and removing unwanted attributes depending on role
+ [ attributeNames removeObjectsInArray: [ NSArray arrayWithObjects:
+ NSAccessibilityTitleAttribute,
+ NSAccessibilityEnabledAttribute,
+ NSAccessibilitySelectedChildrenAttribute,
+ nil ]
+ ];
+ [ attributeNames addObject: NSAccessibilityContentsAttribute ];
+ [ attributeNames addObject: NSAccessibilityTitleUIElementAttribute ];
+ return attributeNames;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperlist.h b/vcl/aqua/source/a11y/aqua11ywrapperlist.h
new file mode 100644
index 000000000000..95df8323467b
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperlist.h
@@ -0,0 +1,39 @@
+/*************************************************************************
+ *
+ * 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_AQUA11WRAPPERLIST_H
+#define _SV_AQUA11WRAPPERLIST_H
+
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yWrapperList : AquaA11yWrapper
+{
+}
+-(NSArray *)accessibilityAttributeNames;
+@end
+
+#endif // _SV_AQUA11WRAPPERLIST_H
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperlist.mm b/vcl/aqua/source/a11y/aqua11ywrapperlist.mm
new file mode 100644
index 000000000000..eeb210d70e65
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperlist.mm
@@ -0,0 +1,48 @@
+/*************************************************************************
+ *
+ * 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 "salinst.h"
+#include "aqua11ywrapperlist.h"
+
+using namespace ::com::sun::star::accessibility;
+
+// Wrapper for AXList role
+
+@implementation AquaA11yWrapperList : AquaA11yWrapper
+
+-(NSArray *)accessibilityAttributeNames {
+ // Default Attributes
+ NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ];
+ // Special Attributes and removing unwanted attributes depending on role
+ [ attributeNames addObject: NSAccessibilityOrientationAttribute ];
+ return attributeNames;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperradiobutton.h b/vcl/aqua/source/a11y/aqua11ywrapperradiobutton.h
new file mode 100644
index 000000000000..13ceee6f826f
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperradiobutton.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11WRAPPERRADIOBUTTON_H
+#define _SV_AQUA11WRAPPERRADIOBUTTON_H
+
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yWrapperRadioButton : AquaA11yWrapper
+{
+}
+-(id)valueAttribute;
+-(MacOSBOOL)accessibilityIsAttributeSettable:(NSString *)attribute;
+-(NSArray *)accessibilityAttributeNames;
+@end
+
+#endif // _SV_AQUA11WRAPPERRADIOGROUP_H
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperradiobutton.mm b/vcl/aqua/source/a11y/aqua11ywrapperradiobutton.mm
new file mode 100644
index 000000000000..54d6edac619a
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperradiobutton.mm
@@ -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 "salinst.h"
+#include "aqua11ywrapperradiobutton.h"
+#include "aqua11ytextwrapper.h"
+#include "aqua11yvaluewrapper.h"
+
+// Wrapper for AXRadioButton role
+
+@implementation AquaA11yWrapperRadioButton : AquaA11yWrapper
+
+-(id)valueAttribute {
+ if ( [ self accessibleValue ] != nil ) {
+ return [ AquaA11yValueWrapper valueAttributeForElement: self ];
+ }
+ return [ NSNumber numberWithInt: 0 ];
+}
+
+-(MacOSBOOL)accessibilityIsAttributeSettable:(NSString *)attribute {
+ if ( [ attribute isEqualToString: NSAccessibilityValueAttribute ] ) {
+ return NO;
+ }
+ return [ super accessibilityIsAttributeSettable: attribute ];
+}
+
+-(NSArray *)accessibilityAttributeNames {
+ // Default Attributes
+ NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ];
+ // Special Attributes and removing unwanted attributes depending on role
+ [ attributeNames removeObjectsInArray: [ AquaA11yTextWrapper specialAttributeNames ] ];
+ [ attributeNames addObject: NSAccessibilityMinValueAttribute ];
+ [ attributeNames addObject: NSAccessibilityMaxValueAttribute ];
+ [ attributeNames addObject: NSAccessibilityValueAttribute ];
+ return attributeNames;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperradiogroup.h b/vcl/aqua/source/a11y/aqua11ywrapperradiogroup.h
new file mode 100644
index 000000000000..544b709223b3
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperradiogroup.h
@@ -0,0 +1,39 @@
+/*************************************************************************
+ *
+ * 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_AQUA11WRAPPERRADIOGROUP_H
+#define _SV_AQUA11WRAPPERRADIOGROUP_H
+
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yWrapperRadioGroup : AquaA11yWrapper
+{
+}
+-(NSArray *)accessibilityAttributeNames;
+@end
+
+#endif // _SV_AQUA11WRAPPERRADIOGROUP_H
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperradiogroup.mm b/vcl/aqua/source/a11y/aqua11ywrapperradiogroup.mm
new file mode 100644
index 000000000000..f89ac78b044c
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperradiogroup.mm
@@ -0,0 +1,48 @@
+/*************************************************************************
+ *
+ * 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 "salinst.h"
+#include "aqua11ywrapperradiogroup.h"
+#include "aqua11ytextwrapper.h"
+
+// Wrapper for AXRadioGroup role
+
+@implementation AquaA11yWrapperRadioGroup : AquaA11yWrapper
+
+-(NSArray *)accessibilityAttributeNames {
+ // Default Attributes
+ NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ];
+ // Special Attributes and removing unwanted attributes depending on role
+ [ attributeNames removeObjectsInArray: [ AquaA11yTextWrapper specialAttributeNames ] ];
+ [ attributeNames removeObject: NSAccessibilityTitleAttribute ];
+ return attributeNames;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperrow.h b/vcl/aqua/source/a11y/aqua11ywrapperrow.h
new file mode 100644
index 000000000000..252af6f5987f
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperrow.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11WRAPPERROW_H
+#define _SV_AQUA11WRAPPERROW_H
+
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yWrapperRow : AquaA11yWrapper
+{
+}
+-(id)disclosingAttribute;
+-(NSArray *)accessibilityAttributeNames;
+@end
+
+#endif // _SV_AQUA11WRAPPERROW_H
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperrow.mm b/vcl/aqua/source/a11y/aqua11ywrapperrow.mm
new file mode 100644
index 000000000000..d49e229218bf
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperrow.mm
@@ -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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "salinst.h"
+#include "aqua11ywrapperrow.h"
+#include "aqua11ytextwrapper.h"
+
+// Wrapper for AXRow role
+
+@implementation AquaA11yWrapperRow : AquaA11yWrapper
+
+-(id)disclosingAttribute {
+ return NO; // TODO
+}
+
+-(NSArray *)accessibilityAttributeNames {
+ // Default Attributes
+ NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ];
+ // Special Attributes and removing unwanted attributes depending on role
+ [ attributeNames removeObjectsInArray: [ AquaA11yTextWrapper specialAttributeNames ] ];
+ [ attributeNames removeObject: NSAccessibilityTitleAttribute ];
+ [ attributeNames removeObject: NSAccessibilityEnabledAttribute ];
+ [ attributeNames removeObject: NSAccessibilityFocusedAttribute ];
+ [ attributeNames addObject: NSAccessibilitySelectedAttribute ];
+ [ attributeNames addObject: NSAccessibilityDisclosingAttribute ];
+ return attributeNames;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperscrollarea.h b/vcl/aqua/source/a11y/aqua11ywrapperscrollarea.h
new file mode 100644
index 000000000000..2c206fd0904b
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperscrollarea.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11WRAPPERSCROLLAREA_H
+#define _SV_AQUA11WRAPPERSCROLLAREA_H
+
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yWrapperScrollArea : AquaA11yWrapper
+{
+}
+-(id)verticalScrollBarAttribute;
+-(id)horizontalScrollBarAttribute;
+-(NSArray *)accessibilityAttributeNames;
+@end
+
+#endif // _SV_AQUA11WRAPPERSCROLLAREA_H
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperscrollarea.mm b/vcl/aqua/source/a11y/aqua11ywrapperscrollarea.mm
new file mode 100644
index 000000000000..f375e5ce788d
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperscrollarea.mm
@@ -0,0 +1,84 @@
+/*************************************************************************
+ *
+ * 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 "salinst.h"
+#include "aqua11ywrapperscrollarea.h"
+#include "aqua11ywrapperscrollbar.h"
+#include "aqua11yrolehelper.h"
+
+// Wrapper for AXScrollArea role
+
+@implementation AquaA11yWrapperScrollArea : AquaA11yWrapper
+
+-(id)scrollBarWithOrientation:(NSString *)orientation {
+ AquaA11yWrapper * theScrollBar = nil;
+ NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ];
+ NSArray * elementChildren = [ self accessibilityAttributeValue: NSAccessibilityChildrenAttribute ];
+ if ( [ elementChildren count ] > 0 ) {
+ NSEnumerator * enumerator = [ elementChildren objectEnumerator ];
+ id child;
+ while ( ( child = [ enumerator nextObject ] ) ) {
+ AquaA11yWrapper * element = ( AquaA11yWrapper * ) child;
+ if ( [ element isKindOfClass: [ AquaA11yWrapperScrollBar class ] ] ) {
+ AquaA11yWrapperScrollBar * scrollBar = (AquaA11yWrapperScrollBar *) element;
+ if ( [ [ scrollBar orientationAttribute ] isEqualToString: orientation ] ) {
+ theScrollBar = scrollBar;
+ break;
+ }
+ }
+ }
+ }
+ [ pool release ];
+ return theScrollBar;
+}
+
+-(id)verticalScrollBarAttribute {
+ return [ self scrollBarWithOrientation: NSAccessibilityVerticalOrientationValue ];
+}
+
+-(id)horizontalScrollBarAttribute {
+ return [ self scrollBarWithOrientation: NSAccessibilityHorizontalOrientationValue ];
+}
+
+-(NSArray *)accessibilityAttributeNames {
+ // Default Attributes
+ NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ];
+ // Special Attributes and removing unwanted attributes depending on role
+ [ attributeNames removeObject: NSAccessibilityEnabledAttribute ];
+ [ attributeNames addObjectsFromArray: [ NSArray arrayWithObjects:
+ NSAccessibilityContentsAttribute,
+ NSAccessibilityVerticalScrollBarAttribute,
+ NSAccessibilityHorizontalScrollBarAttribute,
+ nil ]
+ ];
+ return attributeNames;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperscrollbar.h b/vcl/aqua/source/a11y/aqua11ywrapperscrollbar.h
new file mode 100644
index 000000000000..1070c682cd5e
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperscrollbar.h
@@ -0,0 +1,39 @@
+/*************************************************************************
+ *
+ * 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_AQUA11WRAPPERSCROLLBAR_H
+#define _SV_AQUA11WRAPPERSCROLLBAR_H
+
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yWrapperScrollBar : AquaA11yWrapper
+{
+}
+-(NSArray *)accessibilityAttributeNames;
+@end
+
+#endif // _SV_AQUA11WRAPPERSCROLLBAR_H
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperscrollbar.mm b/vcl/aqua/source/a11y/aqua11ywrapperscrollbar.mm
new file mode 100644
index 000000000000..826da647055b
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperscrollbar.mm
@@ -0,0 +1,49 @@
+/*************************************************************************
+ *
+ * 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 "salinst.h"
+#include "aqua11ywrapperscrollbar.h"
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+
+using namespace ::com::sun::star::accessibility;
+
+// Wrapper for AXScrollBar role
+
+@implementation AquaA11yWrapperScrollBar : AquaA11yWrapper
+
+-(NSArray *)accessibilityAttributeNames {
+ // Default Attributes
+ NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ];
+ // Special Attributes and removing unwanted attributes depending on role
+ [ attributeNames addObject: NSAccessibilityOrientationAttribute ];
+ return attributeNames;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrappersplitter.h b/vcl/aqua/source/a11y/aqua11ywrappersplitter.h
new file mode 100644
index 000000000000..084a72ea7a18
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrappersplitter.h
@@ -0,0 +1,39 @@
+/*************************************************************************
+ *
+ * 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_AQUA11WRAPPERSPLITTER_H
+#define _SV_AQUA11WRAPPERSPLITTER_H
+
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yWrapperSplitter : AquaA11yWrapper
+{
+}
+-(NSArray *)accessibilityAttributeNames;
+@end
+
+#endif // _SV_AQUA11WRAPPERSPLITTER_H
diff --git a/vcl/aqua/source/a11y/aqua11ywrappersplitter.mm b/vcl/aqua/source/a11y/aqua11ywrappersplitter.mm
new file mode 100644
index 000000000000..4dc645c006c8
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrappersplitter.mm
@@ -0,0 +1,48 @@
+/*************************************************************************
+ *
+ * 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 "salinst.h"
+#include "aqua11ywrappersplitter.h"
+
+using namespace ::com::sun::star::accessibility;
+
+// Wrapper for AXSplitter role
+
+@implementation AquaA11yWrapperSplitter : AquaA11yWrapper
+
+-(NSArray *)accessibilityAttributeNames {
+ // Default Attributes
+ NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ];
+ // Special Attributes and removing unwanted attributes depending on role
+ [ attributeNames addObject: NSAccessibilityOrientationAttribute ];
+ return attributeNames;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperstatictext.h b/vcl/aqua/source/a11y/aqua11ywrapperstatictext.h
new file mode 100644
index 000000000000..c21e5573d125
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperstatictext.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_AQUA11WRAPPERSTATICTEXT_H
+#define _SV_AQUA11WRAPPERSTATICTEXT_H
+
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yWrapperStaticText : AquaA11yWrapper
+{
+}
+-(id)titleAttribute;
+-(NSArray *)accessibilityAttributeNames;
+@end
+
+#endif // _SV_AQUA11WRAPPERSTATICTEXT_H
diff --git a/vcl/aqua/source/a11y/aqua11ywrapperstatictext.mm b/vcl/aqua/source/a11y/aqua11ywrapperstatictext.mm
new file mode 100644
index 000000000000..7192e64b2e7c
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrapperstatictext.mm
@@ -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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "salinst.h"
+#include "aqua11ywrapperstatictext.h"
+
+// Wrapper for AXStaticText role
+
+@implementation AquaA11yWrapperStaticText : AquaA11yWrapper
+
+-(id)titleAttribute {
+ NSString * title = [ super titleAttribute ];
+ if ( [ title isEqualToString: [ super valueAttribute ] ] ) {
+ return [ NSString string ];
+ }
+ return title;
+}
+
+-(NSArray *)accessibilityAttributeNames {
+ // Default Attributes
+ NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ];
+ // Special Attributes and removing unwanted attributes depending on role
+ [ attributeNames removeObject: NSAccessibilityTitleAttribute ];
+ [ attributeNames removeObject: NSAccessibilitySharedTextUIElementsAttribute ];
+ [ attributeNames removeObject: NSAccessibilitySharedCharacterRangeAttribute ];
+ return attributeNames;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrappertabgroup.h b/vcl/aqua/source/a11y/aqua11ywrappertabgroup.h
new file mode 100644
index 000000000000..be72b9e27396
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrappertabgroup.h
@@ -0,0 +1,39 @@
+/*************************************************************************
+ *
+ * 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_AQUA11WRAPPERTABGROUP_H
+#define _SV_AQUA11WRAPPERTABGROUP_H
+
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yWrapperTabGroup : AquaA11yWrapper
+{
+}
+-(NSArray *)accessibilityAttributeNames;
+@end
+
+#endif // _SV_AQUA11WRAPPERTABGROUP_H
diff --git a/vcl/aqua/source/a11y/aqua11ywrappertabgroup.mm b/vcl/aqua/source/a11y/aqua11ywrappertabgroup.mm
new file mode 100644
index 000000000000..708ae5440c4f
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrappertabgroup.mm
@@ -0,0 +1,50 @@
+/*************************************************************************
+ *
+ * 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 "salinst.h"
+#include "aqua11ywrappertabgroup.h"
+
+// Wrapper for AXTabGroup role
+
+@implementation AquaA11yWrapperTabGroup : AquaA11yWrapper
+
+-(NSArray *)accessibilityAttributeNames {
+ // Default Attributes
+ NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ];
+ // Special Attributes and removing unwanted attributes depending on role
+ [ attributeNames addObjectsFromArray: [ NSArray arrayWithObjects:
+ NSAccessibilityContentsAttribute,
+ NSAccessibilityTabsAttribute,
+ nil ]
+ ];
+ return attributeNames;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrappertextarea.h b/vcl/aqua/source/a11y/aqua11ywrappertextarea.h
new file mode 100644
index 000000000000..724f85994053
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrappertextarea.h
@@ -0,0 +1,39 @@
+/*************************************************************************
+ *
+ * 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_AQUA11WRAPPERTEXTAREA_H
+#define _SV_AQUA11WRAPPERTEXTAREA_H
+
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yWrapperTextArea : AquaA11yWrapper
+{
+}
+-(NSArray *)accessibilityAttributeNames;
+@end
+
+#endif // _SV_AQUA11WRAPPERTEXTAREA_H
diff --git a/vcl/aqua/source/a11y/aqua11ywrappertextarea.mm b/vcl/aqua/source/a11y/aqua11ywrappertextarea.mm
new file mode 100644
index 000000000000..9a425eb2b893
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrappertextarea.mm
@@ -0,0 +1,48 @@
+/*************************************************************************
+ *
+ * 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 "salinst.h"
+#include "aqua11ywrappertextarea.h"
+
+// Wrapper for AXTextArea role
+
+@implementation AquaA11yWrapperTextArea : AquaA11yWrapper
+
+-(NSArray *)accessibilityAttributeNames {
+ // Default Attributes
+ NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ];
+ // Special Attributes and removing unwanted attributes depending on role
+ [ attributeNames removeObject: NSAccessibilityTitleAttribute ];
+ [ attributeNames removeObject: NSAccessibilityEnabledAttribute ];
+ [ attributeNames addObject: NSAccessibilityChildrenAttribute ];
+ return attributeNames;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/aqua11ywrappertoolbar.h b/vcl/aqua/source/a11y/aqua11ywrappertoolbar.h
new file mode 100644
index 000000000000..e7ac0a25acec
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrappertoolbar.h
@@ -0,0 +1,39 @@
+/*************************************************************************
+ *
+ * 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_AQUA11WRAPPERTOOLBAR_H
+#define _SV_AQUA11WRAPPERTOOLBAR_H
+
+#include "aqua11ywrapper.h"
+
+@interface AquaA11yWrapperToolbar : AquaA11yWrapper
+{
+}
+-(NSArray *)accessibilityAttributeNames;
+@end
+
+#endif // _SV_AQUA11WRAPPERTOOLBAR_H
diff --git a/vcl/aqua/source/a11y/aqua11ywrappertoolbar.mm b/vcl/aqua/source/a11y/aqua11ywrappertoolbar.mm
new file mode 100644
index 000000000000..28990355af55
--- /dev/null
+++ b/vcl/aqua/source/a11y/aqua11ywrappertoolbar.mm
@@ -0,0 +1,50 @@
+/*************************************************************************
+ *
+ * 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 "salinst.h"
+#include "aqua11ywrappertoolbar.h"
+
+// Wrapper for AXToolbar role
+
+@implementation AquaA11yWrapperToolbar : AquaA11yWrapper
+
+-(NSArray *)accessibilityAttributeNames {
+ // Default Attributes
+ NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ];
+ // Special Attributes and removing unwanted attributes depending on role
+ [ attributeNames removeObjectsInArray: [ NSArray arrayWithObjects:
+ NSAccessibilityTitleAttribute,
+ NSAccessibilityEnabledAttribute,
+ nil ]
+ ];
+ return attributeNames;
+}
+
+@end
diff --git a/vcl/aqua/source/a11y/documentfocuslistener.cxx b/vcl/aqua/source/a11y/documentfocuslistener.cxx
new file mode 100644
index 000000000000..02a7337ce397
--- /dev/null
+++ b/vcl/aqua/source/a11y/documentfocuslistener.cxx
@@ -0,0 +1,253 @@
+/*************************************************************************
+ *
+ * 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 "documentfocuslistener.hxx"
+
+#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLEEVENTBROADCASTER_HPP_
+#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
+#endif
+
+#ifndef _COM_SUN_STAR_ACCESSIBILITY_ACCESSIBLEEVENTID_HPP_
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#endif
+
+#ifndef _COM_SUN_STAR_ACCESSIBILITY_ACCESSIBLESTATETYPE_HPP_
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#endif
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+
+
+//------------------------------------------------------------------------------
+
+DocumentFocusListener::DocumentFocusListener(AquaA11yFocusTracker& rTracker) :
+ m_aFocusTracker(rTracker)
+{
+}
+
+//------------------------------------------------------------------------------
+
+void SAL_CALL
+DocumentFocusListener::disposing( const EventObject& aEvent )
+ throw (RuntimeException)
+{
+ // Unref the object here, but do not remove as listener since the object
+ // might no longer be in a state that safely allows this.
+ if( aEvent.Source.is() )
+ m_aRefList.erase(aEvent.Source);
+}
+
+//------------------------------------------------------------------------------
+
+void SAL_CALL
+DocumentFocusListener::notifyEvent( const AccessibleEventObject& aEvent )
+ throw( RuntimeException )
+{
+ switch( aEvent.EventId )
+ {
+ case AccessibleEventId::STATE_CHANGED:
+ try
+ {
+ sal_Int16 nState = AccessibleStateType::INVALID;
+ aEvent.NewValue >>= nState;
+
+ if( AccessibleStateType::FOCUSED == nState )
+ m_aFocusTracker.setFocusedObject( getAccessible(aEvent) );
+ }
+ catch(IndexOutOfBoundsException e)
+ {
+ OSL_TRACE("Focused object has invalid index in parent");
+ }
+ break;
+
+ case AccessibleEventId::CHILD:
+ {
+ Reference< XAccessible > xChild;
+ if( (aEvent.OldValue >>= xChild) && xChild.is() )
+ detachRecursive(xChild);
+
+ if( (aEvent.NewValue >>= xChild) && xChild.is() )
+ attachRecursive(xChild);
+ }
+ break;
+
+ case AccessibleEventId::INVALIDATE_ALL_CHILDREN:
+ {
+ Reference< XAccessible > xAccessible( getAccessible(aEvent) );
+ detachRecursive(xAccessible);
+ attachRecursive(xAccessible);
+ }
+
+ OSL_TRACE( "Invalidate all children called\n" );
+ break;
+ default:
+ break;
+ }
+}
+
+//------------------------------------------------------------------------------
+
+Reference< XAccessible > DocumentFocusListener::getAccessible(const EventObject& aEvent )
+ throw (IndexOutOfBoundsException, RuntimeException)
+{
+ Reference< XAccessible > xAccessible(aEvent.Source, UNO_QUERY);
+
+ if( xAccessible.is() )
+ return xAccessible;
+
+ Reference< XAccessibleContext > xContext(aEvent.Source, UNO_QUERY);
+
+ if( xContext.is() )
+ {
+ Reference< XAccessible > xParent( xContext->getAccessibleParent() );
+ if( xParent.is() )
+ {
+ Reference< XAccessibleContext > xParentContext( xParent->getAccessibleContext() );
+ if( xParentContext.is() )
+ {
+ return xParentContext->getAccessibleChild( xContext->getAccessibleIndexInParent() );
+ }
+ }
+ }
+
+ return Reference< XAccessible >();
+}
+
+//------------------------------------------------------------------------------
+
+void DocumentFocusListener::attachRecursive(const Reference< XAccessible >& xAccessible)
+ throw (IndexOutOfBoundsException, RuntimeException)
+{
+ Reference< XAccessibleContext > xContext = xAccessible->getAccessibleContext();
+
+ if( xContext.is() )
+ attachRecursive(xAccessible, xContext);
+}
+
+//------------------------------------------------------------------------------
+
+void DocumentFocusListener::attachRecursive(
+ const Reference< XAccessible >& xAccessible,
+ const Reference< XAccessibleContext >& xContext
+) throw (IndexOutOfBoundsException, RuntimeException)
+{
+ if( xContext.is() )
+ {
+ Reference< XAccessibleStateSet > xStateSet = xContext->getAccessibleStateSet();
+
+ if( xStateSet.is() )
+ attachRecursive(xAccessible, xContext, xStateSet);
+ }
+}
+
+//------------------------------------------------------------------------------
+
+void DocumentFocusListener::attachRecursive(
+ const Reference< XAccessible >& xAccessible,
+ const Reference< XAccessibleContext >& xContext,
+ const Reference< XAccessibleStateSet >& xStateSet
+) throw (IndexOutOfBoundsException,RuntimeException)
+{
+ if( xStateSet->contains(AccessibleStateType::FOCUSED ) )
+ m_aFocusTracker.setFocusedObject( xAccessible );
+
+ Reference< XAccessibleEventBroadcaster > xBroadcaster =
+ Reference< XAccessibleEventBroadcaster >(xContext, UNO_QUERY);
+
+ // If not already done, add the broadcaster to the list and attach as listener.
+ if( xBroadcaster.is() && m_aRefList.insert(xBroadcaster).second )
+ {
+ xBroadcaster->addEventListener(static_cast< XAccessibleEventListener *>(this));
+
+ if( ! xStateSet->contains(AccessibleStateType::MANAGES_DESCENDANTS ) )
+ {
+ sal_Int32 n, nmax = xContext->getAccessibleChildCount();
+ for( n = 0; n < nmax; n++ )
+ {
+ Reference< XAccessible > xChild( xContext->getAccessibleChild( n ) );
+
+ if( xChild.is() )
+ attachRecursive(xChild);
+ }
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+
+void DocumentFocusListener::detachRecursive(const Reference< XAccessible >& xAccessible)
+ throw (IndexOutOfBoundsException, RuntimeException)
+{
+ Reference< XAccessibleContext > xContext = xAccessible->getAccessibleContext();
+
+ if( xContext.is() )
+ detachRecursive(xAccessible, xContext);
+}
+
+//------------------------------------------------------------------------------
+
+void DocumentFocusListener::detachRecursive(
+ const Reference< XAccessible >& xAccessible,
+ const Reference< XAccessibleContext >& xContext
+) throw (IndexOutOfBoundsException, RuntimeException)
+{
+ Reference< XAccessibleStateSet > xStateSet = xContext->getAccessibleStateSet();
+
+ if( xStateSet.is() )
+ detachRecursive(xAccessible, xContext, xStateSet);
+}
+
+//------------------------------------------------------------------------------
+
+void DocumentFocusListener::detachRecursive(
+ const Reference< XAccessible >&,
+ const Reference< XAccessibleContext >& xContext,
+ const Reference< XAccessibleStateSet >& xStateSet
+) throw (IndexOutOfBoundsException, RuntimeException)
+{
+ Reference< XAccessibleEventBroadcaster > xBroadcaster =
+ Reference< XAccessibleEventBroadcaster >(xContext, UNO_QUERY);
+
+ if( xBroadcaster.is() && 0 < m_aRefList.erase(xBroadcaster) )
+ {
+ xBroadcaster->removeEventListener(static_cast< XAccessibleEventListener *>(this));
+
+ if( ! xStateSet->contains(AccessibleStateType::MANAGES_DESCENDANTS ) )
+ {
+ sal_Int32 n, nmax = xContext->getAccessibleChildCount();
+ for( n = 0; n < nmax; n++ )
+ {
+ Reference< XAccessible > xChild( xContext->getAccessibleChild( n ) );
+
+ if( xChild.is() )
+ detachRecursive(xChild);
+ }
+ }
+ }
+}
diff --git a/vcl/aqua/source/a11y/documentfocuslistener.hxx b/vcl/aqua/source/a11y/documentfocuslistener.hxx
new file mode 100644
index 000000000000..863bc59d173f
--- /dev/null
+++ b/vcl/aqua/source/a11y/documentfocuslistener.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _DOCUMENTFOCUSLISTENER_HXX_
+#define _DOCUMENTFOCUSLISTENER_HXX_
+
+#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLEEVENTLISTENER_HPP_
+#include <com/sun/star/accessibility/XAccessibleEventListener.hpp>
+#endif
+
+#ifndef _CPPUHELPER_IMPLBASE1_HXX_
+#include <cppuhelper/implbase1.hxx>
+#endif
+
+#include "aqua11yfocustracker.hxx"
+#include <set>
+
+// -------------------------
+// - DocumentFocusListener -
+// -------------------------
+
+class DocumentFocusListener :
+ public ::cppu::WeakImplHelper1< ::com::sun::star::accessibility::XAccessibleEventListener >
+{
+
+public:
+
+ DocumentFocusListener(AquaA11yFocusTracker& rTracker);
+
+ void attachRecursive(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& xAccessible
+ ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException);
+
+ void attachRecursive(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& xAccessible,
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >& xContext
+ ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException);
+
+ void attachRecursive(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& xAccessible,
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >& xContext,
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleStateSet >& xStateSet
+ ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException);
+
+ void detachRecursive(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& xAccessible
+ ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException);
+
+ void detachRecursive(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& xAccessible,
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >& xContext
+ ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException);
+
+ void detachRecursive(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& xAccessible,
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >& xContext,
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleStateSet >& xStateSet
+ ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException);
+
+ static ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > getAccessible(const ::com::sun::star::lang::EventObject& aEvent )
+ throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException);
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source )
+ throw (::com::sun::star::uno::RuntimeException);
+
+ // XAccessibleEventListener
+ virtual void SAL_CALL notifyEvent( const ::com::sun::star::accessibility::AccessibleEventObject& aEvent )
+ throw( ::com::sun::star::uno::RuntimeException );
+
+private:
+ std::set< ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > > m_aRefList;
+
+ AquaA11yFocusTracker& m_aFocusTracker;
+};
+
+#endif // _DOCUMENTFOCUSLISTENER_HXX_ \ No newline at end of file
diff --git a/vcl/aqua/source/a11y/makefile.mk b/vcl/aqua/source/a11y/makefile.mk
new file mode 100644
index 000000000000..0a16281e5a69
--- /dev/null
+++ b/vcl/aqua/source/a11y/makefile.mk
@@ -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.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+
+PRJNAME=vcl
+TARGET=sala11y
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+ENABLE_EXCEPTIONS=TRUE
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)"!="aqua"
+
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+
+.ELSE # "$(GUIBASE)"!="aqua"
+
+SLOFILES= \
+ $(SLO)$/aqua11ywrapper.obj \
+ $(SLO)$/aqua11yfactory.obj \
+ $(SLO)$/aqua11yfocuslistener.obj \
+ $(SLO)$/aqua11yfocustracker.obj \
+ $(SLO)$/aqua11ylistener.obj \
+ $(SLO)$/aqua11yrolehelper.obj \
+ $(SLO)$/aqua11yactionwrapper.obj \
+ $(SLO)$/aqua11ycomponentwrapper.obj \
+ $(SLO)$/aqua11yselectionwrapper.obj \
+ $(SLO)$/aqua11ytablewrapper.obj \
+ $(SLO)$/aqua11ytextattributeswrapper.obj \
+ $(SLO)$/aqua11ytextwrapper.obj \
+ $(SLO)$/aqua11yutil.obj \
+ $(SLO)$/aqua11yvaluewrapper.obj \
+ $(SLO)$/aqua11ywrapperbutton.obj \
+ $(SLO)$/aqua11ywrappercheckbox.obj \
+ $(SLO)$/aqua11ywrappercombobox.obj \
+ $(SLO)$/aqua11ywrappergroup.obj \
+ $(SLO)$/aqua11ywrapperlist.obj \
+ $(SLO)$/aqua11ywrapperradiobutton.obj \
+ $(SLO)$/aqua11ywrapperradiogroup.obj \
+ $(SLO)$/aqua11ywrapperrow.obj \
+ $(SLO)$/aqua11ywrapperscrollarea.obj \
+ $(SLO)$/aqua11ywrapperscrollbar.obj \
+ $(SLO)$/aqua11ywrappersplitter.obj \
+ $(SLO)$/aqua11ywrapperstatictext.obj \
+ $(SLO)$/aqua11ywrappertabgroup.obj \
+ $(SLO)$/aqua11ywrappertextarea.obj \
+ $(SLO)$/aqua11ywrappertoolbar.obj \
+ $(SLO)$/documentfocuslistener.obj
+
+.ENDIF # "$(GUIBASE)"!="aqua"
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
+.INCLUDE : $(PRJ)$/util$/target.pmk
diff --git a/vcl/aqua/source/a11y/readme.txt b/vcl/aqua/source/a11y/readme.txt
new file mode 100644
index 000000000000..19e80ab1a162
--- /dev/null
+++ b/vcl/aqua/source/a11y/readme.txt
@@ -0,0 +1,8 @@
+Naming scheme:
+
+aqua11yXYZhelper: Helper class providing static methods
+
+aqua11yXYZwrapper: Wrapper around one (or two) UNO-interfaces
+
+aqua11ywrapperXYZ: Subclass of aqua11ywrapper for a specific AXRole
+
diff --git a/vcl/aqua/source/app/makefile.mk b/vcl/aqua/source/app/makefile.mk
new file mode 100644
index 000000000000..a0ddcbc02226
--- /dev/null
+++ b/vcl/aqua/source/app/makefile.mk
@@ -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.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+
+PRJNAME=vcl
+TARGET=salapp
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+ENABLE_EXCEPTIONS=TRUE
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)"!="aqua"
+
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+
+.ELSE # "$(GUIBASE)"!="aqua"
+
+SLOFILES= $(SLO)$/salinst.obj \
+ $(SLO)$/saldata.obj \
+ $(SLO)$/vclnsapp.obj \
+ $(SLO)$/saltimer.obj \
+ $(SLO)$/salnstimer.obj \
+ $(SLO)$/salsys.obj
+
+.ENDIF # "$(GUIBASE)"!="aqua"
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
+.INCLUDE : $(PRJ)$/util$/target.pmk
+
diff --git a/vcl/aqua/source/app/saldata.cxx b/vcl/aqua/source/app/saldata.cxx
new file mode 100644
index 000000000000..3cb878636ad3
--- /dev/null
+++ b/vcl/aqua/source/app/saldata.cxx
@@ -0,0 +1,293 @@
+/*************************************************************************
+ *
+ * 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 "saldata.hxx"
+#include "salnsmenu.h"
+#include "salinst.h"
+#import "apple_remote/RemoteMainController.h"
+
+oslThreadKey SalData::s_aAutoReleaseKey = 0;
+
+static void SAL_CALL releasePool( void* pPool )
+{
+ if( pPool )
+ [(NSAutoreleasePool*)pPool release];
+}
+
+SalData::SalData()
+:
+ mpTimerProc( NULL ),
+ mpFirstInstance( NULL ),
+ mpFirstObject( NULL ),
+ mpFirstVD( NULL ),
+ mpFirstPrinter( NULL ),
+ mpFontList( NULL ),
+ mpStatusItem( nil ),
+ mxRGBSpace( CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB) ),
+ mxGraySpace( CGColorSpaceCreateWithName(kCGColorSpaceGenericGray) ),
+ mxP50Space( NULL ),
+ mxP50Pattern( NULL ),
+ maCursors( POINTER_COUNT, INVALID_CURSOR_PTR ),
+ mbIsScrollbarDoubleMax( false ),
+ mnSystemVersion( VER_TIGER ),
+ mpMainController( NULL ),
+ mpDockIconClickHandler( nil ),
+ mnDPIX( 0 ),
+ mnDPIY( 0 )
+{
+ if( s_aAutoReleaseKey == 0 )
+ s_aAutoReleaseKey = osl_createThreadKey( releasePool );
+}
+
+SalData::~SalData()
+{
+ CGPatternRelease( mxP50Pattern );
+ CGColorSpaceRelease( mxP50Space );
+ CGColorSpaceRelease( mxRGBSpace );
+ CGColorSpaceRelease( mxGraySpace );
+ for( unsigned int i = 0; i < maCursors.size(); i++ )
+ {
+ NSCursor* pCurs = maCursors[i];
+ if( pCurs && pCurs != INVALID_CURSOR_PTR )
+ [pCurs release];
+ }
+ if( s_aAutoReleaseKey )
+ {
+ // release the last pool
+ NSAutoreleasePool* pPool = nil;
+ pPool = reinterpret_cast<NSAutoreleasePool*>( osl_getThreadKeyData( s_aAutoReleaseKey ) );
+ if( pPool )
+ {
+ osl_setThreadKeyData( s_aAutoReleaseKey, NULL );
+ [pPool release];
+ }
+
+ osl_destroyThreadKey( s_aAutoReleaseKey );
+ s_aAutoReleaseKey = 0;
+ }
+ if ( mpMainController )
+ [mpMainController release];
+}
+
+void SalData::ensureThreadAutoreleasePool()
+{
+ NSAutoreleasePool* pPool = nil;
+ if( s_aAutoReleaseKey )
+ {
+ pPool = reinterpret_cast<NSAutoreleasePool*>( osl_getThreadKeyData( s_aAutoReleaseKey ) );
+ if( ! pPool )
+ {
+ pPool = [[NSAutoreleasePool alloc] init];
+ osl_setThreadKeyData( s_aAutoReleaseKey, pPool );
+ }
+ }
+ else
+ {
+ DBG_ERROR( "no autorelease key" );
+ }
+}
+
+void SalData::drainThreadAutoreleasePool()
+{
+ NSAutoreleasePool* pPool = nil;
+ if( s_aAutoReleaseKey )
+ {
+ pPool = reinterpret_cast<NSAutoreleasePool*>( osl_getThreadKeyData( s_aAutoReleaseKey ) );
+ if( pPool )
+ {
+ // osl_setThreadKeyData( s_aAutoReleaseKey, NULL );
+ // [pPool release];
+ [pPool drain];
+ }
+ else
+ {
+ pPool = [[NSAutoreleasePool alloc] init];
+ osl_setThreadKeyData( s_aAutoReleaseKey, pPool );
+ }
+ }
+ else
+ {
+ DBG_ERROR( "no autorelease key" );
+ }
+}
+
+
+struct curs_ent
+{
+ const char* pBaseName;
+ const NSPoint aHotSpot;
+}
+const aCursorTab[ POINTER_COUNT ] =
+{
+{ NULL, { 0, 0 } }, //POINTER_ARROW
+{ "nullptr", { 16, 16 } }, //POINTER_NULL
+{ "hourglass", { 15, 15 } }, //POINTER_WAIT
+{ NULL, { 0, 0 } }, //POINTER_TEXT
+{ "help", { 0, 0 } }, //POINTER_HELP
+{ NULL, { 0, 0 } }, //POINTER_CROSS
+{ NULL, { 0, 0 } }, //POINTER_MOVE
+{ NULL, { 0, 0 } }, //POINTER_NSIZE
+{ NULL, { 0, 0 } }, //POINTER_SSIZE
+{ NULL, { 0, 0 } }, //POINTER_WSIZE
+{ NULL, { 0, 0 } }, //POINTER_ESIZE
+{ "nwsesize", { 15, 15 } }, //POINTER_NWSIZE
+{ "neswsize", { 15, 15 } }, //POINTER_NESIZE
+{ "neswsize", { 15, 15 } }, //POINTER_SWSIZE
+{ "nwsesize", { 15, 15 } }, //POINTER_SESIZE
+{ NULL, { 0, 0 } }, //POINTER_WINDOW_NSIZE
+{ NULL, { 0, 0 } }, //POINTER_WINDOW_SSIZE
+{ NULL, { 0, 0 } }, //POINTER_WINDOW_WSIZE
+{ NULL, { 0, 0 } }, //POINTER_WINDOW_ESIZE
+{ "nwsesize", { 15, 15 } }, //POINTER_WINDOW_NWSIZE
+{ "neswsize", { 15, 15 } }, //POINTER_WINDOW_NESIZE
+{ "neswsize", { 15, 15 } }, //POINTER_WINDOW_SWSIZE
+{ "nwsesize", { 15, 15 } }, //POINTER_WINDOW_SESIZE
+{ NULL, { 0, 0 } }, //POINTER_HSPLIT
+{ NULL, { 0, 0 } }, //POINTER_VSPLIT
+{ NULL, { 0, 0 } }, //POINTER_HSIZEBAR
+{ NULL, { 0, 0 } }, //POINTER_VSIZEBAR
+{ NULL, { 0, 0 } }, //POINTER_HAND
+{ NULL, { 0, 0 } }, //POINTER_REFHAND
+{ "pen", { 3, 27 } }, //POINTER_PEN
+{ "magnify", { 12, 13 } }, //POINTER_MAGNIFY
+{ "fill", { 10, 22 } }, //POINTER_FILL
+{ "rotate", { 15, 15 } }, //POINTER_ROTATE
+{ "hshear", { 15, 15 } }, //POINTER_HSHEAR
+{ "vshear", { 15, 15 } }, //POINTER_VSHEAR
+{ "mirror", { 14, 12 } }, //POINTER_MIRROR
+{ "crook", { 15, 14 } }, //POINTER_CROOK
+{ "crop", { 9, 9 } }, //POINTER_CROP
+{ "movept", { 0, 0 } }, //POINTER_MOVEPOINT
+{ "movebw", { 0, 0 } }, //POINTER_MOVEBEZIERWEIGHT
+{ "movedata", { 0, 0 } }, //POINTER_MOVEDATA
+{ "copydata", { 0, 0 } }, //POINTER_COPYDATA
+{ "linkdata", { 0, 0 } }, //POINTER_LINKDATA
+{ "movedlnk", { 0, 0 } }, //POINTER_MOVEDATALINK
+{ "copydlnk", { 0, 0 } }, //POINTER_COPYDATALINK
+{ "movef", { 8, 8 } }, //POINTER_MOVEFILE
+{ "copyf", { 8, 8 } }, //POINTER_COPYFILE
+{ "linkf", { 8, 8 } }, //POINTER_LINKFILE
+{ "moveflnk", { 8, 8 } }, //POINTER_MOVEFILELINK
+{ "copyflnk", { 8, 8 } }, //POINTER_COPYFILELINK
+{ "movef2", { 7, 8 } }, //POINTER_MOVEFILES
+{ "copyf2", { 7, 8 } }, //POINTER_COPYFILES
+{ "notallow", { 15, 15 } }, //POINTER_NOTALLOWED
+{ "dline", { 8, 8 } }, //POINTER_DRAW_LINE
+{ "drect", { 8, 8 } }, //POINTER_DRAW_RECT
+{ "dpolygon", { 8, 8 } }, //POINTER_DRAW_POLYGON
+{ "dbezier", { 8, 8 } }, //POINTER_DRAW_BEZIER
+{ "darc", { 8, 8 } }, //POINTER_DRAW_ARC
+{ "dpie", { 8, 8 } }, //POINTER_DRAW_PIE
+{ "dcirccut", { 8, 8 } }, //POINTER_DRAW_CIRCLECUT
+{ "dellipse", { 8, 8 } }, //POINTER_DRAW_ELLIPSE
+{ "dfree", { 8, 8 } }, //POINTER_DRAW_FREEHAND
+{ "dconnect", { 8, 8 } }, //POINTER_DRAW_CONNECT
+{ "dtext", { 8, 8 } }, //POINTER_DRAW_TEXT
+{ "dcapt", { 8, 8 } }, //POINTER_DRAW_CAPTION
+{ "chart", { 15, 16 } }, //POINTER_CHART
+{ "detectiv", { 12, 13 } }, //POINTER_DETECTIVE
+{ "pivotcol", { 7, 5 } }, //POINTER_PIVOT_COL
+{ "pivotrow", { 8, 7 } }, //POINTER_PIVOT_ROW
+{ "pivotfld", { 8, 7 } }, //POINTER_PIVOT_FIELD
+{ "chain", { 0, 2 } }, //POINTER_CHAIN
+{ "chainnot", { 2, 2 } }, //POINTER_CHAIN_NOTALLOWED
+{ "timemove", { 16, 16 } }, //POINTER_TIMEEVENT_MOVE
+{ "timesize", { 16, 17 } }, //POINTER_TIMEEVENT_SIZE
+{ "asn", { 16, 12 } }, //POINTER_AUTOSCROLL_N
+{ "ass", { 15, 19 } }, //POINTER_AUTOSCROLL_S
+{ "asw", { 12, 15 } }, //POINTER_AUTOSCROLL_W
+{ "ase", { 19, 16 } }, //POINTER_AUTOSCROLL_E
+{ "asnw", { 10, 10 } }, //POINTER_AUTOSCROLL_NW
+{ "asne", { 21, 10 } }, //POINTER_AUTOSCROLL_NE
+{ "assw", { 21, 21 } }, //POINTER_AUTOSCROLL_SW
+{ "asse", { 21, 21 } }, //POINTER_AUTOSCROLL_SE
+{ "asns", { 15, 15 } }, //POINTER_AUTOSCROLL_NS
+{ "aswe", { 15, 15 } }, //POINTER_AUTOSCROLL_WE
+{ "asnswe", { 15, 15 } }, //POINTER_AUTOSCROLL_NSWE
+{ "airbrush", { 5, 22 } }, //POINTER_AIRBRUSH
+{ "vtext", { 15, 15 } }, //POINTER_TEXT_VERTICAL
+{ "pivotdel", { 18, 15 } }, //POINTER_PIVOT_DELETE
+{ "tblsels", { 15, 30 } }, //POINTER_TAB_SELECT_S
+{ "tblsele", { 30, 16 } }, //POINTER_TAB_SELECT_E
+{ "tblselse", { 30, 30 } }, //POINTER_TAB_SELECT_SE
+{ "tblselw", { 1, 16 } }, //POINTER_TAB_SELECT_W
+{ "tblselsw", { 1, 30 } }, //POINTER_TAB_SELECT_SW
+{ "pntbrsh", { 9, 16 } } //POINTER_PAINTBRUSH
+};
+
+NSCursor* SalData::getCursor( PointerStyle i_eStyle )
+{
+ if( i_eStyle >= POINTER_COUNT )
+ return nil;
+
+ NSCursor* pCurs = maCursors[ i_eStyle ];
+ if( pCurs == INVALID_CURSOR_PTR )
+ {
+ pCurs = nil;
+ if( aCursorTab[ i_eStyle ].pBaseName )
+ {
+ NSPoint aHotSpot = aCursorTab[ i_eStyle ].aHotSpot;
+ CFStringRef pCursorName =
+ CFStringCreateWithCStringNoCopy(
+ kCFAllocatorDefault,
+ aCursorTab[ i_eStyle ].pBaseName,
+ kCFStringEncodingASCII,
+ kCFAllocatorNull );
+ CFBundleRef hMain = CFBundleGetMainBundle();
+ CFURLRef hURL = CFBundleCopyResourceURL( hMain, pCursorName, CFSTR("png"), CFSTR("cursors") );
+ if( hURL )
+ {
+ pCurs = [[NSCursor alloc] initWithImage: [[NSImage alloc] initWithContentsOfURL: (NSURL*)hURL] hotSpot: aHotSpot];
+ CFRelease( hURL );
+ }
+ CFRelease( pCursorName );
+ }
+ maCursors[ i_eStyle ] = pCurs;
+ }
+ return pCurs;
+}
+
+NSStatusItem* SalData::getStatusItem()
+{
+ SalData* pData = GetSalData();
+ if( ! pData->mpStatusItem )
+ {
+ NSStatusBar* pStatBar =[NSStatusBar systemStatusBar];
+ if( pStatBar )
+ {
+ pData->mpStatusItem = [pStatBar statusItemWithLength: NSVariableStatusItemLength];
+ [pData->mpStatusItem retain];
+ OOStatusItemView* pView = [[OOStatusItemView alloc] init];
+ [pData->mpStatusItem setView: pView ];
+ [pView display];
+ }
+ }
+ return pData->mpStatusItem;
+}
diff --git a/vcl/aqua/source/app/salinst.cxx b/vcl/aqua/source/app/salinst.cxx
new file mode 100644
index 000000000000..b8a2261ed9db
--- /dev/null
+++ b/vcl/aqua/source/app/salinst.cxx
@@ -0,0 +1,1313 @@
+/*************************************************************************
+ *
+ * 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 "tools/fsys.hxx"
+#include "tools/getprocessworkingdir.hxx"
+#include "osl/process.h"
+#include "rtl/ustrbuf.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/print.h"
+#include "vcl/salimestatus.hxx"
+#include "vcl/window.hxx"
+#include "vcl/timer.hxx"
+#include "vcl/impbmp.hxx"
+
+#include "saldata.hxx"
+#include "salinst.h"
+#include "salframe.h"
+#include "salobj.h"
+#include "salsys.h"
+#include "salvd.h"
+#include "salbmp.h"
+#include "salprn.h"
+#include "saltimer.h"
+#include "vclnsapp.h"
+
+#include <comphelper/processfactory.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/uri/XExternalUriReferenceTranslator.hpp>
+#include <com/sun/star/uri/ExternalUriReferenceTranslator.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include "premac.h"
+#include <Foundation/Foundation.h>
+#include <ApplicationServices/ApplicationServices.h>
+#import "apple_remote/RemoteMainController.h"
+#include "apple_remote/RemoteControl.h"
+#include "postmac.h"
+#include <tools/solarmutex.hxx>
+
+using namespace std;
+using namespace ::com::sun::star;
+
+extern BOOL ImplSVMain();
+
+static BOOL* gpbInit = 0;
+static NSMenu* pDockMenu = nil;
+static bool bNoSVMain = true;
+static bool bLeftMain = false;
+// -----------------------------------------------------------------------
+
+class AquaDelayedSettingsChanged : public Timer
+{
+ bool mbInvalidate;
+ public:
+ AquaDelayedSettingsChanged( bool bInvalidate ) :
+ mbInvalidate( bInvalidate )
+ {
+ }
+
+ virtual void Timeout()
+ {
+ SalData* pSalData = GetSalData();
+ if( ! pSalData->maFrames.empty() )
+ pSalData->maFrames.front()->CallCallback( SALEVENT_SETTINGSCHANGED, NULL );
+
+ if( mbInvalidate )
+ {
+ for( std::list< AquaSalFrame* >::iterator it = pSalData->maFrames.begin();
+ it != pSalData->maFrames.end(); ++it )
+ {
+ if( (*it)->mbShown )
+ (*it)->SendPaintEvent( NULL );
+ }
+ }
+ Stop();
+ delete this;
+ }
+};
+
+void AquaSalInstance::delayedSettingsChanged( bool bInvalidate )
+{
+ vos::OGuard aGuard( *mpSalYieldMutex );
+ AquaDelayedSettingsChanged* pTimer = new AquaDelayedSettingsChanged( bInvalidate );
+ pTimer->SetTimeout( 50 );
+ pTimer->Start();
+}
+
+
+// the AppEventList must be available before any SalData/SalInst/etc. objects are ready
+typedef std::list<const ApplicationEvent*> AppEventList;
+AppEventList AquaSalInstance::aAppEventList;
+
+NSMenu* AquaSalInstance::GetDynamicDockMenu()
+{
+ if( ! pDockMenu && ! bLeftMain )
+ pDockMenu = [[NSMenu alloc] initWithTitle: @""];
+ return pDockMenu;
+}
+
+bool AquaSalInstance::isOnCommandLine( const rtl::OUString& rArg )
+{
+ sal_uInt32 nArgs = osl_getCommandArgCount();
+ for( sal_uInt32 i = 0; i < nArgs; i++ )
+ {
+ rtl::OUString aArg;
+ osl_getCommandArg( i, &aArg.pData );
+ if( aArg.equals( rArg ) )
+ return true;
+ }
+ return false;
+}
+
+
+// initialize the cocoa VCL_NSApplication object
+// returns an NSAutoreleasePool that must be released when the event loop begins
+static void initNSApp()
+{
+ // create our cocoa NSApplication
+ [VCL_NSApplication sharedApplication];
+
+ SalData::ensureThreadAutoreleasePool();
+
+ // put cocoa into multithreaded mode
+ [NSThread detachNewThreadSelector:@selector(enableCocoaThreads:) toTarget:[[CocoaThreadEnabler alloc] init] withObject:nil];
+
+ // activate our delegate methods
+ [NSApp setDelegate: NSApp];
+
+ [[NSNotificationCenter defaultCenter] addObserver: NSApp
+ selector: @selector(systemColorsChanged:)
+ name: NSSystemColorsDidChangeNotification
+ object: nil ];
+ [[NSNotificationCenter defaultCenter] addObserver: NSApp
+ selector: @selector(screenParametersChanged:)
+ name: NSApplicationDidChangeScreenParametersNotification
+ object: nil ];
+ // add observers for some settings changes that affect vcl's settings
+ // scrollbar variant
+ [[NSDistributedNotificationCenter defaultCenter] addObserver: NSApp
+ selector: @selector(scrollbarVariantChanged:)
+ name: @"AppleAquaScrollBarVariantChanged"
+ object: nil ];
+ // scrollbar page behavior ("jump to here" or not)
+ [[NSDistributedNotificationCenter defaultCenter] addObserver: NSApp
+ selector: @selector(scrollbarSettingsChanged:)
+ name: @"AppleNoRedisplayAppearancePreferenceChanged"
+ object: nil ];
+
+ // get System Version and store the value in GetSalData()->mnSystemVersion
+ OSErr err = noErr;
+ SInt32 systemVersion = VER_TIGER; // Initialize with minimal requirement
+ if( (err = Gestalt(gestaltSystemVersion, &systemVersion)) == noErr )
+ {
+ GetSalData()->mnSystemVersion = systemVersion;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "System Version %x\n", (unsigned int)systemVersion);
+#endif
+ }
+ else
+ NSLog(@"Unable to obtain system version: %ld", (long)err);
+
+ // Initialize Apple Remote
+ GetSalData()->mpMainController = [[MainController alloc] init];
+
+ [[NSDistributedNotificationCenter defaultCenter] addObserver: NSApp
+ selector: @selector(applicationWillBecomeActive:)
+ name: @"AppleRemoteWillBecomeActive"
+ object: nil ];
+
+ [[NSDistributedNotificationCenter defaultCenter] addObserver: NSApp
+ selector: @selector(applicationWillResignActive:)
+ name: @"AppleRemoteWillResignActive"
+ object: nil ];
+
+ if( ImplGetSVData()->mbIsTestTool )
+ [NSApp activateIgnoringOtherApps: YES];
+}
+
+BOOL ImplSVMainHook( BOOL * pbInit )
+{
+ gpbInit = pbInit;
+
+ bNoSVMain = false;
+ initNSApp();
+
+ NSPoint aPt = { 0, 0 };
+ NSEvent* pEvent = [NSEvent otherEventWithType: NSApplicationDefined
+ location: aPt
+ modifierFlags: 0
+ timestamp: 0
+ windowNumber: 0
+ context: nil
+ subtype: AquaSalInstance::AppExecuteSVMain
+ data1: 0
+ data2: 0 ];
+ if( pEvent )
+ {
+ [NSApp postEvent: pEvent atStart: NO];
+
+ rtl::OUString aExeURL, aExe;
+ osl_getExecutableFile( &aExeURL.pData );
+ osl_getSystemPathFromFileURL( aExeURL.pData, &aExe.pData );
+ rtl::OString aByteExe( rtl::OUStringToOString( aExe, osl_getThreadTextEncoding() ) );
+
+#ifdef DEBUG
+ aByteExe += OString ( " NSAccessibilityDebugLogLevel 1" );
+ const char* pArgv[] = { aByteExe.getStr(), NULL };
+ NSApplicationMain( 3, pArgv );
+#else
+ const char* pArgv[] = { aByteExe.getStr(), NULL };
+ NSApplicationMain( 1, pArgv );
+#endif
+ }
+ else
+ {
+ DBG_ERROR( "NSApplication initialization could not be done" );
+ }
+
+ return TRUE; // indicate that ImplSVMainHook is implemented
+}
+
+// =======================================================================
+
+void SalAbort( const XubString& rErrorText )
+{
+ if( !rErrorText.Len() )
+ fprintf( stderr, "Application Error " );
+ else
+ fprintf( stderr, "%s ",
+ ByteString( rErrorText, gsl_getSystemTextEncoding() ).GetBuffer() );
+ abort();
+}
+
+// -----------------------------------------------------------------------
+
+void InitSalData()
+{
+ SalData *pSalData = new SalData;
+ SetSalData( pSalData );
+}
+
+// -----------------------------------------------------------------------
+
+const ::rtl::OUString& SalGetDesktopEnvironment()
+{
+ static OUString aDesktopEnvironment(RTL_CONSTASCII_USTRINGPARAM( "MacOSX" ));
+ return aDesktopEnvironment;
+}
+
+// -----------------------------------------------------------------------
+
+void DeInitSalData()
+{
+ SalData *pSalData = GetSalData();
+ if( pSalData->mpStatusItem )
+ {
+ [pSalData->mpStatusItem release];
+ pSalData->mpStatusItem = nil;
+ }
+ delete pSalData;
+ SetSalData( NULL );
+}
+
+// -----------------------------------------------------------------------
+
+extern "C" {
+#include <crt_externs.h>
+}
+
+// -----------------------------------------------------------------------
+
+void InitSalMain()
+{
+ rtl::OUString urlWorkDir;
+ rtl_uString *sysWorkDir = NULL;
+ if (tools::getProcessWorkingDir(&urlWorkDir))
+ {
+ oslFileError err2 = osl_getSystemPathFromFileURL(urlWorkDir.pData, &sysWorkDir);
+ if (err2 == osl_File_E_None)
+ {
+ ByteString aPath( getenv( "PATH" ) );
+ ByteString aResPath( getenv( "STAR_RESOURCEPATH" ) );
+ ByteString aLibPath( getenv( "DYLD_LIBRARY_PATH" ) );
+ ByteString aCmdPath( OUStringToOString(OUString(sysWorkDir), RTL_TEXTENCODING_UTF8).getStr() );
+ ByteString aTmpPath;
+ // Get absolute path of command's directory
+ if ( aCmdPath.Len() ) {
+ DirEntry aCmdDirEntry( aCmdPath );
+ aCmdDirEntry.ToAbs();
+ aCmdPath = ByteString( aCmdDirEntry.GetPath().GetFull(), RTL_TEXTENCODING_ASCII_US );
+ }
+ // Assign to PATH environment variable
+ if ( aCmdPath.Len() )
+ {
+ aTmpPath = ByteString( "PATH=" );
+ aTmpPath += aCmdPath;
+ if ( aPath.Len() )
+ aTmpPath += ByteString( DirEntry::GetSearchDelimiter(), RTL_TEXTENCODING_ASCII_US );
+ aTmpPath += aPath;
+ putenv( (char*)aTmpPath.GetBuffer() );
+ }
+ // Assign to STAR_RESOURCEPATH environment variable
+ if ( aCmdPath.Len() )
+ {
+ aTmpPath = ByteString( "STAR_RESOURCEPATH=" );
+ aTmpPath += aCmdPath;
+ if ( aResPath.Len() )
+ aTmpPath += ByteString( DirEntry::GetSearchDelimiter(), RTL_TEXTENCODING_ASCII_US );
+ aTmpPath += aResPath;
+ putenv( (char*)aTmpPath.GetBuffer() );
+ }
+ // Assign to DYLD_LIBRARY_PATH environment variable
+ if ( aCmdPath.Len() )
+ {
+ aTmpPath = ByteString( "DYLD_LIBRARY_PATH=" );
+ aTmpPath += aCmdPath;
+ if ( aLibPath.Len() )
+ aTmpPath += ByteString( DirEntry::GetSearchDelimiter(), RTL_TEXTENCODING_ASCII_US );
+ aTmpPath += aLibPath;
+ putenv( (char*)aTmpPath.GetBuffer() );
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void DeInitSalMain()
+{
+}
+
+// =======================================================================
+
+SalYieldMutex::SalYieldMutex()
+{
+ mnCount = 0;
+ mnThreadId = 0;
+}
+
+void SalYieldMutex::acquire()
+{
+ OMutex::acquire();
+ mnThreadId = NAMESPACE_VOS(OThread)::getCurrentIdentifier();
+ mnCount++;
+}
+
+void SalYieldMutex::release()
+{
+ if ( mnThreadId == NAMESPACE_VOS(OThread)::getCurrentIdentifier() )
+ {
+ if ( mnCount == 1 )
+ mnThreadId = 0;
+ mnCount--;
+ }
+ OMutex::release();
+}
+
+sal_Bool SalYieldMutex::tryToAcquire()
+{
+ if ( OMutex::tryToAcquire() )
+ {
+ mnThreadId = NAMESPACE_VOS(OThread)::getCurrentIdentifier();
+ mnCount++;
+ return sal_True;
+ }
+ else
+ return sal_False;
+}
+
+// -----------------------------------------------------------------------
+
+// some convenience functions regarding the yield mutex, aka solar mutex
+
+BOOL ImplSalYieldMutexTryToAcquire()
+{
+ AquaSalInstance* pInst = (AquaSalInstance*) GetSalData()->mpFirstInstance;
+ if ( pInst )
+ return pInst->mpSalYieldMutex->tryToAcquire();
+ else
+ return FALSE;
+}
+
+void ImplSalYieldMutexAcquire()
+{
+ AquaSalInstance* pInst = (AquaSalInstance*) GetSalData()->mpFirstInstance;
+ if ( pInst )
+ pInst->mpSalYieldMutex->acquire();
+}
+
+void ImplSalYieldMutexRelease()
+{
+ AquaSalInstance* pInst = (AquaSalInstance*) GetSalData()->mpFirstInstance;
+ if ( pInst )
+ pInst->mpSalYieldMutex->release();
+}
+
+// =======================================================================
+
+SalInstance* CreateSalInstance()
+{
+ // this is the case for not using SVMain
+ // not so good
+ if( bNoSVMain )
+ initNSApp();
+
+ SalData* pSalData = GetSalData();
+ DBG_ASSERT( pSalData->mpFirstInstance == NULL, "more than one instance created" );
+ AquaSalInstance* pInst = new AquaSalInstance;
+
+ // init instance (only one instance in this version !!!)
+ pSalData->mpFirstInstance = pInst;
+ // this one is for outside AquaSalInstance::Yield
+ SalData::ensureThreadAutoreleasePool();
+ // no focus rects on NWF aqua
+ ImplGetSVData()->maNWFData.mbNoFocusRects = true;
+ ImplGetSVData()->maNWFData.mbNoBoldTabFocus = true;
+ ImplGetSVData()->maNWFData.mbNoActiveTabTextRaise = true;
+ ImplGetSVData()->maNWFData.mbCenteredTabs = true;
+ ImplGetSVData()->maNWFData.mbProgressNeedsErase = true;
+ ImplGetSVData()->maNWFData.mbCheckBoxNeedsErase = true;
+ ImplGetSVData()->maGDIData.mbPrinterPullModel = true;
+ ImplGetSVData()->maGDIData.mbNoXORClipping = true;
+ ImplGetSVData()->maWinData.mbNoSaveBackground = true;
+
+ return pInst;
+}
+
+// -----------------------------------------------------------------------
+
+void DestroySalInstance( SalInstance* pInst )
+{
+ delete pInst;
+}
+
+// -----------------------------------------------------------------------
+
+AquaSalInstance::AquaSalInstance()
+{
+ mpSalYieldMutex = new SalYieldMutex;
+ mpSalYieldMutex->acquire();
+ ::tools::SolarMutex::SetSolarMutex( mpSalYieldMutex );
+ maMainThread = vos::OThread::getCurrentIdentifier();
+ mbWaitingYield = false;
+ maUserEventListMutex = osl_createMutex();
+ mnActivePrintJobs = 0;
+ maWaitingYieldCond = osl_createCondition();
+}
+
+// -----------------------------------------------------------------------
+
+AquaSalInstance::~AquaSalInstance()
+{
+ ::tools::SolarMutex::SetSolarMutex( 0 );
+ mpSalYieldMutex->release();
+ delete mpSalYieldMutex;
+ osl_destroyMutex( maUserEventListMutex );
+ osl_destroyCondition( maWaitingYieldCond );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInstance::wakeupYield()
+{
+ // wakeup :Yield
+ if( mbWaitingYield )
+ {
+ SalData::ensureThreadAutoreleasePool();
+ NSPoint aPt = { 0, 0 };
+ NSEvent* pEvent = [NSEvent otherEventWithType: NSApplicationDefined
+ location: aPt
+ modifierFlags: 0
+ timestamp: 0
+ windowNumber: 0
+ context: nil
+ subtype: AquaSalInstance::YieldWakeupEvent
+ data1: 0
+ data2: 0 ];
+ if( pEvent )
+ [NSApp postEvent: pEvent atStart: NO];
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInstance::PostUserEvent( AquaSalFrame* pFrame, USHORT nType, void* pData )
+{
+ osl_acquireMutex( maUserEventListMutex );
+ maUserEvents.push_back( SalUserEvent( pFrame, pData, nType ) );
+ osl_releaseMutex( maUserEventListMutex );
+
+ // notify main loop that an event has arrived
+ wakeupYield();
+}
+
+// -----------------------------------------------------------------------
+
+vos::IMutex* AquaSalInstance::GetYieldMutex()
+{
+ return mpSalYieldMutex;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG AquaSalInstance::ReleaseYieldMutex()
+{
+ SalYieldMutex* pYieldMutex = mpSalYieldMutex;
+ if ( pYieldMutex->GetThreadId() ==
+ NAMESPACE_VOS(OThread)::getCurrentIdentifier() )
+ {
+ ULONG nCount = pYieldMutex->GetAcquireCount();
+ ULONG n = nCount;
+ while ( n )
+ {
+ pYieldMutex->release();
+ n--;
+ }
+
+ return nCount;
+ }
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInstance::AcquireYieldMutex( ULONG nCount )
+{
+ SalYieldMutex* pYieldMutex = mpSalYieldMutex;
+ while ( nCount )
+ {
+ pYieldMutex->acquire();
+ nCount--;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+bool AquaSalInstance::isNSAppThread() const
+{
+ return vos::OThread::getCurrentIdentifier() == maMainThread;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInstance::handleAppDefinedEvent( NSEvent* pEvent )
+{
+ switch( [pEvent subtype] )
+ {
+ case AppStartTimerEvent:
+ AquaSalTimer::handleStartTimerEvent( pEvent );
+ break;
+ case AppEndLoopEvent:
+ [NSApp stop: NSApp];
+ break;
+ case AppExecuteSVMain:
+ {
+ BOOL bResult = ImplSVMain();
+ if( gpbInit )
+ *gpbInit = bResult;
+ [NSApp stop: NSApp];
+ bLeftMain = true;
+ if( pDockMenu )
+ {
+ [pDockMenu release];
+ pDockMenu = nil;
+ }
+ }
+ break;
+ case AppleRemoteEvent:
+ {
+ sal_Int16 nCommand = 0;
+ SalData* pSalData = GetSalData();
+ bool bIsFullScreenMode = false;
+
+ std::list<AquaSalFrame*>::iterator it = pSalData->maFrames.begin();
+ while( (*it) && ( (it != pSalData->maFrames.end() ) || ( (*it)->mbFullScreen == false ) ) )
+ {
+ if ( ((*it)->mbFullScreen == true) )
+ bIsFullScreenMode = true;
+ it++;
+ }
+
+ switch ([pEvent data1])
+ {
+ case kRemoteButtonPlay:
+ nCommand = ( bIsFullScreenMode == true ) ? MEDIA_COMMAND_PLAY_PAUSE : MEDIA_COMMAND_PLAY;
+ break;
+
+ // kept for experimentation purpose (scheduled for future implementation)
+ // case kRemoteButtonMenu: nCommand = MEDIA_COMMAND_MENU; break;
+
+ case kRemoteButtonPlus: nCommand = MEDIA_COMMAND_VOLUME_UP; break;
+
+ case kRemoteButtonMinus: nCommand = MEDIA_COMMAND_VOLUME_DOWN; break;
+
+ case kRemoteButtonRight: nCommand = MEDIA_COMMAND_NEXTTRACK; break;
+
+ case kRemoteButtonRight_Hold: nCommand = MEDIA_COMMAND_NEXTTRACK_HOLD; break;
+
+ case kRemoteButtonLeft: nCommand = MEDIA_COMMAND_PREVIOUSTRACK; break;
+
+ case kRemoteButtonLeft_Hold: nCommand = MEDIA_COMMAND_REWIND; break;
+
+ case kRemoteButtonPlay_Hold: nCommand = MEDIA_COMMAND_PLAY_HOLD; break;
+
+ case kRemoteButtonMenu_Hold: nCommand = MEDIA_COMMAND_STOP; break;
+
+ // FIXME : not detected
+ case kRemoteButtonPlus_Hold:
+ case kRemoteButtonMinus_Hold:
+ break;
+
+ default:
+ break;
+ }
+ AquaSalFrame* pFrame = pSalData->maFrames.front();
+ Window * pWindow = pFrame->GetWindow() ? pSalData->maFrames.front()->GetWindow() : NULL;
+
+ if( pWindow )
+ {
+ const Point aPoint;
+ CommandEvent aCEvt( aPoint, COMMAND_MEDIA, FALSE, &nCommand );
+ NotifyEvent aNCmdEvt( EVENT_COMMAND, pWindow, &aCEvt );
+
+ if ( !ImplCallPreNotify( aNCmdEvt ) )
+ pWindow->Command( aCEvt );
+ }
+
+ }
+ break;
+
+ case YieldWakeupEvent:
+ // do nothing, fall out of Yield
+ break;
+
+ default:
+ DBG_ERROR( "unhandled NSApplicationDefined event" );
+ break;
+ };
+}
+
+// -----------------------------------------------------------------------
+
+class ReleasePoolHolder
+{
+ NSAutoreleasePool* mpPool;
+ public:
+ ReleasePoolHolder() : mpPool( [[NSAutoreleasePool alloc] init] ) {}
+ ~ReleasePoolHolder() { [mpPool release]; }
+};
+
+void AquaSalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents )
+{
+ // ensure that the per thread autorelease pool is top level and
+ // will therefore not be destroyed by cocoa implicitly
+ SalData::ensureThreadAutoreleasePool();
+
+ // NSAutoreleasePool documentation suggests we should have
+ // an own pool for each yield level
+ ReleasePoolHolder aReleasePool;
+
+ // Release all locks so that we don't deadlock when we pull pending
+ // events from the event queue
+ bool bDispatchUser = true;
+ while( bDispatchUser )
+ {
+ ULONG nCount = ReleaseYieldMutex();
+
+ // get one user event
+ osl_acquireMutex( maUserEventListMutex );
+ SalUserEvent aEvent( NULL, NULL, 0 );
+ if( ! maUserEvents.empty() )
+ {
+ aEvent = maUserEvents.front();
+ maUserEvents.pop_front();
+ }
+ else
+ bDispatchUser = false;
+ osl_releaseMutex( maUserEventListMutex );
+
+ AcquireYieldMutex( nCount );
+
+ // dispatch it
+ if( aEvent.mpFrame && AquaSalFrame::isAlive( aEvent.mpFrame ) )
+ {
+ aEvent.mpFrame->CallCallback( aEvent.mnType, aEvent.mpData );
+ osl_setCondition( maWaitingYieldCond );
+ // return if only one event is asked for
+ if( ! bHandleAllCurrentEvents )
+ return;
+ }
+ }
+
+ // handle cocoa event queue
+ // cocoa events mye be only handled in the thread the NSApp was created
+ if( isNSAppThread() && mnActivePrintJobs == 0 )
+ {
+ // we need to be woken up by a cocoa-event
+ // if a user event should be posted by the event handling below
+ bool bOldWaitingYield = mbWaitingYield;
+ mbWaitingYield = bWait;
+
+ // handle available events
+ NSEvent* pEvent = nil;
+ bool bHadEvent = false;
+ do
+ {
+ ULONG nCount = ReleaseYieldMutex();
+
+ pEvent = [NSApp nextEventMatchingMask: NSAnyEventMask untilDate: nil
+ inMode: NSDefaultRunLoopMode dequeue: YES];
+ if( pEvent )
+ {
+ [NSApp sendEvent: pEvent];
+ bHadEvent = true;
+ }
+ [NSApp updateWindows];
+
+ AcquireYieldMutex( nCount );
+ } while( bHandleAllCurrentEvents && pEvent );
+
+ // if we had no event yet, wait for one if requested
+ if( bWait && ! bHadEvent )
+ {
+ ULONG nCount = ReleaseYieldMutex();
+
+ NSDate* pDt = AquaSalTimer::pRunningTimer ? [AquaSalTimer::pRunningTimer fireDate] : [NSDate distantFuture];
+ pEvent = [NSApp nextEventMatchingMask: NSAnyEventMask untilDate: pDt
+ inMode: NSDefaultRunLoopMode dequeue: YES];
+ if( pEvent )
+ [NSApp sendEvent: pEvent];
+ [NSApp updateWindows];
+
+ AcquireYieldMutex( nCount );
+
+ // #i86581#
+ // FIXME: sometimes the NSTimer will never fire. Firing it by hand then
+ // fixes the problem even seems to set the correct next firing date
+ // Why oh why ?
+ if( ! pEvent && AquaSalTimer::pRunningTimer )
+ {
+ // this cause crashes on MacOSX 10.4
+ // [AquaSalTimer::pRunningTimer fire];
+ ImplGetSVData()->mpSalTimer->CallCallback();
+ }
+ }
+
+ mbWaitingYield = bOldWaitingYield;
+
+ // collect update rectangles
+ const std::list< AquaSalFrame* > rFrames( GetSalData()->maFrames );
+ for( std::list< AquaSalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it )
+ {
+ if( (*it)->mbShown && ! (*it)->maInvalidRect.IsEmpty() )
+ {
+ (*it)->Flush( (*it)->maInvalidRect );
+ (*it)->maInvalidRect.SetEmpty();
+ }
+ }
+ osl_setCondition( maWaitingYieldCond );
+ }
+ else if( bWait )
+ {
+ // #i103162#
+ // wait until any thread (most likely the main thread)
+ // has dispatched an event, cop out at 200 ms
+ osl_resetCondition( maWaitingYieldCond );
+ TimeValue aVal = { 0, 200000000 };
+ ULONG nCount = ReleaseYieldMutex();
+ osl_waitCondition( maWaitingYieldCond, &aVal );
+ AcquireYieldMutex( nCount );
+ }
+
+ // we get some apple events way too early
+ // before the application is ready to handle them,
+ // so their corresponding application events need to be delayed
+ // now is a good time to handle at least one of them
+ if( bWait && !aAppEventList.empty() && ImplGetSVData()->maAppData.mbInAppExecute )
+ {
+ // make sure that only one application event is active at a time
+ static bool bInAppEvent = false;
+ if( !bInAppEvent )
+ {
+ bInAppEvent = true;
+ // get the next delayed application event
+ const ApplicationEvent* pAppEvent = aAppEventList.front();
+ aAppEventList.pop_front();
+ // handle one application event (no recursion)
+ const ImplSVData* pSVData = ImplGetSVData();
+ pSVData->mpApp->AppEvent( *pAppEvent );
+ delete pAppEvent;
+ // allow the next delayed application event
+ bInAppEvent = false;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+bool AquaSalInstance::AnyInput( USHORT nType )
+{
+ if( nType & INPUT_APPEVENT )
+ {
+ if( ! aAppEventList.empty() )
+ return true;
+ if( nType == INPUT_APPEVENT )
+ return false;
+ }
+
+ if( nType & INPUT_TIMER )
+ {
+ if( AquaSalTimer::pRunningTimer )
+ {
+ NSDate* pDt = [AquaSalTimer::pRunningTimer fireDate];
+ if( pDt && [pDt timeIntervalSinceNow] < 0 )
+ {
+ return true;
+ }
+ }
+ }
+
+ unsigned/*NSUInteger*/ nEventMask = 0;
+ if( nType & INPUT_MOUSE)
+ nEventMask |=
+ NSLeftMouseDownMask | NSRightMouseDownMask | NSOtherMouseDownMask |
+ NSLeftMouseUpMask | NSRightMouseUpMask | NSOtherMouseUpMask |
+ NSLeftMouseDraggedMask | NSRightMouseDraggedMask | NSOtherMouseDraggedMask |
+ NSScrollWheelMask |
+ // NSMouseMovedMask |
+ NSMouseEnteredMask | NSMouseExitedMask;
+ if( nType & INPUT_KEYBOARD)
+ nEventMask |= NSKeyDownMask | NSKeyUpMask | NSFlagsChangedMask;
+ if( nType & INPUT_OTHER)
+ nEventMask |= NSTabletPoint;
+ // TODO: INPUT_PAINT / more INPUT_OTHER
+ if( !nType)
+ return false;
+
+ NSEvent* pEvent = [NSApp nextEventMatchingMask: nEventMask untilDate: nil
+ inMode: NSDefaultRunLoopMode dequeue: NO];
+ return (pEvent != NULL);
+}
+
+// -----------------------------------------------------------------------
+
+SalFrame* AquaSalInstance::CreateChildFrame( SystemParentData* pSystemParentData, ULONG nSalFrameStyle )
+{
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+SalFrame* AquaSalInstance::CreateFrame( SalFrame* pParent, ULONG nSalFrameStyle )
+{
+ SalData::ensureThreadAutoreleasePool();
+
+ SalFrame* pFrame = new AquaSalFrame( pParent, nSalFrameStyle );
+ return pFrame;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInstance::DestroyFrame( SalFrame* pFrame )
+{
+ delete pFrame;
+}
+
+// -----------------------------------------------------------------------
+
+SalObject* AquaSalInstance::CreateObject( SalFrame* pParent, SystemWindowData* /* pWindowData */, BOOL /* bShow */ )
+{
+ // SystemWindowData is meaningless on Mac OS X
+ AquaSalObject *pObject = NULL;
+
+ if ( pParent )
+ pObject = new AquaSalObject( static_cast<AquaSalFrame*>(pParent) );
+
+ return pObject;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInstance::DestroyObject( SalObject* pObject )
+{
+ delete ( pObject );
+}
+
+// -----------------------------------------------------------------------
+
+SalPrinter* AquaSalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter )
+{
+ return new AquaSalPrinter( dynamic_cast<AquaSalInfoPrinter*>(pInfoPrinter) );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInstance::DestroyPrinter( SalPrinter* pPrinter )
+{
+ delete pPrinter;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList )
+{
+ NSArray* pNames = [NSPrinter printerNames];
+ NSArray* pTypes = [NSPrinter printerTypes];
+ unsigned int nNameCount = pNames ? [pNames count] : 0;
+ unsigned int nTypeCount = pTypes ? [pTypes count] : 0;
+ DBG_ASSERT( nTypeCount == nNameCount, "type count not equal to printer count" );
+ for( unsigned int i = 0; i < nNameCount; i++ )
+ {
+ NSString* pName = [pNames objectAtIndex: i];
+ NSString* pType = i < nTypeCount ? [pTypes objectAtIndex: i] : nil;
+ if( pName )
+ {
+ SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo;
+ pInfo->maPrinterName = GetOUString( pName );
+ if( pType )
+ pInfo->maDriver = GetOUString( pType );
+ pInfo->mnStatus = 0;
+ pInfo->mnJobs = 0;
+ pInfo->mpSysData = NULL;
+
+ pList->Add( pInfo );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInstance::GetPrinterQueueState( SalPrinterQueueInfo* pInfo )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo )
+{
+ delete pInfo;
+}
+
+// -----------------------------------------------------------------------
+
+XubString AquaSalInstance::GetDefaultPrinter()
+{
+ if( ! maDefaultPrinter.getLength() )
+ {
+ NSPrintInfo* pPI = [NSPrintInfo sharedPrintInfo];
+ DBG_ASSERT( pPI, "no print info" );
+ if( pPI )
+ {
+ NSPrinter* pPr = [pPI printer];
+ DBG_ASSERT( pPr, "no printer in default info" );
+ if( pPr )
+ {
+ NSString* pDefName = [pPr name];
+ DBG_ASSERT( pDefName, "printer has no name" );
+ maDefaultPrinter = GetOUString( pDefName );
+ }
+ }
+ }
+ return maDefaultPrinter;
+}
+
+// -----------------------------------------------------------------------
+
+SalInfoPrinter* AquaSalInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
+ ImplJobSetup* pSetupData )
+{
+ SalInfoPrinter* pNewInfoPrinter = NULL;
+ if( pQueueInfo )
+ {
+ pNewInfoPrinter = new AquaSalInfoPrinter( *pQueueInfo );
+ if( pSetupData )
+ pNewInfoPrinter->SetPrinterData( pSetupData );
+ }
+
+ return pNewInfoPrinter;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter )
+{
+ delete pPrinter;
+}
+
+// -----------------------------------------------------------------------
+
+SalSystem* AquaSalInstance::CreateSystem()
+{
+ return new AquaSalSystem();
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInstance::DestroySystem( SalSystem* pSystem )
+{
+ delete pSystem;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInstance::SetEventCallback( void* pInstance, bool(*pCallback)(void*,void*,int) )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInstance::SetErrorEventCallback( void* pInstance, bool(*pCallback)(void*,void*,int) )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void* AquaSalInstance::GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes )
+{
+ rReturnedBytes = 1;
+ rReturnedType = AsciiCString;
+ return (void*)"";
+}
+
+// We need to re-encode file urls because osl_getFileURLFromSystemPath converts
+// to UTF-8 before encoding non ascii characters, which is not what other apps expect.
+static rtl::OUString translateToExternalUrl(const rtl::OUString& internalUrl)
+{
+ rtl::OUString extUrl;
+
+ uno::Reference< lang::XMultiServiceFactory > sm = comphelper::getProcessServiceFactory();
+ if (sm.is())
+ {
+ uno::Reference< beans::XPropertySet > pset;
+ sm->queryInterface( getCppuType( &pset )) >>= pset;
+ if (pset.is())
+ {
+ uno::Reference< uno::XComponentContext > context;
+ static const rtl::OUString DEFAULT_CONTEXT( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ) );
+ pset->getPropertyValue(DEFAULT_CONTEXT) >>= context;
+ if (context.is())
+ extUrl = uri::ExternalUriReferenceTranslator::create(context)->translateToExternal(internalUrl);
+ }
+ }
+ return extUrl;
+}
+
+// #i104525# many versions of OSX have problems with some URLs:
+// when an app requests OSX to add one of these URLs to the "Recent Items" list
+// then this app gets killed (TextEdit, Preview, etc. and also OOo)
+static bool isDangerousUrl( const rtl::OUString& rUrl )
+{
+ // use a heuristic that detects all known cases since there is no official comment
+ // on the exact impact and root cause of the OSX bug
+ const int nLen = rUrl.getLength();
+ const sal_Unicode* p = rUrl.getStr();
+ for( int i = 0; i < nLen-3; ++i, ++p ) {
+ if( p[0] != '%' )
+ continue;
+ // escaped percent?
+ if( (p[1] == '2') && (p[2] == '5') )
+ return true;
+ // escapes are considered to be UTF-8 encoded
+ // => check for invalid UTF-8 leading byte
+ if( (p[1] != 'f') && (p[1] != 'F') )
+ continue;
+ int cLowNibble = p[2];
+ if( (cLowNibble >= '0' ) && (cLowNibble <= '9'))
+ return false;
+ if( cLowNibble >= 'a' )
+ cLowNibble -= 'a' - 'A';
+ if( (cLowNibble < 'A') || (cLowNibble >= 'C'))
+ return true;
+ }
+
+ return false;
+}
+
+void AquaSalInstance::AddToRecentDocumentList(const rtl::OUString& rFileUrl, const rtl::OUString& /*rMimeType*/)
+{
+ // Convert file URL for external use (see above)
+ rtl::OUString externalUrl = translateToExternalUrl(rFileUrl);
+ if( 0 == externalUrl.getLength() )
+ externalUrl = rFileUrl;
+
+ if( externalUrl.getLength() && !isDangerousUrl( externalUrl ) )
+ {
+ NSString* pString = CreateNSString( externalUrl );
+ NSURL* pURL = [NSURL URLWithString: pString];
+
+ if( pURL )
+ {
+ NSDocumentController* pCtrl = [NSDocumentController sharedDocumentController];
+ [pCtrl noteNewRecentDocumentURL: pURL];
+ }
+ if( pString )
+ [pString release];
+ }
+}
+
+
+// -----------------------------------------------------------------------
+
+SalTimer* AquaSalInstance::CreateSalTimer()
+{
+ return new AquaSalTimer();
+}
+
+// -----------------------------------------------------------------------
+
+SalSystem* AquaSalInstance::CreateSalSystem()
+{
+ return new AquaSalSystem();
+}
+
+// -----------------------------------------------------------------------
+
+SalBitmap* AquaSalInstance::CreateSalBitmap()
+{
+ return new AquaSalBitmap();
+}
+
+// -----------------------------------------------------------------------
+
+SalSession* AquaSalInstance::CreateSalSession()
+{
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+class MacImeStatus : public SalI18NImeStatus
+{
+public:
+ MacImeStatus() {}
+ virtual ~MacImeStatus() {}
+
+ // asks whether there is a status window available
+ // to toggle into menubar
+ virtual bool canToggle() { return false; }
+ virtual void toggle() {}
+};
+
+// -----------------------------------------------------------------------
+
+SalI18NImeStatus* AquaSalInstance::CreateI18NImeStatus()
+{
+ return new MacImeStatus();
+}
+
+// YieldMutexReleaser
+YieldMutexReleaser::YieldMutexReleaser() : mnCount( 0 )
+{
+ SalData* pSalData = GetSalData();
+ if( ! pSalData->mpFirstInstance->isNSAppThread() )
+ {
+ SalData::ensureThreadAutoreleasePool();
+ mnCount = pSalData->mpFirstInstance->ReleaseYieldMutex();
+ }
+}
+
+YieldMutexReleaser::~YieldMutexReleaser()
+{
+ if( mnCount != 0 )
+ GetSalData()->mpFirstInstance->AcquireYieldMutex( mnCount );
+}
+
+//////////////////////////////////////////////////////////////
+rtl::OUString GetOUString( CFStringRef rStr )
+{
+ if( rStr == 0 )
+ return rtl::OUString();
+ CFIndex nLength = CFStringGetLength( rStr );
+ if( nLength == 0 )
+ return rtl::OUString();
+ const UniChar* pConstStr = CFStringGetCharactersPtr( rStr );
+ if( pConstStr )
+ return rtl::OUString( pConstStr, nLength );
+ UniChar* pStr = reinterpret_cast<UniChar*>( rtl_allocateMemory( sizeof(UniChar)*nLength ) );
+ CFRange aRange = { 0, nLength };
+ CFStringGetCharacters( rStr, aRange, pStr );
+ rtl::OUString aRet( pStr, nLength );
+ rtl_freeMemory( pStr );
+ return aRet;
+}
+
+rtl::OUString GetOUString( NSString* pStr )
+{
+ if( ! pStr )
+ return rtl::OUString();
+ int nLen = [pStr length];
+ if( nLen == 0 )
+ return rtl::OUString();
+
+ rtl::OUStringBuffer aBuf( nLen+1 );
+ aBuf.setLength( nLen );
+ [pStr getCharacters: const_cast<sal_Unicode*>(aBuf.getStr())];
+ return aBuf.makeStringAndClear();
+}
+
+CFStringRef CreateCFString( const rtl::OUString& rStr )
+{
+ return CFStringCreateWithCharacters(kCFAllocatorDefault, rStr.getStr(), rStr.getLength() );
+}
+
+NSString* CreateNSString( const rtl::OUString& rStr )
+{
+ return [[NSString alloc] initWithCharacters: rStr.getStr() length: rStr.getLength()];
+}
+
+CGImageRef CreateCGImage( const Image& rImage )
+{
+ BitmapEx aBmpEx( rImage.GetBitmapEx() );
+ Bitmap aBmp( aBmpEx.GetBitmap() );
+
+ if( ! aBmp || ! aBmp.ImplGetImpBitmap() )
+ return NULL;
+
+ // simple case, no transparency
+ AquaSalBitmap* pSalBmp = static_cast<AquaSalBitmap*>(aBmp.ImplGetImpBitmap()->ImplGetSalBitmap());
+
+ if( ! pSalBmp )
+ return NULL;
+
+ CGImageRef xImage = NULL;
+ if( ! (aBmpEx.IsAlpha() || aBmpEx.IsTransparent() ) )
+ xImage = pSalBmp->CreateCroppedImage( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight );
+ else if( aBmpEx.IsAlpha() )
+ {
+ AlphaMask aAlphaMask( aBmpEx.GetAlpha() );
+ Bitmap aMask( aAlphaMask.GetBitmap() );
+ AquaSalBitmap* pMaskBmp = static_cast<AquaSalBitmap*>(aMask.ImplGetImpBitmap()->ImplGetSalBitmap());
+ if( pMaskBmp )
+ xImage = pSalBmp->CreateWithMask( *pMaskBmp, 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight );
+ else
+ xImage = pSalBmp->CreateCroppedImage( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight );
+ }
+ else if( aBmpEx.GetTransparentType() == TRANSPARENT_BITMAP )
+ {
+ Bitmap aMask( aBmpEx.GetMask() );
+ AquaSalBitmap* pMaskBmp = static_cast<AquaSalBitmap*>(aMask.ImplGetImpBitmap()->ImplGetSalBitmap());
+ if( pMaskBmp )
+ xImage = pSalBmp->CreateWithMask( *pMaskBmp, 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight );
+ else
+ xImage = pSalBmp->CreateCroppedImage( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight );
+ }
+ else if( aBmpEx.GetTransparentType() == TRANSPARENT_COLOR )
+ {
+ Color aTransColor( aBmpEx.GetTransparentColor() );
+ SalColor nTransColor = MAKE_SALCOLOR( aTransColor.GetRed(), aTransColor.GetGreen(), aTransColor.GetBlue() );
+ xImage = pSalBmp->CreateColorMask( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight, nTransColor );
+ }
+
+ return xImage;
+}
+
+NSImage* CreateNSImage( const Image& rImage )
+{
+ CGImageRef xImage = CreateCGImage( rImage );
+
+ if( ! xImage )
+ return nil;
+
+ Size aSize( rImage.GetSizePixel() );
+ NSImage* pImage = [[NSImage alloc] initWithSize: NSMakeSize( aSize.Width(), aSize.Height() )];
+ if( pImage )
+ {
+ [pImage setFlipped: YES];
+ [pImage lockFocus];
+
+ NSGraphicsContext* pContext = [NSGraphicsContext currentContext];
+ CGContextRef rCGContext = reinterpret_cast<CGContextRef>([pContext graphicsPort]);
+
+ const CGRect aDstRect = { {0, 0}, { aSize.Width(), aSize.Height() } };
+ CGContextDrawImage( rCGContext, aDstRect, xImage );
+
+ [pImage unlockFocus];
+ }
+
+ CGImageRelease( xImage );
+
+ return pImage;
+}
diff --git a/vcl/aqua/source/app/salnstimer.mm b/vcl/aqua/source/app/salnstimer.mm
new file mode 100755
index 000000000000..73e49fd99c61
--- /dev/null
+++ b/vcl/aqua/source/app/salnstimer.mm
@@ -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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "saltimer.h"
+#include "salnstimer.h"
+#include "salinst.h"
+#include "saldata.hxx"
+
+#include "vcl/svdata.hxx"
+
+@implementation TimerCallbackCaller
+-(void)timerElapsed:(NSTimer*)pTimer
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if( AquaSalTimer::bDispatchTimer )
+ {
+ if( pSVData->mpSalTimer )
+ {
+ YIELD_GUARD;
+ pSVData->mpSalTimer->CallCallback();
+
+ // NSTimer does not end nextEventMatchingMask of NSApplication
+ // so we need to wakeup a waiting Yield to inform it something happened
+ GetSalData()->mpFirstInstance->wakeupYield();
+ }
+ }
+}
+@end
+
diff --git a/vcl/aqua/source/app/salsys.cxx b/vcl/aqua/source/app/salsys.cxx
new file mode 100644
index 000000000000..3b548099feef
--- /dev/null
+++ b/vcl/aqua/source/app/salsys.cxx
@@ -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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "tools/rc.hxx"
+#include "vcl/svids.hrc"
+
+#include "salsys.h"
+#include "saldata.hxx"
+#include "rtl/ustrbuf.hxx"
+
+using namespace rtl;
+
+// =======================================================================
+
+AquaSalSystem::~AquaSalSystem()
+{
+}
+
+unsigned int AquaSalSystem::GetDisplayScreenCount()
+{
+ NSArray* pScreens = [NSScreen screens];
+ return pScreens ? [pScreens count] : 1;
+}
+
+bool AquaSalSystem::IsMultiDisplay()
+{
+ return false;
+}
+
+unsigned int AquaSalSystem::GetDefaultDisplayNumber()
+{
+ return 0;
+}
+
+Rectangle AquaSalSystem::GetDisplayScreenPosSizePixel( unsigned int nScreen )
+{
+ NSArray* pScreens = [NSScreen screens];
+ Rectangle aRet;
+ NSScreen* pScreen = nil;
+ if( pScreens && nScreen < [pScreens count] )
+ pScreen = [pScreens objectAtIndex: nScreen];
+ else
+ pScreen = [NSScreen mainScreen];
+
+ if( pScreen )
+ {
+ NSRect aFrame = [pScreen frame];
+ aRet = Rectangle( Point( static_cast<long int>(aFrame.origin.x), static_cast<long int>(aFrame.origin.y) ),
+ Size( static_cast<long int>(aFrame.size.width), static_cast<long int>(aFrame.size.height) ) );
+ }
+ return aRet;
+}
+
+Rectangle AquaSalSystem::GetDisplayWorkAreaPosSizePixel( unsigned int nScreen )
+{
+ NSArray* pScreens = [NSScreen screens];
+ Rectangle aRet;
+ NSScreen* pScreen = nil;
+ if( pScreens && nScreen < [pScreens count] )
+ pScreen = [pScreens objectAtIndex: nScreen];
+ else
+ pScreen = [NSScreen mainScreen];
+
+ if( pScreen )
+ {
+ NSRect aFrame = [pScreen visibleFrame];
+ aRet = Rectangle( Point( static_cast<long int>(aFrame.origin.x), static_cast<long int>(aFrame.origin.y) ),
+ Size( static_cast<long int>(aFrame.size.width), static_cast<long int>(aFrame.size.height) ) );
+ }
+ return aRet;
+}
+
+rtl::OUString AquaSalSystem::GetScreenName( unsigned int nScreen )
+{
+ NSArray* pScreens = [NSScreen screens];
+ OUString aRet;
+ if( nScreen < [pScreens count] )
+ {
+ ResMgr* pMgr = ImplGetResMgr();
+ if( pMgr )
+ {
+ String aScreenName( ResId( SV_MAC_SCREENNNAME, *pMgr ) );
+ aScreenName.SearchAndReplaceAllAscii( "%d", String::CreateFromInt32( nScreen ) );
+ aRet = aScreenName;
+ }
+ }
+ return aRet;
+}
+
+int AquaSalSystem::ShowNativeDialog( const String& rTitle,
+ const String& rMessage,
+ const std::list< String >& rButtons,
+ int nDefButton )
+{
+ return 0;
+}
+
+int AquaSalSystem::ShowNativeMessageBox( const String& rTitle,
+ const String& rMessage,
+ int nButtonCombination,
+ int nDefaultButton)
+{
+ return 0;
+}
diff --git a/vcl/aqua/source/app/saltimer.cxx b/vcl/aqua/source/app/saltimer.cxx
new file mode 100644
index 000000000000..724857e92a0c
--- /dev/null
+++ b/vcl/aqua/source/app/saltimer.cxx
@@ -0,0 +1,135 @@
+/*************************************************************************
+ *
+ * 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 "saltimer.h"
+#include "salnstimer.h"
+#include "saldata.hxx"
+#include "salframe.h"
+#include "salinst.h"
+
+// =======================================================================
+
+NSTimer* AquaSalTimer::pRunningTimer = nil;
+bool AquaSalTimer::bDispatchTimer = false;
+
+
+void ImplSalStartTimer( ULONG nMS )
+{
+ SalData* pSalData = GetSalData();
+ if( pSalData->mpFirstInstance->isNSAppThread() )
+ {
+ AquaSalTimer::bDispatchTimer = true;
+ NSTimeInterval aTI = double(nMS)/1000.0;
+ if( AquaSalTimer::pRunningTimer != nil )
+ {
+ if( [AquaSalTimer::pRunningTimer timeInterval] == aTI )
+ // set new fire date
+ [AquaSalTimer::pRunningTimer setFireDate: [NSDate dateWithTimeIntervalSinceNow: aTI]];
+ else
+ {
+ [AquaSalTimer::pRunningTimer invalidate];
+ AquaSalTimer::pRunningTimer = nil;
+ }
+ }
+ if( AquaSalTimer::pRunningTimer == nil )
+ {
+ AquaSalTimer::pRunningTimer = [NSTimer scheduledTimerWithTimeInterval: aTI
+ target: [[[TimerCallbackCaller alloc] init] autorelease]
+ selector: @selector(timerElapsed:)
+ userInfo: nil
+ repeats: YES];
+ /* #i84055# add timer to tracking run loop mode,
+ so they also elapse while e.g. life resize
+ */
+ [[NSRunLoop currentRunLoop] addTimer: AquaSalTimer::pRunningTimer forMode: NSEventTrackingRunLoopMode];
+ }
+ }
+ else
+ {
+ SalData::ensureThreadAutoreleasePool();
+ // post an event so we can get into the main thread
+ NSPoint aPt = { 0, 0 };
+ NSEvent* pEvent = [NSEvent otherEventWithType: NSApplicationDefined
+ location: aPt
+ modifierFlags: 0
+ timestamp: [NSDate timeIntervalSinceReferenceDate]
+ windowNumber: 0
+ context: nil
+ subtype: AquaSalInstance::AppStartTimerEvent
+ data1: (int)nMS
+ data2: 0 ];
+ if( pEvent )
+ [NSApp postEvent: pEvent atStart: YES];
+ }
+}
+
+void ImplSalStopTimer()
+{
+ AquaSalTimer::bDispatchTimer = false;
+}
+
+void AquaSalTimer::handleStartTimerEvent( NSEvent* pEvent )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if( pSVData->mpSalTimer )
+ {
+ NSTimeInterval posted = [pEvent timestamp] + NSTimeInterval([pEvent data1])/1000.0;
+ NSTimeInterval current = [NSDate timeIntervalSinceReferenceDate];
+ if( (posted - current) <= 0.0 )
+ {
+ YIELD_GUARD;
+ // timer already elapsed since event posted
+ pSVData->mpSalTimer->CallCallback();
+ }
+ ImplSalStartTimer( ULONG( [pEvent data1] ) );
+ }
+
+}
+
+AquaSalTimer::AquaSalTimer( )
+{
+}
+
+AquaSalTimer::~AquaSalTimer()
+{
+ ImplSalStopTimer();
+}
+
+void AquaSalTimer::Start( ULONG nMS )
+{
+ ImplSalStartTimer( nMS );
+}
+
+void AquaSalTimer::Stop()
+{
+ ImplSalStopTimer();
+}
+
+
diff --git a/vcl/aqua/source/app/vclnsapp.mm b/vcl/aqua/source/app/vclnsapp.mm
new file mode 100755
index 000000000000..f33599fa086e
--- /dev/null
+++ b/vcl/aqua/source/app/vclnsapp.mm
@@ -0,0 +1,518 @@
+/*************************************************************************
+ *
+ * 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 "vclnsapp.h"
+#include "salinst.h"
+#include "saldata.hxx"
+#include "salframe.h"
+#include "salframeview.h"
+
+#include "vcl/window.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/cmdevt.hxx"
+#include "rtl/ustrbuf.hxx"
+
+#include "premac.h"
+#import "Carbon/Carbon.h"
+#import "apple_remote/RemoteControl.h"
+#include "postmac.h"
+
+
+@implementation CocoaThreadEnabler
+-(void)enableCocoaThreads:(id)param
+{
+ // do nothing, this is just to start an NSThread and therefore put
+ // Cocoa into multithread mode
+}
+@end
+
+@implementation VCL_NSApplication
+-(void)sendEvent:(NSEvent*)pEvent
+{
+ NSEventType eType = [pEvent type];
+ if( eType == NSApplicationDefined )
+ GetSalData()->mpFirstInstance->handleAppDefinedEvent( pEvent );
+ else if( eType == NSKeyDown && ([pEvent modifierFlags] & NSCommandKeyMask) != 0 )
+ {
+ NSWindow* pKeyWin = [NSApp keyWindow];
+ if( pKeyWin && [pKeyWin isKindOfClass: [SalFrameWindow class]] )
+ {
+ AquaSalFrame* pFrame = [(SalFrameWindow*)pKeyWin getSalFrame];
+ // handle Cmd-W
+ // FIXME: the correct solution would be to handle this in framework
+ // in the menu code
+ // however that is currently being revised, so let's use a preliminary solution here
+ // this hack is based on assumption
+ // a) Cmd-W is the same in all languages in OOo's menu conig
+ // b) Cmd-W is the same in all languages in on MacOS
+ // for now this seems to be true
+ unsigned int nModMask = ([pEvent modifierFlags] & (NSShiftKeyMask|NSControlKeyMask|NSAlternateKeyMask|NSCommandKeyMask));
+ if( (pFrame->mnStyleMask & NSClosableWindowMask) != 0 )
+ {
+ if( nModMask == NSCommandKeyMask
+ && [[pEvent charactersIgnoringModifiers] isEqualToString: @"w"] )
+ {
+ [pFrame->getWindow() windowShouldClose: nil];
+ return;
+ }
+ }
+
+ /*
+ * #i98949# - Cmd-M miniaturize window, Cmd-Option-M miniaturize all windows
+ */
+ if( [[pEvent charactersIgnoringModifiers] isEqualToString: @"m"] )
+ {
+ if ( nModMask == NSCommandKeyMask && ([pFrame->getWindow() styleMask] & NSMiniaturizableWindowMask) )
+ {
+ [pFrame->getWindow() performMiniaturize: nil];
+ return;
+ }
+
+ if ( nModMask == ( NSCommandKeyMask | NSAlternateKeyMask ) )
+ {
+ [NSApp miniaturizeAll: nil];
+ return;
+ }
+ }
+
+ // #i90083# handle frame switching
+ // FIXME: lousy workaround
+ if( (nModMask & (NSControlKeyMask|NSAlternateKeyMask)) == 0 )
+ {
+ if( [[pEvent characters] isEqualToString: @"<"] ||
+ [[pEvent characters] isEqualToString: @"~"] )
+ {
+ [self cycleFrameForward: pFrame];
+ return;
+ }
+ else if( [[pEvent characters] isEqualToString: @">"] ||
+ [[pEvent characters] isEqualToString: @"`"] )
+ {
+ [self cycleFrameBackward: pFrame];
+ return;
+ }
+ }
+
+ // get information whether the event was handled; keyDown returns nothing
+ GetSalData()->maKeyEventAnswer[ pEvent ] = false;
+ bool bHandled = false;
+
+ // dispatch to view directly to avoid the key event being consumed by the menubar
+ // popup windows do not get the focus, so they don't get these either
+ // simplest would be dispatch this to the key window always if it is without parent
+ // however e.g. in document we want the menu shortcut if e.g. the stylist has focus
+ if( pFrame->mpParent && (pFrame->mnStyle & SAL_FRAME_STYLE_FLOAT) == 0 )
+ {
+ [[pKeyWin contentView] keyDown: pEvent];
+ bHandled = GetSalData()->maKeyEventAnswer[ pEvent ];
+ }
+
+ // see whether the main menu consumes this event
+ // if not, we want to dispatch it ourselves. Unless we do this "trick"
+ // the main menu just beeps for an unknown or disabled key equivalent
+ // and swallows the event wholesale
+ NSMenu* pMainMenu = [NSApp mainMenu];
+ if( ! bHandled && (pMainMenu == 0 || ! [pMainMenu performKeyEquivalent: pEvent]) )
+ {
+ [[pKeyWin contentView] keyDown: pEvent];
+ bHandled = GetSalData()->maKeyEventAnswer[ pEvent ];
+ }
+ else
+ bHandled = true; // event handled already or main menu just handled it
+
+ GetSalData()->maKeyEventAnswer.erase( pEvent );
+ if( bHandled )
+ return;
+ }
+ else if( pKeyWin )
+ {
+ // #i94601# a window not of vcl's making has the focus.
+ // Since our menus do not invoke the usual commands
+ // try to play nice with native windows like the file dialog
+ // and emulate them
+ // precondition: this ONLY works because CMD-V (paste), CMD-C (copy) and CMD-X (cut) are
+ // NOT localized, that is the same in all locales. Should this be
+ // different in any locale, this hack will fail.
+ unsigned int nModMask = ([pEvent modifierFlags] & (NSShiftKeyMask|NSControlKeyMask|NSAlternateKeyMask|NSCommandKeyMask));
+ if( nModMask == NSCommandKeyMask )
+ {
+
+ if( [[pEvent charactersIgnoringModifiers] isEqualToString: @"v"] )
+ {
+ if( [NSApp sendAction: @selector(paste:) to: nil from: nil] )
+ return;
+ }
+ else if( [[pEvent charactersIgnoringModifiers] isEqualToString: @"c"] )
+ {
+ if( [NSApp sendAction: @selector(copy:) to: nil from: nil] )
+ return;
+ }
+ else if( [[pEvent charactersIgnoringModifiers] isEqualToString: @"x"] )
+ {
+ if( [NSApp sendAction: @selector(cut:) to: nil from: nil] )
+ return;
+ }
+ }
+ }
+ }
+ else if( eType == NSScrollWheel && ( GetSalData()->mnSystemVersion < VER_LEOPARD /* fixed in Leopard and above */ ) )
+ {
+
+ NSWindow* pWin = [pEvent window];
+ // on Tiger wheel events do not reach non key windows
+ // which probably should be considered a bug
+ if( [pWin isKindOfClass: [SalFrameWindow class]] && [pWin canBecomeKeyWindow] == NO )
+ {
+ [[pWin contentView] scrollWheel: pEvent];
+ return;
+ }
+ }
+ [super sendEvent: pEvent];
+}
+
+-(void)sendSuperEvent:(NSEvent*)pEvent
+{
+ [super sendEvent: pEvent];
+}
+
+-(void)cycleFrameForward: (AquaSalFrame*)pCurFrame
+{
+ // find current frame in list
+ std::list< AquaSalFrame* >& rFrames( GetSalData()->maFrames );
+ std::list< AquaSalFrame* >::iterator it = rFrames.begin();
+ for( ; it != rFrames.end() && *it != pCurFrame; ++it )
+ ;
+ if( it != rFrames.end() )
+ {
+ // now find the next frame (or end)
+ do
+ {
+ ++it;
+ if( it != rFrames.end() )
+ {
+ if( (*it)->mpDockMenuEntry != NULL &&
+ (*it)->mbShown )
+ {
+ [(*it)->getWindow() makeKeyAndOrderFront: NSApp];
+ return;
+ }
+ }
+ } while( it != rFrames.end() );
+ // cycle around, find the next up to pCurFrame
+ it = rFrames.begin();
+ while( *it != pCurFrame )
+ {
+ if( (*it)->mpDockMenuEntry != NULL &&
+ (*it)->mbShown )
+ {
+ [(*it)->getWindow() makeKeyAndOrderFront: NSApp];
+ return;
+ }
+ ++it;
+ }
+ }
+}
+
+-(void)cycleFrameBackward: (AquaSalFrame*)pCurFrame
+{
+ // do the same as cycleFrameForward only with a reverse iterator
+
+ // find current frame in list
+ std::list< AquaSalFrame* >& rFrames( GetSalData()->maFrames );
+ std::list< AquaSalFrame* >::reverse_iterator it = rFrames.rbegin();
+ for( ; it != rFrames.rend() && *it != pCurFrame; ++it )
+ ;
+ if( it != rFrames.rend() )
+ {
+ // now find the next frame (or end)
+ do
+ {
+ ++it;
+ if( it != rFrames.rend() )
+ {
+ if( (*it)->mpDockMenuEntry != NULL &&
+ (*it)->mbShown )
+ {
+ [(*it)->getWindow() makeKeyAndOrderFront: NSApp];
+ return;
+ }
+ }
+ } while( it != rFrames.rend() );
+ // cycle around, find the next up to pCurFrame
+ it = rFrames.rbegin();
+ while( *it != pCurFrame )
+ {
+ if( (*it)->mpDockMenuEntry != NULL &&
+ (*it)->mbShown )
+ {
+ [(*it)->getWindow() makeKeyAndOrderFront: NSApp];
+ return;
+ }
+ ++it;
+ }
+ }
+}
+
+-(NSMenu*)applicationDockMenu:(NSApplication *)sender
+{
+ return AquaSalInstance::GetDynamicDockMenu();
+}
+
+-(MacOSBOOL)application: (NSApplication*)app openFile: (NSString*)pFile
+{
+ const rtl::OUString aFile( GetOUString( pFile ) );
+ if( ! AquaSalInstance::isOnCommandLine( aFile ) )
+ {
+ const ApplicationEvent* pAppEvent = new ApplicationEvent( String(), ApplicationAddress(),
+ APPEVENT_OPEN_STRING, aFile );
+ AquaSalInstance::aAppEventList.push_back( pAppEvent );
+ }
+ return YES;
+}
+
+-(void)application: (NSApplication*) app openFiles: (NSArray*)files
+{
+ rtl::OUStringBuffer aFileList( 256 );
+
+ NSEnumerator* it = [files objectEnumerator];
+ NSString* pFile = nil;
+
+ while( (pFile = [it nextObject]) != nil )
+ {
+ const rtl::OUString aFile( GetOUString( pFile ) );
+ if( ! AquaSalInstance::isOnCommandLine( aFile ) )
+ {
+ if( aFileList.getLength() > 0 )
+ aFileList.append( sal_Unicode( APPEVENT_PARAM_DELIMITER ) );
+ aFileList.append( aFile );
+ }
+ }
+
+ if( aFileList.getLength() )
+ {
+ // we have no back channel here, we have to assume success, in which case
+ // replyToOpenOrPrint does not need to be called according to documentation
+ // [app replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
+ const ApplicationEvent* pAppEvent = new ApplicationEvent( String(), ApplicationAddress(),
+ APPEVENT_OPEN_STRING, aFileList.makeStringAndClear() );
+ AquaSalInstance::aAppEventList.push_back( pAppEvent );
+ }
+}
+
+-(MacOSBOOL)application: (NSApplication*)app printFile: (NSString*)pFile
+{
+ const rtl::OUString aFile( GetOUString( pFile ) );
+ const ApplicationEvent* pAppEvent = new ApplicationEvent( String(), ApplicationAddress(),
+ APPEVENT_PRINT_STRING, aFile );
+ AquaSalInstance::aAppEventList.push_back( pAppEvent );
+ return YES;
+}
+-(NSApplicationPrintReply)application: (NSApplication *) app printFiles:(NSArray *)files withSettings: (NSDictionary *)printSettings showPrintPanels:(MacOSBOOL)bShowPrintPanels
+{
+ // currently ignores print settings an bShowPrintPanels
+ rtl::OUStringBuffer aFileList( 256 );
+
+ NSEnumerator* it = [files objectEnumerator];
+ NSString* pFile = nil;
+
+ while( (pFile = [it nextObject]) != nil )
+ {
+ if( aFileList.getLength() > 0 )
+ aFileList.append( sal_Unicode( APPEVENT_PARAM_DELIMITER ) );
+ aFileList.append( GetOUString( pFile ) );
+ }
+ const ApplicationEvent* pAppEvent = new ApplicationEvent( String(), ApplicationAddress(),
+ APPEVENT_PRINT_STRING, aFileList.makeStringAndClear() );
+ AquaSalInstance::aAppEventList.push_back( pAppEvent );
+ // we have no back channel here, we have to assume success
+ // correct handling would be NSPrintingReplyLater and then send [app replyToOpenOrPrint]
+ return NSPrintingSuccess;
+}
+
+-(NSApplicationTerminateReply)applicationShouldTerminate: (NSApplication *) app
+{
+ SalData* pSalData = GetSalData();
+ #if 1 // currently do some really bad hack
+ if( ! pSalData->maFrames.empty() )
+ {
+ /* #i92766# something really weird is going on with the retain count of
+ our windows; sometimes we get a duplicate free before exit on one of our
+ NSWindows. The reason is unclear; to avoid this currently we retain them once more
+
+ FIXME: this is a really bad hack, relying on the system to catch the leaked
+ resources. Find out what really goes on here and fix it !
+ */
+ std::vector< NSWindow* > aHackRetainedWindows;
+ for( std::list< AquaSalFrame* >::iterator it = pSalData->maFrames.begin();
+ it != pSalData->maFrames.end(); ++it )
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ Window* pWin = (*it)->GetWindow();
+ String aTitle = pWin->GetText();
+ Window* pClient = pWin->ImplGetClientWindow();
+ fprintf( stderr, "retaining %p (old count %d) windowtype=%s clienttyp=%s title=%s\n",
+ (*it)->mpWindow, [(*it)->mpWindow retainCount],
+ typeid(*pWin).name(), pClient ? typeid(*pClient).name() : "<nil>",
+ rtl::OUStringToOString( aTitle, RTL_TEXTENCODING_UTF8 ).getStr()
+ );
+ #endif
+ [(*it)->mpWindow retain];
+ aHackRetainedWindows.push_back( (*it)->mpWindow );
+ }
+ if( pSalData->maFrames.front()->CallCallback( SALEVENT_SHUTDOWN, NULL ) )
+ {
+ for( std::vector< NSWindow* >::iterator it = aHackRetainedWindows.begin();
+ it != aHackRetainedWindows.end(); ++it )
+ {
+ // clean up the retaing count again from the shutdown workaround
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "releasing %p\n", (*it) );
+ #endif
+ [(*it) release];
+ }
+ return NSTerminateCancel;
+ }
+ #if OSL_DEBUG_LEVEL > 1
+ for( std::list< AquaSalFrame* >::iterator it = pSalData->maFrames.begin();
+ it != pSalData->maFrames.end(); ++it )
+ {
+ Window* pWin = (*it)->GetWindow();
+ String aTitle = pWin->GetText();
+ Window* pClient = pWin->ImplGetClientWindow();
+ fprintf( stderr, "frame still alive: NSWindow %p windowtype=%s clienttyp=%s title=%s\n",
+ (*it)->mpWindow, typeid(*pWin).name(), pClient ? typeid(*pClient).name() : "<nil>",
+ rtl::OUStringToOString( aTitle, RTL_TEXTENCODING_UTF8 ).getStr()
+ );
+ }
+ #endif
+ }
+ #else // the clean version follows
+ return pSalData->maFrames.front()->CallCallback( SALEVENT_SHUTDOWN, NULL ) ? NSTerminateCancel : NSTerminateNow;
+ #endif
+ return NSTerminateNow;
+}
+
+-(void)systemColorsChanged: (NSNotification*) pNotification
+{
+ const SalData* pSalData = GetSalData();
+ if( !pSalData->maFrames.empty() )
+ pSalData->maFrames.front()->CallCallback( SALEVENT_SETTINGSCHANGED, NULL );
+}
+
+-(void)screenParametersChanged: (NSNotification*) pNotification
+{
+ SalData* pSalData = GetSalData();
+ std::list< AquaSalFrame* >::iterator it;
+ for( it = pSalData->maFrames.begin(); it != pSalData->maFrames.end(); ++it )
+ {
+ (*it)->screenParametersChanged();
+ }
+}
+
+-(void)scrollbarVariantChanged: (NSNotification*) pNotification
+{
+ GetSalData()->mpFirstInstance->delayedSettingsChanged( true );
+}
+
+-(void)scrollbarSettingsChanged: (NSNotification*) pNotification
+{
+ GetSalData()->mpFirstInstance->delayedSettingsChanged( false );
+}
+
+-(void)addFallbackMenuItem: (NSMenuItem*)pNewItem
+{
+ AquaSalMenu::addFallbackMenuItem( pNewItem );
+}
+
+-(void)removeFallbackMenuItem: (NSMenuItem*)pItem
+{
+ AquaSalMenu::removeFallbackMenuItem( pItem );
+}
+
+-(void)addDockMenuItem: (NSMenuItem*)pNewItem
+{
+ NSMenu* pDock = AquaSalInstance::GetDynamicDockMenu();
+ [pDock insertItem: pNewItem atIndex: [pDock numberOfItems]];
+}
+
+// for Apple Remote implementation
+
+#pragma mark -
+#pragma mark NSApplication Delegates
+- (void)applicationWillBecomeActive:(NSNotification *)aNotification {
+ if (GetSalData()->mpMainController->remoteControl) {
+
+ // [remoteControl startListening: self];
+ // does crash because the right thing to do is
+ // [GetSalData()->mpMainController->remoteControl startListening: self];
+ // but the instance variable 'remoteControl' is declared protected
+ // workaround : declare remoteControl instance variable as public in RemoteMainController.m
+
+ [GetSalData()->mpMainController->remoteControl startListening: self];
+#ifdef DEBUG
+ NSLog(@"Apple Remote will become active - Using remote controls");
+#endif
+ }
+}
+
+- (void)applicationWillResignActive:(NSNotification *)aNotification {
+ if (GetSalData()->mpMainController->remoteControl) {
+
+ // [remoteControl stopListening: self];
+ // does crash because the right thing to do is
+ // [GetSalData()->mpMainController->remoteControl stopListening: self];
+ // but the instance variable 'remoteControl' is declared protected
+ // workaround : declare remoteControl instance variable as public in RemoteMainController.m
+
+ [GetSalData()->mpMainController->remoteControl stopListening: self];
+#ifdef DEBUG
+ NSLog(@"Apple Remote will resign active - Releasing remote controls");
+#endif
+ }
+}
+
+- (MacOSBOOL)applicationShouldHandleReopen: (NSApplication*)pApp hasVisibleWindows: (MacOSBOOL) bWinVisible
+{
+ NSObject* pHdl = GetSalData()->mpDockIconClickHandler;
+ if( pHdl && [pHdl respondsToSelector: @selector(dockIconClicked:)] )
+ {
+ [pHdl performSelector:@selector(dockIconClicked:) withObject: self];
+ }
+ return YES;
+}
+
+-(void)setDockIconClickHandler: (NSObject*)pHandler
+{
+ GetSalData()->mpDockIconClickHandler = pHandler;
+}
+
+
+@end
+
diff --git a/vcl/aqua/source/dtrans/DataFlavorMapping.cxx b/vcl/aqua/source/dtrans/DataFlavorMapping.cxx
new file mode 100644
index 000000000000..e0a95a532bf8
--- /dev/null
+++ b/vcl/aqua/source/dtrans/DataFlavorMapping.cxx
@@ -0,0 +1,732 @@
+/*************************************************************************
+ *
+ * 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/unohelp.hxx"
+#include <DataFlavorMapping.hxx>
+#include "HtmlFmtFlt.hxx"
+#include "PictToBmpFlt.hxx"
+#include "com/sun/star/datatransfer/UnsupportedFlavorException.hpp"
+#include "com/sun/star/datatransfer/XMimeContentType.hpp"
+#include "com/sun/star/lang/XMultiServiceFactory.hpp"
+#include "com/sun/star/uno/Sequence.hxx"
+
+#include <rtl/ustring.hxx>
+#include <rtl/memory.h>
+#include <osl/endian.h>
+
+#include <vector>
+#include <stdio.h>
+
+#include <premac.h>
+#include <Cocoa/Cocoa.h>
+#include <postmac.h>
+
+using namespace ::com::sun::star::datatransfer;
+using namespace rtl;
+using namespace ::com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace cppu;
+using namespace std;
+
+namespace // private
+{
+ const Type CPPUTYPE_SEQINT8 = getCppuType((Sequence<sal_Int8>*)0);
+ const Type CPPUTYPE_OUSTRING = getCppuType( (OUString*)0 );
+
+ /* Determine whether or not a DataFlavor is valid.
+ */
+ bool isValidFlavor(const DataFlavor& aFlavor)
+ {
+ size_t len = aFlavor.MimeType.getLength();
+ Type dtype = aFlavor.DataType;
+ return ((len > 0) && ((dtype == CPPUTYPE_SEQINT8) || (dtype == CPPUTYPE_OUSTRING)));
+ }
+
+ typedef vector<sal_Unicode> UnicodeBuffer;
+
+ OUString NSStringToOUString(NSString* cfString)
+ {
+ BOOST_ASSERT(cfString && "Invalid parameter");
+
+ const char* utf8Str = [cfString UTF8String];
+ unsigned int len = rtl_str_getLength(utf8Str);
+
+ return OUString(utf8Str, len, RTL_TEXTENCODING_UTF8);
+ }
+
+ NSString* OUStringToNSString(const OUString& ustring)
+ {
+ OString utf8Str = OUStringToOString(ustring, RTL_TEXTENCODING_UTF8);
+ return [NSString stringWithCString: utf8Str.getStr() encoding: NSUTF8StringEncoding];
+ }
+
+
+ const NSString* PBTYPE_UT16 = @"CorePasteboardFlavorType 0x75743136";
+ const NSString* PBTYPE_PICT = @"CorePasteboardFlavorType 0x50494354";
+ const NSString* PBTYPE_HTML = @"CorePasteboardFlavorType 0x48544D4C";
+ const NSString* PBTYPE_SODX = @"application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star Object Descriptor (XML)\"";
+ const NSString* PBTYPE_SESX = @"application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"";
+ const NSString* PBTYPE_SLSDX = @"application/x-openoffice-linksrcdescriptor-xml;windows_formatname=\"Star Link Source Descriptor (XML)\"";
+ const NSString* PBTYPE_ESX = @"application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"";
+ const NSString* PBTYPE_LSX = @"application/x-openoffice-link-source-xml;windows_formatname=\"Star Link Source (XML)\"";
+ const NSString* PBTYPE_EOX = @"application/x-openoffice-embedded-obj-xml;windows_formatname=\"Star Embedded Object (XML)\"";
+ const NSString* PBTYPE_SVXB = @"application/x-openoffice-svbx;windows_formatname=\"SVXB (StarView Bitmap/Animation)\"";
+ const NSString* PBTYPE_GDIMF = @"application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"";
+ const NSString* PBTYPE_WMF = @"application/x-openoffice-wmf;windows_formatname=\"Image WMF\"";
+ const NSString* PBTYPE_EMF = @"application/x-openoffice-emf;windows_formatname=\"Image EMF\"";
+
+ const NSString* PBTYPE_DUMMY_INTERNAL = @"application/x-openoffice-internal";
+
+ const char* FLAVOR_SODX = "application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star Object Descriptor (XML)\"";
+ const char* FLAVOR_SESX = "application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"";
+ const char* FLAVOR_SLSDX = "application/x-openoffice-linksrcdescriptor-xml;windows_formatname=\"Star Link Source Descriptor (XML)\"";
+ const char* FLAVOR_ESX = "application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"";
+ const char* FLAVOR_LSX = "application/x-openoffice-link-source-xml;windows_formatname=\"Star Link Source (XML)\"";
+ const char* FLAVOR_EOX = "application/x-openoffice-embedded-obj-xml;windows_formatname=\"Star Embedded Object (XML)\"";
+ const char* FLAVOR_SVXB = "application/x-openoffice-svbx;windows_formatname=\"SVXB (StarView Bitmap/Animation)\"";
+ const char* FLAVOR_GDIMF = "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"";
+ const char* FLAVOR_WMF = "application/x-openoffice-wmf;windows_formatname=\"Image WMF\"";
+ const char* FLAVOR_EMF = "application/x-openoffice-emf;windows_formatname=\"Image EMF\"";
+
+ const char* FLAVOR_DUMMY_INTERNAL = "application/x-openoffice-internal";
+
+
+ struct FlavorMap
+ {
+ NSString* SystemFlavor;
+ const char* OOoFlavor;
+ const char* HumanPresentableName;
+ Type DataType;
+ };
+
+ /* At the moment it appears as if only MS Office pastes "public.html" to the clipboard.
+ */
+ FlavorMap flavorMap[] =
+ {
+ { NSStringPboardType, "text/plain;charset=utf-16", "Unicode Text (UTF-16)", CPPUTYPE_OUSTRING },
+ { NSRTFPboardType, "text/richtext", "Rich Text Format", CPPUTYPE_SEQINT8 },
+ { NSTIFFPboardType, "image/bmp", "Windows Bitmap", CPPUTYPE_SEQINT8 },
+ { NSPICTPboardType, "image/bmp", "Windows Bitmap", CPPUTYPE_SEQINT8 },
+ { NSHTMLPboardType, "text/html", "Plain Html", CPPUTYPE_SEQINT8 },
+ { NSFilenamesPboardType, "application/x-openoffice-filelist;windows_formatname=\"FileList\"", "FileList", CPPUTYPE_SEQINT8 },
+ { PBTYPE_SESX, FLAVOR_SESX, "Star Embed Source (XML)", CPPUTYPE_SEQINT8 },
+ { PBTYPE_SLSDX, FLAVOR_SLSDX, "Star Link Source Descriptor (XML)", CPPUTYPE_SEQINT8 },
+ { PBTYPE_ESX, FLAVOR_ESX, "Star Embed Source (XML)", CPPUTYPE_SEQINT8 },
+ { PBTYPE_LSX, FLAVOR_LSX, "Star Link Source (XML)", CPPUTYPE_SEQINT8 },
+ { PBTYPE_EOX, FLAVOR_EOX, "Star Embedded Object (XML)", CPPUTYPE_SEQINT8 },
+ { PBTYPE_SVXB, FLAVOR_SVXB, "SVXB (StarView Bitmap/Animation", CPPUTYPE_SEQINT8 },
+ { PBTYPE_GDIMF, FLAVOR_GDIMF, "GDIMetaFile", CPPUTYPE_SEQINT8 },
+ { PBTYPE_WMF, FLAVOR_WMF, "Windows MetaFile", CPPUTYPE_SEQINT8 },
+ { PBTYPE_EMF, FLAVOR_EMF, "Windows Enhanced MetaFile", CPPUTYPE_SEQINT8 },
+ { PBTYPE_SODX, FLAVOR_SODX, "Star Object Descriptor (XML)", CPPUTYPE_SEQINT8 },
+ { PBTYPE_DUMMY_INTERNAL, FLAVOR_DUMMY_INTERNAL, "internal data",CPPUTYPE_SEQINT8 }
+ };
+
+
+ #define SIZE_FLAVOR_MAP (sizeof(flavorMap)/sizeof(FlavorMap))
+
+
+ inline bool isByteSequenceType(const Type& theType)
+ {
+ return (theType == CPPUTYPE_SEQINT8);
+ }
+
+ inline bool isOUStringType(const Type& theType)
+ {
+ return (theType == CPPUTYPE_OUSTRING);
+ }
+
+} // namespace private
+
+
+//###########################
+
+/* A base class for other data provider.
+ */
+class DataProviderBaseImpl : public DataProvider
+{
+public:
+ DataProviderBaseImpl(const Any& data);
+ DataProviderBaseImpl(id data);
+ virtual ~DataProviderBaseImpl();
+
+protected:
+ Any mData;
+ //NSData* mSystemData;
+ id mSystemData;
+};
+
+DataProviderBaseImpl::DataProviderBaseImpl(const Any& data) :
+ mData(data),
+ mSystemData(nil)
+{
+}
+
+DataProviderBaseImpl::DataProviderBaseImpl(id data) :
+ mSystemData(data)
+{
+ [mSystemData retain];
+}
+
+
+DataProviderBaseImpl::~DataProviderBaseImpl()
+{
+ if (mSystemData)
+ {
+ [mSystemData release];
+ }
+}
+
+//#################################
+
+class UniDataProvider : public DataProviderBaseImpl
+{
+public:
+ UniDataProvider(const Any& data);
+
+ UniDataProvider(NSData* data);
+
+ virtual NSData* getSystemData();
+
+ virtual Any getOOoData();
+};
+
+UniDataProvider::UniDataProvider(const Any& data) :
+ DataProviderBaseImpl(data)
+{
+}
+
+UniDataProvider::UniDataProvider(NSData* data) :
+ DataProviderBaseImpl(data)
+{
+}
+
+NSData* UniDataProvider::getSystemData()
+{
+ OUString ustr;
+ mData >>= ustr;
+
+ OString strUtf8;
+ ustr.convertToString(&strUtf8, RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS);
+
+ return [NSData dataWithBytes: strUtf8.getStr() length: strUtf8.getLength()];
+}
+
+Any UniDataProvider::getOOoData()
+{
+ Any oOOData;
+
+ if (mSystemData)
+ {
+ oOOData = makeAny(OUString(reinterpret_cast<const sal_Char*>([mSystemData bytes]),
+ [mSystemData length],
+ RTL_TEXTENCODING_UTF8));
+ }
+ else
+ {
+ oOOData = mData;
+ }
+
+ return oOOData;
+}
+
+//###########################
+
+class ByteSequenceDataProvider : public DataProviderBaseImpl
+{
+public:
+ ByteSequenceDataProvider(const Any& data);
+
+ ByteSequenceDataProvider(NSData* data);
+
+ virtual NSData* getSystemData();
+
+ virtual Any getOOoData();
+};
+
+ByteSequenceDataProvider::ByteSequenceDataProvider(const Any& data) :
+ DataProviderBaseImpl(data)
+{
+}
+
+ByteSequenceDataProvider::ByteSequenceDataProvider(NSData* data) :
+ DataProviderBaseImpl(data)
+{
+}
+
+
+NSData* ByteSequenceDataProvider::getSystemData()
+{
+ Sequence<sal_Int8> rawData;
+ mData >>= rawData;
+
+ return [NSData dataWithBytes: rawData.getArray() length: rawData.getLength()];
+}
+
+Any ByteSequenceDataProvider::getOOoData()
+{
+ Any oOOData;
+
+ if (mSystemData)
+ {
+ unsigned int flavorDataLength = [mSystemData length];
+ Sequence<sal_Int8> byteSequence;
+ byteSequence.realloc(flavorDataLength);
+ memcpy(byteSequence.getArray(), [mSystemData bytes], flavorDataLength);
+ oOOData = makeAny(byteSequence);
+ }
+ else
+ {
+ oOOData = mData;
+ }
+
+ return oOOData;
+}
+
+
+//###########################
+
+class HTMLFormatDataProvider : public DataProviderBaseImpl
+{
+public:
+ HTMLFormatDataProvider(const Any& data);
+
+ HTMLFormatDataProvider(NSData* data);
+
+ virtual NSData* getSystemData();
+
+ virtual Any getOOoData();
+};
+
+HTMLFormatDataProvider::HTMLFormatDataProvider(const Any& data) :
+ DataProviderBaseImpl(data)
+{
+}
+
+HTMLFormatDataProvider::HTMLFormatDataProvider(NSData* data) :
+ DataProviderBaseImpl(data)
+{
+}
+
+NSData* HTMLFormatDataProvider::getSystemData()
+{
+ Sequence<sal_Int8> textHtmlData;
+ mData >>= textHtmlData;
+
+ Sequence<sal_Int8> htmlFormatData = TextHtmlToHTMLFormat(textHtmlData);
+
+ return [NSData dataWithBytes: htmlFormatData.getArray() length: htmlFormatData.getLength()];
+}
+
+Any HTMLFormatDataProvider::getOOoData()
+{
+ Any oOOData;
+
+ if (mSystemData)
+ {
+ unsigned int flavorDataLength = [mSystemData length];
+ Sequence<sal_Int8> unkHtmlData;
+
+ unkHtmlData.realloc(flavorDataLength);
+ memcpy(unkHtmlData.getArray(), [mSystemData bytes], flavorDataLength);
+
+ Sequence<sal_Int8>* pPlainHtml = &unkHtmlData;
+ Sequence<sal_Int8> plainHtml;
+
+ if (isHTMLFormat(unkHtmlData))
+ {
+ plainHtml = HTMLFormatToTextHtml(unkHtmlData);
+ pPlainHtml = &plainHtml;
+ }
+
+ oOOData = makeAny(*pPlainHtml);
+ }
+ else
+ {
+ oOOData = mData;
+ }
+
+ return oOOData;
+}
+
+//###########################
+
+class BMPDataProvider : public DataProviderBaseImpl
+{
+ NSBitmapImageFileType meImageType;
+public:
+ BMPDataProvider(const Any& data, NSBitmapImageFileType eImageType );
+
+ BMPDataProvider(NSData* data, NSBitmapImageFileType eImageType);
+
+ virtual NSData* getSystemData();
+
+ virtual Any getOOoData();
+};
+
+BMPDataProvider::BMPDataProvider(const Any& data, NSBitmapImageFileType eImageType) :
+ DataProviderBaseImpl(data),
+ meImageType( eImageType )
+{
+}
+
+BMPDataProvider::BMPDataProvider(NSData* data, NSBitmapImageFileType eImageType) :
+ DataProviderBaseImpl(data),
+ meImageType( eImageType )
+{
+}
+
+NSData* BMPDataProvider::getSystemData()
+{
+ Sequence<sal_Int8> bmpData;
+ mData >>= bmpData;
+
+ Sequence<sal_Int8> pictData;
+ NSData* sysData = NULL;
+
+ if (BMPToImage(bmpData, pictData, meImageType))
+ {
+ sysData = [NSData dataWithBytes: pictData.getArray() length: pictData.getLength()];
+ }
+
+ return sysData;
+}
+
+/* At the moment the OOo 'PCT' filter is not good enough to be used
+ and there is no flavor defined for exchanging 'PCT' with OOo so
+ we will at the moment convert 'PCT' to a Windows BMP and provide
+ this to OOo
+*/
+Any BMPDataProvider::getOOoData()
+{
+ Any oOOData;
+
+ if (mSystemData)
+ {
+ unsigned int flavorDataLength = [mSystemData length];
+ Sequence<sal_Int8> pictData(flavorDataLength);
+
+ memcpy(pictData.getArray(), [mSystemData bytes], flavorDataLength);
+
+ Sequence<sal_Int8> bmpData;
+
+ if (ImageToBMP(pictData, bmpData, meImageType))
+ {
+ oOOData = makeAny(bmpData);
+ }
+ }
+ else
+ {
+ oOOData = mData;
+ }
+
+ return oOOData;
+}
+
+//######################
+
+class FileListDataProvider : public DataProviderBaseImpl
+{
+public:
+ FileListDataProvider(const Any& data);
+ FileListDataProvider(NSArray* data);
+
+ virtual NSData* getSystemData();
+ virtual Any getOOoData();
+};
+
+FileListDataProvider::FileListDataProvider(const Any& data) :
+ DataProviderBaseImpl(data)
+{
+}
+
+FileListDataProvider::FileListDataProvider(NSArray* data) :
+ DataProviderBaseImpl(data)
+{
+}
+
+NSData* FileListDataProvider::getSystemData()
+{
+ return [NSData data];
+}
+
+Any FileListDataProvider::getOOoData()
+{
+ Any oOOData;
+
+ if (mSystemData)
+ {
+ size_t length = [mSystemData count];
+ size_t lenSeqRequired = 0;
+
+ for (size_t i = 0; i < length; i++)
+ {
+ NSString* fname = [mSystemData objectAtIndex: i];
+ lenSeqRequired += [fname maximumLengthOfBytesUsingEncoding: NSUnicodeStringEncoding] + sizeof(unichar);
+ }
+
+ Sequence<sal_Int8> oOOFileList(lenSeqRequired);
+ unichar* pBuffer = reinterpret_cast<unichar*>(oOOFileList.getArray());
+ rtl_zeroMemory(pBuffer, lenSeqRequired);
+
+ for (size_t i = 0; i < length; i++)
+ {
+ NSString* fname = [mSystemData objectAtIndex: i];
+ [fname getCharacters: pBuffer];
+ size_t l = [fname length];
+ pBuffer += l + 1;
+ }
+
+ oOOData = makeAny(oOOFileList);
+ }
+ else
+ {
+ oOOData = mData;
+ }
+
+ return oOOData;
+}
+
+//###########################
+
+DataFlavorMapper::DataFlavorMapper()
+{
+ Reference<XMultiServiceFactory> mrServiceManager = vcl::unohelper::GetMultiServiceFactory();
+ mrXMimeCntFactory = Reference<XMimeContentTypeFactory>(mrServiceManager->createInstance(
+ OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.MimeContentTypeFactory"))), UNO_QUERY);
+
+ if (!mrXMimeCntFactory.is())
+ throw RuntimeException(OUString(RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Cannot create com.sun.star.datatransfer.MimeContentTypeFactory")), NULL);
+}
+
+DataFlavor DataFlavorMapper::systemToOpenOfficeFlavor(NSString* systemDataFlavor) const
+{
+ DataFlavor oOOFlavor;
+
+ for (size_t i = 0; i < SIZE_FLAVOR_MAP; i++)
+ {
+ if ([systemDataFlavor caseInsensitiveCompare: flavorMap[i].SystemFlavor] == NSOrderedSame)
+ {
+ oOOFlavor.MimeType = OUString::createFromAscii(flavorMap[i].OOoFlavor);
+ oOOFlavor.HumanPresentableName = OUString(RTL_CONSTASCII_USTRINGPARAM(flavorMap[i].HumanPresentableName));
+ oOOFlavor.DataType = flavorMap[i].DataType;
+ return oOOFlavor;
+ }
+ } // for
+
+ return oOOFlavor;
+}
+
+NSString* DataFlavorMapper::openOfficeToSystemFlavor(const DataFlavor& oOOFlavor) const
+{
+ NSString* sysFlavor = NULL;
+
+ for (size_t i = 0; i < SIZE_FLAVOR_MAP; i++)
+ {
+ if (oOOFlavor.MimeType.compareToAscii(flavorMap[i].OOoFlavor, strlen(flavorMap[i].OOoFlavor)) == 0)
+ {
+ sysFlavor = flavorMap[i].SystemFlavor;
+ }
+ }
+
+ return sysFlavor;
+}
+
+NSString* DataFlavorMapper::openOfficeImageToSystemFlavor(NSPasteboard* pPasteboard) const
+{
+ NSArray *supportedTypes = [NSArray arrayWithObjects: NSTIFFPboardType, NSPICTPboardType, nil];
+ NSString *sysFlavor = [pPasteboard availableTypeFromArray:supportedTypes];
+ return sysFlavor;
+}
+
+DataProviderPtr_t DataFlavorMapper::getDataProvider(NSString* systemFlavor, Reference<XTransferable> rTransferable) const
+{
+ DataProviderPtr_t dp;
+
+ try
+ {
+ DataFlavor oOOFlavor = systemToOpenOfficeFlavor(systemFlavor);
+
+ Any data = rTransferable->getTransferData(oOOFlavor);
+
+ if (isByteSequenceType(data.getValueType()))
+ {
+ if ([systemFlavor caseInsensitiveCompare: NSHTMLPboardType] == NSOrderedSame)
+ {
+ dp = DataProviderPtr_t(new HTMLFormatDataProvider(data));
+ }
+ else if ([systemFlavor caseInsensitiveCompare: NSPICTPboardType] == NSOrderedSame)
+ {
+ dp = DataProviderPtr_t(new BMPDataProvider(data, PICTImageFileType));
+ }
+ else if ([systemFlavor caseInsensitiveCompare: NSTIFFPboardType] == NSOrderedSame)
+ {
+ dp = DataProviderPtr_t(new BMPDataProvider(data, NSTIFFFileType));
+ }
+ else if ([systemFlavor caseInsensitiveCompare: NSFilenamesPboardType] == NSOrderedSame)
+ {
+ dp = DataProviderPtr_t(new FileListDataProvider(data));
+ }
+ else
+ {
+ dp = DataProviderPtr_t(new ByteSequenceDataProvider(data));
+ }
+ }
+ else // Must be OUString type
+ {
+ BOOST_ASSERT(isOUStringType(data.getValueType()));
+ dp = DataProviderPtr_t(new UniDataProvider(data));
+ }
+ }
+ catch(UnsupportedFlavorException&)
+ {
+ // Somebody violates the contract of the clipboard
+ // interface @see XTransferable
+ }
+
+ return dp;
+}
+
+DataProviderPtr_t DataFlavorMapper::getDataProvider(const NSString* systemFlavor, NSArray* systemData) const
+{
+ return DataProviderPtr_t(new FileListDataProvider(systemData));
+}
+
+DataProviderPtr_t DataFlavorMapper::getDataProvider(const NSString* systemFlavor, NSData* systemData) const
+{
+ DataProviderPtr_t dp;
+
+ if ([systemFlavor caseInsensitiveCompare: NSStringPboardType] == NSOrderedSame)
+ {
+ dp = DataProviderPtr_t(new UniDataProvider(systemData));
+ }
+ else if ([systemFlavor caseInsensitiveCompare: NSHTMLPboardType] == NSOrderedSame)
+ {
+ dp = DataProviderPtr_t(new HTMLFormatDataProvider(systemData));
+ }
+ else if ([systemFlavor caseInsensitiveCompare: NSPICTPboardType] == NSOrderedSame)
+ {
+ dp = DataProviderPtr_t(new BMPDataProvider(systemData, PICTImageFileType));
+ }
+ else if ([systemFlavor caseInsensitiveCompare: NSTIFFPboardType] == NSOrderedSame)
+ {
+ dp = DataProviderPtr_t(new BMPDataProvider(systemData, NSTIFFFileType));
+ }
+ else if ([systemFlavor caseInsensitiveCompare: NSFilenamesPboardType] == NSOrderedSame)
+ {
+ //dp = DataProviderPtr_t(new FileListDataProvider(systemData));
+ }
+ else
+ {
+ dp = DataProviderPtr_t(new ByteSequenceDataProvider(systemData));
+ }
+
+ return dp;
+}
+
+bool DataFlavorMapper::isValidMimeContentType(const rtl::OUString& contentType) const
+{
+ bool result = true;
+
+ try
+ {
+ Reference<XMimeContentType> xCntType(mrXMimeCntFactory->createMimeContentType(contentType));
+ }
+ catch( IllegalArgumentException& )
+ {
+ result = false;
+ }
+
+ return result;
+}
+
+NSArray* DataFlavorMapper::flavorSequenceToTypesArray(const com::sun::star::uno::Sequence<com::sun::star::datatransfer::DataFlavor>& flavors) const
+{
+ sal_uInt32 nFlavors = flavors.getLength();
+ NSMutableArray* array = [[NSMutableArray alloc] initWithCapacity: 1];
+
+ for (sal_uInt32 i = 0; i < nFlavors; i++)
+ {
+ if( flavors[i].MimeType.compareToAscii( "image/bmp", 9 ) == 0 )
+ {
+ [array addObject: NSTIFFPboardType];
+ [array addObject: NSPICTPboardType];
+ }
+ else
+ {
+ NSString* str = openOfficeToSystemFlavor(flavors[i]);
+
+ if (str != NULL)
+ {
+ [array addObject: str];
+ }
+ }
+ }
+
+ // #i89462# #i90747#
+ // in case no system flavor was found to report
+ // report at least one so D&D between OOo targets works
+ if( [array count] == 0 )
+ {
+ [array addObject: PBTYPE_DUMMY_INTERNAL];
+ }
+
+ return [array autorelease];
+}
+
+com::sun::star::uno::Sequence<com::sun::star::datatransfer::DataFlavor> DataFlavorMapper::typesArrayToFlavorSequence(NSArray* types) const
+{
+ int nFormats = [types count];
+ Sequence<DataFlavor> flavors;
+
+ for (int i = 0; i < nFormats; i++)
+ {
+ NSString* sysFormat = [types objectAtIndex: i];
+ DataFlavor oOOFlavor = systemToOpenOfficeFlavor(sysFormat);
+
+ if (isValidFlavor(oOOFlavor))
+ {
+ flavors.realloc(flavors.getLength() + 1);
+ flavors[flavors.getLength() - 1] = oOOFlavor;
+ }
+ }
+
+ return flavors;
+}
+
+
+NSArray* DataFlavorMapper::getAllSupportedPboardTypes() const
+{
+ NSMutableArray* array = [[NSMutableArray alloc] initWithCapacity: SIZE_FLAVOR_MAP];
+
+ for (sal_uInt32 i = 0; i < SIZE_FLAVOR_MAP; i++)
+ {
+ [array addObject: flavorMap[i].SystemFlavor];
+ }
+
+ return [array autorelease];
+}
diff --git a/vcl/aqua/source/dtrans/DataFlavorMapping.hxx b/vcl/aqua/source/dtrans/DataFlavorMapping.hxx
new file mode 100644
index 000000000000..9847fcbd3987
--- /dev/null
+++ b/vcl/aqua/source/dtrans/DataFlavorMapping.hxx
@@ -0,0 +1,143 @@
+/*************************************************************************
+ *
+ * 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 INCLUDED_DATAFLAVORMAPPING_HXX_
+#define INCLUDED_DATAFLAVORMAPPING_HXX_
+
+#include <com/sun/star/datatransfer/DataFlavor.hpp>
+#include <com/sun/star/datatransfer/XMimeContentTypeFactory.hpp>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+
+#include <premac.h>
+#import <Cocoa/Cocoa.h>
+#include <postmac.h>
+
+#include <memory>
+#include <boost/shared_ptr.hpp>
+
+
+/* An interface to get the clipboard data in either
+ system or OOo format.
+ */
+class DataProvider
+{
+public:
+ virtual ~DataProvider() {};
+
+ /* Get the clipboard data in the system format.
+ The caller has to retain/release the returned
+ CFDataRef on demand.
+ */
+ virtual NSData* getSystemData() = 0;
+
+ /* Get the clipboard data in OOo format.
+ */
+ virtual com::sun::star::uno::Any getOOoData() = 0;
+};
+
+typedef std::auto_ptr<DataProvider> DataProviderPtr_t;
+
+
+//################################
+
+
+class DataFlavorMapper
+{
+public:
+ /* Initialialize a DataFavorMapper instance. Throws a RuntimeException in case the XMimeContentTypeFactory service
+ cannot be created.
+ */
+ DataFlavorMapper();
+
+
+ /* Map a system data flavor to an OpenOffice data flavor.
+ Return an empty string if there is not suiteable
+ mapping from a system data flavor to a OpenOffice data
+ flavor.
+ */
+ com::sun::star::datatransfer::DataFlavor systemToOpenOfficeFlavor(NSString* systemDataFlavor) const;
+
+
+ /* Map an OpenOffice data flavor to a system data flavor.
+ If there is no suiteable mapping available NULL will
+ be returned.
+ */
+ NSString* openOfficeToSystemFlavor(const com::sun::star::datatransfer::DataFlavor& oooDataFlavor) const;
+
+ /* Select the best available image data type
+ If there is no suiteable mapping available NULL will
+ be returned.
+ */
+ NSString* openOfficeImageToSystemFlavor(NSPasteboard* pPasteboard) const;
+
+ /* Get a data provider which is able to provide the data 'rTransferable' offers in a format that can
+ be put on to the system clipboard.
+ */
+ DataProviderPtr_t getDataProvider(NSString* systemFlavor,
+ const com::sun::star::uno::Reference< com::sun::star::datatransfer::XTransferable > rTransferable) const;
+
+
+
+ /* Get a data provider which is able to provide 'systemData' in the OOo expected format.
+ */
+ DataProviderPtr_t getDataProvider(const NSString* systemFlavor, NSArray* systemData) const;
+
+
+ /* Get a data provider which is able to provide 'systemData' in the OOo expected format.
+ */
+ DataProviderPtr_t getDataProvider(const NSString* systemFlavor, NSData* systemData) const;
+
+
+ /* Translate a sequence of DataFlavors into a NSArray of system types.
+ Only those DataFlavors for which a suitable mapping to a system
+ type exist will be contained in the returned types array.
+ */
+ NSArray* flavorSequenceToTypesArray(const com::sun::star::uno::Sequence<com::sun::star::datatransfer::DataFlavor>& flavors) const;
+
+ /* Translate a NSArray of system types into a sequence of DataFlavors.
+ Only those types for which a suitable mapping to a DataFlavor
+ exist will be contained in the new DataFlavor Sequence.
+ */
+ com::sun::star::uno::Sequence<com::sun::star::datatransfer::DataFlavor> typesArrayToFlavorSequence(NSArray* types) const;
+
+ /* Returns an NSArray containing all pasteboard types supported by OOo
+ */
+ NSArray* DataFlavorMapper::getAllSupportedPboardTypes() const;
+
+private:
+ /* Determines if the provided Mime content type is valid.
+ */
+ bool isValidMimeContentType(const rtl::OUString& contentType) const;
+
+private:
+ ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XMimeContentTypeFactory> mrXMimeCntFactory;
+};
+
+typedef boost::shared_ptr<DataFlavorMapper> DataFlavorMapperPtr_t;
+
+#endif
diff --git a/vcl/aqua/source/dtrans/DragActionConversion.cxx b/vcl/aqua/source/dtrans/DragActionConversion.cxx
new file mode 100644
index 000000000000..06ce57e8748f
--- /dev/null
+++ b/vcl/aqua/source/dtrans/DragActionConversion.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.
+ *
+ ************************************************************************/
+
+#include "DragActionConversion.hxx"
+#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
+
+
+using namespace com::sun::star::datatransfer::dnd;
+
+
+/* Convert office drag actions as defined in
+ <type>com::sun::star::datatransfer::dnd::DNDConstants</type>
+ into system conform drag actions.
+ */
+unsigned int OfficeToSystemDragActions(sal_Int8 dragActions)
+{
+ unsigned int actions = NSDragOperationNone;
+
+ if (dragActions & DNDConstants::ACTION_COPY)
+ {
+ actions |= NSDragOperationCopy;
+ }
+
+ if (dragActions & DNDConstants::ACTION_MOVE)
+ {
+ actions |= NSDragOperationMove;
+ }
+
+ if (dragActions & DNDConstants::ACTION_LINK)
+ {
+ actions |= NSDragOperationLink;
+ }
+
+ return actions;
+}
+
+/* Convert system conform drag actions into office conform
+ drag actions as defined in
+ <type>com::sun::star::datatransfer::dnd::DNDConstants</type>.
+ */
+sal_Int8 SystemToOfficeDragActions(unsigned int dragActions)
+{
+ sal_Int8 actions = DNDConstants::ACTION_NONE;
+
+ if (dragActions & NSDragOperationCopy)
+ {
+ actions |= DNDConstants::ACTION_COPY;
+ }
+
+ if (dragActions & NSDragOperationMove)
+ {
+ actions |= DNDConstants::ACTION_MOVE;
+ }
+
+ if (dragActions & NSDragOperationLink)
+ {
+ actions |= DNDConstants::ACTION_LINK;
+ }
+
+ // We map NSDragOperationGeneric to ACTION_DEFAULT to
+ // signal that we have to decide for a drag action
+ if (dragActions & NSDragOperationGeneric)
+ {
+ actions |= DNDConstants::ACTION_DEFAULT;
+ }
+
+ return actions;
+}
diff --git a/vcl/aqua/source/dtrans/DragActionConversion.hxx b/vcl/aqua/source/dtrans/DragActionConversion.hxx
new file mode 100644
index 000000000000..7facfef794b6
--- /dev/null
+++ b/vcl/aqua/source/dtrans/DragActionConversion.hxx
@@ -0,0 +1,46 @@
+/*************************************************************************
+ *
+ * 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 <sal/types.h>
+
+#include <premac.h>
+#import <Cocoa/Cocoa.h>
+#include <postmac.h>
+
+
+/* Convert office drag actions as defined in
+ <type>com::sun::star::datatransfer::dnd::DNDConstants</type>
+ into system conform drag actions.
+ */
+unsigned int OfficeToSystemDragActions(sal_Int8 dragActions);
+
+/* Convert system conform drag actions into office conform
+ drag actions as defined in
+ <type>com::sun::star::datatransfer::dnd::DNDConstants</type>.
+ */
+sal_Int8 SystemToOfficeDragActions(unsigned int dragActions);
diff --git a/vcl/aqua/source/dtrans/DragSource.cxx b/vcl/aqua/source/dtrans/DragSource.cxx
new file mode 100644
index 000000000000..adb247d70711
--- /dev/null
+++ b/vcl/aqua/source/dtrans/DragSource.cxx
@@ -0,0 +1,363 @@
+/*************************************************************************
+ *
+ * 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/datatransfer/dnd/DNDConstants.hpp>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <com/sun/star/awt/MouseButton.hpp>
+#include <rtl/unload.h>
+
+#include "comphelper/makesequence.hxx"
+
+#include "DragSource.hxx"
+#include "DragSourceContext.hxx"
+#include "aqua_clipboard.hxx"
+#include "DragActionConversion.hxx"
+
+#include <rtl/ustring.h>
+#include <memory>
+
+
+using namespace rtl;
+using namespace cppu;
+using namespace osl;
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::datatransfer::clipboard;
+using namespace com::sun::star::datatransfer::dnd;
+using namespace com::sun::star::datatransfer::dnd::DNDConstants;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::awt::MouseButton;
+using namespace com::sun::star::awt;
+using namespace com::sun::star::lang;
+using namespace comphelper;
+using namespace std;
+
+
+// For OOo internal D&D we provide the Transferable without NSDragPboard
+// interference as a shortcut
+Reference<XTransferable> DragSource::g_XTransferable = Reference<XTransferable>();
+NSView* DragSource::g_DragSourceView = nil;
+bool DragSource::g_DropSuccessSet = false;
+bool DragSource::g_DropSuccess = false;
+
+
+OUString dragSource_getImplementationName()
+{
+ return OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.datatransfer.dnd.OleDragSource_V1"));
+}
+
+Sequence<OUString> dragSource_getSupportedServiceNames()
+{
+ return makeSequence(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.dnd.OleDragSource")));
+}
+
+
+@implementation DragSourceHelper;
+
+-(DragSourceHelper*)initWithDragSource: (DragSource*) pds
+{
+ self = [super init];
+
+ if (self)
+ {
+ mDragSource = pds;
+ }
+
+ return self;
+}
+
+
+-(void)mouseDown: (NSEvent*)theEvent
+{
+ mDragSource->saveMouseEvent(theEvent);
+}
+
+
+-(void)mouseDragged: (NSEvent*)theEvent
+{
+ mDragSource->saveMouseEvent(theEvent);
+}
+
+
+-(unsigned int)draggingSourceOperationMaskForLocal: (MacOSBOOL)isLocal
+{
+ return mDragSource->getSupportedDragOperations(isLocal);
+}
+
+
+-(void)draggedImage:(NSImage*)anImage beganAt:(NSPoint)aPoint
+{
+ DragSourceDragEvent dsde(static_cast<OWeakObject*>(mDragSource),
+ new DragSourceContext(mDragSource),
+ mDragSource,
+ DNDConstants::ACTION_COPY,
+ DNDConstants::ACTION_COPY);
+
+ mDragSource->mXDragSrcListener->dragEnter(dsde);
+}
+
+
+-(void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation
+{
+ // an internal drop can accept the drop but fail with dropComplete( false )
+ // this is different than the Cocoa API
+ bool bDropSuccess = operation != NSDragOperationNone;
+ if( DragSource::g_DropSuccessSet )
+ bDropSuccess = DragSource::g_DropSuccess;
+
+ DragSourceDropEvent dsde(static_cast<OWeakObject*>(mDragSource),
+ new DragSourceContext(mDragSource),
+ static_cast< XDragSource* >(mDragSource),
+ SystemToOfficeDragActions(operation),
+ bDropSuccess );
+
+ mDragSource->mXDragSrcListener->dragDropEnd(dsde);
+ mDragSource->mXDragSrcListener = Reference<XDragSourceListener>();
+}
+
+
+-(void)draggedImage:(NSImage *)draggedImage movedTo:(NSPoint)screenPoint
+{
+ DragSourceDragEvent dsde(static_cast<OWeakObject*>(mDragSource),
+ new DragSourceContext(mDragSource),
+ mDragSource,
+ DNDConstants::ACTION_COPY,
+ DNDConstants::ACTION_COPY);
+
+ mDragSource->mXDragSrcListener->dragOver(dsde);
+}
+
+@end
+
+
+DragSource::DragSource():
+ WeakComponentImplHelper3<XDragSource, XInitialization, XServiceInfo>(m_aMutex),
+ mView(NULL),
+ mLastMouseEventBeforeStartDrag(nil),
+ m_MouseButton(0)
+{
+}
+
+
+DragSource::~DragSource()
+{
+ [(id <MouseEventListener>)mView unregisterMouseEventListener: mDragSourceHelper];
+ [mDragSourceHelper release];
+}
+
+
+void SAL_CALL DragSource::initialize(const Sequence< Any >& aArguments)
+ throw(Exception)
+{
+ if (aArguments.getLength() < 2)
+ {
+ throw Exception(OUString(RTL_CONSTASCII_USTRINGPARAM("DragSource::initialize: Not enough parameter.")),
+ static_cast<OWeakObject*>(this));
+ }
+
+ Any pNSView = aArguments[1];
+ sal_uInt64 tmp = 0;
+ pNSView >>= tmp;
+ mView = (NSView*)tmp;
+
+ /* All SalFrameView the base class for all VCL system views inherits from
+ NSView in order to get mouse and other events. This is the only way to
+ get these events. In order to start a drag operation we need to provide
+ the mouse event which was the trigger. SalFrameView therefor implements
+ a hook mechanism so that we can get mouse events for our purpose.
+ */
+ if (![mView respondsToSelector: @selector(registerMouseEventListener:)] ||
+ ![mView respondsToSelector: @selector(unregisterMouseEventListener:)])
+ {
+ throw Exception(OUString(RTL_CONSTASCII_USTRINGPARAM("DragSource::initialize: Provided view doesn't support mouse listener")),
+ static_cast<OWeakObject*>(this));
+ }
+
+ mDragSourceHelper = [[DragSourceHelper alloc] initWithDragSource: this];
+
+ if (mDragSourceHelper == nil)
+ {
+ throw Exception(OUString(RTL_CONSTASCII_USTRINGPARAM("DragSource::initialize: Cannot initialize DragSource")),
+ static_cast<OWeakObject*>(this));
+ }
+
+ [(id <MouseEventListener>)mView registerMouseEventListener: mDragSourceHelper];
+}
+
+
+//----------------------------------------------------
+// XDragSource
+//----------------------------------------------------
+
+sal_Bool SAL_CALL DragSource::isDragImageSupported( )
+ throw(RuntimeException)
+{
+ return true;
+}
+
+
+sal_Int32 SAL_CALL DragSource::getDefaultCursor( sal_Int8 /*dragAction*/ )
+ throw( IllegalArgumentException, RuntimeException)
+{
+ return 0;
+}
+
+
+void SAL_CALL DragSource::startDrag(const DragGestureEvent& trigger,
+ sal_Int8 sourceActions,
+ sal_Int32 cursor,
+ sal_Int32 image,
+ const Reference<XTransferable >& transferable,
+ const Reference<XDragSourceListener >& listener )
+ throw( RuntimeException)
+{
+ MutexGuard guard(m_aMutex);
+
+ OSL_ASSERT(listener.is() && "DragSource::startDrag: No XDragSourceListener provided\n");
+ OSL_ASSERT(transferable.is() && "DragSource::startDrag: No transferable provided\n");
+
+ trigger.Event >>= mMouseEvent;
+ m_MouseButton= mMouseEvent.Buttons;
+ mXDragSrcListener = listener;
+ mXCurrentContext = static_cast<XDragSourceContext*>(new DragSourceContext(this));
+ auto_ptr<AquaClipboard> clipb(new AquaClipboard(NULL, false));
+ g_XTransferable = transferable;
+ clipb->setContents(g_XTransferable, Reference<XClipboardOwner>());
+ mDragSourceActions = sourceActions;
+ g_DragSourceView = mView;
+
+ NSSize sz;
+ sz.width = 5;
+ sz.height = 5;
+
+ NSImage* dragImage;
+ dragImage = [[NSImage alloc] initWithSize: sz];
+
+ NSRect bounds;
+ bounds.origin = NSMakePoint(0,0);
+ bounds.size = sz;
+
+ [dragImage lockFocus];
+ [[NSColor blackColor] set];
+ [NSBezierPath fillRect: bounds];
+ [dragImage unlockFocus];
+
+ NSPoint pInWnd = [mLastMouseEventBeforeStartDrag locationInWindow];
+ NSPoint p;
+ p = [mView convertPoint: pInWnd fromView: nil];
+ p.x = p.x - sz.width/2;
+ p.y = p.y - sz.height/2;
+
+ // reset drop success flags
+ g_DropSuccessSet = false;
+ g_DropSuccess = false;
+
+ [mView dragImage: dragImage
+ at: p
+ offset: NSMakeSize(0,0)
+ event: mLastMouseEventBeforeStartDrag
+ pasteboard: clipb->getPasteboard()
+ source: mDragSourceHelper
+ slideBack: 1];
+
+ [dragImage release];
+
+ g_XTransferable = Reference<XTransferable>();
+ g_DragSourceView = nil;
+
+ // reset drop success flags
+ g_DropSuccessSet = false;
+ g_DropSuccess = false;
+}
+
+
+// In order to initiate a D&D operation we need to
+// provide the triggering mouse event which we get
+// from the SalFrameView that is associated with
+// this DragSource
+void DragSource::saveMouseEvent(NSEvent* theEvent)
+{
+ if (mLastMouseEventBeforeStartDrag != nil)
+ {
+ [mLastMouseEventBeforeStartDrag release];
+ }
+
+ mLastMouseEventBeforeStartDrag = theEvent;
+}
+
+
+/* isLocal indicates whether or not the DnD operation is OOo
+ internal.
+ */
+unsigned int DragSource::getSupportedDragOperations(bool isLocal) const
+{
+ unsigned int srcActions = OfficeToSystemDragActions(mDragSourceActions);
+
+ if (isLocal)
+ {
+ // Support NSDragOperation generic which means we can
+ // decide which D&D operation to choose. We map
+ // NSDragOperationGenric to DNDConstants::ACTION_DEFAULT
+ // in SystemToOfficeDragActions to signal this and
+ // use it in DropTarget::determineDropAction
+ srcActions |= NSDragOperationGeneric;
+ }
+ else
+ {
+ // Mask out link and move operations on external DnD
+ srcActions &= ~(NSDragOperationMove | NSDragOperationLink);
+ }
+
+ return srcActions;
+}
+
+
+//################################
+// XServiceInfo
+//################################
+
+OUString SAL_CALL DragSource::getImplementationName( ) throw (RuntimeException)
+{
+ return dragSource_getImplementationName();
+}
+
+
+sal_Bool SAL_CALL DragSource::supportsService( const OUString& ServiceName ) throw (RuntimeException)
+{
+ return ServiceName.equals(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.dnd.OleDragSource")));
+}
+
+
+Sequence< OUString > SAL_CALL DragSource::getSupportedServiceNames() throw (RuntimeException)
+{
+ return dragSource_getSupportedServiceNames();
+}
+
+
+
+
diff --git a/vcl/aqua/source/dtrans/DragSource.hxx b/vcl/aqua/source/dtrans/DragSource.hxx
new file mode 100644
index 000000000000..5d02b9874149
--- /dev/null
+++ b/vcl/aqua/source/dtrans/DragSource.hxx
@@ -0,0 +1,140 @@
+/*************************************************************************
+ *
+ * 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 _DRAGSOURCE_HXX_
+#define _DRAGSOURCE_HXX_
+
+#include <com/sun/star/datatransfer/dnd/XDragSource.hpp>
+#include <com/sun/star/datatransfer/dnd/XDragSourceContext.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <cppuhelper/compbase3.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/basemutex.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <osl/thread.h>
+#include <com/sun/star/awt/MouseEvent.hpp>
+
+#include <boost/utility.hpp>
+
+#include <premac.h>
+#import <Cocoa/Cocoa.h>
+#include <postmac.h>
+
+
+class DragSource;
+
+/* The functions declared in this protocol are actually
+ declared in vcl/aqua/inc/salframe.h. Because we want
+ to avoid importing VCL headers in UNO services and
+ on the other hand want to avoid warnings caused by
+ gcc complaining about unknowness of these functions
+ we declare them in a protocol here and cast at the
+ appropriate places.
+*/
+@protocol MouseEventListener
+-(void)registerMouseEventListener:(id)theHandler;
+-(void)unregisterMouseEventListener:(id)theHandler;
+@end
+
+
+@interface DragSourceHelper : NSObject
+{
+ DragSource* mDragSource;
+}
+
+-(DragSourceHelper*)initWithDragSource: (DragSource*) pds;
+
+-(void)mouseDown: (NSEvent*)theEvent;
+-(void)mouseDragged: (NSEvent*)theEvent;
+
+-(unsigned int)draggingSourceOperationMaskForLocal:(MacOSBOOL)isLocal;
+-(void)draggedImage:(NSImage*)anImage beganAt:(NSPoint)aPoint;
+-(void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation;
+-(void)draggedImage:(NSImage *)draggedImage movedTo:(NSPoint)screenPoint;
+
+@end
+
+
+class DragSource : public ::cppu::BaseMutex,
+ public ::cppu::WeakComponentImplHelper3< com::sun::star::datatransfer::dnd::XDragSource,
+ com::sun::star::lang::XInitialization,
+ com::sun::star::lang::XServiceInfo >,
+ private ::boost::noncopyable
+{
+public:
+ DragSource();
+ virtual ~DragSource();
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const com::sun::star::uno::Sequence< com::sun::star::uno::Any >& aArguments )
+ throw(com::sun::star::uno::Exception/*, com::sun::star::uno::RuntimeException*/);
+
+ // XDragSource
+ virtual sal_Bool SAL_CALL isDragImageSupported( ) throw(com::sun::star::uno::RuntimeException);
+
+ virtual sal_Int32 SAL_CALL getDefaultCursor(sal_Int8 dragAction)
+ throw(com::sun::star::lang::IllegalArgumentException, com::sun::star::uno::RuntimeException);
+
+ virtual void SAL_CALL startDrag( const com::sun::star::datatransfer::dnd::DragGestureEvent& trigger,
+ sal_Int8 sourceActions,
+ sal_Int32 cursor,
+ sal_Int32 image,
+ const com::sun::star::uno::Reference< com::sun::star::datatransfer::XTransferable >& transferable,
+ const com::sun::star::uno::Reference< com::sun::star::datatransfer::dnd::XDragSourceListener >& listener )
+ throw(com::sun::star::uno::RuntimeException);
+
+ // XServiceInfo
+ virtual rtl::OUString SAL_CALL getImplementationName() throw (com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL supportsService(const rtl::OUString& ServiceName) throw (com::sun::star::uno::RuntimeException);
+ virtual com::sun::star::uno::Sequence< rtl::OUString > SAL_CALL getSupportedServiceNames() throw (com::sun::star::uno::RuntimeException);
+
+ virtual void saveMouseEvent(NSEvent* theEvent);
+ virtual unsigned int getSupportedDragOperations(bool isLocal) const;
+
+public:
+ // The context notifies the XDragSourceListeners
+ com::sun::star::uno::Reference< com::sun::star::datatransfer::dnd::XDragSourceContext > mXCurrentContext;
+
+ id mView;
+ NSEvent* mLastMouseEventBeforeStartDrag;
+ DragSourceHelper* mDragSourceHelper;
+ com::sun::star::awt::MouseEvent mMouseEvent;
+ com::sun::star::uno::Reference< com::sun::star::datatransfer::XTransferable > mXTransferable;
+ com::sun::star::uno::Reference< com::sun::star::datatransfer::dnd::XDragSourceListener > mXDragSrcListener;
+ // The mouse button that set off the drag and drop operation
+ short m_MouseButton;
+ sal_Int8 mDragSourceActions;
+
+ static com::sun::star::uno::Reference< com::sun::star::datatransfer::XTransferable > g_XTransferable;
+ static NSView* g_DragSourceView;
+ static bool g_DropSuccessSet;
+ static bool g_DropSuccess;
+
+};
+
+
+#endif
diff --git a/vcl/aqua/source/dtrans/DragSourceContext.cxx b/vcl/aqua/source/dtrans/DragSourceContext.cxx
new file mode 100644
index 000000000000..cd70dc55c896
--- /dev/null
+++ b/vcl/aqua/source/dtrans/DragSourceContext.cxx
@@ -0,0 +1,74 @@
+/*************************************************************************
+ *
+ * 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/datatransfer/dnd/DNDConstants.hpp>
+
+#include "DragSourceContext.hxx"
+#include <rtl/unload.h>
+
+
+using namespace com::sun::star::datatransfer::dnd;
+using namespace com::sun::star::datatransfer::dnd::DNDConstants;
+using namespace com::sun::star::uno;
+using namespace cppu;
+
+DragSourceContext::DragSourceContext( DragSource* pSource) :
+ WeakComponentImplHelper1<XDragSourceContext>(m_aMutex),
+ m_pDragSource( pSource)
+{
+}
+
+DragSourceContext::~DragSourceContext()
+{
+}
+
+sal_Int32 SAL_CALL DragSourceContext::getCurrentCursor( )
+ throw( RuntimeException)
+{
+ return 0;
+}
+
+void SAL_CALL DragSourceContext::setCursor( sal_Int32 /*cursorId*/ )
+ throw( RuntimeException)
+{
+}
+
+void SAL_CALL DragSourceContext::setImage( sal_Int32 /*imageId*/ )
+ throw( RuntimeException)
+{
+}
+
+void SAL_CALL DragSourceContext::transferablesFlavorsChanged( )
+ throw( RuntimeException)
+{
+}
+
+
diff --git a/vcl/aqua/source/dtrans/DragSourceContext.hxx b/vcl/aqua/source/dtrans/DragSourceContext.hxx
new file mode 100644
index 000000000000..5d84c165d851
--- /dev/null
+++ b/vcl/aqua/source/dtrans/DragSourceContext.hxx
@@ -0,0 +1,72 @@
+/*************************************************************************
+ *
+ * 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 _DRAGSOURCECONTEXT_HXX_
+#define _DRAGSOURCECONTEXT_HXX_
+
+#include <cppuhelper/implbase1.hxx>
+#include <com/sun/star/datatransfer/dnd/XDragSourceContext.hpp>
+#include <cppuhelper/compbase1.hxx>
+#include <cppuhelper/basemutex.hxx>
+
+#include <boost/utility.hpp>
+
+#include "DragSource.hxx"
+
+// This class fires events to XDragSourceListener implementations.
+// Of that interface only dragDropEnd and dropActionChanged are called.
+// The functions dragEnter, dragExit and dragOver are not supported
+// currently.
+// An instance of SourceContext only lives as long as the drag and drop
+// operation lasts.
+class DragSourceContext: public cppu::BaseMutex,
+ public cppu::WeakComponentImplHelper1<com::sun::star::datatransfer::dnd::XDragSourceContext>,
+ private ::boost::noncopyable
+{
+public:
+ DragSourceContext(DragSource* pSource);
+ ~DragSourceContext();
+
+ virtual sal_Int32 SAL_CALL getCurrentCursor( )
+ throw( com::sun::star::uno::RuntimeException);
+
+ virtual void SAL_CALL setCursor( sal_Int32 cursorId )
+ throw( com::sun::star::uno::RuntimeException);
+
+ virtual void SAL_CALL setImage( sal_Int32 imageId )
+ throw( com::sun::star::uno::RuntimeException);
+
+ virtual void SAL_CALL transferablesFlavorsChanged( )
+ throw( com::sun::star::uno::RuntimeException);
+
+private:
+ DragSource* m_pDragSource;
+};
+
+
+
+#endif
diff --git a/vcl/aqua/source/dtrans/DropTarget.cxx b/vcl/aqua/source/dtrans/DropTarget.cxx
new file mode 100644
index 000000000000..c928d66e156d
--- /dev/null
+++ b/vcl/aqua/source/dtrans/DropTarget.cxx
@@ -0,0 +1,599 @@
+/*************************************************************************
+ *
+ * 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/datatransfer/dnd/DNDConstants.hpp>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <com/sun/star/datatransfer/dnd/DropTargetDragEnterEvent.hpp>
+#include <rtl/unload.h>
+
+#ifndef COMPHELPER_MAKESEQUENCE_HXX_INCLUDED
+#include "comphelper/makesequence.hxx"
+#endif
+#include <cppuhelper/interfacecontainer.hxx>
+
+#include "aqua_clipboard.hxx"
+#include "DropTarget.hxx"
+#include "DragActionConversion.hxx"
+
+#include "DragSource.hxx"
+
+#include <rtl/ustring.h>
+#include <stdio.h>
+
+#include <premac.h>
+#include <Carbon/Carbon.h>
+#include <postmac.h>
+
+
+using namespace rtl;
+using namespace cppu;
+using namespace osl;
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::datatransfer::dnd;
+using namespace com::sun::star::datatransfer::dnd::DNDConstants;
+using namespace com::sun::star::datatransfer::clipboard;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::uno;
+using namespace comphelper;
+
+OUString dropTarget_getImplementationName()
+{
+ return OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.datatransfer.dnd.OleDropTarget_V1"));
+}
+
+
+Sequence<OUString> dropTarget_getSupportedServiceNames()
+{
+ return makeSequence(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.dnd.OleDropTarget")));
+}
+
+
+namespace /* private */
+{
+ // Cocoa's coordinate system has its origin lower-left, VCL's
+ // coordinate system upper-left hence we need to transform
+ // coordinates
+
+ inline void CocoaToVCL(NSPoint& rPoint, const NSRect& bounds)
+ {
+ rPoint.y = bounds.size.height - rPoint.y;
+ }
+
+ inline void CocoaToVCL(NSRect& rRect, const NSRect& bounds)
+ {
+ rRect.origin.y = bounds.size.height - (rRect.origin.y + rRect.size.height);
+ }
+}
+
+
+@implementation DropTargetHelper
+
+
+-(DropTargetHelper*)initWithDropTarget:(DropTarget*)pdt
+{
+ self = [super init];
+
+ if (self)
+ {
+ mDropTarget = pdt;
+ }
+
+ return self;
+}
+
+
+-(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
+{
+ return mDropTarget->draggingEntered(sender);
+}
+
+
+-(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
+{
+ return mDropTarget->draggingUpdated(sender);
+}
+
+
+-(void)draggingExited:(id <NSDraggingInfo>)sender
+{
+ mDropTarget->draggingExited(sender);
+}
+
+
+-(MacOSBOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
+{
+ return mDropTarget->prepareForDragOperation(sender);
+}
+
+
+-(MacOSBOOL)performDragOperation:(id <NSDraggingInfo>)sender
+{
+ return mDropTarget->performDragOperation(sender);
+}
+
+
+-(void)concludeDragOperation:(id <NSDraggingInfo>)sender
+{
+ mDropTarget->concludeDragOperation(sender);
+}
+
+
+@end
+
+
+DropTarget::DropTarget() :
+ WeakComponentImplHelper5<XInitialization, XDropTarget, XDropTargetDragContext, XDropTargetDropContext, XServiceInfo>(m_aMutex),
+ mDropTargetHelper(nil),
+ mbActive(false),
+ mDragSourceSupportedActions(DNDConstants::ACTION_NONE),
+ mSelectedDropAction(DNDConstants::ACTION_NONE),
+ mDefaultActions(DNDConstants::ACTION_COPY_OR_MOVE | DNDConstants::ACTION_LINK | DNDConstants::ACTION_DEFAULT)
+{
+ mDataFlavorMapper = DataFlavorMapperPtr_t(new DataFlavorMapper());
+}
+
+
+DropTarget::~DropTarget()
+{
+ [(id <DraggingDestinationHandler>)mView unregisterDraggingDestinationHandler:mDropTargetHelper];
+ [mDropTargetHelper release];
+}
+
+
+sal_Int8 DropTarget::determineDropAction(sal_Int8 dropActions, id sender) const
+{
+ sal_Int8 dropAct = dropActions;
+ bool srcAndDestEqual = false;
+
+ if ([sender draggingSource] != nil)
+ {
+ // Internal DnD
+ NSView* destView = [[sender draggingDestinationWindow] contentView];
+ srcAndDestEqual = (DragSource::g_DragSourceView == destView);
+ }
+
+ // If ACTION_DEFAULT is set this means NSDragOperationGeneric
+ // has been set and we map this to ACTION_MOVE or ACTION_COPY
+ // depending on whether or not source and dest are equal,
+ // this hopefully satisfies all parties
+ if( (dropActions == DNDConstants::ACTION_DEFAULT)
+ || ((dropActions == mDragSourceSupportedActions)
+ && !(~mDragSourceSupportedActions & DNDConstants::ACTION_COPY_OR_MOVE ) ) )
+ {
+ dropAct = srcAndDestEqual ? DNDConstants::ACTION_MOVE :
+ DNDConstants::ACTION_COPY;
+ }
+ // if more than one drop actions have been specified
+ // set ACTION_DEFAULT in order to let the drop target
+ // decide which one to use
+ else if (dropActions != DNDConstants::ACTION_NONE &&
+ dropActions != DNDConstants::ACTION_MOVE &&
+ dropActions != DNDConstants::ACTION_COPY &&
+ dropActions != DNDConstants::ACTION_LINK)
+ {
+ if (srcAndDestEqual)
+ {
+ dropAct = dropActions;
+ }
+ else // source and destination are different
+ {
+ if (dropActions & DNDConstants::ACTION_COPY)
+ dropAct = DNDConstants::ACTION_COPY;
+ else if (dropActions & DNDConstants::ACTION_MOVE)
+ dropAct = DNDConstants::ACTION_MOVE;
+ else if (dropActions & DNDConstants::ACTION_LINK)
+ dropAct = DNDConstants::ACTION_LINK;
+ }
+
+ dropAct |= DNDConstants::ACTION_DEFAULT;
+ }
+
+ return dropAct;
+}
+
+
+NSDragOperation DropTarget::draggingEntered(id sender)
+{
+ // Initially when DnD will be started no modifier key can be pressed yet
+ // thus we are getting all actions that the drag source supports, we save
+ // this value because later the system masks the drag source actions if
+ // a modifier key will be pressed
+ mDragSourceSupportedActions = SystemToOfficeDragActions([sender draggingSourceOperationMask]);
+
+ // Only if the drop target is really interessted in the drag actions
+ // supported by the source
+ if (mDragSourceSupportedActions & mDefaultActions)
+ {
+ sal_Int8 currentAction = determineDropAction(mDragSourceSupportedActions, sender);
+
+ NSRect bounds = [mView bounds];
+ NSPoint dragLocation = [sender draggedImageLocation];
+
+ CocoaToVCL(dragLocation, bounds);
+
+ sal_Int32 posX = static_cast<sal_Int32>(dragLocation.x);
+ sal_Int32 posY = static_cast<sal_Int32>(dragLocation.y);
+
+ NSPasteboard* dragPboard = [sender draggingPasteboard];
+ mXCurrentDragClipboard = new AquaClipboard(dragPboard, false);
+
+ Reference<XTransferable> xTransferable = DragSource::g_XTransferable.is() ?
+ DragSource::g_XTransferable : mXCurrentDragClipboard->getContents();
+
+ DropTargetDragEnterEvent dtdee(static_cast<OWeakObject*>(this),
+ 0,
+ this,
+ currentAction,
+ posX,
+ posY,
+ mDragSourceSupportedActions,
+ xTransferable->getTransferDataFlavors());
+
+ fire_dragEnter(dtdee);
+ }
+
+ return OfficeToSystemDragActions(mSelectedDropAction);
+}
+
+
+NSDragOperation DropTarget::draggingUpdated(id sender)
+{
+ sal_Int8 currentDragSourceActions =
+ SystemToOfficeDragActions([sender draggingSourceOperationMask]);
+ NSDragOperation dragOp = NSDragOperationNone;
+
+ if (currentDragSourceActions & mDefaultActions)
+ {
+ sal_Int8 currentAction = determineDropAction(currentDragSourceActions, sender);
+ NSRect bounds = [mView bounds];
+ NSPoint dragLocation = [sender draggedImageLocation];
+
+ CocoaToVCL(dragLocation, bounds);
+
+ sal_Int32 posX = static_cast<sal_Int32>(dragLocation.x);
+ sal_Int32 posY = static_cast<sal_Int32>(dragLocation.y);
+
+ DropTargetDragEvent dtde(static_cast<OWeakObject*>(this),
+ 0,
+ this,
+ currentAction,
+ posX,
+ posY,
+ mDragSourceSupportedActions);
+
+ fire_dragOver(dtde);
+
+ // drag over callbacks likely have rendered something
+ [mView setNeedsDisplay: TRUE];
+
+ dragOp = OfficeToSystemDragActions(mSelectedDropAction);
+
+ //NSLog(@"Drag update: Source actions: %x proposed action %x selected action %x", mDragSourceSupportedActions, currentAction, mSelectedDropAction);
+ }
+
+ // Weird but it appears as if there is no method in Cocoa
+ // to create a kThemeCopyArrowCursor hence we have to use
+ // Carbon to do it
+ if (dragOp == NSDragOperationNone)
+ SetThemeCursor(kThemeNotAllowedCursor);
+ else if (dragOp == NSDragOperationCopy)
+ SetThemeCursor(kThemeCopyArrowCursor);
+ else
+ SetThemeCursor(kThemeArrowCursor);
+
+ return dragOp;
+}
+
+
+ void DropTarget::draggingExited(id sender)
+ {
+ DropTargetEvent dte(static_cast<OWeakObject*>(this), 0);
+ fire_dragExit(dte);
+ mDragSourceSupportedActions = DNDConstants::ACTION_NONE;
+ mSelectedDropAction = DNDConstants::ACTION_NONE;
+ SetThemeCursor(kThemeArrowCursor);
+ }
+
+
+ MacOSBOOL DropTarget::prepareForDragOperation(id sender)
+ {
+ return 1;
+ }
+
+
+MacOSBOOL DropTarget::performDragOperation(id sender)
+{
+ bool bSuccess = false;
+
+ if (mSelectedDropAction != DNDConstants::ACTION_NONE)
+ {
+ Reference<XTransferable> xTransferable = DragSource::g_XTransferable;
+
+ if (!DragSource::g_XTransferable.is())
+ {
+ xTransferable = mXCurrentDragClipboard->getContents();
+ }
+
+ NSRect bounds = [mView bounds];
+ NSPoint dragLocation = [sender draggedImageLocation];
+
+ CocoaToVCL(dragLocation, bounds);
+
+ sal_Int32 posX = static_cast<sal_Int32>(dragLocation.x);
+ sal_Int32 posY = static_cast<sal_Int32>(dragLocation.y);
+
+ DropTargetDropEvent dtde(static_cast<OWeakObject*>(this),
+ 0,
+ this,
+ mSelectedDropAction,
+ posX,
+ posY,
+ mDragSourceSupportedActions,
+ xTransferable);
+
+ fire_drop(dtde);
+
+ bSuccess = true;
+ }
+
+ return bSuccess;
+}
+
+
+ void DropTarget::concludeDragOperation(id sender)
+ {
+ mDragSourceSupportedActions = DNDConstants::ACTION_NONE;
+ mSelectedDropAction = DNDConstants::ACTION_NONE;
+ mXCurrentDragClipboard = Reference<XClipboard>();
+ SetThemeCursor(kThemeArrowCursor);
+ }
+
+
+ // called from WeakComponentImplHelperX::dispose
+ // WeakComponentImplHelper calls disposing before it destroys
+ // itself.
+ void SAL_CALL DropTarget::disposing()
+ {
+ }
+
+
+ void SAL_CALL DropTarget::initialize(const Sequence< Any >& aArguments)
+ throw(Exception)
+ {
+ if (aArguments.getLength() < 2)
+ {
+ throw RuntimeException(OUString(RTL_CONSTASCII_USTRINGPARAM("DropTarget::initialize: Cannot install window event handler")),
+ static_cast<OWeakObject*>(this));
+ }
+
+ Any pNSView = aArguments[0];
+ sal_uInt64 tmp = 0;
+ pNSView >>= tmp;
+ mView = (id)tmp;
+
+ mDropTargetHelper = [[DropTargetHelper alloc] initWithDropTarget: this];
+
+ [(id <DraggingDestinationHandler>)mView registerDraggingDestinationHandler:mDropTargetHelper];
+ [mView registerForDraggedTypes: mDataFlavorMapper->getAllSupportedPboardTypes()];
+
+ id wnd = [mView window];
+ NSWindow* parentWnd = [wnd parentWindow];
+ unsigned int topWndStyle = (NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask);
+ unsigned int wndStyles = [wnd styleMask] & topWndStyle;
+
+ if (parentWnd == nil && (wndStyles == topWndStyle))
+ {
+ [wnd registerDraggingDestinationHandler:mDropTargetHelper];
+ [wnd registerForDraggedTypes: [NSArray arrayWithObjects: NSFilenamesPboardType, nil]];
+ }
+ }
+
+
+ void SAL_CALL DropTarget::addDropTargetListener(const Reference<XDropTargetListener>& dtl)
+ throw(RuntimeException)
+ {
+ rBHelper.addListener(::getCppuType(&dtl), dtl);
+ }
+
+
+ void SAL_CALL DropTarget::removeDropTargetListener(const Reference<XDropTargetListener>& dtl)
+ throw(RuntimeException)
+ {
+ rBHelper.removeListener(::getCppuType(&dtl), dtl);
+ }
+
+
+ sal_Bool SAL_CALL DropTarget::isActive( ) throw(RuntimeException)
+ {
+ return mbActive;
+ }
+
+
+ void SAL_CALL DropTarget::setActive(sal_Bool active) throw(RuntimeException)
+ {
+ mbActive = active;
+ }
+
+
+ sal_Int8 SAL_CALL DropTarget::getDefaultActions() throw(RuntimeException)
+ {
+ return mDefaultActions;
+ }
+
+
+ void SAL_CALL DropTarget::setDefaultActions(sal_Int8 actions) throw(RuntimeException)
+ {
+ OSL_ENSURE( actions < 8, "No valid default actions");
+ mDefaultActions= actions;
+ }
+
+
+ // XDropTargetDragContext
+
+ void SAL_CALL DropTarget::acceptDrag(sal_Int8 dragOperation) throw (RuntimeException)
+ {
+ mSelectedDropAction = dragOperation;
+ }
+
+
+ void SAL_CALL DropTarget::rejectDrag() throw (RuntimeException)
+ {
+ mSelectedDropAction = DNDConstants::ACTION_NONE;
+ }
+
+
+ //XDropTargetDropContext
+
+ void SAL_CALL DropTarget::acceptDrop(sal_Int8 dropOperation) throw( RuntimeException)
+ {
+ mSelectedDropAction = dropOperation;
+ }
+
+
+ void SAL_CALL DropTarget::rejectDrop() throw (RuntimeException)
+ {
+ mSelectedDropAction = DNDConstants::ACTION_NONE;
+ }
+
+
+ void SAL_CALL DropTarget::dropComplete(sal_Bool success) throw (RuntimeException)
+ {
+ // Reset the internal transferable used as shortcut in case this is
+ // an internal D&D operation
+ DragSource::g_XTransferable = Reference<XTransferable>();
+ DragSource::g_DropSuccessSet = true;
+ DragSource::g_DropSuccess = success;
+ }
+
+
+ void DropTarget::fire_drop( const DropTargetDropEvent& dte)
+ {
+ OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (Reference<XDropTargetListener>* )0 ) );
+ if( pContainer)
+ {
+ OInterfaceIteratorHelper iter( *pContainer);
+ while( iter.hasMoreElements())
+ {
+ Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
+
+ try { listener->drop( dte); }
+ catch(RuntimeException&) {}
+ }
+ }
+ }
+
+
+ void DropTarget::fire_dragEnter(const DropTargetDragEnterEvent& e)
+ {
+ OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (Reference<XDropTargetListener>* )0 ) );
+ if( pContainer)
+ {
+ OInterfaceIteratorHelper iter( *pContainer);
+ while( iter.hasMoreElements())
+ {
+ Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
+
+ try { listener->dragEnter( e); }
+ catch (RuntimeException&) {}
+ }
+ }
+ }
+
+
+ void DropTarget::fire_dragExit(const DropTargetEvent& dte)
+ {
+ OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (Reference<XDropTargetListener>* )0 ) );
+
+ if( pContainer)
+ {
+ OInterfaceIteratorHelper iter( *pContainer);
+ while( iter.hasMoreElements())
+ {
+ Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
+
+ try { listener->dragExit( dte); }
+ catch (RuntimeException&) {}
+ }
+ }
+ }
+
+
+ void DropTarget::fire_dragOver(const DropTargetDragEvent& dtde)
+ {
+ OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (Reference<XDropTargetListener>* )0 ) );
+ if( pContainer)
+ {
+ OInterfaceIteratorHelper iter( *pContainer );
+ while( iter.hasMoreElements())
+ {
+ Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
+
+ try { listener->dragOver( dtde); }
+ catch (RuntimeException&) {}
+ }
+ }
+ }
+
+
+ void DropTarget::fire_dropActionChanged(const DropTargetDragEvent& dtde)
+ {
+ OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (Reference<XDropTargetListener>* )0 ) );
+ if( pContainer)
+ {
+ OInterfaceIteratorHelper iter( *pContainer);
+ while( iter.hasMoreElements())
+ {
+ Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
+
+ try { listener->dropActionChanged( dtde); }
+ catch (RuntimeException&) {}
+ }
+ }
+ }
+
+
+ // XServiceInfo
+
+ OUString SAL_CALL DropTarget::getImplementationName() throw (RuntimeException)
+ {
+ return dropTarget_getImplementationName();
+ }
+
+
+ sal_Bool SAL_CALL DropTarget::supportsService( const OUString& ServiceName ) throw (RuntimeException)
+ {
+ return ServiceName.equals(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.dnd.OleDropTarget")));
+ }
+
+
+ Sequence< OUString > SAL_CALL DropTarget::getSupportedServiceNames( ) throw (RuntimeException)
+ {
+ return dropTarget_getSupportedServiceNames();
+ }
+
diff --git a/vcl/aqua/source/dtrans/DropTarget.hxx b/vcl/aqua/source/dtrans/DropTarget.hxx
new file mode 100644
index 000000000000..6baa8bb69d01
--- /dev/null
+++ b/vcl/aqua/source/dtrans/DropTarget.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _DROPTARGET_HXX_
+#define _DROPTARGET_HXX_
+
+#include "DataFlavorMapping.hxx"
+#include <cppuhelper/compbase5.hxx>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/datatransfer/dnd/XDropTarget.hpp>
+
+#ifndef _COM_SUN_STAR_DATATRANSFER_DND_XDROPTARGETLISTENR_HPP_
+#include <com/sun/star/datatransfer/dnd/XDropTargetListener.hpp>
+#endif
+#include <com/sun/star/datatransfer/dnd/DropTargetDragEnterEvent.hpp>
+#include <com/sun/star/datatransfer/dnd/XDropTargetDragContext.hpp>
+#include <com/sun/star/datatransfer/dnd/XDropTargetDropContext.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/basemutex.hxx>
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+
+#include <boost/utility.hpp>
+
+#include <premac.h>
+#import <Cocoa/Cocoa.h>
+#include <postmac.h>
+
+class DropTarget;
+
+/* The functions declared in this protocol are actually
+ declared in vcl/aqua/inc/salframe.h. Because we want
+ to avoid importing VCL headers in UNO services and
+ on the other hand want to avoid warnings caused by
+ gcc complaining about unknowness of these functions
+ we declare them in a protocol here and cast at the
+ appropriate places.
+*/
+@protocol DraggingDestinationHandler
+-(void)registerDraggingDestinationHandler:(id)theHandler;
+-(void)unregisterDraggingDestinationHandler:(id)theHandler;
+@end
+
+
+@interface DropTargetHelper : NSObject
+{
+ DropTarget* mDropTarget;
+}
+
+-(DropTargetHelper*)initWithDropTarget:(DropTarget*)pdt;
+
+-(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender;
+-(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender;
+-(void)draggingExited:(id <NSDraggingInfo>)sender;
+-(MacOSBOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender;
+-(MacOSBOOL)performDragOperation:(id <NSDraggingInfo>)sender;
+-(void)concludeDragOperation:(id <NSDraggingInfo>)sender;
+
+@end
+
+
+class DropTarget: public cppu::BaseMutex,
+ public cppu::WeakComponentImplHelper5< com::sun::star::lang::XInitialization,
+ com::sun::star::datatransfer::dnd::XDropTarget,
+ com::sun::star::datatransfer::dnd::XDropTargetDragContext,
+ com::sun::star::datatransfer::dnd::XDropTargetDropContext,
+ com::sun::star::lang::XServiceInfo >,
+ private boost::noncopyable
+{
+public:
+ DropTarget();
+ virtual ~DropTarget();
+
+ // Overrides WeakComponentImplHelper::disposing which is called by
+ // WeakComponentImplHelper::dispose
+ // Must be called.
+ virtual void SAL_CALL disposing();
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const com::sun::star::uno::Sequence< com::sun::star::uno::Any >& aArguments )
+ throw(com::sun::star::uno::Exception);
+
+ // XDropTarget
+ virtual void SAL_CALL addDropTargetListener( const com::sun::star::uno::Reference< com::sun::star::datatransfer::dnd::XDropTargetListener >& dtl )
+ throw(com::sun::star::uno::RuntimeException);
+
+ virtual void SAL_CALL removeDropTargetListener( const com::sun::star::uno::Reference< com::sun::star::datatransfer::dnd::XDropTargetListener >& dtl )
+ throw(com::sun::star::uno::RuntimeException);
+
+ // Default is not active
+ virtual sal_Bool SAL_CALL isActive() throw(com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL setActive(sal_Bool isActive) throw(com::sun::star::uno::RuntimeException);
+ virtual sal_Int8 SAL_CALL getDefaultActions() throw(com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL setDefaultActions(sal_Int8 actions) throw(com::sun::star::uno::RuntimeException);
+
+ // XDropTargetDragContext
+ virtual void SAL_CALL acceptDrag(sal_Int8 dragOperation) throw(com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL rejectDrag() throw(com::sun::star::uno::RuntimeException);
+
+ // XDropTargetDragContext
+ virtual void SAL_CALL acceptDrop(sal_Int8 dropOperation) throw (com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL rejectDrop() throw (com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL dropComplete(sal_Bool success) throw (com::sun::star::uno::RuntimeException);
+
+ // XServiceInfo
+ virtual rtl::OUString SAL_CALL getImplementationName() throw (com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL supportsService(const rtl::OUString& ServiceName) throw (com::sun::star::uno::RuntimeException);
+ virtual com::sun::star::uno::Sequence< rtl::OUString > SAL_CALL getSupportedServiceNames() throw (com::sun::star::uno::RuntimeException);
+
+ // NSDraggingDestination protocol functions
+ virtual NSDragOperation draggingEntered(id sender);
+ virtual NSDragOperation draggingUpdated(id sender);
+ virtual void draggingExited(id sender);
+ virtual MacOSBOOL prepareForDragOperation(id sender);
+ virtual MacOSBOOL performDragOperation(id sender);
+ virtual void concludeDragOperation(id sender);
+
+ /* If multiple actions are supported by the drag source and
+ the user did not choose a specific action by pressing a
+ modifier key choose a default action to be proposed to
+ the application.
+ */
+ sal_Int8 determineDropAction(sal_Int8 dropActions, id sender) const;
+
+private:
+ void fire_drop(const com::sun::star::datatransfer::dnd::DropTargetDropEvent& dte);
+ void fire_dragEnter(const com::sun::star::datatransfer::dnd::DropTargetDragEnterEvent& dtdee);
+ void fire_dragExit(const com::sun::star::datatransfer::dnd::DropTargetEvent& dte);
+ void fire_dragOver(const com::sun::star::datatransfer::dnd::DropTargetDragEvent& dtde);
+ void fire_dropActionChanged(const com::sun::star::datatransfer::dnd::DropTargetDragEvent& dtde);
+
+private:
+ com::sun::star::uno::Reference< com::sun::star::datatransfer::dnd::XDropTargetDragContext > mXCurrentDragContext;
+ com::sun::star::uno::Reference< com::sun::star::datatransfer::dnd::XDropTargetDropContext > mXCurrentDropContext;
+ com::sun::star::uno::Reference< com::sun::star::datatransfer::clipboard::XClipboard > mXCurrentDragClipboard;
+ DataFlavorMapperPtr_t mDataFlavorMapper;
+ id mView;
+ DropTargetHelper* mDropTargetHelper;
+ bool mbActive;
+ sal_Int8 mDragSourceSupportedActions;
+ sal_Int8 mSelectedDropAction;
+ sal_Int8 mDefaultActions;
+};
+
+#endif
diff --git a/vcl/aqua/source/dtrans/HtmlFmtFlt.cxx b/vcl/aqua/source/dtrans/HtmlFmtFlt.cxx
new file mode 100644
index 000000000000..3f558b0a5b4f
--- /dev/null
+++ b/vcl/aqua/source/dtrans/HtmlFmtFlt.cxx
@@ -0,0 +1,147 @@
+#include "HtmlFmtFlt.hxx"
+
+#include <rtl/string.h>
+
+#include <string>
+#include <sstream>
+#include <vector>
+#include <iomanip>
+
+#include <boost/assert.hpp>
+
+using namespace com::sun::star::uno;
+
+//------------------------------------------------------------------------------
+// converts the openoffice text/html clipboard format to the HTML Format
+// well known under MS Windows
+// the MS HTML Format has a header before the real html data
+//
+// Version:1.0 Version number of the clipboard. Staring is 0.9
+// StartHTML: Byte count from the beginning of the clipboard to the start
+// of the context, or -1 if no context
+// EndHTML: Byte count from the beginning of the clipboard to the end
+// of the context, or -1 if no context
+// StartFragment: Byte count from the beginning of the clipboard to the
+// start of the fragment
+// EndFragment: Byte count from the beginning of the clipboard to the
+// end of the fragment
+// StartSelection: Byte count from the beginning of the clipboard to the
+// start of the selection
+// EndSelection: Byte count from the beginning of the clipboard to the
+// end of the selection
+//
+// StartSelection and EndSelection are optional
+// The fragment should be preceded and followed by the HTML comments
+// <!--StartFragment--> and <!--EndFragment--> (no space between !-- and the
+// text
+//------------------------------------------------------------------------------
+
+namespace // private
+{
+std::string GetHtmlFormatHeader(size_t startHtml, size_t endHtml, size_t startFragment, size_t endFragment)
+{
+ std::ostringstream htmlHeader;
+ htmlHeader << "Version:1.0" << '\r' << '\n';
+ htmlHeader << "StartHTML:" << std::setw(10) << std::setfill('0') << std::dec << startHtml << '\r' << '\n';
+ htmlHeader << "EndHTML:" << std::setw(10) << std::setfill('0') << std::dec << endHtml << '\r' << '\n';
+ htmlHeader << "StartFragment:" << std::setw(10) << std::setfill('0') << std::dec << startFragment << '\r' << '\n';
+ htmlHeader << "EndFragment:" << std::setw(10) << std::setfill('0') << std::dec << endFragment << '\r' << '\n';
+ return htmlHeader.str();
+}
+
+} // namespace private
+
+
+// the office allways writes the start and end html tag in upper cases and
+// without spaces both tags don't allow parameters
+const std::string TAG_HTML = std::string("<HTML>");
+const std::string TAG_END_HTML = std::string("</HTML>");
+
+// The body tag may have parameters so we need to search for the
+// closing '>' manually e.g. <BODY param> #92840#
+const std::string TAG_BODY = std::string("<BODY");
+const std::string TAG_END_BODY = std::string("</BODY");
+
+Sequence<sal_Int8> SAL_CALL TextHtmlToHTMLFormat(Sequence<sal_Int8>& aTextHtml)
+{
+ OSL_ASSERT(aTextHtml.getLength() > 0);
+
+ if (!(aTextHtml.getLength() > 0))
+ return Sequence<sal_Int8>();
+
+ // fill the buffer with dummy values to calc the exact length
+ std::string dummyHtmlHeader = GetHtmlFormatHeader(0, 0, 0, 0);
+ size_t lHtmlFormatHeader = dummyHtmlHeader.length();
+
+ std::string textHtml(
+ reinterpret_cast<const sal_Char*>(aTextHtml.getConstArray()),
+ reinterpret_cast<const sal_Char*>(aTextHtml.getConstArray()) + aTextHtml.getLength());
+
+ std::string::size_type nStartHtml = textHtml.find(TAG_HTML) + lHtmlFormatHeader - 1; // we start one before '<HTML>' Word 2000 does also so
+ std::string::size_type nEndHtml = textHtml.find(TAG_END_HTML) + lHtmlFormatHeader + TAG_END_HTML.length() + 1; // our SOffice 5.2 wants 2 behind </HTML>?
+
+ // The body tag may have parameters so we need to search for the
+ // closing '>' manually e.g. <BODY param> #92840#
+ std::string::size_type nStartFragment = textHtml.find(">", textHtml.find(TAG_BODY)) + lHtmlFormatHeader + 1;
+ std::string::size_type nEndFragment = textHtml.find(TAG_END_BODY) + lHtmlFormatHeader;
+
+ std::string htmlFormat = GetHtmlFormatHeader(nStartHtml, nEndHtml, nStartFragment, nEndFragment);
+ htmlFormat += textHtml;
+
+ Sequence<sal_Int8> byteSequence(htmlFormat.length() + 1); // space the trailing '\0'
+ rtl_zeroMemory(byteSequence.getArray(), byteSequence.getLength());
+
+ rtl_copyMemory(
+ static_cast<void*>(byteSequence.getArray()),
+ static_cast<const void*>(htmlFormat.c_str()),
+ htmlFormat.length());
+
+ return byteSequence;
+}
+
+const char* HtmlStartTag = "<html";
+
+Sequence<sal_Int8> HTMLFormatToTextHtml(const Sequence<sal_Int8>& aHTMLFormat)
+{
+ BOOST_ASSERT(isHTMLFormat(aHTMLFormat) && "No HTML Format provided");
+
+ Sequence<sal_Int8>& nonconstHTMLFormatRef = const_cast< Sequence<sal_Int8>& >(aHTMLFormat);
+ sal_Char* dataStart = reinterpret_cast<sal_Char*>(nonconstHTMLFormatRef.getArray());
+ sal_Char* dataEnd = dataStart + nonconstHTMLFormatRef.getLength() - 1;
+ const sal_Char* htmlStartTag = strcasestr(dataStart, HtmlStartTag);
+
+ BOOST_ASSERT(htmlStartTag && "Seems to be no HTML at all");
+
+ // It doesn't seem to be HTML? Well then simply return what has been
+ // provided in non-debug builds
+ if (htmlStartTag == NULL)
+ {
+ return aHTMLFormat;
+ }
+
+ sal_Int32 len = dataEnd - htmlStartTag;
+ Sequence<sal_Int8> plainHtmlData(len);
+
+ rtl_copyMemory(static_cast<void*>(plainHtmlData.getArray()), htmlStartTag, len);
+
+ return plainHtmlData;
+}
+
+/* A simple format detection. We are just comparing the first few bytes
+ of the provided byte sequence to see whether or not it is the MS
+ Office Html format. If it shows that this is not reliable enough we
+ can improve this
+*/
+const char HtmlFormatStart[] = "Version:";
+int HtmlFormatStartLen = (sizeof(HtmlFormatStart) - 1);
+
+bool isHTMLFormat(const Sequence<sal_Int8>& aHtmlSequence)
+{
+ if (aHtmlSequence.getLength() < HtmlFormatStartLen)
+ return false;
+
+ return rtl_str_compareIgnoreAsciiCase_WithLength(HtmlFormatStart,
+ HtmlFormatStartLen,
+ reinterpret_cast<const sal_Char*>(aHtmlSequence.getConstArray()),
+ HtmlFormatStartLen) == 0;
+}
diff --git a/vcl/aqua/source/dtrans/HtmlFmtFlt.hxx b/vcl/aqua/source/dtrans/HtmlFmtFlt.hxx
new file mode 100644
index 000000000000..49f0cc70590c
--- /dev/null
+++ b/vcl/aqua/source/dtrans/HtmlFmtFlt.hxx
@@ -0,0 +1,20 @@
+#ifndef INCLUDED_HTMLFMTFLT_HXX
+#define INCLUDED_HTMLFMTFLT_HXX
+
+#include <com/sun/star/uno/Sequence.hxx>
+
+/* Transform plain HTML into the format expected by MS Office.
+ */
+com::sun::star::uno::Sequence<sal_Int8> TextHtmlToHTMLFormat(com::sun::star::uno::Sequence<sal_Int8>& aTextHtml);
+
+/* Transform the MS Office HTML format into plain HTML.
+ */
+com::sun::star::uno::Sequence<sal_Int8> HTMLFormatToTextHtml(const com::sun::star::uno::Sequence<sal_Int8>& aHTMLFormat);
+
+/* Detects whether the given byte sequence contains the MS Office Html format.
+
+ @returns True if the MS Office Html format will be detected False otherwise.
+ */
+bool isHTMLFormat (const com::sun::star::uno::Sequence<sal_Int8>& aHtmlSequence);
+
+#endif
diff --git a/vcl/aqua/source/dtrans/OSXTransferable.cxx b/vcl/aqua/source/dtrans/OSXTransferable.cxx
new file mode 100644
index 000000000000..2e6b327de446
--- /dev/null
+++ b/vcl/aqua/source/dtrans/OSXTransferable.cxx
@@ -0,0 +1,215 @@
+/*************************************************************************
+ *
+ * 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/types.h>
+
+#ifndef _TRANSFERABLE_HXX_
+#include "OSXTransferable.hxx"
+#endif
+
+#include "DataFlavorMapping.hxx"
+
+using namespace rtl;
+using namespace std;
+using namespace osl;
+using namespace cppu;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::io;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::container;
+
+const Type CPPUTYPE_SEQINT8 = getCppuType((Sequence<sal_Int8>*)0);
+const Type CPPUTYPE_OUSTRING = getCppuType((OUString*)0);
+
+namespace // private
+{
+ bool isValidFlavor( const DataFlavor& aFlavor )
+ {
+ size_t len = aFlavor.MimeType.getLength();
+ Type dtype = aFlavor.DataType;
+ return ((len > 0) && ((dtype == CPPUTYPE_SEQINT8) || (dtype == CPPUTYPE_OUSTRING)));
+ }
+
+} // namespace private
+
+
+OSXTransferable::OSXTransferable(const Reference<XMimeContentTypeFactory> rXMimeCntFactory,
+ DataFlavorMapperPtr_t pDataFlavorMapper,
+ NSPasteboard* pasteboard) :
+ mrXMimeCntFactory(rXMimeCntFactory),
+ mDataFlavorMapper(pDataFlavorMapper),
+ mPasteboard(pasteboard)
+{
+ [mPasteboard retain];
+
+ initClipboardItemList();
+}
+
+
+OSXTransferable::~OSXTransferable()
+{
+ [mPasteboard release];
+}
+
+
+Any SAL_CALL OSXTransferable::getTransferData( const DataFlavor& aFlavor )
+ throw( UnsupportedFlavorException, IOException, RuntimeException )
+{
+ if (!isValidFlavor(aFlavor) || !isDataFlavorSupported(aFlavor))
+ {
+ throw UnsupportedFlavorException(OUString(RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Unsupported data flavor")),
+ static_cast<XTransferable*>(this));
+ }
+
+ NSString* sysFormat =
+ (aFlavor.MimeType.compareToAscii( "image/bmp", 9 ) == 0)
+ ? mDataFlavorMapper->openOfficeImageToSystemFlavor( mPasteboard )
+ : mDataFlavorMapper->openOfficeToSystemFlavor(aFlavor);
+ DataProviderPtr_t dp;
+
+ if ([sysFormat caseInsensitiveCompare: NSFilenamesPboardType] == NSOrderedSame)
+ {
+ NSArray* sysData = [mPasteboard propertyListForType: sysFormat];
+ dp = mDataFlavorMapper->getDataProvider(sysFormat, sysData);
+ }
+ else
+ {
+ NSData* sysData = [mPasteboard dataForType: sysFormat];
+ dp = mDataFlavorMapper->getDataProvider(sysFormat, sysData);
+ }
+
+ if (dp.get() == NULL)
+ {
+ throw UnsupportedFlavorException(OUString(RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Unsupported data flavor")),
+ static_cast<XTransferable*>(this));
+ }
+
+ return dp->getOOoData();
+}
+
+
+bool OSXTransferable::isUnicodeText(const DataFlavor& flavor)
+{
+ return (flavor.DataType == CPPUTYPE_OUSTRING);
+}
+
+
+Sequence< DataFlavor > SAL_CALL OSXTransferable::getTransferDataFlavors( )
+ throw( RuntimeException )
+{
+ return mFlavorList;
+}
+
+
+sal_Bool SAL_CALL OSXTransferable::isDataFlavorSupported(const DataFlavor& aFlavor)
+ throw( RuntimeException )
+{
+ for (sal_Int32 i = 0; i < mFlavorList.getLength(); i++)
+ if (compareDataFlavors(aFlavor, mFlavorList[i]))
+ return sal_True;
+
+ return sal_False;
+}
+
+
+void OSXTransferable::initClipboardItemList()
+{
+ NSArray* pboardFormats = [mPasteboard types];
+
+ if (pboardFormats == NULL)
+ {
+ throw RuntimeException(OUString(RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Cannot get clipboard data")),
+ static_cast<XTransferable*>(this));
+ }
+
+ mFlavorList = mDataFlavorMapper->typesArrayToFlavorSequence(pboardFormats);
+}
+
+
+/* Compares two DataFlavors. Returns true if both DataFlavor have the same media type
+ and the number of parameter and all parameter values do match otherwise false
+ is returned.
+ */
+bool OSXTransferable::compareDataFlavors(const DataFlavor& lhs, const DataFlavor& rhs )
+{
+ try
+ {
+ Reference<XMimeContentType> xLhs(mrXMimeCntFactory->createMimeContentType(lhs.MimeType));
+ Reference<XMimeContentType> xRhs(mrXMimeCntFactory->createMimeContentType(rhs.MimeType));
+
+ if (!xLhs->getFullMediaType().equalsIgnoreAsciiCase(xRhs->getFullMediaType()) ||
+ !cmpAllContentTypeParameter(xLhs, xRhs))
+ {
+ return false;
+ }
+ }
+ catch( IllegalArgumentException& )
+ {
+ OSL_ENSURE( sal_False, "Invalid content type detected" );
+ return false;
+ }
+
+ return true;
+}
+
+
+bool OSXTransferable::cmpAllContentTypeParameter(const Reference<XMimeContentType> xLhs,
+ const Reference<XMimeContentType> xRhs) const
+{
+ Sequence<OUString> xLhsFlavors = xLhs->getParameters();
+ Sequence<OUString> xRhsFlavors = xRhs->getParameters();
+
+ // Stop here if the number of parameters is different already
+ if (xLhsFlavors.getLength() != xRhsFlavors.getLength())
+ return false;
+
+ try
+ {
+ OUString pLhs;
+ OUString pRhs;
+
+ for (sal_Int32 i = 0; i < xLhsFlavors.getLength(); i++)
+ {
+ pLhs = xLhs->getParameterValue(xLhsFlavors[i]);
+ pRhs = xRhs->getParameterValue(xLhsFlavors[i]);
+
+ if (!pLhs.equalsIgnoreAsciiCase(pRhs))
+ {
+ return false;
+ }
+ }
+ }
+ catch(IllegalArgumentException&)
+ {
+ return false;
+ }
+
+ return true;
+}
diff --git a/vcl/aqua/source/dtrans/OSXTransferable.hxx b/vcl/aqua/source/dtrans/OSXTransferable.hxx
new file mode 100644
index 000000000000..6601905f1610
--- /dev/null
+++ b/vcl/aqua/source/dtrans/OSXTransferable.hxx
@@ -0,0 +1,100 @@
+/*************************************************************************
+ *
+ * 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 _TRANSFERABLE_HXX_
+#define _TRANSFERABLE_HXX_
+
+//------------------------------------------------------------------------
+// includes
+//------------------------------------------------------------------------
+
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <cppuhelper/implbase1.hxx>
+#include <com/sun/star/datatransfer/XMimeContentTypeFactory.hpp>
+#include <com/sun/star/datatransfer/XMimeContentType.hpp>
+
+#include "DataFlavorMapping.hxx"
+
+#include <premac.h>
+#import <Cocoa/Cocoa.h>
+#include <postmac.h>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+#include <vector>
+
+
+class OSXTransferable : public ::cppu::WeakImplHelper1<com::sun::star::datatransfer::XTransferable>,
+ private ::boost::noncopyable
+{
+public:
+ typedef com::sun::star::uno::Sequence< sal_Int8 > ByteSequence_t;
+
+ explicit OSXTransferable(com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XMimeContentTypeFactory> rXMimeCntFactory,
+ DataFlavorMapperPtr_t pDataFlavorMapper,
+ NSPasteboard* pasteboard);
+
+ virtual ~OSXTransferable();
+
+ //------------------------------------------------------------------------
+ // XTransferable
+ //------------------------------------------------------------------------
+
+ virtual ::com::sun::star::uno::Any SAL_CALL getTransferData( const ::com::sun::star::datatransfer::DataFlavor& aFlavor )
+ throw( ::com::sun::star::datatransfer::UnsupportedFlavorException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException );
+
+ virtual ::com::sun::star::uno::Sequence< ::com::sun::star::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors( )
+ throw( ::com::sun::star::uno::RuntimeException );
+
+ virtual sal_Bool SAL_CALL isDataFlavorSupported( const ::com::sun::star::datatransfer::DataFlavor& aFlavor )
+ throw( ::com::sun::star::uno::RuntimeException );
+
+ //------------------------------------------------------------------------
+ // Helper functions not part of the XTransferable interface
+ //------------------------------------------------------------------------
+
+ void initClipboardItemList();
+
+ //com::sun::star::uno::Any getClipboardItemData(ClipboardItemPtr_t clipboardItem);
+
+ bool isUnicodeText(const com::sun::star::datatransfer::DataFlavor& flavor);
+
+ bool compareDataFlavors( const com::sun::star::datatransfer::DataFlavor& lhs,
+ const com::sun::star::datatransfer::DataFlavor& rhs );
+
+ bool cmpAllContentTypeParameter( const com::sun::star::uno::Reference< com::sun::star::datatransfer::XMimeContentType > xLhs,
+ const com::sun::star::uno::Reference< com::sun::star::datatransfer::XMimeContentType > xRhs ) const;
+
+private:
+ com::sun::star::uno::Sequence< com::sun::star::datatransfer::DataFlavor > mFlavorList;
+ ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XMimeContentTypeFactory> mrXMimeCntFactory;
+ DataFlavorMapperPtr_t mDataFlavorMapper;
+ NSPasteboard* mPasteboard;
+};
+
+#endif
diff --git a/vcl/aqua/source/dtrans/PictToBmpFlt.cxx b/vcl/aqua/source/dtrans/PictToBmpFlt.cxx
new file mode 100644
index 000000000000..1410fc2bd66d
--- /dev/null
+++ b/vcl/aqua/source/dtrans/PictToBmpFlt.cxx
@@ -0,0 +1,201 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: OSXTransferable.hxx,v $
+ * $Revision: 1.4 $
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+/* This is a work-around to prevent 'deprecated' warning for 'KillPicture' API
+ Hopefully we can get rid of this whole code again when the OOo PICT filter
+ are good enough to be used see #i78953 thus this hack would vanish to again.
+ */
+#include <premac.h>
+#include <AvailabilityMacros.h>
+#undef DEPRECATED_ATTRIBUTE
+#define DEPRECATED_ATTRIBUTE
+
+#include <Carbon/Carbon.h>
+#include <QuickTime/QuickTime.h>
+#include <postmac.h>
+
+#include "PictToBmpFlt.hxx"
+
+bool PICTtoBMP(com::sun::star::uno::Sequence<sal_Int8>& aPict,
+ com::sun::star::uno::Sequence<sal_Int8>& aBmp)
+{
+
+ bool result = false;
+
+ ComponentInstance bmpExporter;
+ if (OpenADefaultComponent(GraphicsExporterComponentType,
+ kQTFileTypeBMP,
+ &bmpExporter) != noErr)
+ {
+ return result;
+ }
+
+ Handle hPict;
+ if (PtrToHand(aPict.getArray(), &hPict, aPict.getLength()) != noErr)
+ {
+ return result;
+ }
+
+ Handle hBmp;
+ if ((GraphicsExportSetInputPicture(bmpExporter, (PicHandle)hPict) != noErr) ||
+ ((hBmp = NewHandleClear(0)) == NULL))
+ {
+ CloseComponent(bmpExporter);
+ DisposeHandle(hPict);
+ return result;
+ }
+
+ if ((GraphicsExportSetOutputHandle(bmpExporter, hBmp) == noErr) &&
+ (GraphicsExportDoExport(bmpExporter, NULL) == noErr))
+ {
+ size_t sz = GetHandleSize(hBmp);
+ aBmp.realloc(sz);
+
+ HLock(hBmp);
+ rtl_copyMemory(aBmp.getArray(), ((sal_Int8*)*hBmp), sz);
+ HUnlock(hBmp);
+
+ result = true;
+ }
+
+ DisposeHandle(hPict);
+ DisposeHandle(hBmp);
+ CloseComponent(bmpExporter);
+
+ return result;
+}
+
+bool BMPtoPICT(com::sun::star::uno::Sequence<sal_Int8>& aBmp,
+ com::sun::star::uno::Sequence<sal_Int8>& aPict)
+{
+ bool result = false;
+
+ Handle hBmp;
+ ComponentInstance pictExporter;
+ if ((PtrToHand(aBmp.getArray(), &hBmp, aBmp.getLength()) != noErr))
+ {
+ return result;
+ }
+
+ if (OpenADefaultComponent(GraphicsImporterComponentType,
+ kQTFileTypeBMP,
+ &pictExporter) != noErr)
+ {
+ DisposeHandle(hBmp);
+ return result;
+ }
+
+ if (GraphicsImportSetDataHandle(pictExporter, hBmp) != noErr)
+ {
+ DisposeHandle(hBmp);
+ CloseComponent(pictExporter);
+ return result;
+ }
+
+ PicHandle hPict;
+ if (GraphicsImportGetAsPicture(pictExporter, &hPict) == noErr)
+ {
+ size_t sz = GetHandleSize((Handle)hPict);
+ aPict.realloc(sz);
+
+ HLock((Handle)hPict);
+ rtl_copyMemory(aPict.getArray(), ((sal_Int8*)*hPict), sz);
+ HUnlock((Handle)hPict);
+
+ // Release the data associated with the picture
+ // Note: This function is deprecated in Mac OS X
+ // 10.4.
+ KillPicture(hPict);
+
+ result = true;
+ }
+
+ DisposeHandle(hBmp);
+ CloseComponent(pictExporter);
+
+ return result;
+}
+
+bool ImageToBMP( com::sun::star::uno::Sequence<sal_Int8>& aPict,
+ com::sun::star::uno::Sequence<sal_Int8>& aBmp,
+ NSBitmapImageFileType eInFormat)
+{
+ if( eInFormat == PICTImageFileType )
+ return PICTtoBMP( aPict, aBmp );
+
+ bool bResult = false;
+
+ NSData* pData = [NSData dataWithBytesNoCopy: (void*)aPict.getConstArray() length: aPict.getLength() freeWhenDone: 0];
+ if( pData )
+ {
+ NSBitmapImageRep* pRep = [NSBitmapImageRep imageRepWithData: pData];
+ if( pRep )
+ {
+ NSData* pOut = [pRep representationUsingType: NSBMPFileType properties: nil];
+ if( pOut )
+ {
+ aBmp.realloc( [pOut length] );
+ [pOut getBytes: aBmp.getArray() length: aBmp.getLength()];
+ bResult = (aBmp.getLength() != 0);
+ }
+ }
+ }
+
+ return bResult;
+}
+
+bool BMPToImage( com::sun::star::uno::Sequence<sal_Int8>& aBmp,
+ com::sun::star::uno::Sequence<sal_Int8>& aPict,
+ NSBitmapImageFileType eOutFormat
+ )
+{
+ if( eOutFormat == PICTImageFileType )
+ return BMPtoPICT( aBmp, aPict );
+
+ bool bResult = false;
+
+ NSData* pData = [NSData dataWithBytesNoCopy: const_cast<sal_Int8*>(aBmp.getConstArray()) length: aBmp.getLength() freeWhenDone: 0];
+ if( pData )
+ {
+ NSBitmapImageRep* pRep = [NSBitmapImageRep imageRepWithData: pData];
+ if( pRep )
+ {
+ NSData* pOut = [pRep representationUsingType: eOutFormat properties: nil];
+ if( pOut )
+ {
+ aPict.realloc( [pOut length] );
+ [pOut getBytes: aPict.getArray() length: aPict.getLength()];
+ bResult = (aPict.getLength() != 0);
+ }
+ }
+ }
+
+ return bResult;
+}
diff --git a/vcl/aqua/source/dtrans/PictToBmpFlt.hxx b/vcl/aqua/source/dtrans/PictToBmpFlt.hxx
new file mode 100644
index 000000000000..12a73452ad7b
--- /dev/null
+++ b/vcl/aqua/source/dtrans/PictToBmpFlt.hxx
@@ -0,0 +1,37 @@
+#ifndef INCLUDED_PICTTOBMPFLT_HXX
+#define INCLUDED_PICTTOBMPFLT_HXX
+
+#include <com/sun/star/uno/Sequence.hxx>
+
+#include <premac.h>
+#include <Cocoa/Cocoa.h>
+#include <postmac.h>
+
+/* Transform PICT into the a Window BMP.
+
+ Returns true if the conversion was successful false
+ otherwise.
+ */
+bool PICTtoBMP(com::sun::star::uno::Sequence<sal_Int8>& aPict,
+ com::sun::star::uno::Sequence<sal_Int8>& aBmp);
+
+/* Transform a Windows BMP to a PICT.
+
+ Returns true if the conversion was successful false
+ otherwise.
+ */
+bool BMPtoPICT(com::sun::star::uno::Sequence<sal_Int8>& aBmp,
+ com::sun::star::uno::Sequence<sal_Int8>& aPict);
+
+#define PICTImageFileType ((NSBitmapImageFileType)~0)
+
+bool ImageToBMP( com::sun::star::uno::Sequence<sal_Int8>& aPict,
+ com::sun::star::uno::Sequence<sal_Int8>& aBmp,
+ NSBitmapImageFileType eInFormat);
+
+bool BMPToImage( com::sun::star::uno::Sequence<sal_Int8>& aBmp,
+ com::sun::star::uno::Sequence<sal_Int8>& aPict,
+ NSBitmapImageFileType eOutFormat
+ );
+
+#endif
diff --git a/vcl/aqua/source/dtrans/aqua_clipboard.cxx b/vcl/aqua/source/dtrans/aqua_clipboard.cxx
new file mode 100644
index 000000000000..52fb13e1e11f
--- /dev/null
+++ b/vcl/aqua/source/dtrans/aqua_clipboard.cxx
@@ -0,0 +1,387 @@
+/*************************************************************************
+ *
+ * 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 "aqua_clipboard.hxx"
+
+#include "DataFlavorMapping.hxx"
+#include "OSXTransferable.hxx"
+
+#include "vcl/unohelp.hxx"
+
+#include "comphelper/makesequence.hxx"
+
+#include <boost/assert.hpp>
+
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::datatransfer::clipboard;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::uno;
+using namespace cppu;
+using namespace osl;
+using namespace rtl;
+using namespace std;
+using namespace comphelper;
+
+
+@implementation EventListener;
+
+-(EventListener*)initWithAquaClipboard: (AquaClipboard*) pcb
+{
+ self = [super init];
+
+ if (self)
+ pAquaClipboard = pcb;
+
+ return self;
+}
+
+-(void)pasteboard:(NSPasteboard*)sender provideDataForType:(NSString*)type
+{
+ if( pAquaClipboard )
+ pAquaClipboard->provideDataForType(sender, type);
+}
+
+-(void)applicationDidBecomeActive:(NSNotification*)aNotification
+{
+ if( pAquaClipboard )
+ pAquaClipboard->applicationDidBecomeActive(aNotification);
+}
+
+-(void)disposing
+{
+ pAquaClipboard = NULL;
+}
+
+@end
+
+
+OUString clipboard_getImplementationName()
+{
+ return OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.clipboard.AquaClipboard"));
+}
+
+Sequence<OUString> clipboard_getSupportedServiceNames()
+{
+ return makeSequence(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.clipboard.SystemClipboard")));
+}
+
+
+AquaClipboard::AquaClipboard(NSPasteboard* pasteboard, bool bUseSystemPasteboard) :
+ WeakComponentImplHelper4<XClipboardEx, XClipboardNotifier, XFlushableClipboard, XServiceInfo>(m_aMutex),
+ mIsSystemPasteboard(bUseSystemPasteboard)
+{
+ Reference<XMultiServiceFactory> mrServiceMgr = vcl::unohelper::GetMultiServiceFactory();
+
+ mrXMimeCntFactory = Reference<XMimeContentTypeFactory>(mrServiceMgr->createInstance(
+ OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.MimeContentTypeFactory"))), UNO_QUERY);
+
+ if (!mrXMimeCntFactory.is())
+ {
+ throw RuntimeException(OUString(
+ RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Cannot create com.sun.star.datatransfer.MimeContentTypeFactory")),
+ static_cast<XClipboardEx*>(this));
+ }
+
+ mpDataFlavorMapper = DataFlavorMapperPtr_t(new DataFlavorMapper());
+
+ if (pasteboard != NULL)
+ {
+ mPasteboard = pasteboard;
+ mIsSystemPasteboard = false;
+ }
+ else
+ {
+ mPasteboard = bUseSystemPasteboard ? [NSPasteboard generalPasteboard] :
+ [NSPasteboard pasteboardWithName: NSDragPboard];
+
+ if (mPasteboard == nil)
+ {
+ throw RuntimeException(OUString(
+ RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Cannot create Cocoa pasteboard")),
+ static_cast<XClipboardEx*>(this));
+ }
+ }
+
+ [mPasteboard retain];
+
+ mEventListener = [[EventListener alloc] initWithAquaClipboard: this];
+
+ if (mEventListener == nil)
+ {
+ [mPasteboard release];
+
+ throw RuntimeException(
+ OUString(RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Cannot create pasteboard change listener")),
+ static_cast<XClipboardEx*>(this));
+ }
+
+ if (mIsSystemPasteboard)
+ {
+ NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter];
+
+ [notificationCenter addObserver: mEventListener
+ selector: @selector(applicationDidBecomeActive:)
+ name: @"NSApplicationDidBecomeActiveNotification"
+ object: [NSApplication sharedApplication]];
+ }
+
+ mPasteboardChangeCount = [mPasteboard changeCount];
+}
+
+
+AquaClipboard::~AquaClipboard()
+{
+ if (mIsSystemPasteboard)
+ {
+ [[NSNotificationCenter defaultCenter] removeObserver: mEventListener];
+ }
+
+ [mEventListener disposing];
+ [mEventListener release];
+ [mPasteboard release];
+}
+
+
+Reference<XTransferable> SAL_CALL AquaClipboard::getContents() throw(RuntimeException)
+{
+ MutexGuard aGuard(m_aMutex);
+
+ // Shortcut: If we are clipboard owner already we don't need
+ // to drag the data through the system clipboard
+ if (mXClipboardContent.is())
+ {
+ return mXClipboardContent;
+ }
+
+ return Reference<XTransferable>(new OSXTransferable(mrXMimeCntFactory,
+ mpDataFlavorMapper,
+ mPasteboard));
+}
+
+
+void SAL_CALL AquaClipboard::setContents(const Reference<XTransferable>& xTransferable,
+ const Reference<XClipboardOwner>& xClipboardOwner)
+ throw( RuntimeException )
+{
+ NSArray* types = xTransferable.is() ?
+ mpDataFlavorMapper->flavorSequenceToTypesArray(xTransferable->getTransferDataFlavors()) :
+ [NSArray array];
+
+ ClearableMutexGuard aGuard(m_aMutex);
+
+ Reference<XClipboardOwner> oldOwner(mXClipboardOwner);
+ mXClipboardOwner = xClipboardOwner;
+
+ Reference<XTransferable> oldContent(mXClipboardContent);
+ mXClipboardContent = xTransferable;
+
+ mPasteboardChangeCount = [mPasteboard declareTypes: types owner: mEventListener];
+
+ aGuard.clear();
+
+ // if we are already the owner of the clipboard
+ // then fire lost ownership event
+ if (oldOwner.is())
+ {
+ fireLostClipboardOwnershipEvent(oldOwner, oldContent);
+ }
+
+ fireClipboardChangedEvent();
+}
+
+
+OUString SAL_CALL AquaClipboard::getName() throw( RuntimeException )
+{
+ return OUString();
+}
+
+
+sal_Int8 SAL_CALL AquaClipboard::getRenderingCapabilities() throw( RuntimeException )
+{
+ return 0;
+}
+
+
+void SAL_CALL AquaClipboard::addClipboardListener(const Reference< XClipboardListener >& listener)
+ throw( RuntimeException )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ if (!listener.is())
+ throw IllegalArgumentException(OUString(RTL_CONSTASCII_USTRINGPARAM("empty reference")),
+ static_cast<XClipboardEx*>(this), 1);
+
+ mClipboardListeners.push_back(listener);
+}
+
+
+void SAL_CALL AquaClipboard::removeClipboardListener(const Reference< XClipboardListener >& listener)
+ throw( RuntimeException )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ if (!listener.is())
+ throw IllegalArgumentException(OUString(RTL_CONSTASCII_USTRINGPARAM("empty reference")),
+ static_cast<XClipboardEx*>(this), 1);
+
+ mClipboardListeners.remove(listener);
+}
+
+
+void AquaClipboard::applicationDidBecomeActive(NSNotification* aNotification)
+{
+ ClearableMutexGuard aGuard(m_aMutex);
+
+ int currentPboardChgCount = [mPasteboard changeCount];
+
+ if (currentPboardChgCount != mPasteboardChangeCount)
+ {
+ mPasteboardChangeCount = currentPboardChgCount;
+
+ // Clear clipboard content and owner and send lostOwnership
+ // notification to the old clipboard owner as well as
+ // ClipboardChanged notification to any clipboard listener
+ Reference<XClipboardOwner> oldOwner(mXClipboardOwner);
+ mXClipboardOwner = Reference<XClipboardOwner>();
+
+ Reference<XTransferable> oldContent(mXClipboardContent);
+ mXClipboardContent = Reference<XTransferable>();
+
+ aGuard.clear();
+
+ if (oldOwner.is())
+ {
+ fireLostClipboardOwnershipEvent(oldOwner, oldContent);
+ }
+
+ fireClipboardChangedEvent();
+ }
+}
+
+
+void AquaClipboard::fireClipboardChangedEvent()
+{
+ ClearableMutexGuard aGuard(m_aMutex);
+
+ list<Reference< XClipboardListener > > listeners(mClipboardListeners);
+ ClipboardEvent aEvent;
+
+ if (listeners.begin() != listeners.end())
+ {
+ aEvent = ClipboardEvent(static_cast<OWeakObject*>(this), getContents());
+ }
+
+ aGuard.clear();
+
+ while (listeners.begin() != listeners.end())
+ {
+ if (listeners.front().is())
+ {
+ try { listeners.front()->changedContents(aEvent); }
+ catch (RuntimeException&) { }
+ }
+ listeners.pop_front();
+ }
+}
+
+
+void AquaClipboard::fireLostClipboardOwnershipEvent(Reference<XClipboardOwner> oldOwner, Reference<XTransferable> oldContent)
+{
+ BOOST_ASSERT(oldOwner.is());
+
+ try { oldOwner->lostOwnership(static_cast<XClipboardEx*>(this), oldContent); }
+ catch(RuntimeException&) { }
+}
+
+
+void AquaClipboard::provideDataForType(NSPasteboard* sender, NSString* type)
+{
+ DataProviderPtr_t dp = mpDataFlavorMapper->getDataProvider(type, mXClipboardContent);
+ NSData* pBoardData = NULL;
+
+ if (dp.get() != NULL)
+ {
+ pBoardData = (NSData*)dp->getSystemData();
+ [sender setData: pBoardData forType: type];
+ }
+}
+
+
+//------------------------------------------------
+// XFlushableClipboard
+//------------------------------------------------
+
+void SAL_CALL AquaClipboard::flushClipboard()
+ throw(RuntimeException)
+{
+ if (mXClipboardContent.is())
+ {
+ Sequence<DataFlavor> flavorList = mXClipboardContent->getTransferDataFlavors();
+ sal_uInt32 nFlavors = flavorList.getLength();
+
+ for (sal_uInt32 i = 0; i < nFlavors; i++)
+ {
+ NSString* sysType = mpDataFlavorMapper->openOfficeToSystemFlavor(flavorList[i]);
+
+ if (sysType != NULL)
+ {
+ provideDataForType(mPasteboard, sysType);
+ }
+ }
+ }
+}
+
+
+NSPasteboard* AquaClipboard::getPasteboard() const
+{
+ return mPasteboard;
+}
+
+
+//-------------------------------------------------
+// XServiceInfo
+//-------------------------------------------------
+
+OUString SAL_CALL AquaClipboard::getImplementationName() throw( RuntimeException )
+{
+ return clipboard_getImplementationName();
+}
+
+
+sal_Bool SAL_CALL AquaClipboard::supportsService( const OUString& ServiceName ) throw( RuntimeException )
+{
+ return sal_False;
+}
+
+
+Sequence< OUString > SAL_CALL AquaClipboard::getSupportedServiceNames() throw( RuntimeException )
+{
+ return clipboard_getSupportedServiceNames();
+}
+
diff --git a/vcl/aqua/source/dtrans/aqua_clipboard.hxx b/vcl/aqua/source/dtrans/aqua_clipboard.hxx
new file mode 100644
index 000000000000..8f45f50717f3
--- /dev/null
+++ b/vcl/aqua/source/dtrans/aqua_clipboard.hxx
@@ -0,0 +1,181 @@
+/*************************************************************************
+ *
+ * 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 _AQUA_CLIPBOARD_HXX_
+#define _AQUA_CLIPBOARD_HXX_
+
+#include "DataFlavorMapping.hxx"
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+#include <cppuhelper/compbase4.hxx>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboardEx.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboardOwner.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboardListener.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboardNotifier.hpp>
+#include <com/sun/star/datatransfer/XMimeContentTypeFactory.hpp>
+#include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/basemutex.hxx>
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+
+#include <boost/utility.hpp>
+#include <list>
+
+#include <premac.h>
+#import <Cocoa/Cocoa.h>
+#include <postmac.h>
+
+class AquaClipboard;
+
+@interface EventListener : NSObject
+{
+ AquaClipboard* pAquaClipboard;
+}
+
+// Init the pasteboard change listener with a reference to the OfficeClipboard
+// instance
+- (EventListener*)initWithAquaClipboard: (AquaClipboard*) pcb;
+
+// Promiss resolver function
+- (void)pasteboard:(NSPasteboard*)sender provideDataForType:(NSString *)type;
+
+-(void)applicationDidBecomeActive:(NSNotification*)aNotification;
+
+-(void)disposing;
+@end
+
+
+class AquaClipboard : public ::cppu::BaseMutex,
+ public ::cppu::WeakComponentImplHelper4< com::sun::star::datatransfer::clipboard::XClipboardEx,
+ com::sun::star::datatransfer::clipboard::XClipboardNotifier,
+ com::sun::star::datatransfer::clipboard::XFlushableClipboard,
+ com::sun::star::lang::XServiceInfo >,
+ private ::boost::noncopyable
+{
+public:
+ /* Create a clipboard instance.
+
+ @param pasteboard
+ If not equal NULL the instance will be instantiated with the provided
+ pasteboard reference and 'bUseSystemClipboard' will be ignored
+
+ @param bUseSystemClipboard
+ If 'pasteboard' is NULL 'bUseSystemClipboard' determines whether the
+ system clipboard will be created (bUseSystemClipboard == true) or if
+ the DragPasteboard if bUseSystemClipboard == false
+ */
+ AquaClipboard(NSPasteboard* pasteboard = NULL,
+ bool bUseSystemClipboard = true);
+
+ ~AquaClipboard();
+
+ //------------------------------------------------
+ // XClipboard
+ //------------------------------------------------
+
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > SAL_CALL getContents()
+ throw( ::com::sun::star::uno::RuntimeException );
+
+ virtual void SAL_CALL setContents( const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >& xTransferable,
+ const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboardOwner >& xClipboardOwner )
+ throw( ::com::sun::star::uno::RuntimeException );
+
+ virtual ::rtl::OUString SAL_CALL getName()
+ throw( ::com::sun::star::uno::RuntimeException );
+
+ //------------------------------------------------
+ // XClipboardEx
+ //------------------------------------------------
+
+ virtual sal_Int8 SAL_CALL getRenderingCapabilities()
+ throw( ::com::sun::star::uno::RuntimeException );
+
+ //------------------------------------------------
+ // XClipboardNotifier
+ //------------------------------------------------
+
+ virtual void SAL_CALL addClipboardListener( const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboardListener >& listener )
+ throw( ::com::sun::star::uno::RuntimeException );
+
+ virtual void SAL_CALL removeClipboardListener( const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboardListener >& listener )
+ throw( ::com::sun::star::uno::RuntimeException );
+
+ //------------------------------------------------
+ // XFlushableClipboard
+ //------------------------------------------------
+
+ virtual void SAL_CALL flushClipboard( ) throw( com::sun::star::uno::RuntimeException );
+
+ //------------------------------------------------
+ // XServiceInfo
+ //------------------------------------------------
+
+ virtual ::rtl::OUString SAL_CALL getImplementationName()
+ throw(::com::sun::star::uno::RuntimeException);
+
+ virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName )
+ throw(::com::sun::star::uno::RuntimeException);
+
+ virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames()
+ throw(::com::sun::star::uno::RuntimeException);
+
+ /* Get a reference to the used pastboard.
+ */
+ NSPasteboard* getPasteboard() const;
+
+ /* Notify the current clipboard owner that he is no longer the clipboard owner.
+ */
+ void fireLostClipboardOwnershipEvent(::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboardOwner> oldOwner,
+ ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > oldContent);
+
+ void pasteboardChangedOwner();
+
+ void provideDataForType(NSPasteboard* sender, NSString* type);
+
+ void applicationDidBecomeActive(NSNotification* aNotification);
+
+private:
+
+ /* Notify all registered XClipboardListener that the clipboard content
+ has changed.
+ */
+ void fireClipboardChangedEvent();
+
+private:
+ ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XMimeContentTypeFactory > mrXMimeCntFactory;
+ ::std::list< ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboardListener > > mClipboardListeners;
+ ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > mXClipboardContent;
+ com::sun::star::uno::Reference< com::sun::star::datatransfer::clipboard::XClipboardOwner > mXClipboardOwner;
+ DataFlavorMapperPtr_t mpDataFlavorMapper;
+ bool mIsSystemPasteboard;
+ NSPasteboard* mPasteboard;
+ int mPasteboardChangeCount;
+ EventListener* mEventListener;
+};
+
+#endif
diff --git a/vcl/aqua/source/dtrans/aqua_service.cxx b/vcl/aqua/source/dtrans/aqua_service.cxx
new file mode 100644
index 000000000000..571bea2e554f
--- /dev/null
+++ b/vcl/aqua/source/dtrans/aqua_service.cxx
@@ -0,0 +1,108 @@
+/*************************************************************************
+ *
+ * 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 "aqua_clipboard.hxx"
+#include <cppuhelper/factory.hxx>
+#include <com/sun/star/container/XSet.hpp>
+#include <osl/diagnose.h>
+
+using namespace rtl;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::registry;
+using namespace cppu;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::datatransfer::clipboard;
+using namespace aqua;
+
+namespace aqua {
+
+Reference< XInterface > SAL_CALL createInstance( const Reference< XMultiServiceFactory >& rServiceManager )
+{
+ return Reference< XInterface >( static_cast< XClipboard* >( new AquaClipboard(rServiceManager) ) );
+}
+
+} // namespace aqua
+
+extern "C"
+{
+
+void SAL_CALL component_getImplementationEnvironment(
+ const sal_Char ** ppEnvTypeName, uno_Environment ** ppEnv )
+{
+ *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
+}
+
+sal_Bool SAL_CALL component_writeInfo( void* pServiceManager, void* pRegistryKey )
+{
+ sal_Bool bRetVal = sal_False;
+
+ if ( pRegistryKey )
+ {
+ try
+ {
+ Reference< XRegistryKey > pXNewKey( static_cast< XRegistryKey* >( pRegistryKey ) );
+ pXNewKey->createKey( OUString( RTL_CONSTASCII_USTRINGPARAM( AQUA_CLIPBOARD_REGKEY_NAME ) ) );
+ bRetVal = sal_True;
+ }
+ catch( InvalidRegistryException& )
+ {
+ OSL_ENSURE(sal_False, "InvalidRegistryException caught");
+ bRetVal = sal_False;
+ }
+ }
+
+ return bRetVal;
+}
+
+void* SAL_CALL component_getFactory( const sal_Char* pImplName, uno_Interface* pSrvManager, uno_Interface* pRegistryKey )
+{
+ void* pRet = 0;
+
+ if ( pSrvManager && ( 0 == rtl_str_compare( pImplName, AQUA_CLIPBOARD_IMPL_NAME ) ) )
+ {
+ Sequence< OUString > aSNS( 1 );
+ aSNS.getArray()[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( AQUA_CLIPBOARD_SERVICE_NAME ) );
+
+ //OUString( RTL_CONSTASCII_USTRINGPARAM( FPS_IMPL_NAME ) )
+ Reference< XSingleServiceFactory > xFactory ( createOneInstanceFactory(
+ reinterpret_cast< XMultiServiceFactory* > ( pSrvManager ),
+ OUString::createFromAscii( pImplName ),
+ createInstance,
+ aSNS ) );
+ if ( xFactory.is() )
+ {
+ xFactory->acquire();
+ pRet = xFactory.get();
+ }
+ }
+
+ return pRet;
+}
+
+} // extern "C"
diff --git a/vcl/aqua/source/dtrans/makefile.mk b/vcl/aqua/source/dtrans/makefile.mk
new file mode 100644
index 000000000000..369799c9a260
--- /dev/null
+++ b/vcl/aqua/source/dtrans/makefile.mk
@@ -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.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+
+PRJNAME=vcl
+TARGET=dtransaqua
+ENABLE_EXCEPTIONS=TRUE
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+
+# ------------------------------------------------------------------
+
+.IF "$(OS)"!="MACOSX"
+dummy:
+ @echo "Nothing to build for this platform"
+.ELSE # "$(OS)"!="MACOSX"
+.IF "$(GUIBASE)"!="aqua"
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+.ELSE
+
+CFLAGSCXX+=-fconstant-cfstrings -x objective-c++ -fobjc-exceptions
+
+SLOFILES= \
+ $(SLO)$/aqua_clipboard.obj \
+ $(SLO)$/DataFlavorMapping.obj \
+ $(SLO)$/OSXTransferable.obj \
+ $(SLO)$/HtmlFmtFlt.obj \
+ $(SLO)$/PictToBmpFlt.obj \
+ $(SLO)$/DropTarget.obj \
+ $(SLO)$/DragSource.obj \
+ $(SLO)$/service_entry.obj \
+ $(SLO)$/DragSourceContext.obj \
+ $(SLO)$/DragActionConversion.obj
+
+# --- Targets ------------------------------------------------------
+.INCLUDE : target.mk
+
+.ENDIF # "$(GUIBASE)"!="aqua"
+.ENDIF # "$(OS)"!="MACOSX"
+
diff --git a/vcl/aqua/source/dtrans/service_entry.cxx b/vcl/aqua/source/dtrans/service_entry.cxx
new file mode 100644
index 000000000000..16308951bcfe
--- /dev/null
+++ b/vcl/aqua/source/dtrans/service_entry.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 "saldata.hxx"
+#include "salinst.h"
+#include "DragSource.hxx"
+#include "DropTarget.hxx"
+#include "aqua_clipboard.hxx"
+#include "osl/diagnose.h"
+
+using namespace ::osl;
+using namespace ::rtl;
+using namespace ::com::sun::star::uno;
+using namespace ::cppu;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::datatransfer::clipboard;
+
+
+Reference< XInterface > AquaSalInstance::CreateClipboard( const Sequence< Any >& i_rArguments )
+{
+ SalData* pSalData = GetSalData();
+ if( ! pSalData->mxClipboard.is() )
+ pSalData->mxClipboard = Reference<XInterface>(static_cast< XClipboard* >(new AquaClipboard()), UNO_QUERY);
+ return pSalData->mxClipboard;
+}
+
+
+Reference<XInterface> AquaSalInstance::CreateDragSource()
+{
+ return Reference<XInterface>(static_cast< XInitialization* >(new DragSource()), UNO_QUERY);
+}
+
+Reference<XInterface> AquaSalInstance::CreateDropTarget()
+{
+ return Reference<XInterface>(static_cast< XInitialization* >(new DropTarget()), UNO_QUERY);
+}
+
diff --git a/vcl/aqua/source/dtrans/test_aquacb.cxx b/vcl/aqua/source/dtrans/test_aquacb.cxx
new file mode 100644
index 000000000000..85c87c6b9ba9
--- /dev/null
+++ b/vcl/aqua/source/dtrans/test_aquacb.cxx
@@ -0,0 +1,208 @@
+/*************************************************************************
+ *
+ * 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 "aqua_clipboard.hxx"
+#include <cppuhelper/servicefactory.hxx>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboardOwner.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboardNotifier.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboardEx.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+
+#ifndef _CPPUHELPER_IMPLBASE1_HXX_
+#include <cppuhelper/implbase2.hxx>
+#endif
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+#include <osl/diagnose.h>
+
+#include <stdio.h>
+
+using namespace ::rtl;
+using namespace ::std;
+using namespace ::cppu;
+using namespace ::com::sun::star::datatransfer;
+using namespace ::com::sun::star::datatransfer::clipboard;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::lang;
+
+Reference< XTransferable > rXTransfRead;
+
+class TestTransferable : public WeakImplHelper2< XClipboardOwner, XTransferable >
+{
+public:
+ TestTransferable();
+ virtual Any SAL_CALL getTransferData( const DataFlavor& aFlavor ) throw(UnsupportedFlavorException, IOException, RuntimeException);
+ virtual Sequence< DataFlavor > SAL_CALL getTransferDataFlavors() throw(RuntimeException);
+ virtual sal_Bool SAL_CALL isDataFlavorSupported( const DataFlavor& aFlavor ) throw(RuntimeException);
+ virtual void SAL_CALL lostOwnership( const Reference< XClipboard >& xClipboard, const Reference< XTransferable >& xTrans ) throw(RuntimeException);
+
+private:
+ Sequence< DataFlavor > m_seqDFlv;
+ OUString m_Data;
+};
+
+TestTransferable::TestTransferable() :
+ m_seqDFlv( 1 ),
+ m_Data( RTL_CONSTASCII_USTRINGPARAM( "This is a test string" ) )
+{
+ DataFlavor df;
+
+ df.MimeType = OUString::createFromAscii( "text/html" );
+ df.DataType = getCppuType( ( Sequence< sal_Int8 >* )0 );
+
+ m_seqDFlv[0] = df;
+}
+
+Any SAL_CALL TestTransferable::getTransferData( const DataFlavor& aFlavor )
+ throw(UnsupportedFlavorException, IOException, RuntimeException)
+{
+ Any anyData;
+
+ if ( aFlavor.MimeType == m_seqDFlv[0].MimeType )
+ {
+ OString aStr( m_Data.getStr(), m_Data.getLength(), 1252 );
+ Sequence< sal_Int8 > sOfChars( aStr.getLength() );
+ sal_Int32 lenStr = aStr.getLength();
+
+ for ( sal_Int32 i = 0; i < lenStr; ++i )
+ sOfChars[i] = aStr[i];
+
+ anyData = makeAny( sOfChars );
+ }
+
+ return anyData;
+}
+
+Sequence< DataFlavor > SAL_CALL TestTransferable::getTransferDataFlavors()
+ throw(RuntimeException)
+{
+ return m_seqDFlv;
+}
+
+sal_Bool SAL_CALL TestTransferable::isDataFlavorSupported( const DataFlavor& aFlavor )
+ throw(RuntimeException)
+{
+ sal_Int32 nLength = m_seqDFlv.getLength();
+ sal_Bool bRet = sal_False;
+
+ for ( sal_Int32 i = 0; i < nLength; ++i )
+ {
+ if ( m_seqDFlv[i].MimeType == aFlavor.MimeType )
+ {
+ bRet = sal_True;
+ break;
+ }
+ }
+
+ return bRet;
+}
+
+void SAL_CALL TestTransferable::lostOwnership( const Reference< XClipboard >& xClipboard, const Reference< XTransferable >& xTrans )
+ throw(RuntimeException)
+{
+}
+
+int SAL_CALL main( int argc, char** argv )
+{
+ if(argc != 2)
+ {
+ fprintf( stderr, "usage: %s <my rdb file>\n", argv[0] );
+ return 1;
+ }
+
+ //-------------------------------------------------
+ // get the global service-manager
+ //-------------------------------------------------
+ OUString rdbName = OUString::createFromAscii( argv[1] );
+ Reference< XMultiServiceFactory > g_xFactory( createRegistryServiceFactory( rdbName ) );
+
+ // Print a message if an error occured.
+ if ( !g_xFactory.is() )
+ {
+ OSL_ENSURE(sal_False, "Can't create RegistryServiceFactory");
+ return(-1);
+ }
+
+ //-------------------------------------------------
+ // try to get an Interface to a XFilePicker Service
+ //-------------------------------------------------
+
+ Reference< XTransferable > rXTransf( static_cast< XTransferable* >( new TestTransferable ) );
+
+ Reference< XClipboard > xClipboard( g_xFactory->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( AQUA_CLIPBOARD_SERVICE_NAME ) ) ), UNO_QUERY );
+ if ( !xClipboard.is() )
+ {
+ OSL_ENSURE( sal_False, "Error creating FolderPicker Service" );
+ return(-1);
+ }
+
+ Reference< XTypeProvider > rXTypProv( xClipboard, UNO_QUERY );
+
+ if ( rXTypProv.is() )
+ {
+ Sequence< Type > seqType = rXTypProv->getTypes();
+ sal_Int32 nLen = seqType.getLength();
+ for ( sal_Int32 i = 0; i < nLen; i++ )
+ {
+ Type nxtType = seqType[i];
+ }
+
+ Sequence< sal_Int8 > seqInt8 = rXTypProv->getImplementationId();
+ }
+
+ xClipboard->setContents( rXTransf, Reference< XClipboardOwner >( rXTransf, UNO_QUERY ) );
+
+ rXTransfRead = xClipboard->getContents();
+
+ // destroy the transferable explicitly
+ rXTransfRead = Reference< XTransferable>();
+
+ // destroy the clipboard
+ xClipboard = Reference< XClipboard >();
+
+ //--------------------------------------------------
+ // shutdown the service manager
+ //--------------------------------------------------
+
+ // Cast factory to XComponent
+ Reference< XComponent > xComponent( g_xFactory, UNO_QUERY );
+
+ if ( !xComponent.is() )
+ OSL_ENSURE(sal_False, "Error shuting down");
+
+ // Dispose and clear factory
+ xComponent->dispose();
+ g_xFactory.clear();
+ g_xFactory = Reference< XMultiServiceFactory >();
+
+ return 0;
+}
diff --git a/vcl/aqua/source/gdi/aquaprintaccessoryview.mm b/vcl/aqua/source/gdi/aquaprintaccessoryview.mm
new file mode 100644
index 000000000000..d00fc9a6cd0e
--- /dev/null
+++ b/vcl/aqua/source/gdi/aquaprintaccessoryview.mm
@@ -0,0 +1,1241 @@
+/************************************************************************
+ *
+ * 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 "aquaprintview.h"
+#include "salinst.h"
+#include "vcl/print.hxx"
+#include "vcl/image.hxx"
+#include "vcl/virdev.hxx"
+#include "vcl/svdata.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/unohelp.hxx"
+
+#include "vcl/svids.hrc"
+
+#include "tools/resary.hxx"
+
+#include "com/sun/star/i18n/XBreakIterator.hpp"
+#include "com/sun/star/i18n/WordType.hpp"
+
+#include <map>
+
+using namespace vcl;
+using namespace com::sun::star;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::uno;
+
+/* Note: the accesory view as implemented here is already deprecated in Leopard. Unfortunately
+ as long as our baseline is Tiger we cannot gain the advantages over multiple accessory views
+ as well havs having accessory views AND a preview (as long as you are linked vs. 10.4 libraries
+ the preview insists on not being present. This is unfortunate.
+*/
+
+class ControllerProperties;
+
+@interface ControlTarget : NSObject
+{
+ ControllerProperties* mpController;
+}
+-(id)initWithControllerMap: (ControllerProperties*)pController;
+-(void)triggered:(id)pSender;
+-(void)triggeredNumeric:(id)pSender;
+-(void)triggeredPreview:(id)pSender;
+-(void)dealloc;
+@end
+
+
+class ControllerProperties
+{
+ vcl::PrinterController* mpController;
+ std::map< int, rtl::OUString > maTagToPropertyName;
+ std::map< int, sal_Int32 > maTagToValueInt;
+ std::map< NSView*, NSView* > maViewPairMap;
+ std::vector< NSObject* > maViews;
+ int mnNextTag;
+ sal_Int32 mnLastPageCount;
+ PrintAccessoryViewState* mpState;
+ NSPrintOperation* mpOp;
+ NSView* mpAccessoryView;
+ NSTabView* mpTabView;
+ NSBox* mpPreviewBox;
+ NSImageView* mpPreview;
+ NSTextField* mpPageEdit;
+ NSStepper* mpStepper;
+ NSTextView* mpPagesLabel;
+ ResStringArray maLocalizedStrings;
+
+ public:
+ ControllerProperties( vcl::PrinterController* i_pController,
+ NSPrintOperation* i_pOp,
+ NSView* i_pAccessoryView,
+ NSTabView* i_pTabView,
+ PrintAccessoryViewState* i_pState )
+ : mpController( i_pController ),
+ mnNextTag( 0 ),
+ mnLastPageCount( i_pController->getFilteredPageCount() ),
+ mpState( i_pState ),
+ mpOp( i_pOp ),
+ mpAccessoryView( i_pAccessoryView ),
+ mpTabView( i_pTabView ),
+ mpPreviewBox( nil ),
+ mpPreview( nil ),
+ mpPageEdit( nil ),
+ mpStepper( nil ),
+ mpPagesLabel( nil ),
+ maLocalizedStrings( VclResId( SV_PRINT_NATIVE_STRINGS ) )
+ {
+ mpState->bNeedRestart = false;
+ DBG_ASSERT( maLocalizedStrings.Count() >= 4, "resources not found !" );
+ }
+
+ rtl::OUString getMoreString()
+ {
+ return maLocalizedStrings.Count() >= 4
+ ? rtl::OUString( maLocalizedStrings.GetString( 3 ) )
+ : rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "More" ) );
+ }
+
+ void updatePrintJob()
+ {
+ // TODO: refresh page count etc from mpController
+
+ // page range may have changed depending on options
+ sal_Int32 nPages = mpController->getFilteredPageCount();
+ #if OSL_DEBUG_LEVEL > 1
+ if( nPages != mnLastPageCount )
+ fprintf( stderr, "trouble: number of pages changed from %ld to %ld !\n", mnLastPageCount, nPages );
+ #endif
+ mpState->bNeedRestart = (nPages != mnLastPageCount);
+ NSTabViewItem* pItem = [mpTabView selectedTabViewItem];
+ if( pItem )
+ mpState->nLastPage = [mpTabView indexOfTabViewItem: pItem];
+ else
+ mpState->nLastPage = 0;
+ mnLastPageCount = nPages;
+ if( mpState->bNeedRestart )
+ {
+ #if 0
+ // Warning: bad hack ahead
+ // Apple does not give us a chance of changing the page count,
+ // and they don't let us cancel the dialog either
+ // hack: send a cancel message to the window displaying our views.
+ // this is ugly.
+ for( std::vector< NSObject* >::iterator it = maViews.begin(); it != maViews.end(); ++it )
+ {
+ if( [*it isKindOfClass: [NSView class]] )
+ {
+ NSView* pView = (NSView*)*it;
+ NSWindow* pWindow = [pView window];
+ if( pWindow )
+ {
+ [pWindow cancelOperation: nil];
+ break;
+ }
+ }
+ }
+ #else
+ NSWindow* pWindow = [NSApp modalWindow];
+ if( pWindow )
+ [pWindow cancelOperation: nil];
+ #endif
+ [[mpOp printInfo] setJobDisposition: NSPrintCancelJob];
+ }
+ else
+ {
+ sal_Int32 nPage = [mpStepper intValue];
+ updatePreviewImage( nPage-1 );
+ }
+ }
+
+ int addNameTag( const rtl::OUString& i_rPropertyName )
+ {
+ int nNewTag = mnNextTag++;
+ maTagToPropertyName[ nNewTag ] = i_rPropertyName;
+ return nNewTag;
+ }
+
+ int addNameAndValueTag( const rtl::OUString& i_rPropertyName, sal_Int32 i_nValue )
+ {
+ int nNewTag = mnNextTag++;
+ maTagToPropertyName[ nNewTag ] = i_rPropertyName;
+ maTagToValueInt[ nNewTag ] = i_nValue;
+ return nNewTag;
+ }
+
+ void addObservedControl( NSObject* i_pView )
+ {
+ maViews.push_back( i_pView );
+ }
+
+ void addViewPair( NSView* i_pLeft, NSView* i_pRight )
+ {
+ maViewPairMap[ i_pLeft ] = i_pRight;
+ maViewPairMap[ i_pRight ] = i_pLeft;
+ }
+
+ NSView* getPair( NSView* i_pLeft ) const
+ {
+ NSView* pRight = nil;
+ std::map< NSView*, NSView* >::const_iterator it = maViewPairMap.find( i_pLeft );
+ if( it != maViewPairMap.end() )
+ pRight = it->second;
+ return pRight;
+ }
+
+ void changePropertyWithIntValue( int i_nTag )
+ {
+ std::map< int, rtl::OUString >::const_iterator name_it = maTagToPropertyName.find( i_nTag );
+ std::map< int, sal_Int32 >::const_iterator value_it = maTagToValueInt.find( i_nTag );
+ if( name_it != maTagToPropertyName.end() && value_it != maTagToValueInt.end() )
+ {
+ PropertyValue* pVal = mpController->getValue( name_it->second );
+ if( pVal )
+ {
+ pVal->Value <<= value_it->second;
+ updatePrintJob();
+ }
+ }
+ }
+
+ void changePropertyWithIntValue( int i_nTag, sal_Int64 i_nValue )
+ {
+ std::map< int, rtl::OUString >::const_iterator name_it = maTagToPropertyName.find( i_nTag );
+ if( name_it != maTagToPropertyName.end() )
+ {
+ PropertyValue* pVal = mpController->getValue( name_it->second );
+ if( pVal )
+ {
+ pVal->Value <<= i_nValue;
+ updatePrintJob();
+ }
+ }
+ }
+
+ void changePropertyWithBoolValue( int i_nTag, sal_Bool i_bValue )
+ {
+ std::map< int, rtl::OUString >::const_iterator name_it = maTagToPropertyName.find( i_nTag );
+ if( name_it != maTagToPropertyName.end() )
+ {
+ PropertyValue* pVal = mpController->getValue( name_it->second );
+ if( pVal )
+ {
+ pVal->Value <<= i_bValue;
+ updatePrintJob();
+ }
+ }
+ }
+
+ void changePropertyWithStringValue( int i_nTag, const rtl::OUString& i_rValue )
+ {
+ std::map< int, rtl::OUString >::const_iterator name_it = maTagToPropertyName.find( i_nTag );
+ if( name_it != maTagToPropertyName.end() )
+ {
+ PropertyValue* pVal = mpController->getValue( name_it->second );
+ if( pVal )
+ {
+ pVal->Value <<= i_rValue;
+ updatePrintJob();
+ }
+ }
+ }
+
+ void updateEnableState()
+ {
+ for( std::vector< NSObject* >::iterator it = maViews.begin(); it != maViews.end(); ++it )
+ {
+ NSObject* pObj = *it;
+ NSControl* pCtrl = nil;
+ NSCell* pCell = nil;
+ if( [pObj isKindOfClass: [NSControl class]] )
+ pCtrl = (NSControl*)pObj;
+ else if( [pObj isKindOfClass: [NSCell class]] )
+ pCell = (NSCell*)pObj;
+
+ int nTag = pCtrl ? [pCtrl tag] :
+ pCell ? [pCell tag] :
+ -1;
+
+ std::map< int, rtl::OUString >::const_iterator name_it = maTagToPropertyName.find( nTag );
+ if( name_it != maTagToPropertyName.end() )
+ {
+ MacOSBOOL bEnabled = mpController->isUIOptionEnabled( name_it->second ) ? YES : NO;
+ if( pCtrl )
+ {
+ [pCtrl setEnabled: bEnabled];
+ NSView* pOther = getPair( pCtrl );
+ if( pOther && [pOther isKindOfClass: [NSControl class]] )
+ [(NSControl*)pOther setEnabled: bEnabled];
+ }
+ else if( pCell )
+ [pCell setEnabled: bEnabled];
+
+ }
+ }
+ }
+
+ void updatePreviewImage( sal_Int32 i_nPage )
+ {
+ sal_Int32 nPages = mpController->getFilteredPageCount();
+ NSRect aViewFrame = [mpPreview frame];
+ Size aPixelSize( static_cast<long>(aViewFrame.size.width),
+ static_cast<long>(aViewFrame.size.height) );
+ if( i_nPage >= 0 && nPages > i_nPage )
+ {
+ GDIMetaFile aMtf;
+ PrinterController::PageSize aPageSize( mpController->getFilteredPageFile( i_nPage, aMtf, false ) );
+ VirtualDevice aDev;
+ // see salprn.cxx, currently we pretend to be a 720dpi device on printers
+ aDev.SetReferenceDevice( 720, 720 );
+ aDev.EnableOutput( TRUE );
+ Size aLogicSize( aDev.PixelToLogic( aPixelSize, MapMode( MAP_100TH_MM ) ) );
+ double fScaleX = double(aLogicSize.Width())/double(aPageSize.aSize.Width());
+ double fScaleY = double(aLogicSize.Height())/double(aPageSize.aSize.Height());
+ double fScale = (fScaleX < fScaleY) ? fScaleX : fScaleY;
+ // #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
+ if( fScale < 0.1 )
+ fScale = 0.1;
+ aMtf.WindStart();
+ aMtf.Scale( fScale, fScale );
+ aMtf.WindStart();
+ aLogicSize.Width() = long(double(aPageSize.aSize.Width()) * fScale);
+ aLogicSize.Height() = long(double(aPageSize.aSize.Height()) * fScale);
+ aPixelSize = aDev.LogicToPixel( aLogicSize, MapMode( MAP_100TH_MM ) );
+ aDev.SetOutputSizePixel( aPixelSize );
+ aMtf.WindStart();
+ aDev.SetMapMode( MapMode( MAP_100TH_MM ) );
+ aMtf.Play( &aDev, Point( 0, 0 ), aLogicSize );
+ aDev.EnableMapMode( FALSE );
+ Image aImage( aDev.GetBitmap( Point( 0, 0 ), aPixelSize ) );
+ NSImage* pImage = CreateNSImage( aImage );
+ [mpPreview setImage: [pImage autorelease]];
+ }
+ else
+ [mpPreview setImage: nil];
+ }
+
+ void setupPreview( ControlTarget* i_pCtrlTarget )
+ {
+ if( maLocalizedStrings.Count() < 3 )
+ return;
+
+ // get the preview control
+ NSRect aPreviewFrame = [mpAccessoryView frame];
+ aPreviewFrame.origin.x = 0;
+ aPreviewFrame.origin.y = 5;
+ aPreviewFrame.size.width = 190;
+ aPreviewFrame.size.height -= 7;
+
+ // create a box to put the preview controls in
+ mpPreviewBox = [[NSBox alloc] initWithFrame: aPreviewFrame];
+ [mpPreviewBox setTitle: [CreateNSString( maLocalizedStrings.GetString( 0 ) ) autorelease]];
+ [mpAccessoryView addSubview: [mpPreviewBox autorelease]];
+
+ // now create the image view of the preview
+ NSSize aMargins = [mpPreviewBox contentViewMargins];
+ aPreviewFrame.origin.x = 0;
+ aPreviewFrame.origin.y = 34;
+ aPreviewFrame.size.width -= 2*(aMargins.width+1);
+ aPreviewFrame.size.height -= 61;
+ mpPreview = [[NSImageView alloc] initWithFrame: aPreviewFrame];
+ [mpPreview setImageScaling: NSScaleProportionally];
+ [mpPreview setImageAlignment: NSImageAlignCenter];
+ [mpPreview setImageFrameStyle: NSImageFrameNone];
+ [mpPreviewBox addSubview: [mpPreview autorelease]];
+
+ // add a label
+ sal_Int32 nPages = mpController->getFilteredPageCount();
+ rtl::OUStringBuffer aBuf( 16 );
+ aBuf.appendAscii( "/ " );
+ aBuf.append( rtl::OUString::valueOf( nPages ) );
+
+ NSString* pText = CreateNSString( aBuf.makeStringAndClear() );
+ NSRect aTextRect = { { 100, 5 }, { 100, 22 } };
+ mpPagesLabel = [[NSTextView alloc] initWithFrame: aTextRect];
+ [mpPagesLabel setFont: [NSFont controlContentFontOfSize: 0]];
+ [mpPagesLabel setEditable: NO];
+ [mpPagesLabel setSelectable: NO];
+ [mpPagesLabel setDrawsBackground: NO];
+ [mpPagesLabel setString: [pText autorelease]];
+ [mpPagesLabel setToolTip: [CreateNSString( maLocalizedStrings.GetString( 2 ) ) autorelease]];
+ [mpPreviewBox addSubview: [mpPagesLabel autorelease]];
+
+ NSRect aFieldRect = { { 45, 5 }, { 35, 25 } };
+ mpPageEdit = [[NSTextField alloc] initWithFrame: aFieldRect];
+ [mpPageEdit setEditable: YES];
+ [mpPageEdit setSelectable: YES];
+ [mpPageEdit setDrawsBackground: YES];
+ [mpPageEdit setToolTip: [CreateNSString( maLocalizedStrings.GetString( 1 ) ) autorelease]];
+ [mpPreviewBox addSubview: [mpPageEdit autorelease]];
+
+ // add a stepper control
+ NSRect aStepFrame = { { 85, 5 }, { 15, 25 } };
+ mpStepper = [[NSStepper alloc] initWithFrame: aStepFrame];
+ [mpStepper setIncrement: 1];
+ [mpStepper setValueWraps: NO];
+ [mpPreviewBox addSubview: [mpStepper autorelease]];
+
+ // constrain the text field to decimal numbers
+ NSNumberFormatter* pFormatter = [[NSNumberFormatter alloc] init];
+ [pFormatter setFormatterBehavior: NSNumberFormatterBehavior10_4];
+ [pFormatter setMinimum: [[NSNumber numberWithInt: 1] autorelease]];
+ [pFormatter setMaximum: [[NSNumber numberWithInt: nPages] autorelease]];
+ [pFormatter setNumberStyle: NSNumberFormatterDecimalStyle];
+ [pFormatter setAllowsFloats: NO];
+ [pFormatter setMaximumFractionDigits: 0];
+ [mpPageEdit setFormatter: pFormatter];
+ [mpStepper setMinValue: 1];
+ [mpStepper setMaxValue: nPages];
+
+ [mpPageEdit setIntValue: 1];
+ [mpStepper setIntValue: 1];
+
+ // connect target and action
+ [mpStepper setTarget: i_pCtrlTarget];
+ [mpStepper setAction: @selector(triggeredPreview:)];
+ [mpPageEdit setTarget: i_pCtrlTarget];
+ [mpPageEdit setAction: @selector(triggeredPreview:)];
+
+ // set first preview image
+ updatePreviewImage( 0 );
+ }
+
+ void changePreview( NSObject* i_pSender )
+ {
+ if( [i_pSender isMemberOfClass: [NSTextField class]] )
+ {
+ NSTextField* pField = (NSTextField*)i_pSender;
+ if( pField == mpPageEdit ) // sanity check
+ {
+ sal_Int32 nPage = [pField intValue];
+ [mpStepper setIntValue: nPage];
+ updatePreviewImage( nPage-1 );
+ }
+ }
+ else if( [i_pSender isMemberOfClass: [NSStepper class]] )
+ {
+ NSStepper* pStepper = (NSStepper*)i_pSender;
+ if( pStepper == mpStepper ) // sanity check
+ {
+ sal_Int32 nPage = [pStepper intValue];
+ [mpPageEdit setIntValue: nPage];
+ updatePreviewImage( nPage-1 );
+ }
+ }
+ }
+};
+
+static void filterAccelerator( rtl::OUString& io_rText )
+{
+ rtl::OUStringBuffer aBuf( io_rText.getLength() );
+ for( sal_Int32 nIndex = 0; nIndex != -1; )
+ aBuf.append( io_rText.getToken( 0, '~', nIndex ) );
+ io_rText = aBuf.makeStringAndClear();
+}
+
+@implementation ControlTarget
+-(id)initWithControllerMap: (ControllerProperties*)pController
+{
+ if( (self = [super init]) )
+ {
+ mpController = pController;
+ }
+ return self;
+}
+-(void)triggered:(id)pSender;
+{
+ if( [pSender isMemberOfClass: [NSPopUpButton class]] )
+ {
+ NSPopUpButton* pBtn = (NSPopUpButton*)pSender;
+ NSMenuItem* pSelected = [pBtn selectedItem];
+ if( pSelected )
+ {
+ int nTag = [pSelected tag];
+ mpController->changePropertyWithIntValue( nTag );
+ }
+ }
+ else if( [pSender isMemberOfClass: [NSButton class]] )
+ {
+ NSButton* pBtn = (NSButton*)pSender;
+ int nTag = [pBtn tag];
+ mpController->changePropertyWithBoolValue( nTag, [pBtn state] == NSOnState );
+ }
+ else if( [pSender isMemberOfClass: [NSMatrix class]] )
+ {
+ NSObject* pObj = [(NSMatrix*)pSender selectedCell];
+ if( [pObj isMemberOfClass: [NSButtonCell class]] )
+ {
+ NSButtonCell* pCell = (NSButtonCell*)pObj;
+ int nTag = [pCell tag];
+ mpController->changePropertyWithIntValue( nTag );
+ }
+ }
+ else if( [pSender isMemberOfClass: [NSTextField class]] )
+ {
+ NSTextField* pField = (NSTextField*)pSender;
+ int nTag = [pField tag];
+ rtl::OUString aValue = GetOUString( [pSender stringValue] );
+ mpController->changePropertyWithStringValue( nTag, aValue );
+ }
+ else
+ {
+ DBG_ERROR( "unsupported class" );
+ }
+ mpController->updateEnableState();
+}
+-(void)triggeredNumeric:(id)pSender;
+{
+ if( [pSender isMemberOfClass: [NSTextField class]] )
+ {
+ NSTextField* pField = (NSTextField*)pSender;
+ int nTag = [pField tag];
+ sal_Int64 nValue = [pField intValue];
+
+ NSView* pOther = mpController->getPair( pField );
+ if( pOther )
+ [(NSControl*)pOther setIntValue: nValue];
+
+ mpController->changePropertyWithIntValue( nTag, nValue );
+ }
+ else if( [pSender isMemberOfClass: [NSStepper class]] )
+ {
+ NSStepper* pStep = (NSStepper*)pSender;
+ int nTag = [pStep tag];
+ sal_Int64 nValue = [pStep intValue];
+
+ NSView* pOther = mpController->getPair( pStep );
+ if( pOther )
+ [(NSControl*)pOther setIntValue: nValue];
+
+ mpController->changePropertyWithIntValue( nTag, nValue );
+ }
+ else
+ {
+ DBG_ERROR( "unsupported class" );
+ }
+ mpController->updateEnableState();
+}
+-(void)triggeredPreview:(id)pSender
+{
+ mpController->changePreview( pSender );
+}
+-(void)dealloc
+{
+ delete mpController;
+ [super dealloc];
+}
+@end
+
+struct ColumnItem
+{
+ NSControl* pControl;
+ long nOffset;
+ NSControl* pSubControl;
+
+ ColumnItem( NSControl* i_pControl = nil, long i_nOffset = 0, NSControl* i_pSub = nil )
+ : pControl( i_pControl )
+ , nOffset( i_nOffset )
+ , pSubControl( i_pSub )
+ {}
+
+ long getWidth() const
+ {
+ long nWidth = 0;
+ if( pControl )
+ {
+ NSRect aCtrlRect = [pControl frame];
+ nWidth = aCtrlRect.size.width;
+ nWidth += nOffset;
+ if( pSubControl )
+ {
+ NSRect aSubRect = [pSubControl frame];
+ nWidth += aSubRect.size.width;
+ nWidth += aSubRect.origin.x - (aCtrlRect.origin.x + aCtrlRect.size.width);
+ }
+ }
+ return nWidth;
+ }
+};
+
+static void adjustViewAndChildren( NSView* pView, NSSize& rMaxSize,
+ std::vector< ColumnItem >& rLeftColumn,
+ std::vector< ColumnItem >& rRightColumn
+ )
+{
+ // balance columns
+
+ // first get overall column widths
+ long nLeftWidth = 0;
+ long nRightWidth = 0;
+ for( size_t i = 0; i < rLeftColumn.size(); i++ )
+ {
+ long nW = rLeftColumn[i].getWidth();
+ if( nW > nLeftWidth )
+ nLeftWidth = nW;
+ }
+ for( size_t i = 0; i < rRightColumn.size(); i++ )
+ {
+ long nW = rRightColumn[i].getWidth();
+ if( nW > nRightWidth )
+ nRightWidth = nW;
+ }
+
+ // right align left column
+ for( size_t i = 0; i < rLeftColumn.size(); i++ )
+ {
+ if( rLeftColumn[i].pControl )
+ {
+ NSRect aCtrlRect = [rLeftColumn[i].pControl frame];
+ long nX = nLeftWidth - aCtrlRect.size.width;
+ if( rLeftColumn[i].pSubControl )
+ {
+ NSRect aSubRect = [rLeftColumn[i].pSubControl frame];
+ nX -= aSubRect.size.width + (aSubRect.origin.x - (aCtrlRect.origin.x + aCtrlRect.size.width));
+ aSubRect.origin.x = nLeftWidth - aSubRect.size.width;
+ [rLeftColumn[i].pSubControl setFrame: aSubRect];
+ }
+ aCtrlRect.origin.x = nX;
+ [rLeftColumn[i].pControl setFrame: aCtrlRect];
+ }
+ }
+
+ // left align right column
+ for( size_t i = 0; i < rRightColumn.size(); i++ )
+ {
+ if( rRightColumn[i].pControl )
+ {
+ NSRect aCtrlRect = [rRightColumn[i].pControl frame];
+ long nX = nLeftWidth + 3;
+ if( rRightColumn[i].pSubControl )
+ {
+ NSRect aSubRect = [rRightColumn[i].pSubControl frame];
+ aSubRect.origin.x = nX + aSubRect.origin.x - aCtrlRect.origin.x;
+ [rRightColumn[i].pSubControl setFrame: aSubRect];
+ }
+ aCtrlRect.origin.x = nX;
+ [rRightColumn[i].pControl setFrame: aCtrlRect];
+ }
+ }
+
+ NSArray* pSubViews = [pView subviews];
+ unsigned int nViews = [pSubViews count];
+ NSRect aUnion = { { 0, 0 }, { 0, 0 } };
+
+ // get the combined frame of all subviews
+ for( unsigned int n = 0; n < nViews; n++ )
+ {
+ aUnion = NSUnionRect( aUnion, [[pSubViews objectAtIndex: n] frame] );
+ }
+
+ // move everything so it will fit
+ for( unsigned int n = 0; n < nViews; n++ )
+ {
+ NSView* pCurSubView = [pSubViews objectAtIndex: n];
+ NSRect aFrame = [pCurSubView frame];
+ aFrame.origin.x -= aUnion.origin.x - 5;
+ aFrame.origin.y -= aUnion.origin.y - 5;
+ [pCurSubView setFrame: aFrame];
+ }
+
+ // resize the view itself
+ aUnion.size.height += 10;
+ aUnion.size.width += 20;
+ [pView setFrameSize: aUnion.size];
+
+ if( aUnion.size.width > rMaxSize.width )
+ rMaxSize.width = aUnion.size.width;
+ if( aUnion.size.height > rMaxSize.height )
+ rMaxSize.height = aUnion.size.height;
+}
+
+static void adjustTabViews( NSTabView* pTabView, NSSize aTabSize )
+{
+ // loop over all contained tab pages
+ NSArray* pTabbedViews = [pTabView tabViewItems];
+ int nViews = [pTabbedViews count];
+ for( int i = 0; i < nViews; i++ )
+ {
+ NSTabViewItem* pItem = (NSTabViewItem*)[pTabbedViews objectAtIndex: i];
+ NSView* pView = [pItem view];
+ if( pView )
+ {
+ NSRect aRect = [pView frame];
+ double nDiff = aTabSize.height - aRect.size.height;
+ aRect.size = aTabSize;
+ [pView setFrame: aRect];
+
+ NSArray* pSubViews = [pView subviews];
+ unsigned int nSubViews = [pSubViews count];
+
+ // move everything up
+ for( unsigned int n = 0; n < nSubViews; n++ )
+ {
+ NSView* pCurSubView = [pSubViews objectAtIndex: n];
+ NSRect aFrame = [pCurSubView frame];
+ aFrame.origin.y += nDiff;
+ // give separators the correct width
+ // separators are currently the only NSBoxes we use
+ if( [pCurSubView isMemberOfClass: [NSBox class]] )
+ {
+ aFrame.size.width = aTabSize.width - aFrame.origin.x - 10;
+ }
+ [pCurSubView setFrame: aFrame];
+ }
+ }
+ }
+}
+
+static NSControl* createLabel( const rtl::OUString& i_rText )
+{
+ NSString* pText = CreateNSString( i_rText );
+ NSRect aTextRect = { { 0, 0 }, {20, 15} };
+ NSTextField* pTextView = [[NSTextField alloc] initWithFrame: aTextRect];
+ [pTextView setFont: [NSFont controlContentFontOfSize: 0]];
+ [pTextView setEditable: NO];
+ [pTextView setSelectable: NO];
+ [pTextView setDrawsBackground: NO];
+ [pTextView setBordered: NO];
+ [pTextView setStringValue: pText];
+ [pTextView sizeToFit];
+ [pText release];
+ return pTextView;
+}
+
+static sal_Int32 findBreak( const rtl::OUString& i_rText, sal_Int32 i_nPos )
+{
+ sal_Int32 nRet = i_rText.getLength();
+ Reference< i18n::XBreakIterator > xBI( vcl::unohelper::CreateBreakIterator() );
+ if( xBI.is() )
+ {
+ i18n::Boundary aBoundary = xBI->getWordBoundary( i_rText, i_nPos,
+ Application::GetSettings().GetLocale(),
+ i18n::WordType::ANYWORD_IGNOREWHITESPACES,
+ sal_True );
+ nRet = aBoundary.endPos;
+ }
+ return nRet;
+}
+
+static void linebreakCell( NSCell* pBtn, const rtl::OUString& i_rText )
+{
+ NSString* pText = CreateNSString( i_rText );
+ [pBtn setTitle: pText];
+ [pText release];
+ NSSize aSize = [pBtn cellSize];
+ if( aSize.width > 280 )
+ {
+ // need two lines
+ sal_Int32 nLen = i_rText.getLength();
+ sal_Int32 nIndex = nLen / 2;
+ nIndex = findBreak( i_rText, nIndex );
+ if( nIndex < nLen )
+ {
+ rtl::OUStringBuffer aBuf( i_rText );
+ aBuf.setCharAt( nIndex, '\n' );
+ pText = CreateNSString( aBuf.makeStringAndClear() );
+ [pBtn setTitle: pText];
+ [pText release];
+ }
+ }
+}
+
+
+@implementation AquaPrintAccessoryView
++(NSObject*)setupPrinterPanel: (NSPrintOperation*)pOp withController: (vcl::PrinterController*)pController withState: (PrintAccessoryViewState*)pState;
+{
+ const Sequence< PropertyValue >& rOptions( pController->getUIOptions() );
+ if( rOptions.getLength() == 0 )
+ return nil;
+
+ NSView* pCurParent = 0;
+ long nCurY = 0;
+ long nCurX = 0;
+ NSRect aViewFrame = { { 0, 0 }, {600, 400 } };
+ NSRect aTabViewFrame = { { 190, 0 }, {410, 400 } };
+ NSSize aMaxTabSize = { 0, 0 };
+ NSView* pAccessoryView = [[NSView alloc] initWithFrame: aViewFrame];
+ NSTabView* pTabView = [[NSTabView alloc] initWithFrame: aTabViewFrame];
+ [pAccessoryView addSubview: [pTabView autorelease]];
+
+ sal_Bool bIgnoreSubgroup = sal_False;
+
+ ControllerProperties* pControllerProperties = new ControllerProperties( pController, pOp, pAccessoryView, pTabView, pState );
+ ControlTarget* pCtrlTarget = [[ControlTarget alloc] initWithControllerMap: pControllerProperties];
+
+ std::vector< ColumnItem > aLeftColumn, aRightColumn;
+
+ 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;
+ sal_Int64 nMinValue = 0, nMaxValue = 0;
+ long nAttachOffset = 0;
+ sal_Bool bIgnore = sal_False;
+
+ for( int n = 0; n < aOptProp.getLength(); n++ )
+ {
+ const beans::PropertyValue& rEntry( aOptProp[ n ] );
+ if( rEntry.Name.equalsAscii( "Text" ) )
+ {
+ rEntry.Value >>= aText;
+ filterAccelerator( 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( "MinValue" ) )
+ {
+ rEntry.Value >>= nMinValue;
+ }
+ else if( rEntry.Name.equalsAscii( "MaxValue" ) )
+ {
+ rEntry.Value >>= nMaxValue;
+ }
+ else if( rEntry.Name.equalsAscii( "AttachToDependency" ) )
+ {
+ nAttachOffset = 20;
+ }
+ else if( rEntry.Name.equalsAscii( "InternalUIOnly" ) )
+ {
+ rEntry.Value >>= bIgnore;
+ }
+ }
+
+ if( aCtrlType.equalsAscii( "Group" ) ||
+ aCtrlType.equalsAscii( "Subgroup" ) ||
+ aCtrlType.equalsAscii( "Radio" ) ||
+ aCtrlType.equalsAscii( "List" ) ||
+ aCtrlType.equalsAscii( "Edit" ) ||
+ aCtrlType.equalsAscii( "Range" ) ||
+ aCtrlType.equalsAscii( "Bool" ) )
+ {
+ // since our build target is MacOSX 10.4 we can have only one accessory view
+ // so we have a single accessory view that is tabbed for grouping
+ if( aCtrlType.equalsAscii( "Group" )
+ || ! pCurParent
+ || ( aCtrlType.equalsAscii( "Subgroup" ) && nCurY < -250 && ! bIgnore )
+ )
+ {
+ rtl::OUString aGroupTitle( aText );
+ if( aCtrlType.equalsAscii( "Subgroup" ) )
+ aGroupTitle = pControllerProperties->getMoreString();
+ // set size of current parent
+ if( pCurParent )
+ adjustViewAndChildren( pCurParent, aMaxTabSize, aLeftColumn, aRightColumn );
+
+ // new tab item
+ if( ! aText.getLength() )
+ aText = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "OOo" ) );
+ NSString* pLabel = CreateNSString( aGroupTitle );
+ NSTabViewItem* pItem = [[NSTabViewItem alloc] initWithIdentifier: pLabel ];
+ [pItem setLabel: pLabel];
+ [pTabView addTabViewItem: pItem];
+ pCurParent = [[NSView alloc] initWithFrame: aTabViewFrame];
+ [pItem setView: pCurParent];
+ [pLabel release];
+
+ // reset indent
+ nCurX = 20;
+ // reset Y
+ nCurY = 0;
+ // clear columns
+ aLeftColumn.clear();
+ aRightColumn.clear();
+ }
+
+ if( aCtrlType.equalsAscii( "Subgroup" ) && pCurParent )
+ {
+ bIgnoreSubgroup = bIgnore;
+ if( bIgnore )
+ continue;
+
+ NSControl* pTextView = createLabel( aText );
+ [pCurParent addSubview: [pTextView autorelease]];
+ NSRect aTextRect = [pTextView frame];
+ // move to nCurY
+ aTextRect.origin.y = nCurY - aTextRect.size.height;
+ [pTextView setFrame: aTextRect];
+
+ NSRect aSepRect = { { aTextRect.size.width + 1, aTextRect.origin.y }, { 100, 6 } };
+ NSBox* pBox = [[NSBox alloc] initWithFrame: aSepRect];
+ [pBox setBoxType: NSBoxSeparator];
+ [pCurParent addSubview: [pBox autorelease]];
+
+ // update nCurY
+ nCurY = aTextRect.origin.y - 5;
+ }
+ else if( bIgnoreSubgroup || bIgnore )
+ continue;
+ else if( aCtrlType.equalsAscii( "Bool" ) && pCurParent )
+ {
+ NSRect aCheckRect = { { nCurX + nAttachOffset, 0 }, { 0, 15 } };
+ NSButton* pBtn = [[NSButton alloc] initWithFrame: aCheckRect];
+ [pBtn setButtonType: NSSwitchButton];
+ sal_Bool bVal = sal_False;
+ PropertyValue* pVal = pController->getValue( aPropertyName );
+ if( pVal )
+ pVal->Value >>= bVal;
+ [pBtn setState: bVal ? NSOnState : NSOffState];
+ linebreakCell( [pBtn cell], aText );
+ [pBtn sizeToFit];
+ [pCurParent addSubview: [pBtn autorelease]];
+
+ aRightColumn.push_back( ColumnItem( pBtn ) );
+
+ // connect target
+ [pBtn setTarget: pCtrlTarget];
+ [pBtn setAction: @selector(triggered:)];
+ int nTag = pControllerProperties->addNameTag( aPropertyName );
+ pControllerProperties->addObservedControl( pBtn );
+ [pBtn setTag: nTag];
+
+ aCheckRect = [pBtn frame];
+
+ // move to nCurY
+ aCheckRect.origin.y = nCurY - aCheckRect.size.height;
+ [pBtn setFrame: aCheckRect];
+
+ // update nCurY
+ nCurY = aCheckRect.origin.y - 5;
+ }
+ else if( aCtrlType.equalsAscii( "Radio" ) && pCurParent )
+ {
+ sal_Int32 nOff = 0;
+ if( aText.getLength() )
+ {
+ // add a label
+ NSControl* pTextView = createLabel( aText );
+ NSRect aTextRect = [pTextView frame];
+ aTextRect.origin.x = nCurX + nAttachOffset;
+ [pCurParent addSubview: [pTextView autorelease]];
+
+ aLeftColumn.push_back( ColumnItem( pTextView ) );
+
+ // move to nCurY
+ aTextRect.origin.y = nCurY - aTextRect.size.height;
+ [pTextView setFrame: aTextRect];
+
+ // update nCurY
+ nCurY = aTextRect.origin.y - 5;
+
+ // indent the radio group relative to the text
+ // nOff = 20;
+ }
+
+ // setup radio matrix
+ NSButtonCell* pProto = [[NSButtonCell alloc] init];
+
+ NSRect aRadioRect = { { nCurX + nOff, 0 }, { 280 - nCurX, 5*aChoices.getLength() } };
+ [pProto setTitle: @"RadioButtonGroup"];
+ [pProto setButtonType: NSRadioButton];
+ NSMatrix* pMatrix = [[NSMatrix alloc] initWithFrame: aRadioRect
+ mode: NSRadioModeMatrix
+ prototype: (NSCell*)pProto
+ numberOfRows: aChoices.getLength()
+ numberOfColumns: 1];
+ // get currently selected value
+ sal_Int32 nSelectVal = 0;
+ PropertyValue* pVal = pController->getValue( aPropertyName );
+ if( pVal && pVal->Value.hasValue() )
+ pVal->Value >>= nSelectVal;
+ // set individual titles
+ NSArray* pCells = [pMatrix cells];
+ for( sal_Int32 m = 0; m < aChoices.getLength(); m++ )
+ {
+ NSCell* pCell = [pCells objectAtIndex: m];
+ filterAccelerator( aChoices[m] );
+ linebreakCell( pCell, aChoices[m] );
+ //NSString* pTitle = CreateNSString( aChoices[m] );
+ //[pCell setTitle: pTitle];
+ // connect target and action
+ [pCell setTarget: pCtrlTarget];
+ [pCell setAction: @selector(triggered:)];
+ int nTag = pControllerProperties->addNameAndValueTag( aPropertyName, m );
+ pControllerProperties->addObservedControl( pCell );
+ [pCell setTag: nTag];
+ //[pTitle release];
+ // set current selection
+ if( nSelectVal == m )
+ [pMatrix selectCellAtRow: m column: 0];
+ }
+ [pMatrix sizeToFit];
+ aRadioRect = [pMatrix frame];
+
+ // move it down, so it comes to the correct position
+ aRadioRect.origin.y = nCurY - aRadioRect.size.height;
+ [pMatrix setFrame: aRadioRect];
+ [pCurParent addSubview: [pMatrix autorelease]];
+
+ aRightColumn.push_back( ColumnItem( pMatrix ) );
+
+ // update nCurY
+ nCurY = aRadioRect.origin.y - 5;
+
+ [pProto release];
+ }
+ else if( aCtrlType.equalsAscii( "List" ) && pCurParent )
+ {
+ // don't indent attached lists, looks bad in the existing cases
+ NSControl* pTextView = createLabel( aText );
+ [pCurParent addSubview: [pTextView autorelease]];
+ aLeftColumn.push_back( ColumnItem( pTextView ) );
+ NSRect aTextRect = [pTextView frame];
+ aTextRect.origin.x = nCurX /* + nAttachOffset*/;
+
+ // don't indent attached lists, looks bad in the existing cases
+ NSRect aBtnRect = { { nCurX /*+ nAttachOffset*/ + aTextRect.size.width, 0 }, { 0, 15 } };
+ NSPopUpButton* pBtn = [[NSPopUpButton alloc] initWithFrame: aBtnRect pullsDown: NO];
+
+ // iterate options
+ for( sal_Int32 m = 0; m < aChoices.getLength(); m++ )
+ {
+ NSString* pItemText = CreateNSString( aChoices[m] );
+ [pBtn addItemWithTitle: pItemText];
+ NSMenuItem* pItem = [pBtn itemWithTitle: pItemText];
+ int nTag = pControllerProperties->addNameAndValueTag( aPropertyName, m );
+ [pItem setTag: nTag];
+ [pItemText release];
+ }
+
+ PropertyValue* pVal = pController->getValue( aPropertyName );
+ sal_Int32 aSelectVal = 0;
+ if( pVal && pVal->Value.hasValue() )
+ pVal->Value >>= aSelectVal;
+ [pBtn selectItemAtIndex: aSelectVal];
+
+ // add the button to observed controls for enabled state changes
+ // also add a tag just for this purpose
+ pControllerProperties->addObservedControl( pBtn );
+ [pBtn setTag: pControllerProperties->addNameTag( aPropertyName )];
+
+ [pBtn sizeToFit];
+ [pCurParent addSubview: [pBtn autorelease]];
+
+ aRightColumn.push_back( ColumnItem( pBtn ) );
+
+ // connect target and action
+ [pBtn setTarget: pCtrlTarget];
+ [pBtn setAction: @selector(triggered:)];
+
+ // move to nCurY
+ aBtnRect = [pBtn frame];
+ aBtnRect.origin.y = nCurY - aBtnRect.size.height;
+ [pBtn setFrame: aBtnRect];
+
+ // align label
+ aTextRect.origin.y = aBtnRect.origin.y + (aBtnRect.size.height - aTextRect.size.height)/2;
+ [pTextView setFrame: aTextRect];
+
+ // update nCurY
+ nCurY = aBtnRect.origin.y - 5;
+ }
+ else if( (aCtrlType.equalsAscii( "Edit" ) || aCtrlType.equalsAscii( "Range" )) && pCurParent )
+ {
+ sal_Int32 nOff = 0;
+ if( aText.getLength() )
+ {
+ // add a label
+ NSControl* pTextView = createLabel( aText );
+ [pCurParent addSubview: [pTextView autorelease]];
+
+ aLeftColumn.push_back( ColumnItem( pTextView ) );
+
+ // move to nCurY
+ NSRect aTextRect = [pTextView frame];
+ aTextRect.origin.x = nCurX + nAttachOffset;
+ aTextRect.origin.y = nCurY - aTextRect.size.height;
+ [pTextView setFrame: aTextRect];
+
+ // update nCurY
+ nCurY = aTextRect.origin.y - 5;
+
+ // and set the offset for the real edit field
+ nOff = aTextRect.size.width + 5;
+ }
+
+ NSRect aFieldRect = { { nCurX + nOff + nAttachOffset, 0 }, { 100, 25 } };
+ NSTextField* pFieldView = [[NSTextField alloc] initWithFrame: aFieldRect];
+ [pFieldView setEditable: YES];
+ [pFieldView setSelectable: YES];
+ [pFieldView setDrawsBackground: YES];
+ [pFieldView sizeToFit]; // FIXME: this does nothing
+ [pCurParent addSubview: [pFieldView autorelease]];
+
+ aRightColumn.push_back( ColumnItem( pFieldView ) );
+
+ // add the field to observed controls for enabled state changes
+ // also add a tag just for this purpose
+ pControllerProperties->addObservedControl( pFieldView );
+ int nTag = pControllerProperties->addNameTag( aPropertyName );
+ [pFieldView setTag: nTag];
+ // pControllerProperties->addNamedView( pFieldView, aPropertyName );
+
+ // move to nCurY
+ aFieldRect.origin.y = nCurY - aFieldRect.size.height;
+ [pFieldView setFrame: aFieldRect];
+
+ // current value
+ PropertyValue* pVal = pController->getValue( aPropertyName );
+ if( aCtrlType.equalsAscii( "Range" ) )
+ {
+ // add a stepper control
+ NSRect aStepFrame = { { aFieldRect.origin.x + aFieldRect.size.width + 5,
+ aFieldRect.origin.y },
+ { 15, aFieldRect.size.height } };
+ NSStepper* pStep = [[NSStepper alloc] initWithFrame: aStepFrame];
+ [pStep setIncrement: 1];
+ [pStep setValueWraps: NO];
+ [pStep setTag: nTag];
+ [pCurParent addSubview: [pStep autorelease]];
+
+ aRightColumn.back().pSubControl = pStep;
+
+ pControllerProperties->addObservedControl( pStep );
+ [pStep setTarget: pCtrlTarget];
+ [pStep setAction: @selector(triggered:)];
+
+ // constrain the text field to decimal numbers
+ NSNumberFormatter* pFormatter = [[NSNumberFormatter alloc] init];
+ [pFormatter setFormatterBehavior: NSNumberFormatterBehavior10_4];
+ [pFormatter setNumberStyle: NSNumberFormatterDecimalStyle];
+ [pFormatter setAllowsFloats: NO];
+ [pFormatter setMaximumFractionDigits: 0];
+ if( nMinValue != nMaxValue )
+ {
+ [pFormatter setMinimum: [[NSNumber numberWithInt: nMinValue] autorelease]];
+ [pStep setMinValue: nMinValue];
+ [pFormatter setMaximum: [[NSNumber numberWithInt: nMaxValue] autorelease]];
+ [pStep setMaxValue: nMaxValue];
+ }
+ [pFieldView setFormatter: pFormatter];
+
+ sal_Int64 nSelectVal = 0;
+ if( pVal && pVal->Value.hasValue() )
+ pVal->Value >>= nSelectVal;
+
+ [pFieldView setIntValue: nSelectVal];
+ [pStep setIntValue: nSelectVal];
+
+ pControllerProperties->addViewPair( pFieldView, pStep );
+ // connect target and action
+ [pFieldView setTarget: pCtrlTarget];
+ [pFieldView setAction: @selector(triggeredNumeric:)];
+ [pStep setTarget: pCtrlTarget];
+ [pStep setAction: @selector(triggeredNumeric:)];
+ }
+ else
+ {
+ // connect target and action
+ [pFieldView setTarget: pCtrlTarget];
+ [pFieldView setAction: @selector(triggered:)];
+
+ if( pVal && pVal->Value.hasValue() )
+ {
+ rtl::OUString aValue;
+ pVal->Value >>= aValue;
+ if( aValue.getLength() )
+ {
+ NSString* pText = CreateNSString( aValue );
+ [pFieldView setStringValue: pText];
+ [pText release];
+ }
+ }
+ }
+
+ // update nCurY
+ nCurY = aFieldRect.origin.y - 5;
+
+ }
+ }
+ else
+ {
+ DBG_ERROR( "Unsupported UI option" );
+ }
+ }
+
+ pControllerProperties->updateEnableState();
+ adjustViewAndChildren( pCurParent, aMaxTabSize, aLeftColumn, aRightColumn );
+
+ // leave some space for the preview
+ if( aMaxTabSize.height < 200 )
+ aMaxTabSize.height = 200;
+
+ // now reposition everything again so it is upper bound
+ adjustTabViews( pTabView, aMaxTabSize );
+
+ // find the minimum needed tab size
+ NSSize aTabCtrlSize = [pTabView minimumSize];
+ aTabCtrlSize.height += aMaxTabSize.height + 10;
+ if( aTabCtrlSize.width < aMaxTabSize.width + 10 )
+ aTabCtrlSize.width = aMaxTabSize.width + 10;
+ [pTabView setFrameSize: aTabCtrlSize];
+ aViewFrame.size.width = aTabCtrlSize.width + aTabViewFrame.origin.x;
+ aViewFrame.size.height = aTabCtrlSize.height + aTabViewFrame.origin.y;
+ [pAccessoryView setFrameSize: aViewFrame.size];
+
+ pControllerProperties->setupPreview( pCtrlTarget );
+
+ // set the accessory view
+ [pOp setAccessoryView: [pAccessoryView autorelease]];
+
+ // set the current selecte tab item
+ if( pState->nLastPage >= 0 && pState->nLastPage < [pTabView numberOfTabViewItems] )
+ [pTabView selectTabViewItemAtIndex: pState->nLastPage];
+
+ return pCtrlTarget;
+}
+
+@end
diff --git a/vcl/aqua/source/gdi/aquaprintview.mm b/vcl/aqua/source/gdi/aquaprintview.mm
new file mode 100755
index 000000000000..ae42c5c09e8d
--- /dev/null
+++ b/vcl/aqua/source/gdi/aquaprintview.mm
@@ -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 "aquaprintview.h"
+#include "salprn.h"
+#include "vcl/print.hxx"
+
+@implementation AquaPrintView
+-(id)initWithController: (vcl::PrinterController*)pController withInfoPrinter: (AquaSalInfoPrinter*)pInfoPrinter
+{
+ NSRect aRect = { { 0, 0 }, [pInfoPrinter->getPrintInfo() paperSize] };
+ if( (self = [super initWithFrame: aRect]) != nil )
+ {
+ mpController = pController;
+ mpInfoPrinter = pInfoPrinter;
+ }
+ return self;
+}
+
+-(MacOSBOOL)knowsPageRange: (NSRangePointer)range
+{
+ range->location = 1;
+ range->length = mpInfoPrinter->getCurPageRangeCount();
+ return YES;
+}
+
+-(NSRect)rectForPage: (int)page
+{
+ NSSize aPaperSize = [mpInfoPrinter->getPrintInfo() paperSize];
+ int nWidth = (int)aPaperSize.width;
+ // #i101108# sanity check
+ if( nWidth < 1 )
+ nWidth = 1;
+ NSRect aRect = { { page % nWidth, page / nWidth }, aPaperSize };
+ return aRect;
+}
+
+-(NSPoint)locationOfPrintRect: (NSRect)aRect
+{
+ NSPoint aPoint = { 0, 0 };
+ return aPoint;
+}
+
+-(void)drawRect: (NSRect)rect
+{
+ NSPoint aPoint = [self locationOfPrintRect: rect];
+ mpInfoPrinter->setStartPageOffset( static_cast<int>(rect.origin.x), static_cast<int>(rect.origin.y) );
+ NSSize aPaperSize = [mpInfoPrinter->getPrintInfo() paperSize];
+ int nPage = (int)(aPaperSize.width * rect.origin.y + rect.origin.x);
+
+ // page count is 1 based
+ if( nPage - 1 < (mpInfoPrinter->getCurPageRangeStart() + mpInfoPrinter->getCurPageRangeCount() ) )
+ mpController->printFilteredPage( nPage-1 );
+}
+@end
diff --git a/vcl/aqua/source/gdi/makefile.mk b/vcl/aqua/source/gdi/makefile.mk
new file mode 100644
index 000000000000..2aea58e49250
--- /dev/null
+++ b/vcl/aqua/source/gdi/makefile.mk
@@ -0,0 +1,74 @@
+#*************************************************************************
+#
+# 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=salgdi
+ENABLE_EXCEPTIONS=TRUE
+
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)"!="aqua"
+
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+
+.ELSE # "$(GUIBASE)"!="aqua"
+
+SLOFILES= $(SLO)$/salmathutils.obj \
+ $(SLO)$/salcolorutils.obj \
+ $(SLO)$/salgdiutils.obj \
+ $(SLO)$/salnativewidgets.obj \
+ $(SLO)$/salatsuifontutils.obj \
+ $(SLO)$/salatslayout.obj \
+ $(SLO)$/salgdi.obj \
+ $(SLO)$/salvd.obj \
+ $(SLO)$/salprn.obj \
+ $(SLO)$/aquaprintview.obj \
+ $(SLO)$/aquaprintaccessoryview.obj \
+ $(SLO)$/salbmp.obj
+
+.IF "$(ENABLE_CAIRO)" == "TRUE"
+CDEFS+= -DCAIRO
+.ENDIF
+
+.ENDIF # "$(GUIBASE)"!="aqua"
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
+.INCLUDE : $(PRJ)$/util$/target.pmk
+
diff --git a/vcl/aqua/source/gdi/salatslayout.cxx b/vcl/aqua/source/gdi/salatslayout.cxx
new file mode 100755
index 000000000000..335505de85ac
--- /dev/null
+++ b/vcl/aqua/source/gdi/salatslayout.cxx
@@ -0,0 +1,1264 @@
+/*************************************************************************
+*
+ * 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/salgdi.hxx"
+#include "saldata.hxx"
+#include "salgdi.h"
+#include "vcl/sallayout.hxx"
+#include "salatsuifontutils.hxx"
+#include "tools/debug.hxx"
+
+#include <math.h>
+
+// =======================================================================
+
+class ATSLayout : public SalLayout
+{
+public:
+ ATSLayout( ATSUStyle&, float fFontScale );
+ virtual ~ATSLayout();
+
+ virtual bool LayoutText( ImplLayoutArgs& );
+ virtual void AdjustLayout( ImplLayoutArgs& );
+ virtual void DrawText( SalGraphics& ) const;
+
+ virtual int GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, int&,
+ sal_Int32* pGlyphAdvances, int* pCharIndexes ) const;
+
+ virtual long GetTextWidth() const;
+ virtual long FillDXArray( long* pDXArray ) const;
+ virtual int GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const;
+ virtual void GetCaretPositions( int nArraySize, long* pCaretXArray ) const;
+ virtual bool GetGlyphOutlines( SalGraphics&, PolyPolyVector& ) const;
+ virtual bool GetBoundRect( SalGraphics&, Rectangle& ) const;
+
+ const ImplFontData* GetFallbackFontData( sal_GlyphId ) const;
+
+ virtual void InitFont();
+ virtual void MoveGlyph( int nStart, long nNewXPos );
+ virtual void DropGlyph( int nStart );
+ virtual void Simplify( bool bIsBase );
+
+private:
+ ATSUStyle& mrATSUStyle;
+ ATSUTextLayout maATSULayout;
+ int mnCharCount; // ==mnEndCharPos-mnMinCharPos
+ // to prevent ATS overflowing the Fixed16.16 values
+ // ATS font requests get size limited by downscaling huge fonts
+ // in these cases the font scale becomes something bigger than 1.0
+ float mfFontScale;
+
+private:
+ bool InitGIA( ImplLayoutArgs* pArgs = NULL ) const;
+ bool GetIdealX() const;
+ bool GetDeltaY() const;
+ void InvalidateMeasurements();
+
+ int Fixed2Vcl( Fixed ) const; // convert ATSU-Fixed units to VCL units
+ int AtsuPix2Vcl( int ) const; // convert ATSU-Pixel units to VCL units
+ Fixed Vcl2Fixed( int ) const; // convert VCL units to ATSU-Fixed units
+
+ // cached details about the resulting layout
+ // mutable members since these details are all lazy initialized
+ mutable int mnGlyphCount; // glyph count
+ mutable Fixed mnCachedWidth; // cached value of resulting typographical width
+ int mnTrailingSpaceWidth; // in Pixels
+
+ mutable ATSGlyphRef* mpGlyphIds; // ATSU glyph ids
+ mutable Fixed* mpCharWidths; // map relative charpos to charwidth
+ mutable int* mpChars2Glyphs; // map relative charpos to absolute glyphpos
+ mutable int* mpGlyphs2Chars; // map absolute glyphpos to absolute charpos
+ mutable bool* mpGlyphRTLFlags; // BiDi status for glyphs: true if RTL
+ mutable Fixed* mpGlyphAdvances; // contains glyph widths for the justified layout
+ mutable Fixed* mpGlyphOrigAdvs; // contains glyph widths for the unjustified layout
+ mutable Fixed* mpDeltaY; // vertical offset from the baseline
+
+ struct SubPortion { int mnMinCharPos, mnEndCharPos; Fixed mnXOffset; };
+ typedef std::vector<SubPortion> SubPortionVector;
+ mutable SubPortionVector maSubPortions; // Writer&ATSUI layouts can differ quite a bit...
+
+ // storing details about fonts used in glyph-fallback for this layout
+ mutable class FallbackInfo* mpFallbackInfo;
+
+ // x-offset relative to layout origin
+ // currently only used in RTL-layouts
+ mutable Fixed mnBaseAdv;
+};
+
+class FallbackInfo
+{
+public:
+ FallbackInfo() : mnMaxLevel(0) {}
+ int AddFallback( ATSUFontID );
+ const ImplFontData* GetFallbackFontData( int nLevel ) const;
+
+private:
+ const ImplMacFontData* maFontData[ MAX_FALLBACK ];
+ ATSUFontID maATSUFontId[ MAX_FALLBACK ];
+ int mnMaxLevel;
+};
+
+// =======================================================================
+
+ATSLayout::ATSLayout( ATSUStyle& rATSUStyle, float fFontScale )
+: mrATSUStyle( rATSUStyle ),
+ maATSULayout( NULL ),
+ mnCharCount( 0 ),
+ mfFontScale( fFontScale ),
+ mnGlyphCount( -1 ),
+ mnCachedWidth( 0 ),
+ mnTrailingSpaceWidth( 0 ),
+ mpGlyphIds( NULL ),
+ mpCharWidths( NULL ),
+ mpChars2Glyphs( NULL ),
+ mpGlyphs2Chars( NULL ),
+ mpGlyphRTLFlags( NULL ),
+ mpGlyphAdvances( NULL ),
+ mpGlyphOrigAdvs( NULL ),
+ mpDeltaY( NULL ),
+ mpFallbackInfo( NULL ),
+ mnBaseAdv( 0 )
+{}
+
+// -----------------------------------------------------------------------
+
+ATSLayout::~ATSLayout()
+{
+ if( mpDeltaY )
+ ATSUDirectReleaseLayoutDataArrayPtr( NULL,
+ kATSUDirectDataBaselineDeltaFixedArray, (void**)&mpDeltaY );
+
+ if( maATSULayout )
+ ATSUDisposeTextLayout( maATSULayout );
+
+ delete[] mpGlyphRTLFlags;
+ delete[] mpGlyphs2Chars;
+ delete[] mpChars2Glyphs;
+ if( mpCharWidths != mpGlyphAdvances )
+ delete[] mpCharWidths;
+ delete[] mpGlyphIds;
+ delete[] mpGlyphOrigAdvs;
+ delete[] mpGlyphAdvances;
+
+ delete mpFallbackInfo;
+}
+
+// -----------------------------------------------------------------------
+
+inline int ATSLayout::Fixed2Vcl( Fixed nFixed ) const
+{
+ float fFloat = mfFontScale * FixedToFloat( nFixed );
+ return static_cast<int>(fFloat + 0.5);
+}
+
+// -----------------------------------------------------------------------
+
+inline int ATSLayout::AtsuPix2Vcl( int nAtsuPixel) const
+{
+ float fVclPixel = mfFontScale * nAtsuPixel;
+ fVclPixel += (fVclPixel>=0) ? +0.5 : -0.5; // prepare rounding to int
+ int nVclPixel = static_cast<int>( fVclPixel);
+ return nVclPixel;
+}
+
+// -----------------------------------------------------------------------
+
+inline Fixed ATSLayout::Vcl2Fixed( int nPixel ) const
+{
+ return FloatToFixed( nPixel / mfFontScale );
+}
+
+// -----------------------------------------------------------------------
+/**
+ * ATSLayout::LayoutText : Manage text layouting
+ *
+ * @param rArgs: contains array of char to be layouted, starting and ending position of the text to layout
+ *
+ * Typographic layout of text by using the style maATSUStyle
+ *
+ * @return : true if everything is ok
+**/
+bool ATSLayout::LayoutText( ImplLayoutArgs& rArgs )
+{
+ if( maATSULayout )
+ ATSUDisposeTextLayout( maATSULayout );
+
+ maATSULayout = NULL;
+
+ // Layout text
+ // set up our locals, verify parameters...
+ DBG_ASSERT( (rArgs.mpStr!=NULL), "ATSLayout::LayoutText() with rArgs.mpStr==NULL !!!");
+ DBG_ASSERT( (mrATSUStyle!=NULL), "ATSLayout::LayoutText() with ATSUStyle==NULL !!!");
+
+ SalLayout::AdjustLayout( rArgs );
+ mnCharCount = mnEndCharPos - mnMinCharPos;
+
+ // Workaround a bug in ATSUI with empty string
+ if( mnCharCount<=0 )
+ return false;
+
+#if (OSL_DEBUG_LEVEL > 3)
+ Fixed fFontSize = 0;
+ ByteCount nDummy;
+ ATSUGetAttribute( mrATSUStyle, kATSUSizeTag, sizeof(fFontSize), &fFontSize, &nDummy);
+ String aUniName( &rArgs.mpStr[rArgs.mnMinCharPos], mnCharCount );
+ ByteString aCName( aUniName, RTL_TEXTENCODING_UTF8 );
+ fprintf( stderr, "ATSLayout( \"%s\" %d..%d of %d) with h=%4.1f\n",
+ aCName.GetBuffer(),rArgs.mnMinCharPos,rArgs.mnEndCharPos,rArgs.mnLength,Fix2X(fFontSize) );
+#endif
+
+ // create the ATSUI layout
+ UniCharCount nRunLengths[1] = { mnCharCount };
+ const int nRunCount = sizeof(nRunLengths)/sizeof(*nRunLengths);
+ OSStatus eStatus = ATSUCreateTextLayoutWithTextPtr( rArgs.mpStr,
+ rArgs.mnMinCharPos, mnCharCount, rArgs.mnLength,
+ nRunCount, &nRunLengths[0], &mrATSUStyle,
+ &maATSULayout);
+
+ DBG_ASSERT( (eStatus==noErr), "ATSUCreateTextLayoutWithTextPtr failed\n");
+ if( eStatus != noErr )
+ return false;
+
+ // prepare setting of layout controls
+ static const int nMaxTagCount = 1;
+ ATSUAttributeTag aTagAttrs[ nMaxTagCount ];
+ ByteCount aTagSizes[ nMaxTagCount ];
+ ATSUAttributeValuePtr aTagValues[ nMaxTagCount ];
+
+ // prepare control of "glyph fallback"
+ const SalData* pSalData = GetSalData();
+ ATSUFontFallbacks aFontFallbacks = pSalData->mpFontList->maFontFallbacks;
+ aTagAttrs[0] = kATSULineFontFallbacksTag;
+ aTagSizes[0] = sizeof( ATSUFontFallbacks );
+ aTagValues[0] = &aFontFallbacks;
+
+ // set paragraph layout controls
+ ATSUSetLayoutControls( maATSULayout, 1, aTagAttrs, aTagSizes, aTagValues );
+
+ // enable "glyph fallback"
+ ATSUSetTransientFontMatching( maATSULayout, true );
+
+ // control run-specific layout controls
+ if( (rArgs.mnFlags & SAL_LAYOUT_BIDI_STRONG) != 0 )
+ {
+ // control BiDi defaults
+ MacOSBOOL nLineDirTag = kATSULeftToRightBaseDirection;
+ if( (rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL) != 0 )
+ nLineDirTag = kATSURightToLeftBaseDirection;
+ aTagAttrs[0] = kATSULineDirectionTag;
+ aTagSizes[0] = sizeof( nLineDirTag );
+ aTagValues[0] = &nLineDirTag;
+ // set run-specific layout controls
+#if 0 // why don't line-controls work as reliably as layout-controls???
+ ATSUSetLineControls( maATSULayout, rArgs.mnMinCharPos, 1, aTagAttrs, aTagSizes, aTagValues );
+#else
+ ATSUSetLayoutControls( maATSULayout, 1, aTagAttrs, aTagSizes, aTagValues );
+#endif
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+/**
+ * ATSLayout::AdjustLayout : Adjust layout style
+ *
+ * @param rArgs: contains attributes relevant to do a text specific layout
+ *
+ * Adjust text layout by moving glyphs to match the requested logical widths
+ *
+ * @return : none
+**/
+void ATSLayout::AdjustLayout( ImplLayoutArgs& rArgs )
+{
+ int nOrigWidth = GetTextWidth();
+ int nPixelWidth = rArgs.mnLayoutWidth;
+ if( !nPixelWidth && rArgs.mpDXArray ) {
+ // for now we are only interested in the layout width
+ // TODO: use all mpDXArray elements for layouting
+ nPixelWidth = rArgs.mpDXArray[ mnCharCount - 1 ];
+
+ // workaround for ATSUI not using trailing spaces for justification
+ int i = mnCharCount;
+ while( (--i >= 0) && IsSpacingGlyph( rArgs.mpStr[mnMinCharPos+i]|GF_ISCHAR ) ) {}
+ if( i < 0 ) // nothing to do if the text is all spaces
+ return;
+ // #i91685# trailing letters are left aligned (right aligned for RTL)
+ mnTrailingSpaceWidth = rArgs.mpDXArray[ mnCharCount-1 ];
+ if( i > 0 )
+ mnTrailingSpaceWidth -= rArgs.mpDXArray[ i-1 ];
+ InitGIA(); // ensure valid mpCharWidths[], TODO: use GetIdealX() instead?
+ mnTrailingSpaceWidth -= Fixed2Vcl( mpCharWidths[i] );
+ // ignore trailing space for calculating the available width
+ nOrigWidth -= mnTrailingSpaceWidth;
+ nPixelWidth -= mnTrailingSpaceWidth;
+ // in RTL-layouts trailing spaces are leftmost
+ // TODO: use BiDi-algorithm to thoroughly check this assumption
+ if( rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL)
+ mnBaseAdv = mnTrailingSpaceWidth;
+ }
+ // return early if there is nothing to do
+ if( !nPixelWidth )
+ return;
+
+ // HACK: justification requests which change the width by just one pixel were probably
+ // #i86038# introduced by lossy conversions between integer based coordinate system
+ // => ignoring such requests has many more benefits than eventual drawbacks
+ if( (nOrigWidth >= nPixelWidth-1) && (nOrigWidth <= nPixelWidth+1) )
+ return;
+
+ // changing the layout will make all previous measurements invalid
+ InvalidateMeasurements();
+
+ ATSUAttributeTag nTags[3];
+ ATSUAttributeValuePtr nVals[3];
+ ByteCount nBytes[3];
+
+ Fixed nFixedWidth = Vcl2Fixed( nPixelWidth );
+ mnCachedWidth = nFixedWidth;
+ Fract nFractFactor = kATSUFullJustification;
+ ATSLineLayoutOptions nLineLayoutOptions = kATSLineHasNoHangers | kATSLineHasNoOpticalAlignment | kATSLineBreakToNearestCharacter;
+
+ nTags[0] = kATSULineWidthTag;
+ nVals[0] = &nFixedWidth;
+ nBytes[0] = sizeof(Fixed);
+ nTags[1] = kATSULineLayoutOptionsTag;
+ nVals[1] = &nLineLayoutOptions;
+ nBytes[1] = sizeof(ATSLineLayoutOptions);
+ nTags[2] = kATSULineJustificationFactorTag;
+ nVals[2] = &nFractFactor;
+ nBytes[2] = sizeof(Fract);
+
+ OSStatus eStatus = ATSUSetLayoutControls( maATSULayout, 3, nTags, nBytes, nVals );
+ if( eStatus != noErr )
+ return;
+
+ // update the measurements of the justified layout to match the justification request
+ if( rArgs.mpDXArray )
+ InitGIA( &rArgs );
+}
+
+// -----------------------------------------------------------------------
+/**
+ * ATSLayout::DrawText : Draw text to screen
+ *
+ * @param rGraphics: device to draw to
+ *
+ * Draw the layouted text to the CGContext
+ *
+ * @return : none
+**/
+void ATSLayout::DrawText( SalGraphics& rGraphics ) const
+{
+ AquaSalGraphics& rAquaGraphics = static_cast<AquaSalGraphics&>(rGraphics);
+
+ // short circuit if there is nothing to do
+ if( (mnCharCount <= 0)
+ || !rAquaGraphics.CheckContext() )
+ return;
+
+ // the view is vertically flipped => flipped glyphs
+ // so apply a temporary transformation that it flips back
+ // also compensate if the font was size limited
+ CGContextSaveGState( rAquaGraphics.mrContext );
+ CGContextScaleCTM( rAquaGraphics.mrContext, +mfFontScale, -mfFontScale );
+ CGContextSetShouldAntialias( rAquaGraphics.mrContext, !rAquaGraphics.mbNonAntialiasedText );
+
+ // prepare ATSUI drawing attributes
+ static const ItemCount nMaxControls = 8;
+ ATSUAttributeTag theTags[ nMaxControls ];
+ ByteCount theSizes[ nMaxControls];
+ ATSUAttributeValuePtr theValues[ nMaxControls ];
+ ItemCount numcontrols = 0;
+
+ // Tell ATSUI to use CoreGraphics
+ theTags[numcontrols] = kATSUCGContextTag;
+ theSizes[numcontrols] = sizeof( CGContextRef );
+ theValues[numcontrols++] = &rAquaGraphics.mrContext;
+
+ // Rotate if necessary
+ if( rAquaGraphics.mnATSUIRotation != 0 )
+ {
+ Fixed theAngle = rAquaGraphics.mnATSUIRotation;
+ theTags[numcontrols] = kATSULineRotationTag;
+ theSizes[numcontrols] = sizeof( Fixed );
+ theValues[numcontrols++] = &theAngle;
+ }
+
+ DBG_ASSERT( (numcontrols <= nMaxControls), "ATSLayout::DrawText() numcontrols overflow" );
+ OSStatus theErr = ATSUSetLayoutControls (maATSULayout, numcontrols, theTags, theSizes, theValues);
+ DBG_ASSERT( (theErr==noErr), "ATSLayout::DrawText ATSUSetLayoutControls failed!\n" );
+
+ // Draw the text
+ const Point aPos = GetDrawPosition( Point(mnBaseAdv,0) );
+ const Fixed nFixedX = Vcl2Fixed( +aPos.X() );
+ const Fixed nFixedY = Vcl2Fixed( -aPos.Y() ); // adjusted for y-mirroring
+ if( maSubPortions.empty() )
+ ATSUDrawText( maATSULayout, mnMinCharPos, mnCharCount, nFixedX, nFixedY );
+ else
+ {
+ // draw the sub-portions and apply individual adjustments
+ SubPortionVector::const_iterator it = maSubPortions.begin();
+ for(; it != maSubPortions.end(); ++it )
+ {
+ const SubPortion& rSubPortion = *it;
+ // calculate sub-portion offset for rotated text
+ Fixed nXOfsFixed = 0, nYOfsFixed = 0;
+ if( rAquaGraphics.mnATSUIRotation != 0 )
+ {
+ const double fRadians = rAquaGraphics.mnATSUIRotation * (M_PI/0xB40000);
+ nXOfsFixed = static_cast<Fixed>(static_cast<double>(+rSubPortion.mnXOffset) * cos( fRadians ));
+ nYOfsFixed = static_cast<Fixed>(static_cast<double>(+rSubPortion.mnXOffset) * sin( fRadians ));
+ }
+
+ // draw sub-portions
+ ATSUDrawText( maATSULayout,
+ rSubPortion.mnMinCharPos, rSubPortion.mnEndCharPos - rSubPortion.mnMinCharPos,
+ nFixedX + nXOfsFixed, nFixedY + nYOfsFixed );
+ }
+ }
+
+ // request an update of the changed window area
+ if( rAquaGraphics.IsWindowGraphics() )
+ {
+ Rect drawRect; // rectangle of the changed area
+ theErr = ATSUMeasureTextImage( maATSULayout,
+ mnMinCharPos, mnCharCount, nFixedX, nFixedY, &drawRect );
+ if( theErr == noErr )
+ {
+ // FIXME: transformation from baseline to top left
+ // with the simple approach below we invalidate too much
+ short d = drawRect.bottom - drawRect.top;
+ drawRect.top -= d;
+ drawRect.bottom += d;
+ CGRect aRect = CGRectMake( drawRect.left, drawRect.top,
+ drawRect.right - drawRect.left,
+ drawRect.bottom - drawRect.top );
+ aRect = CGContextConvertRectToDeviceSpace( rAquaGraphics.mrContext, aRect );
+ rAquaGraphics.RefreshRect( aRect );
+ }
+ }
+
+ // restore the original graphic context transformations
+ CGContextRestoreGState( rAquaGraphics.mrContext );
+}
+
+// -----------------------------------------------------------------------
+/**
+ * ATSLayout::GetNextGlyphs : Get info about next glyphs in the layout
+ *
+ * @param nLen: max number of char
+ * @param pGlyphs: returned array of glyph ids
+ * @param rPos: returned x starting position
+ * @param nStart: index of the first requested glyph
+ * @param pGlyphAdvances: returned array of glyphs advances
+ * @param pCharIndexes: returned array of char indexes
+ *
+ * Returns infos about the next glyphs in the text layout
+ *
+ * @return : number of glyph details that were provided
+**/
+int ATSLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphIDs, Point& rPos, int& nStart,
+ sal_Int32* pGlyphAdvances, int* pCharIndexes ) const
+{
+ if( nStart < 0 ) // first glyph requested?
+ nStart = 0;
+
+ // get glyph measurements
+ InitGIA();
+ // some measurements are only needed for multi-glyph results
+ if( nLen > 1 )
+ {
+ GetIdealX();
+ GetDeltaY();
+ }
+
+ if( nStart >= mnGlyphCount ) // no glyph left?
+ return 0;
+
+ // calculate glyph position relative to layout base
+ // TODO: avoid for nStart!=0 case by reusing rPos
+ Fixed nXOffset = mnBaseAdv;
+ for( int i = 0; i < nStart; ++i )
+ nXOffset += mpGlyphAdvances[ i ];
+ // if sub-portion offsets are involved there is an additional x-offset
+ if( !maSubPortions.empty() )
+ {
+ // prepare to find the sub-portion
+ int nCharPos = nStart + mnMinCharPos;
+ if( mpGlyphs2Chars )
+ nCharPos = mpGlyphs2Chars[nStart];
+
+ // find the matching subportion
+ // TODO: is a non-linear search worth it?
+ SubPortionVector::const_iterator it = maSubPortions.begin();
+ for(; it != maSubPortions.end(); ++it) {
+ const SubPortion& r = *it;
+ if( nCharPos < r.mnMinCharPos )
+ continue;
+ if( nCharPos >= r.mnEndCharPos )
+ continue;
+ // apply the sub-portion xoffset
+ nXOffset += r.mnXOffset;
+ break;
+ }
+ }
+
+ Fixed nYOffset = 0;
+ if( mpDeltaY )
+ nYOffset = mpDeltaY[ nStart ];
+
+ // calculate absolute position in pixel units
+ const Point aRelativePos( Fix2Long(static_cast<Fixed>(nXOffset*mfFontScale)), Fix2Long(static_cast<Fixed>(nYOffset*mfFontScale)) );
+ rPos = GetDrawPosition( aRelativePos );
+
+ // update return values
+ int nCount = 0;
+ while( nCount < nLen )
+ {
+ ++nCount;
+ sal_GlyphId nGlyphId = mpGlyphIds[nStart];
+
+ // check if glyph fallback is needed for this glyph
+ // TODO: use ATSUDirectGetLayoutDataArrayPtrFromTextLayout(kATSUDirectDataStyleIndex) API instead?
+ const int nCharPos = mpGlyphs2Chars ? mpGlyphs2Chars[nStart] : nStart + mnMinCharPos;
+ ATSUFontID nFallbackFontID = kATSUInvalidFontID;
+ UniCharArrayOffset nChangedOffset = 0;
+ UniCharCount nChangedLength = 0;
+ OSStatus eStatus = ATSUMatchFontsToText( maATSULayout, nCharPos, kATSUToTextEnd,
+ &nFallbackFontID, &nChangedOffset, &nChangedLength );
+ if( (eStatus == kATSUFontsMatched) && ((int)nChangedOffset == nCharPos) )
+ {
+ // fallback is needed
+ if( !mpFallbackInfo )
+ mpFallbackInfo = new FallbackInfo;
+ // register fallback font
+ const int nLevel = mpFallbackInfo->AddFallback( nFallbackFontID );
+ // update sal_GlyphId with fallback level
+ nGlyphId |= (nLevel << GF_FONTSHIFT);
+ }
+
+ // update resulting glyphid array
+ *(pGlyphIDs++) = nGlyphId;
+
+ // update returned glyph advance array
+ if( pGlyphAdvances )
+ *(pGlyphAdvances++) = Fixed2Vcl( mpGlyphAdvances[nStart] );
+
+ // update returned index-into-string array
+ if( pCharIndexes )
+ {
+ int nCharPos;
+ if( mpGlyphs2Chars )
+ nCharPos = mpGlyphs2Chars[nStart];
+ else
+ nCharPos = nStart + mnMinCharPos;
+ *(pCharIndexes++) = nCharPos;
+ }
+
+ // stop at last glyph
+ if( ++nStart >= mnGlyphCount )
+ break;
+
+ // stop when next the x-position is unexpected
+ if( !maSubPortions.empty() )
+ break; // TODO: finish the complete sub-portion
+ if( !pGlyphAdvances && mpGlyphOrigAdvs )
+ if( mpGlyphAdvances[nStart-1] != mpGlyphOrigAdvs[nStart-1] )
+ break;
+
+ // stop when the next y-position is unexpected
+ if( mpDeltaY )
+ if( mpDeltaY[nStart-1] != mpDeltaY[nStart] )
+ break;
+ }
+
+ return nCount;
+}
+
+// -----------------------------------------------------------------------
+/**
+ * ATSLayout::GetTextWidth : Get typographic width of layouted text
+ *
+ * Get typographic bounds of the text
+ *
+ * @return : text width
+**/
+long ATSLayout::GetTextWidth() const
+{
+ if( mnCharCount <= 0 )
+ return 0;
+
+ DBG_ASSERT( (maATSULayout!=NULL), "ATSLayout::GetTextWidth() with maATSULayout==NULL !\n");
+ if( !maATSULayout )
+ return 0;
+
+ if( !mnCachedWidth )
+ {
+ // prepare precise measurements on pixel based or reference-device
+ const UInt16 eTypeOfBounds = kATSUseFractionalOrigins;
+
+ // determine number of needed measurement trapezoids
+ ItemCount nMaxBounds = 0;
+ OSStatus err = ATSUGetGlyphBounds( maATSULayout, 0, 0, mnMinCharPos, mnCharCount,
+ eTypeOfBounds, 0, NULL, &nMaxBounds );
+ if( (err != noErr)
+ || (nMaxBounds <= 0) )
+ return 0;
+
+ // get the trapezoids
+ typedef std::vector<ATSTrapezoid> TrapezoidVector;
+ TrapezoidVector aTrapezoidVector( nMaxBounds );
+ ItemCount nBoundsCount = 0;
+ err = ATSUGetGlyphBounds( maATSULayout, 0, 0, mnMinCharPos, mnCharCount,
+ eTypeOfBounds, nMaxBounds, &aTrapezoidVector[0], &nBoundsCount );
+ if( err != noErr )
+ return 0;
+
+ DBG_ASSERT( (nBoundsCount <= nMaxBounds), "ATSLayout::GetTextWidth() : too many trapezoids !\n");
+
+ // find the bound extremas
+ Fixed nLeftBound = 0;
+ Fixed nRightBound = 0;
+ for( ItemCount i = 0; i < nBoundsCount; ++i )
+ {
+ const ATSTrapezoid& rTrap = aTrapezoidVector[i];
+ if( (i == 0) || (nLeftBound < rTrap.lowerLeft.x) )
+ nLeftBound = rTrap.lowerLeft.x;
+ if( (i == 0) || (nRightBound > rTrap.lowerRight.x) )
+ nRightBound = rTrap.lowerRight.x;
+ }
+
+ // measure the bound extremas
+ mnCachedWidth = nRightBound - nLeftBound;
+ // adjust for eliminated trailing space widths
+ }
+
+ int nScaledWidth = Fixed2Vcl( mnCachedWidth );
+ nScaledWidth += mnTrailingSpaceWidth;
+ return nScaledWidth;
+}
+
+// -----------------------------------------------------------------------
+/**
+ * ATSLayout::FillDXArray : Get Char widths
+ *
+ * @param pDXArray: array to be filled with x-advances
+ *
+ * Fill the pDXArray with horizontal deltas : CharWidths
+ *
+ * @return : typographical width of the complete text layout
+**/
+long ATSLayout::FillDXArray( long* pDXArray ) const
+{
+ // short circuit requests which don't need full details
+ if( !pDXArray )
+ return GetTextWidth();
+
+ // check assumptions
+ DBG_ASSERT( !mnTrailingSpaceWidth, "ATSLayout::FillDXArray() with nTSW!=0" );
+
+ // initialize details about the resulting layout
+ InitGIA();
+
+ // distribute the widths among the string elements
+ int nPixWidth = 0;
+ mnCachedWidth = 0;
+ for( int i = 0; i < mnCharCount; ++i )
+ {
+ // convert and adjust for accumulated rounding errors
+ mnCachedWidth += mpCharWidths[i];
+ const int nOldPixWidth = nPixWidth;
+ nPixWidth = Fixed2Vcl( mnCachedWidth );
+ pDXArray[i] = nPixWidth - nOldPixWidth;
+ }
+
+ return nPixWidth;
+}
+
+// -----------------------------------------------------------------------
+/**
+ * ATSLayout::GetTextBreak : Find line break depending on width
+ *
+ * @param nMaxWidth : maximal logical text width in subpixel units
+ * @param nCharExtra: expanded/condensed spacing in subpixel units
+ * @param nFactor: number of subpixel units per pixel
+ *
+ * Measure the layouted text to find the typographical line break
+ * the result is needed by the language specific line breaking
+ *
+ * @return : string index corresponding to the suggested line break
+**/
+int ATSLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const
+{
+ if( !maATSULayout )
+ return STRING_LEN;
+
+ // the semantics of the legacy use case (nCharExtra!=0) cannot be mapped to ATSUBreakLine()
+ if( nCharExtra != 0 )
+ {
+ // prepare the measurement by layouting and measuring the un-expanded/un-condensed text
+ if( !InitGIA() )
+ return STRING_LEN;
+
+ // TODO: use a better way than by testing each the char position
+ ATSUTextMeasurement nATSUSumWidth = 0;
+ const ATSUTextMeasurement nATSUMaxWidth = Vcl2Fixed( nMaxWidth / nFactor );
+ const ATSUTextMeasurement nATSUExtraWidth = Vcl2Fixed( nCharExtra ) / nFactor;
+ for( int i = 0; i < mnCharCount; ++i )
+ {
+ nATSUSumWidth += mpCharWidths[i];
+ if( nATSUSumWidth >= nATSUMaxWidth )
+ return (mnMinCharPos + i);
+ nATSUSumWidth += nATSUExtraWidth;
+ if( nATSUSumWidth >= nATSUMaxWidth )
+ if( i+1 < mnCharCount )
+ return (mnMinCharPos + i);
+ }
+
+ return STRING_LEN;
+ }
+
+ // get a quick overview on what could fit
+ const long nPixelWidth = (nMaxWidth - (nCharExtra * mnCharCount)) / nFactor;
+ if( nPixelWidth <= 0 )
+ return mnMinCharPos;
+
+ // check assumptions
+ DBG_ASSERT( !mnTrailingSpaceWidth, "ATSLayout::GetTextBreak() with nTSW!=0" );
+
+ // initial measurement of text break position
+ UniCharArrayOffset nBreakPos = mnMinCharPos;
+ const ATSUTextMeasurement nATSUMaxWidth = Vcl2Fixed( nPixelWidth );
+ OSStatus eStatus = ATSUBreakLine( maATSULayout, mnMinCharPos,
+ nATSUMaxWidth, false, &nBreakPos );
+
+ if( (eStatus != noErr) && (eStatus != kATSULineBreakInWord) )
+ return STRING_LEN;
+
+ // the result from ATSUBreakLine() doesn't match the semantics expected by its
+ // application layer callers from SW+SVX+I18N. Adjust the results to the expectations:
+
+ // ATSU reports that everything fits even when trailing spaces would break the line
+ // #i89789# OOo's application layers expect STRING_LEN if everything fits
+ if( nBreakPos >= static_cast<UniCharArrayOffset>(mnEndCharPos) )
+ return STRING_LEN;
+
+ // GetTextBreak()'s callers expect it to return the "stupid visual line break".
+ // Returning anything else result.s in subtle problems in the application layers.
+ static const bool bInWord = true; // TODO: add as argument to GetTextBreak() method
+ if( !bInWord )
+ return nBreakPos;
+
+ // emulate stupid visual line breaking by line breaking for the remaining width
+ ATSUTextMeasurement nLeft, nRight, nDummy;
+ eStatus = ATSUGetUnjustifiedBounds( maATSULayout, mnMinCharPos, nBreakPos-mnMinCharPos,
+ &nLeft, &nRight, &nDummy, &nDummy );
+ if( eStatus != noErr )
+ return nBreakPos;
+ const ATSUTextMeasurement nATSURemWidth = nATSUMaxWidth - (nRight - nLeft);
+ if( nATSURemWidth <= 0 )
+ return nBreakPos;
+ UniCharArrayOffset nBreakPosInWord = nBreakPos;
+ eStatus = ATSUBreakLine( maATSULayout, nBreakPos, nATSURemWidth, false, &nBreakPosInWord );
+ return nBreakPosInWord;
+}
+
+// -----------------------------------------------------------------------
+/**
+ * ATSLayout::GetCaretPositions : Find positions of carets
+ *
+ * @param nMaxIndex position to which we want to find the carets
+ *
+ * Fill the array of positions of carets (for cursors and selections)
+ *
+ * @return : none
+**/
+void ATSLayout::GetCaretPositions( int nMaxIndex, long* pCaretXArray ) const
+{
+ DBG_ASSERT( ((nMaxIndex>0)&&!(nMaxIndex&1)),
+ "ATSLayout::GetCaretPositions() : invalid number of caret pairs requested");
+
+ // initialize the caret positions
+ for( int i = 0; i < nMaxIndex; ++i )
+ pCaretXArray[ i ] = -1;
+
+ for( int n = 0; n <= mnCharCount; ++n )
+ {
+ // measure the characters cursor position
+ typedef unsigned char Boolean;
+ const Boolean bIsLeading = true;
+ ATSUCaret aCaret0, aCaret1;
+ Boolean bIsSplit;
+ OSStatus eStatus = ATSUOffsetToCursorPosition( maATSULayout,
+ mnMinCharPos + n, bIsLeading, kATSUByCharacter,
+ &aCaret0, &aCaret1, &bIsSplit );
+ if( eStatus != noErr )
+ continue;
+ const Fixed nFixedPos = mnBaseAdv + aCaret0.fX;
+ // convert the measurement to pixel units
+ const int nPixelPos = Fixed2Vcl( nFixedPos );
+ // update previous trailing position
+ if( n > 0 )
+ pCaretXArray[2*n-1] = nPixelPos;
+ // update current leading position
+ if( 2*n >= nMaxIndex )
+ break;
+ pCaretXArray[2*n+0] = nPixelPos;
+ }
+}
+
+// -----------------------------------------------------------------------
+/**
+ * ATSLayout::GetBoundRect : Get rectangle dim containing the layouted text
+ *
+ * @param rVCLRect: rectangle of text image (layout) measures
+ *
+ * Get ink bounds of the text
+ *
+ * @return : measurement valid
+**/
+bool ATSLayout::GetBoundRect( SalGraphics&, Rectangle& rVCLRect ) const
+{
+ const Point aPos = GetDrawPosition( Point(mnBaseAdv, 0) );
+ const Fixed nFixedX = Vcl2Fixed( +aPos.X() );
+ const Fixed nFixedY = Vcl2Fixed( +aPos.Y() );
+
+ Rect aMacRect;
+ OSStatus eStatus = ATSUMeasureTextImage( maATSULayout,
+ mnMinCharPos, mnCharCount, nFixedX, nFixedY, &aMacRect );
+ if( eStatus != noErr )
+ return false;
+
+ // ATSU top-bottom are vertically flipped from a VCL aspect
+ rVCLRect.Left() = AtsuPix2Vcl( aMacRect.left );
+ rVCLRect.Top() = AtsuPix2Vcl( aMacRect.top );
+ rVCLRect.Right() = AtsuPix2Vcl( aMacRect.right );
+ rVCLRect.Bottom() = AtsuPix2Vcl( aMacRect.bottom );
+ return true;
+}
+
+// -----------------------------------------------------------------------
+/**
+ * ATSLayout::InitGIA() : get many informations about layouted text
+ *
+ * Fills arrays of information about the gylph layout previously done
+ * in ASTLayout::LayoutText() : glyph advance (width), glyph delta Y (from baseline),
+ * mapping between glyph index and character index, chars widths
+ *
+ * @return : true if everything could be computed, otherwise false
+**/
+bool ATSLayout::InitGIA( ImplLayoutArgs* pArgs ) const
+{
+ // no need to run InitGIA more than once on the same ATSLayout object
+ if( mnGlyphCount >= 0 )
+ return true;
+ mnGlyphCount = 0;
+
+ // Workaround a bug in ATSUI with empty string
+ if( mnCharCount <= 0 )
+ return false;
+
+ // initialize character details
+ mpCharWidths = new Fixed[ mnCharCount ];
+ mpChars2Glyphs = new int[ mnCharCount ];
+ for( int n = 0; n < mnCharCount; ++n )
+ {
+ mpCharWidths[ n ] = 0;
+ mpChars2Glyphs[ n ] = -1;
+ }
+
+ // get details about the glyph layout
+ ItemCount iLayoutDataCount;
+ const ATSLayoutRecord* pALR;
+ OSStatus eStatus = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(
+ maATSULayout, mnMinCharPos, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
+ (void**)&pALR, &iLayoutDataCount );
+ DBG_ASSERT( (eStatus==noErr), "ATSLayout::InitGIA() : no ATSLayoutRecords!\n");
+ if( (eStatus != noErr)
+ || (iLayoutDataCount <= 1) )
+ return false;
+
+ // initialize glyph details
+ mpGlyphIds = new ATSGlyphRef[ iLayoutDataCount ];
+ mpGlyphAdvances = new Fixed[ iLayoutDataCount ];
+ mpGlyphs2Chars = new int[ iLayoutDataCount ];
+
+ // measure details of the glyph layout
+ Fixed nLeftPos = 0;
+ for( ItemCount i = 0; i < iLayoutDataCount; ++i )
+ {
+ const ATSLayoutRecord& rALR = pALR[i];
+
+ // distribute the widths as fairly as possible among the chars
+ const int nRelativeIdx = (rALR.originalOffset / 2);
+ if( i+1 < iLayoutDataCount )
+ mpCharWidths[ nRelativeIdx ] += pALR[i+1].realPos - rALR.realPos;
+
+ // new glyph is available => finish measurement of old glyph
+ if( mnGlyphCount > 0 )
+ mpGlyphAdvances[ mnGlyphCount-1 ] = rALR.realPos - nLeftPos;
+
+ // ignore marker or deleted glyphs
+ enum { MARKED_OUTGLYPH=0xFFFE, DROPPED_OUTGLYPH=0xFFFF};
+ if( rALR.glyphID >= MARKED_OUTGLYPH )
+ continue;
+
+ DBG_ASSERT( !(rALR.flags & kATSGlyphInfoTerminatorGlyph),
+ "ATSLayout::InitGIA(): terminator glyph not marked as deleted!" );
+
+ // store details of the visible glyphs
+ nLeftPos = rALR.realPos;
+ mpGlyphIds[ mnGlyphCount ] = rALR.glyphID;
+
+ // map visible glyphs to their counterparts in the UTF16-character array
+ mpGlyphs2Chars[ mnGlyphCount ] = nRelativeIdx + mnMinCharPos;
+ mpChars2Glyphs[ nRelativeIdx ] = mnGlyphCount;
+
+ ++mnGlyphCount;
+ }
+
+ // measure complete width
+ mnCachedWidth = mnBaseAdv;
+ mnCachedWidth += pALR[iLayoutDataCount-1].realPos - pALR[0].realPos;
+
+#if (OSL_DEBUG_LEVEL > 1)
+ Fixed nWidthSum = mnBaseAdv;
+ for( int n = 0; n < mnCharCount; ++n )
+ nWidthSum += mpCharWidths[ n ];
+ DBG_ASSERT( (nWidthSum==mnCachedWidth),
+ "ATSLayout::InitGIA(): measured widths do not match!\n" );
+#endif
+
+ // #i91183# we need to split up the portion into sub-portions
+ // if the ATSU-layout differs too much from the requested layout
+ if( pArgs && pArgs->mpDXArray )
+ {
+ // TODO: non-strong-LTR case cases should be handled too
+ if( (pArgs->mnFlags & TEXT_LAYOUT_BIDI_STRONG)
+ && !(pArgs->mnFlags & TEXT_LAYOUT_BIDI_RTL) )
+ {
+ Fixed nSumCharWidths = 0;
+ SubPortion aSubPortion = { mnMinCharPos, 0, 0 };
+ for( int i = 0; i < mnCharCount; ++i )
+ {
+ // calculate related logical position
+ nSumCharWidths += mpCharWidths[i];
+
+ // start new sub-portion if needed
+ const Fixed nNextXPos = Vcl2Fixed(pArgs->mpDXArray[i]);
+ const Fixed nNextXOffset = nNextXPos - nSumCharWidths;
+ const Fixed nFixedDiff = aSubPortion.mnXOffset - nNextXOffset;
+ if( (nFixedDiff < -0xC000) || (nFixedDiff > +0xC000) ) {
+ // get to the end of the current sub-portion
+ // prevent splitting up at diacritics etc.
+ int j = i;
+ while( (++j < mnCharCount) && !mpCharWidths[j] );
+ aSubPortion.mnEndCharPos = mnMinCharPos + j;
+ // emit current sub-portion
+ maSubPortions.push_back( aSubPortion );
+ // prepare next sub-portion
+ aSubPortion.mnMinCharPos = aSubPortion.mnEndCharPos;
+ aSubPortion.mnXOffset = nNextXOffset;
+ }
+ }
+
+ // emit the remaining sub-portion
+ if( !maSubPortions.empty() )
+ {
+ aSubPortion.mnEndCharPos = mnEndCharPos;
+ if( aSubPortion.mnEndCharPos != aSubPortion.mnMinCharPos )
+ maSubPortions.push_back( aSubPortion );
+ }
+ }
+
+ // override layouted charwidths with requested charwidths
+ for( int n = 0; n < mnCharCount; ++n )
+ mpCharWidths[ n ] = pArgs->mpDXArray[ n ];
+ }
+
+ // release the ATSU layout records
+ ATSUDirectReleaseLayoutDataArrayPtr(NULL,
+ kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void**)&pALR );
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+bool ATSLayout::GetIdealX() const
+{
+ // compute the ideal advance widths only once
+ if( mpGlyphOrigAdvs != NULL )
+ return true;
+
+ DBG_ASSERT( (mpGlyphIds!=NULL), "GetIdealX() called with mpGlyphIds==NULL !" );
+ DBG_ASSERT( (mrATSUStyle!=NULL), "GetIdealX called with mrATSUStyle==NULL !" );
+
+ // TODO: cache ideal metrics per glyph?
+ std::vector<ATSGlyphIdealMetrics> aIdealMetrics;
+ aIdealMetrics.resize( mnGlyphCount );
+ OSStatus theErr = ATSUGlyphGetIdealMetrics( mrATSUStyle,
+ mnGlyphCount, &mpGlyphIds[0], sizeof(*mpGlyphIds), &aIdealMetrics[0] );
+ DBG_ASSERT( (theErr==noErr), "ATSUGlyphGetIdealMetrics failed!");
+ if( theErr != noErr )
+ return false;
+
+ mpGlyphOrigAdvs = new Fixed[ mnGlyphCount ];
+ for( int i = 0;i < mnGlyphCount;++i )
+ mpGlyphOrigAdvs[i] = FloatToFixed( aIdealMetrics[i].advance.x );
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+bool ATSLayout::GetDeltaY() const
+{
+ // don't bother to get the same delta-y-array more than once
+ if( mpDeltaY != NULL )
+ return true;
+
+#if 1
+ if( !maATSULayout )
+ return false;
+
+ // get and keep the y-deltas in the mpDeltaY member variable
+ // => release it in the destructor
+ ItemCount nDeltaCount = 0;
+ OSStatus theErr = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(
+ maATSULayout, mnMinCharPos, kATSUDirectDataBaselineDeltaFixedArray,
+ (void**)&mpDeltaY, &nDeltaCount );
+
+ DBG_ASSERT( (theErr==noErr ), "mpDeltaY - ATSUDirectGetLayoutDataArrayPtrFromTextLayout failed!\n");
+ if( theErr != noErr )
+ return false;
+
+ if( mpDeltaY == NULL )
+ return true;
+
+ if( nDeltaCount != (ItemCount)mnGlyphCount )
+ {
+ DBG_WARNING( "ATSLayout::GetDeltaY() : wrong deltaY count!" );
+ ATSUDirectReleaseLayoutDataArrayPtr( NULL,
+ kATSUDirectDataBaselineDeltaFixedArray, (void**)&mpDeltaY );
+ mpDeltaY = NULL;
+ return false;
+ }
+#endif
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+#define DELETEAZ( X ) { delete[] X; X = NULL; }
+
+void ATSLayout::InvalidateMeasurements()
+{
+ mnGlyphCount = -1;
+ DELETEAZ( mpGlyphIds );
+ DELETEAZ( mpCharWidths );
+ DELETEAZ( mpChars2Glyphs );
+ DELETEAZ( mpGlyphs2Chars );
+ DELETEAZ( mpGlyphRTLFlags );
+ DELETEAZ( mpGlyphAdvances );
+ DELETEAZ( mpGlyphOrigAdvs );
+ DELETEAZ( mpDeltaY );
+}
+
+// =======================================================================
+
+#if 0
+// helper class to convert ATSUI outlines to VCL PolyPolygons
+class PolyArgs
+{
+public:
+ PolyArgs();
+ ~PolyArgs();
+
+ void Init( PolyPolygon* pPolyPoly, long nXOffset, long nYOffset );
+ void AddPoint( const Float32Point&, PolyFlags );
+ void ClosePolygon();
+
+private:
+ PolyPolygon* mpPolyPoly;
+ long mnXOffset, mnYOffset;
+
+ Point* mpPointAry;
+ BYTE* mpFlagAry;
+ USHORT mnMaxPoints;
+
+ USHORT mnPointCount;
+ USHORT mnPolyCount;
+ bool mbHasOffline;
+};
+
+// -----------------------------------------------------------------------
+
+PolyArgs::PolyArgs()
+: mpPolyPoly(NULL),
+ mnPointCount(0),
+ mnPolyCount(0),
+ mbHasOffline(false)
+{
+ mnMaxPoints = 256;
+ mpPointAry = new Point[ mnMaxPoints ];
+ mpFlagAry = new BYTE [ mnMaxPoints ];
+}
+
+// -----------------------------------------------------------------------
+
+PolyArgs::~PolyArgs()
+{
+ delete[] mpFlagAry;
+ delete[] mpPointAry;
+}
+
+// -----------------------------------------------------------------------
+
+void PolyArgs::Init( PolyPolygon* pPolyPoly, long nXOffset, long nYOffset )
+{
+ mnXOffset = nXOffset;
+ mnYOffset = nYOffset;
+ mpPolyPoly = pPolyPoly;
+
+ mpPolyPoly->Clear();
+ mnPointCount = 0;
+ mnPolyCount = 0;
+}
+
+// -----------------------------------------------------------------------
+
+void PolyArgs::AddPoint( const Float32Point& rPoint, PolyFlags eFlags )
+{
+ if( mnPointCount >= mnMaxPoints )
+ {
+ // resize if needed (TODO: use STL?)
+ mnMaxPoints *= 4;
+ Point* mpNewPoints = new Point[ mnMaxPoints ];
+ BYTE* mpNewFlags = new BYTE[ mnMaxPoints ];
+ for( int i = 0; i < mnPointCount; ++i )
+ {
+ mpNewPoints[ i ] = mpPointAry[ i ];
+ mpNewFlags[ i ] = mpFlagAry[ i ];
+ }
+ delete[] mpFlagAry;
+ delete[] mpPointAry;
+ mpPointAry = mpNewPoints;
+ mpFlagAry = mpNewFlags;
+ }
+
+ // convert to pixels and add startpoint offset
+ int nXPos = Float32ToInt( rPoint.x );
+ int nYPos = Float32ToInt( rPoint.y );
+ mpPointAry[ mnPointCount ] = Point( nXPos + mnXOffset, nYPos + mnYOffset );
+ // set point flags
+ mpFlagAry[ mnPointCount++ ]= eFlags;
+ mbHasOffline |= (eFlags != POLY_NORMAL);
+}
+
+// -----------------------------------------------------------------------
+
+void PolyArgs::ClosePolygon()
+{
+ if( !mnPolyCount++ )
+ return;
+
+ // append finished polygon
+ Polygon aPoly( mnPointCount, mpPointAry, (mbHasOffline ? mpFlagAry : NULL) );
+ mpPolyPoly->Insert( aPoly );
+
+ // prepare for new polygon
+ mnPointCount = 0;
+ mbHasOffline = false;
+}
+#endif
+// =======================================================================
+
+// glyph fallback is supported directly by Aqua
+// so methods used only by MultiSalLayout can be dummy implementated
+bool ATSLayout::GetGlyphOutlines( SalGraphics&, PolyPolyVector& rPPV ) const { return false; }
+void ATSLayout::InitFont() {}
+void ATSLayout::MoveGlyph( int /*nStart*/, long /*nNewXPos*/ ) {}
+void ATSLayout::DropGlyph( int /*nStart*/ ) {}
+void ATSLayout::Simplify( bool /*bIsBase*/ ) {}
+
+// get the ImplFontData for a glyph fallback font
+// for a glyphid that was returned by ATSLayout::GetNextGlyphs()
+const ImplFontData* ATSLayout::GetFallbackFontData( sal_GlyphId nGlyphId ) const
+{
+ // check if any fallback fonts were needed
+ if( !mpFallbackInfo )
+ return NULL;
+ // check if the current glyph needs a fallback font
+ int nFallbackLevel = (nGlyphId & GF_FONTMASK) >> GF_FONTSHIFT;
+ if( !nFallbackLevel )
+ return NULL;
+ return mpFallbackInfo->GetFallbackFontData( nFallbackLevel );
+}
+
+// =======================================================================
+
+int FallbackInfo::AddFallback( ATSUFontID nFontId )
+{
+ // check if the fallback font is already known
+ for( int nLevel = 0; nLevel < mnMaxLevel; ++nLevel )
+ if( maATSUFontId[ nLevel ] == nFontId )
+ return (nLevel + 1);
+
+ // append new fallback font if possible
+ if( mnMaxLevel >= MAX_FALLBACK-1 )
+ return 0;
+ // keep ATSU font id of fallback font
+ maATSUFontId[ mnMaxLevel ] = nFontId;
+ // find and cache the corresponding ImplFontData pointer
+ const SystemFontList* pSFL = GetSalData()->mpFontList;
+ const ImplMacFontData* pFontData = pSFL->GetFontDataFromId( nFontId );
+ maFontData[ mnMaxLevel ] = pFontData;
+ // increase fallback level by one
+ return (++mnMaxLevel);
+}
+
+// -----------------------------------------------------------------------
+
+const ImplFontData* FallbackInfo::GetFallbackFontData( int nFallbackLevel ) const
+{
+ const ImplMacFontData* pFallbackFont = maFontData[ nFallbackLevel-1 ];
+ return pFallbackFont;
+}
+
+// =======================================================================
+
+SalLayout* AquaSalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLevel )
+{
+ ATSLayout* pATSLayout = new ATSLayout( maATSUStyle, mfFontScale );
+ return pATSLayout;
+}
+
+// =======================================================================
+
diff --git a/vcl/aqua/source/gdi/salatsuifontutils.cxx b/vcl/aqua/source/gdi/salatsuifontutils.cxx
new file mode 100644
index 000000000000..8281c41ceeab
--- /dev/null
+++ b/vcl/aqua/source/gdi/salatsuifontutils.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 <boost/assert.hpp>
+#include <vector>
+#include <set>
+
+#include "salgdi.h"
+#include "saldata.hxx"
+#include "vcl/svapp.hxx"
+#include "salatsuifontutils.hxx"
+
+// we have to get the font attributes from the name table
+// since neither head's macStyle nor OS/2's panose are easily available
+// during font enumeration. macStyle bits would be not sufficient anyway
+// and SFNT fonts on Mac usually do not contain an OS/2 table.
+static void UpdateAttributesFromPSName( const String& rPSName, ImplDevFontAttributes& rDFA )
+{
+ ByteString aPSName( rPSName, RTL_TEXTENCODING_UTF8 );
+ aPSName.ToLowerAscii();
+
+ // TODO: use a multi-string ignore-case matcher once it becomes available
+ if( (aPSName.Search("regular") != STRING_NOTFOUND)
+ || (aPSName.Search("normal") != STRING_NOTFOUND)
+ || (aPSName.Search("roman") != STRING_NOTFOUND)
+ || (aPSName.Search("medium") != STRING_NOTFOUND)
+ || (aPSName.Search("plain") != STRING_NOTFOUND)
+ || (aPSName.Search("standard") != STRING_NOTFOUND)
+ || (aPSName.Search("std") != STRING_NOTFOUND) )
+ {
+ rDFA.meWidthType = WIDTH_NORMAL;
+ rDFA.meWeight = WEIGHT_NORMAL;
+ rDFA.meItalic = ITALIC_NONE;
+ }
+
+ // heuristics for font weight
+ if (aPSName.Search("extrablack") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_BLACK;
+ else if (aPSName.Search("black") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_BLACK;
+ //else if (aPSName.Search("book") != STRING_NOTFOUND)
+ // rDFA.meWeight = WEIGHT_SEMIBOLD;
+ else if( (aPSName.Search("semibold") != STRING_NOTFOUND)
+ || (aPSName.Search("smbd") != STRING_NOTFOUND))
+ rDFA.meWeight = WEIGHT_SEMIBOLD;
+ else if (aPSName.Search("ultrabold") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_ULTRABOLD;
+ else if (aPSName.Search("extrabold") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_BLACK;
+ else if( (aPSName.Search("bold") != STRING_NOTFOUND)
+ || (aPSName.Search("-bd") != STRING_NOTFOUND))
+ rDFA.meWeight = WEIGHT_BOLD;
+ else if (aPSName.Search("extralight") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_ULTRALIGHT;
+ else if (aPSName.Search("ultralight") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_ULTRALIGHT;
+ else if (aPSName.Search("light") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_LIGHT;
+ else if (aPSName.Search("thin") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_THIN;
+ else if (aPSName.Search("-w3") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_LIGHT;
+ else if (aPSName.Search("-w4") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_SEMILIGHT;
+ else if (aPSName.Search("-w5") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_NORMAL;
+ else if (aPSName.Search("-w6") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_SEMIBOLD;
+ else if (aPSName.Search("-w7") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_BOLD;
+ else if (aPSName.Search("-w8") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_ULTRABOLD;
+ else if (aPSName.Search("-w9") != STRING_NOTFOUND)
+ rDFA.meWeight = WEIGHT_BLACK;
+
+ // heuristics for font slant
+ if( (aPSName.Search("italic") != STRING_NOTFOUND)
+ || (aPSName.Search(" ital") != STRING_NOTFOUND)
+ || (aPSName.Search("cursive") != STRING_NOTFOUND)
+ || (aPSName.Search("-it") != STRING_NOTFOUND)
+ || (aPSName.Search("lightit") != STRING_NOTFOUND)
+ || (aPSName.Search("mediumit") != STRING_NOTFOUND)
+ || (aPSName.Search("boldit") != STRING_NOTFOUND)
+ || (aPSName.Search("cnit") != STRING_NOTFOUND)
+ || (aPSName.Search("bdcn") != STRING_NOTFOUND)
+ || (aPSName.Search("bdit") != STRING_NOTFOUND)
+ || (aPSName.Search("condit") != STRING_NOTFOUND)
+ || (aPSName.Search("bookit") != STRING_NOTFOUND)
+ || (aPSName.Search("blackit") != STRING_NOTFOUND) )
+ rDFA.meItalic = ITALIC_NORMAL;
+ if( (aPSName.Search("oblique") != STRING_NOTFOUND)
+ || (aPSName.Search("inclined") != STRING_NOTFOUND)
+ || (aPSName.Search("slanted") != STRING_NOTFOUND) )
+ rDFA.meItalic = ITALIC_OBLIQUE;
+
+ // heuristics for font width
+ if( (aPSName.Search("condensed") != STRING_NOTFOUND)
+ || (aPSName.Search("-cond") != STRING_NOTFOUND)
+ || (aPSName.Search("boldcond") != STRING_NOTFOUND)
+ || (aPSName.Search("boldcn") != STRING_NOTFOUND)
+ || (aPSName.Search("cnit") != STRING_NOTFOUND) )
+ rDFA.meWidthType = WIDTH_CONDENSED;
+ else if (aPSName.Search("narrow") != STRING_NOTFOUND)
+ rDFA.meWidthType = WIDTH_SEMI_CONDENSED;
+ else if (aPSName.Search("expanded") != STRING_NOTFOUND)
+ rDFA.meWidthType = WIDTH_EXPANDED;
+ else if (aPSName.Search("wide") != STRING_NOTFOUND)
+ rDFA.meWidthType = WIDTH_EXPANDED;
+
+ // heuristics for font pitch
+ if( (aPSName.Search("mono") != STRING_NOTFOUND)
+ || (aPSName.Search("courier") != STRING_NOTFOUND)
+ || (aPSName.Search("monaco") != STRING_NOTFOUND)
+ || (aPSName.Search("typewriter") != STRING_NOTFOUND) )
+ rDFA.mePitch = PITCH_FIXED;
+
+ // heuristics for font family type
+ if( (aPSName.Search("script") != STRING_NOTFOUND)
+ || (aPSName.Search("chancery") != STRING_NOTFOUND)
+ || (aPSName.Search("zapfino") != STRING_NOTFOUND))
+ rDFA.meFamily = FAMILY_SCRIPT;
+ else if( (aPSName.Search("comic") != STRING_NOTFOUND)
+ || (aPSName.Search("outline") != STRING_NOTFOUND)
+ || (aPSName.Search("pinpoint") != STRING_NOTFOUND) )
+ rDFA.meFamily = FAMILY_DECORATIVE;
+ else if( (aPSName.Search("sans") != STRING_NOTFOUND)
+ || (aPSName.Search("arial") != STRING_NOTFOUND) )
+ rDFA.meFamily = FAMILY_SWISS;
+ else if( (aPSName.Search("roman") != STRING_NOTFOUND)
+ || (aPSName.Search("times") != STRING_NOTFOUND) )
+ rDFA.meFamily = FAMILY_ROMAN;
+
+ // heuristics for codepoint semantic
+ if( (aPSName.Search("symbol") != STRING_NOTFOUND)
+ || (aPSName.Search("dings") != STRING_NOTFOUND)
+ || (aPSName.Search("dingbats") != STRING_NOTFOUND)
+ || (aPSName.Search("ornaments") != STRING_NOTFOUND)
+ || (aPSName.Search("embellishments") != STRING_NOTFOUND) )
+ rDFA.mbSymbolFlag = true;
+
+ // #i100020# special heuristic for names with single-char styles
+ // NOTE: we are checking name that hasn't been lower-cased
+ if( rPSName.Len() > 3 )
+ {
+ int i = rPSName.Len();
+ sal_Unicode c = rPSName.GetChar( --i );
+ if( c == 'C' ) { // "capitals"
+ rDFA.meFamily = FAMILY_DECORATIVE;
+ c = rPSName.GetChar( --i );
+ }
+ if( c == 'O' ) { // CFF-based OpenType
+ c = rPSName.GetChar( --i );
+ }
+ if( c == 'I' ) { // "italic"
+ rDFA.meItalic = ITALIC_NORMAL;
+ c = rPSName.GetChar( --i );
+ }
+ if( c == 'B' ) // "bold"
+ rDFA.meWeight = WEIGHT_BOLD;
+ if( c == 'C' ) // "capitals"
+ rDFA.meFamily = FAMILY_DECORATIVE;
+ // TODO: check that all single-char styles have been resolved?
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static bool GetDevFontAttributes( ATSUFontID nFontID, ImplDevFontAttributes& rDFA )
+{
+ // all ATSU fonts are device fonts that can be directly rotated
+ rDFA.mbOrientation = true;
+ rDFA.mbDevice = true;
+ rDFA.mnQuality = 0;
+
+ // reset the attributes
+ rDFA.meFamily = FAMILY_DONTKNOW;
+ rDFA.mePitch = PITCH_VARIABLE;
+ rDFA.meWidthType = WIDTH_NORMAL;
+ rDFA.meWeight = WEIGHT_NORMAL;
+ rDFA.meItalic = ITALIC_NONE;
+ rDFA.mbSymbolFlag = false;
+
+ // ignore bitmap fonts
+ ATSFontRef rATSFontRef = FMGetATSFontRefFromFont( nFontID );
+ ByteCount nHeadLen = 0;
+ OSStatus rc = ATSFontGetTable( rATSFontRef, 0x68656164/*head*/, 0, 0, NULL, &nHeadLen );
+ if( (rc != noErr) || (nHeadLen <= 0) )
+ return false;
+
+ // all scalable fonts on this platform are subsettable
+ rDFA.mbSubsettable = true;
+ rDFA.mbEmbeddable = false;
+
+ // prepare iterating over all name strings of the font
+ ItemCount nFontNameCount = 0;
+ rc = ATSUCountFontNames( nFontID, &nFontNameCount );
+ if( rc != noErr )
+ return false;
+ int nBestNameValue = 0;
+ int nBestStyleValue = 0;
+ FontLanguageCode eBestLangCode = 0;
+ const FontLanguageCode eUILangCode = Application::GetSettings().GetUILanguage();
+ typedef std::vector<char> NameBuffer;
+ NameBuffer aNameBuffer( 256 );
+
+ // iterate over all available name strings of the font
+ for( ItemCount nNameIndex = 0; nNameIndex < nFontNameCount; ++nNameIndex )
+ {
+ ByteCount nNameLength = 0;
+
+ FontNameCode eFontNameCode;
+ FontPlatformCode eFontNamePlatform;
+ FontScriptCode eFontNameScript;
+ FontLanguageCode eFontNameLanguage;
+ rc = ATSUGetIndFontName( nFontID, nNameIndex, 0, NULL,
+ &nNameLength, &eFontNameCode, &eFontNamePlatform, &eFontNameScript, &eFontNameLanguage );
+ if( rc != noErr )
+ continue;
+
+ // ignore non-interesting name entries
+ if( (eFontNameCode != kFontFamilyName)
+ && (eFontNameCode != kFontStyleName)
+ && (eFontNameCode != kFontPostscriptName) )
+ continue;
+
+ // heuristic to find the most common font name
+ // prefering default language names or even better the names matching to the UI language
+ int nNameValue = (eFontNameLanguage==eUILangCode) ? 0 : ((eFontNameLanguage==0) ? -10 : -20);
+ rtl_TextEncoding eEncoding = RTL_TEXTENCODING_UNICODE;
+ const int nPlatformEncoding = ((int)eFontNamePlatform << 8) + (int)eFontNameScript;
+ switch( nPlatformEncoding )
+ {
+ case 0x000: nNameValue += 23; break; // Unicode 1.0
+ case 0x001: nNameValue += 24; break; // Unicode 1.1
+ case 0x002: nNameValue += 25; break; // iso10646_1993
+ case 0x003: nNameValue += 26; break; // UCS-2
+ case 0x301: nNameValue += 27; break; // Win UCS-2
+ case 0x004: // UCS-4
+ case 0x30A: nNameValue += 0; // Win-UCS-4
+ eEncoding = RTL_TEXTENCODING_UCS4;
+ break;
+ case 0x100: nNameValue += 21; // Mac Roman
+ eEncoding = RTL_TEXTENCODING_APPLE_ROMAN;
+ break;
+ case 0x300: nNameValue = 0; // Win Symbol encoded name!
+ rDFA.mbSymbolFlag = true; // (often seen for symbol fonts)
+ break;
+ default: nNameValue = 0; // ignore other encodings
+ break;
+ }
+
+ // ignore name entries with no useful encoding
+ if( nNameValue <= 0 )
+ continue;
+ if( nNameLength >= aNameBuffer.size() )
+ continue;
+
+ // get the encoded name
+ aNameBuffer.reserve( nNameLength+1 ); // extra byte helps for debugging
+ rc = ATSUGetIndFontName( nFontID, nNameIndex, nNameLength, &aNameBuffer[0],
+ &nNameLength, &eFontNameCode, &eFontNamePlatform, &eFontNameScript, &eFontNameLanguage );
+ if( rc != noErr )
+ continue;
+
+ // convert to unicode name
+ UniString aUtf16Name;
+ if( eEncoding == RTL_TEXTENCODING_UNICODE ) // we are just interested in UTF16 encoded names
+ aUtf16Name = UniString( (const sal_Unicode*)&aNameBuffer[0], nNameLength/2 );
+ else if( eEncoding == RTL_TEXTENCODING_UCS4 )
+ aUtf16Name = UniString(); // TODO
+ else // assume the non-unicode encoded names are byte encoded
+ aUtf16Name = UniString( &aNameBuffer[0], nNameLength, eEncoding );
+
+ // ignore empty strings
+ if( aUtf16Name.Len() <= 0 )
+ continue;
+
+ // handle the name depending on its namecode
+ switch( eFontNameCode )
+ {
+ case kFontFamilyName:
+ // ignore font names starting with '.'
+ if( aUtf16Name.GetChar(0) == '.' )
+ nNameValue = 0;
+ else if( rDFA.maName.Len() )
+ {
+ // even if a family name is not the one we are looking for
+ // it is still useful as a font name alternative
+ if( rDFA.maMapNames.Len() )
+ rDFA.maMapNames += ';';
+ rDFA.maMapNames += (nBestNameValue < nNameValue) ? rDFA.maName : aUtf16Name;
+ }
+ if( nBestNameValue < nNameValue )
+ {
+ // get the best family name
+ nBestNameValue = nNameValue;
+ eBestLangCode = eFontNameLanguage;
+ rDFA.maName = aUtf16Name;
+ }
+ break;
+ case kFontStyleName:
+ // get a style name matching to the family name
+ if( nBestStyleValue < nNameValue )
+ {
+ nBestStyleValue = nNameValue;
+ rDFA.maStyleName = aUtf16Name;
+ }
+ break;
+ case kFontPostscriptName:
+ // use the postscript name to get some useful info
+ UpdateAttributesFromPSName( aUtf16Name, rDFA );
+ break;
+ default:
+ // TODO: use other name entries too?
+ break;
+ }
+ }
+
+#if 0 // multiple-master fonts are mostly obsolete nowadays
+ // if we still want to support them this should probably be done one frame higher
+ ItemCount nMaxInstances = 0;
+ rc = ATSUCountFontInstances ( nFontID, &nMaxInstances );
+ for( ItemCount nInstanceIndex = 0; nInstanceIndex < nMaxInstances; ++nInstanceIndex )
+ {
+ ItemCount nMaxVariations = 0;
+ rc = ATSUGetFontInstance( nFontID, nInstanceIndex, 0, NULL, NULL, &nMaxVariations );
+ if( (rc == noErr) && (nMaxVariations > 0) )
+ {
+ fprintf(stderr,"\tnMaxVariations=%d\n",(int)nMaxVariations);
+ typedef ::std::vector<ATSUFontVariationAxis> VariationAxisVector;
+ typedef ::std::vector<ATSUFontVariationValue> VariationValueVector;
+ VariationAxisVector aVariationAxes( nMaxVariations );
+ VariationValueVector aVariationValues( nMaxVariations );
+ ItemCount nVariationCount = 0;
+ rc = ATSUGetFontInstance ( nFontID, nInstanceIndex, nMaxVariations,
+ &aVariationAxes[0], &aVariationValues[0], &nVariationCount );
+ fprintf(stderr,"\tnVariationCount=%d\n",(int)nVariationCount);
+ for( ItemCount nVariationIndex = 0; nVariationIndex < nMaxVariations; ++nVariationIndex )
+ {
+ const char* pTag = (const char*)&aVariationAxes[nVariationIndex];
+ fprintf(stderr,"\tvariation[%d] \'%c%c%c%c\' is %d\n", (int)nVariationIndex,
+ pTag[3],pTag[2],pTag[1],pTag[0], (int)aVariationValues[nVariationIndex]);
+ }
+ }
+ }
+#endif
+
+#if 0 // selecting non-defaulted font features is not enabled yet
+ ByteString aFName( rDFA.maName, RTL_TEXTENCODING_UTF8 );
+ ByteString aSName( rDFA.maStyleName, RTL_TEXTENCODING_UTF8 );
+ ItemCount nMaxFeatures = 0;
+ rc = ATSUCountFontFeatureTypes( nFontID, &nMaxFeatures );
+ fprintf(stderr,"Font \"%s\" \"%s\" has %d features\n",aFName.GetBuffer(),aSName.GetBuffer(),rc);
+ if( (rc == noErr) && (nMaxFeatures > 0) )
+ {
+ typedef std::vector<ATSUFontFeatureType> FeatureVector;
+ FeatureVector aFeatureVector( nMaxFeatures );
+ ItemCount nFeatureCount = 0;
+ rc = ATSUGetFontFeatureTypes( nFontID, nMaxFeatures, &aFeatureVector[0], &nFeatureCount );
+ fprintf(stderr,"nFeatureCount=%d\n",(int)nFeatureCount);
+ for( ItemCount nFeatureIndex = 0; nFeatureIndex < nFeatureCount; ++nFeatureIndex )
+ {
+ ItemCount nMaxSelectors = 0;
+ rc = ATSUCountFontFeatureSelectors( nFontID, aFeatureVector[nFeatureIndex], &nMaxSelectors );
+ fprintf(stderr,"\tFeature[%d] = %d has %d selectors\n",
+ (int)nFeatureIndex, (int)aFeatureVector[nFeatureIndex], (int)nMaxSelectors );
+ typedef std::vector<ATSUFontFeatureSelector> SelectorVector;
+ SelectorVector aSelectorVector( nMaxSelectors );
+ typedef std::vector<MacOSBoolean> BooleanVector;
+ BooleanVector aEnabledVector( nMaxSelectors );
+ BooleanVector aExclusiveVector( nMaxSelectors );
+ ItemCount nSelectorCount = 0;
+ rc = ATSUGetFontFeatureSelectors ( nFontID, aFeatureVector[nFeatureIndex], nMaxSelectors,
+ &aSelectorVector[0], &aEnabledVector[0], &nSelectorCount, &aExclusiveVector[0]);
+ for( ItemCount nSelectorIndex = 0; nSelectorIndex < nSelectorCount; ++nSelectorIndex )
+ {
+ FontNameCode eFontNameCode;
+ rc = ATSUGetFontFeatureNameCode( nFontID, aFeatureVector[nFeatureIndex],
+ aSelectorVector[nSelectorIndex], &eFontNameCode );
+ fprintf(stderr,"\t\tselector[%d] n=%d e=%d, x=%d\n",
+ (int)nSelectorIndex, (int)eFontNameCode,
+ aEnabledVector[nSelectorIndex], aExclusiveVector[nSelectorIndex] );
+ }
+ }
+ }
+#endif
+
+ bool bRet = (rDFA.maName.Len() > 0);
+ return bRet;
+}
+
+// =======================================================================
+
+SystemFontList::SystemFontList()
+{
+ // count available system fonts
+ ItemCount nATSUICompatibleFontsAvailable = 0;
+ if( ATSUFontCount(&nATSUICompatibleFontsAvailable) != noErr )
+ return;
+ if( nATSUICompatibleFontsAvailable <= 0 )
+ return;
+
+ // enumerate available system fonts
+ typedef std::vector<ATSUFontID> AtsFontIDVector;
+ AtsFontIDVector aFontIDVector( nATSUICompatibleFontsAvailable );
+ ItemCount nFontItemsCount = 0;
+ if( ATSUGetFontIDs( &aFontIDVector[0], aFontIDVector.capacity(), &nFontItemsCount ) != noErr )
+ return;
+
+ BOOST_ASSERT(nATSUICompatibleFontsAvailable == nFontItemsCount && "Strange I would expect them to be equal");
+
+ // prepare use of the available fonts
+ AtsFontIDVector::const_iterator it = aFontIDVector.begin();
+ for(; it != aFontIDVector.end(); ++it )
+ {
+ const ATSUFontID nFontID = *it;
+ ImplDevFontAttributes aDevFontAttr;
+ if( !GetDevFontAttributes( nFontID, aDevFontAttr ) )
+ continue;
+ ImplMacFontData* pFontData = new ImplMacFontData( aDevFontAttr, nFontID );
+ maFontContainer[ nFontID ] = pFontData;
+ }
+
+ InitGlyphFallbacks();
+}
+
+// -----------------------------------------------------------------------
+
+SystemFontList::~SystemFontList()
+{
+ MacFontContainer::const_iterator it = maFontContainer.begin();
+ for(; it != maFontContainer.end(); ++it )
+ delete (*it).second;
+ maFontContainer.clear();
+
+ ATSUDisposeFontFallbacks( maFontFallbacks );
+}
+
+// -----------------------------------------------------------------------
+
+void SystemFontList::AnnounceFonts( ImplDevFontList& rFontList ) const
+{
+ MacFontContainer::const_iterator it = maFontContainer.begin();
+ for(; it != maFontContainer.end(); ++it )
+ rFontList.Add( (*it).second->Clone() );
+}
+
+// -----------------------------------------------------------------------
+
+// not all fonts are suitable for glyph fallback => sort them
+struct GfbCompare{ bool operator()(const ImplMacFontData*, const ImplMacFontData*); };
+
+inline bool GfbCompare::operator()( const ImplMacFontData* pA, const ImplMacFontData* pB )
+{
+ // use symbol fonts only as last resort
+ bool bPreferA = !pA->IsSymbolFont();
+ bool bPreferB = !pB->IsSymbolFont();
+ if( bPreferA != bPreferB )
+ return bPreferA;
+ // prefer scalable fonts
+ bPreferA = pA->IsScalable();
+ bPreferB = pB->IsScalable();
+ if( bPreferA != bPreferB )
+ return bPreferA;
+ // prefer non-slanted fonts
+ bPreferA = (pA->GetSlant() == ITALIC_NONE);
+ bPreferB = (pB->GetSlant() == ITALIC_NONE);
+ if( bPreferA != bPreferB )
+ return bPreferA;
+ // prefer normal weight fonts
+ bPreferA = (pA->GetWeight() == WEIGHT_NORMAL);
+ bPreferB = (pB->GetWeight() == WEIGHT_NORMAL);
+ if( bPreferA != bPreferB )
+ return bPreferA;
+ // prefer normal width fonts
+ bPreferA = (pA->GetWidthType() == WIDTH_NORMAL);
+ bPreferB = (pB->GetWidthType() == WIDTH_NORMAL);
+ if( bPreferA != bPreferB )
+ return bPreferA;
+ return false;
+}
+
+void SystemFontList::InitGlyphFallbacks()
+{
+ // sort fonts for "glyph fallback"
+ typedef std::multiset<const ImplMacFontData*,GfbCompare> FallbackSet;
+ FallbackSet aFallbackSet;
+ MacFontContainer::const_iterator it = maFontContainer.begin();
+ for(; it != maFontContainer.end(); ++it )
+ {
+ const ImplMacFontData* pIFD = (*it).second;
+ // TODO: subsettable/embeddable glyph fallback only for PDF export?
+ if( pIFD->IsSubsettable() || pIFD->IsEmbeddable() )
+ aFallbackSet.insert( pIFD );
+ }
+
+ // tell ATSU about font preferences for "glyph fallback"
+ typedef std::vector<ATSUFontID> AtsFontIDVector;
+ AtsFontIDVector aFallbackVector;
+ aFallbackVector.reserve( maFontContainer.size() );
+ FallbackSet::const_iterator itFData = aFallbackSet.begin();
+ for(; itFData != aFallbackSet.end(); ++itFData )
+ {
+ const ImplMacFontData* pFontData = (*itFData);
+ ATSUFontID nFontID = (ATSUFontID)pFontData->GetFontId();
+ aFallbackVector.push_back( nFontID );
+ }
+
+ ATSUCreateFontFallbacks( &maFontFallbacks );
+ ATSUSetObjFontFallbacks( maFontFallbacks,
+ aFallbackVector.size(), &aFallbackVector[0], kATSUSequentialFallbacksPreferred );
+}
+
+// -----------------------------------------------------------------------
+
+ImplMacFontData* SystemFontList::GetFontDataFromId( ATSUFontID nFontId ) const
+{
+ MacFontContainer::const_iterator it = maFontContainer.find( nFontId );
+ if( it == maFontContainer.end() )
+ return NULL;
+ return (*it).second;
+}
+
+// -----------------------------------------------------------------------
+
diff --git a/vcl/aqua/source/gdi/salbmp.cxx b/vcl/aqua/source/gdi/salbmp.cxx
new file mode 100644
index 000000000000..0e58c35b5fad
--- /dev/null
+++ b/vcl/aqua/source/gdi/salbmp.cxx
@@ -0,0 +1,904 @@
+/*************************************************************************
+ *
+ * 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/color.hxx"
+#include "salbmp.h"
+#include "vcl/bitmap.hxx" // for BitmapSystemData
+#include "vcl/salbtype.hxx"
+#include "vcl/bmpfast.hxx"
+
+#include "basebmp/scanlineformats.hxx"
+#include "basebmp/color.hxx"
+#include "basegfx/vector/b2ivector.hxx"
+
+#include <boost/bind.hpp>
+
+#include "salinst.h"
+
+// =======================================================================
+
+static bool isValidBitCount( sal_uInt16 nBitCount )
+{
+ return (nBitCount == 1) || (nBitCount == 4) || (nBitCount == 8) || (nBitCount == 16) || (nBitCount == 24) || (nBitCount == 32);
+}
+
+// =======================================================================
+
+AquaSalBitmap::AquaSalBitmap()
+: mxGraphicContext( NULL )
+, mxCachedImage( NULL )
+, mnBits(0)
+, mnWidth(0)
+, mnHeight(0)
+, mnBytesPerRow(0)
+{
+}
+
+// ------------------------------------------------------------------
+
+AquaSalBitmap::~AquaSalBitmap()
+{
+ Destroy();
+}
+
+// ------------------------------------------------------------------
+
+bool AquaSalBitmap::Create( CGLayerRef xLayer, int nBitmapBits,
+ int nX, int nY, int nWidth, int nHeight, bool /*bMirrorVert*/ )
+{
+ DBG_ASSERT( xLayer, "AquaSalBitmap::Create() from non-layered context" );
+
+ // sanitize input parameters
+ if( nX < 0 )
+ nWidth += nX, nX = 0;
+ if( nY < 0 )
+ nHeight += nY, nY = 0;
+ const CGSize aLayerSize = CGLayerGetSize( xLayer );
+ if( nWidth >= (int)aLayerSize.width - nX )
+ nWidth = (int)aLayerSize.width - nX;
+ if( nHeight >= (int)aLayerSize.height - nY )
+ nHeight = (int)aLayerSize.height - nY;
+ if( (nWidth < 0) || (nHeight < 0) )
+ nWidth = nHeight = 0;
+
+ // initialize properties
+ mnWidth = nWidth;
+ mnHeight = nHeight;
+ mnBits = nBitmapBits ? nBitmapBits : 32;
+
+ // initialize drawing context
+ CreateContext();
+
+ // copy layer content into the bitmap buffer
+ const CGPoint aSrcPoint = { -nX, -nY };
+ ::CGContextDrawLayerAtPoint( mxGraphicContext, aSrcPoint, xLayer );
+ return true;
+}
+
+// ------------------------------------------------------------------
+
+bool AquaSalBitmap::Create( const Size& rSize, USHORT nBits, const BitmapPalette& rBitmapPalette )
+{
+ if( !isValidBitCount( nBits ) )
+ return false;
+ maPalette = rBitmapPalette;
+ mnBits = nBits;
+ mnWidth = rSize.Width();
+ mnHeight = rSize.Height();
+ return AllocateUserData();
+}
+
+// ------------------------------------------------------------------
+
+bool AquaSalBitmap::Create( const SalBitmap& rSalBmp )
+{
+ return Create( rSalBmp, rSalBmp.GetBitCount() );
+}
+
+// ------------------------------------------------------------------
+
+bool AquaSalBitmap::Create( const SalBitmap& rSalBmp, SalGraphics* pGraphics )
+{
+ return Create( rSalBmp, pGraphics ? pGraphics->GetBitCount() : rSalBmp.GetBitCount() );
+}
+
+// ------------------------------------------------------------------
+
+bool AquaSalBitmap::Create( const SalBitmap& rSalBmp, USHORT nNewBitCount )
+{
+ const AquaSalBitmap& rSourceBitmap = static_cast<const AquaSalBitmap&>(rSalBmp);
+
+ if( isValidBitCount( nNewBitCount ) && rSourceBitmap.maUserBuffer.get() )
+ {
+ mnBits = nNewBitCount;
+ mnWidth = rSourceBitmap.mnWidth;
+ mnHeight = rSourceBitmap.mnHeight;
+ maPalette = rSourceBitmap.maPalette;
+
+ if( AllocateUserData() )
+ {
+ ConvertBitmapData( mnWidth, mnHeight, mnBits, mnBytesPerRow, maPalette, maUserBuffer.get(), rSourceBitmap.mnBits, rSourceBitmap.mnBytesPerRow, rSourceBitmap.maPalette, rSourceBitmap.maUserBuffer.get() );
+ return true;
+ }
+ }
+ return false;
+}
+
+// ------------------------------------------------------------------
+
+void AquaSalBitmap::Destroy()
+{
+ DestroyContext();
+ maUserBuffer.reset();
+}
+
+// ------------------------------------------------------------------
+
+void AquaSalBitmap::DestroyContext()
+{
+ CGImageRelease( mxCachedImage );
+ mxCachedImage = NULL;
+
+ if( mxGraphicContext )
+ {
+ CGContextRelease( mxGraphicContext );
+ mxGraphicContext = NULL;
+ maContextBuffer.reset();
+ }
+}
+
+// ------------------------------------------------------------------
+
+bool AquaSalBitmap::CreateContext()
+{
+ DestroyContext();
+
+ // prepare graphics context
+ // convert image from user input if available
+ const bool bSkipConversion = !maUserBuffer;
+ if( bSkipConversion )
+ AllocateUserData();
+
+ // default to RGBA color space
+ CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace;
+ CGBitmapInfo aCGBmpInfo = kCGImageAlphaNoneSkipFirst;
+
+ // convert data into something accepted by CGBitmapContextCreate()
+ size_t bitsPerComponent = (mnBits == 16) ? 5 : 8;
+ sal_uInt32 nContextBytesPerRow = mnBytesPerRow;
+ if( (mnBits == 16) || (mnBits == 32) )
+ {
+ // no conversion needed for truecolor
+ maContextBuffer = maUserBuffer;
+ }
+ else if( (mnBits == 8) && maPalette.IsGreyPalette() )
+ {
+ // no conversion needed for grayscale
+ maContextBuffer = maUserBuffer;
+ aCGColorSpace = GetSalData()->mxGraySpace;
+ aCGBmpInfo = kCGImageAlphaNone;
+ bitsPerComponent = mnBits;
+ }
+ // TODO: is special handling for 1bit input buffers worth it?
+ else
+ {
+ // convert user data to 32 bit
+ nContextBytesPerRow = mnWidth << 2;
+ try
+ {
+ maContextBuffer.reset( new sal_uInt8[ mnHeight * nContextBytesPerRow ] );
+
+ if( !bSkipConversion )
+ ConvertBitmapData( mnWidth, mnHeight,
+ 32, nContextBytesPerRow, maPalette, maContextBuffer.get(),
+ mnBits, mnBytesPerRow, maPalette, maUserBuffer.get() );
+ }
+ catch( std::bad_alloc )
+ {
+ mxGraphicContext = 0;
+ }
+ }
+
+ if( maContextBuffer.get() )
+ {
+ mxGraphicContext = ::CGBitmapContextCreate( maContextBuffer.get(), mnWidth, mnHeight,
+ bitsPerComponent, nContextBytesPerRow, aCGColorSpace, aCGBmpInfo );
+ }
+
+ if( !mxGraphicContext )
+ maContextBuffer.reset();
+
+ return mxGraphicContext != NULL;
+}
+
+// ------------------------------------------------------------------
+
+bool AquaSalBitmap::AllocateUserData()
+{
+ Destroy();
+
+ if( mnWidth && mnHeight )
+ {
+ mnBytesPerRow = 0;
+
+ switch( mnBits )
+ {
+ case 1: mnBytesPerRow = (mnWidth + 7) >> 3; break;
+ case 4: mnBytesPerRow = (mnWidth + 1) >> 1; break;
+ case 8: mnBytesPerRow = mnWidth; break;
+ case 16: mnBytesPerRow = mnWidth << 1; break;
+ case 24: mnBytesPerRow = (mnWidth << 1) + mnWidth; break;
+ case 32: mnBytesPerRow = mnWidth << 2; break;
+ default:
+ DBG_ERROR("vcl::AquaSalBitmap::AllocateUserData(), illegal bitcount!");
+ }
+ }
+
+ try
+ {
+ if( mnBytesPerRow )
+ maUserBuffer.reset( new sal_uInt8[mnBytesPerRow * mnHeight] );
+ }
+ catch( const std::bad_alloc& )
+ {
+ DBG_ERROR( "vcl::AquaSalBitmap::AllocateUserData: bad alloc" );
+ maUserBuffer.reset( NULL );
+ mnBytesPerRow = 0;
+ }
+
+ return maUserBuffer.get() != 0;
+}
+
+// ------------------------------------------------------------------
+
+class ImplPixelFormat
+{
+protected:
+ sal_uInt8* pData;
+public:
+ static ImplPixelFormat* GetFormat( sal_uInt16 nBits, const BitmapPalette& rPalette );
+
+ virtual void StartLine( sal_uInt8* pLine ) { pData = pLine; }
+ virtual void SkipPixel( sal_uInt32 nPixel ) = 0;
+ virtual ColorData ReadPixel() = 0;
+ virtual void WritePixel( ColorData nColor ) = 0;
+};
+
+class ImplPixelFormat32 : public ImplPixelFormat
+// currently ARGB-format for 32bit depth
+{
+public:
+ virtual void SkipPixel( sal_uInt32 nPixel )
+ {
+ pData += nPixel << 2;
+ }
+ virtual ColorData ReadPixel()
+ {
+ const ColorData c = RGB_COLORDATA( pData[1], pData[2], pData[3] );
+ pData += 4;
+ return c;
+ }
+ virtual void WritePixel( ColorData nColor )
+ {
+ *pData++ = 0;
+ *pData++ = COLORDATA_RED( nColor );
+ *pData++ = COLORDATA_GREEN( nColor );
+ *pData++ = COLORDATA_BLUE( nColor );
+ }
+};
+
+class ImplPixelFormat24 : public ImplPixelFormat
+// currently BGR-format for 24bit depth
+{
+public:
+ virtual void SkipPixel( sal_uInt32 nPixel )
+ {
+ pData += (nPixel << 1) + nPixel;
+ }
+ virtual ColorData ReadPixel()
+ {
+ const ColorData c = RGB_COLORDATA( pData[2], pData[1], pData[0] );
+ pData += 3;
+ return c;
+ }
+ virtual void WritePixel( ColorData nColor )
+ {
+ *pData++ = COLORDATA_BLUE( nColor );
+ *pData++ = COLORDATA_GREEN( nColor );
+ *pData++ = COLORDATA_RED( nColor );
+ }
+};
+
+class ImplPixelFormat16 : public ImplPixelFormat
+// currently R5G6B5-format for 16bit depth
+{
+protected:
+ sal_uInt16* pData16;
+public:
+
+ virtual void StartLine( sal_uInt8* pLine )
+ {
+ pData16 = (sal_uInt16*)pLine;
+ }
+ virtual void SkipPixel( sal_uInt32 nPixel )
+ {
+ pData += nPixel;
+ }
+ virtual ColorData ReadPixel()
+ {
+ const ColorData c = RGB_COLORDATA( (*pData & 0x7c00) >> 7, (*pData & 0x03e0) >> 2 , (*pData & 0x001f) << 3 );
+ pData++;
+ return c;
+ }
+ virtual void WritePixel( ColorData nColor )
+ {
+ *pData++ = ((COLORDATA_RED( nColor ) & 0xf8 ) << 7 ) ||
+ ((COLORDATA_GREEN( nColor ) & 0xf8 ) << 2 ) ||
+ ((COLORDATA_BLUE( nColor ) & 0xf8 ) >> 3 );
+ }
+};
+
+class ImplPixelFormat8 : public ImplPixelFormat
+{
+private:
+ const BitmapPalette& mrPalette;
+
+public:
+ ImplPixelFormat8( const BitmapPalette& rPalette )
+ : mrPalette( rPalette )
+ {
+ }
+ virtual void SkipPixel( sal_uInt32 nPixel )
+ {
+ pData += nPixel;
+ }
+ virtual ColorData ReadPixel()
+ {
+ return mrPalette[ *pData++ ].operator Color().GetColor();
+ }
+ virtual void WritePixel( ColorData nColor )
+ {
+ const BitmapColor aColor( COLORDATA_RED( nColor ), COLORDATA_GREEN( nColor ), COLORDATA_BLUE( nColor ) );
+ *pData++ = static_cast< sal_uInt8 >( mrPalette.GetBestIndex( aColor ) );
+ }
+};
+
+class ImplPixelFormat4 : public ImplPixelFormat
+{
+private:
+ const BitmapPalette& mrPalette;
+ sal_uInt32 mnX;
+ sal_uInt32 mnShift;
+
+public:
+ ImplPixelFormat4( const BitmapPalette& rPalette )
+ : mrPalette( rPalette )
+ {
+ }
+ virtual void SkipPixel( sal_uInt32 nPixel )
+ {
+ mnX += nPixel;
+ if( (nPixel & 1) )
+ mnShift ^= 4;
+ }
+ virtual void StartLine( sal_uInt8* pLine )
+ {
+ pData = pLine;
+ mnX = 0;
+ mnShift = 4;
+ }
+ virtual ColorData ReadPixel()
+ {
+ const BitmapColor& rColor = mrPalette[( pData[mnX >> 1] >> mnShift) & 0x0f];
+ mnX++;
+ mnShift ^= 4;
+ return rColor.operator Color().GetColor();
+ }
+ virtual void WritePixel( ColorData nColor )
+ {
+ const BitmapColor aColor( COLORDATA_RED( nColor ), COLORDATA_GREEN( nColor ), COLORDATA_BLUE( nColor ) );
+ pData[mnX>>1] &= (0xf0 >> mnShift);
+ pData[mnX>>1] |= (static_cast< sal_uInt8 >( mrPalette.GetBestIndex( aColor ) ) & 0x0f);
+ mnX++;
+ mnShift ^= 4;
+ }
+};
+
+class ImplPixelFormat1 : public ImplPixelFormat
+{
+private:
+ const BitmapPalette& mrPalette;
+ sal_uInt32 mnX;
+
+public:
+ ImplPixelFormat1( const BitmapPalette& rPalette )
+ : mrPalette( rPalette )
+ {
+ }
+ virtual void SkipPixel( sal_uInt32 nPixel )
+ {
+ mnX += nPixel;
+ }
+ virtual void StartLine( sal_uInt8* pLine )
+ {
+ pData = pLine;
+ mnX = 0;
+ }
+ virtual ColorData ReadPixel()
+ {
+ const BitmapColor& rColor = mrPalette[ (pData[mnX >> 3 ] >> ( 7 - ( mnX & 7 ) )) & 1];
+ mnX++;
+ return rColor.operator Color().GetColor();
+ }
+ virtual void WritePixel( ColorData nColor )
+ {
+ const BitmapColor aColor( COLORDATA_RED( nColor ), COLORDATA_GREEN( nColor ), COLORDATA_BLUE( nColor ) );
+ if( mrPalette.GetBestIndex( aColor ) & 1 )
+ pData[ mnX >> 3 ] |= 1 << ( 7 - ( mnX & 7 ) );
+ else
+ pData[ mnX >> 3 ] &= ~( 1 << ( 7 - ( mnX & 7 ) ) );
+ mnX++;
+ }
+};
+
+ImplPixelFormat* ImplPixelFormat::GetFormat( sal_uInt16 nBits, const BitmapPalette& rPalette )
+{
+ switch( nBits )
+ {
+ case 1: return new ImplPixelFormat1( rPalette );
+ case 4: return new ImplPixelFormat4( rPalette );
+ case 8: return new ImplPixelFormat8( rPalette );
+ case 16: return new ImplPixelFormat16;
+ case 24: return new ImplPixelFormat24;
+ case 32: return new ImplPixelFormat32;
+ }
+
+ return 0;
+}
+
+void AquaSalBitmap::ConvertBitmapData( sal_uInt32 nWidth, sal_uInt32 nHeight,
+ sal_uInt16 nDestBits, sal_uInt32 nDestBytesPerRow, const BitmapPalette& rDestPalette, sal_uInt8* pDestData,
+ sal_uInt16 nSrcBits, sal_uInt32 nSrcBytesPerRow, const BitmapPalette& rSrcPalette, sal_uInt8* pSrcData )
+
+{
+ if( (nDestBytesPerRow == nSrcBytesPerRow) && (nDestBits == nSrcBits) && ((nSrcBits != 8) || (rDestPalette.operator==( rSrcPalette ))) )
+ {
+ // simple case, same format, so just copy
+ memcpy( pDestData, pSrcData, nHeight * nDestBytesPerRow );
+ return;
+ }
+
+ // try accelerated conversion if possible
+ // TODO: are other truecolor conversions except BGR->ARGB worth it?
+ bool bConverted = false;
+ if( (nSrcBits == 24) && (nDestBits == 32) )
+ {
+ // TODO: extend bmpfast.cxx with a method that can be directly used here
+ BitmapBuffer aSrcBuf;
+ aSrcBuf.mnFormat = BMP_FORMAT_24BIT_TC_BGR;
+ aSrcBuf.mpBits = pSrcData;
+ aSrcBuf.mnBitCount = nSrcBits;
+ aSrcBuf.mnScanlineSize = nSrcBytesPerRow;
+ BitmapBuffer aDstBuf;
+ aDstBuf.mnFormat = BMP_FORMAT_32BIT_TC_ARGB;
+ aDstBuf.mpBits = pDestData;
+ aSrcBuf.mnBitCount = nDestBits;
+ aDstBuf.mnScanlineSize = nDestBytesPerRow;
+
+ aSrcBuf.mnWidth = aDstBuf.mnWidth = nWidth;
+ aSrcBuf.mnHeight = aDstBuf.mnHeight = nHeight;
+
+ SalTwoRect aTwoRects;
+ aTwoRects.mnSrcX = aTwoRects.mnDestX = 0;
+ aTwoRects.mnSrcY = aTwoRects.mnDestY = 0;
+ aTwoRects.mnSrcWidth = aTwoRects.mnDestWidth = mnWidth;
+ aTwoRects.mnSrcHeight = aTwoRects.mnDestHeight = mnHeight;
+ bConverted = ::ImplFastBitmapConversion( aDstBuf, aSrcBuf, aTwoRects );
+ }
+
+ if( !bConverted )
+ {
+ // TODO: this implementation is for clarety, not for speed
+
+ ImplPixelFormat* pD = ImplPixelFormat::GetFormat( nDestBits, rDestPalette );
+ ImplPixelFormat* pS = ImplPixelFormat::GetFormat( nSrcBits, rSrcPalette );
+
+ if( pD && pS )
+ {
+ sal_uInt32 nY = nHeight;
+ while( nY-- )
+ {
+ pD->StartLine( pDestData );
+ pS->StartLine( pSrcData );
+
+ sal_uInt32 nX = nWidth;
+ while( nX-- )
+ pD->WritePixel( pS->ReadPixel() );
+
+ pSrcData += nSrcBytesPerRow;
+ pDestData += nDestBytesPerRow;
+ }
+ }
+ delete pS;
+ delete pD;
+ }
+}
+
+// ------------------------------------------------------------------
+
+Size AquaSalBitmap::GetSize() const
+{
+ return Size( mnWidth, mnHeight );
+}
+
+// ------------------------------------------------------------------
+
+USHORT AquaSalBitmap::GetBitCount() const
+{
+ return mnBits;
+}
+
+// ------------------------------------------------------------------
+
+static struct pal_entry
+{
+ BYTE mnRed;
+ BYTE mnGreen;
+ BYTE mnBlue;
+}
+const aImplSalSysPalEntryAry[ 16 ] =
+{
+{ 0, 0, 0 },
+{ 0, 0, 0x80 },
+{ 0, 0x80, 0 },
+{ 0, 0x80, 0x80 },
+{ 0x80, 0, 0 },
+{ 0x80, 0, 0x80 },
+{ 0x80, 0x80, 0 },
+{ 0x80, 0x80, 0x80 },
+{ 0xC0, 0xC0, 0xC0 },
+{ 0, 0, 0xFF },
+{ 0, 0xFF, 0 },
+{ 0, 0xFF, 0xFF },
+{ 0xFF, 0, 0 },
+{ 0xFF, 0, 0xFF },
+{ 0xFF, 0xFF, 0 },
+{ 0xFF, 0xFF, 0xFF }
+};
+
+const BitmapPalette& GetDefaultPalette( int mnBits, bool bMonochrome )
+{
+ if( bMonochrome )
+ return Bitmap::GetGreyPalette( 1U << mnBits );
+
+ // at this point we should provide some kind of default palette
+ // since all other platforms do so, too.
+ static bool bDefPalInit = false;
+ static BitmapPalette aDefPalette256;
+ static BitmapPalette aDefPalette16;
+ static BitmapPalette aDefPalette2;
+ if( ! bDefPalInit )
+ {
+ bDefPalInit = true;
+ aDefPalette256.SetEntryCount( 256 );
+ aDefPalette16.SetEntryCount( 16 );
+ aDefPalette2.SetEntryCount( 2 );
+
+ // Standard colors
+ unsigned int i;
+ for( i = 0; i < 16; i++ )
+ {
+ aDefPalette16[i] =
+ aDefPalette256[i] = BitmapColor( aImplSalSysPalEntryAry[i].mnRed,
+ aImplSalSysPalEntryAry[i].mnGreen,
+ aImplSalSysPalEntryAry[i].mnBlue );
+ }
+
+ aDefPalette2[0] = BitmapColor( 0, 0, 0 );
+ aDefPalette2[1] = BitmapColor( 0xff, 0xff, 0xff );
+
+ // own palette (6/6/6)
+ const int DITHER_PAL_STEPS = 6;
+ const BYTE DITHER_PAL_DELTA = 51;
+ int nB, nG, nR;
+ BYTE nRed, nGreen, nBlue;
+ for( nB=0, nBlue=0; nB < DITHER_PAL_STEPS; nB++, nBlue += DITHER_PAL_DELTA )
+ {
+ for( nG=0, nGreen=0; nG < DITHER_PAL_STEPS; nG++, nGreen += DITHER_PAL_DELTA )
+ {
+ for( nR=0, nRed=0; nR < DITHER_PAL_STEPS; nR++, nRed += DITHER_PAL_DELTA )
+ {
+ aDefPalette256[ i ] = BitmapColor( nRed, nGreen, nBlue );
+ i++;
+ }
+ }
+ }
+ }
+
+ // now fill in appropriate palette
+ switch( mnBits )
+ {
+ case 1: return aDefPalette2;
+ case 4: return aDefPalette16;
+ case 8: return aDefPalette256;
+ default: break;
+ }
+
+ const static BitmapPalette aEmptyPalette;
+ return aEmptyPalette;
+}
+
+BitmapBuffer* AquaSalBitmap::AcquireBuffer( bool bReadOnly )
+{
+ if( !maUserBuffer.get() )
+// || maContextBuffer.get() && (maUserBuffer.get() != maContextBuffer.get()) )
+ {
+ fprintf(stderr,"ASB::Acq(%dx%d,d=%d)\n",mnWidth,mnHeight,mnBits);
+ // TODO: AllocateUserData();
+ return NULL;
+ }
+
+ BitmapBuffer* pBuffer = new BitmapBuffer;
+ pBuffer->mnWidth = mnWidth;
+ pBuffer->mnHeight = mnHeight;
+ pBuffer->maPalette = maPalette;
+ pBuffer->mnScanlineSize = mnBytesPerRow;
+ pBuffer->mpBits = maUserBuffer.get();
+ pBuffer->mnBitCount = mnBits;
+ switch( mnBits )
+ {
+ case 1: pBuffer->mnFormat = BMP_FORMAT_1BIT_MSB_PAL; break;
+ case 4: pBuffer->mnFormat = BMP_FORMAT_4BIT_MSN_PAL; break;
+ case 8: pBuffer->mnFormat = BMP_FORMAT_8BIT_PAL; break;
+ case 16: pBuffer->mnFormat = BMP_FORMAT_16BIT_TC_MSB_MASK;
+ pBuffer->maColorMask = ColorMask( k16BitRedColorMask, k16BitGreenColorMask, k16BitBlueColorMask );
+ break;
+ case 24: pBuffer->mnFormat = BMP_FORMAT_24BIT_TC_BGR; break;
+ case 32: pBuffer->mnFormat = BMP_FORMAT_32BIT_TC_ARGB;
+ pBuffer->maColorMask = ColorMask( k32BitRedColorMask, k32BitGreenColorMask, k32BitBlueColorMask );
+ break;
+ }
+ pBuffer->mnFormat |= BMP_FORMAT_BOTTOM_UP;
+
+ // some BitmapBuffer users depend on a complete palette
+ if( (mnBits <= 8) && !maPalette )
+ pBuffer->maPalette = GetDefaultPalette( mnBits, true );
+
+ return pBuffer;
+}
+
+// ------------------------------------------------------------------
+
+void AquaSalBitmap::ReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly )
+{
+ // invalidate graphic context if we have different data
+ if( !bReadOnly )
+ {
+ maPalette = pBuffer->maPalette;
+ if( mxGraphicContext )
+ DestroyContext();
+ }
+
+ delete pBuffer;
+}
+
+// ------------------------------------------------------------------
+
+CGImageRef AquaSalBitmap::CreateCroppedImage( int nX, int nY, int nNewWidth, int nNewHeight ) const
+{
+ if( !mxCachedImage )
+ {
+ if( !mxGraphicContext )
+ if( !const_cast<AquaSalBitmap*>(this)->CreateContext() )
+ return NULL;
+
+ mxCachedImage = CGBitmapContextCreateImage( mxGraphicContext );
+ }
+
+ CGImageRef xCroppedImage = NULL;
+ // short circuit if there is nothing to crop
+ if( !nX && !nY && (mnWidth == nNewWidth) && (mnHeight == nNewHeight) )
+ {
+ xCroppedImage = mxCachedImage;
+ CFRetain( xCroppedImage );
+ }
+ else
+ {
+ nY = mnHeight - (nY + nNewHeight); // adjust for y-mirrored context
+ const CGRect aCropRect = {{nX, nY}, {nNewWidth, nNewHeight}};
+ xCroppedImage = CGImageCreateWithImageInRect( mxCachedImage, aCropRect );
+ }
+
+ return xCroppedImage;
+}
+
+// ------------------------------------------------------------------
+
+static void CFRTLFree(void* /*info*/, const void* data, size_t /*size*/)
+{
+ rtl_freeMemory( const_cast<void*>(data) );
+}
+
+CGImageRef AquaSalBitmap::CreateWithMask( const AquaSalBitmap& rMask,
+ int nX, int nY, int nWidth, int nHeight ) const
+{
+ CGImageRef xImage( CreateCroppedImage( nX, nY, nWidth, nHeight ) );
+ if( !xImage )
+ return NULL;
+
+ CGImageRef xMask = rMask.CreateCroppedImage( nX, nY, nWidth, nHeight );
+ if( !xMask )
+ return xImage;
+
+ // CGImageCreateWithMask() only likes masks or greyscale images => convert if needed
+ // TODO: isolate in an extra method?
+ if( !CGImageIsMask(xMask) || (CGImageGetColorSpace(xMask) != GetSalData()->mxGraySpace) )
+ {
+ const CGRect xImageRect=CGRectMake( 0, 0, nWidth, nHeight );//the rect has no offset
+
+ // create the alpha mask image fitting our image
+ // TODO: is caching the full mask or the subimage mask worth it?
+ int nMaskBytesPerRow = ((nWidth + 3) & ~3);
+ void* pMaskMem = rtl_allocateMemory( nMaskBytesPerRow * nHeight );
+ CGContextRef xMaskContext = CGBitmapContextCreate( pMaskMem,
+ nWidth, nHeight, 8, nMaskBytesPerRow, GetSalData()->mxGraySpace, kCGImageAlphaNone );
+ CGContextDrawImage( xMaskContext, xImageRect, xMask );
+ CFRelease( xMask );
+ CGDataProviderRef xDataProvider( CGDataProviderCreateWithData( NULL,
+ pMaskMem, nHeight * nMaskBytesPerRow, &CFRTLFree ) );
+ static const float* pDecode = NULL;
+ xMask = CGImageMaskCreate( nWidth, nHeight, 8, 8, nMaskBytesPerRow, xDataProvider, pDecode, false );
+ CFRelease( xDataProvider );
+ CFRelease( xMaskContext );
+ }
+
+ if( !xMask )
+ return xImage;
+
+ // combine image and alpha mask
+ CGImageRef xMaskedImage = CGImageCreateWithMask( xImage, xMask );
+ CFRelease( xMask );
+ CFRelease( xImage );
+ return xMaskedImage;
+}
+
+// ------------------------------------------------------------------
+
+/** creates an image from the given rectangle, replacing all black pixels with nMaskColor and make all other full transparent */
+CGImageRef AquaSalBitmap::CreateColorMask( int nX, int nY, int nWidth, int nHeight, SalColor nMaskColor ) const
+{
+ CGImageRef xMask = 0;
+ if( maUserBuffer.get() && (nX + nWidth <= mnWidth) && (nY + nHeight <= mnHeight) )
+ {
+ const sal_uInt32 nDestBytesPerRow = nWidth << 2;
+ sal_uInt32* pMaskBuffer = static_cast<sal_uInt32*>( rtl_allocateMemory( nHeight * nDestBytesPerRow ) );
+ sal_uInt32* pDest = pMaskBuffer;
+
+ ImplPixelFormat* pSourcePixels = ImplPixelFormat::GetFormat( mnBits, maPalette );
+
+ if( pMaskBuffer && pSourcePixels )
+ {
+ sal_uInt32 nColor;
+ reinterpret_cast<sal_uInt8*>(&nColor)[0] = 0xff;
+ reinterpret_cast<sal_uInt8*>(&nColor)[1] = SALCOLOR_RED( nMaskColor );
+ reinterpret_cast<sal_uInt8*>(&nColor)[2] = SALCOLOR_GREEN( nMaskColor );
+ reinterpret_cast<sal_uInt8*>(&nColor)[3] = SALCOLOR_BLUE( nMaskColor );
+
+ sal_uInt8* pSource = maUserBuffer.get();
+ if( nY )
+ pSource += nY * mnBytesPerRow;
+
+ int y = nHeight;
+ while( y-- )
+ {
+ pSourcePixels->StartLine( pSource );
+ pSourcePixels->SkipPixel(nX);
+ sal_uInt32 x = nWidth;
+ while( x-- )
+ {
+ *pDest++ = ( pSourcePixels->ReadPixel() == 0 ) ? nColor : 0;
+ }
+ pSource += mnBytesPerRow;
+ }
+
+ CGDataProviderRef xDataProvider( CGDataProviderCreateWithData(NULL, pMaskBuffer, nHeight * nDestBytesPerRow, &CFRTLFree) );
+ xMask = CGImageCreate(nWidth, nHeight, 8, 32, nDestBytesPerRow, GetSalData()->mxRGBSpace, kCGImageAlphaPremultipliedFirst, xDataProvider, NULL, true, kCGRenderingIntentDefault);
+ CFRelease(xDataProvider);
+ }
+ else
+ {
+ free(pMaskBuffer);
+ }
+
+ delete pSourcePixels;
+ }
+ return xMask;
+}
+
+// =======================================================================
+
+/** AquaSalBitmap::GetSystemData Get platform native image data from existing image
+ *
+ * @param rData struct BitmapSystemData, defined in vcl/inc/bitmap.hxx
+ * @return true if successful
+**/
+bool AquaSalBitmap::GetSystemData( BitmapSystemData& rData )
+{
+ bool bRet = false;
+
+ if( !mxGraphicContext )
+ CreateContext();
+
+ if ( mxGraphicContext )
+ {
+ bRet = true;
+
+#ifdef CAIRO
+ if ((CGBitmapContextGetBitsPerPixel(mxGraphicContext) == 32) &&
+ (CGBitmapContextGetBitmapInfo(mxGraphicContext) & kCGBitmapByteOrderMask) != kCGBitmapByteOrder32Host) {
+ /**
+ * We need to hack things because VCL does not use kCGBitmapByteOrder32Host, while Cairo requires it.
+ */
+ OSL_TRACE("AquaSalBitmap::%s(): kCGBitmapByteOrder32Host not found => inserting it.",__func__);
+
+ CGImageRef xImage = CGBitmapContextCreateImage (mxGraphicContext);
+
+ // re-create the context with single change: include kCGBitmapByteOrder32Host flag.
+ CGContextRef mxGraphicContextNew = CGBitmapContextCreate( CGBitmapContextGetData(mxGraphicContext),
+ CGBitmapContextGetWidth(mxGraphicContext),
+ CGBitmapContextGetHeight(mxGraphicContext),
+ CGBitmapContextGetBitsPerComponent(mxGraphicContext),
+ CGBitmapContextGetBytesPerRow(mxGraphicContext),
+ CGBitmapContextGetColorSpace(mxGraphicContext),
+ CGBitmapContextGetBitmapInfo(mxGraphicContext) | kCGBitmapByteOrder32Host);
+ CFRelease(mxGraphicContext);
+
+ // Needs to be flipped
+ CGContextSaveGState( mxGraphicContextNew );
+ CGContextTranslateCTM (mxGraphicContextNew, 0, CGBitmapContextGetHeight(mxGraphicContextNew));
+ CGContextScaleCTM (mxGraphicContextNew, 1.0, -1.0);
+
+ CGContextDrawImage(mxGraphicContextNew, CGRectMake( 0, 0, CGImageGetWidth(xImage), CGImageGetHeight(xImage)), xImage);
+
+ // Flip back
+ CGContextRestoreGState( mxGraphicContextNew );
+
+ CGImageRelease( xImage );
+ mxGraphicContext = mxGraphicContextNew;
+ }
+#endif
+
+ rData.rImageContext = (void *) mxGraphicContext;
+ rData.mnWidth = mnWidth;
+ rData.mnHeight = mnHeight;
+ }
+
+ return bRet;
+}
diff --git a/vcl/aqua/source/gdi/salcolorutils.cxx b/vcl/aqua/source/gdi/salcolorutils.cxx
new file mode 100755
index 000000000000..ec33b2dd8f8d
--- /dev/null
+++ b/vcl/aqua/source/gdi/salcolorutils.cxx
@@ -0,0 +1,50 @@
+/*************************************************************************
+ *
+ * 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 "salcolorutils.hxx"
+#include "vcl/salbtype.hxx"
+
+// =======================================================================
+
+SalColor GetSalColor( const float* pQuartzColor )
+{
+ return MAKE_SALCOLOR( sal_uInt8( pQuartzColor[0] * 255.0), sal_uInt8( pQuartzColor[1] * 255.0 ), sal_uInt8( pQuartzColor[2] * 255.0 ) );
+}
+
+void SetSalColor( const SalColor& rColor, float* pQuartzColor )
+{
+ pQuartzColor[0] = (float) SALCOLOR_RED(rColor) / 255.0;
+ pQuartzColor[1] = (float) SALCOLOR_GREEN(rColor) / 255.0;
+ pQuartzColor[2] = (float) SALCOLOR_BLUE(rColor) / 255.0;
+ pQuartzColor[3] = 1.0;
+}
+
+// =======================================================================
+
diff --git a/vcl/aqua/source/gdi/salgdi.cxx b/vcl/aqua/source/gdi/salgdi.cxx
new file mode 100644
index 000000000000..8a4744d1efcd
--- /dev/null
+++ b/vcl/aqua/source/gdi/salgdi.cxx
@@ -0,0 +1,2672 @@
+/*************************************************************************
+ *
+ * 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 "salconst.h"
+#include "salgdi.h"
+#include "salbmp.h"
+#include "salframe.h"
+#include "salcolorutils.hxx"
+#include "sft.hxx"
+#include "salatsuifontutils.hxx"
+
+#include "vcl/impfont.hxx"
+#include "vcl/fontsubset.hxx"
+#include "vcl/sysdata.hxx"
+#include "vcl/sallayout.hxx"
+#include "vcl/svapp.hxx"
+
+#include "osl/file.hxx"
+#include "osl/process.h"
+
+#include "vos/mutex.hxx"
+
+#include "rtl/bootstrap.h"
+#include "rtl/strbuf.hxx"
+
+#include "basegfx/range/b2drectangle.hxx"
+#include "basegfx/polygon/b2dpolygon.hxx"
+#include "basegfx/polygon/b2dpolygontools.hxx"
+#include "basegfx/matrix/b2dhommatrix.hxx"
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+using namespace vcl;
+
+typedef unsigned char Boolean; // copied from MacTypes.h, should be properly included
+typedef std::vector<unsigned char> ByteVector;
+
+
+// =======================================================================
+
+ImplMacFontData::ImplMacFontData( const ImplDevFontAttributes& rDFA, ATSUFontID nFontId )
+: ImplFontData( rDFA, 0 )
+, mnFontId( nFontId )
+, mpCharMap( NULL )
+, mbOs2Read( false )
+, mbHasOs2Table( false )
+, mbCmapEncodingRead( false )
+, mbHasCJKSupport( false )
+{}
+
+// -----------------------------------------------------------------------
+
+ImplMacFontData::~ImplMacFontData()
+{
+ if( mpCharMap )
+ mpCharMap->DeReference();
+}
+
+// -----------------------------------------------------------------------
+
+sal_IntPtr ImplMacFontData::GetFontId() const
+{
+ return (sal_IntPtr)mnFontId;
+}
+
+// -----------------------------------------------------------------------
+
+ImplFontData* ImplMacFontData::Clone() const
+{
+ ImplMacFontData* pClone = new ImplMacFontData(*this);
+ if( mpCharMap )
+ mpCharMap->AddReference();
+ return pClone;
+}
+
+// -----------------------------------------------------------------------
+
+ImplFontEntry* ImplMacFontData::CreateFontInstance(ImplFontSelectData& rFSD) const
+{
+ return new ImplFontEntry(rFSD);
+}
+
+// -----------------------------------------------------------------------
+
+inline FourCharCode GetTag(const char aTagName[5])
+{
+ return (aTagName[0]<<24)+(aTagName[1]<<16)+(aTagName[2]<<8)+(aTagName[3]);
+}
+
+static unsigned GetUShort( const unsigned char* p ){return((p[0]<<8)+p[1]);}
+static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
+
+ImplFontCharMap* ImplMacFontData::GetImplFontCharMap() const
+{
+ if( mpCharMap )
+ {
+ // return the cached charmap
+ mpCharMap->AddReference();
+ return mpCharMap;
+ }
+
+ // set the default charmap
+ mpCharMap = ImplFontCharMap::GetDefaultMap();
+
+ // get the CMAP byte size
+ ATSFontRef rFont = FMGetATSFontRefFromFont( mnFontId );
+ ByteCount nBufSize = 0;
+ OSStatus eStatus = ATSFontGetTable( rFont, GetTag("cmap"), 0, 0, NULL, &nBufSize );
+ DBG_ASSERT( (eStatus==noErr), "ImplMacFontData::GetImplFontCharMap : ATSFontGetTable1 failed!\n");
+ if( eStatus != noErr )
+ return mpCharMap;
+
+ // allocate a buffer for the CMAP raw data
+ ByteVector aBuffer( nBufSize );
+
+ // get the CMAP raw data
+ ByteCount nRawLength = 0;
+ eStatus = ATSFontGetTable( rFont, GetTag("cmap"), 0, nBufSize, (void*)&aBuffer[0], &nRawLength );
+ DBG_ASSERT( (eStatus==noErr), "ImplMacFontData::GetImplFontCharMap : ATSFontGetTable2 failed!\n");
+ if( eStatus != noErr )
+ return mpCharMap;
+ DBG_ASSERT( (nBufSize==nRawLength), "ImplMacFontData::GetImplFontCharMap : ByteCount mismatch!\n");
+
+ // parse the CMAP
+ CmapResult aCmapResult;
+ if( !ParseCMAP( &aBuffer[0], nRawLength, aCmapResult ) )
+ return mpCharMap;
+
+ mpCharMap = new ImplFontCharMap( aCmapResult );
+ return mpCharMap;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplMacFontData::ReadOs2Table( void ) const
+{
+ // read this only once per font
+ if( mbOs2Read )
+ return;
+ mbOs2Read = true;
+
+ // prepare to get the OS/2 table raw data
+ ATSFontRef rFont = FMGetATSFontRefFromFont( mnFontId );
+ ByteCount nBufSize = 0;
+ OSStatus eStatus = ATSFontGetTable( rFont, GetTag("OS/2"), 0, 0, NULL, &nBufSize );
+ DBG_ASSERT( (eStatus==noErr), "ImplMacFontData::ReadOs2Table : ATSFontGetTable1 failed!\n");
+ if( eStatus != noErr )
+ return;
+
+ // allocate a buffer for the OS/2 raw data
+ ByteVector aBuffer( nBufSize );
+
+ // get the OS/2 raw data
+ ByteCount nRawLength = 0;
+ eStatus = ATSFontGetTable( rFont, GetTag("OS/2"), 0, nBufSize, (void*)&aBuffer[0], &nRawLength );
+ DBG_ASSERT( (eStatus==noErr), "ImplMacFontData::ReadOs2Table : ATSFontGetTable2 failed!\n");
+ if( eStatus != noErr )
+ return;
+ DBG_ASSERT( (nBufSize==nRawLength), "ImplMacFontData::ReadOs2Table : ByteCount mismatch!\n");
+ mbHasOs2Table = true;
+
+ // parse the OS/2 raw data
+ // TODO: also analyze panose info, etc.
+
+ // check if the fonts needs the "CJK extra leading" heuristic
+ const unsigned char* pOS2map = &aBuffer[0];
+ const sal_uInt32 nVersion = GetUShort( pOS2map );
+ if( nVersion >= 0x0001 )
+ {
+ sal_uInt32 ulUnicodeRange2 = GetUInt( pOS2map + 46 );
+ if( ulUnicodeRange2 & 0x2DF00000 )
+ mbHasCJKSupport = true;
+ }
+}
+
+void ImplMacFontData::ReadMacCmapEncoding( void ) const
+{
+ // read this only once per font
+ if( mbCmapEncodingRead )
+ return;
+ mbCmapEncodingRead = true;
+
+ ATSFontRef rFont = FMGetATSFontRefFromFont( mnFontId );
+ ByteCount nBufSize = 0;
+ OSStatus eStatus = ATSFontGetTable( rFont, GetTag("cmap"), 0, 0, NULL, &nBufSize );
+ DBG_ASSERT( (eStatus==noErr), "ImplMacFontData::ReadMacCmapEncoding : ATSFontGetTable1 failed!\n");
+ if( eStatus != noErr )
+ return;
+
+ ByteVector aBuffer( nBufSize );
+
+ ByteCount nRawLength = 0;
+ eStatus = ATSFontGetTable( rFont, GetTag("cmap"), 0, nBufSize, (void*)&aBuffer[0], &nRawLength );
+ DBG_ASSERT( (eStatus==noErr), "ImplMacFontData::ReadMacCmapEncoding : ATSFontGetTable2 failed!\n");
+ if( eStatus != noErr )
+ return;
+ DBG_ASSERT( (nBufSize==nRawLength), "ImplMacFontData::ReadMacCmapEncoding : ByteCount mismatch!\n");
+
+ const unsigned char* pCmap = &aBuffer[0];
+
+ if (nRawLength < 24 )
+ return;
+ if( GetUShort( pCmap ) != 0x0000 )
+ return;
+
+ // check if the fonts needs the "CJK extra leading" heuristic
+ int nSubTables = GetUShort( pCmap + 2 );
+
+ for( const unsigned char* p = pCmap + 4; --nSubTables >= 0; p += 8 )
+ {
+ int nPlatform = GetUShort( p );
+ if( nPlatform == kFontMacintoshPlatform ) {
+ int nEncoding = GetUShort (p + 2 );
+ if( nEncoding == kFontJapaneseScript ||
+ nEncoding == kFontTraditionalChineseScript ||
+ nEncoding == kFontKoreanScript ||
+ nEncoding == kFontSimpleChineseScript )
+ {
+ mbHasCJKSupport = true;
+ break;
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+bool ImplMacFontData::HasCJKSupport( void ) const
+{
+ ReadOs2Table();
+ if( !mbHasOs2Table )
+ ReadMacCmapEncoding();
+
+ return mbHasCJKSupport;
+}
+
+// =======================================================================
+
+AquaSalGraphics::AquaSalGraphics()
+ : mpFrame( NULL )
+ , mxLayer( NULL )
+ , mrContext( NULL )
+ , mpXorEmulation( NULL )
+ , mnXorMode( 0 )
+ , mnWidth( 0 )
+ , mnHeight( 0 )
+ , mnBitmapDepth( 0 )
+ , mnRealDPIX( 0 )
+ , mnRealDPIY( 0 )
+ , mfFakeDPIScale( 1.0 )
+ , mxClipPath( NULL )
+ , maLineColor( COL_WHITE )
+ , maFillColor( COL_BLACK )
+ , mpMacFontData( NULL )
+ , mnATSUIRotation( 0 )
+ , mfFontScale( 1.0 )
+ , mfFontStretch( 1.0 )
+ , mbNonAntialiasedText( false )
+ , mbPrinter( false )
+ , mbVirDev( false )
+ , mbWindow( false )
+{
+ // create the style object for font attributes
+ ATSUCreateStyle( &maATSUStyle );
+}
+
+// -----------------------------------------------------------------------
+
+AquaSalGraphics::~AquaSalGraphics()
+{
+/*
+ if( mnUpdateGraphicsEvent )
+ {
+ Application::RemoveUserEvent( mnUpdateGraphicsEvent );
+ }
+*/
+ CGPathRelease( mxClipPath );
+ ATSUDisposeStyle( maATSUStyle );
+
+ if( mpXorEmulation )
+ delete mpXorEmulation;
+
+ if( mxLayer )
+ CGLayerRelease( mxLayer );
+ else if( mrContext && mbWindow )
+ {
+ // destroy backbuffer bitmap context that we created ourself
+ CGContextRelease( mrContext );
+ mrContext = NULL;
+ // memory is freed automatically by maOwnContextMemory
+ }
+}
+
+bool AquaSalGraphics::supportsOperation( OutDevSupportType eType ) const
+{
+ bool bRet = false;
+ switch( eType )
+ {
+ case OutDevSupport_TransparentRect:
+ case OutDevSupport_B2DClip:
+ case OutDevSupport_B2DDraw:
+ bRet = true;
+ break;
+ default: break;
+ }
+ return bRet;
+}
+
+// =======================================================================
+
+void AquaSalGraphics::updateResolution()
+{
+ DBG_ASSERT( mbWindow, "updateResolution on inappropriate graphics" );
+
+ initResolution( (mbWindow && mpFrame) ? mpFrame->mpWindow : nil );
+}
+
+void AquaSalGraphics::initResolution( NSWindow* pWin )
+{
+ // #i100617# read DPI only once; there is some kind of weird caching going on
+ // if the main screen changes
+ // FIXME: this is really unfortunate and needs to be investigated
+
+ SalData* pSalData = GetSalData();
+ if( pSalData->mnDPIX == 0 || pSalData->mnDPIY == 0 )
+ {
+ NSScreen* pScreen = nil;
+
+ /* #i91301#
+ many woes went into the try to have different resolutions
+ on different screens. The result of these trials is that OOo is not ready
+ for that yet, vcl and applications would need to be adapted.
+
+ Unfortunately this is not possible in the 3.0 timeframe.
+ So let's stay with one resolution for all Windows and VirtualDevices
+ which is the resolution of the main screen
+
+ This of course also means that measurements are exact only on the main screen.
+ For activating different resolutions again just comment out the two lines below.
+
+ if( pWin )
+ pScreen = [pWin screen];
+ */
+ if( pScreen == nil )
+ {
+ NSArray* pScreens = [NSScreen screens];
+ if( pScreens )
+ pScreen = [pScreens objectAtIndex: 0];
+ }
+
+ mnRealDPIX = mnRealDPIY = 96;
+ if( pScreen )
+ {
+ NSDictionary* pDev = [pScreen deviceDescription];
+ if( pDev )
+ {
+ NSNumber* pVal = [pDev objectForKey: @"NSScreenNumber"];
+ if( pVal )
+ {
+ // FIXME: casting a long to CGDirectDisplayID is evil, but
+ // Apple suggest to do it this way
+ const CGDirectDisplayID nDisplayID = (CGDirectDisplayID)[pVal longValue];
+ const CGSize aSize = CGDisplayScreenSize( nDisplayID ); // => result is in millimeters
+ mnRealDPIX = static_cast<long>((CGDisplayPixelsWide( nDisplayID ) * 25.4) / aSize.width);
+ mnRealDPIY = static_cast<long>((CGDisplayPixelsHigh( nDisplayID ) * 25.4) / aSize.height);
+ }
+ else
+ {
+ DBG_ERROR( "no resolution found in device description" );
+ }
+ }
+ else
+ {
+ DBG_ERROR( "no device description" );
+ }
+ }
+ else
+ {
+ DBG_ERROR( "no screen found" );
+ }
+
+ // #i107076# maintaining size-WYSIWYG-ness causes many problems for
+ // low-DPI, high-DPI or for mis-reporting devices
+ // => it is better to limit the calculation result then
+ static const int nMinDPI = 72;
+ if( (mnRealDPIX < nMinDPI) || (mnRealDPIY < nMinDPI) )
+ mnRealDPIX = mnRealDPIY = nMinDPI;
+ static const int nMaxDPI = 200;
+ if( (mnRealDPIX > nMaxDPI) || (mnRealDPIY > nMaxDPI) )
+ mnRealDPIX = mnRealDPIY = nMaxDPI;
+
+ // for OSX any anisotropy reported for the display resolution is best ignored (e.g. TripleHead2Go)
+ mnRealDPIX = mnRealDPIY = (mnRealDPIX + mnRealDPIY + 1) / 2;
+
+ pSalData->mnDPIX = mnRealDPIX;
+ pSalData->mnDPIY = mnRealDPIY;
+ }
+ else
+ {
+ mnRealDPIX = pSalData->mnDPIX;
+ mnRealDPIY = pSalData->mnDPIY;
+ }
+
+ mfFakeDPIScale = 1.0;
+}
+
+void AquaSalGraphics::GetResolution( long& rDPIX, long& rDPIY )
+{
+ if( !mnRealDPIY )
+ initResolution( (mbWindow && mpFrame) ? mpFrame->mpWindow : nil );
+
+ rDPIX = static_cast<long>(mfFakeDPIScale * mnRealDPIX);
+ rDPIY = static_cast<long>(mfFakeDPIScale * mnRealDPIY);
+}
+
+void AquaSalGraphics::copyResolution( AquaSalGraphics& rGraphics )
+{
+ if( !rGraphics.mnRealDPIY && rGraphics.mbWindow && rGraphics.mpFrame )
+ rGraphics.initResolution( rGraphics.mpFrame->mpWindow );
+
+ mnRealDPIX = rGraphics.mnRealDPIX;
+ mnRealDPIY = rGraphics.mnRealDPIY;
+ mfFakeDPIScale = rGraphics.mfFakeDPIScale;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT AquaSalGraphics::GetBitCount()
+{
+ USHORT nBits = mnBitmapDepth ? mnBitmapDepth : 32;//24;
+ return nBits;
+}
+
+// -----------------------------------------------------------------------
+
+static const basegfx::B2DPoint aHalfPointOfs ( 0.5, 0.5 );
+
+static void AddPolygonToPath( CGMutablePathRef xPath,
+ const ::basegfx::B2DPolygon& rPolygon, bool bClosePath, bool bPixelSnap, bool bLineDraw )
+{
+ // short circuit if there is nothing to do
+ const int nPointCount = rPolygon.count();
+ if( nPointCount <= 0 )
+ return;
+
+ (void)bPixelSnap; // TODO
+ const CGAffineTransform* pTransform = NULL;
+
+ const bool bHasCurves = rPolygon.areControlPointsUsed();
+ for( int nPointIdx = 0, nPrevIdx = 0;; nPrevIdx = nPointIdx++ )
+ {
+ int nClosedIdx = nPointIdx;
+ if( nPointIdx >= nPointCount )
+ {
+ // prepare to close last curve segment if needed
+ if( bClosePath && (nPointIdx == nPointCount) )
+ nClosedIdx = 0;
+ else
+ break;
+ }
+
+ ::basegfx::B2DPoint aPoint = rPolygon.getB2DPoint( nClosedIdx );
+
+ if( bPixelSnap)
+ {
+ // snap device coordinates to full pixels
+ aPoint.setX( basegfx::fround( aPoint.getX() ) );
+ aPoint.setY( basegfx::fround( aPoint.getY() ) );
+ }
+
+ if( bLineDraw )
+ aPoint += aHalfPointOfs;
+
+ if( !nPointIdx ) { // first point => just move there
+ CGPathMoveToPoint( xPath, pTransform, aPoint.getX(), aPoint.getY() );
+ continue;
+ }
+
+ bool bPendingCurve = false;
+ if( bHasCurves )
+ {
+ bPendingCurve = rPolygon.isNextControlPointUsed( nPrevIdx );
+ bPendingCurve |= rPolygon.isPrevControlPointUsed( nClosedIdx );
+ }
+
+ if( !bPendingCurve ) // line segment
+ CGPathAddLineToPoint( xPath, pTransform, aPoint.getX(), aPoint.getY() );
+ else // cubic bezier segment
+ {
+ basegfx::B2DPoint aCP1 = rPolygon.getNextControlPoint( nPrevIdx );
+ basegfx::B2DPoint aCP2 = rPolygon.getPrevControlPoint( nClosedIdx );
+ if( bLineDraw )
+ {
+ aCP1 += aHalfPointOfs;
+ aCP2 += aHalfPointOfs;
+ }
+ CGPathAddCurveToPoint( xPath, pTransform, aCP1.getX(), aCP1.getY(),
+ aCP2.getX(), aCP2.getY(), aPoint.getX(), aPoint.getY() );
+ }
+ }
+
+ if( bClosePath )
+ CGPathCloseSubpath( xPath );
+}
+
+static void AddPolyPolygonToPath( CGMutablePathRef xPath,
+ const ::basegfx::B2DPolyPolygon& rPolyPoly, bool bPixelSnap, bool bLineDraw )
+{
+ // short circuit if there is nothing to do
+ const int nPolyCount = rPolyPoly.count();
+ if( nPolyCount <= 0 )
+ return;
+
+ for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx )
+ {
+ const ::basegfx::B2DPolygon rPolygon = rPolyPoly.getB2DPolygon( nPolyIdx );
+ AddPolygonToPath( xPath, rPolygon, true, bPixelSnap, bLineDraw );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::ResetClipRegion()
+{
+ // release old path and indicate no clipping
+ if( mxClipPath )
+ {
+ CGPathRelease( mxClipPath );
+ mxClipPath = NULL;
+ }
+ if( CheckContext() )
+ SetState();
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::BeginSetClipRegion( ULONG nRectCount )
+{
+ // release old clip path
+ if( mxClipPath )
+ {
+ CGPathRelease( mxClipPath );
+ mxClipPath = NULL;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalGraphics::unionClipRegion( long nX, long nY, long nWidth, long nHeight )
+{
+ if( (nWidth <= 0) || (nHeight <= 0) )
+ return TRUE;
+
+ if( !mxClipPath )
+ mxClipPath = CGPathCreateMutable();
+ const CGRect aClipRect = {{nX,nY},{nWidth,nHeight}};
+ CGPathAddRect( mxClipPath, NULL, aClipRect );
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+bool AquaSalGraphics::unionClipRegion( const ::basegfx::B2DPolyPolygon& rPolyPolygon )
+{
+ if( rPolyPolygon.count() <= 0 )
+ return true;
+
+ if( !mxClipPath )
+ mxClipPath = CGPathCreateMutable();
+ AddPolyPolygonToPath( mxClipPath, rPolyPolygon, !getAntiAliasB2DDraw(), false );
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::EndSetClipRegion()
+{
+ if( CheckContext() )
+ SetState();
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::SetLineColor()
+{
+ maLineColor.SetAlpha( 0.0 ); // transparent
+ if( CheckContext() )
+ CGContextSetStrokeColor( mrContext, maLineColor.AsArray() );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::SetLineColor( SalColor nSalColor )
+{
+ maLineColor = RGBAColor( nSalColor );
+ if( CheckContext() )
+ CGContextSetStrokeColor( mrContext, maLineColor.AsArray() );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::SetFillColor()
+{
+ maFillColor.SetAlpha( 0.0 ); // transparent
+ if( CheckContext() )
+ CGContextSetFillColor( mrContext, maFillColor.AsArray() );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::SetFillColor( SalColor nSalColor )
+{
+ maFillColor = RGBAColor( nSalColor );
+ if( CheckContext() )
+ CGContextSetFillColor( mrContext, maFillColor.AsArray() );
+}
+
+// -----------------------------------------------------------------------
+
+static SalColor ImplGetROPSalColor( SalROPColor nROPColor )
+{
+ SalColor nSalColor;
+ if ( nROPColor == SAL_ROP_0 )
+ nSalColor = MAKE_SALCOLOR( 0, 0, 0 );
+ else
+ nSalColor = MAKE_SALCOLOR( 255, 255, 255 );
+ return nSalColor;
+}
+
+void AquaSalGraphics::SetROPLineColor( SalROPColor nROPColor )
+{
+ if( ! mbPrinter )
+ SetLineColor( ImplGetROPSalColor( nROPColor ) );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::SetROPFillColor( SalROPColor nROPColor )
+{
+ if( ! mbPrinter )
+ SetFillColor( ImplGetROPSalColor( nROPColor ) );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::ImplDrawPixel( long nX, long nY, const RGBAColor& rColor )
+{
+ if( !CheckContext() )
+ return;
+
+ // overwrite the fill color
+ CGContextSetFillColor( mrContext, rColor.AsArray() );
+ // draw 1x1 rect, there is no pixel drawing in Quartz
+ CGRect aDstRect = {{nX,nY,},{1,1}};
+ CGContextFillRect( mrContext, aDstRect );
+ RefreshRect( aDstRect );
+ // reset the fill color
+ CGContextSetFillColor( mrContext, maFillColor.AsArray() );
+}
+
+void AquaSalGraphics::drawPixel( long nX, long nY )
+{
+ // draw pixel with current line color
+ ImplDrawPixel( nX, nY, maLineColor );
+}
+
+void AquaSalGraphics::drawPixel( long nX, long nY, SalColor nSalColor )
+{
+ const RGBAColor aPixelColor( nSalColor );
+ ImplDrawPixel( nX, nY, aPixelColor );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 )
+{
+ if( nX1 == nX2 && nY1 == nY2 )
+ {
+ // #i109453# platform independent code expects at least one pixel to be drawn
+ drawPixel( nX1, nY1 );
+ return;
+ }
+
+ if( !CheckContext() )
+ return;
+
+ CGContextBeginPath( mrContext );
+ CGContextMoveToPoint( mrContext, static_cast<float>(nX1)+0.5, static_cast<float>(nY1)+0.5 );
+ CGContextAddLineToPoint( mrContext, static_cast<float>(nX2)+0.5, static_cast<float>(nY2)+0.5 );
+ CGContextDrawPath( mrContext, kCGPathStroke );
+
+ Rectangle aRefreshRect( nX1, nY1, nX2, nY2 );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::drawRect( long nX, long nY, long nWidth, long nHeight )
+{
+ if( !CheckContext() )
+ return;
+
+ CGRect aRect( CGRectMake(nX, nY, nWidth, nHeight) );
+ if( IsPenVisible() )
+ {
+ aRect.origin.x += 0.5;
+ aRect.origin.y += 0.5;
+ aRect.size.width -= 1;
+ aRect.size.height -= 1;
+ }
+
+ if( IsBrushVisible() )
+ CGContextFillRect( mrContext, aRect );
+
+ if( IsPenVisible() )
+ CGContextStrokeRect( mrContext, aRect );
+
+ RefreshRect( nX, nY, nWidth, nHeight );
+}
+
+// -----------------------------------------------------------------------
+
+static void getBoundRect( ULONG nPoints, const SalPoint *pPtAry, long &rX, long& rY, long& rWidth, long& rHeight )
+{
+ long nX1 = pPtAry->mnX;
+ long nX2 = nX1;
+ long nY1 = pPtAry->mnY;
+ long nY2 = nY1;
+ for( ULONG n = 1; n < nPoints; n++ )
+ {
+ if( pPtAry[n].mnX < nX1 )
+ nX1 = pPtAry[n].mnX;
+ else if( pPtAry[n].mnX > nX2 )
+ nX2 = pPtAry[n].mnX;
+
+ if( pPtAry[n].mnY < nY1 )
+ nY1 = pPtAry[n].mnY;
+ else if( pPtAry[n].mnY > nY2 )
+ nY2 = pPtAry[n].mnY;
+ }
+ rX = nX1;
+ rY = nY1;
+ rWidth = nX2 - nX1 + 1;
+ rHeight = nY2 - nY1 + 1;
+}
+
+static inline void alignLinePoint( const SalPoint* i_pIn, float& o_fX, float& o_fY )
+{
+ o_fX = static_cast<float>(i_pIn->mnX ) + 0.5;
+ o_fY = static_cast<float>(i_pIn->mnY ) + 0.5;
+}
+
+void AquaSalGraphics::drawPolyLine( ULONG nPoints, const SalPoint *pPtAry )
+{
+ if( nPoints < 1 )
+ return;
+ if( !CheckContext() )
+ return;
+
+ long nX = 0, nY = 0, nWidth = 0, nHeight = 0;
+ getBoundRect( nPoints, pPtAry, nX, nY, nWidth, nHeight );
+
+ float fX, fY;
+
+ CGContextBeginPath( mrContext );
+ alignLinePoint( pPtAry, fX, fY );
+ CGContextMoveToPoint( mrContext, fX, fY );
+ pPtAry++;
+ for( ULONG nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ )
+ {
+ alignLinePoint( pPtAry, fX, fY );
+ CGContextAddLineToPoint( mrContext, fX, fY );
+ }
+ CGContextDrawPath( mrContext, kCGPathStroke );
+
+ RefreshRect( nX, nY, nWidth, nHeight );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::drawPolygon( ULONG nPoints, const SalPoint *pPtAry )
+{
+ if( nPoints <= 1 )
+ return;
+ if( !CheckContext() )
+ return;
+
+ long nX = 0, nY = 0, nWidth = 0, nHeight = 0;
+ getBoundRect( nPoints, pPtAry, nX, nY, nWidth, nHeight );
+
+ CGPathDrawingMode eMode;
+ if( IsBrushVisible() && IsPenVisible() )
+ eMode = kCGPathEOFillStroke;
+ else if( IsPenVisible() )
+ eMode = kCGPathStroke;
+ else if( IsBrushVisible() )
+ eMode = kCGPathEOFill;
+ else
+ return;
+
+ CGContextBeginPath( mrContext );
+
+ if( IsPenVisible() )
+ {
+ float fX, fY;
+ alignLinePoint( pPtAry, fX, fY );
+ CGContextMoveToPoint( mrContext, fX, fY );
+ pPtAry++;
+ for( ULONG nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ )
+ {
+ alignLinePoint( pPtAry, fX, fY );
+ CGContextAddLineToPoint( mrContext, fX, fY );
+ }
+ }
+ else
+ {
+ CGContextMoveToPoint( mrContext, pPtAry->mnX, pPtAry->mnY );
+ pPtAry++;
+ for( ULONG nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ )
+ CGContextAddLineToPoint( mrContext, pPtAry->mnX, pPtAry->mnY );
+ }
+
+ CGContextDrawPath( mrContext, eMode );
+ RefreshRect( nX, nY, nWidth, nHeight );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::drawPolyPolygon( ULONG nPolyCount, const ULONG *pPoints, PCONSTSALPOINT *ppPtAry )
+{
+ if( nPolyCount <= 0 )
+ return;
+ if( !CheckContext() )
+ return;
+
+ // find bound rect
+ long leftX = 0, topY = 0, maxWidth = 0, maxHeight = 0;
+ getBoundRect( pPoints[0], ppPtAry[0], leftX, topY, maxWidth, maxHeight );
+ for( ULONG n = 1; n < nPolyCount; n++ )
+ {
+ long nX = leftX, nY = topY, nW = maxWidth, nH = maxHeight;
+ getBoundRect( pPoints[n], ppPtAry[n], nX, nY, nW, nH );
+ if( nX < leftX )
+ {
+ maxWidth += leftX - nX;
+ leftX = nX;
+ }
+ if( nY < topY )
+ {
+ maxHeight += topY - nY;
+ topY = nY;
+ }
+ if( nX + nW > leftX + maxWidth )
+ maxWidth = nX + nW - leftX;
+ if( nY + nH > topY + maxHeight )
+ maxHeight = nY + nH - topY;
+ }
+
+ // prepare drawing mode
+ CGPathDrawingMode eMode;
+ if( IsBrushVisible() && IsPenVisible() )
+ eMode = kCGPathEOFillStroke;
+ else if( IsPenVisible() )
+ eMode = kCGPathStroke;
+ else if( IsBrushVisible() )
+ eMode = kCGPathEOFill;
+ else
+ return;
+
+ // convert to CGPath
+ CGContextBeginPath( mrContext );
+ if( IsPenVisible() )
+ {
+ for( ULONG nPoly = 0; nPoly < nPolyCount; nPoly++ )
+ {
+ const ULONG nPoints = pPoints[nPoly];
+ if( nPoints > 1 )
+ {
+ const SalPoint *pPtAry = ppPtAry[nPoly];
+ float fX, fY;
+ alignLinePoint( pPtAry, fX, fY );
+ CGContextMoveToPoint( mrContext, fX, fY );
+ pPtAry++;
+ for( ULONG nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ )
+ {
+ alignLinePoint( pPtAry, fX, fY );
+ CGContextAddLineToPoint( mrContext, fX, fY );
+ }
+ CGContextClosePath(mrContext);
+ }
+ }
+ }
+ else
+ {
+ for( ULONG nPoly = 0; nPoly < nPolyCount; nPoly++ )
+ {
+ const ULONG nPoints = pPoints[nPoly];
+ if( nPoints > 1 )
+ {
+ const SalPoint *pPtAry = ppPtAry[nPoly];
+ CGContextMoveToPoint( mrContext, pPtAry->mnX, pPtAry->mnY );
+ pPtAry++;
+ for( ULONG nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ )
+ CGContextAddLineToPoint( mrContext, pPtAry->mnX, pPtAry->mnY );
+ CGContextClosePath(mrContext);
+ }
+ }
+ }
+
+ CGContextDrawPath( mrContext, eMode );
+
+ RefreshRect( leftX, topY, maxWidth, maxHeight );
+}
+
+// -----------------------------------------------------------------------
+
+bool AquaSalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPoly,
+ double fTransparency )
+{
+ // short circuit if there is nothing to do
+ const int nPolyCount = rPolyPoly.count();
+ if( nPolyCount <= 0 )
+ return true;
+
+ // ignore invisible polygons
+ if( (fTransparency >= 1.0) || (fTransparency < 0) )
+ return true;
+
+ // setup poly-polygon path
+ CGMutablePathRef xPath = CGPathCreateMutable();
+ for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx )
+ {
+ const ::basegfx::B2DPolygon rPolygon = rPolyPoly.getB2DPolygon( nPolyIdx );
+ AddPolygonToPath( xPath, rPolygon, true, !getAntiAliasB2DDraw(), IsPenVisible() );
+ }
+
+ const CGRect aRefreshRect = CGPathGetBoundingBox( xPath );
+#ifndef NO_I97317_WORKAROUND
+ // #i97317# workaround for Quartz having problems with drawing small polygons
+ if( ! ((aRefreshRect.size.width <= 0.125) && (aRefreshRect.size.height <= 0.125)) )
+#endif
+ {
+ // use the path to prepare the graphics context
+ CGContextSaveGState( mrContext );
+ CGContextBeginPath( mrContext );
+ CGContextAddPath( mrContext, xPath );
+
+ // draw path with antialiased polygon
+ CGContextSetShouldAntialias( mrContext, true );
+ CGContextSetAlpha( mrContext, 1.0 - fTransparency );
+ CGContextDrawPath( mrContext, kCGPathEOFillStroke );
+ CGContextRestoreGState( mrContext );
+
+ // mark modified rectangle as updated
+ RefreshRect( aRefreshRect );
+ }
+
+ CGPathRelease( xPath );
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+bool AquaSalGraphics::drawPolyLine( const ::basegfx::B2DPolygon& rPolyLine,
+ double fTransparency,
+ const ::basegfx::B2DVector& rLineWidths,
+ basegfx::B2DLineJoin eLineJoin )
+{
+ // short circuit if there is nothing to do
+ const int nPointCount = rPolyLine.count();
+ if( nPointCount <= 0 )
+ return true;
+
+ // reject requests that cannot be handled yet
+ if( rLineWidths.getX() != rLineWidths.getY() )
+ return false;
+
+ // #i101491# Aqua does not support B2DLINEJOIN_NONE; return false to use
+ // the fallback (own geometry preparation)
+ // #i104886# linejoin-mode and thus the above only applies to "fat" lines
+ if( (basegfx::B2DLINEJOIN_NONE == eLineJoin)
+ && (rLineWidths.getX() > 1.3) )
+ return false;
+
+ // setup line attributes
+ CGLineJoin aCGLineJoin = kCGLineJoinMiter;
+ switch( eLineJoin ) {
+ case ::basegfx::B2DLINEJOIN_NONE: aCGLineJoin = /*TODO?*/kCGLineJoinMiter; break;
+ case ::basegfx::B2DLINEJOIN_MIDDLE: aCGLineJoin = /*TODO?*/kCGLineJoinMiter; break;
+ case ::basegfx::B2DLINEJOIN_BEVEL: aCGLineJoin = kCGLineJoinBevel; break;
+ case ::basegfx::B2DLINEJOIN_MITER: aCGLineJoin = kCGLineJoinMiter; break;
+ case ::basegfx::B2DLINEJOIN_ROUND: aCGLineJoin = kCGLineJoinRound; break;
+ }
+
+ // setup poly-polygon path
+ CGMutablePathRef xPath = CGPathCreateMutable();
+ AddPolygonToPath( xPath, rPolyLine, rPolyLine.isClosed(), !getAntiAliasB2DDraw(), true );
+
+ const CGRect aRefreshRect = CGPathGetBoundingBox( xPath );
+#ifndef NO_I97317_WORKAROUND
+ // #i97317# workaround for Quartz having problems with drawing small polygons
+ if( ! ((aRefreshRect.size.width <= 0.125) && (aRefreshRect.size.height <= 0.125)) )
+#endif
+ {
+ // use the path to prepare the graphics context
+ CGContextSaveGState( mrContext );
+ CGContextAddPath( mrContext, xPath );
+ // draw path with antialiased line
+ CGContextSetShouldAntialias( mrContext, true );
+ CGContextSetAlpha( mrContext, 1.0 - fTransparency );
+ CGContextSetLineJoin( mrContext, aCGLineJoin );
+ CGContextSetLineWidth( mrContext, rLineWidths.getX() );
+ CGContextDrawPath( mrContext, kCGPathStroke );
+ CGContextRestoreGState( mrContext );
+
+ // mark modified rectangle as updated
+ RefreshRect( aRefreshRect );
+ }
+
+ CGPathRelease( xPath );
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool AquaSalGraphics::drawPolyLineBezier( ULONG nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry )
+{
+ return sal_False;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool AquaSalGraphics::drawPolygonBezier( ULONG nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry )
+{
+ return sal_False;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool AquaSalGraphics::drawPolyPolygonBezier( ULONG nPoly, const ULONG* pPoints,
+ const SalPoint* const* pPtAry, const BYTE* const* pFlgAry )
+{
+ return sal_False;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::copyBits( const SalTwoRect *pPosAry, SalGraphics *pSrcGraphics )
+{
+ if( !pSrcGraphics )
+ pSrcGraphics = this;
+
+ //from unix salgdi2.cxx
+ //[FIXME] find a better way to prevent calc from crashing when width and height are negative
+ if( pPosAry->mnSrcWidth <= 0
+ || pPosAry->mnSrcHeight <= 0
+ || pPosAry->mnDestWidth <= 0
+ || pPosAry->mnDestHeight <= 0 )
+ {
+ return;
+ }
+
+ // accelerate trivial operations
+ /*const*/ AquaSalGraphics* pSrc = static_cast<AquaSalGraphics*>(pSrcGraphics);
+ const bool bSameGraphics = (this == pSrc) || (mbWindow && mpFrame && pSrc->mbWindow && (mpFrame == pSrc->mpFrame));
+ if( bSameGraphics
+ && (pPosAry->mnSrcWidth == pPosAry->mnDestWidth)
+ && (pPosAry->mnSrcHeight == pPosAry->mnDestHeight))
+ {
+ // short circuit if there is nothing to do
+ if( (pPosAry->mnSrcX == pPosAry->mnDestX)
+ && (pPosAry->mnSrcY == pPosAry->mnDestY))
+ return;
+ // use copyArea() if source and destination context are identical
+ copyArea( pPosAry->mnDestX, pPosAry->mnDestY, pPosAry->mnSrcX, pPosAry->mnSrcY,
+ pPosAry->mnSrcWidth, pPosAry->mnSrcHeight, 0 );
+ return;
+ }
+
+ ApplyXorContext();
+ pSrc->ApplyXorContext();
+
+ DBG_ASSERT( pSrc->mxLayer!=NULL, "AquaSalGraphics::copyBits() from non-layered graphics" );
+
+ const CGPoint aDstPoint = { +pPosAry->mnDestX - pPosAry->mnSrcX, pPosAry->mnDestY - pPosAry->mnSrcY };
+ if( (pPosAry->mnSrcWidth == pPosAry->mnDestWidth && pPosAry->mnSrcHeight == pPosAry->mnDestHeight) &&
+ (!mnBitmapDepth || (aDstPoint.x + pSrc->mnWidth) <= mnWidth) ) // workaround a Quartz crasher
+ {
+ // in XOR mode the drawing context is redirected to the XOR mask
+ // if source and target are identical then copyBits() paints onto the target context though
+ CGContextRef xCopyContext = mrContext;
+ if( mpXorEmulation && mpXorEmulation->IsEnabled() )
+ if( pSrcGraphics == this )
+ xCopyContext = mpXorEmulation->GetTargetContext();
+
+ CGContextSaveGState( xCopyContext );
+ const CGRect aDstRect = { {pPosAry->mnDestX, pPosAry->mnDestY}, {pPosAry->mnDestWidth, pPosAry->mnDestHeight} };
+ CGContextClipToRect( xCopyContext, aDstRect );
+
+ // draw at new destination
+ // NOTE: flipped drawing gets disabled for this, else the subimage would be drawn upside down
+ if( pSrc->IsFlipped() )
+ { CGContextTranslateCTM( xCopyContext, 0, +mnHeight ); CGContextScaleCTM( xCopyContext, +1, -1 ); }
+ // TODO: pSrc->size() != this->size()
+ ::CGContextDrawLayerAtPoint( xCopyContext, aDstPoint, pSrc->mxLayer );
+ CGContextRestoreGState( xCopyContext );
+ // mark the destination rectangle as updated
+ RefreshRect( aDstRect );
+ }
+ else
+ {
+ SalBitmap* pBitmap = pSrc->getBitmap( pPosAry->mnSrcX, pPosAry->mnSrcY, pPosAry->mnSrcWidth, pPosAry->mnSrcHeight );
+
+ if( pBitmap )
+ {
+ SalTwoRect aPosAry( *pPosAry );
+ aPosAry.mnSrcX = 0;
+ aPosAry.mnSrcY = 0;
+ drawBitmap( &aPosAry, *pBitmap );
+ delete pBitmap;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::copyArea( long nDstX, long nDstY,long nSrcX, long nSrcY, long nSrcWidth, long nSrcHeight, USHORT nFlags )
+{
+ ApplyXorContext();
+
+#if 0 // TODO: make AquaSalBitmap as fast as the alternative implementation below
+ SalBitmap* pBitmap = getBitmap( nSrcX, nSrcY, nSrcWidth, nSrcHeight );
+ if( pBitmap )
+ {
+ SalTwoRect aPosAry;
+ aPosAry.mnSrcX = 0;
+ aPosAry.mnSrcY = 0;
+ aPosAry.mnSrcWidth = nSrcWidth;
+ aPosAry.mnSrcHeight = nSrcHeight;
+ aPosAry.mnDestX = nDstX;
+ aPosAry.mnDestY = nDstY;
+ aPosAry.mnDestWidth = nSrcWidth;
+ aPosAry.mnDestHeight = nSrcHeight;
+ drawBitmap( &aPosAry, *pBitmap );
+ delete pBitmap;
+ }
+#else
+ DBG_ASSERT( mxLayer!=NULL, "AquaSalGraphics::copyArea() for non-layered graphics" );
+
+ // in XOR mode the drawing context is redirected to the XOR mask
+ // copyArea() always works on the target context though
+ CGContextRef xCopyContext = mrContext;
+ if( mpXorEmulation && mpXorEmulation->IsEnabled() )
+ xCopyContext = mpXorEmulation->GetTargetContext();
+
+ // drawing a layer onto its own context causes trouble on OSX => copy it first
+ // TODO: is it possible to get rid of this unneeded copy more often?
+ // e.g. on OSX>=10.5 only this situation causes problems:
+ // mnBitmapDepth && (aDstPoint.x + pSrc->mnWidth) > mnWidth
+ CGLayerRef xSrcLayer = mxLayer;
+ // TODO: if( mnBitmapDepth > 0 )
+ {
+ const CGSize aSrcSize = { nSrcWidth, nSrcHeight };
+ xSrcLayer = ::CGLayerCreateWithContext( xCopyContext, aSrcSize, NULL );
+ const CGContextRef xSrcContext = CGLayerGetContext( xSrcLayer );
+ CGPoint aSrcPoint = { -nSrcX, -nSrcY };
+ if( IsFlipped() )
+ {
+ ::CGContextTranslateCTM( xSrcContext, 0, +nSrcHeight );
+ ::CGContextScaleCTM( xSrcContext, +1, -1 );
+ aSrcPoint.y = (nSrcY + nSrcHeight) - mnHeight;
+ }
+ ::CGContextDrawLayerAtPoint( xSrcContext, aSrcPoint, mxLayer );
+ }
+
+ // draw at new destination
+ const CGPoint aDstPoint = { +nDstX, +nDstY };
+ ::CGContextDrawLayerAtPoint( xCopyContext, aDstPoint, xSrcLayer );
+
+ // cleanup
+ if( xSrcLayer != mxLayer )
+ CGLayerRelease( xSrcLayer );
+
+ // mark the destination rectangle as updated
+ RefreshRect( nDstX, nDstY, nSrcWidth, nSrcHeight );
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap )
+{
+ if( !CheckContext() )
+ return;
+
+ const AquaSalBitmap& rBitmap = static_cast<const AquaSalBitmap&>(rSalBitmap);
+ CGImageRef xImage = rBitmap.CreateCroppedImage( (int)pPosAry->mnSrcX, (int)pPosAry->mnSrcY, (int)pPosAry->mnSrcWidth, (int)pPosAry->mnSrcHeight );
+ if( !xImage )
+ return;
+
+ const CGRect aDstRect = {{pPosAry->mnDestX, pPosAry->mnDestY}, {pPosAry->mnDestWidth, pPosAry->mnDestHeight}};
+ CGContextDrawImage( mrContext, aDstRect, xImage );
+ CGImageRelease( xImage );
+ RefreshRect( aDstRect );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap,SalColor nTransparentColor )
+{
+ DBG_ERROR("not implemented for color masking!");
+ drawBitmap( pPosAry, rSalBitmap );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap, const SalBitmap& rTransparentBitmap )
+{
+ if( !CheckContext() )
+ return;
+
+ const AquaSalBitmap& rBitmap = static_cast<const AquaSalBitmap&>(rSalBitmap);
+ const AquaSalBitmap& rMask = static_cast<const AquaSalBitmap&>(rTransparentBitmap);
+ CGImageRef xMaskedImage( rBitmap.CreateWithMask( rMask, pPosAry->mnSrcX, pPosAry->mnSrcY, pPosAry->mnSrcWidth, pPosAry->mnSrcHeight ) );
+ if( !xMaskedImage )
+ return;
+
+ const CGRect aDstRect = {{pPosAry->mnDestX, pPosAry->mnDestY}, {pPosAry->mnDestWidth, pPosAry->mnDestHeight}};
+ CGContextDrawImage( mrContext, aDstRect, xMaskedImage );
+ CGImageRelease( xMaskedImage );
+ RefreshRect( aDstRect );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::drawMask( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap, SalColor nMaskColor )
+{
+ if( !CheckContext() )
+ return;
+
+ const AquaSalBitmap& rBitmap = static_cast<const AquaSalBitmap&>(rSalBitmap);
+ CGImageRef xImage = rBitmap.CreateColorMask( pPosAry->mnSrcX, pPosAry->mnSrcY, pPosAry->mnSrcWidth, pPosAry->mnSrcHeight, nMaskColor );
+ if( !xImage )
+ return;
+
+ const CGRect aDstRect = {{pPosAry->mnDestX, pPosAry->mnDestY}, {pPosAry->mnDestWidth, pPosAry->mnDestHeight}};
+ CGContextDrawImage( mrContext, aDstRect, xImage );
+ CGImageRelease( xImage );
+ RefreshRect( aDstRect );
+}
+
+// -----------------------------------------------------------------------
+
+SalBitmap* AquaSalGraphics::getBitmap( long nX, long nY, long nDX, long nDY )
+{
+ DBG_ASSERT( mxLayer, "AquaSalGraphics::getBitmap() with no layer" );
+
+ ApplyXorContext();
+
+ AquaSalBitmap* pBitmap = new AquaSalBitmap;
+ if( !pBitmap->Create( mxLayer, mnBitmapDepth, nX, nY, nDX, nDY, !mbWindow ) )
+ {
+ delete pBitmap;
+ pBitmap = NULL;
+ }
+
+ return pBitmap;
+}
+
+// -----------------------------------------------------------------------
+
+SalColor AquaSalGraphics::getPixel( long nX, long nY )
+{
+ // return default value on printers or when out of bounds
+ if( !mxLayer
+ || (nX < 0) || (nX >= mnWidth)
+ || (nY < 0) || (nY >= mnHeight))
+ return COL_BLACK;
+
+ // prepare creation of matching a CGBitmapContext
+ CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace;
+ CGBitmapInfo aCGBmpInfo = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Big;
+#if __BIG_ENDIAN__
+ struct{ unsigned char b, g, r, a; } aPixel;
+#else
+ struct{ unsigned char a, r, g, b; } aPixel;
+#endif
+
+ // create a one-pixel bitmap context
+ // TODO: is it worth to cache it?
+ CGContextRef xOnePixelContext = ::CGBitmapContextCreate( &aPixel,
+ 1, 1, 8, sizeof(aPixel), aCGColorSpace, aCGBmpInfo );
+
+ // update this graphics layer
+ ApplyXorContext();
+
+ // copy the requested pixel into the bitmap context
+ if( IsFlipped() )
+ nY = mnHeight - nY;
+ const CGPoint aCGPoint = {-nX, -nY};
+ CGContextDrawLayerAtPoint( xOnePixelContext, aCGPoint, mxLayer );
+ CGContextRelease( xOnePixelContext );
+
+ SalColor nSalColor = MAKE_SALCOLOR( aPixel.r, aPixel.g, aPixel.b );
+ return nSalColor;
+}
+
+// -----------------------------------------------------------------------
+
+
+static void DrawPattern50( void* info, CGContextRef rContext )
+{
+ static const CGRect aRects[2] = { { {0,0}, { 2, 2 } }, { { 2, 2 }, { 2, 2 } } };
+ CGContextAddRects( rContext, aRects, 2 );
+ CGContextFillPath( rContext );
+}
+
+void AquaSalGraphics::Pattern50Fill()
+{
+ static const float aFillCol[4] = { 1,1,1,1 };
+ static const CGPatternCallbacks aCallback = { 0, &DrawPattern50, NULL };
+ if( ! GetSalData()->mxP50Space )
+ GetSalData()->mxP50Space = CGColorSpaceCreatePattern( GetSalData()->mxRGBSpace );
+ if( ! GetSalData()->mxP50Pattern )
+ GetSalData()->mxP50Pattern = CGPatternCreate( NULL, CGRectMake( 0, 0, 4, 4 ),
+ CGAffineTransformIdentity, 4, 4,
+ kCGPatternTilingConstantSpacing,
+ false, &aCallback );
+
+ CGContextSetFillColorSpace( mrContext, GetSalData()->mxP50Space );
+ CGContextSetFillPattern( mrContext, GetSalData()->mxP50Pattern, aFillCol );
+ CGContextFillPath( mrContext );
+}
+
+void AquaSalGraphics::invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags )
+{
+ if ( CheckContext() )
+ {
+ CGRect aCGRect = CGRectMake( nX, nY, nWidth, nHeight);
+ CGContextSaveGState(mrContext);
+
+ if ( nFlags & SAL_INVERT_TRACKFRAME )
+ {
+ const float dashLengths[2] = { 4.0, 4.0 }; // for drawing dashed line
+ CGContextSetBlendMode( mrContext, kCGBlendModeDifference );
+ CGContextSetRGBStrokeColor ( mrContext, 1.0, 1.0, 1.0, 1.0 );
+ CGContextSetLineDash ( mrContext, 0, dashLengths, 2 );
+ CGContextSetLineWidth( mrContext, 2.0);
+ CGContextStrokeRect ( mrContext, aCGRect );
+ }
+ else if ( nFlags & SAL_INVERT_50 )
+ {
+ //CGContextSetAllowsAntialiasing( mrContext, false );
+ CGContextSetBlendMode(mrContext, kCGBlendModeDifference);
+ CGContextAddRect( mrContext, aCGRect );
+ Pattern50Fill();
+ }
+ else // just invert
+ {
+ CGContextSetBlendMode(mrContext, kCGBlendModeDifference);
+ CGContextSetRGBFillColor ( mrContext,1.0, 1.0, 1.0 , 1.0 );
+ CGContextFillRect ( mrContext, aCGRect );
+ }
+ CGContextRestoreGState( mrContext);
+ RefreshRect( aCGRect );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::invert( ULONG nPoints, const SalPoint* pPtAry, SalInvert nSalFlags )
+{
+ CGPoint* CGpoints ;
+ if ( CheckContext() )
+ {
+ CGContextSaveGState(mrContext);
+ CGpoints = makeCGptArray(nPoints,pPtAry);
+ CGContextAddLines ( mrContext, CGpoints, nPoints );
+ if ( nSalFlags & SAL_INVERT_TRACKFRAME )
+ {
+ const float dashLengths[2] = { 4.0, 4.0 }; // for drawing dashed line
+ CGContextSetBlendMode( mrContext, kCGBlendModeDifference );
+ CGContextSetRGBStrokeColor ( mrContext, 1.0, 1.0, 1.0, 1.0 );
+ CGContextSetLineDash ( mrContext, 0, dashLengths, 2 );
+ CGContextSetLineWidth( mrContext, 2.0);
+ CGContextStrokePath ( mrContext );
+ }
+ else if ( nSalFlags & SAL_INVERT_50 )
+ {
+ CGContextSetBlendMode(mrContext, kCGBlendModeDifference);
+ Pattern50Fill();
+ }
+ else // just invert
+ {
+ CGContextSetBlendMode( mrContext, kCGBlendModeDifference );
+ CGContextSetRGBFillColor( mrContext, 1.0, 1.0, 1.0, 1.0 );
+ CGContextFillPath( mrContext );
+ }
+ const CGRect aRefreshRect = CGContextGetClipBoundingBox(mrContext);
+ CGContextRestoreGState( mrContext);
+ delete [] CGpoints;
+ RefreshRect( aRefreshRect );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalGraphics::drawEPS( long nX, long nY, long nWidth, long nHeight,
+ void* pEpsData, ULONG nByteCount )
+{
+ // convert the raw data to an NSImageRef
+ NSData* xNSData = [NSData dataWithBytes:(void*)pEpsData length:(int)nByteCount];
+ NSImageRep* xEpsImage = [NSEPSImageRep imageRepWithData: xNSData];
+ if( !xEpsImage )
+ return false;
+
+ // get the target context
+ if( !CheckContext() )
+ return false;
+
+ // NOTE: flip drawing, else the nsimage would be drawn upside down
+ CGContextSaveGState( mrContext );
+// CGContextTranslateCTM( mrContext, 0, +mnHeight );
+ CGContextScaleCTM( mrContext, +1, -1 );
+ nY = /*mnHeight*/ - (nY + nHeight);
+
+ // prepare the target context
+ NSGraphicsContext* pOrigNSCtx = [NSGraphicsContext currentContext];
+ NSGraphicsContext* pDrawNSCtx = [NSGraphicsContext graphicsContextWithGraphicsPort: mrContext flipped: IsFlipped()];
+ [NSGraphicsContext setCurrentContext: pDrawNSCtx];
+ // draw the EPS
+ const NSRect aDstRect = {{nX,nY},{nWidth,nHeight}};
+ const BOOL bOK = [xEpsImage drawInRect: aDstRect];
+ CGContextRestoreGState( mrContext );
+ // mark the destination rectangle as updated
+ RefreshRect( aDstRect );
+ // restore the NSGraphicsContext, TODO: do we need this?
+ [NSGraphicsContext setCurrentContext: pOrigNSCtx];
+
+ return bOK;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+bool AquaSalGraphics::drawAlphaBitmap( const SalTwoRect& rTR,
+ const SalBitmap& rSrcBitmap, const SalBitmap& rAlphaBmp )
+{
+ // An image mask can't have a depth > 8 bits (should be 1 to 8 bits)
+ if( rAlphaBmp.GetBitCount() > 8 )
+ return false;
+
+ // are these two tests really necessary? (see vcl/unx/source/gdi/salgdi2.cxx)
+ // horizontal/vertical mirroring not implemented yet
+ if( rTR.mnDestWidth < 0 || rTR.mnDestHeight < 0 )
+ return false;
+
+ const AquaSalBitmap& rSrcSalBmp = static_cast<const AquaSalBitmap&>(rSrcBitmap);
+ const AquaSalBitmap& rMaskSalBmp = static_cast<const AquaSalBitmap&>(rAlphaBmp);
+
+ CGImageRef xMaskedImage = rSrcSalBmp.CreateWithMask( rMaskSalBmp, rTR.mnSrcX, rTR.mnSrcY, rTR.mnSrcWidth, rTR.mnSrcHeight );
+ if( !xMaskedImage )
+ return false;
+
+ if ( CheckContext() )
+ {
+ const CGRect aDstRect = {{rTR.mnDestX, rTR.mnDestY}, {rTR.mnDestWidth, rTR.mnDestHeight}};
+ CGContextDrawImage( mrContext, aDstRect, xMaskedImage );
+ RefreshRect( aDstRect );
+ }
+
+ CGImageRelease(xMaskedImage);
+ return true;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+bool AquaSalGraphics::drawAlphaRect( long nX, long nY, long nWidth,
+ long nHeight, sal_uInt8 nTransparency )
+{
+ if( !CheckContext() )
+ return true;
+
+ // save the current state
+ CGContextSaveGState( mrContext );
+ CGContextSetAlpha( mrContext, (100-nTransparency) * (1.0/100) );
+
+ CGRect aRect = {{nX,nY},{nWidth-1,nHeight-1}};
+ if( IsPenVisible() )
+ {
+ aRect.origin.x += 0.5;
+ aRect.origin.y += 0.5;
+ }
+
+ CGContextBeginPath( mrContext );
+ CGContextAddRect( mrContext, aRect );
+ CGContextDrawPath( mrContext, kCGPathFill );
+
+ // restore state
+ CGContextRestoreGState(mrContext);
+ RefreshRect( aRect );
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::SetTextColor( SalColor nSalColor )
+{
+ RGBColor color;
+ color.red = (unsigned short) ( SALCOLOR_RED(nSalColor) * 65535.0 / 255.0 );
+ color.green = (unsigned short) ( SALCOLOR_GREEN(nSalColor) * 65535.0 / 255.0 );
+ color.blue = (unsigned short) ( SALCOLOR_BLUE(nSalColor) * 65535.0 / 255.0 );
+
+ ATSUAttributeTag aTag = kATSUColorTag;
+ ByteCount aValueSize = sizeof( color );
+ ATSUAttributeValuePtr aValue = &color;
+
+ OSStatus err = ATSUSetAttributes( maATSUStyle, 1, &aTag, &aValueSize, &aValue );
+ DBG_ASSERT( (err==noErr), "AquaSalGraphics::SetTextColor() : Could not set font attributes!\n");
+ if( err != noErr )
+ return;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::GetFontMetric( ImplFontMetricData* pMetric )
+{
+ // get the ATSU font metrics (in point units)
+ // of the font that has eventually been size-limited
+
+ ATSUFontID fontId;
+ OSStatus err = ATSUGetAttribute( maATSUStyle, kATSUFontTag, sizeof(ATSUFontID), &fontId, 0 );
+ DBG_ASSERT( (err==noErr), "AquaSalGraphics::GetFontMetric() : could not get font id\n");
+
+ ATSFontMetrics aMetrics;
+ ATSFontRef rFont = FMGetATSFontRefFromFont( fontId );
+ err = ATSFontGetHorizontalMetrics ( rFont, kATSOptionFlagsDefault, &aMetrics );
+ DBG_ASSERT( (err==noErr), "AquaSalGraphics::GetFontMetric() : could not get font metrics\n");
+ if( err != noErr )
+ return;
+
+ // all ATS fonts are scalable fonts
+ pMetric->mbScalableFont = true;
+ // TODO: check if any kerning is possible
+ pMetric->mbKernableFont = true;
+
+ // convert into VCL font metrics (in unscaled pixel units)
+
+ Fixed ptSize;
+ err = ATSUGetAttribute( maATSUStyle, kATSUSizeTag, sizeof(Fixed), &ptSize, 0);
+ DBG_ASSERT( (err==noErr), "AquaSalGraphics::GetFontMetric() : could not get font size\n");
+ const double fPointSize = Fix2X( ptSize );
+
+ // convert quartz units to pixel units
+ // please see the comment in AquaSalGraphics::SetFont() for details
+ const double fPixelSize = (mfFontScale * mfFakeDPIScale * fPointSize);
+ pMetric->mnAscent = static_cast<long>(+aMetrics.ascent * fPixelSize + 0.5);
+ pMetric->mnDescent = static_cast<long>(-aMetrics.descent * fPixelSize + 0.5);
+ const long nExtDescent = static_cast<long>((-aMetrics.descent + aMetrics.leading) * fPixelSize + 0.5);
+ pMetric->mnExtLeading = nExtDescent - pMetric->mnDescent;
+ pMetric->mnIntLeading = 0;
+ // ATSFontMetrics.avgAdvanceWidth is obsolete, so it is usually set to zero
+ // since ImplFontMetricData::mnWidth is only used for stretching/squeezing fonts
+ // setting this width to the pixel height of the fontsize is good enough
+ // it also makes the calculation of the stretch factor simple
+ pMetric->mnWidth = static_cast<long>(mfFontStretch * fPixelSize + 0.5);
+}
+
+// -----------------------------------------------------------------------
+
+ULONG AquaSalGraphics::GetKernPairs( ULONG nPairs, ImplKernPairData* pKernPairs )
+{
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+static bool AddTempFontDir( const char* pDir )
+{
+ FSRef aPathFSRef;
+ Boolean bIsDirectory = true;
+ OSStatus eStatus = FSPathMakeRef( reinterpret_cast<const UInt8*>(pDir), &aPathFSRef, &bIsDirectory );
+ DBG_ASSERTWARNING( (eStatus==noErr) && bIsDirectory, "vcl AddTempFontDir() with invalid directory name!" );
+ if( eStatus != noErr )
+ return false;
+
+ // TODO: deactivate ATSFontContainerRef when closing app
+ ATSFontContainerRef aATSFontContainer;
+
+ const ATSFontContext eContext = kATSFontContextLocal; // TODO: *Global???
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
+ eStatus = ::ATSFontActivateFromFileReference( &aPathFSRef,
+ eContext, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault,
+ &aATSFontContainer );
+#else
+ FSSpec aPathFSSpec;
+ eStatus = ::FSGetCatalogInfo( &aPathFSRef, kFSCatInfoNone,
+ NULL, NULL, &aPathFSSpec, NULL );
+ if( eStatus != noErr )
+ return false;
+
+ eStatus = ::ATSFontActivateFromFileSpecification( &aPathFSSpec,
+ eContext, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault,
+ &aATSFontContainer );
+#endif
+ if( eStatus != noErr )
+ return false;
+
+ return true;
+}
+
+static bool AddLocalTempFontDirs( void )
+{
+ static bool bFirst = true;
+ if( !bFirst )
+ return false;
+ bFirst = false;
+
+ // add private font files found in brand and base layer
+
+ rtl::OUString aBrandStr( RTL_CONSTASCII_USTRINGPARAM( "$BRAND_BASE_DIR" ) );
+ rtl_bootstrap_expandMacros( &aBrandStr.pData );
+ rtl::OUString aBrandSysPath;
+ OSL_VERIFY( osl_getSystemPathFromFileURL( aBrandStr.pData, &aBrandSysPath.pData ) == osl_File_E_None );
+
+ rtl::OStringBuffer aBrandFontDir( aBrandSysPath.getLength()*2 );
+ aBrandFontDir.append( rtl::OUStringToOString( aBrandSysPath, RTL_TEXTENCODING_UTF8 ) );
+ aBrandFontDir.append( "/share/fonts/truetype/" );
+ bool bBrandSuccess = AddTempFontDir( aBrandFontDir.getStr() );
+
+ rtl::OUString aBaseStr( RTL_CONSTASCII_USTRINGPARAM( "$OOO_BASE_DIR" ) );
+ rtl_bootstrap_expandMacros( &aBaseStr.pData );
+ rtl::OUString aBaseSysPath;
+ OSL_VERIFY( osl_getSystemPathFromFileURL( aBaseStr.pData, &aBaseSysPath.pData ) == osl_File_E_None );
+
+ rtl::OStringBuffer aBaseFontDir( aBaseSysPath.getLength()*2 );
+ aBaseFontDir.append( rtl::OUStringToOString( aBaseSysPath, RTL_TEXTENCODING_UTF8 ) );
+ aBaseFontDir.append( "/share/fonts/truetype/" );
+ bool bBaseSuccess = AddTempFontDir( aBaseFontDir.getStr() );
+
+ return bBrandSuccess && bBaseSuccess;
+}
+
+void AquaSalGraphics::GetDevFontList( ImplDevFontList* pFontList )
+{
+ DBG_ASSERT( pFontList, "AquaSalGraphics::GetDevFontList(NULL) !");
+
+ AddLocalTempFontDirs();
+
+ // The idea is to cache the list of system fonts once it has been generated.
+ // SalData seems to be a good place for this caching. However we have to
+ // carefully make the access to the font list thread-safe. If we register
+ // a font-change event handler to update the font list in case fonts have
+ // changed on the system we have to lock access to the list. The right
+ // way to do that is the solar mutex since GetDevFontList is protected
+ // through it as should be all event handlers
+
+ SalData* pSalData = GetSalData();
+ if (pSalData->mpFontList == NULL)
+ pSalData->mpFontList = new SystemFontList();
+
+ // Copy all ImplFontData objects contained in the SystemFontList
+ pSalData->mpFontList->AnnounceFonts( *pFontList );
+}
+
+// -----------------------------------------------------------------------
+
+bool AquaSalGraphics::AddTempDevFont( ImplDevFontList* pFontList,
+ const String& rFontFileURL, const String& rFontName )
+{
+ ::rtl::OUString aUSytemPath;
+ OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL, aUSytemPath ) );
+
+ FSRef aNewRef;
+ Boolean bIsDirectory = true;
+ ::rtl::OString aCFileName = rtl::OUStringToOString( aUSytemPath, RTL_TEXTENCODING_UTF8 );
+ OSStatus eStatus = FSPathMakeRef( (UInt8*)aCFileName.getStr(), &aNewRef, &bIsDirectory );
+ DBG_ASSERT( (eStatus==noErr) && !bIsDirectory, "vcl AddTempDevFont() with invalid fontfile name!" );
+ if( eStatus != noErr )
+ return false;
+
+ ATSFontContainerRef oContainer;
+
+ const ATSFontContext eContext = kATSFontContextLocal; // TODO: *Global???
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
+ eStatus = ::ATSFontActivateFromFileReference( &aNewRef,
+ eContext, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault,
+ &oContainer );
+#else
+ FSSpec aFontFSSpec;
+ eStatus = ::FSGetCatalogInfo( &aNewRef, kFSCatInfoNone,
+ NULL, NULL, &aFontFSSpec, NULL );
+ if( eStatus != noErr )
+ return false;
+
+ eStatus = ::ATSFontActivateFromFileSpecification( &aFontFSSpec,
+ eContext, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault,
+ &oContainer );
+#endif
+ if( eStatus != noErr )
+ return false;
+
+ // TODO: ATSFontDeactivate( oContainer ) when fonts are no longer needed
+ // TODO: register new ImplMacFontdata in pFontList
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+// callbacks from ATSUGlyphGetCubicPaths() fore GetGlyphOutline()
+struct GgoData { basegfx::B2DPolygon maPolygon; basegfx::B2DPolyPolygon* mpPolyPoly; };
+
+static OSStatus GgoLineToProc( const Float32Point* pPoint, void* pData )
+{
+ basegfx::B2DPolygon& rPolygon = static_cast<GgoData*>(pData)->maPolygon;
+ const basegfx::B2DPoint aB2DPoint( pPoint->x, pPoint->y );
+ rPolygon.append( aB2DPoint );
+ return noErr;
+}
+
+static OSStatus GgoCurveToProc( const Float32Point* pCP1, const Float32Point* pCP2,
+ const Float32Point* pPoint, void* pData )
+{
+ basegfx::B2DPolygon& rPolygon = static_cast<GgoData*>(pData)->maPolygon;
+ const sal_uInt32 nPointCount = rPolygon.count();
+ const basegfx::B2DPoint aB2DControlPoint1( pCP1->x, pCP1->y );
+ rPolygon.setNextControlPoint( nPointCount-1, aB2DControlPoint1 );
+ const basegfx::B2DPoint aB2DEndPoint( pPoint->x, pPoint->y );
+ rPolygon.append( aB2DEndPoint );
+ const basegfx::B2DPoint aB2DControlPoint2( pCP2->x, pCP2->y );
+ rPolygon.setPrevControlPoint( nPointCount, aB2DControlPoint2 );
+ return noErr;
+}
+
+static OSStatus GgoClosePathProc( void* pData )
+{
+ GgoData* pGgoData = static_cast<GgoData*>(pData);
+ basegfx::B2DPolygon& rPolygon = pGgoData->maPolygon;
+ if( rPolygon.count() > 0 )
+ pGgoData->mpPolyPoly->append( rPolygon );
+ rPolygon.clear();
+ return noErr;
+}
+
+static OSStatus GgoMoveToProc( const Float32Point* pPoint, void* pData )
+{
+ GgoClosePathProc( pData );
+ OSStatus eStatus = GgoLineToProc( pPoint, pData );
+ return eStatus;
+}
+
+BOOL AquaSalGraphics::GetGlyphOutline( long nGlyphId, basegfx::B2DPolyPolygon& rPolyPoly )
+{
+ GgoData aGgoData;
+ aGgoData.mpPolyPoly = &rPolyPoly;
+ rPolyPoly.clear();
+
+ ATSUStyle rATSUStyle = maATSUStyle; // TODO: handle glyph fallback when CWS pdffix02 is integrated
+ OSStatus eGgoStatus = noErr;
+ OSStatus eStatus = ATSUGlyphGetCubicPaths( rATSUStyle, nGlyphId,
+ GgoMoveToProc, GgoLineToProc, GgoCurveToProc, GgoClosePathProc,
+ &aGgoData, &eGgoStatus );
+ if( (eStatus != noErr) ) // TODO: why is (eGgoStatus!=noErr) when curves are involved?
+ return false;
+
+ GgoClosePathProc( &aGgoData );
+ if( mfFontScale != 1.0 ) {
+ rPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix(+mfFontScale, +mfFontScale));
+ }
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+long AquaSalGraphics::GetGraphicsWidth() const
+{
+ long w = 0;
+ if( mrContext && (mbWindow || mbVirDev) )
+ {
+ w = mnWidth;
+ }
+
+ if( w == 0 )
+ {
+ if( mbWindow && mpFrame )
+ w = mpFrame->maGeometry.nWidth;
+ }
+
+ return w;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalGraphics::GetGlyphBoundRect( long nGlyphId, Rectangle& rRect )
+{
+ ATSUStyle rATSUStyle = maATSUStyle; // TODO: handle glyph fallback
+ GlyphID aGlyphId = nGlyphId;
+ ATSGlyphScreenMetrics aGlyphMetrics;
+ OSStatus eStatus = ATSUGlyphGetScreenMetrics( rATSUStyle,
+ 1, &aGlyphId, 0, FALSE, !mbNonAntialiasedText, &aGlyphMetrics );
+ if( eStatus != noErr )
+ return false;
+
+ const long nMinX = (long)(+aGlyphMetrics.topLeft.x * mfFontScale - 0.5);
+ const long nMaxX = (long)(aGlyphMetrics.width * mfFontScale + 0.5) + nMinX;
+ const long nMinY = (long)(-aGlyphMetrics.topLeft.y * mfFontScale - 0.5);
+ const long nMaxY = (long)(aGlyphMetrics.height * mfFontScale + 0.5) + nMinY;
+ rRect = Rectangle( nMinX, nMinY, nMaxX, nMaxY );
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::GetDevFontSubstList( OutputDevice* )
+{
+ // nothing to do since there are no device-specific fonts on Aqua
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::DrawServerFontLayout( const ServerFontLayout& )
+{
+}
+
+// -----------------------------------------------------------------------
+
+USHORT AquaSalGraphics::SetFont( ImplFontSelectData* pReqFont, int nFallbackLevel )
+{
+ if( !pReqFont )
+ {
+ ATSUClearStyle( maATSUStyle );
+ mpMacFontData = NULL;
+ return 0;
+ }
+
+ // store the requested device font entry
+ const ImplMacFontData* pMacFont = static_cast<const ImplMacFontData*>( pReqFont->mpFontData );
+ mpMacFontData = pMacFont;
+
+ // convert pixel units (as seen by upper layers) to typographic point units
+ double fScaledAtsHeight = pReqFont->mfExactHeight;
+ // avoid Fixed16.16 overflows by limiting the ATS font size
+ static const float fMaxAtsHeight = 144.0;
+ if( fScaledAtsHeight <= fMaxAtsHeight )
+ mfFontScale = 1.0;
+ else
+ {
+ mfFontScale = fScaledAtsHeight / fMaxAtsHeight;
+ fScaledAtsHeight = fMaxAtsHeight;
+ }
+ Fixed fFixedSize = FloatToFixed( fScaledAtsHeight );
+ // enable bold-emulation if needed
+ Boolean bFakeBold = FALSE;
+ if( (pReqFont->GetWeight() >= WEIGHT_BOLD)
+ && (pMacFont->GetWeight() < WEIGHT_SEMIBOLD) )
+ bFakeBold = TRUE;
+ // enable italic-emulation if needed
+ Boolean bFakeItalic = FALSE;
+ if( ((pReqFont->GetSlant() == ITALIC_NORMAL) || (pReqFont->GetSlant() == ITALIC_OBLIQUE))
+ && !((pMacFont->GetSlant() == ITALIC_NORMAL) || (pMacFont->GetSlant() == ITALIC_OBLIQUE)) )
+ bFakeItalic = TRUE;
+
+ // enable/disable antialiased text
+ mbNonAntialiasedText = pReqFont->mbNonAntialiased;
+ UInt32 nStyleRenderingOptions = kATSStyleNoOptions;
+ if( pReqFont->mbNonAntialiased )
+ nStyleRenderingOptions |= kATSStyleNoAntiAliasing;
+
+ // set horizontal/vertical mode
+ ATSUVerticalCharacterType aVerticalCharacterType = kATSUStronglyHorizontal;
+ if( pReqFont->mbVertical )
+ aVerticalCharacterType = kATSUStronglyVertical;
+
+ // prepare ATS-fontid as type matching to the kATSUFontTag request
+ ATSUFontID nFontID = static_cast<ATSUFontID>(pMacFont->GetFontId());
+
+ // update ATSU style attributes with requested font parameters
+ // TODO: no need to set styles which are already defaulted
+
+ const ATSUAttributeTag aTag[] =
+ {
+ kATSUFontTag,
+ kATSUSizeTag,
+ kATSUQDBoldfaceTag,
+ kATSUQDItalicTag,
+ kATSUStyleRenderingOptionsTag,
+ kATSUVerticalCharacterTag
+ };
+
+ const ByteCount aValueSize[] =
+ {
+ sizeof(ATSUFontID),
+ sizeof(fFixedSize),
+ sizeof(bFakeBold),
+ sizeof(bFakeItalic),
+ sizeof(nStyleRenderingOptions),
+ sizeof(aVerticalCharacterType)
+ };
+
+ const ATSUAttributeValuePtr aValue[] =
+ {
+ &nFontID,
+ &fFixedSize,
+ &bFakeBold,
+ &bFakeItalic,
+ &nStyleRenderingOptions,
+ &aVerticalCharacterType
+ };
+
+ static const int nTagCount = sizeof(aTag) / sizeof(*aTag);
+ OSStatus eStatus = ATSUSetAttributes( maATSUStyle, nTagCount,
+ aTag, aValueSize, aValue );
+ // reset ATSUstyle if there was an error
+ if( eStatus != noErr )
+ {
+ DBG_WARNING( "AquaSalGraphics::SetFont() : Could not set font attributes!\n");
+ ATSUClearStyle( maATSUStyle );
+ mpMacFontData = NULL;
+ return 0;
+ }
+
+ // prepare font stretching
+ const ATSUAttributeTag aMatrixTag = kATSUFontMatrixTag;
+ if( (pReqFont->mnWidth == 0) || (pReqFont->mnWidth == pReqFont->mnHeight) )
+ {
+ mfFontStretch = 1.0;
+ ATSUClearAttributes( maATSUStyle, 1, &aMatrixTag );
+ }
+ else
+ {
+ mfFontStretch = (float)pReqFont->mnWidth / pReqFont->mnHeight;
+ CGAffineTransform aMatrix = CGAffineTransformMakeScale( mfFontStretch, 1.0F );
+ const ATSUAttributeValuePtr aAttr = &aMatrix;
+ const ByteCount aMatrixBytes = sizeof(aMatrix);
+ eStatus = ATSUSetAttributes( maATSUStyle, 1, &aMatrixTag, &aMatrixBytes, &aAttr );
+ DBG_ASSERT( (eStatus==noErr), "AquaSalGraphics::SetFont() : Could not set font matrix\n");
+ }
+
+ // prepare font rotation
+ mnATSUIRotation = FloatToFixed( pReqFont->mnOrientation / 10.0 );
+
+#if OSL_DEBUG_LEVEL > 3
+ fprintf( stderr, "SetFont to (\"%s\", \"%s\", fontid=%d) for (\"%s\" \"%s\" weight=%d, slant=%d size=%dx%d orientation=%d)\n",
+ ::rtl::OUStringToOString( pMacFont->GetFamilyName(), RTL_TEXTENCODING_UTF8 ).getStr(),
+ ::rtl::OUStringToOString( pMacFont->GetStyleName(), RTL_TEXTENCODING_UTF8 ).getStr(),
+ (int)nFontID,
+ ::rtl::OUStringToOString( pReqFont->GetFamilyName(), RTL_TEXTENCODING_UTF8 ).getStr(),
+ ::rtl::OUStringToOString( pReqFont->GetStyleName(), RTL_TEXTENCODING_UTF8 ).getStr(),
+ pReqFont->GetWeight(),
+ pReqFont->GetSlant(),
+ pReqFont->mnHeight,
+ pReqFont->mnWidth,
+ pReqFont->mnOrientation);
+#endif
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+ImplFontCharMap* AquaSalGraphics::GetImplFontCharMap() const
+{
+ if( !mpMacFontData )
+ return ImplFontCharMap::GetDefaultMap();
+
+ return mpMacFontData->GetImplFontCharMap();
+}
+
+// -----------------------------------------------------------------------
+
+// fake a SFNT font directory entry for a font table
+// see http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6.html#Directory
+static void FakeDirEntry( FourCharCode eFCC, ByteCount nOfs, ByteCount nLen,
+ const unsigned char* /*pData*/, unsigned char*& rpDest )
+{
+ // write entry tag
+ rpDest[ 0] = (char)(eFCC >> 24);
+ rpDest[ 1] = (char)(eFCC >> 16);
+ rpDest[ 2] = (char)(eFCC >> 8);
+ rpDest[ 3] = (char)(eFCC >> 0);
+ // TODO: get entry checksum and write it
+ // not too important since the subsetter doesn't care currently
+ // for( pData+nOfs ... pData+nOfs+nLen )
+ // write entry offset
+ rpDest[ 8] = (char)(nOfs >> 24);
+ rpDest[ 9] = (char)(nOfs >> 16);
+ rpDest[10] = (char)(nOfs >> 8);
+ rpDest[11] = (char)(nOfs >> 0);
+ // write entry length
+ rpDest[12] = (char)(nLen >> 24);
+ rpDest[13] = (char)(nLen >> 16);
+ rpDest[14] = (char)(nLen >> 8);
+ rpDest[15] = (char)(nLen >> 0);
+ // advance to next entry
+ rpDest += 16;
+}
+
+static bool GetRawFontData( const ImplFontData* pFontData,
+ ByteVector& rBuffer, bool* pJustCFF )
+{
+ const ImplMacFontData* pMacFont = static_cast<const ImplMacFontData*>(pFontData);
+ const ATSUFontID nFontId = static_cast<ATSUFontID>(pMacFont->GetFontId());
+ ATSFontRef rFont = FMGetATSFontRefFromFont( nFontId );
+
+ ByteCount nCffLen = 0;
+ OSStatus eStatus = ATSFontGetTable( rFont, GetTag("CFF "), 0, 0, NULL, &nCffLen);
+ if( pJustCFF != NULL )
+ {
+ *pJustCFF = (eStatus == noErr) && (nCffLen > 0);
+ if( *pJustCFF )
+ {
+ rBuffer.resize( nCffLen );
+ eStatus = ATSFontGetTable( rFont, GetTag("CFF "), 0, nCffLen, (void*)&rBuffer[0], &nCffLen);
+ if( (eStatus != noErr) || (nCffLen <= 0) )
+ return false;
+ return true;
+ }
+ }
+
+ // get font table availability and size in bytes
+ ByteCount nHeadLen = 0;
+ eStatus = ATSFontGetTable( rFont, GetTag("head"), 0, 0, NULL, &nHeadLen);
+ if( (eStatus != noErr) || (nHeadLen <= 0) )
+ return false;
+ ByteCount nMaxpLen = 0;
+ eStatus = ATSFontGetTable( rFont, GetTag("maxp"), 0, 0, NULL, &nMaxpLen);
+ if( (eStatus != noErr) || (nMaxpLen <= 0) )
+ return false;
+ ByteCount nCmapLen = 0;
+ eStatus = ATSFontGetTable( rFont, GetTag("cmap"), 0, 0, NULL, &nCmapLen);
+ if( (eStatus != noErr) || (nCmapLen <= 0) )
+ return false;
+ ByteCount nNameLen = 0;
+ eStatus = ATSFontGetTable( rFont, GetTag("name"), 0, 0, NULL, &nNameLen);
+ if( (eStatus != noErr) || (nNameLen <= 0) )
+ return false;
+ ByteCount nHheaLen = 0;
+ eStatus = ATSFontGetTable( rFont, GetTag("hhea"), 0, 0, NULL, &nHheaLen);
+ if( (eStatus != noErr) || (nHheaLen <= 0) )
+ return false;
+ ByteCount nHmtxLen = 0;
+ eStatus = ATSFontGetTable( rFont, GetTag("hmtx"), 0, 0, NULL, &nHmtxLen);
+ if( (eStatus != noErr) || (nHmtxLen <= 0) )
+ return false;
+
+ // get the glyph outline tables
+ ByteCount nLocaLen = 0;
+ ByteCount nGlyfLen = 0;
+ if( (eStatus != noErr) || (nCffLen <= 0) )
+ {
+ eStatus = ATSFontGetTable( rFont, GetTag("loca"), 0, 0, NULL, &nLocaLen);
+ if( (eStatus != noErr) || (nLocaLen <= 0) )
+ return false;
+ eStatus = ATSFontGetTable( rFont, GetTag("glyf"), 0, 0, NULL, &nGlyfLen);
+ if( (eStatus != noErr) || (nGlyfLen <= 0) )
+ return false;
+ }
+
+ ByteCount nPrepLen=0, nCvtLen=0, nFpgmLen=0;
+ if( nGlyfLen ) // TODO: reduce PDF size by making hint subsetting optional
+ {
+ eStatus = ATSFontGetTable( rFont, GetTag("prep"), 0, 0, NULL, &nPrepLen);
+ eStatus = ATSFontGetTable( rFont, GetTag("cvt "), 0, 0, NULL, &nCvtLen);
+ eStatus = ATSFontGetTable( rFont, GetTag("fpgm"), 0, 0, NULL, &nFpgmLen);
+ }
+
+ // prepare a byte buffer for a fake font
+ int nTableCount = 7;
+ nTableCount += (nPrepLen>0) + (nCvtLen>0) + (nFpgmLen>0) + (nGlyfLen>0);
+ const ByteCount nFdirLen = 12 + 16*nTableCount;
+ ByteCount nTotalLen = nFdirLen;
+ nTotalLen += nHeadLen + nMaxpLen + nNameLen + nCmapLen;
+ if( nGlyfLen )
+ nTotalLen += nLocaLen + nGlyfLen;
+ else
+ nTotalLen += nCffLen;
+ nTotalLen += nHheaLen + nHmtxLen;
+ nTotalLen += nPrepLen + nCvtLen + nFpgmLen;
+ rBuffer.resize( nTotalLen );
+
+ // fake a SFNT font directory header
+ if( nTableCount < 16 )
+ {
+ int nLog2 = 0;
+ while( (nTableCount >> nLog2) > 1 ) ++nLog2;
+ rBuffer[ 1] = 1; // Win-TTF style scaler
+ rBuffer[ 5] = nTableCount; // table count
+ rBuffer[ 7] = nLog2*16; // searchRange
+ rBuffer[ 9] = nLog2; // entrySelector
+ rBuffer[11] = (nTableCount-nLog2)*16; // rangeShift
+ }
+
+ // get font table raw data and update the fake directory entries
+ ByteCount nOfs = nFdirLen;
+ unsigned char* pFakeEntry = &rBuffer[12];
+ eStatus = ATSFontGetTable( rFont, GetTag("cmap"), 0, nCmapLen, (void*)&rBuffer[nOfs], &nCmapLen);
+ FakeDirEntry( GetTag("cmap"), nOfs, nCmapLen, &rBuffer[0], pFakeEntry );
+ nOfs += nCmapLen;
+ if( nCvtLen ) {
+ eStatus = ATSFontGetTable( rFont, GetTag("cvt "), 0, nCvtLen, (void*)&rBuffer[nOfs], &nCvtLen);
+ FakeDirEntry( GetTag("cvt "), nOfs, nCvtLen, &rBuffer[0], pFakeEntry );
+ nOfs += nCvtLen;
+ }
+ if( nFpgmLen ) {
+ eStatus = ATSFontGetTable( rFont, GetTag("fpgm"), 0, nFpgmLen, (void*)&rBuffer[nOfs], &nFpgmLen);
+ FakeDirEntry( GetTag("fpgm"), nOfs, nFpgmLen, &rBuffer[0], pFakeEntry );
+ nOfs += nFpgmLen;
+ }
+ if( nCffLen ) {
+ eStatus = ATSFontGetTable( rFont, GetTag("CFF "), 0, nCffLen, (void*)&rBuffer[nOfs], &nCffLen);
+ FakeDirEntry( GetTag("CFF "), nOfs, nCffLen, &rBuffer[0], pFakeEntry );
+ nOfs += nGlyfLen;
+ } else {
+ eStatus = ATSFontGetTable( rFont, GetTag("glyf"), 0, nGlyfLen, (void*)&rBuffer[nOfs], &nGlyfLen);
+ FakeDirEntry( GetTag("glyf"), nOfs, nGlyfLen, &rBuffer[0], pFakeEntry );
+ nOfs += nGlyfLen;
+ eStatus = ATSFontGetTable( rFont, GetTag("loca"), 0, nLocaLen, (void*)&rBuffer[nOfs], &nLocaLen);
+ FakeDirEntry( GetTag("loca"), nOfs, nLocaLen, &rBuffer[0], pFakeEntry );
+ nOfs += nLocaLen;
+ }
+ eStatus = ATSFontGetTable( rFont, GetTag("head"), 0, nHeadLen, (void*)&rBuffer[nOfs], &nHeadLen);
+ FakeDirEntry( GetTag("head"), nOfs, nHeadLen, &rBuffer[0], pFakeEntry );
+ nOfs += nHeadLen;
+ eStatus = ATSFontGetTable( rFont, GetTag("hhea"), 0, nHheaLen, (void*)&rBuffer[nOfs], &nHheaLen);
+ FakeDirEntry( GetTag("hhea"), nOfs, nHheaLen, &rBuffer[0], pFakeEntry );
+ nOfs += nHheaLen;
+ eStatus = ATSFontGetTable( rFont, GetTag("hmtx"), 0, nHmtxLen, (void*)&rBuffer[nOfs], &nHmtxLen);
+ FakeDirEntry( GetTag("hmtx"), nOfs, nHmtxLen, &rBuffer[0], pFakeEntry );
+ nOfs += nHmtxLen;
+ eStatus = ATSFontGetTable( rFont, GetTag("maxp"), 0, nMaxpLen, (void*)&rBuffer[nOfs], &nMaxpLen);
+ FakeDirEntry( GetTag("maxp"), nOfs, nMaxpLen, &rBuffer[0], pFakeEntry );
+ nOfs += nMaxpLen;
+ eStatus = ATSFontGetTable( rFont, GetTag("name"), 0, nNameLen, (void*)&rBuffer[nOfs], &nNameLen);
+ FakeDirEntry( GetTag("name"), nOfs, nNameLen, &rBuffer[0], pFakeEntry );
+ nOfs += nNameLen;
+ if( nPrepLen ) {
+ eStatus = ATSFontGetTable( rFont, GetTag("prep"), 0, nPrepLen, (void*)&rBuffer[nOfs], &nPrepLen);
+ FakeDirEntry( GetTag("prep"), nOfs, nPrepLen, &rBuffer[0], pFakeEntry );
+ nOfs += nPrepLen;
+ }
+
+ DBG_ASSERT( (nOfs==nTotalLen), "AquaSalGraphics::CreateFontSubset (nOfs!=nTotalLen)");
+
+ return true;
+}
+
+BOOL AquaSalGraphics::CreateFontSubset( const rtl::OUString& rToFile,
+ const ImplFontData* pFontData, long* pGlyphIDs, sal_uInt8* pEncoding,
+ sal_Int32* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rInfo )
+{
+ // TODO: move more of the functionality here into the generic subsetter code
+
+ // prepare the requested file name for writing the font-subset file
+ rtl::OUString aSysPath;
+ if( osl_File_E_None != osl_getSystemPathFromFileURL( rToFile.pData, &aSysPath.pData ) )
+ return FALSE;
+ const rtl_TextEncoding aThreadEncoding = osl_getThreadTextEncoding();
+ const ByteString aToFile( rtl::OUStringToOString( aSysPath, aThreadEncoding ) );
+
+ // get the raw-bytes from the font to be subset
+ ByteVector aBuffer;
+ bool bCffOnly = false;
+ if( !GetRawFontData( pFontData, aBuffer, &bCffOnly ) )
+ return sal_False;
+
+ // handle CFF-subsetting
+ if( bCffOnly )
+ {
+ // provide the raw-CFF data to the subsetter
+ ByteCount nCffLen = aBuffer.size();
+ rInfo.LoadFont( FontSubsetInfo::CFF_FONT, &aBuffer[0], nCffLen );
+
+ // NOTE: assuming that all glyphids requested on Aqua are fully translated
+
+ // make the subsetter provide the requested subset
+ FILE* pOutFile = fopen( aToFile.GetBuffer(), "wb" );
+ bool bRC = rInfo.CreateFontSubset( FontSubsetInfo::TYPE1_PFB, pOutFile, NULL,
+ pGlyphIDs, pEncoding, nGlyphCount, pGlyphWidths );
+ fclose( pOutFile );
+ return bRC;
+ }
+
+ // TODO: modernize psprint's horrible fontsubset C-API
+ // this probably only makes sense after the switch to another SCM
+ // that can preserve change history after file renames
+
+ // prepare data for psprint's font subsetter
+ TrueTypeFont* pSftFont = NULL;
+ int nRC = ::OpenTTFontBuffer( (void*)&aBuffer[0], aBuffer.size(), 0, &pSftFont);
+ if( nRC != SF_OK )
+ return sal_False;
+
+ // get details about the subsetted font
+ TTGlobalFontInfo aTTInfo;
+ ::GetTTGlobalFontInfo( pSftFont, &aTTInfo );
+ rInfo.m_nFontType = FontSubsetInfo::SFNT_TTF;
+ rInfo.m_aPSName = String( aTTInfo.psname, RTL_TEXTENCODING_UTF8 );
+ rInfo.m_aFontBBox = Rectangle( Point( aTTInfo.xMin, aTTInfo.yMin ),
+ Point( aTTInfo.xMax, aTTInfo.yMax ) );
+ rInfo.m_nCapHeight = aTTInfo.yMax; // Well ...
+ rInfo.m_nAscent = +aTTInfo.winAscent;
+ rInfo.m_nDescent = -aTTInfo.winDescent;
+ // mac fonts usually do not have an OS2-table
+ // => get valid ascent/descent values from other tables
+ if( !rInfo.m_nAscent )
+ rInfo.m_nAscent = +aTTInfo.typoAscender;
+ if( !rInfo.m_nAscent )
+ rInfo.m_nAscent = +aTTInfo.ascender;
+ if( !rInfo.m_nDescent )
+ rInfo.m_nDescent = +aTTInfo.typoDescender;
+ if( !rInfo.m_nDescent )
+ rInfo.m_nDescent = -aTTInfo.descender;
+
+ // subset glyphs and get their properties
+ // take care that subset fonts require the NotDef glyph in pos 0
+ int nOrigCount = nGlyphCount;
+ USHORT aShortIDs[ 256 ];
+ sal_uInt8 aTempEncs[ 256 ];
+
+ int nNotDef = -1;
+ for( int i = 0; i < nGlyphCount; ++i )
+ {
+ aTempEncs[i] = pEncoding[i];
+ sal_uInt32 nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK;
+ if( pGlyphIDs[i] & GF_ISCHAR )
+ {
+ bool bVertical = (pGlyphIDs[i] & GF_ROTMASK) != 0;
+ nGlyphIdx = ::MapChar( pSftFont, static_cast<sal_uInt16>(nGlyphIdx), bVertical );
+ if( nGlyphIdx == 0 && pFontData->IsSymbolFont() )
+ {
+ // #i12824# emulate symbol aliasing U+FXXX <-> U+0XXX
+ nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK;
+ nGlyphIdx = (nGlyphIdx & 0xF000) ? (nGlyphIdx & 0x00FF) : (nGlyphIdx | 0xF000 );
+ nGlyphIdx = ::MapChar( pSftFont, static_cast<sal_uInt16>(nGlyphIdx), bVertical );
+ }
+ }
+ aShortIDs[i] = static_cast<USHORT>( nGlyphIdx );
+ if( !nGlyphIdx )
+ if( nNotDef < 0 )
+ nNotDef = i; // first NotDef glyph found
+ }
+
+ if( nNotDef != 0 )
+ {
+ // add fake NotDef glyph if needed
+ if( nNotDef < 0 )
+ nNotDef = nGlyphCount++;
+
+ // NotDef glyph must be in pos 0 => swap glyphids
+ aShortIDs[ nNotDef ] = aShortIDs[0];
+ aTempEncs[ nNotDef ] = aTempEncs[0];
+ aShortIDs[0] = 0;
+ aTempEncs[0] = 0;
+ }
+ DBG_ASSERT( nGlyphCount < 257, "too many glyphs for subsetting" );
+
+ // TODO: where to get bVertical?
+ const bool bVertical = false;
+
+ // fill the pGlyphWidths array
+ // while making sure that the NotDef glyph is at index==0
+ TTSimpleGlyphMetrics* pGlyphMetrics =
+ ::GetTTSimpleGlyphMetrics( pSftFont, aShortIDs, nGlyphCount, bVertical );
+ if( !pGlyphMetrics )
+ return FALSE;
+ sal_uInt16 nNotDefAdv = pGlyphMetrics[0].adv;
+ pGlyphMetrics[0].adv = pGlyphMetrics[nNotDef].adv;
+ pGlyphMetrics[nNotDef].adv = nNotDefAdv;
+ for( int i = 0; i < nOrigCount; ++i )
+ pGlyphWidths[i] = pGlyphMetrics[i].adv;
+ free( pGlyphMetrics );
+
+ // write subset into destination file
+ nRC = ::CreateTTFromTTGlyphs( pSftFont, aToFile.GetBuffer(), aShortIDs,
+ aTempEncs, nGlyphCount, 0, NULL, 0 );
+ ::CloseTTFont(pSftFont);
+ return (nRC == SF_OK);
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::GetGlyphWidths( const ImplFontData* pFontData, bool bVertical,
+ Int32Vector& rGlyphWidths, Ucs2UIntMap& rUnicodeEnc )
+{
+ rGlyphWidths.clear();
+ rUnicodeEnc.clear();
+
+ if( pFontData->IsSubsettable() )
+ {
+ ByteVector aBuffer;
+ if( !GetRawFontData( pFontData, aBuffer, NULL ) )
+ return;
+
+ // TODO: modernize psprint's horrible fontsubset C-API
+ // this probably only makes sense after the switch to another SCM
+ // that can preserve change history after file renames
+
+ // use the font subsetter to get the widths
+ TrueTypeFont* pSftFont = NULL;
+ int nRC = ::OpenTTFontBuffer( (void*)&aBuffer[0], aBuffer.size(), 0, &pSftFont);
+ if( nRC != SF_OK )
+ return;
+
+ const int nGlyphCount = ::GetTTGlyphCount( pSftFont );
+ if( nGlyphCount > 0 )
+ {
+ // get glyph metrics
+ rGlyphWidths.resize(nGlyphCount);
+ std::vector<sal_uInt16> aGlyphIds(nGlyphCount);
+ for( int i = 0; i < nGlyphCount; i++ )
+ aGlyphIds[i] = static_cast<sal_uInt16>(i);
+ const TTSimpleGlyphMetrics* pGlyphMetrics = ::GetTTSimpleGlyphMetrics(
+ pSftFont, &aGlyphIds[0], nGlyphCount, bVertical );
+ if( pGlyphMetrics )
+ {
+ for( int i = 0; i < nGlyphCount; ++i )
+ rGlyphWidths[i] = pGlyphMetrics[i].adv;
+ free( (void*)pGlyphMetrics );
+ }
+
+ const ImplFontCharMap* pMap = mpMacFontData->GetImplFontCharMap();
+ DBG_ASSERT( pMap && pMap->GetCharCount(), "no charmap" );
+
+ // get unicode<->glyph encoding
+ int nCharCount = pMap->GetCharCount();
+ sal_uInt32 nChar = pMap->GetFirstChar();
+ for(; --nCharCount >= 0; nChar = pMap->GetNextChar( nChar ) )
+ {
+ if( nChar > 0xFFFF ) // TODO: allow UTF-32 chars
+ break;
+ sal_Ucs nUcsChar = static_cast<sal_Ucs>(nChar);
+ sal_uInt32 nGlyph = ::MapChar( pSftFont, nUcsChar, bVertical );
+ if( nGlyph > 0 )
+ rUnicodeEnc[ nUcsChar ] = nGlyph;
+ }
+ }
+
+ ::CloseTTFont( pSftFont );
+ }
+ else if( pFontData->IsEmbeddable() )
+ {
+ // get individual character widths
+#if 0 // FIXME
+ rWidths.reserve( 224 );
+ for( sal_Unicode i = 32; i < 256; ++i )
+ {
+ int nCharWidth = 0;
+ if( ::GetCharWidth32W( mhDC, i, i, &nCharWidth ) )
+ {
+ rUnicodeEnc[ i ] = rWidths.size();
+ rWidths.push_back( nCharWidth );
+ }
+ }
+#else
+ DBG_ERROR("not implemented for non-subsettable fonts!\n");
+#endif
+ }
+}
+
+// -----------------------------------------------------------------------
+
+const Ucs2SIntMap* AquaSalGraphics::GetFontEncodingVector(
+ const ImplFontData* pFontData, const Ucs2OStrMap** ppNonEncoded )
+{
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+const void* AquaSalGraphics::GetEmbedFontData( const ImplFontData* pFontData,
+ const sal_Ucs* pUnicodes,
+ sal_Int32* pWidths,
+ FontSubsetInfo& rInfo,
+ long* pDataLen )
+{
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::FreeEmbedFontData( const void* pData, long nDataLen )
+{
+ // TODO: implementing this only makes sense when the implementation of
+ // AquaSalGraphics::GetEmbedFontData() returns non-NULL
+ DBG_ASSERT( (pData!=NULL), "AquaSalGraphics::FreeEmbedFontData() is not implemented\n");
+}
+
+// -----------------------------------------------------------------------
+
+SystemFontData AquaSalGraphics::GetSysFontData( int /* nFallbacklevel */ ) const
+{
+ SystemFontData aSysFontData;
+ OSStatus err;
+ aSysFontData.nSize = sizeof( SystemFontData );
+
+ // NOTE: Native ATSU font fallbacks are used, not the VCL fallbacks.
+ ATSUFontID fontId;
+ err = ATSUGetAttribute( maATSUStyle, kATSUFontTag, sizeof(fontId), &fontId, 0 );
+ if (err) fontId = 0;
+ aSysFontData.aATSUFontID = (void *) fontId;
+
+ Boolean bFbold;
+ err = ATSUGetAttribute( maATSUStyle, kATSUQDBoldfaceTag, sizeof(bFbold), &bFbold, 0 );
+ if (err) bFbold = FALSE;
+ aSysFontData.bFakeBold = (bool) bFbold;
+
+ Boolean bFItalic;
+ err = ATSUGetAttribute( maATSUStyle, kATSUQDItalicTag, sizeof(bFItalic), &bFItalic, 0 );
+ if (err) bFItalic = FALSE;
+ aSysFontData.bFakeItalic = (bool) bFItalic;
+
+ ATSUVerticalCharacterType aVerticalCharacterType;
+ err = ATSUGetAttribute( maATSUStyle, kATSUVerticalCharacterTag, sizeof(aVerticalCharacterType), &aVerticalCharacterType, 0 );
+ if (!err && aVerticalCharacterType == kATSUStronglyVertical) {
+ aSysFontData.bVerticalCharacterType = true;
+ } else {
+ aSysFontData.bVerticalCharacterType = false;
+ }
+
+ aSysFontData.bAntialias = !mbNonAntialiasedText;
+
+ return aSysFontData;
+}
+
+// -----------------------------------------------------------------------
+
+SystemGraphicsData AquaSalGraphics::GetGraphicsData() const
+{
+ SystemGraphicsData aRes;
+ aRes.nSize = sizeof(aRes);
+ aRes.rCGContext = mrContext;
+ return aRes;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::SetXORMode( bool bSet, bool bInvertOnly )
+{
+ // return early if XOR mode remains unchanged
+ if( mbPrinter )
+ return;
+
+ if( ! bSet && mnXorMode == 2 )
+ {
+ CGContextSetBlendMode( mrContext, kCGBlendModeNormal );
+ mnXorMode = 0;
+ return;
+ }
+ else if( bSet && bInvertOnly && mnXorMode == 0)
+ {
+ CGContextSetBlendMode( mrContext, kCGBlendModeDifference );
+ mnXorMode = 2;
+ return;
+ }
+
+ if( (mpXorEmulation == NULL) && !bSet )
+ return;
+ if( (mpXorEmulation != NULL) && (bSet == mpXorEmulation->IsEnabled()) )
+ return;
+ if( !CheckContext() )
+ return;
+
+ // prepare XOR emulation
+ if( !mpXorEmulation )
+ {
+ mpXorEmulation = new XorEmulation();
+ mpXorEmulation->SetTarget( mnWidth, mnHeight, mnBitmapDepth, mrContext, mxLayer );
+ }
+
+ // change the XOR mode
+ if( bSet )
+ {
+ mpXorEmulation->Enable();
+ mrContext = mpXorEmulation->GetMaskContext();
+ mnXorMode = 1;
+ }
+ else
+ {
+ mpXorEmulation->UpdateTarget();
+ mpXorEmulation->Disable();
+ mrContext = mpXorEmulation->GetTargetContext();
+ mnXorMode = 0;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+// apply the XOR mask to the target context if active and dirty
+void AquaSalGraphics::ApplyXorContext()
+{
+ if( !mpXorEmulation )
+ return;
+ if( mpXorEmulation->UpdateTarget() )
+ RefreshRect( 0, 0, mnWidth, mnHeight ); // TODO: refresh minimal changerect
+}
+
+// ======================================================================
+
+XorEmulation::XorEmulation()
+: mxTargetLayer( NULL )
+, mxTargetContext( NULL )
+, mxMaskContext( NULL )
+, mxTempContext( NULL )
+, mpMaskBuffer( NULL )
+, mpTempBuffer( NULL )
+, mnBufferLongs( 0 )
+, mbIsEnabled( false )
+{}
+
+// ----------------------------------------------------------------------
+
+XorEmulation::~XorEmulation()
+{
+ Disable();
+ SetTarget( 0, 0, 0, NULL, NULL );
+}
+
+// -----------------------------------------------------------------------
+
+void XorEmulation::SetTarget( int nWidth, int nHeight, int nTargetDepth,
+ CGContextRef xTargetContext, CGLayerRef xTargetLayer )
+{
+ // prepare to replace old mask+temp context
+ if( mxMaskContext )
+ {
+ // cleanup the mask context
+ CGContextRelease( mxMaskContext );
+ delete[] mpMaskBuffer;
+ mxMaskContext = NULL;
+ mpMaskBuffer = NULL;
+
+ // cleanup the temp context if needed
+ if( mxTempContext )
+ {
+ CGContextRelease( mxTempContext );
+ delete[] mpTempBuffer;
+ mxTempContext = NULL;
+ mpTempBuffer = NULL;
+ }
+ }
+
+ // return early if there is nothing more to do
+ if( !xTargetContext )
+ return;
+
+ // retarget drawing operations to the XOR mask
+ mxTargetLayer = xTargetLayer;
+ mxTargetContext = xTargetContext;
+
+ // prepare creation of matching CGBitmaps
+ CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace;
+ CGBitmapInfo aCGBmpInfo = kCGImageAlphaNoneSkipFirst;
+ int nBitDepth = nTargetDepth;
+ if( !nBitDepth )
+ nBitDepth = 32;
+ int nBytesPerRow = (nBitDepth == 16) ? 2 : 4;
+ const size_t nBitsPerComponent = (nBitDepth == 16) ? 5 : 8;
+ if( nBitDepth <= 8 )
+ {
+ aCGColorSpace = GetSalData()->mxGraySpace;
+ aCGBmpInfo = kCGImageAlphaNone;
+ nBytesPerRow = 1;
+ }
+ nBytesPerRow *= nWidth;
+ mnBufferLongs = (nHeight * nBytesPerRow + sizeof(ULONG)-1) / sizeof(ULONG);
+
+ // create a XorMask context
+ mpMaskBuffer = new ULONG[ mnBufferLongs ];
+ mxMaskContext = ::CGBitmapContextCreate( mpMaskBuffer,
+ nWidth, nHeight, nBitsPerComponent, nBytesPerRow,
+ aCGColorSpace, aCGBmpInfo );
+ // reset the XOR mask to black
+ memset( mpMaskBuffer, 0, mnBufferLongs * sizeof(ULONG) );
+
+ // a bitmap context will be needed for manual XORing
+ // create one unless the target context is a bitmap context
+ if( nTargetDepth )
+ mpTempBuffer = (ULONG*)CGBitmapContextGetData( mxTargetContext );
+ if( !mpTempBuffer )
+ {
+ // create a bitmap context matching to the target context
+ mpTempBuffer = new ULONG[ mnBufferLongs ];
+ mxTempContext = ::CGBitmapContextCreate( mpTempBuffer,
+ nWidth, nHeight, nBitsPerComponent, nBytesPerRow,
+ aCGColorSpace, aCGBmpInfo );
+ }
+
+ // initialize XOR mask context for drawing
+ CGContextSetFillColorSpace( mxMaskContext, aCGColorSpace );
+ CGContextSetStrokeColorSpace( mxMaskContext, aCGColorSpace );
+ CGContextSetShouldAntialias( mxMaskContext, false );
+
+ // improve the XorMask's XOR emulation a litte
+ // NOTE: currently only enabled for monochrome contexts
+ if( aCGColorSpace == GetSalData()->mxGraySpace )
+ CGContextSetBlendMode( mxMaskContext, kCGBlendModeDifference );
+
+ // intialize the transformation matrix to the drawing target
+ const CGAffineTransform aCTM = CGContextGetCTM( xTargetContext );
+ CGContextConcatCTM( mxMaskContext, aCTM );
+ if( mxTempContext )
+ CGContextConcatCTM( mxTempContext, aCTM );
+
+ // initialize the default XorMask graphics state
+ CGContextSaveGState( mxMaskContext );
+}
+
+// ----------------------------------------------------------------------
+
+bool XorEmulation::UpdateTarget()
+{
+ if( !IsEnabled() )
+ return false;
+
+ // update the temp bitmap buffer if needed
+ if( mxTempContext )
+ CGContextDrawLayerAtPoint( mxTempContext, CGPointZero, mxTargetLayer );
+
+ // do a manual XOR with the XorMask
+ // this approach suffices for simple color manipulations
+ // and also the complex-clipping-XOR-trick used in metafiles
+ const ULONG* pSrc = mpMaskBuffer;
+ ULONG* pDst = mpTempBuffer;
+ for( int i = mnBufferLongs; --i >= 0;)
+ *(pDst++) ^= *(pSrc++);
+
+ // write back the XOR results to the target context
+ if( mxTempContext )
+ {
+ CGImageRef xXorImage = CGBitmapContextCreateImage( mxTempContext );
+ const int nWidth = (int)CGImageGetWidth( xXorImage );
+ const int nHeight = (int)CGImageGetHeight( xXorImage );
+ // TODO: update minimal changerect
+ const CGRect aFullRect = {{0,0},{nWidth,nHeight}};
+ CGContextDrawImage( mxTargetContext, aFullRect, xXorImage );
+ CGImageRelease( xXorImage );
+ }
+
+ // reset the XorMask to black again
+ // TODO: not needed for last update
+ memset( mpMaskBuffer, 0, mnBufferLongs * sizeof(ULONG) );
+
+ // TODO: return FALSE if target was not changed
+ return true;
+}
+
+// =======================================================================
+
diff --git a/vcl/aqua/source/gdi/salgdiutils.cxx b/vcl/aqua/source/gdi/salgdiutils.cxx
new file mode 100755
index 000000000000..f7c234d2c4c4
--- /dev/null
+++ b/vcl/aqua/source/gdi/salgdiutils.cxx
@@ -0,0 +1,300 @@
+/*************************************************************************
+ *
+ * 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 "salgdi.h"
+#include "salframe.h"
+
+#include "basebmp/scanlineformats.hxx"
+#include "basebmp/color.hxx"
+#include "basegfx/range/b2drectangle.hxx"
+#include "basegfx/range/b2irange.hxx"
+#include "basegfx/vector/b2ivector.hxx"
+#include "basegfx/polygon/b2dpolygon.hxx"
+#include "basegfx/polygon/b2dpolygontools.hxx"
+#include <boost/bind.hpp>
+
+#include "vcl/svapp.hxx"
+#include "saldata.hxx"
+
+// ----------------------------------------------------------------------
+
+void AquaSalGraphics::SetWindowGraphics( AquaSalFrame* pFrame )
+{
+ mpFrame = pFrame;
+
+ mbWindow = true;
+ mbPrinter = false;
+ mbVirDev = false;
+}
+
+void AquaSalGraphics::SetPrinterGraphics( CGContextRef xContext, long nDPIX, long nDPIY, double fScale )
+{
+ mbWindow = false;
+ mbPrinter = true;
+ mbVirDev = false;
+
+ mrContext = xContext;
+ mfFakeDPIScale = fScale;
+ mnRealDPIX = nDPIX;
+ mnRealDPIY = nDPIY;
+
+ // a previously set clip path is now invalid
+ if( mxClipPath )
+ {
+ CGPathRelease( mxClipPath );
+ mxClipPath = NULL;
+ }
+
+ if( mrContext )
+ {
+ CGContextSetFillColorSpace( mrContext, GetSalData()->mxRGBSpace );
+ CGContextSetStrokeColorSpace( mrContext, GetSalData()->mxRGBSpace );
+ CGContextSaveGState( mrContext );
+ SetState();
+ }
+}
+
+void AquaSalGraphics::SetVirDevGraphics( CGLayerRef xLayer, CGContextRef xContext,
+ int nBitmapDepth )
+{
+ mbWindow = false;
+ mbPrinter = false;
+ mbVirDev = true;
+
+ // set graphics properties
+ mxLayer = xLayer;
+ mrContext = xContext;
+ mnBitmapDepth = nBitmapDepth;
+
+ // return early if the virdev is being destroyed
+ if( !xContext )
+ return;
+
+ // get new graphics properties
+ if( !mxLayer )
+ {
+ mnWidth = CGBitmapContextGetWidth( mrContext );
+ mnHeight = CGBitmapContextGetHeight( mrContext );
+ }
+ else
+ {
+ const CGSize aSize = CGLayerGetSize( mxLayer );
+ mnWidth = static_cast<int>(aSize.width);
+ mnHeight = static_cast<int>(aSize.height);
+ }
+
+ // prepare graphics for drawing
+ const CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace;
+ CGContextSetFillColorSpace( mrContext, aCGColorSpace );
+ CGContextSetStrokeColorSpace( mrContext, aCGColorSpace );
+
+ // re-enable XorEmulation for the new context
+ if( mpXorEmulation )
+ {
+ mpXorEmulation->SetTarget( mnWidth, mnHeight, mnBitmapDepth, mrContext, mxLayer );
+ if( mpXorEmulation->IsEnabled() )
+ mrContext = mpXorEmulation->GetMaskContext();
+ }
+
+ // initialize stack of CGContext states
+ CGContextSaveGState( mrContext );
+ SetState();
+}
+
+// ----------------------------------------------------------------------
+
+void AquaSalGraphics::InvalidateContext()
+{
+ UnsetState();
+ mrContext = 0;
+}
+
+// ----------------------------------------------------------------------
+
+void AquaSalGraphics::UnsetState()
+{
+ if( mrContext )
+ {
+ CGContextRestoreGState( mrContext );
+ mrContext = 0;
+ }
+ if( mxClipPath )
+ {
+ CGPathRelease( mxClipPath );
+ mxClipPath = NULL;
+ }
+}
+
+void AquaSalGraphics::SetState()
+{
+ CGContextRestoreGState( mrContext );
+ CGContextSaveGState( mrContext );
+
+ // setup clipping
+ if( mxClipPath )
+ {
+ CGContextBeginPath( mrContext ); // discard any existing path
+ CGContextAddPath( mrContext, mxClipPath ); // set the current path to the clipping path
+ CGContextClip( mrContext ); // use it for clipping
+ }
+
+ // set RGB colorspace and line and fill colors
+ CGContextSetFillColor( mrContext, maFillColor.AsArray() );
+ CGContextSetStrokeColor( mrContext, maLineColor.AsArray() );
+ CGContextSetShouldAntialias( mrContext, false );
+ if( mnXorMode == 2 )
+ CGContextSetBlendMode( mrContext, kCGBlendModeDifference );
+}
+
+// ----------------------------------------------------------------------
+
+bool AquaSalGraphics::CheckContext()
+{
+ if( mbWindow && mpFrame != NULL )
+ {
+ const unsigned int nWidth = mpFrame->maGeometry.nWidth;
+ const unsigned int nHeight = mpFrame->maGeometry.nHeight;
+
+ CGContextRef rReleaseContext = 0;
+ CGLayerRef rReleaseLayer = NULL;
+
+ // check if a new drawing context is needed (e.g. after a resize)
+ if( (unsigned(mnWidth) != nWidth) || (unsigned(mnHeight) != nHeight) )
+ {
+ mnWidth = nWidth;
+ mnHeight = nHeight;
+ // prepare to release the corresponding resources
+ rReleaseContext = mrContext;
+ rReleaseLayer = mxLayer;
+ mrContext = NULL;
+ mxLayer = NULL;
+ }
+
+ if( !mrContext )
+ {
+ const CGSize aLayerSize = {nWidth,nHeight};
+ NSGraphicsContext* pNSGContext = [NSGraphicsContext graphicsContextWithWindow: mpFrame->getWindow()];
+ CGContextRef xCGContext = reinterpret_cast<CGContextRef>([pNSGContext graphicsPort]);
+ mxLayer = CGLayerCreateWithContext( xCGContext, aLayerSize, NULL );
+ if( mxLayer )
+ mrContext = CGLayerGetContext( mxLayer );
+
+ if( mrContext )
+ {
+ // copy original layer to resized layer
+ if( rReleaseLayer )
+ CGContextDrawLayerAtPoint( mrContext, CGPointZero, rReleaseLayer );
+
+ CGContextTranslateCTM( mrContext, 0, nHeight );
+ CGContextScaleCTM( mrContext, 1.0, -1.0 );
+ CGContextSetFillColorSpace( mrContext, GetSalData()->mxRGBSpace );
+ CGContextSetStrokeColorSpace( mrContext, GetSalData()->mxRGBSpace );
+ CGContextSaveGState( mrContext );
+ SetState();
+
+ // re-enable XOR emulation for the new context
+ if( mpXorEmulation )
+ mpXorEmulation->SetTarget( mnWidth, mnHeight, mnBitmapDepth, mrContext, mxLayer );
+ }
+ }
+
+ if( rReleaseLayer )
+ CGLayerRelease( rReleaseLayer );
+ else if( rReleaseContext )
+ CGContextRelease( rReleaseContext );
+ }
+
+ DBG_ASSERT( mrContext || mbPrinter, "<<<WARNING>>> AquaSalGraphics::CheckContext() FAILED!!!!\n" );
+ return (mrContext != NULL);
+}
+
+
+void AquaSalGraphics::RefreshRect(float lX, float lY, float lWidth, float lHeight)
+{
+ if( ! mbWindow ) // view only on Window graphics
+ return;
+
+ if( mpFrame )
+ {
+ // update a little more around the designated rectangle
+ // this helps with antialiased rendering
+ const Rectangle aVclRect(Point(static_cast<long int>(lX-1),
+ static_cast<long int>(lY-1) ),
+ Size( static_cast<long int>(lWidth+2),
+ static_cast<long int>(lHeight+2) ) );
+ mpFrame->maInvalidRect.Union( aVclRect );
+ }
+}
+
+CGPoint* AquaSalGraphics::makeCGptArray(ULONG nPoints, const SalPoint* pPtAry)
+{
+ CGPoint *CGpoints = new (CGPoint[nPoints]);
+ if ( CGpoints )
+ {
+ for(ULONG i=0;i<nPoints;i++)
+ {
+ CGpoints[i].x = (float)(pPtAry[i].mnX);
+ CGpoints[i].y = (float)(pPtAry[i].mnY);
+ }
+ }
+ return CGpoints;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::UpdateWindow( NSRect& rRect )
+{
+ if( !mpFrame )
+ return;
+ NSGraphicsContext* pContext = [NSGraphicsContext currentContext];
+ if( (mxLayer != NULL) && (pContext != NULL) )
+ {
+ CGContextRef rCGContext = reinterpret_cast<CGContextRef>([pContext graphicsPort]);
+
+ CGMutablePathRef rClip = mpFrame->getClipPath();
+ if( rClip )
+ {
+ CGContextSaveGState( rCGContext );
+ CGContextBeginPath( rCGContext );
+ CGContextAddPath( rCGContext, rClip );
+ CGContextClip( rCGContext );
+ }
+
+ ApplyXorContext();
+ CGContextDrawLayerAtPoint( rCGContext, CGPointZero, mxLayer );
+ if( rClip ) // cleanup clipping
+ CGContextRestoreGState( rCGContext );
+ }
+ else
+ DBG_ASSERT( mpFrame->mbInitShow, "UpdateWindow called on uneligible graphics" );
+}
+
+// -----------------------------------------------------------------------
+
diff --git a/vcl/aqua/source/gdi/salmathutils.cxx b/vcl/aqua/source/gdi/salmathutils.cxx
new file mode 100755
index 000000000000..8df44acbf730
--- /dev/null
+++ b/vcl/aqua/source/gdi/salmathutils.cxx
@@ -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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "salmathutils.hxx"
+
+#include <stdlib.h>
+
+// =======================================================================
+
+// =======================================================================
+
+#define Swap( x, y ) { x ^= y; y ^= x; x ^= y; }
+
+// =======================================================================
+
+// =======================================================================
+
+// Storage free swapping using XOR
+
+void CSwap ( char &rX, char &rY )
+{
+ Swap( rX, rY );
+} // CSwap
+
+// -----------------------------------------------------------------------
+
+// Storage free swapping using XOR
+
+void UCSwap ( unsigned char &rX, unsigned char &rY )
+{
+ Swap( rX, rY );
+} // UCSwap
+
+// -----------------------------------------------------------------------
+
+// Storage free swapping using XOR
+
+void SSwap ( short &rX, short &rY )
+{
+ Swap( rX, rY );
+} // SSwap
+
+// -----------------------------------------------------------------------
+
+// Storage free swapping using XOR
+
+void USSwap ( unsigned short &rX, unsigned short &rY )
+{
+ Swap( rX, rY );
+} // USSwap
+
+// -----------------------------------------------------------------------
+
+// Storage free swapping using XOR
+
+void LSwap ( long &rX, long &rY )
+{
+ Swap( rX, rY );
+} // LSwap
+
+// -----------------------------------------------------------------------
+
+// Storage free swapping using XOR
+
+void ULSwap ( unsigned long &rX, unsigned long &rY )
+{
+ Swap( rX, rY );
+} // ULSwap
+
+// =======================================================================
+
+// =======================================================================
+
+// -----------------------------------------------------------------------
+//
+// This way of measuring distance is also called the "Manhattan distance."
+// Manhattan distance takes advantage of the fact that the sum of the
+// lengths of the three components of a 3D vector is a rough approxima-
+// tion of the vector's length.
+//
+// -----------------------------------------------------------------------
+
+unsigned long Euclidian2Norm ( const LRectCoorVector pVec )
+{
+ unsigned long ndist = 0;
+
+ if ( pVec )
+ {
+ long nDX = 0;
+ long nDY = 0;
+ long nDZ = 0;
+ unsigned long nMax = 0;
+ unsigned long nMed = 0;
+ unsigned long nMin = 0;
+
+ // Find |x'-x|, |y'-y|, and |z'-z| from (x,y,z) and (x',y',z')
+
+ nDX = pVec[1].x - pVec[0].x;
+ nDY = pVec[1].y - pVec[0].y;
+ nDZ = pVec[1].z - pVec[0].z;
+
+ nMax = (unsigned long)abs( nDX );
+ nMed = (unsigned long)abs( nDY );
+ nMin = (unsigned long)abs( nDZ );
+
+ // Sort them (3 compares, 0-3 swaps)
+
+ if ( nMax < nMed )
+ {
+ Swap( nMax, nMed );
+ } // if
+
+ if ( nMax < nMin )
+ {
+ Swap( nMax, nMin );
+ } // if
+
+ // Approximate Euclidian distance:
+ //
+ // d = max + (11/32)*med + (1/4)*min
+ //
+ // with +/- 8% error, where the exact formulae for d is
+ //
+ // || (x',y',z') - (x,y,z) || = { |x'-x|^2 + |y'-y|^2 + |z'-z|^2 }^(1/2)
+
+ ndist = nMax + ( nMin >> 2UL )
+ + ( ( ( nMed << 3UL ) + ( nMed << 1UL ) + nMed ) >> 5UL );
+ } // if
+
+ return ndist;
+} // RGBDistance
+
+// =======================================================================
+
+// =======================================================================
+
diff --git a/vcl/aqua/source/gdi/salnativewidgets.cxx b/vcl/aqua/source/gdi/salnativewidgets.cxx
new file mode 100644
index 000000000000..5eccf88dc523
--- /dev/null
+++ b/vcl/aqua/source/gdi/salnativewidgets.cxx
@@ -0,0 +1,1525 @@
+/*************************************************************************
+ *
+ * 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 "salconst.h"
+#include "salgdi.h"
+#include "salnativewidgets.h"
+#include "saldata.hxx"
+#include "salframe.h"
+
+#include "vcl/salnativewidgets.hxx"
+#include "vcl/decoview.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/timer.hxx"
+
+#include "premac.h"
+#include <Carbon/Carbon.h>
+#include "postmac.h"
+
+class AquaBlinker : public Timer
+{
+ AquaSalFrame* mpFrame;
+ Rectangle maInvalidateRect;
+
+ AquaBlinker( AquaSalFrame* pFrame, const Rectangle& rRect )
+ : mpFrame( pFrame ), maInvalidateRect( rRect )
+ {
+ mpFrame->maBlinkers.push_back( this );
+ }
+
+ public:
+
+ static void Blink( AquaSalFrame*, const Rectangle&, int nTimeout = 80 );
+
+ virtual void Timeout()
+ {
+ Stop();
+ if( AquaSalFrame::isAlive( mpFrame ) && mpFrame->mbShown )
+ {
+ mpFrame->maBlinkers.remove( this );
+ mpFrame->SendPaintEvent( &maInvalidateRect );
+ }
+ delete this;
+ }
+};
+
+void AquaBlinker::Blink( AquaSalFrame* pFrame, const Rectangle& rRect, int nTimeout )
+{
+ // prevent repeated paints from triggering themselves all the time
+ for( std::list< AquaBlinker* >::const_iterator it = pFrame->maBlinkers.begin();
+ it != pFrame->maBlinkers.end(); ++it )
+ {
+ if( (*it)->maInvalidateRect == rRect )
+ return;
+ }
+ AquaBlinker* pNew = new AquaBlinker( pFrame, rRect );
+ pNew->SetTimeout( nTimeout );
+ pNew->Start();
+}
+
+ControlPart ImplgetCounterPart( ControlPart nPart )
+{
+ ControlPart nCounterPart = 0;
+ switch (nPart)
+ {
+ case PART_BUTTON_UP:
+ nCounterPart = PART_BUTTON_DOWN;
+ break;
+ case PART_BUTTON_DOWN:
+ nCounterPart = PART_BUTTON_UP;
+ break;
+ case PART_BUTTON_LEFT:
+ nCounterPart = PART_BUTTON_RIGHT;
+ break;
+ case PART_BUTTON_RIGHT:
+ nCounterPart = PART_BUTTON_LEFT;
+ break;
+ }
+ return nCounterPart;
+}
+
+
+// Helper returns an HIRect
+
+static HIRect ImplGetHIRectFromRectangle(Rectangle aRect)
+{
+ HIRect aHIRect;
+ aHIRect.origin.x = static_cast<float>(aRect.Left());
+ aHIRect.origin.y = static_cast<float>(aRect.Top());
+ aHIRect.size.width = static_cast<float>(aRect.GetWidth());
+ aHIRect.size.height = static_cast<float>(aRect.GetHeight());
+ return aHIRect;
+}
+
+static ThemeButtonValue ImplGetButtonValue( ButtonValue aButtonValue )
+{
+ switch( aButtonValue )
+ {
+ case BUTTONVALUE_ON:
+ return kThemeButtonOn;
+ break;
+
+ case BUTTONVALUE_OFF:
+ return kThemeButtonOff;
+ break;
+
+ case BUTTONVALUE_MIXED:
+ case BUTTONVALUE_DONTKNOW:
+ default:
+ return kThemeButtonMixed;
+ break;
+ }
+}
+
+static bool AquaGetScrollRect( /* TODO: int nScreen, */ ControlPart nPart,
+ const Rectangle& rControlRect, Rectangle& rResultRect )
+{
+ bool bRetVal = true;
+ rResultRect = rControlRect;
+
+ switch( nPart )
+ {
+ case PART_BUTTON_UP:
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ rResultRect.Top() = rControlRect.Bottom() - 2*BUTTON_HEIGHT;
+ rResultRect.Bottom() = rResultRect.Top() + BUTTON_HEIGHT;
+ break;
+
+ case PART_BUTTON_DOWN:
+ rResultRect.Top() = rControlRect.Bottom() - BUTTON_HEIGHT;
+ break;
+
+ case PART_BUTTON_LEFT:
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ rResultRect.Left() = rControlRect.Right() - 2*BUTTON_WIDTH;
+ rResultRect.Right() = rResultRect.Left() + BUTTON_WIDTH;
+ break;
+
+ case PART_BUTTON_RIGHT:
+ rResultRect.Left() = rControlRect.Right() - BUTTON_WIDTH;
+ break;
+
+ case PART_TRACK_HORZ_AREA:
+ rResultRect.Right() -= BUTTON_WIDTH + 1;
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ rResultRect.Right() -= BUTTON_WIDTH;
+ else
+ rResultRect.Left() += BUTTON_WIDTH + 1;
+ break;
+
+ case PART_TRACK_VERT_AREA:
+ rResultRect.Bottom() -= BUTTON_HEIGHT + 1;
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ rResultRect.Bottom() -= BUTTON_HEIGHT;
+ else
+ rResultRect.Top() += BUTTON_HEIGHT + 1;
+ break;
+ case PART_THUMB_HORZ:
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ {
+ rResultRect.Left() += 8;
+ rResultRect.Right() += 6;
+ }
+ else
+ {
+ rResultRect.Left() += 4;
+ rResultRect.Right() += 4;
+ }
+ break;
+ case PART_THUMB_VERT:
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ {
+ rResultRect.Top() += 8;
+ rResultRect.Bottom() += 8;
+ }
+ else
+ {
+ rResultRect.Top() += 4;
+ rResultRect.Bottom() += 4;
+ }
+ break;
+ case PART_TRACK_HORZ_LEFT:
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ rResultRect.Right() += 8;
+ else
+ rResultRect.Right() += 4;
+ break;
+ case PART_TRACK_HORZ_RIGHT:
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ rResultRect.Left() += 6;
+ else
+ rResultRect.Left() += 4;
+ break;
+ case PART_TRACK_VERT_UPPER:
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ rResultRect.Bottom() += 8;
+ else
+ rResultRect.Bottom() += 4;
+ break;
+ case PART_TRACK_VERT_LOWER:
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ rResultRect.Top() += 8;
+ else
+ rResultRect.Top() += 4;
+ break;
+ default:
+ bRetVal = false;
+ }
+
+ return bRetVal;
+}
+
+/*
+ * IsNativeControlSupported()
+ * --------------------------
+ * Returns TRUE if the platform supports native
+ * drawing of the control defined by nPart.
+ *
+ */
+BOOL AquaSalGraphics::IsNativeControlSupported( ControlType nType, ControlPart nPart )
+{
+ bool bOk = FALSE;
+
+ // Native controls are now defaults
+ // If you want to disable experimental native controls code,
+ // just set the environment variable SAL_NO_NWF to something
+ // and vcl controls will be used as default again.
+
+ switch( nType )
+ {
+ case CTRL_PUSHBUTTON:
+ case CTRL_RADIOBUTTON:
+ case CTRL_CHECKBOX:
+ case CTRL_LISTNODE:
+ if( nPart == PART_ENTIRE_CONTROL )
+ return true;
+ break;
+
+ case CTRL_SCROLLBAR:
+ if( nPart == PART_DRAW_BACKGROUND_HORZ ||
+ nPart == PART_DRAW_BACKGROUND_VERT ||
+ nPart == PART_ENTIRE_CONTROL ||
+ nPart == HAS_THREE_BUTTONS )
+ return true;
+ break;
+
+ case CTRL_SLIDER:
+ if( nPart == PART_TRACK_HORZ_AREA || nPart == PART_TRACK_VERT_AREA )
+ return true;
+ break;
+
+ case CTRL_EDITBOX:
+ if( nPart == PART_ENTIRE_CONTROL ||
+ nPart == HAS_BACKGROUND_TEXTURE )
+ return true;
+ break;
+
+ case CTRL_MULTILINE_EDITBOX:
+ if( nPart == PART_ENTIRE_CONTROL ||
+ nPart == HAS_BACKGROUND_TEXTURE )
+ return true;
+ break;
+
+ case CTRL_SPINBOX:
+ if( nPart == PART_ENTIRE_CONTROL ||
+ nPart == PART_ALL_BUTTONS ||
+ nPart == HAS_BACKGROUND_TEXTURE )
+ return true;
+ break;
+
+ case CTRL_SPINBUTTONS:
+ return false;
+ break;
+
+ case CTRL_COMBOBOX:
+ if( nPart == PART_ENTIRE_CONTROL ||
+ nPart == HAS_BACKGROUND_TEXTURE )
+ return true;
+ break;
+
+ case CTRL_LISTBOX:
+ if( nPart == PART_ENTIRE_CONTROL ||
+ nPart == PART_WINDOW ||
+ nPart == HAS_BACKGROUND_TEXTURE ||
+ nPart == PART_SUB_EDIT
+ )
+ return true;
+ break;
+
+ case CTRL_TAB_ITEM:
+ case CTRL_TAB_PANE:
+ case CTRL_TAB_BODY: // see vcl/source/window/tabpage.cxx
+ case CTRL_FIXEDBORDER:
+ if( nPart == PART_ENTIRE_CONTROL ||
+ nPart == PART_TABS_DRAW_RTL ||
+ nPart == HAS_BACKGROUND_TEXTURE )
+ return true;
+ break;
+
+ // when PART_BUTTON is used, toolbar icons are not highlighted when mouse rolls over.
+ // More Aqua compliant
+ case CTRL_TOOLBAR:
+ if( nPart == PART_ENTIRE_CONTROL ||
+ nPart == PART_DRAW_BACKGROUND_HORZ ||
+ nPart == PART_DRAW_BACKGROUND_VERT)
+ return true;
+ break;
+
+ case CTRL_WINDOW_BACKGROUND:
+ if ( nPart == PART_BACKGROUND_WINDOW ||
+ nPart == PART_BACKGROUND_DIALOG )
+ return true;
+ break;
+
+ case CTRL_MENUBAR:
+ if( nPart == PART_ENTIRE_CONTROL )
+ return true;
+ break;
+
+ case CTRL_TOOLTIP: // ** TO DO
+ #if 0
+ if( nPart == PART_ENTIRE_CONTROL ) // we don't currently support the tooltip
+ return true;
+ #endif
+ break;
+
+ case CTRL_MENU_POPUP:
+ if( nPart == PART_ENTIRE_CONTROL ||
+ nPart == PART_MENU_ITEM ||
+ nPart == PART_MENU_ITEM_CHECK_MARK ||
+ nPart == PART_MENU_ITEM_RADIO_MARK)
+ return true;
+ break;
+ case CTRL_PROGRESS:
+ case CTRL_INTROPROGRESS:
+ if( nPart == PART_ENTIRE_CONTROL )
+ return true;
+ break;
+ case CTRL_FRAME:
+ if( nPart == PART_BORDER )
+ return true;
+ break;
+ case CTRL_LISTNET:
+ if( nPart == PART_ENTIRE_CONTROL )
+ return true;
+ break;
+ }
+
+ return bOk;
+}
+
+/*
+ * 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 AquaSalGraphics::hitTestNativeControl( ControlType nType, ControlPart nPart, const Region& rControlRegion,
+ const Point& rPos, BOOL& rIsInside )
+{
+ if ( nType == CTRL_SCROLLBAR )
+ {
+ Rectangle aRect;
+ bool bValid = AquaGetScrollRect( /* TODO: m_nScreen */ nPart, rControlRegion.GetBoundRect(), aRect );
+ rIsInside = bValid ? aRect.IsInside( rPos ) : FALSE;
+ if( GetSalData()->mbIsScrollbarDoubleMax )
+ {
+ // in double max mode the actual trough is a little smaller than the track
+ // there is some visual filler that is not sensitive
+ if( bValid && rIsInside )
+ {
+ if( nPart == PART_TRACK_HORZ_AREA )
+ {
+ // the left 4 pixels are not hit sensitive
+ if( rPos.X() - aRect.Left() < 4 )
+ rIsInside = FALSE;
+ }
+ else if( nPart == PART_TRACK_VERT_AREA )
+ {
+ // the top 4 pixels are not hit sensitive
+ if( rPos.Y() - aRect.Top() < 4 )
+ rIsInside = FALSE;
+ }
+ }
+ }
+ return bValid;
+ } // CTRL_SCROLLBAR
+
+ return FALSE;
+}
+
+/*
+ kThemeStateInactive = 0,
+ kThemeStateActive = 1,
+ kThemeStatePressed = 2,
+ kThemeStateRollover = 6,
+ kThemeStateUnavailable = 7,
+ kThemeStateUnavailableInactive = 8
+ kThemeStatePressedUp = 2,
+ kThemeStatePressedDown = 3
+
+#define CTRL_STATE_ENABLED 0x0001
+#define CTRL_STATE_FOCUSED 0x0002
+#define CTRL_STATE_PRESSED 0x0004
+#define CTRL_STATE_ROLLOVER 0x0008
+#define CTRL_STATE_HIDDEN 0x0010
+#define CTRL_STATE_DEFAULT 0x0020
+#define CTRL_STATE_SELECTED 0x0040
+#define CTRL_CACHING_ALLOWED 0x8000 // set when the control is completely visible (i.e. not clipped)
+*/
+UInt32 AquaSalGraphics::getState( ControlState nState )
+{
+ bool bDrawActive = mpFrame ? ([mpFrame->getWindow() isKeyWindow] ? true : false) : true;
+ if( (nState & CTRL_STATE_ENABLED) == 0 || ! bDrawActive )
+ {
+ if( (nState & CTRL_STATE_HIDDEN) == 0 )
+ return kThemeStateInactive;
+ else
+ return kThemeStateUnavailableInactive;
+ }
+
+ if( (nState & CTRL_STATE_HIDDEN) != 0 )
+ return kThemeStateUnavailable;
+
+ if( (nState & CTRL_STATE_PRESSED) != 0 )
+ return kThemeStatePressed;
+
+ return kThemeStateActive;
+}
+
+UInt32 AquaSalGraphics::getTrackState( ControlState nState )
+{
+ bool bDrawActive = mpFrame ? ([mpFrame->getWindow() isKeyWindow] ? true : false) : true;
+ if( (nState & CTRL_STATE_ENABLED) == 0 || ! bDrawActive )
+ return kThemeTrackInactive;
+
+ return kThemeTrackActive;
+}
+
+/*
+ * 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 AquaSalGraphics::drawNativeControl(ControlType nType,
+ ControlPart nPart,
+ const Region& rControlRegion,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const rtl::OUString& aCaption )
+{
+ BOOL bOK = FALSE;
+
+ if( ! CheckContext() )
+ return false;
+
+ CGContextSaveGState( mrContext );
+
+ Rectangle buttonRect = rControlRegion.GetBoundRect();
+ HIRect rc = ImplGetHIRectFromRectangle(buttonRect);
+
+ /** Scrollbar parts code equivalent **
+ PART_BUTTON_UP 101
+ PART_BUTTON_DOWN 102
+ PART_THUMB_VERT 211
+ PART_TRACK_VERT_UPPER 201
+ PART_TRACK_VERT_LOWER 203
+
+ PART_DRAW_BACKGROUND_HORZ 1000
+ PART_DRAW_BACKGROUND_VERT 1001
+ **/
+
+ switch( nType )
+ {
+
+ case CTRL_COMBOBOX:
+ if ( nPart == HAS_BACKGROUND_TEXTURE ||
+ nPart == PART_ENTIRE_CONTROL )
+ {
+ HIThemeButtonDrawInfo aComboInfo;
+ aComboInfo.version = 0;
+ aComboInfo.kind = kThemeComboBox;
+ aComboInfo.state = getState( nState );
+ aComboInfo.value = kThemeButtonOn;
+ aComboInfo.adornment = kThemeAdornmentNone;
+
+ if( (nState & CTRL_STATE_FOCUSED) != 0 )
+ aComboInfo.adornment |= kThemeAdornmentFocus;
+
+ HIThemeDrawButton(&rc, &aComboInfo, mrContext, kHIThemeOrientationNormal,&rc);
+ bOK = true;
+ }
+ break;
+
+ case CTRL_FIXEDBORDER:
+ case CTRL_TOOLBAR:
+ {
+ HIThemeMenuItemDrawInfo aMenuItemDrawInfo;
+ aMenuItemDrawInfo.version = 0;
+ aMenuItemDrawInfo.state = kThemeMenuActive;
+ aMenuItemDrawInfo.itemType = kThemeMenuItemHierBackground;
+ HIThemeDrawMenuItem(&rc,&rc,&aMenuItemDrawInfo,mrContext,kHIThemeOrientationNormal,NULL);
+ bOK = true;
+ }
+ break;
+
+ case CTRL_WINDOW_BACKGROUND:
+ {
+ HIThemeBackgroundDrawInfo aThemeBackgroundInfo;
+ aThemeBackgroundInfo.version = 0;
+ aThemeBackgroundInfo.state = getState( nState );
+ aThemeBackgroundInfo.kind = kThemeBrushDialogBackgroundInactive;
+ // FIXME: without this magical offset there is a 2 pixel black border on the right and bottom
+ rc.size.width += 2;
+ rc.size.height += 2;
+
+ HIThemeApplyBackground( &rc, &aThemeBackgroundInfo, mrContext, kHIThemeOrientationNormal);
+ CGContextFillRect( mrContext, rc );
+ bOK = true;
+ }
+ break;
+
+ case CTRL_MENUBAR:
+ case CTRL_MENU_POPUP:
+ {
+ if ((nPart == PART_ENTIRE_CONTROL) || (nPart == PART_MENU_ITEM )|| (nPart == HAS_BACKGROUND_TEXTURE ))
+ {
+ // FIXME: without this magical offset there is a 2 pixel black border on the right
+ rc.size.width += 2;
+
+ HIThemeMenuDrawInfo aMenuInfo;
+ aMenuInfo.version = 0;
+ aMenuInfo.menuType = kThemeMenuTypePullDown;
+
+ HIThemeMenuItemDrawInfo aMenuItemDrawInfo;
+ // the Aqua grey theme when the item is selected is drawn here.
+ aMenuItemDrawInfo.itemType = kThemeMenuItemPlain;
+
+ if ((nPart == PART_MENU_ITEM ) && (nState & CTRL_STATE_SELECTED))
+ {
+ // the blue theme when the item is selected is drawn here.
+ aMenuItemDrawInfo.state = kThemeMenuSelected;
+ }
+ else
+ {
+ // normal color for non selected item
+ aMenuItemDrawInfo.state = kThemeMenuActive;
+ }
+
+ // repaints the background of the pull down menu
+ HIThemeDrawMenuBackground(&rc,&aMenuInfo,mrContext,kHIThemeOrientationNormal);
+
+ // repaints the item either blue (selected) and/or Aqua grey (active only)
+ HIThemeDrawMenuItem(&rc,&rc,&aMenuItemDrawInfo,mrContext,kHIThemeOrientationNormal,&rc);
+
+ bOK = true;
+ }
+ else if(( nPart == PART_MENU_ITEM_CHECK_MARK )||( nPart == PART_MENU_ITEM_RADIO_MARK )) {
+ if( nState & CTRL_STATE_PRESSED ) {//checked, else it is not displayed (see vcl/source/window/menu.cxx)
+ HIThemeTextInfo aTextInfo;
+ aTextInfo.version = 0;
+ aTextInfo.state = ((nState & CTRL_STATE_ENABLED)==0) ? kThemeStateInactive: kThemeStateActive;
+ aTextInfo.fontID = kThemeMenuItemMarkFont;
+ aTextInfo.horizontalFlushness=kHIThemeTextHorizontalFlushCenter;
+ aTextInfo.verticalFlushness=kHIThemeTextVerticalFlushTop;
+ aTextInfo.options=kHIThemeTextBoxOptionNone;
+ aTextInfo.truncationPosition=kHIThemeTextTruncationNone;
+ //aTextInfo.truncationMaxLines unused because of kHIThemeTextTruncationNone
+
+ if( nState & CTRL_STATE_SELECTED) aTextInfo.state = kThemeStatePressed; //item highlighted
+
+ UniChar mark=( nPart == PART_MENU_ITEM_CHECK_MARK ) ? kCheckUnicode: kBulletUnicode;//0x2713;
+ CFStringRef cfString = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, &mark, 1, kCFAllocatorNull);
+ HIThemeDrawTextBox(cfString, &rc, &aTextInfo, mrContext, kHIThemeOrientationNormal);
+ if (cfString)
+ CFRelease(cfString);
+
+ bOK = true;
+ }
+ }
+ }
+ break;
+
+ case CTRL_PUSHBUTTON:
+ {
+ // [ FIXME] : instead of use a value, vcl can retrieve corect values on the fly (to be implemented)
+ const int PB_Mini_Height = 15;
+ const int PB_Norm_Height = 21;
+
+ HIThemeButtonDrawInfo aPushInfo;
+ aPushInfo.version = 0;
+
+ // no animation
+ aPushInfo.animation.time.start = 0;
+ aPushInfo.animation.time.current = 0;
+ PushButtonValue* pPBVal = (PushButtonValue*)aValue.getOptionalVal();
+ int nPaintHeight = static_cast<int>(rc.size.height);
+
+ if( pPBVal && pPBVal->mbBevelButton )
+ {
+ aPushInfo.kind = kThemeRoundedBevelButton;
+ }
+ else if( rc.size.height <= PB_Norm_Height )
+ {
+ aPushInfo.kind = kThemePushButtonMini;
+ nPaintHeight = PB_Mini_Height;
+ }
+ else if( pPBVal->mbSingleLine || rc.size.height < (PB_Norm_Height + PB_Norm_Height/2) )
+ {
+ aPushInfo.kind = kThemePushButtonNormal;
+ nPaintHeight = PB_Norm_Height;
+
+ // avoid clipping when focused
+ rc.origin.x += FOCUS_RING_WIDTH/2;
+ rc.size.width -= FOCUS_RING_WIDTH;
+
+ if( (nState & CTRL_STATE_DEFAULT) != 0 )
+ {
+ AquaBlinker::Blink( mpFrame, buttonRect );
+ // show correct animation phase
+ aPushInfo.animation.time.current = CFAbsoluteTimeGetCurrent();
+ }
+ }
+ else
+ aPushInfo.kind = kThemeBevelButton;
+
+ // translate the origin for controls with fixed paint height
+ // so content ends up somewhere sensible
+ int delta_y = static_cast<int>(rc.size.height) - nPaintHeight;
+ rc.origin.y += delta_y/2;
+
+ aPushInfo.state = getState( nState );
+ aPushInfo.value = ImplGetButtonValue( aValue.getTristateVal() );
+
+ aPushInfo.adornment = (( nState & CTRL_STATE_DEFAULT ) != 0) ?
+ kThemeAdornmentDefault :
+ kThemeAdornmentNone;
+ if( (nState & CTRL_STATE_FOCUSED) != 0 )
+ aPushInfo.adornment |= kThemeAdornmentFocus;
+
+ HIThemeDrawButton( &rc, &aPushInfo, mrContext, kHIThemeOrientationNormal, NULL );
+ bOK = true;
+ }
+ break;
+
+ case CTRL_RADIOBUTTON:
+ case CTRL_CHECKBOX:
+ {
+ HIThemeButtonDrawInfo aInfo;
+ aInfo.version = 0;
+ switch( nType )
+ {
+ case CTRL_RADIOBUTTON: if(rc.size.width >= BUTTON_HEIGHT) aInfo.kind = kThemeRadioButton;
+ else aInfo.kind = kThemeSmallRadioButton;
+ break;
+ case CTRL_CHECKBOX: if(rc.size.width >= BUTTON_HEIGHT) aInfo.kind = kThemeCheckBox;
+ else aInfo.kind = kThemeSmallCheckBox;
+ break;
+ }
+
+ aInfo.state = getState( nState );
+
+ ButtonValue aButtonValue = aValue.getTristateVal();
+ aInfo.value = ImplGetButtonValue( aButtonValue );
+
+ aInfo.adornment = (( nState & CTRL_STATE_DEFAULT ) != 0) ?
+ kThemeAdornmentDefault :
+ kThemeAdornmentNone;
+ if( (nState & CTRL_STATE_FOCUSED) != 0 )
+ aInfo.adornment |= kThemeAdornmentFocus;
+ HIThemeDrawButton( &rc, &aInfo, mrContext, kHIThemeOrientationNormal, NULL );
+ bOK = true;
+ }
+ break;
+
+ case CTRL_LISTNODE:
+ {
+ ButtonValue aButtonValue = aValue.getTristateVal();
+
+ if( Application::GetSettings().GetLayoutRTL() && aButtonValue == BUTTONVALUE_OFF )
+ {
+ // FIXME: a value of kThemeDisclosureLeft
+ // should draw a theme compliant left disclosure triangle
+ // sadly this does not seem to work, so we'll draw a left
+ // grey equilateral triangle here ourselves.
+ // Perhaps some other HIThemeButtonDrawInfo setting would do the trick ?
+
+ CGContextSetShouldAntialias( mrContext, true );
+ float aGrey[] = { 0.45, 0.45, 0.45, 1.0 };
+ CGContextSetFillColor( mrContext, aGrey );
+ CGContextBeginPath( mrContext );
+ float x = rc.origin.x + rc.size.width;
+ float y = rc.origin.y;
+ CGContextMoveToPoint( mrContext, x, y );
+ y += rc.size.height;
+ CGContextAddLineToPoint( mrContext, x, y );
+ x -= rc.size.height * 0.866; // cos( 30 degree ) is approx. 0.866
+ y -= rc.size.height/2;
+ CGContextAddLineToPoint( mrContext, x, y );
+ CGContextDrawPath( mrContext, kCGPathEOFill );
+ }
+ else
+ {
+ HIThemeButtonDrawInfo aInfo;
+ aInfo.version = 0;
+ aInfo.kind = kThemeDisclosureTriangle;
+ aInfo.value = kThemeDisclosureRight;
+ aInfo.state = getState( nState );
+
+ aInfo.adornment = kThemeAdornmentNone;
+
+ switch( aButtonValue ) {
+ case BUTTONVALUE_ON: aInfo.value = kThemeDisclosureDown;//expanded
+ break;
+ case BUTTONVALUE_OFF:
+ // FIXME: this should have drawn a theme compliant disclosure triangle
+ // (see above)
+ if( Application::GetSettings().GetLayoutRTL() )
+ {
+ aInfo.value = kThemeDisclosureLeft;//collapsed, RTL
+ }
+ break;
+ case BUTTONVALUE_DONTKNOW: //what to do?
+ default:
+ break;
+ }
+
+ HIThemeDrawButton( &rc, &aInfo, mrContext, kHIThemeOrientationNormal, NULL );
+ }
+ bOK = true;
+ }
+ break;
+
+ case CTRL_PROGRESS:
+ case CTRL_INTROPROGRESS:
+ {
+ long nProgressWidth = aValue.getNumericVal();
+ HIThemeTrackDrawInfo aTrackInfo;
+ aTrackInfo.version = 0;
+ aTrackInfo.kind = (rc.size.height > 10) ? kThemeProgressBarLarge : kThemeProgressBarMedium;
+ aTrackInfo.bounds = rc;
+ aTrackInfo.min = 0;
+ aTrackInfo.max = static_cast<SInt32>(rc.size.width);
+ aTrackInfo.value = nProgressWidth;
+ aTrackInfo.reserved = 0;
+ aTrackInfo.bounds.origin.y -= 2; // FIXME: magic for shadow
+ aTrackInfo.bounds.size.width -= 2; // FIXME: magic for shadow
+ aTrackInfo.attributes = kThemeTrackHorizontal;
+ if( Application::GetSettings().GetLayoutRTL() )
+ aTrackInfo.attributes |= kThemeTrackRightToLeft;
+ aTrackInfo.enableState = getTrackState( nState );
+ // the intro bitmap never gets key anyway; we want to draw that enabled
+ if( nType == CTRL_INTROPROGRESS )
+ aTrackInfo.enableState = kThemeTrackActive;
+ aTrackInfo.filler1 = 0;
+ aTrackInfo.trackInfo.progress.phase = static_cast<UInt8>(CFAbsoluteTimeGetCurrent()*10.0);
+
+ HIThemeDrawTrack( &aTrackInfo, NULL, mrContext, kHIThemeOrientationNormal );
+ bOK = true;
+ }
+ break;
+
+ case CTRL_SLIDER:
+ {
+ SliderValue* pSLVal = (SliderValue*)aValue.getOptionalVal();
+
+ HIThemeTrackDrawInfo aTrackDraw;
+ aTrackDraw.kind = kThemeSliderMedium;
+ if( nPart == PART_TRACK_HORZ_AREA || nPart == PART_TRACK_VERT_AREA )
+ {
+ aTrackDraw.bounds = rc;
+ aTrackDraw.min = pSLVal->mnMin;
+ aTrackDraw.max = pSLVal->mnMax;;
+ aTrackDraw.value = pSLVal->mnCur;
+ aTrackDraw.reserved = 0;
+ aTrackDraw.attributes = kThemeTrackShowThumb;
+ if( nPart == PART_TRACK_HORZ_AREA )
+ aTrackDraw.attributes |= kThemeTrackHorizontal;
+ aTrackDraw.enableState = (nState & CTRL_STATE_ENABLED)
+ ? kThemeTrackActive : kThemeTrackInactive;
+
+ SliderTrackInfo aSlideInfo;
+ aSlideInfo.thumbDir = kThemeThumbUpward;
+ aSlideInfo.pressState = 0;
+ aTrackDraw.trackInfo.slider = aSlideInfo;
+
+ HIThemeDrawTrack( &aTrackDraw, NULL, mrContext, kHIThemeOrientationNormal );
+ bOK = true;
+ }
+ }
+ break;
+
+ case CTRL_SCROLLBAR:
+ {
+ ScrollbarValue* pScrollbarVal = (ScrollbarValue *)(aValue.getOptionalVal());
+
+ if( nPart == PART_DRAW_BACKGROUND_VERT ||
+ nPart == PART_DRAW_BACKGROUND_HORZ )
+ {
+ HIThemeTrackDrawInfo aTrackDraw;
+ aTrackDraw.kind = kThemeMediumScrollBar;
+ // FIXME: the scrollbar length must be adjusted
+ if (nPart == PART_DRAW_BACKGROUND_VERT)
+ rc.size.height += 2;
+ else
+ rc.size.width += 2;
+
+ aTrackDraw.bounds = rc;
+ aTrackDraw.min = pScrollbarVal->mnMin;
+ aTrackDraw.max = pScrollbarVal->mnMax - pScrollbarVal->mnVisibleSize;
+ aTrackDraw.value = pScrollbarVal->mnCur;
+ aTrackDraw.reserved = 0;
+ aTrackDraw.attributes = kThemeTrackShowThumb;
+ if( nPart == PART_DRAW_BACKGROUND_HORZ )
+ aTrackDraw.attributes |= kThemeTrackHorizontal;
+ aTrackDraw.enableState = getTrackState( nState );
+
+ ScrollBarTrackInfo aScrollInfo;
+ aScrollInfo.viewsize = pScrollbarVal->mnVisibleSize;
+ aScrollInfo.pressState = 0;
+
+ if ( pScrollbarVal->mnButton1State & CTRL_STATE_ENABLED )
+ {
+ if ( pScrollbarVal->mnButton1State & CTRL_STATE_PRESSED )
+ aScrollInfo.pressState = kThemeTopOutsideArrowPressed;
+ }
+
+ if ( pScrollbarVal->mnButton2State & CTRL_STATE_ENABLED )
+ {
+ if ( pScrollbarVal->mnButton2State & CTRL_STATE_PRESSED )
+ aScrollInfo.pressState = kThemeBottomOutsideArrowPressed;
+ }
+
+ if ( pScrollbarVal->mnThumbState & CTRL_STATE_ENABLED )
+ {
+ if ( pScrollbarVal->mnThumbState & CTRL_STATE_PRESSED )
+ aScrollInfo.pressState = kThemeThumbPressed;
+ }
+
+ aTrackDraw.trackInfo.scrollbar = aScrollInfo;
+
+ HIThemeDrawTrack( &aTrackDraw, NULL, mrContext, kHIThemeOrientationNormal );
+ bOK = true;
+ }
+ }
+ break;
+
+//#define OLD_TAB_STYLE
+#ifdef OLD_TAB_STYLE
+ case CTRL_TAB_PANE:
+ {
+ HIThemeTabPaneDrawInfo aTabPaneDrawInfo;
+ aTabPaneDrawInfo.version = 0;
+ aTabPaneDrawInfo.state = kThemeStateActive;
+ aTabPaneDrawInfo.direction=kThemeTabNorth;
+ aTabPaneDrawInfo.size=kHIThemeTabSizeNormal;
+
+ //the border is outside the rect rc for Carbon
+ //but for VCL it should be inside
+ rc.origin.x+=1;
+ rc.size.width-=2;
+
+ HIThemeDrawTabPane(&rc, &aTabPaneDrawInfo, mrContext, kHIThemeOrientationNormal);
+ bOK = true;
+ }
+ break;
+
+ case CTRL_TAB_ITEM:
+ {
+ HIThemeTabDrawInfo aTabItemDrawInfo;
+ aTabItemDrawInfo.version=0;
+ aTabItemDrawInfo.style=kThemeTabNonFront;
+ aTabItemDrawInfo.direction=kThemeTabNorth;
+ aTabItemDrawInfo.size=kHIThemeTabSizeNormal;
+ aTabItemDrawInfo.adornment=kHIThemeTabAdornmentNone;
+
+ if(nState & CTRL_STATE_SELECTED) {
+ aTabItemDrawInfo.style=kThemeTabFront;
+ }
+ if(nState & CTRL_STATE_FOCUSED) {
+ aTabItemDrawInfo.adornment=kHIThemeTabAdornmentFocus;
+ }
+
+ /*if(rc.size.height>=TAB_HEIGHT_NORMAL) rc.size.height=TAB_HEIGHT_NORMAL;
+ else if(rc.size.height>=TAB_HEIGHT_SMALL) rc.size.height=TAB_HEIGHT_SMALL;
+ else rc.size.height=TAB_HEIGHT_MINI;*/
+ //now we only use the default size
+ rc.size.height=TAB_HEIGHT_NORMAL;
+
+ HIThemeDrawTab(&rc, &aTabItemDrawInfo, mrContext, kHIThemeOrientationNormal, &rc );
+
+ bOK=true;
+ }
+ break;
+#else
+ case CTRL_TAB_PANE:
+ {
+ HIThemeTabPaneDrawInfo aTabPaneDrawInfo;
+ aTabPaneDrawInfo.version = 1;
+ aTabPaneDrawInfo.state = kThemeStateActive;
+ aTabPaneDrawInfo.direction=kThemeTabNorth;
+ aTabPaneDrawInfo.size=kHIThemeTabSizeNormal;
+ aTabPaneDrawInfo.kind=kHIThemeTabKindNormal;
+
+ //the border is outside the rect rc for Carbon
+ //but for VCL it should be inside
+ rc.origin.x+=1;
+ rc.origin.y-=TAB_HEIGHT_NORMAL/2;
+ rc.size.height+=TAB_HEIGHT_NORMAL/2;
+ rc.size.width-=2;
+
+ HIThemeDrawTabPane(&rc, &aTabPaneDrawInfo, mrContext, kHIThemeOrientationNormal);
+
+ bOK = true;
+ }
+ break;
+
+ case CTRL_TAB_ITEM:
+ {
+ HIThemeTabDrawInfo aTabItemDrawInfo;
+ aTabItemDrawInfo.version=1;
+ aTabItemDrawInfo.style=kThemeTabNonFront;
+ aTabItemDrawInfo.direction=kThemeTabNorth;
+ aTabItemDrawInfo.size=kHIThemeTabSizeNormal;
+ aTabItemDrawInfo.adornment=kHIThemeTabAdornmentTrailingSeparator;
+ //State
+ if(nState & CTRL_STATE_SELECTED) {
+ aTabItemDrawInfo.style=kThemeTabFront;
+ }
+ if(nState & CTRL_STATE_FOCUSED) {
+ aTabItemDrawInfo.adornment|=kHIThemeTabAdornmentFocus;
+ }
+
+ //first, last or middle tab
+ aTabItemDrawInfo.position=kHIThemeTabPositionMiddle;
+
+ TabitemValue *aTabValue=(TabitemValue *) aValue.getOptionalVal();
+ unsigned int nAlignement=aTabValue->mnAlignment;
+ //TABITEM_LEFTALIGNED (and TABITEM_RIGHTALIGNED) for the leftmost (or rightmost) tab
+ //when there are several lines of tabs because there is only one first tab and one
+ //last tab and TABITEM_FIRST_IN_GROUP (and TABITEM_LAST_IN_GROUP) because when the
+ //line width is different from window width, there may not be TABITEM_RIGHTALIGNED
+ if((nAlignement & TABITEM_LEFTALIGNED)&&(nAlignement & TABITEM_RIGHTALIGNED)) //tab alone
+ aTabItemDrawInfo.position=kHIThemeTabPositionOnly;
+ else if((nAlignement & TABITEM_LEFTALIGNED)||(nAlignement & TABITEM_FIRST_IN_GROUP))
+ aTabItemDrawInfo.position=kHIThemeTabPositionFirst;
+ else if((nAlignement & TABITEM_RIGHTALIGNED)||(nAlignement & TABITEM_LAST_IN_GROUP))
+ aTabItemDrawInfo.position=kHIThemeTabPositionLast;
+
+ //support for RTL
+ //see issue 79748
+ if( Application::GetSettings().GetLayoutRTL() ) {
+ if( aTabItemDrawInfo.position == kHIThemeTabPositionFirst )
+ aTabItemDrawInfo.position = kHIThemeTabPositionLast;
+ else if( aTabItemDrawInfo.position == kHIThemeTabPositionLast )
+ aTabItemDrawInfo.position = kHIThemeTabPositionFirst;
+ }
+
+ rc.size.width+=2;//because VCL has 2 empty pixels between 2 tabs
+ rc.origin.x-=1;
+
+ HIThemeDrawTab(&rc, &aTabItemDrawInfo, mrContext, kHIThemeOrientationNormal, &rc );
+
+ bOK=true;
+ }
+ break;
+#endif
+
+ case CTRL_LISTBOX:
+ switch( nPart)
+ {
+ case PART_ENTIRE_CONTROL:
+ case PART_BUTTON_DOWN:
+ {
+ HIThemeButtonDrawInfo aListInfo;
+ aListInfo.version = 0;
+ aListInfo.kind = kThemePopupButton;
+ aListInfo.state = getState( nState );//kThemeStateInactive -> greyed
+ aListInfo.value = kThemeButtonOn;
+
+ aListInfo.adornment = kThemeAdornmentDefault;
+ if( (nState & CTRL_STATE_FOCUSED) != 0 )
+ aListInfo.adornment |= kThemeAdornmentFocus;
+
+ HIThemeDrawButton(&rc, &aListInfo, mrContext, kHIThemeOrientationNormal,&rc);
+ bOK = true;
+ break;
+ }
+ case PART_WINDOW:
+ {
+ HIThemeFrameDrawInfo aTextDrawInfo;
+ aTextDrawInfo.version=0;
+ aTextDrawInfo.kind=kHIThemeFrameTextFieldSquare;
+ aTextDrawInfo.state=getState( nState );
+ aTextDrawInfo.isFocused=false;
+
+ rc.size.width+=1;//else there's a white space because aqua theme hasn't a 3D border
+ rc.size.height+=1;
+ HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
+
+ if(nState & CTRL_STATE_FOCUSED) HIThemeDrawFocusRect(&rc, true, mrContext, kHIThemeOrientationNormal);
+
+ bOK=true;
+ break;
+ }
+ }
+ break;
+
+ case CTRL_EDITBOX:
+ case CTRL_MULTILINE_EDITBOX:
+ {
+ HIThemeFrameDrawInfo aTextDrawInfo;
+ aTextDrawInfo.version=0;
+ aTextDrawInfo.kind=kHIThemeFrameTextFieldSquare;
+ aTextDrawInfo.state=getState( nState );
+ aTextDrawInfo.isFocused=false;
+
+ rc.size.width += 1; // else there may be a white space because aqua theme hasn't a 3D border
+ // change rc so that the frame will encompass only the content region
+ // see counterpart in GetNativeControlRegion
+ rc.size.width += 2;
+ rc.size.height += 2;
+
+ //CGContextSetFillColorWithColor
+ CGContextFillRect (mrContext, CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height));
+ //fill a white background, because drawFrame only draws the border
+
+ HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
+
+ if(nState & CTRL_STATE_FOCUSED) HIThemeDrawFocusRect(&rc, true, mrContext, kHIThemeOrientationNormal);
+
+ bOK=true;
+ }
+ break;
+
+ case CTRL_SPINBOX:
+ {
+ if(nPart == PART_ENTIRE_CONTROL)
+ {
+ //text field:
+ HIThemeFrameDrawInfo aTextDrawInfo;
+ aTextDrawInfo.version=0;
+ aTextDrawInfo.kind=kHIThemeFrameTextFieldSquare;
+ aTextDrawInfo.state=getState( nState );
+ aTextDrawInfo.isFocused=false;
+
+ //rc.size.width contains the full size of the spinbox ie textfield + button
+ //so we remove the button width and the space between the button and the textfield
+ rc.size.width -= SPIN_BUTTON_SPACE + SPIN_BUTTON_WIDTH + 2*FOCUS_RING_WIDTH;
+ rc.origin.x += FOCUS_RING_WIDTH;
+ rc.origin.y += FOCUS_RING_WIDTH;
+
+ //CGContextSetFillColorWithColor
+ CGContextFillRect (mrContext, CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height));
+ //fill a white background, because drawFrame only draws the border
+
+ HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
+
+ if(nState & CTRL_STATE_FOCUSED) HIThemeDrawFocusRect(&rc, true, mrContext, kHIThemeOrientationNormal);
+
+ //buttons:
+ SpinbuttonValue* pSpinButtonVal = (SpinbuttonValue *)(aValue.getOptionalVal());
+ ControlState nUpperState = CTRL_STATE_ENABLED;//state of the upper button
+ ControlState nLowerState = CTRL_STATE_ENABLED;//and of the lower button
+ if(pSpinButtonVal) {//pSpinButtonVal is sometimes null
+ nUpperState = (ControlState) pSpinButtonVal->mnUpperState;
+ nLowerState = (ControlState) pSpinButtonVal->mnLowerState;
+ }
+
+ if( pSpinButtonVal )
+ {
+ HIThemeButtonDrawInfo aSpinInfo;
+ aSpinInfo.kind = kThemeIncDecButton;
+ aSpinInfo.state = kThemeStateActive;
+ if(nUpperState & CTRL_STATE_PRESSED)
+ aSpinInfo.state = kThemeStatePressedUp;
+ else if(nLowerState & CTRL_STATE_PRESSED)
+ aSpinInfo.state = kThemeStatePressedDown;
+ else if((nUpperState & ~CTRL_STATE_ENABLED)||(nLowerState & ~CTRL_STATE_ENABLED))
+ aSpinInfo.state = kThemeStateInactive;
+ else if((nUpperState & CTRL_STATE_ROLLOVER)||(nLowerState & CTRL_STATE_ROLLOVER))
+ aSpinInfo.state = kThemeStateRollover;
+
+ Rectangle aSpinRect( pSpinButtonVal->maUpperRect );
+ aSpinRect.Union( pSpinButtonVal->maLowerRect );
+ HIRect buttonRc = ImplGetHIRectFromRectangle(aSpinRect);
+
+ // FIXME: without this fuzz factor there is some unwanted clipping
+ if( Application::GetSettings().GetLayoutRTL() )
+ buttonRc.origin.x -= FOCUS_RING_WIDTH - CLIP_FUZZ;
+ else
+ buttonRc.origin.x += FOCUS_RING_WIDTH + CLIP_FUZZ;
+
+ switch( aValue.getTristateVal() )
+ {
+ case BUTTONVALUE_ON: aSpinInfo.value = kThemeButtonOn;
+ break;
+ case BUTTONVALUE_OFF: aSpinInfo.value = kThemeButtonOff;
+ break;
+ case BUTTONVALUE_MIXED:
+ case BUTTONVALUE_DONTKNOW:
+ default: aSpinInfo.value = kThemeButtonMixed;
+ break;
+ }
+
+ aSpinInfo.adornment = ( ((nUpperState & CTRL_STATE_DEFAULT) != 0 ) ||
+ ((nLowerState & CTRL_STATE_DEFAULT) != 0 )) ?
+ kThemeAdornmentDefault :
+ kThemeAdornmentNone;
+ if( ((nUpperState & CTRL_STATE_FOCUSED) != 0 ) || ((nLowerState & CTRL_STATE_FOCUSED) != 0 ))
+ aSpinInfo.adornment |= kThemeAdornmentFocus;
+
+ HIThemeDrawButton( &buttonRc, &aSpinInfo, mrContext, kHIThemeOrientationNormal, NULL );
+ }
+
+ bOK=true;
+ }
+
+ }
+ break;
+
+ case CTRL_FRAME:
+ {
+ USHORT nStyle = aValue.getNumericVal();
+ if( nPart == PART_BORDER ) {
+ if(!( nStyle & FRAME_DRAW_MENU ) && !(nStyle & FRAME_DRAW_WINDOWBORDER) )
+ {
+ // #i84756# strange effects start to happen when HIThemeDrawFrame
+ // meets the border of the window. These can be avoided by clipping
+ // to the boundary of the frame
+ if( rc.origin.y + rc.size.height >= mpFrame->maGeometry.nHeight-3 )
+ {
+ CGMutablePathRef rPath = CGPathCreateMutable();
+ CGPathAddRect( rPath, NULL, CGRectMake( 0, 0, mpFrame->maGeometry.nWidth-1, mpFrame->maGeometry.nHeight-1 ) );
+
+ CGContextBeginPath( mrContext );
+ CGContextAddPath( mrContext, rPath );
+ CGContextClip( mrContext );
+ CGPathRelease( rPath );
+ }
+
+ HIThemeFrameDrawInfo aTextDrawInfo;
+ aTextDrawInfo.version=0;
+ aTextDrawInfo.kind=kHIThemeFrameListBox;
+ aTextDrawInfo.state=kThemeStateActive;
+ aTextDrawInfo.isFocused=false;
+
+ HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
+
+ bOK=true;
+ }
+ }
+ }
+ break;
+
+ case CTRL_LISTNET:
+ {
+ //do nothing as there isn't net for listviews on macos
+ bOK=true;
+ }
+ break;
+
+ }
+
+ CGContextRestoreGState( mrContext );
+
+ /* #i90291# in most cases invalidating the whole control region instead
+ of just the unclipped part of it is sufficient (and probably faster).
+ However for the window background we should not unnecessarily enlarge
+ the really changed rectangle since the difference is usually quite high
+ (the background is always drawn as a whole since we don't know anything
+ about its possible contents)
+ */
+ if( nType == CTRL_WINDOW_BACKGROUND )
+ {
+ CGRect aRect = { { 0, 0 }, { 0, 0 } };
+ if( mxClipPath )
+ aRect = CGPathGetBoundingBox( mxClipPath );
+ if( aRect.size.width != 0 && aRect.size.height != 0 )
+ buttonRect.Intersection( Rectangle( Point( static_cast<long int>(aRect.origin.x),
+ static_cast<long int>(aRect.origin.y) ),
+ Size( static_cast<long int>(aRect.size.width),
+ static_cast<long int>(aRect.size.height) ) ) );
+ }
+
+ RefreshRect( buttonRect.Left(), buttonRect.Top(), buttonRect.GetWidth(), buttonRect.GetHeight() );
+
+ return bOK;
+}
+
+/*
+ * 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 AquaSalGraphics::drawNativeControlText( ControlType nType, ControlPart nPart, const Region& rControlRegion,
+ ControlState nState, const ImplControlValue& aValue,
+ const rtl::OUString& aCaption )
+{
+ 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 AquaSalGraphics::getNativeControlRegion( ControlType nType, ControlPart nPart, const Region& rControlRegion, ControlState nState,
+ const ImplControlValue& aValue, const rtl::OUString& aCaption,
+ Region &rNativeBoundingRegion, Region &rNativeContentRegion )
+
+{
+ BOOL toReturn = FALSE;
+
+ Rectangle aCtrlBoundRect( rControlRegion.GetBoundRect() );
+ short x = aCtrlBoundRect.Left();
+ short y = aCtrlBoundRect.Top();
+ short w, h;
+
+ sal_uInt8 nBorderCleanup = 0;
+
+ switch (nType)
+ {
+ case CTRL_SLIDER:
+ {
+ if( nPart == PART_THUMB_HORZ )
+ {
+ w = 19; // taken from HIG
+ h = aCtrlBoundRect.GetHeight();
+ rNativeBoundingRegion = rNativeContentRegion = Region( Rectangle( Point( x, y ), Size( w, h ) ) );
+ toReturn = true;
+ }
+ else if( nPart == PART_THUMB_VERT )
+ {
+ w = aCtrlBoundRect.GetWidth();
+ h = 18; // taken from HIG
+ rNativeBoundingRegion = rNativeContentRegion = Region( Rectangle( Point( x, y ), Size( w, h ) ) );
+ toReturn = true;
+ }
+ }
+ break;
+
+ case CTRL_SCROLLBAR:
+ {
+ Rectangle aRect;
+ if( AquaGetScrollRect( /* m_nScreen */ nPart, aCtrlBoundRect, aRect ) )
+ {
+ toReturn = TRUE;
+ rNativeBoundingRegion = aRect;
+ rNativeContentRegion = aRect;
+ }
+ }
+ break;
+
+ case CTRL_PUSHBUTTON:
+ case CTRL_RADIOBUTTON:
+ case CTRL_CHECKBOX:
+ {
+ if ( nType == CTRL_PUSHBUTTON )
+ {
+ w = aCtrlBoundRect.GetWidth();
+ h = aCtrlBoundRect.GetHeight();
+ }
+ else
+ {
+ // checkbox and radio borders need cleanup after unchecking them
+ nBorderCleanup = 4;
+
+ // TEXT_SEPARATOR to respect Aqua HIG
+ w = BUTTON_WIDTH + TEXT_SEPARATOR;
+ h = BUTTON_HEIGHT;
+
+ }
+
+ rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h + nBorderCleanup) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
+
+ toReturn = TRUE;
+ }
+ break;
+ case CTRL_PROGRESS:
+ {
+ Rectangle aRect( aCtrlBoundRect );
+ if( aRect.GetHeight() < 16 )
+ aRect.Bottom() = aRect.Top() + 9; // values taken from HIG for medium progress
+ else
+ aRect.Bottom() = aRect.Top() + 15; // values taken from HIG for large progress
+ rNativeBoundingRegion = aRect;
+ rNativeContentRegion = aRect;
+ toReturn = TRUE;
+ }
+ break;
+
+ case CTRL_INTROPROGRESS:
+ {
+ Rectangle aRect( aCtrlBoundRect );
+ aRect.Bottom() = aRect.Top() + INTRO_PROGRESS_HEIGHT; // values taken from HIG for medium progress
+ rNativeBoundingRegion = aRect;
+ rNativeContentRegion = aRect;
+ toReturn = TRUE;
+ }
+ break;
+
+ case CTRL_TAB_ITEM:
+
+ w = aCtrlBoundRect.GetWidth() + 2*TAB_TEXT_OFFSET - 2*VCL_TAB_TEXT_OFFSET;
+
+#ifdef OLD_TAB_STYLE
+ h = TAB_HEIGHT_NORMAL;
+#else
+ h = TAB_HEIGHT_NORMAL+2;
+#endif
+ rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
+
+ toReturn = TRUE;
+
+ break;
+
+ case CTRL_EDITBOX:
+ {
+ w = aCtrlBoundRect.GetWidth();
+ if( w < 3+2*FOCUS_RING_WIDTH )
+ w = 3+2*FOCUS_RING_WIDTH;
+ h = TEXT_EDIT_HEIGHT_NORMAL;
+
+ rNativeContentRegion = Rectangle( Point( x+FOCUS_RING_WIDTH, y+FOCUS_RING_WIDTH ), Size( w-2*FOCUS_RING_WIDTH-2, h-2 ) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) );
+
+ toReturn = TRUE;
+ }
+ break;
+ case CTRL_LISTBOX:
+ case CTRL_COMBOBOX:
+ {
+ if( nPart == PART_ENTIRE_CONTROL )
+ {
+ w = aCtrlBoundRect.GetWidth();
+ h = COMBOBOX_HEIGHT_NORMAL;//listboxes and comboxes have the same height
+
+ rNativeContentRegion = Rectangle( Point( x+FOCUS_RING_WIDTH, y+FOCUS_RING_WIDTH ), Size( w-2*FOCUS_RING_WIDTH, h ) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) );
+
+ toReturn = TRUE;
+ }
+ else if( nPart == PART_BUTTON_DOWN )
+ {
+ w = aCtrlBoundRect.GetWidth();
+ if( w < 3+2*FOCUS_RING_WIDTH )
+ w = 3+2*FOCUS_RING_WIDTH;
+ h = COMBOBOX_HEIGHT_NORMAL;//listboxes and comboxes have the same height
+
+ x += w-DROPDOWN_BUTTON_WIDTH - FOCUS_RING_WIDTH;
+ y += FOCUS_RING_WIDTH;
+ w = DROPDOWN_BUTTON_WIDTH;
+
+ rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w+FOCUS_RING_WIDTH, h+2*FOCUS_RING_WIDTH ) );
+
+ toReturn = true;
+ }
+ else if( nPart == PART_SUB_EDIT )
+ {
+ w = aCtrlBoundRect.GetWidth();
+ h = COMBOBOX_HEIGHT_NORMAL;//listboxes and comboxes have the same height
+
+ x += FOCUS_RING_WIDTH;
+ x += 3; // add an offset for rounded borders
+ y += 2; // don't draw into upper border
+ y += FOCUS_RING_WIDTH;
+ w -= 3 + DROPDOWN_BUTTON_WIDTH + 2*FOCUS_RING_WIDTH;
+ if( nType == CTRL_LISTBOX )
+ w -= 9; // HIG specifies 9 units distance between dropdown button area and content
+ h -= 4; // don't draw into lower border
+
+ rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w+FOCUS_RING_WIDTH, h+2*FOCUS_RING_WIDTH ) );
+
+ toReturn = true;
+ }
+ }
+ break;
+ case CTRL_SPINBOX:
+ if( nPart == PART_ENTIRE_CONTROL ) {
+ w = aCtrlBoundRect.GetWidth();
+ if( w < 3+2*FOCUS_RING_WIDTH+SPIN_BUTTON_SPACE+SPIN_BUTTON_WIDTH )
+ w = 3+2*FOCUS_RING_WIDTH+SPIN_BUTTON_SPACE+SPIN_BUTTON_WIDTH;
+ h = TEXT_EDIT_HEIGHT_NORMAL;
+
+ rNativeContentRegion = Rectangle( Point( x+FOCUS_RING_WIDTH, y ), Size( w-2*FOCUS_RING_WIDTH, h ) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) );
+
+ toReturn = TRUE;
+ }
+ else if( nPart == PART_SUB_EDIT ) {
+ w = aCtrlBoundRect.GetWidth() - SPIN_BUTTON_SPACE - SPIN_BUTTON_WIDTH;
+ h = TEXT_EDIT_HEIGHT_NORMAL;
+ x += 4; // add an offset for rounded borders
+ y += 2; // don't draw into upper border
+ w -= 8; // offset for left and right rounded border
+ h -= 4; // don't draw into upper or ower border
+
+ rNativeContentRegion = Rectangle( Point( x + FOCUS_RING_WIDTH, y + FOCUS_RING_WIDTH ), Size( w - 2* FOCUS_RING_WIDTH, h ) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) );
+
+ toReturn = TRUE;
+ }
+ else if( nPart == PART_BUTTON_UP ) {
+ //aCtrlBoundRect.GetWidth() contains the width of the full control
+ //ie the width of the textfield + button
+ //x is the position of the left corner of the full control
+ x += aCtrlBoundRect.GetWidth() - SPIN_BUTTON_WIDTH - SPIN_BUTTON_SPACE - CLIP_FUZZ;
+ y += FOCUS_RING_WIDTH - CLIP_FUZZ;
+ w = SPIN_BUTTON_WIDTH + 2*CLIP_FUZZ;
+ h = SPIN_UPPER_BUTTON_HEIGHT + 2*CLIP_FUZZ;
+
+ rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
+
+ toReturn = TRUE;
+ }
+ else if( nPart == PART_BUTTON_DOWN ) {
+ x += aCtrlBoundRect.GetWidth() - SPIN_BUTTON_WIDTH - SPIN_BUTTON_SPACE - CLIP_FUZZ;
+ y += SPIN_UPPER_BUTTON_HEIGHT + FOCUS_RING_WIDTH - CLIP_FUZZ;
+ w = SPIN_BUTTON_WIDTH + 2*CLIP_FUZZ;
+ h = SPIN_LOWER_BUTTON_HEIGHT + 2*CLIP_FUZZ;
+
+ rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
+
+ toReturn = TRUE;
+ }
+ break;
+ case CTRL_FRAME:
+ {
+ USHORT nStyle = aValue.getNumericVal();
+ if( ( nPart == PART_BORDER ) &&
+ !( nStyle & (FRAME_DRAW_MENU | FRAME_DRAW_WINDOWBORDER | FRAME_DRAW_BORDERWINDOWBORDER) ) )
+ {
+ Rectangle aRect(aCtrlBoundRect);
+ if( nStyle & FRAME_DRAW_DOUBLEIN )
+ {
+ aRect.Left() += 1;
+ aRect.Top() += 1;
+ //rRect.Right() -= 1;
+ //rRect.Bottom() -= 1;
+ }
+ else
+ {
+ aRect.Left() += 1;
+ aRect.Top() += 1;
+ aRect.Right() -= 1;
+ aRect.Bottom() -= 1;
+ }
+
+ rNativeContentRegion = aRect;
+ rNativeBoundingRegion = aRect;
+
+ toReturn = TRUE;
+ }
+ }
+ break;
+
+ case CTRL_MENUBAR:
+ case CTRL_MENU_POPUP:
+ {
+ if(( nPart == PART_MENU_ITEM_CHECK_MARK )||( nPart == PART_MENU_ITEM_RADIO_MARK )) {
+
+ w=10;
+ h=10;//dimensions of the mark (10px font)
+
+ rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) );
+ rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) );
+
+ toReturn = TRUE;
+ }
+ }
+ break;
+
+ }
+
+ return toReturn;
+}
diff --git a/vcl/aqua/source/gdi/salprn.cxx b/vcl/aqua/source/gdi/salprn.cxx
new file mode 100644
index 000000000000..1c0401f769b5
--- /dev/null
+++ b/vcl/aqua/source/gdi/salprn.cxx
@@ -0,0 +1,875 @@
+/*************************************************************************
+ *
+ * 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 "salinst.h"
+#include "salprn.h"
+#include "aquaprintview.h"
+#include "salgdi.h"
+#include "saldata.hxx"
+#include "vcl/jobset.h"
+#include "vcl/salptype.hxx"
+#include "vcl/print.hxx"
+#include "vcl/unohelp.hxx"
+
+#include <boost/bind.hpp>
+
+#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"
+
+#include <algorithm>
+
+using namespace rtl;
+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::beans;
+using namespace com::sun::star::container;
+
+// =======================================================================
+
+AquaSalInfoPrinter::AquaSalInfoPrinter( const SalPrinterQueueInfo& i_rQueue ) :
+ mpGraphics( 0 ),
+ mbGraphics( false ),
+ mbJob( false ),
+ mpPrinter( nil ),
+ mpPrintInfo( nil ),
+ mePageOrientation( ORIENTATION_PORTRAIT ),
+ mnStartPageOffsetX( 0 ),
+ mnStartPageOffsetY( 0 ),
+ mnCurPageRangeStart( 0 ),
+ mnCurPageRangeCount( 0 )
+{
+ NSString* pStr = CreateNSString( i_rQueue.maPrinterName );
+ mpPrinter = [NSPrinter printerWithName: pStr];
+ [pStr release];
+
+ NSPrintInfo* pShared = [NSPrintInfo sharedPrintInfo];
+ if( pShared )
+ {
+ mpPrintInfo = [pShared copy];
+ [mpPrintInfo setPrinter: mpPrinter];
+ mePageOrientation = ([mpPrintInfo orientation] == NSLandscapeOrientation) ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
+ [mpPrintInfo setOrientation: NSPortraitOrientation];
+ }
+
+ mpGraphics = new AquaSalGraphics();
+
+ const int nWidth = 100, nHeight = 100;
+ maContextMemory.reset( reinterpret_cast<sal_uInt8*>( rtl_allocateMemory( nWidth * 4 * nHeight ) ),
+ boost::bind( rtl_freeMemory, _1 ) );
+
+ if( maContextMemory )
+ {
+ mrContext = CGBitmapContextCreate( maContextMemory.get(), nWidth, nHeight, 8, nWidth * 4, GetSalData()->mxRGBSpace, kCGImageAlphaNoneSkipFirst );
+ if( mrContext )
+ SetupPrinterGraphics( mrContext );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+AquaSalInfoPrinter::~AquaSalInfoPrinter()
+{
+ delete mpGraphics;
+ if( mpPrintInfo )
+ [mpPrintInfo release];
+ #if 0
+ // FIXME: verify that NSPrintInfo releases the printer
+ // else we have a leak here
+ if( mpPrinter )
+ [mpPrinter release];
+ #endif
+ if( mrContext )
+ CFRelease( mrContext );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInfoPrinter::SetupPrinterGraphics( CGContextRef i_rContext ) const
+{
+ if( mpGraphics )
+ {
+ if( mpPrintInfo )
+ {
+ // FIXME: get printer resolution
+ long nDPIX = 720, nDPIY = 720;
+ NSSize aPaperSize = [mpPrintInfo paperSize];
+
+ NSRect aImageRect = [mpPrintInfo imageablePageBounds];
+ if( mePageOrientation == ORIENTATION_PORTRAIT )
+ {
+ // move mirrored CTM back into paper
+ double dX = 0, dY = aPaperSize.height;
+ // move CTM to reflect imageable area
+ dX += aImageRect.origin.x;
+ dY -= aPaperSize.height - aImageRect.size.height - aImageRect.origin.y;
+ CGContextTranslateCTM( i_rContext, dX + mnStartPageOffsetX, dY - mnStartPageOffsetY );
+ // scale to be top/down and reflect our "virtual" DPI
+ CGContextScaleCTM( i_rContext, 72.0/double(nDPIX), -(72.0/double(nDPIY)) );
+ }
+ else
+ {
+ // move CTM to reflect imageable area
+ double dX = aImageRect.origin.x, dY = aPaperSize.height - aImageRect.size.height - aImageRect.origin.y;
+ CGContextTranslateCTM( i_rContext, -dX, -dY );
+ // turn by 90 degree
+ CGContextRotateCTM( i_rContext, M_PI/2 );
+ // move turned CTM back into paper
+ dX = aPaperSize.height;
+ dY = -aPaperSize.width;
+ CGContextTranslateCTM( i_rContext, dX + mnStartPageOffsetY, dY - mnStartPageOffsetX );
+ // scale to be top/down and reflect our "virtual" DPI
+ CGContextScaleCTM( i_rContext, -(72.0/double(nDPIY)), (72.0/double(nDPIX)) );
+ }
+ mpGraphics->SetPrinterGraphics( i_rContext, nDPIX, nDPIY, 1.0 );
+ }
+ else
+ DBG_ERROR( "no print info in SetupPrinterGraphics" );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+SalGraphics* AquaSalInfoPrinter::GetGraphics()
+{
+ SalGraphics* pGraphics = mbGraphics ? NULL : mpGraphics;
+ mbGraphics = true;
+ return pGraphics;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInfoPrinter::ReleaseGraphics( SalGraphics* )
+{
+ mbGraphics = false;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalInfoPrinter::Setup( SalFrame* i_pFrame, ImplJobSetup* i_pSetupData )
+{
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+static struct PaperSizeEntry
+{
+ double fWidth;
+ double fHeight;
+ Paper nPaper;
+} aPaperSizes[] =
+{
+ { 842, 1191, PAPER_A3 },
+ { 595, 842, PAPER_A4 },
+ { 420, 595, PAPER_A5 },
+ { 612, 792, PAPER_LETTER },
+ { 612, 1008, PAPER_LEGAL },
+ { 728, 1032, PAPER_B4_JIS },
+ { 516, 729, PAPER_B5_JIS },
+ { 792, 1224, PAPER_TABLOID }
+};
+
+static bool getPaperSize( double& o_fWidth, double& o_fHeight, const Paper i_ePaper )
+{
+ for(unsigned int i = 0; i < sizeof(aPaperSizes)/sizeof(aPaperSizes[0]); i++ )
+ {
+ if( aPaperSizes[i].nPaper == i_ePaper )
+ {
+ o_fWidth = aPaperSizes[i].fWidth;
+ o_fHeight = aPaperSizes[i].fHeight;
+ return true;
+ }
+ }
+ return false;
+}
+
+static Paper recognizePaper( double i_fWidth, double i_fHeight )
+{
+ Paper aPaper = PAPER_USER;
+ sal_uInt64 nPaperDesc = 1000000*sal_uInt64(i_fWidth) + sal_uInt64(i_fHeight);
+ switch( nPaperDesc )
+ {
+ case 842001191: aPaper = PAPER_A3; break;
+ case 595000842: aPaper = PAPER_A4; break;
+ case 420000595: aPaper = PAPER_A5; break;
+ case 612000792: aPaper = PAPER_LETTER; break;
+ case 728001032: aPaper = PAPER_B4_JIS; break;
+ case 516000729: aPaper = PAPER_B5_JIS; break;
+ case 612001008: aPaper = PAPER_LEGAL; break;
+ case 792001224: aPaper = PAPER_TABLOID; break;
+ default:
+ aPaper = PAPER_USER;
+ break;
+ }
+
+ if( aPaper == PAPER_USER )
+ {
+ // search with fuzz factor
+ for( unsigned int i = 0; i < sizeof(aPaperSizes)/sizeof(aPaperSizes[0]); i++ )
+ {
+ double w = (i_fWidth > aPaperSizes[i].fWidth) ? i_fWidth - aPaperSizes[i].fWidth : aPaperSizes[i].fWidth - i_fWidth;
+ double h = (i_fHeight > aPaperSizes[i].fHeight) ? i_fHeight - aPaperSizes[i].fHeight : aPaperSizes[i].fHeight - i_fHeight;
+ if( w < 3 && h < 3 )
+ {
+ aPaper = aPaperSizes[i].nPaper;
+ break;
+ }
+ }
+ }
+
+ return aPaper;
+}
+
+BOOL AquaSalInfoPrinter::SetPrinterData( ImplJobSetup* io_pSetupData )
+{
+ // FIXME: implement driver data
+ if( io_pSetupData && io_pSetupData->mpDriverData )
+ return SetData( ~0, io_pSetupData );
+
+
+ BOOL bSuccess = TRUE;
+
+ // set system type
+ io_pSetupData->mnSystem = JOBSETUP_SYSTEM_MAC;
+
+ // get paper format
+ if( mpPrintInfo )
+ {
+ NSSize aPaperSize = [mpPrintInfo paperSize];
+ double width = aPaperSize.width, height = aPaperSize.height;
+ // set paper
+ io_pSetupData->mePaperFormat = recognizePaper( width, height );
+ if( io_pSetupData->mePaperFormat == PAPER_USER )
+ {
+ io_pSetupData->mnPaperWidth = PtTo10Mu( width );
+ io_pSetupData->mnPaperHeight = PtTo10Mu( height );
+ }
+ else
+ {
+ io_pSetupData->mnPaperWidth = 0;
+ io_pSetupData->mnPaperHeight = 0;
+ }
+
+ // set orientation
+ io_pSetupData->meOrientation = mePageOrientation;
+
+ io_pSetupData->mnPaperBin = 0;
+ io_pSetupData->mpDriverData = reinterpret_cast<BYTE*>(rtl_allocateMemory( 4 ));
+ io_pSetupData->mnDriverDataLen = 4;
+ }
+ else
+ bSuccess = FALSE;
+
+
+ return bSuccess;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInfoPrinter::setPaperSize( long i_nWidth, long i_nHeight, Orientation i_eSetOrientation )
+{
+
+ Orientation ePaperOrientation = ORIENTATION_PORTRAIT;
+ const PaperInfo* pPaper = matchPaper( i_nWidth, i_nHeight, ePaperOrientation );
+
+ if( pPaper )
+ {
+ NSString* pPaperName = [CreateNSString( rtl::OStringToOUString(PaperInfo::toPSName(pPaper->getPaper()), RTL_TEXTENCODING_ASCII_US) ) autorelease];
+ [mpPrintInfo setPaperName: pPaperName];
+ }
+ else if( i_nWidth > 0 && i_nHeight > 0 )
+ {
+ NSSize aPaperSize = { TenMuToPt(i_nWidth), TenMuToPt(i_nHeight) };
+ [mpPrintInfo setPaperSize: aPaperSize];
+ }
+ // this seems counterintuitive
+ mePageOrientation = i_eSetOrientation;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalInfoPrinter::SetData( ULONG i_nFlags, ImplJobSetup* io_pSetupData )
+{
+ if( ! io_pSetupData || io_pSetupData->mnSystem != JOBSETUP_SYSTEM_MAC )
+ return FALSE;
+
+
+ if( mpPrintInfo )
+ {
+ if( (i_nFlags & SAL_JOBSET_ORIENTATION) != 0 )
+ mePageOrientation = io_pSetupData->meOrientation;
+
+ if( (i_nFlags & SAL_JOBSET_PAPERSIZE) != 0)
+ {
+ // set paper format
+ long width = 21000, height = 29700;
+ if( io_pSetupData->mePaperFormat == PAPER_USER )
+ {
+ // #i101108# sanity check
+ if( io_pSetupData->mnPaperWidth && io_pSetupData->mnPaperHeight )
+ {
+ width = io_pSetupData->mnPaperWidth;
+ height = io_pSetupData->mnPaperHeight;
+ }
+ }
+ else
+ {
+ double w = 595, h = 842;
+ getPaperSize( w, h, io_pSetupData->mePaperFormat );
+ width = static_cast<long>(PtTo10Mu( w ));
+ height = static_cast<long>(PtTo10Mu( h ));
+ }
+
+ setPaperSize( width, height, mePageOrientation );
+ }
+ }
+
+ return mpPrintInfo != nil;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG AquaSalInfoPrinter::GetPaperBinCount( const ImplJobSetup* i_pSetupData )
+{
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+XubString AquaSalInfoPrinter::GetPaperBinName( const ImplJobSetup* i_pSetupData, ULONG i_nPaperBin )
+{
+ return XubString();
+}
+
+// -----------------------------------------------------------------------
+
+static bool getUseNativeDialog()
+{
+ bool bNative = true;
+ 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 = OUString( RTL_CONSTASCII_USTRINGPARAM( "nodepath" ) );
+ aVal.Value <<= OUString( RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.Office.Common/Misc" ) );
+ 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( "UseSystemPrintDialog" ) ) );
+ if( aAny >>= bValue )
+ bNative = bValue;
+ }
+ catch( NoSuchElementException& )
+ {
+ }
+ catch( WrappedTargetException& )
+ {
+ }
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ }
+ }
+ }
+ catch( WrappedTargetException& )
+ {
+ }
+
+ return bNative;
+}
+
+ULONG AquaSalInfoPrinter::GetCapabilities( const ImplJobSetup* i_pSetupData, USHORT i_nType )
+{
+ switch( i_nType )
+ {
+ case PRINTER_CAPABILITIES_SUPPORTDIALOG:
+ return 0;
+ case PRINTER_CAPABILITIES_COPIES:
+ return 0xffff;
+ case PRINTER_CAPABILITIES_COLLATECOPIES:
+ return 0;
+ case PRINTER_CAPABILITIES_SETORIENTATION:
+ return 1;
+ case PRINTER_CAPABILITIES_SETDUPLEX:
+ return 0;
+ case PRINTER_CAPABILITIES_SETPAPERBIN:
+ return 0;
+ case PRINTER_CAPABILITIES_SETPAPERSIZE:
+ return 1;
+ case PRINTER_CAPABILITIES_SETPAPER:
+ return 1;
+ case PRINTER_CAPABILITIES_EXTERNALDIALOG:
+ return getUseNativeDialog() ? 1 : 0;
+ case PRINTER_CAPABILITIES_PDF:
+ return 1;
+ default: break;
+ };
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInfoPrinter::GetPageInfo( const ImplJobSetup*,
+ long& o_rOutWidth, long& o_rOutHeight,
+ long& o_rPageOffX, long& o_rPageOffY,
+ long& o_rPageWidth, long& o_rPageHeight )
+{
+ if( mpPrintInfo )
+ {
+ long nDPIX = 72, nDPIY = 72;
+ mpGraphics->GetResolution( nDPIX, nDPIY );
+ const double fXScaling = static_cast<double>(nDPIX)/72.0,
+ fYScaling = static_cast<double>(nDPIY)/72.0;
+
+ NSSize aPaperSize = [mpPrintInfo paperSize];
+ o_rPageWidth = static_cast<long>( double(aPaperSize.width) * fXScaling );
+ o_rPageHeight = static_cast<long>( double(aPaperSize.height) * fYScaling );
+
+ NSRect aImageRect = [mpPrintInfo imageablePageBounds];
+ o_rPageOffX = static_cast<long>( aImageRect.origin.x * fXScaling );
+ o_rPageOffY = static_cast<long>( (aPaperSize.height - aImageRect.size.height - aImageRect.origin.y) * fYScaling );
+ o_rOutWidth = static_cast<long>( aImageRect.size.width * fXScaling );
+ o_rOutHeight = static_cast<long>( aImageRect.size.height * fYScaling );
+
+ if( mePageOrientation == ORIENTATION_LANDSCAPE )
+ {
+ std::swap( o_rOutWidth, o_rOutHeight );
+ std::swap( o_rPageWidth, o_rPageHeight );
+ std::swap( o_rPageOffX, o_rPageOffY );
+ }
+ }
+}
+
+static Size getPageSize( vcl::PrinterController& i_rController, sal_Int32 i_nPage )
+{
+ Size aPageSize;
+ Sequence< PropertyValue > aPageParms( i_rController.getPageParameters( i_nPage ) );
+ for( sal_Int32 nProperty = 0, nPropertyCount = aPageParms.getLength(); nProperty < nPropertyCount; ++nProperty )
+ {
+ if( aPageParms[ nProperty ].Name.equalsAscii( "PageSize" ) )
+ {
+ awt::Size aSize;
+ aPageParms[ nProperty].Value >>= aSize;
+ aPageSize.Width() = aSize.Width;
+ aPageSize.Height() = aSize.Height;
+ break;
+ }
+ }
+ return aPageSize;
+}
+
+BOOL AquaSalInfoPrinter::StartJob( const String* i_pFileName,
+ const String& i_rJobName,
+ const String& i_rAppName,
+ ImplJobSetup* i_pSetupData,
+ vcl::PrinterController& i_rController
+ )
+{
+ if( mbJob )
+ return FALSE;
+
+ BOOL bSuccess = FALSE;
+ bool bWasAborted = false;
+ AquaSalInstance* pInst = GetSalData()->mpFirstInstance;
+ PrintAccessoryViewState aAccViewState;
+ sal_Int32 nAllPages = 0;
+
+ // reset IsLastPage
+ i_rController.setLastPage( sal_False );
+
+ // update job data
+ if( i_pSetupData )
+ SetData( ~0, i_pSetupData );
+
+ // do we want a progress panel ?
+ sal_Bool bShowProgressPanel = sal_True;
+ beans::PropertyValue* pMonitor = i_rController.getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MonitorVisible" ) ) );
+ if( pMonitor )
+ pMonitor->Value >>= bShowProgressPanel;
+ if( ! i_rController.isShowDialogs() )
+ bShowProgressPanel = sal_False;
+
+ // possibly create one job for collated output
+ sal_Bool bSinglePrintJobs = sal_False;
+ beans::PropertyValue* pSingleValue = i_rController.getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintCollateAsSingleJobs" ) ) );
+ if( pSingleValue )
+ {
+ pSingleValue->Value >>= bSinglePrintJobs;
+ }
+
+ // FIXME: jobStarted() should be done after the print dialog has ended (if there is one)
+ // how do I know when that might be ?
+ i_rController.jobStarted();
+
+
+ int nCopies = i_rController.getPrinter()->GetCopyCount();
+ int nJobs = 1;
+ if( bSinglePrintJobs )
+ {
+ nJobs = nCopies;
+ nCopies = 1;
+ }
+
+ for( int nCurJob = 0; nCurJob < nJobs; nCurJob++ )
+ {
+ aAccViewState.bNeedRestart = true;
+ do
+ {
+ if( aAccViewState.bNeedRestart )
+ {
+ mnCurPageRangeStart = 0;
+ mnCurPageRangeCount = 0;
+ nAllPages = i_rController.getFilteredPageCount();
+ }
+
+ aAccViewState.bNeedRestart = false;
+
+ Size aCurSize( 21000, 29700 );
+ if( nAllPages > 0 )
+ {
+ mnCurPageRangeCount = 1;
+ aCurSize = getPageSize( i_rController, mnCurPageRangeStart );
+ Size aNextSize( aCurSize );
+
+ // print pages up to a different size
+ while( mnCurPageRangeCount + mnCurPageRangeStart < nAllPages )
+ {
+ aNextSize = getPageSize( i_rController, mnCurPageRangeStart + mnCurPageRangeCount );
+ if( aCurSize == aNextSize // same page size
+ ||
+ (aCurSize.Width() == aNextSize.Height() && aCurSize.Height() == aNextSize.Width()) // same size, but different orientation
+ )
+ {
+ mnCurPageRangeCount++;
+ }
+ else
+ break;
+ }
+ }
+ else
+ mnCurPageRangeCount = 0;
+
+ // now for the current run
+ mnStartPageOffsetX = mnStartPageOffsetY = 0;
+ // setup the paper size and orientation
+ // do this on our associated Printer object, since that is
+ // out interface to the applications which occasionally rely on the paper
+ // information (e.g. brochure printing scales to the found paper size)
+ // also SetPaperSizeUser has the advantage that we can share a
+ // platform independent paper matching algorithm
+ boost::shared_ptr<Printer> pPrinter( i_rController.getPrinter() );
+ pPrinter->SetMapMode( MapMode( MAP_100TH_MM ) );
+ pPrinter->SetPaperSizeUser( aCurSize, true );
+
+ // create view
+ NSView* pPrintView = [[AquaPrintView alloc] initWithController: &i_rController withInfoPrinter: this];
+
+ NSMutableDictionary* pPrintDict = [mpPrintInfo dictionary];
+
+ // set filename
+ if( i_pFileName )
+ {
+ [mpPrintInfo setJobDisposition: NSPrintSaveJob];
+ NSString* pPath = CreateNSString( *i_pFileName );
+ [pPrintDict setObject: pPath forKey: NSPrintSavePath];
+ [pPath release];
+ }
+
+ [pPrintDict setObject: [[NSNumber numberWithInt: nCopies] autorelease] forKey: NSPrintCopies];
+ [pPrintDict setObject: [[NSNumber numberWithBool: YES] autorelease] forKey: NSPrintDetailedErrorReporting];
+ [pPrintDict setObject: [[NSNumber numberWithInt: 1] autorelease] forKey: NSPrintFirstPage];
+ // #i103253# weird: for some reason, autoreleasing the value below like the others above
+ // leads do a double free malloc error. Why this value should behave differently from all the others
+ // is a mystery.
+ [pPrintDict setObject: [NSNumber numberWithInt: mnCurPageRangeCount] forKey: NSPrintLastPage];
+
+
+ // create print operation
+ NSPrintOperation* pPrintOperation = [NSPrintOperation printOperationWithView: pPrintView printInfo: mpPrintInfo];
+
+ if( pPrintOperation )
+ {
+ NSObject* pReleaseAfterUse = nil;
+ bool bShowPanel = (! i_rController.isDirectPrint() && getUseNativeDialog() && i_rController.isShowDialogs() );
+ [pPrintOperation setShowsPrintPanel: bShowPanel ? YES : NO ];
+ [pPrintOperation setShowsProgressPanel: bShowProgressPanel ? YES : NO];
+
+ // set job title (since MacOSX 10.5)
+ if( [pPrintOperation respondsToSelector: @selector(setJobTitle:)] )
+ [pPrintOperation performSelector: @selector(setJobTitle:) withObject: [CreateNSString( i_rJobName ) autorelease]];
+
+ if( bShowPanel && mnCurPageRangeStart == 0 && nCurJob == 0) // only the first range of pages (in the first job) gets the accesory view
+ pReleaseAfterUse = [AquaPrintAccessoryView setupPrinterPanel: pPrintOperation withController: &i_rController withState: &aAccViewState];
+
+ bSuccess = TRUE;
+ mbJob = true;
+ pInst->startedPrintJob();
+ [pPrintOperation runOperation];
+ pInst->endedPrintJob();
+ bWasAborted = [[[pPrintOperation printInfo] jobDisposition] compare: NSPrintCancelJob] == NSOrderedSame;
+ mbJob = false;
+ if( pReleaseAfterUse )
+ [pReleaseAfterUse release];
+ }
+
+ mnCurPageRangeStart += mnCurPageRangeCount;
+ mnCurPageRangeCount = 1;
+ } while( aAccViewState.bNeedRestart || mnCurPageRangeStart + mnCurPageRangeCount < nAllPages );
+ }
+
+ // inform application that it can release its data
+ // this is awkward, but the XRenderable interface has no method for this,
+ // so we need to call XRenderadble::render one last time with IsLastPage = TRUE
+ i_rController.setLastPage( sal_True );
+ GDIMetaFile aPageFile;
+ if( mrContext )
+ SetupPrinterGraphics( mrContext );
+ i_rController.getFilteredPageFile( 0, aPageFile );
+
+ i_rController.setJobState( bWasAborted
+ ? view::PrintableState_JOB_ABORTED
+ : view::PrintableState_JOB_SPOOLED );
+
+ mnCurPageRangeStart = mnCurPageRangeCount = 0;
+
+ return bSuccess;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalInfoPrinter::EndJob()
+{
+ mnStartPageOffsetX = mnStartPageOffsetY = 0;
+ mbJob = false;
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalInfoPrinter::AbortJob()
+{
+ mbJob = false;
+
+ // FIXME: implementation
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+SalGraphics* AquaSalInfoPrinter::StartPage( ImplJobSetup* i_pSetupData, BOOL i_bNewJobData )
+{
+ if( i_bNewJobData && i_pSetupData )
+ SetPrinterData( i_pSetupData );
+
+ CGContextRef rContext = reinterpret_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]);
+
+ SetupPrinterGraphics( rContext );
+
+ return mpGraphics;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalInfoPrinter::EndPage()
+{
+ mpGraphics->InvalidateContext();
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG AquaSalInfoPrinter::GetErrorCode() const
+{
+ return 0;
+}
+
+// =======================================================================
+
+AquaSalPrinter::AquaSalPrinter( AquaSalInfoPrinter* i_pInfoPrinter ) :
+ mpInfoPrinter( i_pInfoPrinter )
+{
+}
+
+// -----------------------------------------------------------------------
+
+AquaSalPrinter::~AquaSalPrinter()
+{
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalPrinter::StartJob( const String* i_pFileName,
+ const String& i_rJobName,
+ const String& i_rAppName,
+ ImplJobSetup* i_pSetupData,
+ vcl::PrinterController& i_rController )
+{
+ return mpInfoPrinter->StartJob( i_pFileName, i_rJobName, i_rAppName, i_pSetupData, i_rController );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalPrinter::StartJob( const XubString* i_pFileName,
+ const XubString& i_rJobName,
+ const XubString& i_rAppName,
+ ULONG i_nCopies,
+ bool i_bCollate,
+ bool i_bDirect,
+ ImplJobSetup* i_pSetupData )
+{
+ DBG_ERROR( "should never be called" );
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalPrinter::EndJob()
+{
+ return mpInfoPrinter->EndJob();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalPrinter::AbortJob()
+{
+ return mpInfoPrinter->AbortJob();
+}
+
+// -----------------------------------------------------------------------
+
+SalGraphics* AquaSalPrinter::StartPage( ImplJobSetup* i_pSetupData, BOOL i_bNewJobData )
+{
+ return mpInfoPrinter->StartPage( i_pSetupData, i_bNewJobData );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalPrinter::EndPage()
+{
+ return mpInfoPrinter->EndPage();
+}
+
+// -----------------------------------------------------------------------
+
+ULONG AquaSalPrinter::GetErrorCode()
+{
+ return mpInfoPrinter->GetErrorCode();
+}
+
+void AquaSalInfoPrinter::InitPaperFormats( const ImplJobSetup* i_pSetupData )
+{
+ m_aPaperFormats.clear();
+ m_bPapersInit = true;
+
+ if( mpPrinter )
+ {
+ if( [mpPrinter statusForTable: @"PPD"] == NSPrinterTableOK )
+ {
+ NSArray* pPaperNames = [mpPrinter stringListForKey: @"PageSize" inTable: @"PPD"];
+ if( pPaperNames )
+ {
+ unsigned int nPapers = [pPaperNames count];
+ for( unsigned int i = 0; i < nPapers; i++ )
+ {
+ NSString* pPaper = [pPaperNames objectAtIndex: i];
+ NSSize aPaperSize = [mpPrinter pageSizeForPaper: pPaper];
+ if( aPaperSize.width > 0 && aPaperSize.height > 0 )
+ {
+ PaperInfo aInfo( PtTo10Mu( aPaperSize.width ),
+ PtTo10Mu( aPaperSize.height ) );
+ m_aPaperFormats.push_back( aInfo );
+ }
+ }
+ }
+ }
+ }
+}
+
+const PaperInfo* AquaSalInfoPrinter::matchPaper( long i_nWidth, long i_nHeight, Orientation& o_rOrientation ) const
+{
+ if( ! m_bPapersInit )
+ const_cast<AquaSalInfoPrinter*>(this)->InitPaperFormats( NULL );
+
+ const PaperInfo* pMatch = NULL;
+ o_rOrientation = ORIENTATION_PORTRAIT;
+ for( int n = 0; n < 2 ; n++ )
+ {
+ for( size_t i = 0; i < m_aPaperFormats.size(); i++ )
+ {
+ if( abs( m_aPaperFormats[i].getWidth() - i_nWidth ) < 50 &&
+ abs( m_aPaperFormats[i].getHeight() - i_nHeight ) < 50 )
+ {
+ pMatch = &m_aPaperFormats[i];
+ return pMatch;
+ }
+ }
+ o_rOrientation = ORIENTATION_LANDSCAPE;
+ std::swap( i_nWidth, i_nHeight );
+ }
+ return pMatch;
+}
+
+int AquaSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* i_pSetupData )
+{
+ return 900;
+}
+
+
diff --git a/vcl/aqua/source/gdi/salvd.cxx b/vcl/aqua/source/gdi/salvd.cxx
new file mode 100644
index 000000000000..eb09a44f5edd
--- /dev/null
+++ b/vcl/aqua/source/gdi/salvd.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"
+
+#include "salvd.h"
+#include "salinst.h"
+#include "salgdi.h"
+#include "saldata.hxx"
+#include "salframe.h"
+
+#include "vcl/sysdata.hxx"
+
+// -----------------------------------------------------------------------
+
+SalVirtualDevice* AquaSalInstance::CreateVirtualDevice( SalGraphics* pGraphics,
+ long nDX, long nDY, USHORT nBitCount, const SystemGraphicsData *pData )
+{
+ // #i92075# can be called first in a thread
+ SalData::ensureThreadAutoreleasePool();
+
+ return new AquaSalVirtualDevice( static_cast< AquaSalGraphics* >( pGraphics ), nDX, nDY, nBitCount, pData );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalInstance::DestroyVirtualDevice( SalVirtualDevice* pDevice )
+{
+ delete pDevice;
+}
+
+// =======================================================================
+
+AquaSalVirtualDevice::AquaSalVirtualDevice( AquaSalGraphics* pGraphic, long nDX, long nDY, USHORT nBitCount, const SystemGraphicsData *pData )
+: mbGraphicsUsed( false )
+, mxBitmapContext( NULL )
+, mnBitmapDepth( 0 )
+, mxLayer( NULL )
+{
+ if( pGraphic && pData && pData->rCGContext )
+ {
+ // Create virtual device based on existing SystemGraphicsData
+ // We ignore nDx and nDY, as the desired size comes from the SystemGraphicsData
+ mbForeignContext = true; // the mxContext is from pData
+ mpGraphics = new AquaSalGraphics( /*pGraphic*/ );
+ mpGraphics->SetVirDevGraphics( mxLayer, pData->rCGContext );
+ }
+ else
+ {
+ // create empty new virtual device
+ mbForeignContext = false; // the mxContext is created within VCL
+ mpGraphics = new AquaSalGraphics(); // never fails
+ mnBitmapDepth = nBitCount;
+
+ // inherit resolution from reference device
+ if( pGraphic )
+ {
+ AquaSalFrame* pFrame = pGraphic->getGraphicsFrame();
+ if( pFrame && AquaSalFrame::isAlive( pFrame ) )
+ {
+ mpGraphics->setGraphicsFrame( pFrame );
+ mpGraphics->copyResolution( *pGraphic );
+ }
+ }
+
+ if( nDX && nDY )
+ SetSize( nDX, nDY );
+
+ // NOTE: if SetSize does not succeed, we just ignore the nDX and nDY
+ }
+}
+
+// -----------------------------------------------------------------------
+
+AquaSalVirtualDevice::~AquaSalVirtualDevice()
+{
+ if( mpGraphics )
+ {
+ mpGraphics->SetVirDevGraphics( NULL, NULL );
+ delete mpGraphics;
+ mpGraphics = 0;
+ }
+ Destroy();
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalVirtualDevice::Destroy()
+{
+ if( mbForeignContext ) {
+ // Do not delete mxContext that we have received from outside VCL
+ mxLayer = NULL;
+ return;
+ }
+
+ if( mxLayer )
+ {
+ if( mpGraphics )
+ mpGraphics->SetVirDevGraphics( NULL, NULL );
+ CGLayerRelease( mxLayer );
+ mxLayer = NULL;
+ }
+
+ if( mxBitmapContext )
+ {
+ void* pRawData = CGBitmapContextGetData( mxBitmapContext );
+ rtl_freeMemory( pRawData );
+ CGContextRelease( mxBitmapContext );
+ mxBitmapContext = NULL;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+SalGraphics* AquaSalVirtualDevice::GetGraphics()
+{
+ if( mbGraphicsUsed || !mpGraphics )
+ return 0;
+
+ mbGraphicsUsed = true;
+ return mpGraphics;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalVirtualDevice::ReleaseGraphics( SalGraphics *pGraphics )
+{
+ mbGraphicsUsed = false;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalVirtualDevice::SetSize( long nDX, long nDY )
+{
+ if( mbForeignContext )
+ {
+ // Do not delete/resize mxContext that we have received from outside VCL
+ return true;
+ }
+
+ if( mxLayer )
+ {
+ const CGSize aSize = CGLayerGetSize( mxLayer );
+ if( (nDX == aSize.width) && (nDY == aSize.height) )
+ {
+ // Yay, we do not have to do anything :)
+ return true;
+ }
+ }
+
+ Destroy();
+
+ // create a Quartz layer matching to the intended virdev usage
+ CGContextRef xCGContext = NULL;
+ if( mnBitmapDepth && (mnBitmapDepth < 16) )
+ {
+ mnBitmapDepth = 8; // TODO: are 1bit vdevs worth it?
+ const CGColorSpaceRef aCGColorSpace = GetSalData()->mxGraySpace;
+ const CGBitmapInfo aCGBmpInfo = kCGImageAlphaNone;
+ const int nBytesPerRow = (mnBitmapDepth * nDX + 7) / 8;
+
+ void* pRawData = rtl_allocateMemory( nBytesPerRow * nDY );
+ mxBitmapContext = ::CGBitmapContextCreate( pRawData, nDX, nDY,
+ mnBitmapDepth, nBytesPerRow, aCGColorSpace, aCGBmpInfo );
+ xCGContext = mxBitmapContext;
+ }
+ else
+ {
+ // default to a NSView target context
+ AquaSalFrame* pSalFrame = mpGraphics->getGraphicsFrame();
+ if( !pSalFrame && !GetSalData()->maFrames.empty() )
+ pSalFrame = *GetSalData()->maFrames.begin();
+ if( pSalFrame )
+ {
+ NSGraphicsContext* pNSContext = [NSGraphicsContext graphicsContextWithWindow: pSalFrame->getWindow()];
+ if( pNSContext )
+ xCGContext = reinterpret_cast<CGContextRef>([pNSContext graphicsPort]);
+ }
+ }
+
+ DBG_ASSERT( xCGContext, "no context" );
+
+ const CGSize aNewSize = { nDX, nDY };
+ mxLayer = CGLayerCreateWithContext( xCGContext, aNewSize, NULL );
+
+ if( mxLayer && mpGraphics )
+ {
+ // get the matching Quartz context
+ CGContextRef xDrawContext = CGLayerGetContext( mxLayer );
+ mpGraphics->SetVirDevGraphics( mxLayer, xDrawContext, mnBitmapDepth );
+ }
+
+ return (mxLayer != NULL);
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalVirtualDevice::GetSize( long& rWidth, long& rHeight )
+{
+ if( mxLayer )
+ {
+ const CGSize aSize = CGLayerGetSize( mxLayer );
+ rWidth = static_cast<long>(aSize.width);
+ rHeight = static_cast<long>(aSize.height);
+ }
+ else
+ {
+ rWidth = 0;
+ rHeight = 0;
+ }
+}
diff --git a/vcl/aqua/source/res/MainMenu.nib/classes.nib b/vcl/aqua/source/res/MainMenu.nib/classes.nib
new file mode 100644
index 000000000000..b9b4b09f6b0d
--- /dev/null
+++ b/vcl/aqua/source/res/MainMenu.nib/classes.nib
@@ -0,0 +1,4 @@
+{
+ IBClasses = ({CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; });
+ IBVersion = 1;
+} \ No newline at end of file
diff --git a/vcl/aqua/source/res/MainMenu.nib/info.nib b/vcl/aqua/source/res/MainMenu.nib/info.nib
new file mode 100644
index 000000000000..856429aee5bd
--- /dev/null
+++ b/vcl/aqua/source/res/MainMenu.nib/info.nib
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>IBDocumentLocation</key>
+ <string>135 107 356 240 0 0 1680 1028 </string>
+ <key>IBEditorPositions</key>
+ <dict>
+ <key>29</key>
+ <string>132 352 141 44 0 0 1680 1028 </string>
+ </dict>
+ <key>IBFramework Version</key>
+ <string>446.1</string>
+ <key>IBOpenObjects</key>
+ <array>
+ <integer>29</integer>
+ </array>
+ <key>IBSystem Version</key>
+ <string>8R2218</string>
+</dict>
+</plist>
diff --git a/vcl/aqua/source/res/MainMenu.nib/keyedobjects.nib b/vcl/aqua/source/res/MainMenu.nib/keyedobjects.nib
new file mode 100644
index 000000000000..d39d10119c0c
--- /dev/null
+++ b/vcl/aqua/source/res/MainMenu.nib/keyedobjects.nib
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/airbrush.png b/vcl/aqua/source/res/cursors/airbrush.png
new file mode 100644
index 000000000000..7ec780c4f9f9
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/airbrush.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/ase.png b/vcl/aqua/source/res/cursors/ase.png
new file mode 100644
index 000000000000..a3a30e0bcdce
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/ase.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/asn.png b/vcl/aqua/source/res/cursors/asn.png
new file mode 100644
index 000000000000..7a140b1ec926
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/asn.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/asne.png b/vcl/aqua/source/res/cursors/asne.png
new file mode 100644
index 000000000000..311506aeb349
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/asne.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/asns.png b/vcl/aqua/source/res/cursors/asns.png
new file mode 100644
index 000000000000..1c8950eb28bc
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/asns.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/asnswe.png b/vcl/aqua/source/res/cursors/asnswe.png
new file mode 100644
index 000000000000..aae5246fbbc0
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/asnswe.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/asnw.png b/vcl/aqua/source/res/cursors/asnw.png
new file mode 100644
index 000000000000..9fd0036df077
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/asnw.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/ass.png b/vcl/aqua/source/res/cursors/ass.png
new file mode 100644
index 000000000000..bee09e736ad1
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/ass.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/asse.png b/vcl/aqua/source/res/cursors/asse.png
new file mode 100644
index 000000000000..d7883211d44f
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/asse.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/assw.png b/vcl/aqua/source/res/cursors/assw.png
new file mode 100644
index 000000000000..0b0a496a52ec
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/assw.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/asw.png b/vcl/aqua/source/res/cursors/asw.png
new file mode 100644
index 000000000000..5a4b9519e075
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/asw.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/aswe.png b/vcl/aqua/source/res/cursors/aswe.png
new file mode 100644
index 000000000000..b9c5afaac043
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/aswe.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/chain.png b/vcl/aqua/source/res/cursors/chain.png
new file mode 100644
index 000000000000..dbf069924d73
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/chain.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/chainnot.png b/vcl/aqua/source/res/cursors/chainnot.png
new file mode 100644
index 000000000000..547703edf12c
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/chainnot.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/chart.png b/vcl/aqua/source/res/cursors/chart.png
new file mode 100644
index 000000000000..de5514006e1f
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/chart.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/copydata.png b/vcl/aqua/source/res/cursors/copydata.png
new file mode 100644
index 000000000000..b6202fd9144f
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/copydata.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/copydlnk.png b/vcl/aqua/source/res/cursors/copydlnk.png
new file mode 100644
index 000000000000..fab24c9f8f7c
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/copydlnk.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/copyf.png b/vcl/aqua/source/res/cursors/copyf.png
new file mode 100644
index 000000000000..70546d0c0c22
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/copyf.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/copyf2.png b/vcl/aqua/source/res/cursors/copyf2.png
new file mode 100644
index 000000000000..b6f76051f10f
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/copyf2.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/copyflnk.png b/vcl/aqua/source/res/cursors/copyflnk.png
new file mode 100644
index 000000000000..23561e484e36
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/copyflnk.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/crook.png b/vcl/aqua/source/res/cursors/crook.png
new file mode 100644
index 000000000000..4378f8df8351
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/crook.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/crop.png b/vcl/aqua/source/res/cursors/crop.png
new file mode 100644
index 000000000000..92a778ada31a
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/crop.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/darc.png b/vcl/aqua/source/res/cursors/darc.png
new file mode 100644
index 000000000000..9772a1c6b85a
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/darc.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/dbezier.png b/vcl/aqua/source/res/cursors/dbezier.png
new file mode 100644
index 000000000000..988498137e9a
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/dbezier.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/dcapt.png b/vcl/aqua/source/res/cursors/dcapt.png
new file mode 100644
index 000000000000..d1ef82818735
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/dcapt.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/dcirccut.png b/vcl/aqua/source/res/cursors/dcirccut.png
new file mode 100644
index 000000000000..cb4ed0e85ecd
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/dcirccut.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/dconnect.png b/vcl/aqua/source/res/cursors/dconnect.png
new file mode 100644
index 000000000000..e4a43bdbe021
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/dconnect.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/dellipse.png b/vcl/aqua/source/res/cursors/dellipse.png
new file mode 100644
index 000000000000..319c4574c7c1
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/dellipse.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/detectiv.png b/vcl/aqua/source/res/cursors/detectiv.png
new file mode 100644
index 000000000000..abe93f263d4d
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/detectiv.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/dfree.png b/vcl/aqua/source/res/cursors/dfree.png
new file mode 100644
index 000000000000..2de92942adde
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/dfree.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/dline.png b/vcl/aqua/source/res/cursors/dline.png
new file mode 100644
index 000000000000..6afb670ef8a8
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/dline.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/dpie.png b/vcl/aqua/source/res/cursors/dpie.png
new file mode 100644
index 000000000000..44a9474846b9
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/dpie.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/dpolygon.png b/vcl/aqua/source/res/cursors/dpolygon.png
new file mode 100644
index 000000000000..847e6ad9bea5
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/dpolygon.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/drect.png b/vcl/aqua/source/res/cursors/drect.png
new file mode 100644
index 000000000000..ff3dcbba07b4
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/drect.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/dtext.png b/vcl/aqua/source/res/cursors/dtext.png
new file mode 100644
index 000000000000..ee375f0e47a0
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/dtext.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/fill.png b/vcl/aqua/source/res/cursors/fill.png
new file mode 100644
index 000000000000..220641b9beb4
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/fill.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/help.png b/vcl/aqua/source/res/cursors/help.png
new file mode 100644
index 000000000000..e29c19eccd22
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/help.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/hourglass.png b/vcl/aqua/source/res/cursors/hourglass.png
new file mode 100644
index 000000000000..07bb5af73e6e
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/hourglass.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/hshear.png b/vcl/aqua/source/res/cursors/hshear.png
new file mode 100644
index 000000000000..b45beded2d93
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/hshear.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/linkdata.png b/vcl/aqua/source/res/cursors/linkdata.png
new file mode 100644
index 000000000000..6432db0155b6
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/linkdata.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/linkf.png b/vcl/aqua/source/res/cursors/linkf.png
new file mode 100644
index 000000000000..e17107fec9ff
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/linkf.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/magnify.png b/vcl/aqua/source/res/cursors/magnify.png
new file mode 100644
index 000000000000..4e73146b91e4
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/magnify.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/mirror.png b/vcl/aqua/source/res/cursors/mirror.png
new file mode 100644
index 000000000000..8fac93f0b6df
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/mirror.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/movebw.png b/vcl/aqua/source/res/cursors/movebw.png
new file mode 100644
index 000000000000..63bf76ad3942
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/movebw.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/movedata.png b/vcl/aqua/source/res/cursors/movedata.png
new file mode 100644
index 000000000000..60ece8a53e59
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/movedata.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/movedlnk.png b/vcl/aqua/source/res/cursors/movedlnk.png
new file mode 100644
index 000000000000..6951cd718d97
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/movedlnk.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/movef.png b/vcl/aqua/source/res/cursors/movef.png
new file mode 100644
index 000000000000..97a01c88fa4d
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/movef.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/movef2.png b/vcl/aqua/source/res/cursors/movef2.png
new file mode 100644
index 000000000000..2cdddb410aae
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/movef2.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/moveflnk.png b/vcl/aqua/source/res/cursors/moveflnk.png
new file mode 100644
index 000000000000..53301ba58c50
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/moveflnk.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/movept.png b/vcl/aqua/source/res/cursors/movept.png
new file mode 100644
index 000000000000..41945deb1916
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/movept.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/neswsize.png b/vcl/aqua/source/res/cursors/neswsize.png
new file mode 100644
index 000000000000..91b89b5803ec
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/neswsize.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/notallow.png b/vcl/aqua/source/res/cursors/notallow.png
new file mode 100644
index 000000000000..df770a495194
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/notallow.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/nullptr.png b/vcl/aqua/source/res/cursors/nullptr.png
new file mode 100644
index 000000000000..489636595bec
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/nullptr.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/nwsesize.png b/vcl/aqua/source/res/cursors/nwsesize.png
new file mode 100644
index 000000000000..fc6a33288ef2
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/nwsesize.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/pen.png b/vcl/aqua/source/res/cursors/pen.png
new file mode 100644
index 000000000000..81b583086778
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/pen.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/pivotcol.png b/vcl/aqua/source/res/cursors/pivotcol.png
new file mode 100644
index 000000000000..1c38b915b886
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/pivotcol.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/pivotdel.png b/vcl/aqua/source/res/cursors/pivotdel.png
new file mode 100644
index 000000000000..fbd663ee36c1
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/pivotdel.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/pivotfld.png b/vcl/aqua/source/res/cursors/pivotfld.png
new file mode 100644
index 000000000000..04375de1efe6
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/pivotfld.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/pivotrow.png b/vcl/aqua/source/res/cursors/pivotrow.png
new file mode 100644
index 000000000000..18ef0e8e59ba
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/pivotrow.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/pntbrsh.png b/vcl/aqua/source/res/cursors/pntbrsh.png
new file mode 100644
index 000000000000..ec8d799f66c2
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/pntbrsh.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/rotate.png b/vcl/aqua/source/res/cursors/rotate.png
new file mode 100644
index 000000000000..a8137e077e56
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/rotate.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/tblsele.png b/vcl/aqua/source/res/cursors/tblsele.png
new file mode 100644
index 000000000000..a2da05e009d1
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/tblsele.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/tblsels.png b/vcl/aqua/source/res/cursors/tblsels.png
new file mode 100644
index 000000000000..ba20589c794f
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/tblsels.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/tblselse.png b/vcl/aqua/source/res/cursors/tblselse.png
new file mode 100644
index 000000000000..4ee7f62b304b
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/tblselse.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/tblselsw.png b/vcl/aqua/source/res/cursors/tblselsw.png
new file mode 100644
index 000000000000..11d7cb34d64d
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/tblselsw.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/tblselw.png b/vcl/aqua/source/res/cursors/tblselw.png
new file mode 100644
index 000000000000..62813a975855
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/tblselw.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/timemove.png b/vcl/aqua/source/res/cursors/timemove.png
new file mode 100644
index 000000000000..3dae038a2011
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/timemove.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/timesize.png b/vcl/aqua/source/res/cursors/timesize.png
new file mode 100644
index 000000000000..22178c9b8d0e
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/timesize.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/vshear.png b/vcl/aqua/source/res/cursors/vshear.png
new file mode 100644
index 000000000000..b01cb6c935e1
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/vshear.png
Binary files differ
diff --git a/vcl/aqua/source/res/cursors/vtext.png b/vcl/aqua/source/res/cursors/vtext.png
new file mode 100644
index 000000000000..2d6c847c9fc7
--- /dev/null
+++ b/vcl/aqua/source/res/cursors/vtext.png
Binary files differ
diff --git a/vcl/aqua/source/res/delzip b/vcl/aqua/source/res/delzip
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/vcl/aqua/source/res/delzip
diff --git a/vcl/aqua/source/res/makefile.mk b/vcl/aqua/source/res/makefile.mk
new file mode 100644
index 000000000000..2043504450e7
--- /dev/null
+++ b/vcl/aqua/source/res/makefile.mk
@@ -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.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+TARGET=aquares
+
+# --- Settings -------------------------------------------------
+
+.INCLUDE : settings.mk
+
+# --- Files ----------------------------------------------------
+
+.IF "$(OS)"!="MACOSX"
+
+dummy:
+ @echo "Nothing to build for OS $(OS)"
+
+.ELSE # "$(OS)"!="MACOSX"
+
+ZIPFLAGS = -r
+ZIP1TARGET = osxres
+#ZIP1DIR =
+ZIP1LIST = MainMenu.nib/*.nib cursors/*.png
+
+# --- Targets --------------------------------------------------
+
+.INCLUDE : target.mk
+
+.ENDIF # "$(OS)"!="MACOSX"
+
diff --git a/vcl/aqua/source/window/makefile.mk b/vcl/aqua/source/window/makefile.mk
new file mode 100644
index 000000000000..7afbce885e4a
--- /dev/null
+++ b/vcl/aqua/source/window/makefile.mk
@@ -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.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+
+PRJNAME=vcl
+TARGET=salwin
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+ENABLE_EXCEPTIONS=TRUE
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)"!="aqua"
+
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+
+.ELSE # "$(GUIBASE)"!="aqua"
+
+SLOFILES= \
+ $(SLO)/salframe.obj \
+ $(SLO)/salframeview.obj \
+ $(SLO)/salmenu.obj \
+ $(SLO)/salnsmenu.obj \
+ $(SLO)/salobj.obj
+
+.ENDIF # "$(GUIBASE)"!="aqua"
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
+.INCLUDE : $(PRJ)$/util$/target.pmk
diff --git a/vcl/aqua/source/window/salframe.cxx b/vcl/aqua/source/window/salframe.cxx
new file mode 100644
index 000000000000..b14354e1b4bd
--- /dev/null
+++ b/vcl/aqua/source/window/salframe.cxx
@@ -0,0 +1,1636 @@
+/************************************************************************
+ *
+ * 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>
+
+#include "saldata.hxx"
+#include "salgdi.h"
+#include "salframe.h"
+#include "salmenu.h"
+#include "saltimer.h"
+#include "salinst.h"
+#include "salframeview.h"
+#include "aqua11yfactory.h"
+#include "vcl/salwtype.hxx"
+#include "vcl/window.hxx"
+#include "vcl/timer.hxx"
+
+#include "premac.h"
+// needed for theming
+// FIXME: move theming code to salnativewidgets.cxx
+#include <Carbon/Carbon.h>
+#include "postmac.h"
+
+#include "boost/assert.hpp"
+#include "vcl/svapp.hxx"
+#include "rtl/ustrbuf.hxx"
+#include "osl/file.h"
+
+using namespace std;
+
+// =======================================================================
+
+AquaSalFrame* AquaSalFrame::s_pCaptureFrame = NULL;
+
+// =======================================================================
+
+AquaSalFrame::AquaSalFrame( SalFrame* pParent, ULONG salFrameStyle ) :
+ mpWindow(nil),
+ mpView(nil),
+ mpDockMenuEntry(nil),
+ mpGraphics(NULL),
+ mpParent(NULL),
+ mnMinWidth(0),
+ mnMinHeight(0),
+ mnMaxWidth(0),
+ mnMaxHeight(0),
+ mbGraphics(false),
+ mbFullScreen( false ),
+ mbShown(false),
+ mbInitShow(true),
+ mbPositioned(false),
+ mbSized(false),
+ mbPresentation( false ),
+ mnStyle( salFrameStyle ),
+ mnStyleMask( 0 ),
+ mnLastEventTime( 0 ),
+ mnLastModifierFlags( 0 ),
+ mpMenu( NULL ),
+ mnExtStyle( 0 ),
+ mePointerStyle( POINTER_ARROW ),
+ mnTrackingRectTag( 0 ),
+ mrClippingPath( 0 ),
+ mnICOptions( 0 )
+{
+ maSysData.nSize = sizeof( SystemEnvData );
+
+ mpParent = dynamic_cast<AquaSalFrame*>(pParent);
+
+ initWindowAndView();
+
+ SalData* pSalData = GetSalData();
+ pSalData->maFrames.push_front( this );
+ pSalData->maFrameCheck.insert( this );
+}
+
+// -----------------------------------------------------------------------
+
+AquaSalFrame::~AquaSalFrame()
+{
+ // if the frame is destroyed and has the current menubar
+ // set the default menubar
+ if( mpMenu && mpMenu->mbMenuBar && AquaSalMenu::pCurrentMenuBar == mpMenu )
+ AquaSalMenu::setDefaultMenu();
+
+ // cleanup clipping stuff
+ ResetClipRegion();
+
+ [SalFrameView unsetMouseFrame: this];
+
+ SalData* pSalData = GetSalData();
+ pSalData->maFrames.remove( this );
+ pSalData->maFrameCheck.erase( this );
+
+ DBG_ASSERT( this != s_pCaptureFrame, "capture frame destroyed" );
+ if( this == s_pCaptureFrame )
+ s_pCaptureFrame = NULL;
+
+ if ( mpGraphics )
+ delete mpGraphics;
+
+ if( mpDockMenuEntry )
+ // life cycle comment: the menu has ownership of the item, so no release
+ [AquaSalInstance::GetDynamicDockMenu() removeItem: mpDockMenuEntry];
+ if ( mpView ) {
+ [AquaA11yFactory revokeView: mpView];
+ [mpView release];
+ }
+ if ( mpWindow )
+ [mpWindow release];
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::initWindowAndView()
+{
+ // initialize mirroring parameters
+ // FIXME: screens changing
+ NSScreen * pScreen = [mpWindow screen];
+ if( pScreen == nil )
+ pScreen = [NSScreen mainScreen];
+ maScreenRect = [pScreen frame];
+
+ // calculate some default geometry
+ NSRect aVisibleRect = [pScreen visibleFrame];
+ CocoaToVCL( aVisibleRect );
+
+ maGeometry.nX = static_cast<int>(aVisibleRect.origin.x + aVisibleRect.size.width / 10);
+ maGeometry.nY = static_cast<int>(aVisibleRect.origin.y + aVisibleRect.size.height / 10);
+ maGeometry.nWidth = static_cast<unsigned int>(aVisibleRect.size.width * 0.8);
+ maGeometry.nHeight = static_cast<unsigned int>(aVisibleRect.size.height * 0.8);
+
+ // calculate style mask
+ if( (mnStyle & SAL_FRAME_STYLE_FLOAT) ||
+ (mnStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) )
+ mnStyleMask = NSBorderlessWindowMask;
+ else if( mnStyle & SAL_FRAME_STYLE_DEFAULT )
+ {
+ mnStyleMask = NSTitledWindowMask |
+ NSMiniaturizableWindowMask |
+ NSResizableWindowMask |
+ NSClosableWindowMask;
+ // make default window "maximized"
+ maGeometry.nX = static_cast<int>(aVisibleRect.origin.x);
+ maGeometry.nY = static_cast<int>(aVisibleRect.origin.y);
+ maGeometry.nWidth = static_cast<int>(aVisibleRect.size.width);
+ maGeometry.nHeight = static_cast<int>(aVisibleRect.size.height);
+ mbPositioned = mbSized = true;
+ }
+ else
+ {
+ if( (mnStyle & SAL_FRAME_STYLE_MOVEABLE) )
+ {
+ mnStyleMask |= NSTitledWindowMask;
+ if( mpParent == NULL )
+ mnStyleMask |= NSMiniaturizableWindowMask;
+ }
+ if( (mnStyle & SAL_FRAME_STYLE_SIZEABLE) )
+ mnStyleMask |= NSResizableWindowMask;
+ if( (mnStyle & SAL_FRAME_STYLE_CLOSEABLE) )
+ mnStyleMask |= NSClosableWindowMask;
+ // documentation says anything other than NSBorderlessWindowMask (=0)
+ // should also include NSTitledWindowMask;
+ if( mnStyleMask != 0 )
+ mnStyleMask |= NSTitledWindowMask;
+ }
+
+ mpWindow = [[SalFrameWindow alloc] initWithSalFrame: this];
+ mpView = [[SalFrameView alloc] initWithSalFrame: this];
+ if( (mnStyle & SAL_FRAME_STYLE_TOOLTIP) )
+ [mpWindow setIgnoresMouseEvents: YES];
+ else
+ [mpWindow setAcceptsMouseMovedEvents: YES];
+ [mpWindow setHasShadow: YES];
+ [mpWindow setDelegate: mpWindow];
+
+ NSRect aRect = { { 0,0 }, { maGeometry.nWidth, maGeometry.nHeight } };
+ mnTrackingRectTag = [mpView addTrackingRect: aRect owner: mpView userData: nil assumeInside: NO];
+
+ maSysData.pView = mpView;
+
+ UpdateFrameGeometry();
+
+ // setContentView causes a display; in multithreaded use this can deadlock
+ //YieldMutexReleaser aRel;
+ [mpWindow setContentView: mpView];
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::CocoaToVCL( NSRect& io_rRect, bool bRelativeToScreen )
+{
+ if( bRelativeToScreen )
+ io_rRect.origin.y = maScreenRect.size.height - (io_rRect.origin.y+io_rRect.size.height);
+ else
+ io_rRect.origin.y = maGeometry.nHeight - (io_rRect.origin.y+io_rRect.size.height);
+}
+
+void AquaSalFrame::VCLToCocoa( NSRect& io_rRect, bool bRelativeToScreen )
+{
+ if( bRelativeToScreen )
+ io_rRect.origin.y = maScreenRect.size.height - (io_rRect.origin.y+io_rRect.size.height);
+ else
+ io_rRect.origin.y = maGeometry.nHeight - (io_rRect.origin.y+io_rRect.size.height);
+}
+
+void AquaSalFrame::CocoaToVCL( NSPoint& io_rPoint, bool bRelativeToScreen )
+{
+ if( bRelativeToScreen )
+ io_rPoint.y = maScreenRect.size.height - io_rPoint.y;
+ else
+ io_rPoint.y = maGeometry.nHeight - io_rPoint.y;
+}
+
+void AquaSalFrame::VCLToCocoa( NSPoint& io_rPoint, bool bRelativeToScreen )
+{
+ if( bRelativeToScreen )
+ io_rPoint.y = maScreenRect.size.height - io_rPoint.y;
+ else
+ io_rPoint.y = maGeometry.nHeight - io_rPoint.y;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::screenParametersChanged()
+{
+ UpdateFrameGeometry();
+
+ if( mpGraphics )
+ mpGraphics->updateResolution();
+ CallCallback( SALEVENT_DISPLAYCHANGED, 0 );
+}
+
+// -----------------------------------------------------------------------
+
+SalGraphics* AquaSalFrame::GetGraphics()
+{
+ if ( mbGraphics )
+ return NULL;
+
+ if ( !mpGraphics )
+ {
+ mpGraphics = new AquaSalGraphics;
+ mpGraphics->SetWindowGraphics( this );
+ }
+
+ mbGraphics = TRUE;
+ return mpGraphics;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::ReleaseGraphics( SalGraphics *pGraphics )
+{
+ DBG_ASSERT( pGraphics == mpGraphics, "graphics released on wrong frame" );
+ mbGraphics = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalFrame::PostEvent( void *pData )
+{
+ GetSalData()->mpFirstInstance->PostUserEvent( this, SALEVENT_USEREVENT, pData );
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+void AquaSalFrame::SetTitle(const XubString& rTitle)
+{
+ NSString* pTitle = CreateNSString( rTitle );
+ [mpWindow setTitle: pTitle];
+
+ // create an entry in the dock menu
+ const ULONG nAppWindowStyle = (SAL_FRAME_STYLE_CLOSEABLE | SAL_FRAME_STYLE_MOVEABLE);
+ if( mpParent == NULL &&
+ (mnStyle & nAppWindowStyle) == nAppWindowStyle )
+ {
+ if( mpDockMenuEntry == NULL )
+ {
+ NSMenu* pDock = AquaSalInstance::GetDynamicDockMenu();
+ mpDockMenuEntry = [pDock insertItemWithTitle: pTitle
+ action: @selector(dockMenuItemTriggered:)
+ keyEquivalent: @""
+ atIndex: 0];
+ [mpDockMenuEntry setTarget: mpWindow];
+
+ // TODO: image (either the generic window image or an icon
+ // check mark (for "main" window ?)
+ }
+ else
+ [mpDockMenuEntry setTitle: pTitle];
+ }
+
+ if (pTitle)
+ [pTitle release];
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::SetIcon( USHORT )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::SetRepresentedURL( const rtl::OUString& i_rDocURL )
+{
+ if( i_rDocURL.indexOfAsciiL( "file:", 5 ) == 0 )
+ {
+ rtl::OUString aSysPath;
+ osl_getSystemPathFromFileURL( i_rDocURL.pData, &aSysPath.pData );
+ NSString* pStr = CreateNSString( aSysPath );
+ if( pStr )
+ {
+ [pStr autorelease];
+ [mpWindow setRepresentedFilename: pStr];
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::initShow()
+{
+ mbInitShow = false;
+ if( ! mbPositioned && ! mbFullScreen )
+ {
+ Rectangle aScreenRect;
+ GetWorkArea( aScreenRect );
+ if( mpParent ) // center relative to parent
+ {
+ // center on parent
+ long nNewX = mpParent->maGeometry.nX + (mpParent->maGeometry.nWidth - maGeometry.nWidth)/2;
+ if( nNewX < aScreenRect.Left() )
+ nNewX = aScreenRect.Left();
+ if( long(nNewX + maGeometry.nWidth) > aScreenRect.Right() )
+ nNewX = aScreenRect.Right() - maGeometry.nWidth-1;
+ long nNewY = mpParent->maGeometry.nY + (mpParent->maGeometry.nHeight - maGeometry.nHeight)/2;
+ if( nNewY < aScreenRect.Top() )
+ nNewY = aScreenRect.Top();
+ if( nNewY > aScreenRect.Bottom() )
+ nNewY = aScreenRect.Bottom() - maGeometry.nHeight-1;
+ SetPosSize( nNewX - mpParent->maGeometry.nX,
+ nNewY - mpParent->maGeometry.nY,
+ 0, 0, SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y );
+ }
+ else if( ! (mnStyle & SAL_FRAME_STYLE_SIZEABLE) )
+ {
+ // center on screen
+ long nNewX = (aScreenRect.GetWidth() - maGeometry.nWidth)/2;
+ long nNewY = (aScreenRect.GetHeight() - maGeometry.nHeight)/2;
+ SetPosSize( nNewX, nNewY, 0, 0, SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y );
+ }
+ }
+
+ // make sure the view is present in the wrapper list before any children receive focus
+ [AquaA11yFactory registerView: mpView];
+}
+
+void AquaSalFrame::SendPaintEvent( const Rectangle* pRect )
+{
+ SalPaintEvent aPaintEvt( 0, 0, maGeometry.nWidth, maGeometry.nHeight, true );
+ if( pRect )
+ {
+ aPaintEvt.mnBoundX = pRect->Left();
+ aPaintEvt.mnBoundY = pRect->Top();
+ aPaintEvt.mnBoundWidth = pRect->GetWidth();
+ aPaintEvt.mnBoundHeight = pRect->GetHeight();
+ }
+
+ CallCallback(SALEVENT_PAINT, &aPaintEvt);
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::Show(BOOL bVisible, BOOL bNoActivate)
+{
+ mbShown = bVisible;
+ if(bVisible)
+ {
+ if( mbInitShow )
+ initShow();
+
+ CallCallback(SALEVENT_RESIZE, 0);
+ // trigger filling our backbuffer
+ SendPaintEvent();
+
+ //YieldMutexReleaser aRel;
+
+ if( bNoActivate || [mpWindow canBecomeKeyWindow] == NO )
+ [mpWindow orderFront: NSApp];
+ else
+ [mpWindow makeKeyAndOrderFront: NSApp];
+
+ if( mpParent )
+ {
+ /* #i92674# #i96433# we do not want an invisible parent to show up (which adding a visible
+ child implicitly does). However we also do not want a parentless toolbar.
+
+ HACK: try to decide when we should not insert a child to its parent
+ floaters and ownerdraw windows have not yet shown up in cases where
+ we don't want the parent to become visible
+ */
+ if( mpParent->mbShown || (mnStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION | SAL_FRAME_STYLE_FLOAT) ) )
+ {
+ [mpParent->mpWindow addChildWindow: mpWindow ordered: NSWindowAbove];
+ }
+ }
+
+ if( mbPresentation )
+ [mpWindow makeMainWindow];
+ }
+ else
+ {
+ // if the frame holding the current menubar gets hidden
+ // show the default menubar
+ if( mpMenu && mpMenu->mbMenuBar && AquaSalMenu::pCurrentMenuBar == mpMenu )
+ AquaSalMenu::setDefaultMenu();
+
+ //YieldMutexReleaser aRel;
+
+ // #i90440# #i94443# work around the focus going back to some other window
+ // if a child gets hidden for a parent window
+ if( mpParent && mpParent->mbShown && [mpWindow isKeyWindow] )
+ [mpParent->mpWindow makeKeyAndOrderFront: NSApp];
+
+ [SalFrameView unsetMouseFrame: this];
+ if( mpParent && [mpWindow parentWindow] == mpParent->mpWindow )
+ [mpParent->mpWindow removeChildWindow: mpWindow];
+
+ [mpWindow orderOut: NSApp];
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::Enable( BOOL bEnable )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::SetMinClientSize( long nWidth, long nHeight )
+{
+ mnMinWidth = nWidth;
+ mnMinHeight = nHeight;
+
+ if( mpWindow )
+ {
+ // Always add the decoration as the dimension concerns only
+ // the content rectangle
+ nWidth += maGeometry.nLeftDecoration + maGeometry.nRightDecoration;
+ nHeight += maGeometry.nTopDecoration + maGeometry.nBottomDecoration;
+
+ NSSize aSize = { nWidth, nHeight };
+
+ // Size of full window (content+structure) although we only
+ // have the client size in arguments
+ [mpWindow setMinSize: aSize];
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::SetMaxClientSize( long nWidth, long nHeight )
+{
+ mnMaxWidth = nWidth;
+ mnMaxHeight = nHeight;
+
+ if( mpWindow )
+ {
+ // Always add the decoration as the dimension concerns only
+ // the content rectangle
+ nWidth += maGeometry.nLeftDecoration + maGeometry.nRightDecoration;
+ nHeight += maGeometry.nTopDecoration + maGeometry.nBottomDecoration;
+
+ // Carbon windows can't have a size greater than 32767x32767
+ if (nWidth>32767) nWidth=32767;
+ if (nHeight>32767) nHeight=32767;
+
+ NSSize aSize = { nWidth, nHeight };
+
+ // Size of full window (content+structure) although we only
+ // have the client size in arguments
+ [mpWindow setMaxSize: aSize];
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::SetClientSize( long nWidth, long nHeight )
+{
+ if( mpWindow )
+ {
+ NSSize aSize = { nWidth, nHeight };
+
+ [mpWindow setContentSize: aSize];
+ UpdateFrameGeometry();
+ if( mbShown )
+ // trigger filling our backbuffer
+ SendPaintEvent();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::GetClientSize( long& rWidth, long& rHeight )
+{
+ if( mbShown || mbInitShow )
+ {
+ rWidth = maGeometry.nWidth;
+ rHeight = maGeometry.nHeight;
+ }
+ else
+ {
+ rWidth = 0;
+ rHeight = 0;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::SetWindowState( const SalFrameState* pState )
+{
+ // set normal state
+ NSRect aStateRect = [mpWindow frame];
+ aStateRect = [NSWindow contentRectForFrameRect: aStateRect styleMask: mnStyleMask];
+ CocoaToVCL( aStateRect );
+ if( pState->mnMask & SAL_FRAMESTATE_MASK_X )
+ aStateRect.origin.x = float(pState->mnX);
+ if( pState->mnMask & SAL_FRAMESTATE_MASK_Y )
+ aStateRect.origin.y = float(pState->mnY);
+ if( pState->mnMask & SAL_FRAMESTATE_MASK_WIDTH )
+ aStateRect.size.width = float(pState->mnWidth);
+ if( pState->mnMask & SAL_FRAMESTATE_MASK_HEIGHT )
+ aStateRect.size.height = float(pState->mnHeight);
+ VCLToCocoa( aStateRect );
+ aStateRect = [NSWindow frameRectForContentRect: aStateRect styleMask: mnStyleMask];
+
+ // relase and acquire mutex again since this call can block waiting for an internal lock
+ {
+ //YieldMutexReleaser aRel;
+ [mpWindow setFrame: aStateRect display: NO];
+ }
+
+ // FIXME: HTH maximized state ?
+
+ // get new geometry
+ UpdateFrameGeometry();
+
+ USHORT nEvent = 0;
+ if( pState->mnMask & (SAL_FRAMESTATE_MASK_X | SAL_FRAMESTATE_MASK_X) )
+ {
+ mbPositioned = true;
+ nEvent = SALEVENT_MOVE;
+ }
+
+ if( pState->mnMask & (SAL_FRAMESTATE_MASK_WIDTH | SAL_FRAMESTATE_MASK_HEIGHT) )
+ {
+ mbSized = true;
+ nEvent = (nEvent == SALEVENT_MOVE) ? SALEVENT_MOVERESIZE : SALEVENT_RESIZE;
+ }
+ // send event that we were moved/sized
+ if( nEvent )
+ CallCallback( nEvent, NULL );
+
+ if( mbShown )
+ {
+ // trigger filling our backbuffer
+ SendPaintEvent();
+
+ // tell the system the views need to be updated
+ //YieldMutexReleaser aRel;
+
+ [mpWindow display];
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL AquaSalFrame::GetWindowState( SalFrameState* pState )
+{
+ pState->mnMask = SAL_FRAMESTATE_MASK_X |
+ SAL_FRAMESTATE_MASK_Y |
+ SAL_FRAMESTATE_MASK_WIDTH |
+ SAL_FRAMESTATE_MASK_HEIGHT |
+ #if 0
+ SAL_FRAMESTATE_MASK_MAXIMIZED_X |
+ SAL_FRAMESTATE_MASK_MAXIMIZED_Y |
+ SAL_FRAMESTATE_MASK_MAXIMIZED_WIDTH |
+ SAL_FRAMESTATE_MASK_MAXIMIZED_HEIGHT |
+ #endif
+ SAL_FRAMESTATE_MASK_STATE;
+
+ NSRect aStateRect = [mpWindow frame];
+ aStateRect = [NSWindow contentRectForFrameRect: aStateRect styleMask: mnStyleMask];
+ CocoaToVCL( aStateRect );
+ pState->mnX = long(aStateRect.origin.x);
+ pState->mnY = long(aStateRect.origin.y);
+ pState->mnWidth = long(aStateRect.size.width);
+ pState->mnHeight = long(aStateRect.size.height);
+
+ // FIXME: HTH maximized state ?
+
+ if( [mpWindow isMiniaturized] )
+ pState->mnState = SAL_FRAMESTATE_MINIMIZED;
+ else if( ! [mpWindow isZoomed] )
+ pState->mnState = SAL_FRAMESTATE_NORMAL;
+ else
+ pState->mnState = SAL_FRAMESTATE_MAXIMIZED;
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::SetScreenNumber(unsigned int nScreen)
+{
+ NSArray* pScreens = [NSScreen screens];
+ Rectangle aRet;
+ NSScreen* pScreen = nil;
+ if( pScreens && nScreen < [pScreens count] )
+ {
+ // get new screen frame
+ pScreen = [pScreens objectAtIndex: nScreen];
+ NSRect aNewScreen = [pScreen frame];
+
+ // get current screen frame
+ pScreen = [mpWindow screen];
+ if( pScreen )
+ {
+ NSRect aCurScreen = [pScreen frame];
+ if( aCurScreen.origin.x != aNewScreen.origin.x ||
+ aCurScreen.origin.y != aNewScreen.origin.y )
+ {
+ NSRect aFrameRect = [mpWindow frame];
+ aFrameRect.origin.x += aNewScreen.origin.x - aCurScreen.origin.x;
+ aFrameRect.origin.y += aNewScreen.origin.y - aCurScreen.origin.y;
+ [mpWindow setFrame: aFrameRect display: NO];
+ UpdateFrameGeometry();
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::ShowFullScreen( BOOL bFullScreen, sal_Int32 nDisplay )
+{
+ if( mbFullScreen == bFullScreen )
+ return;
+
+ mbFullScreen = bFullScreen;
+ if( bFullScreen )
+ {
+ // hide the dock and the menubar if we are on the menu screen
+ // which is always on index 0 according to documentation
+ bool bHideMenu = (nDisplay == 0);
+
+ NSRect aNewContentRect = { { 0, 0 }, { 0, 0 } };
+ // get correct screen
+ NSScreen* pScreen = nil;
+ NSArray* pScreens = [NSScreen screens];
+ if( pScreens )
+ {
+ if( nDisplay >= 0 && (unsigned int)nDisplay < [pScreens count] )
+ pScreen = [pScreens objectAtIndex: nDisplay];
+ else
+ {
+ // this means span all screens
+ bHideMenu = true;
+ NSEnumerator* pEnum = [pScreens objectEnumerator];
+ while( (pScreen = [pEnum nextObject]) != nil )
+ {
+ NSRect aScreenRect = [pScreen frame];
+ if( aScreenRect.origin.x < aNewContentRect.origin.x )
+ {
+ aNewContentRect.size.width += aNewContentRect.origin.x - aScreenRect.origin.x;
+ aNewContentRect.origin.x = aScreenRect.origin.x;
+ }
+ if( aScreenRect.origin.y < aNewContentRect.origin.y )
+ {
+ aNewContentRect.size.height += aNewContentRect.origin.y - aScreenRect.origin.y;
+ aNewContentRect.origin.y = aScreenRect.origin.y;
+ }
+ if( aScreenRect.origin.x + aScreenRect.size.width > aNewContentRect.origin.x + aNewContentRect.size.width )
+ aNewContentRect.size.width = aScreenRect.origin.x + aScreenRect.size.width - aNewContentRect.origin.x;
+ if( aScreenRect.origin.y + aScreenRect.size.height > aNewContentRect.origin.y + aNewContentRect.size.height )
+ aNewContentRect.size.height = aScreenRect.origin.y + aScreenRect.size.height - aNewContentRect.origin.y;
+ }
+ }
+ }
+ if( aNewContentRect.size.width == 0 && aNewContentRect.size.height == 0 )
+ {
+ if( pScreen == nil )
+ pScreen = [mpWindow screen];
+ if( pScreen == nil )
+ pScreen = [NSScreen mainScreen];
+
+ aNewContentRect = [pScreen frame];
+ }
+
+ if( bHideMenu )
+ [NSMenu setMenuBarVisible:NO];
+
+ maFullScreenRect = [mpWindow frame];
+ {
+ //YieldMutexReleaser aRel;
+ [mpWindow setFrame: [NSWindow frameRectForContentRect: aNewContentRect styleMask: mnStyleMask] display: mbShown ? YES : NO];
+ }
+
+ UpdateFrameGeometry();
+
+ if( mbShown )
+ CallCallback( SALEVENT_MOVERESIZE, NULL );
+ }
+ else
+ {
+ {
+ //YieldMutexReleaser aRel;
+ [mpWindow setFrame: maFullScreenRect display: mbShown ? YES : NO];
+ }
+ UpdateFrameGeometry();
+
+ if( mbShown )
+ CallCallback( SALEVENT_MOVERESIZE, NULL );
+
+ // show the dock and the menubar
+ [NSMenu setMenuBarVisible:YES];
+ }
+ if( mbShown )
+ // trigger filling our backbuffer
+ SendPaintEvent();
+}
+
+// -----------------------------------------------------------------------
+
+class PreventSleepTimer : public AutoTimer
+{
+public:
+ PreventSleepTimer()
+ {
+ SetTimeout( 30000 );
+ Start();
+ }
+
+ virtual ~PreventSleepTimer()
+ {
+ }
+
+ virtual void Timeout()
+ {
+ UpdateSystemActivity(OverallAct);
+ }
+};
+
+void AquaSalFrame::StartPresentation( BOOL bStart )
+{
+ if( bStart )
+ {
+ mpActivityTimer.reset( new PreventSleepTimer() );
+ [mpWindow setLevel: NSScreenSaverWindowLevel];
+ if( mbShown )
+ [mpWindow makeMainWindow];
+ }
+ else
+ {
+ mpActivityTimer.reset();
+ [mpWindow setLevel: NSNormalWindowLevel];
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::SetAlwaysOnTop( BOOL bOnTop )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::ToTop(USHORT nFlags)
+{
+ if( ! (nFlags & SAL_FRAME_TOTOP_RESTOREWHENMIN) )
+ {
+ if( ! [mpWindow isVisible] || [mpWindow isMiniaturized] )
+ return;
+ }
+ if( nFlags & SAL_FRAME_TOTOP_GRABFOCUS )
+ [mpWindow makeKeyAndOrderFront: NSApp];
+ else
+ [mpWindow orderFront: NSApp];
+}
+
+// -----------------------------------------------------------------------
+
+NSCursor* AquaSalFrame::getCurrentCursor() const
+{
+ NSCursor* pCursor = nil;
+ switch( mePointerStyle )
+ {
+ case POINTER_TEXT: pCursor = [NSCursor IBeamCursor]; break;
+ case POINTER_CROSS: pCursor = [NSCursor crosshairCursor]; break;
+ case POINTER_HAND:
+ case POINTER_MOVE: pCursor = [NSCursor openHandCursor]; break;
+ case POINTER_NSIZE: pCursor = [NSCursor resizeUpCursor]; break;
+ case POINTER_SSIZE: pCursor = [NSCursor resizeDownCursor]; break;
+ case POINTER_ESIZE: pCursor = [NSCursor resizeRightCursor]; break;
+ case POINTER_WSIZE: pCursor = [NSCursor resizeLeftCursor]; break;
+ case POINTER_ARROW: pCursor = [NSCursor arrowCursor]; break;
+ case POINTER_VSPLIT:
+ case POINTER_VSIZEBAR:
+ case POINTER_WINDOW_NSIZE:
+ case POINTER_WINDOW_SSIZE:
+ pCursor = [NSCursor resizeUpDownCursor]; break;
+ case POINTER_HSPLIT:
+ case POINTER_HSIZEBAR:
+ case POINTER_WINDOW_ESIZE:
+ case POINTER_WINDOW_WSIZE:
+ pCursor = [NSCursor resizeLeftRightCursor]; break;
+ case POINTER_REFHAND: pCursor = [NSCursor pointingHandCursor]; break;
+
+ default:
+ pCursor = GetSalData()->getCursor( mePointerStyle );
+ if( pCursor == nil )
+ {
+ DBG_ERROR( "unmapped cursor" );
+ pCursor = [NSCursor arrowCursor];
+ }
+ break;
+ }
+ return pCursor;
+}
+
+void AquaSalFrame::SetPointer( PointerStyle ePointerStyle )
+{
+ if( ePointerStyle >= POINTER_COUNT || ePointerStyle == mePointerStyle )
+ return;
+ mePointerStyle = ePointerStyle;
+
+ [mpWindow invalidateCursorRectsForView: mpView];
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::SetPointerPos( long nX, long nY )
+{
+ // FIXME: use Cocoa functions
+
+ // FIXME: multiscreen support
+ CGPoint aPoint = { nX + maGeometry.nX, nY + maGeometry.nY };
+ CGDirectDisplayID mainDisplayID = CGMainDisplayID();
+ CGDisplayMoveCursorToPoint( mainDisplayID, aPoint );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::Flush( void )
+{
+ if( !(mbGraphics && mpGraphics && mpView && mbShown) )
+ return;
+
+ [mpView setNeedsDisplay: YES];
+
+ // outside of the application's event loop (e.g. IntroWindow)
+ // nothing would trigger paint event handling
+ // => fall back to synchronous painting
+ if( ImplGetSVData()->maAppData.mnDispatchLevel <= 0 )
+ {
+ [mpView display];
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::Flush( const Rectangle& rRect )
+{
+ if( !(mbGraphics && mpGraphics && mpView && mbShown) )
+ return;
+
+ NSRect aNSRect = { {rRect.Left(), rRect.Top()}, { rRect.GetWidth(), rRect.GetHeight() } };
+ VCLToCocoa( aNSRect, false );
+ [mpView setNeedsDisplayInRect: aNSRect];
+
+ // outside of the application's event loop (e.g. IntroWindow)
+ // nothing would trigger paint event handling
+ // => fall back to synchronous painting
+ if( ImplGetSVData()->maAppData.mnDispatchLevel <= 0 )
+ {
+ [mpView display];
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::Sync()
+{
+ if( mbGraphics && mpGraphics && mpView && mbShown )
+ {
+ //YieldMutexReleaser aRel;
+
+ [mpView setNeedsDisplay: YES];
+ [mpView display];
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::SetInputContext( SalInputContext* pContext )
+{
+ if (!pContext)
+ {
+ mnICOptions = 0;
+ return;
+ }
+
+ mnICOptions = pContext->mnOptions;
+
+ if(!(pContext->mnOptions & SAL_INPUTCONTEXT_TEXT))
+ return;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::EndExtTextInput( USHORT nFlags )
+{
+}
+
+// -----------------------------------------------------------------------
+
+XubString AquaSalFrame::GetKeyName( USHORT nKeyCode )
+{
+ static std::map< USHORT, rtl::OUString > aKeyMap;
+ if( aKeyMap.empty() )
+ {
+ USHORT i;
+ for( i = KEY_A; i <= KEY_Z; i++ )
+ aKeyMap[ i ] = rtl::OUString( sal_Unicode( 'A' + (i - KEY_A) ) );
+ for( i = KEY_0; i <= KEY_9; i++ )
+ aKeyMap[ i ] = rtl::OUString( sal_Unicode( '0' + (i - KEY_0) ) );
+ for( i = KEY_F1; i <= KEY_F26; i++ )
+ {
+ rtl::OUStringBuffer aKey( 3 );
+ aKey.append( sal_Unicode( 'F' ) );
+ aKey.append( sal_Int32( i - KEY_F1 + 1 ) );
+ aKeyMap[ i ] = aKey.makeStringAndClear();
+ }
+
+ aKeyMap[ KEY_DOWN ] = rtl::OUString( sal_Unicode( 0x21e3 ) );
+ aKeyMap[ KEY_UP ] = rtl::OUString( sal_Unicode( 0x21e1 ) );
+ aKeyMap[ KEY_LEFT ] = rtl::OUString( sal_Unicode( 0x21e0 ) );
+ aKeyMap[ KEY_RIGHT ] = rtl::OUString( sal_Unicode( 0x21e2 ) );
+ aKeyMap[ KEY_HOME ] = rtl::OUString( sal_Unicode( 0x2196 ) );
+ aKeyMap[ KEY_END ] = rtl::OUString( sal_Unicode( 0x2198 ) );
+ aKeyMap[ KEY_PAGEUP ] = rtl::OUString( sal_Unicode( 0x21de ) );
+ aKeyMap[ KEY_PAGEDOWN ] = rtl::OUString( sal_Unicode( 0x21df ) );
+ aKeyMap[ KEY_RETURN ] = rtl::OUString( sal_Unicode( 0x21a9 ) );
+ aKeyMap[ KEY_ESCAPE ] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "esc" ) );
+ aKeyMap[ KEY_TAB ] = rtl::OUString( sal_Unicode( 0x21e5 ) );
+ aKeyMap[ KEY_BACKSPACE ]= rtl::OUString( sal_Unicode( 0x232b ) );
+ aKeyMap[ KEY_SPACE ] = rtl::OUString( sal_Unicode( 0x2423 ) );
+ aKeyMap[ KEY_DELETE ] = rtl::OUString( sal_Unicode( 0x2326 ) );
+ aKeyMap[ KEY_ADD ] = rtl::OUString( sal_Unicode( '+' ) );
+ aKeyMap[ KEY_SUBTRACT ] = rtl::OUString( sal_Unicode( '-' ) );
+ aKeyMap[ KEY_DIVIDE ] = rtl::OUString( sal_Unicode( '/' ) );
+ aKeyMap[ KEY_MULTIPLY ] = rtl::OUString( sal_Unicode( '*' ) );
+ aKeyMap[ KEY_POINT ] = rtl::OUString( sal_Unicode( '.' ) );
+ aKeyMap[ KEY_COMMA ] = rtl::OUString( sal_Unicode( ',' ) );
+ aKeyMap[ KEY_LESS ] = rtl::OUString( sal_Unicode( '<' ) );
+ aKeyMap[ KEY_GREATER ] = rtl::OUString( sal_Unicode( '>' ) );
+ aKeyMap[ KEY_EQUAL ] = rtl::OUString( sal_Unicode( '=' ) );
+ aKeyMap[ KEY_OPEN ] = rtl::OUString( sal_Unicode( 0x23cf ) );
+
+ /* yet unmapped KEYCODES:
+ aKeyMap[ KEY_INSERT ] = rtl::OUString( sal_Unicode( ) );
+ aKeyMap[ KEY_CUT ] = rtl::OUString( sal_Unicode( ) );
+ aKeyMap[ KEY_COPY ] = rtl::OUString( sal_Unicode( ) );
+ aKeyMap[ KEY_PASTE ] = rtl::OUString( sal_Unicode( ) );
+ aKeyMap[ KEY_UNDO ] = rtl::OUString( sal_Unicode( ) );
+ aKeyMap[ KEY_REPEAT ] = rtl::OUString( sal_Unicode( ) );
+ aKeyMap[ KEY_FIND ] = rtl::OUString( sal_Unicode( ) );
+ aKeyMap[ KEY_PROPERTIES ] = rtl::OUString( sal_Unicode( ) );
+ aKeyMap[ KEY_FRONT ] = rtl::OUString( sal_Unicode( ) );
+ aKeyMap[ KEY_CONTEXTMENU ] = rtl::OUString( sal_Unicode( ) );
+ aKeyMap[ KEY_MENU ] = rtl::OUString( sal_Unicode( ) );
+ aKeyMap[ KEY_HELP ] = rtl::OUString( sal_Unicode( ) );
+ aKeyMap[ KEY_HANGUL_HANJA ] = rtl::OUString( sal_Unicode( ) );
+ aKeyMap[ KEY_DECIMAL ] = rtl::OUString( sal_Unicode( ) );
+ aKeyMap[ KEY_TILDE ] = rtl::OUString( sal_Unicode( ) );
+ aKeyMap[ KEY_QUOTELEFT ]= rtl::OUString( sal_Unicode( ) );
+ */
+
+ }
+
+ rtl::OUStringBuffer aResult( 16 );
+
+ USHORT nUnmodifiedCode = (nKeyCode & KEY_CODE);
+ std::map< USHORT, rtl::OUString >::const_iterator it = aKeyMap.find( nUnmodifiedCode );
+ if( it != aKeyMap.end() )
+ {
+ if( (nKeyCode & KEY_SHIFT) != 0 )
+ aResult.append( sal_Unicode( 0x21e7 ) );
+ if( (nKeyCode & KEY_MOD1) != 0 )
+ aResult.append( sal_Unicode( 0x2318 ) );
+ // we do not really handle Alt (see below)
+ // we map it to MOD3, whichis actually Command
+ if( (nKeyCode & (KEY_MOD2|KEY_MOD3)) != 0 )
+ aResult.append( sal_Unicode( 0x2303 ) );
+
+ aResult.append( it->second );
+ }
+
+ return aResult.makeStringAndClear();
+}
+
+// -----------------------------------------------------------------------
+
+XubString AquaSalFrame::GetSymbolKeyName( const XubString&, USHORT nKeyCode )
+{
+ return GetKeyName( nKeyCode );
+}
+
+// -----------------------------------------------------------------------
+
+static void getAppleScrollBarVariant(void)
+{
+ bool bIsScrollbarDoubleMax = true; // default is DoubleMax
+
+ CFStringRef AppleScrollBarType = CFSTR("AppleScrollBarVariant");
+ if( AppleScrollBarType )
+ {
+ CFStringRef ScrollBarVariant = ((CFStringRef)CFPreferencesCopyAppValue( AppleScrollBarType, kCFPreferencesCurrentApplication ));
+ if( ScrollBarVariant )
+ {
+ if( CFGetTypeID( ScrollBarVariant ) == CFStringGetTypeID() )
+ {
+ // TODO: check for the less important variants "DoubleMin" and "DoubleBoth" too
+ CFStringRef DoubleMax = CFSTR("DoubleMax");
+ if (DoubleMax)
+ {
+ if ( !CFStringCompare(ScrollBarVariant, DoubleMax, kCFCompareCaseInsensitive) )
+ bIsScrollbarDoubleMax = true;
+ else
+ bIsScrollbarDoubleMax = false;
+ CFRelease(DoubleMax);
+ }
+ }
+ CFRelease( ScrollBarVariant );
+ }
+ CFRelease(AppleScrollBarType);
+ }
+
+ GetSalData()->mbIsScrollbarDoubleMax = bIsScrollbarDoubleMax;
+
+ CFStringRef jumpScroll = CFSTR("AppleScrollerPagingBehavior");
+ if( jumpScroll )
+ {
+ CFBooleanRef jumpStr = ((CFBooleanRef)CFPreferencesCopyAppValue( jumpScroll, kCFPreferencesCurrentApplication ));
+ if( jumpStr )
+ {
+ if( CFGetTypeID( jumpStr ) == CFBooleanGetTypeID() )
+ ImplGetSVData()->maNWFData.mbScrollbarJumpPage = (jumpStr == kCFBooleanTrue);
+ CFRelease( jumpStr );
+ }
+ CFRelease( jumpScroll );
+ }
+}
+
+static Color getColor( NSColor* pSysColor, const Color& rDefault, NSWindow* pWin )
+{
+ Color aRet( rDefault );
+ if( pSysColor )
+ {
+ // transform to RGB
+ NSColor* pRBGColor = [pSysColor colorUsingColorSpaceName: NSDeviceRGBColorSpace device: [pWin deviceDescription]];
+ if( pRBGColor )
+ {
+ float r = 0, g = 0, b = 0, a = 0;
+ [pRBGColor getRed: &r green: &g blue: &b alpha: &a];
+ aRet = Color( int(r*255.999), int(g*255.999), int(b*255.999) );
+ /*
+ do not release here; leads to duplicate free in yield
+ it seems the converted color comes out autoreleased, although this
+ is not documented
+ [pRBGColor release];
+ */
+ }
+ }
+ return aRet;
+}
+
+static Font getFont( NSFont* pFont, long nDPIY, const Font& rDefault )
+{
+ Font aResult( rDefault );
+ if( pFont )
+ {
+ aResult.SetName( GetOUString( [pFont familyName] ) );
+ aResult.SetHeight( static_cast<int>(([pFont pointSize] * 72.0 / (float)nDPIY)+0.5) );
+ aResult.SetItalic( ([pFont italicAngle] != 0.0) ? ITALIC_NORMAL : ITALIC_NONE );
+ // FIMXE: bold ?
+ }
+
+ return aResult;
+}
+
+void AquaSalFrame::getResolution( long& o_rDPIX, long& o_rDPIY )
+{
+ if( ! mpGraphics )
+ {
+ GetGraphics();
+ ReleaseGraphics( mpGraphics );
+ }
+ mpGraphics->GetResolution( o_rDPIX, o_rDPIY );
+}
+
+// on OSX-Aqua the style settings are independent of the frame, so it does
+// not really belong here. Since the connection to the Appearance_Manager
+// is currently done in salnativewidgets.cxx this would be a good place.
+// On the other hand VCL's platform independent code currently only asks
+// SalFrames for system settings anyway, so moving the code somewhere else
+// doesn't make the anything cleaner for now
+void AquaSalFrame::UpdateSettings( AllSettings& rSettings )
+{
+ [mpView lockFocus];
+
+ StyleSettings aStyleSettings = rSettings.GetStyleSettings();
+
+ // Background Color
+ Color aBackgroundColor = Color( 0xEC, 0xEC, 0xEC );
+ aStyleSettings.Set3DColors( aBackgroundColor );
+ aStyleSettings.SetFaceColor( aBackgroundColor );
+ Color aInactiveTabColor( aBackgroundColor );
+ aInactiveTabColor.DecreaseLuminance( 32 );
+ aStyleSettings.SetInactiveTabColor( aInactiveTabColor );
+
+ aStyleSettings.SetDialogColor( aBackgroundColor );
+ aStyleSettings.SetLightBorderColor( aBackgroundColor );
+ Color aShadowColor( aStyleSettings.GetShadowColor() );
+ aStyleSettings.SetDarkShadowColor( aShadowColor );
+ aShadowColor.IncreaseLuminance( 32 );
+ aStyleSettings.SetShadowColor( aShadowColor );
+
+ // get the system font settings
+ Font aAppFont = aStyleSettings.GetAppFont();
+ long nDPIX = 72, nDPIY = 72;
+ getResolution( nDPIX, nDPIY );
+ aAppFont = getFont( [NSFont systemFontOfSize: 0], nDPIY, aAppFont );
+
+ // TODO: better mapping of aqua<->ooo font settings
+ aStyleSettings.SetAppFont( aAppFont );
+ aStyleSettings.SetHelpFont( aAppFont );
+ aStyleSettings.SetPushButtonFont( aAppFont );
+
+ Font aTitleFont( getFont( [NSFont titleBarFontOfSize: 0], nDPIY, aAppFont ) );
+ aStyleSettings.SetTitleFont( aTitleFont );
+ aStyleSettings.SetFloatTitleFont( aTitleFont );
+
+ Font aMenuFont( getFont( [NSFont menuFontOfSize: 0], nDPIY, aAppFont ) );
+ aStyleSettings.SetMenuFont( aMenuFont );
+
+ aStyleSettings.SetToolFont( aAppFont );
+
+ Font aLabelFont( getFont( [NSFont labelFontOfSize: 0], nDPIY, aAppFont ) );
+ aStyleSettings.SetLabelFont( aLabelFont );
+ aStyleSettings.SetInfoFont( aLabelFont );
+ aStyleSettings.SetRadioCheckFont( aLabelFont );
+ aStyleSettings.SetFieldFont( aLabelFont );
+ aStyleSettings.SetGroupFont( aLabelFont );
+ aStyleSettings.SetIconFont( aLabelFont );
+
+ Color aHighlightColor( getColor( [NSColor selectedTextBackgroundColor],
+ aStyleSettings.GetHighlightColor(), mpWindow ) );
+ aStyleSettings.SetHighlightColor( aHighlightColor );
+ Color aHighlightTextColor( getColor( [NSColor selectedTextColor],
+ aStyleSettings.GetHighlightTextColor(), mpWindow ) );
+ aStyleSettings.SetHighlightTextColor( aHighlightTextColor );
+
+ Color aMenuHighlightColor( getColor( [NSColor selectedMenuItemColor],
+ aStyleSettings.GetMenuHighlightColor(), mpWindow ) );
+ aStyleSettings.SetMenuHighlightColor( aMenuHighlightColor );
+ Color aMenuHighlightTextColor( getColor( [NSColor selectedMenuItemTextColor],
+ aStyleSettings.GetMenuHighlightTextColor(), mpWindow ) );
+ aStyleSettings.SetMenuHighlightTextColor( aMenuHighlightTextColor );
+
+ aStyleSettings.SetMenuColor( aBackgroundColor );
+ Color aMenuTextColor( getColor( [NSColor textColor],
+ aStyleSettings.GetMenuTextColor(), mpWindow ) );
+ aStyleSettings.SetMenuTextColor( aMenuTextColor );
+ aStyleSettings.SetMenuBarTextColor( aMenuTextColor );
+
+ aStyleSettings.SetCursorBlinkTime( 500 );
+
+ // no mnemonics on aqua
+ aStyleSettings.SetOptions( aStyleSettings.GetOptions() | STYLE_OPTION_NOMNEMONICS );
+
+ getAppleScrollBarVariant();
+
+ // set scrollbar size
+ aStyleSettings.SetScrollBarSize( static_cast<long int>([NSScroller scrollerWidth]) );
+
+ // images in menus false for MacOSX
+ aStyleSettings.SetUseImagesInMenus( false );
+
+ rSettings.SetStyleSettings( aStyleSettings );
+
+ [mpView unlockFocus];
+}
+
+// -----------------------------------------------------------------------
+
+const SystemEnvData* AquaSalFrame::GetSystemData() const
+{
+ return &maSysData;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::Beep( SoundType eSoundType )
+{
+ switch( eSoundType )
+ {
+ case SOUND_DISABLE:
+ // don't beep
+ break;
+ default:
+ NSBeep();
+ break;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::SetPosSize(long nX, long nY, long nWidth, long nHeight, USHORT nFlags)
+{
+ USHORT nEvent = 0;
+
+ if( [mpWindow isMiniaturized] )
+ [mpWindow deminiaturize: NSApp]; // expand the window
+
+ if (nFlags & (SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y))
+ {
+ mbPositioned = true;
+ nEvent = SALEVENT_MOVE;
+ }
+
+ if (nFlags & (SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT))
+ {
+ mbSized = true;
+ nEvent = (nEvent == SALEVENT_MOVE) ? SALEVENT_MOVERESIZE : SALEVENT_RESIZE;
+ }
+
+ NSRect aFrameRect = [mpWindow frame];
+ NSRect aContentRect = [NSWindow contentRectForFrameRect: aFrameRect styleMask: mnStyleMask];
+
+ // position is always relative to parent frame
+ NSRect aParentContentRect;
+
+ if( mpParent )
+ {
+ if( Application::GetSettings().GetLayoutRTL() )
+ {
+ if( (nFlags & SAL_FRAME_POSSIZE_WIDTH) != 0 )
+ nX = mpParent->maGeometry.nWidth - nWidth-1 - nX;
+ else
+ nX = mpParent->maGeometry.nWidth - static_cast<long int>( aContentRect.size.width-1) - nX;
+ }
+ NSRect aParentFrameRect = [mpParent->mpWindow frame];
+ aParentContentRect = [NSWindow contentRectForFrameRect: aParentFrameRect styleMask: mpParent->mnStyleMask];
+ }
+ else
+ aParentContentRect = maScreenRect; // use screen if no parent
+
+ CocoaToVCL( aContentRect );
+ CocoaToVCL( aParentContentRect );
+
+ bool bPaint = false;
+ if( (nFlags & (SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT)) != 0 )
+ {
+ if( nWidth != aContentRect.size.width || nHeight != aContentRect.size.height )
+ bPaint = true;
+ }
+
+ // use old window pos if no new pos requested
+ if( (nFlags & SAL_FRAME_POSSIZE_X) != 0 )
+ aContentRect.origin.x = nX + aParentContentRect.origin.x;
+ if( (nFlags & SAL_FRAME_POSSIZE_Y) != 0)
+ aContentRect.origin.y = nY + aParentContentRect.origin.y;
+
+ // use old size if no new size requested
+ if( (nFlags & SAL_FRAME_POSSIZE_WIDTH) != 0 )
+ aContentRect.size.width = nWidth;
+ if( (nFlags & SAL_FRAME_POSSIZE_HEIGHT) != 0)
+ aContentRect.size.height = nHeight;
+
+ VCLToCocoa( aContentRect );
+
+ // do not display yet, we need to update our backbuffer
+ {
+ //YieldMutexReleaser aRel;
+ [mpWindow setFrame: [NSWindow frameRectForContentRect: aContentRect styleMask: mnStyleMask] display: NO];
+ }
+
+ UpdateFrameGeometry();
+
+ if (nEvent)
+ CallCallback(nEvent, NULL);
+
+ if( mbShown && bPaint )
+ {
+ // trigger filling our backbuffer
+ SendPaintEvent();
+
+ // now inform the system that the views need to be drawn
+ //YieldMutexReleaser aRel;
+ [mpWindow display];
+ }
+}
+
+void AquaSalFrame::GetWorkArea( Rectangle& rRect )
+{
+ NSScreen* pScreen = [mpWindow screen];
+ if( pScreen == nil )
+ pScreen = [NSScreen mainScreen];
+ NSRect aRect = [pScreen visibleFrame];
+ CocoaToVCL( aRect );
+ rRect.nLeft = static_cast<long>(aRect.origin.x);
+ rRect.nTop = static_cast<long>(aRect.origin.y);
+ rRect.nRight = static_cast<long>(aRect.origin.x + aRect.size.width - 1);
+ rRect.nBottom = static_cast<long>(aRect.origin.y + aRect.size.height - 1);
+}
+
+SalPointerState AquaSalFrame::GetPointerState()
+{
+ SalPointerState state;
+ state.mnState = 0;
+
+ // get position
+ NSPoint aPt = [mpWindow mouseLocationOutsideOfEventStream];
+ CocoaToVCL( aPt, false );
+ state.maPos = Point(static_cast<long>(aPt.x), static_cast<long>(aPt.y));
+
+ NSEvent* pCur = [NSApp currentEvent];
+ bool bMouseEvent = false;
+ if( pCur )
+ {
+ bMouseEvent = true;
+ switch( [pCur type] )
+ {
+ case NSLeftMouseDown: state.mnState |= MOUSE_LEFT; break;
+ case NSLeftMouseUp: break;
+ case NSRightMouseDown: state.mnState |= MOUSE_RIGHT; break;
+ case NSRightMouseUp: break;
+ case NSOtherMouseDown: state.mnState |= ([pCur buttonNumber] == 2) ? MOUSE_MIDDLE : 0; break;
+ case NSOtherMouseUp: break;
+ case NSMouseMoved: break;
+ case NSLeftMouseDragged: state.mnState |= MOUSE_LEFT; break;
+ case NSRightMouseDragged: state.mnState |= MOUSE_RIGHT; break;
+ case NSOtherMouseDragged: state.mnState |= ([pCur buttonNumber] == 2) ? MOUSE_MIDDLE : 0; break;
+ break;
+ default:
+ bMouseEvent = false;
+ break;
+ }
+ }
+ if( bMouseEvent )
+ {
+ unsigned int nMask = (unsigned int)[pCur modifierFlags];
+ if( (nMask & NSShiftKeyMask) != 0 )
+ state.mnState |= KEY_SHIFT;
+ if( (nMask & NSControlKeyMask) != 0 )
+ state.mnState |= KEY_MOD3;
+ if( (nMask & NSAlternateKeyMask) != 0 )
+ state.mnState |= KEY_MOD2;
+ if( (nMask & NSCommandKeyMask) != 0 )
+ state.mnState |= KEY_MOD1;
+
+ }
+ else
+ {
+ // FIXME: replace Carbon by Cocoa
+ // Cocoa does not have an equivalent for GetCurrentEventButtonState
+ // and GetCurrentEventKeyModifiers.
+ // we could try to get away with tracking all events for modifierKeys
+ // and all mouse events for button state in VCL_NSApllication::sendEvent,
+ // but it is unclear whether this will get us the same result.
+ // leave in GetCurrentEventButtonState and GetCurrentEventKeyModifiers for now
+
+ // fill in button state
+ UInt32 nState = GetCurrentEventButtonState();
+ state.mnState = 0;
+ if( nState & 1 )
+ state.mnState |= MOUSE_LEFT; // primary button
+ if( nState & 2 )
+ state.mnState |= MOUSE_RIGHT; // secondary button
+ if( nState & 4 )
+ state.mnState |= MOUSE_MIDDLE; // tertiary button
+
+ // fill in modifier state
+ nState = GetCurrentEventKeyModifiers();
+ if( nState & shiftKey )
+ state.mnState |= KEY_SHIFT;
+ if( nState & controlKey )
+ state.mnState |= KEY_MOD3;
+ if( nState & optionKey )
+ state.mnState |= KEY_MOD2;
+ if( nState & cmdKey )
+ state.mnState |= KEY_MOD1;
+ }
+
+
+ return state;
+}
+
+bool AquaSalFrame::SetPluginParent( SystemParentData* pNewParent )
+{
+ // plugin parent may be killed unexpectedly by
+ // plugging process;
+
+ //TODO: implement
+ return sal_False;
+}
+
+BOOL AquaSalFrame::MapUnicodeToKeyCode( sal_Unicode , LanguageType , KeyCode& )
+{
+ // not supported yet
+ return FALSE;
+}
+
+LanguageType AquaSalFrame::GetInputLanguage()
+{
+ //TODO: implement
+ return LANGUAGE_DONTKNOW;
+}
+
+void AquaSalFrame::DrawMenuBar()
+{
+}
+
+void AquaSalFrame::SetMenu( SalMenu* pSalMenu )
+{
+ AquaSalMenu* pMenu = static_cast<AquaSalMenu*>(pSalMenu);
+ DBG_ASSERT( ! pMenu || pMenu->mbMenuBar, "setting non menubar on frame" );
+ mpMenu = pMenu;
+ if( mpMenu )
+ mpMenu->setMainMenu();
+}
+
+void AquaSalFrame::SetExtendedFrameStyle( SalExtStyle nStyle )
+{
+ if( (mnExtStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) != (nStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) )
+ [mpWindow setDocumentEdited: (nStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) ? YES : NO];
+ mnExtStyle = nStyle;
+}
+
+void AquaSalFrame::SetBackgroundBitmap( SalBitmap* )
+{
+ //TODO: implement
+}
+
+SalBitmap* AquaSalFrame::SnapShot()
+{
+ return mpGraphics ? mpGraphics->getBitmap( 0, 0, maGeometry.nWidth, maGeometry.nHeight ) : NULL;
+}
+
+SalFrame* AquaSalFrame::GetParent() const
+{
+ return mpParent;
+}
+
+void AquaSalFrame::SetParent( SalFrame* pNewParent )
+{
+ bool bShown = mbShown;
+ // remove from child list
+ Show( FALSE );
+ mpParent = (AquaSalFrame*)pNewParent;
+ // insert to correct parent and paint
+ Show( bShown );
+}
+
+void AquaSalFrame::UpdateFrameGeometry()
+{
+ // keep in mind that view and window coordinates are lower left
+ // whereas vcl's are upper left
+
+ // update screen rect
+ NSScreen * pScreen = [mpWindow screen];
+ if( pScreen )
+ {
+ maScreenRect = [pScreen frame];
+ NSArray* pScreens = [NSScreen screens];
+ if( pScreens )
+ maGeometry.nScreenNumber = [pScreens indexOfObject: pScreen];
+ }
+
+ NSRect aFrameRect = [mpWindow frame];
+ NSRect aContentRect = [NSWindow contentRectForFrameRect: aFrameRect styleMask: mnStyleMask];
+
+ // release old track rect
+ [mpView removeTrackingRect: mnTrackingRectTag];
+ // install the new track rect
+ NSRect aTrackRect = { { 0, 0 }, aContentRect.size };
+ mnTrackingRectTag = [mpView addTrackingRect: aTrackRect owner: mpView userData: nil assumeInside: NO];
+
+ // convert to vcl convention
+ CocoaToVCL( aFrameRect );
+ CocoaToVCL( aContentRect );
+
+ maGeometry.nX = static_cast<int>(aContentRect.origin.x);
+ maGeometry.nY = static_cast<int>(aContentRect.origin.y);
+
+ maGeometry.nLeftDecoration = static_cast<unsigned int>(aContentRect.origin.x - aFrameRect.origin.x);
+ maGeometry.nRightDecoration = static_cast<unsigned int>((aFrameRect.origin.x + aFrameRect.size.width) -
+ (aContentRect.origin.x + aContentRect.size.width));
+
+ maGeometry.nTopDecoration = static_cast<unsigned int>(aContentRect.origin.y - aFrameRect.origin.y);
+ maGeometry.nBottomDecoration = static_cast<unsigned int>((aFrameRect.origin.y + aFrameRect.size.height) -
+ (aContentRect.origin.y + aContentRect.size.height));
+
+ maGeometry.nWidth = static_cast<unsigned int>(aContentRect.size.width);
+ maGeometry.nHeight = static_cast<unsigned int>(aContentRect.size.height);
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalFrame::CaptureMouse( BOOL bCapture )
+{
+ /* Remark:
+ we'll try to use a pidgin version of capture mouse
+ on MacOSX (neither carbon nor cocoa) there is a
+ CaptureMouse equivalent (in Carbon there is TrackMouseLocation
+ but this is useless to use since it is blocking)
+
+ However on cocoa the active frame seems to get mouse events
+ also outside the window, so we'll try to forward mouse events
+ to the capture frame in the hope that one of our frames
+ gets a mouse event.
+
+ This will break as soon as the user activates another app, but
+ a mouse click will normally lead to a release of the mouse anyway.
+
+ Let's see how far we get this way. Alternatively we could use one
+ large overlay window like we did for the carbon implementation,
+ however that is resource intensive.
+ */
+
+ if( bCapture )
+ s_pCaptureFrame = this;
+ else if( ! bCapture && s_pCaptureFrame == this )
+ s_pCaptureFrame = NULL;
+}
+
+void AquaSalFrame::ResetClipRegion()
+{
+ // release old path and indicate no clipping
+ CGPathRelease( mrClippingPath );
+ mrClippingPath = NULL;
+
+ if( mpView && mbShown )
+ [mpView setNeedsDisplay: YES];
+ if( mpWindow )
+ {
+ [mpWindow setOpaque: YES];
+ [mpWindow invalidateShadow];
+ }
+}
+
+void AquaSalFrame::BeginSetClipRegion( ULONG nRects )
+{
+ // release old path
+ if( mrClippingPath )
+ {
+ CGPathRelease( mrClippingPath );
+ mrClippingPath = NULL;
+ }
+
+ if( maClippingRects.size() > SAL_CLIPRECT_COUNT && nRects < maClippingRects.size() )
+ {
+ std::vector<CGRect> aEmptyVec;
+ maClippingRects.swap( aEmptyVec );
+ }
+ maClippingRects.clear();
+ maClippingRects.reserve( nRects );
+}
+
+void AquaSalFrame::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
+{
+ if( nWidth && nHeight )
+ {
+ NSRect aRect = { { nX, nY }, { nWidth, nHeight } };
+ VCLToCocoa( aRect, false );
+ maClippingRects.push_back( CGRectMake(aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height) );
+ }
+}
+
+void AquaSalFrame::EndSetClipRegion()
+{
+ if( ! maClippingRects.empty() )
+ {
+ mrClippingPath = CGPathCreateMutable();
+ CGPathAddRects( mrClippingPath, NULL, &maClippingRects[0], maClippingRects.size() );
+ }
+ if( mpView && mbShown )
+ [mpView setNeedsDisplay: YES];
+ if( mpWindow )
+ {
+ [mpWindow setOpaque: (mrClippingPath != NULL) ? NO : YES];
+ [mpWindow setBackgroundColor: [NSColor clearColor]];
+ // shadow is invalidated when view gets drawn again
+ }
+}
+
diff --git a/vcl/aqua/source/window/salframeview.mm b/vcl/aqua/source/window/salframeview.mm
new file mode 100755
index 000000000000..25dadf0e592b
--- /dev/null
+++ b/vcl/aqua/source/window/salframeview.mm
@@ -0,0 +1,1609 @@
+/*n***********************************************************************
+ *
+ * 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 "salinst.h"
+#include "salgdi.h"
+#include "salframe.h"
+#include "salframeview.h"
+#include "aqua11yfactory.h"
+#include <sal/alloca.h>
+#include "vcl/window.hxx"
+
+#include "vcl/svapp.hxx"
+
+#define WHEEL_EVENT_FACTOR 1.5
+
+static USHORT ImplGetModifierMask( unsigned int nMask )
+{
+ USHORT nRet = 0;
+ if( (nMask & NSShiftKeyMask) != 0 )
+ nRet |= KEY_SHIFT;
+ if( (nMask & NSControlKeyMask) != 0 )
+ nRet |= KEY_MOD3;
+ if( (nMask & NSAlternateKeyMask) != 0 )
+ nRet |= KEY_MOD2;
+ if( (nMask & NSCommandKeyMask) != 0 )
+ nRet |= KEY_MOD1;
+ return nRet;
+}
+
+static USHORT ImplMapCharCode( sal_Unicode aCode )
+{
+ static USHORT aKeyCodeMap[ 128 ] =
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ KEY_BACKSPACE, KEY_TAB, KEY_RETURN, 0, 0, KEY_RETURN, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, KEY_TAB, 0, KEY_ESCAPE, 0, 0, 0, 0,
+ KEY_SPACE, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, KEY_MULTIPLY, KEY_ADD, KEY_COMMA, KEY_SUBTRACT, KEY_POINT, KEY_DIVIDE,
+ KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7,
+ KEY_8, KEY_9, 0, 0, KEY_LESS, KEY_EQUAL, KEY_GREATER, 0,
+ 0, KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G,
+ KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, KEY_M, KEY_N, KEY_O,
+ KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, KEY_V, KEY_W,
+ KEY_X, KEY_Y, KEY_Z, 0, 0, 0, 0, 0,
+ KEY_QUOTELEFT, KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G,
+ KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, KEY_M, KEY_N, KEY_O,
+ KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, KEY_V, KEY_W,
+ KEY_X, KEY_Y, KEY_Z, 0, 0, 0, KEY_TILDE, KEY_BACKSPACE
+ };
+
+ // Note: the mapping 0x7f should by rights be KEY_DELETE
+ // however if you press "backspace" 0x7f is reported
+ // whereas for "delete" 0xf728 gets reported
+
+ // Note: the mapping of 0x19 to KEY_TAB is because for unknown reasons
+ // tab alone is reported as 0x09 (as expected) but shift-tab is
+ // reported as 0x19 (end of medium)
+
+ static USHORT aFunctionKeyCodeMap[ 128 ] =
+ {
+ KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_F1, KEY_F2, KEY_F3, KEY_F4,
+ KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12,
+ KEY_F13, KEY_F14, KEY_F15, KEY_F16, KEY_F17, KEY_F18, KEY_F19, KEY_F20,
+ KEY_F21, KEY_F22, KEY_F23, KEY_F24, KEY_F25, KEY_F26, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, KEY_INSERT,
+ KEY_DELETE, KEY_HOME, 0, KEY_END, KEY_PAGEUP, KEY_PAGEDOWN, 0, 0,
+ 0, 0, 0, 0, 0, KEY_MENU, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, KEY_UNDO, KEY_REPEAT, KEY_FIND, KEY_HELP, 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, 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, 0, 0, 0, 0, 0
+ };
+
+ USHORT nKeyCode = 0;
+ if( aCode < sizeof( aKeyCodeMap) / sizeof( aKeyCodeMap[0] ) )
+ nKeyCode = aKeyCodeMap[ aCode ];
+ else if( aCode >= 0xf700 && aCode < 0xf780 )
+ nKeyCode = aFunctionKeyCodeMap[ aCode - 0xf700 ];
+ return nKeyCode;
+}
+
+// store the frame the mouse last entered
+static AquaSalFrame* s_pMouseFrame = NULL;
+// store the last pressed button for enter/exit events
+// which lack that information
+static USHORT s_nLastButton = 0;
+
+// combinations of keys we need to handle ourselves
+static const struct ExceptionalKey
+{
+ const USHORT nKeyCode;
+ const unsigned int nModifierMask;
+} aExceptionalKeys[] =
+{
+ { KEY_D, NSControlKeyMask | NSShiftKeyMask | NSAlternateKeyMask },
+ { KEY_D, NSCommandKeyMask | NSShiftKeyMask | NSAlternateKeyMask }
+};
+
+static AquaSalFrame* getMouseContainerFrame()
+{
+ int nWindows = 0;
+ NSCountWindows( &nWindows );
+ int* pWindows = (int*)alloca( nWindows * sizeof(int) );
+ // note: NSWindowList is supposed to be in z-order front to back
+ NSWindowList( nWindows, pWindows );
+ AquaSalFrame* pDispatchFrame = NULL;
+ for(int i = 0; i < nWindows && ! pDispatchFrame; i++ )
+ {
+ NSWindow* pWin = [NSApp windowWithWindowNumber: pWindows[i]];
+ if( pWin && [pWin isMemberOfClass: [SalFrameWindow class]] && [(SalFrameWindow*)pWin containsMouse] )
+ pDispatchFrame = [(SalFrameWindow*)pWin getSalFrame];
+ }
+ return pDispatchFrame;
+}
+
+@implementation SalFrameWindow
+-(id)initWithSalFrame: (AquaSalFrame*)pFrame
+{
+ mDraggingDestinationHandler = nil;
+ mpFrame = pFrame;
+ NSRect aRect = { { pFrame->maGeometry.nX, pFrame->maGeometry.nY },
+ { pFrame->maGeometry.nWidth, pFrame->maGeometry.nHeight } };
+ pFrame->VCLToCocoa( aRect );
+ return [super initWithContentRect: aRect styleMask: mpFrame->getStyleMask() backing: NSBackingStoreBuffered defer: NO ];
+}
+
+-(AquaSalFrame*)getSalFrame
+{
+ return mpFrame;
+}
+
+-(MacOSBOOL)containsMouse
+{
+ // is this event actually inside that NSWindow ?
+ NSPoint aPt = [NSEvent mouseLocation];
+ NSRect aFrameRect = [self frame];
+ MacOSBOOL bInRect = NSPointInRect( aPt, aFrameRect );
+ return bInRect;
+}
+
+-(MacOSBOOL)canBecomeKeyWindow
+{
+ if( (mpFrame->mnStyle &
+ ( SAL_FRAME_STYLE_FLOAT |
+ SAL_FRAME_STYLE_TOOLTIP |
+ SAL_FRAME_STYLE_INTRO
+ )) == 0 )
+ return YES;
+ if( (mpFrame->mnStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) != 0 )
+ return YES;
+ if( mpFrame->mbFullScreen )
+ return YES;
+ if( (mpFrame->mnStyle & SAL_FRAME_STYLE_FLOAT_FOCUSABLE) )
+ return YES;
+ return [super canBecomeKeyWindow];
+}
+
+-(void)windowDidBecomeKey: (NSNotification*)pNotification
+{
+ YIELD_GUARD;
+
+ if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
+ {
+ static const ULONG nGuessDocument = SAL_FRAME_STYLE_MOVEABLE|
+ SAL_FRAME_STYLE_SIZEABLE|
+ SAL_FRAME_STYLE_CLOSEABLE;
+
+ if( mpFrame->mpMenu )
+ mpFrame->mpMenu->setMainMenu();
+ else if( ! mpFrame->mpParent &&
+ ( (mpFrame->mnStyle & nGuessDocument) == nGuessDocument || // set default menu for e.g. help
+ mpFrame->mbFullScreen ) ) // ser default menu for e.g. presentation
+ {
+ AquaSalMenu::setDefaultMenu();
+ }
+ #if 0
+ // FIXME: we should disable menus while in modal mode
+ // however from down here there is currently no reliable way to
+ // find out when to do this
+ if( (mpFrame->mpParent && mpFrame->mpParent->GetWindow()->IsInModalMode()) )
+ AquaSalMenu::enableMainMenu( false );
+ #endif
+ mpFrame->CallCallback( SALEVENT_GETFOCUS, 0 );
+ mpFrame->SendPaintEvent(); // repaint controls as active
+ }
+}
+
+-(void)windowDidResignKey: (NSNotification*)pNotification
+{
+ YIELD_GUARD;
+
+ if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
+ {
+ mpFrame->CallCallback(SALEVENT_LOSEFOCUS, 0);
+ mpFrame->SendPaintEvent(); // repaint controls as inactive
+ }
+}
+
+-(void)windowDidChangeScreen: (NSNotification*)pNotification
+{
+ YIELD_GUARD;
+
+ if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
+ mpFrame->screenParametersChanged();
+}
+
+-(void)windowDidMove: (NSNotification*)pNotification
+{
+ YIELD_GUARD;
+
+ if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
+ {
+ mpFrame->UpdateFrameGeometry();
+ mpFrame->CallCallback( SALEVENT_MOVE, 0 );
+ }
+}
+
+-(void)windowDidResize: (NSNotification*)pNotification
+{
+ YIELD_GUARD;
+
+ if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
+ {
+ mpFrame->UpdateFrameGeometry();
+ mpFrame->CallCallback( SALEVENT_RESIZE, 0 );
+ mpFrame->SendPaintEvent();
+ }
+}
+
+-(void)windowDidMiniaturize: (NSNotification*)pNotification
+{
+ YIELD_GUARD;
+
+ if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
+ {
+ mpFrame->mbShown = false;
+ mpFrame->UpdateFrameGeometry();
+ mpFrame->CallCallback( SALEVENT_RESIZE, 0 );
+ }
+}
+
+-(void)windowDidDeminiaturize: (NSNotification*)pNotification
+{
+ YIELD_GUARD;
+
+ if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
+ {
+ mpFrame->mbShown = true;
+ mpFrame->UpdateFrameGeometry();
+ mpFrame->CallCallback( SALEVENT_RESIZE, 0 );
+ }
+}
+
+-(MacOSBOOL)windowShouldClose: (NSNotification*)pNotification
+{
+ YIELD_GUARD;
+
+ MacOSBOOL bRet = YES;
+ if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
+ {
+ // #i84461# end possible input
+ mpFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, 0 );
+ if( AquaSalFrame::isAlive( mpFrame ) )
+ {
+ mpFrame->CallCallback( SALEVENT_CLOSE, 0 );
+ bRet = NO; // application will close the window or not, AppKit shouldn't
+ }
+ }
+
+ return bRet;
+}
+
+-(void)dockMenuItemTriggered: (id)sender
+{
+ YIELD_GUARD;
+
+ if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
+ mpFrame->ToTop( SAL_FRAME_TOTOP_RESTOREWHENMIN | SAL_FRAME_TOTOP_GRABFOCUS );
+}
+
+-(::com::sun::star::uno::Reference < ::com::sun::star::accessibility::XAccessibleContext >)accessibleContext
+{
+ return mpFrame -> GetWindow() -> GetAccessible() -> getAccessibleContext();
+}
+
+-(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
+{
+ return [mDraggingDestinationHandler draggingEntered: sender];
+}
+
+-(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
+{
+ return [mDraggingDestinationHandler draggingUpdated: sender];
+}
+
+-(void)draggingExited:(id <NSDraggingInfo>)sender
+{
+ [mDraggingDestinationHandler draggingExited: sender];
+}
+
+-(MacOSBOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
+{
+ return [mDraggingDestinationHandler prepareForDragOperation: sender];
+}
+
+-(MacOSBOOL)performDragOperation:(id <NSDraggingInfo>)sender
+{
+ return [mDraggingDestinationHandler performDragOperation: sender];
+}
+
+-(void)concludeDragOperation:(id <NSDraggingInfo>)sender
+{
+ [mDraggingDestinationHandler concludeDragOperation: sender];
+}
+
+-(void)registerDraggingDestinationHandler:(id)theHandler
+{
+ mDraggingDestinationHandler = theHandler;
+}
+
+-(void)unregisterDraggingDestinationHandler:(id)theHandler
+{
+ mDraggingDestinationHandler = nil;
+}
+
+@end
+
+@implementation SalFrameView
++(void)unsetMouseFrame: (AquaSalFrame*)pFrame
+{
+ if( pFrame == s_pMouseFrame )
+ s_pMouseFrame = NULL;
+}
+
+-(id)initWithSalFrame: (AquaSalFrame*)pFrame
+{
+ if ((self = [super initWithFrame: [NSWindow contentRectForFrameRect: [pFrame->getWindow() frame] styleMask: pFrame->mnStyleMask]]) != nil)
+ {
+ mDraggingDestinationHandler = nil;
+ mpFrame = pFrame;
+ mMarkedRange = NSMakeRange(NSNotFound, 0);
+ mSelectedRange = NSMakeRange(NSNotFound, 0);
+ mpReferenceWrapper = nil;
+ mpMouseEventListener = nil;
+ mpLastSuperEvent = nil;
+ }
+
+ return self;
+}
+
+-(void)resetCursorRects
+{
+ if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
+ {
+ // FIXME: does this leak the returned NSCursor of getCurrentCursor ?
+ NSRect aRect = { { 0, 0 }, { mpFrame->maGeometry.nWidth, mpFrame->maGeometry.nHeight } };
+ [self addCursorRect: aRect cursor: mpFrame->getCurrentCursor()];
+ }
+}
+
+-(MacOSBOOL)acceptsFirstResponder
+{
+ return YES;
+}
+
+-(MacOSBOOL)acceptsFirstMouse: (NSEvent*)pEvent
+{
+ return YES;
+}
+
+-(MacOSBOOL)isOpaque
+{
+ return mpFrame ? (mpFrame->getClipPath() != 0 ? NO : YES) : YES;
+}
+
+// helper class similar to a vos::OGuard for the SalYieldMutex
+// the difference is that it only does tryToAcquire instead of aquire
+// so dreaded deadlocks like #i93512# are prevented
+class TryGuard
+{
+public:
+ TryGuard() { mbGuarded = ImplSalYieldMutexTryToAcquire(); }
+ ~TryGuard() { if( mbGuarded ) ImplSalYieldMutexRelease(); }
+ bool IsGuarded() { return mbGuarded; }
+private:
+ bool mbGuarded;
+};
+
+-(void)drawRect: (NSRect)aRect
+{
+ // HOTFIX: #i93512# prevent deadlocks if any other thread already has the SalYieldMutex
+ TryGuard aTryGuard;
+ if( !aTryGuard.IsGuarded() )
+ {
+ // NOTE: the mpFrame access below is not guarded yet!
+ // TODO: mpFrame et al need to be guarded by an independent mutex
+ AquaSalGraphics* pGraphics = (mpFrame && AquaSalFrame::isAlive(mpFrame)) ? mpFrame->mpGraphics : NULL;
+ if( pGraphics )
+ {
+ // we did not get the mutex so we cannot draw now => request to redraw later
+ // convert the NSRect to a CGRect for Refreshrect()
+ const CGRect aCGRect = {{aRect.origin.x,aRect.origin.y},{aRect.size.width,aRect.size.height}};
+ pGraphics->RefreshRect( aCGRect );
+ }
+ return;
+ }
+
+ if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
+ {
+ if( mpFrame->mpGraphics )
+ {
+ mpFrame->mpGraphics->UpdateWindow( aRect );
+ if( mpFrame->getClipPath() )
+ [mpFrame->getWindow() invalidateShadow];
+ }
+ }
+}
+
+-(void)sendMouseEventToFrame: (NSEvent*)pEvent button:(USHORT)nButton eventtype:(USHORT)nEvent
+{
+ YIELD_GUARD;
+
+ AquaSalFrame* pDispatchFrame = AquaSalFrame::GetCaptureFrame();
+ bool bIsCaptured = false;
+ if( pDispatchFrame )
+ {
+ bIsCaptured = true;
+ if( nEvent == SALEVENT_MOUSELEAVE ) // no leave events if mouse is captured
+ nEvent = SALEVENT_MOUSEMOVE;
+ }
+ else if( s_pMouseFrame )
+ pDispatchFrame = s_pMouseFrame;
+ else
+ pDispatchFrame = mpFrame;
+
+ /* #i81645# Cocoa reports mouse events while a button is pressed
+ to the window in which it was first pressed. This is reasonable and fine and
+ gets one around most cases where on other platforms one uses CaptureMouse or XGrabPointer,
+ however vcl expects mouse events to occur in the window the mouse is over, unless the
+ mouse is explicitly captured. So we need to find the window the mouse is actually
+ over for conformance with other platforms.
+ */
+ if( ! bIsCaptured && nButton && pDispatchFrame && AquaSalFrame::isAlive( pDispatchFrame ) )
+ {
+ // is this event actually inside that NSWindow ?
+ NSPoint aPt = [NSEvent mouseLocation];
+ NSRect aFrameRect = [pDispatchFrame->getWindow() frame];
+
+ if ( ! NSPointInRect( aPt, aFrameRect ) )
+ {
+ // no, it is not
+ // now we need to find the one it may be in
+ /* #i93756# we ant to get enumerate the application windows in z-order
+ to check if any contains the mouse. This could be elegantly done with this
+ code:
+
+ // use NSApp to check windows in ZOrder whether they contain the mouse pointer
+ NSWindow* pWindow = [NSApp makeWindowsPerform: @selector(containsMouse) inOrder: YES];
+ if( pWindow && [pWindow isMemberOfClass: [SalFrameWindow class]] )
+ pDispatchFrame = [(SalFrameWindow*)pWindow getSalFrame];
+
+ However if a non SalFrameWindow is on screen (like e.g. the file dialog)
+ it can be hit with the containsMouse selector, which it doesn't support.
+ Sadly NSApplication:makeWindowsPerform does not check (for performance reasons
+ I assume) whether a window supports a selector before sending it.
+ */
+ AquaSalFrame* pMouseFrame = getMouseContainerFrame();
+ if( pMouseFrame )
+ pDispatchFrame = pMouseFrame;
+ }
+ }
+
+ if( pDispatchFrame && AquaSalFrame::isAlive( pDispatchFrame ) )
+ {
+ pDispatchFrame->mnLastEventTime = static_cast<ULONG>( [pEvent timestamp] * 1000.0 );
+ pDispatchFrame->mnLastModifierFlags = [pEvent modifierFlags];
+
+ NSPoint aPt = [NSEvent mouseLocation];
+ pDispatchFrame->CocoaToVCL( aPt );
+
+ USHORT nModMask = ImplGetModifierMask( [pEvent modifierFlags] );
+ // #i82284# emulate ctrl left
+ if( nModMask == KEY_MOD3 && nButton == MOUSE_LEFT )
+ {
+ nModMask = 0;
+ nButton = MOUSE_RIGHT;
+ }
+
+ SalMouseEvent aEvent;
+ aEvent.mnTime = pDispatchFrame->mnLastEventTime;
+ aEvent.mnX = static_cast<long>(aPt.x) - pDispatchFrame->maGeometry.nX;
+ aEvent.mnY = static_cast<long>(aPt.y) - pDispatchFrame->maGeometry.nY;
+ aEvent.mnButton = nButton;
+ aEvent.mnCode = aEvent.mnButton | nModMask;
+
+ // --- RTL --- (mirror mouse pos)
+ if( Application::GetSettings().GetLayoutRTL() )
+ aEvent.mnX = pDispatchFrame->maGeometry.nWidth-1-aEvent.mnX;
+
+ pDispatchFrame->CallCallback( nEvent, &aEvent );
+ }
+}
+
+-(void)mouseDown: (NSEvent*)pEvent
+{
+ if ( mpMouseEventListener != nil &&
+ [mpMouseEventListener respondsToSelector: @selector(mouseDown:)])
+ {
+ [mpMouseEventListener mouseDown: [pEvent copyWithZone: NULL]];
+ }
+
+ s_nLastButton = MOUSE_LEFT;
+ [self sendMouseEventToFrame:pEvent button:MOUSE_LEFT eventtype:SALEVENT_MOUSEBUTTONDOWN];
+}
+
+-(void)mouseDragged: (NSEvent*)pEvent
+{
+ if ( mpMouseEventListener != nil &&
+ [mpMouseEventListener respondsToSelector: @selector(mouseDragged:)])
+ {
+ [mpMouseEventListener mouseDragged: [pEvent copyWithZone: NULL]];
+ }
+ s_nLastButton = MOUSE_LEFT;
+ [self sendMouseEventToFrame:pEvent button:MOUSE_LEFT eventtype:SALEVENT_MOUSEMOVE];
+}
+
+-(void)mouseUp: (NSEvent*)pEvent
+{
+ s_nLastButton = 0;
+ [self sendMouseEventToFrame:pEvent button:MOUSE_LEFT eventtype:SALEVENT_MOUSEBUTTONUP];
+}
+
+-(void)mouseMoved: (NSEvent*)pEvent
+{
+ s_nLastButton = 0;
+ [self sendMouseEventToFrame:pEvent button:0 eventtype:SALEVENT_MOUSEMOVE];
+}
+
+-(void)mouseEntered: (NSEvent*)pEvent
+{
+ s_pMouseFrame = mpFrame;
+
+ [self sendMouseEventToFrame:pEvent button:s_nLastButton eventtype:SALEVENT_MOUSEMOVE];
+}
+
+-(void)mouseExited: (NSEvent*)pEvent
+{
+ if( s_pMouseFrame == mpFrame )
+ s_pMouseFrame = NULL;
+
+ [self sendMouseEventToFrame:pEvent button:s_nLastButton eventtype:SALEVENT_MOUSELEAVE];
+}
+
+-(void)rightMouseDown: (NSEvent*)pEvent
+{
+ s_nLastButton = MOUSE_RIGHT;
+ [self sendMouseEventToFrame:pEvent button:MOUSE_RIGHT eventtype:SALEVENT_MOUSEBUTTONDOWN];
+}
+
+-(void)rightMouseDragged: (NSEvent*)pEvent
+{
+ s_nLastButton = MOUSE_RIGHT;
+ [self sendMouseEventToFrame:pEvent button:MOUSE_RIGHT eventtype:SALEVENT_MOUSEMOVE];
+}
+
+-(void)rightMouseUp: (NSEvent*)pEvent
+{
+ s_nLastButton = 0;
+ [self sendMouseEventToFrame:pEvent button:MOUSE_RIGHT eventtype:SALEVENT_MOUSEBUTTONUP];
+}
+
+-(void)otherMouseDown: (NSEvent*)pEvent
+{
+ if( [pEvent buttonNumber] == 2 )
+ {
+ s_nLastButton = MOUSE_MIDDLE;
+ [self sendMouseEventToFrame:pEvent button:MOUSE_MIDDLE eventtype:SALEVENT_MOUSEBUTTONDOWN];
+ }
+ else
+ s_nLastButton = 0;
+}
+
+-(void)otherMouseDragged: (NSEvent*)pEvent
+{
+ if( [pEvent buttonNumber] == 2 )
+ {
+ s_nLastButton = MOUSE_MIDDLE;
+ [self sendMouseEventToFrame:pEvent button:MOUSE_MIDDLE eventtype:SALEVENT_MOUSEMOVE];
+ }
+ else
+ s_nLastButton = 0;
+}
+
+-(void)otherMouseUp: (NSEvent*)pEvent
+{
+ s_nLastButton = 0;
+ if( [pEvent buttonNumber] == 2 )
+ [self sendMouseEventToFrame:pEvent button:MOUSE_MIDDLE eventtype:SALEVENT_MOUSEBUTTONUP];
+}
+
+- (void)magnifyWithEvent: (NSEvent*)pEvent
+{
+ YIELD_GUARD;
+
+ // TODO: ?? -(float)magnification;
+ if( AquaSalFrame::isAlive( mpFrame ) )
+ {
+ mpFrame->mnLastEventTime = static_cast<ULONG>( [pEvent timestamp] * 1000.0 );
+ mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
+
+ float dZ = 0.0;
+ for(;;)
+ {
+ dZ += [pEvent deltaZ];
+ NSEvent* pNextEvent = [NSApp nextEventMatchingMask: NSScrollWheelMask
+ untilDate: nil inMode: NSDefaultRunLoopMode dequeue: YES ];
+ if( !pNextEvent )
+ break;
+ pEvent = pNextEvent;
+ }
+
+ NSPoint aPt = [NSEvent mouseLocation];
+ mpFrame->CocoaToVCL( aPt );
+
+ SalWheelMouseEvent aEvent;
+ aEvent.mnTime = mpFrame->mnLastEventTime;
+ aEvent.mnX = static_cast<long>(aPt.x) - mpFrame->maGeometry.nX;
+ aEvent.mnY = static_cast<long>(aPt.y) - mpFrame->maGeometry.nY;
+ aEvent.mnCode = ImplGetModifierMask( mpFrame->mnLastModifierFlags );
+ aEvent.mnCode |= KEY_MOD1; // we want zooming, no scrolling
+ aEvent.mbDeltaIsPixel = TRUE;
+
+ // --- RTL --- (mirror mouse pos)
+ if( Application::GetSettings().GetLayoutRTL() )
+ aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX;
+
+ if( dZ != 0.0 )
+ {
+ aEvent.mnDelta = static_cast<long>(floor(dZ));
+ aEvent.mnNotchDelta = dZ < 0 ? -1 : 1;
+ if( aEvent.mnDelta == 0 )
+ aEvent.mnDelta = aEvent.mnNotchDelta;
+ aEvent.mbHorz = FALSE;
+ aEvent.mnScrollLines = dZ > 0 ? dZ/WHEEL_EVENT_FACTOR : -dZ/WHEEL_EVENT_FACTOR;
+ if( aEvent.mnScrollLines == 0 )
+ aEvent.mnScrollLines = 1;
+ mpFrame->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
+ }
+ }
+}
+
+- (void)rotateWithEvent: (NSEvent*)pEvent
+{
+ //Rotation : -(float)rotation;
+ // TODO: create new CommandType so rotation is available to the applications
+}
+
+- (void)swipeWithEvent: (NSEvent*)pEvent
+{
+ YIELD_GUARD;
+
+ if( AquaSalFrame::isAlive( mpFrame ) )
+ {
+ mpFrame->mnLastEventTime = static_cast<ULONG>( [pEvent timestamp] * 1000.0 );
+ mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
+
+ // merge pending scroll wheel events
+ float dX = 0.0;
+ float dY = 0.0;
+ for(;;)
+ {
+ dX += [pEvent deltaX];
+ dY += [pEvent deltaY];
+ NSEvent* pNextEvent = [NSApp nextEventMatchingMask: NSScrollWheelMask
+ untilDate: nil inMode: NSDefaultRunLoopMode dequeue: YES ];
+ if( !pNextEvent )
+ break;
+ pEvent = pNextEvent;
+ }
+
+ NSPoint aPt = [NSEvent mouseLocation];
+ mpFrame->CocoaToVCL( aPt );
+
+ SalWheelMouseEvent aEvent;
+ aEvent.mnTime = mpFrame->mnLastEventTime;
+ aEvent.mnX = static_cast<long>(aPt.x) - mpFrame->maGeometry.nX;
+ aEvent.mnY = static_cast<long>(aPt.y) - mpFrame->maGeometry.nY;
+ aEvent.mnCode = ImplGetModifierMask( mpFrame->mnLastModifierFlags );
+ aEvent.mbDeltaIsPixel = TRUE;
+
+ // --- RTL --- (mirror mouse pos)
+ if( Application::GetSettings().GetLayoutRTL() )
+ aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX;
+
+ if( dX != 0.0 )
+ {
+ aEvent.mnDelta = static_cast<long>(floor(dX));
+ aEvent.mnNotchDelta = dX < 0 ? -1 : 1;
+ if( aEvent.mnDelta == 0 )
+ aEvent.mnDelta = aEvent.mnNotchDelta;
+ aEvent.mbHorz = TRUE;
+ aEvent.mnScrollLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
+ mpFrame->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
+ }
+ if( dY != 0.0 && AquaSalFrame::isAlive( mpFrame ))
+ {
+ aEvent.mnDelta = static_cast<long>(floor(dY));
+ aEvent.mnNotchDelta = dY < 0 ? -1 : 1;
+ if( aEvent.mnDelta == 0 )
+ aEvent.mnDelta = aEvent.mnNotchDelta;
+ aEvent.mbHorz = FALSE;
+ aEvent.mnScrollLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
+ mpFrame->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
+ }
+ }
+}
+
+-(void)scrollWheel: (NSEvent*)pEvent
+{
+ YIELD_GUARD;
+
+ if( AquaSalFrame::isAlive( mpFrame ) )
+ {
+ mpFrame->mnLastEventTime = static_cast<ULONG>( [pEvent timestamp] * 1000.0 );
+ mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
+
+ // merge pending scroll wheel events
+ float dX = 0.0;
+ float dY = 0.0;
+ for(;;)
+ {
+ dX += [pEvent deltaX];
+ dY += [pEvent deltaY];
+ NSEvent* pNextEvent = [NSApp nextEventMatchingMask: NSScrollWheelMask
+ untilDate: nil inMode: NSDefaultRunLoopMode dequeue: YES ];
+ if( !pNextEvent )
+ break;
+ pEvent = pNextEvent;
+ }
+
+ NSPoint aPt = [NSEvent mouseLocation];
+ mpFrame->CocoaToVCL( aPt );
+
+ SalWheelMouseEvent aEvent;
+ aEvent.mnTime = mpFrame->mnLastEventTime;
+ aEvent.mnX = static_cast<long>(aPt.x) - mpFrame->maGeometry.nX;
+ aEvent.mnY = static_cast<long>(aPt.y) - mpFrame->maGeometry.nY;
+ aEvent.mnCode = ImplGetModifierMask( mpFrame->mnLastModifierFlags );
+ aEvent.mbDeltaIsPixel = TRUE;
+
+ // --- RTL --- (mirror mouse pos)
+ if( Application::GetSettings().GetLayoutRTL() )
+ aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX;
+
+ if( dX != 0.0 )
+ {
+ aEvent.mnDelta = static_cast<long>(floor(dX));
+ aEvent.mnNotchDelta = dX < 0 ? -1 : 1;
+ if( aEvent.mnDelta == 0 )
+ aEvent.mnDelta = aEvent.mnNotchDelta;
+ aEvent.mbHorz = TRUE;
+ aEvent.mnScrollLines = dY > 0 ? dX/WHEEL_EVENT_FACTOR : -dX/WHEEL_EVENT_FACTOR;
+ if( aEvent.mnScrollLines == 0 )
+ aEvent.mnScrollLines = 1;
+
+ mpFrame->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
+ }
+ if( dY != 0.0 && AquaSalFrame::isAlive( mpFrame ) )
+ {
+ aEvent.mnDelta = static_cast<long>(floor(dY));
+ aEvent.mnNotchDelta = dY < 0 ? -1 : 1;
+ if( aEvent.mnDelta == 0 )
+ aEvent.mnDelta = aEvent.mnNotchDelta;
+ aEvent.mbHorz = FALSE;
+ aEvent.mnScrollLines = dY > 0 ? dY/WHEEL_EVENT_FACTOR : -dY/WHEEL_EVENT_FACTOR;
+ if( aEvent.mnScrollLines < 1 )
+ aEvent.mnScrollLines = 1;
+
+ mpFrame->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
+ }
+ }
+}
+
+
+-(void)keyDown: (NSEvent*)pEvent
+{
+ YIELD_GUARD;
+
+ if( AquaSalFrame::isAlive( mpFrame ) )
+ {
+ mpLastEvent = pEvent;
+ mbInKeyInput = true;
+ mbNeedSpecialKeyHandle = false;
+ mbKeyHandled = false;
+
+ mpFrame->mnLastEventTime = static_cast<ULONG>( [pEvent timestamp] * 1000.0 );
+ mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
+
+ if( ! [self handleKeyDownException: pEvent] )
+ {
+ NSArray* pArray = [NSArray arrayWithObject: pEvent];
+ [self interpretKeyEvents: pArray];
+ }
+
+ mbInKeyInput = false;
+ }
+}
+
+-(MacOSBOOL)handleKeyDownException:(NSEvent*)pEvent
+{
+ // check for a very special set of modified characters
+ NSString* pUnmodifiedString = [pEvent charactersIgnoringModifiers];
+
+ if( pUnmodifiedString && [pUnmodifiedString length] == 1 )
+ {
+ /* #i103102# key events with command and alternate don't make it through
+ interpretKeyEvents (why ?). Try to dispatch them here first,
+ if not successful continue normally
+ */
+ if( (mpFrame->mnLastModifierFlags & (NSAlternateKeyMask | NSCommandKeyMask))
+ == (NSAlternateKeyMask | NSCommandKeyMask) )
+ {
+ if( [self sendSingleCharacter: mpLastEvent] )
+ return YES;
+ }
+ unichar keyChar = [pUnmodifiedString characterAtIndex: 0];
+ USHORT nKeyCode = ImplMapCharCode( keyChar );
+
+ // Caution: should the table grow to more than 5 or 6 entries,
+ // we must consider moving it to a kind of hash map
+ const unsigned int nExceptions = sizeof( aExceptionalKeys ) / sizeof( aExceptionalKeys[0] );
+ for( unsigned int i = 0; i < nExceptions; i++ )
+ {
+ if( nKeyCode == aExceptionalKeys[i].nKeyCode &&
+ (mpFrame->mnLastModifierFlags & aExceptionalKeys[i].nModifierMask)
+ == aExceptionalKeys[i].nModifierMask )
+ {
+ [self sendKeyInputAndReleaseToFrame: nKeyCode character: 0];
+
+ return YES;
+ }
+ }
+ }
+ return NO;
+}
+
+-(void)flagsChanged: (NSEvent*)pEvent
+{
+ YIELD_GUARD;
+
+ if( AquaSalFrame::isAlive( mpFrame ) )
+ {
+ mpFrame->mnLastEventTime = static_cast<ULONG>( [pEvent timestamp] * 1000.0 );
+ mpFrame->mnLastModifierFlags = [pEvent modifierFlags];
+ }
+}
+
+-(void)insertText:(id)aString
+{
+ YIELD_GUARD;
+
+ if( AquaSalFrame::isAlive( mpFrame ) )
+ {
+ NSString* pInsert = nil;
+ if( [aString isMemberOfClass: [NSAttributedString class]] )
+ pInsert = [aString string];
+ else
+ pInsert = aString;
+
+ int nLen = 0;
+ if( pInsert && ( nLen = [pInsert length] ) > 0 )
+ {
+ OUString aInsertString( GetOUString( pInsert ) );
+ // aCharCode initializer is safe since aInsertString will at least contain '\0'
+ sal_Unicode aCharCode = *aInsertString.getStr();
+
+ if( nLen == 1 &&
+ aCharCode < 0x80 &&
+ aCharCode > 0x1f &&
+ ! [self hasMarkedText ]
+ )
+ {
+ USHORT nKeyCode = ImplMapCharCode( aCharCode );
+ unsigned int nLastModifiers = mpFrame->mnLastModifierFlags;
+
+ // #i99567#
+ // find out the unmodified key code
+
+ // sanity check
+ if( mpLastEvent && ( [mpLastEvent type] == NSKeyDown || [mpLastEvent type] == NSKeyUp ) )
+ {
+ // get unmodified string
+ NSString* pUnmodifiedString = [mpLastEvent charactersIgnoringModifiers];
+ if( pUnmodifiedString && [pUnmodifiedString length] == 1 )
+ {
+ // map the unmodified key code
+ unichar keyChar = [pUnmodifiedString characterAtIndex: 0];
+ nKeyCode = ImplMapCharCode( keyChar );
+ }
+ nLastModifiers = [mpLastEvent modifierFlags];
+
+ }
+ // #i99567#
+ // applications and vcl's edit fields ignore key events with ALT
+ // however we're at a place where we know text should be inserted
+ // so it seems we need to strip the Alt modifier here
+ if( (nLastModifiers & (NSControlKeyMask | NSAlternateKeyMask | NSCommandKeyMask))
+ == NSAlternateKeyMask )
+ {
+ nLastModifiers = 0;
+ }
+ [self sendKeyInputAndReleaseToFrame: nKeyCode character: aCharCode modifiers: nLastModifiers];
+ }
+ else
+ {
+ SalExtTextInputEvent aEvent;
+ aEvent.mnTime = mpFrame->mnLastEventTime;
+ aEvent.maText = aInsertString;
+ aEvent.mpTextAttr = NULL;
+ aEvent.mnCursorPos = aInsertString.getLength();
+ aEvent.mnDeltaStart = 0;
+ aEvent.mnCursorFlags = 0;
+ aEvent.mbOnlyCursor = FALSE;
+ mpFrame->CallCallback( SALEVENT_EXTTEXTINPUT, &aEvent );
+ if( AquaSalFrame::isAlive( mpFrame ) )
+ mpFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, 0 );
+ }
+ }
+ else
+ {
+ SalExtTextInputEvent aEvent;
+ aEvent.mnTime = mpFrame->mnLastEventTime;
+ aEvent.maText = String();
+ aEvent.mpTextAttr = NULL;
+ aEvent.mnCursorPos = 0;
+ aEvent.mnDeltaStart = 0;
+ aEvent.mnCursorFlags = 0;
+ aEvent.mbOnlyCursor = FALSE;
+ mpFrame->CallCallback( SALEVENT_EXTTEXTINPUT, &aEvent );
+ if( AquaSalFrame::isAlive( mpFrame ) )
+ mpFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, 0 );
+
+ }
+ mbKeyHandled = true;
+ [self unmarkText];
+ }
+}
+
+-(void)insertTab: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: KEY_TAB character: '\t' modifiers: 0];
+}
+
+-(void)insertBacktab: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: (KEY_TAB | KEY_SHIFT) character: '\t' modifiers: 0];
+}
+
+-(void)moveLeft: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: KEY_LEFT character: 0 modifiers: 0];
+}
+
+-(void)moveLeftAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: KEY_LEFT character: 0 modifiers: NSShiftKeyMask];
+}
+
+-(void)moveBackwardAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_BACKWARD character: 0 modifiers: 0];
+}
+
+-(void)moveRight: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: KEY_RIGHT character: 0 modifiers: 0];
+}
+
+-(void)moveRightAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: KEY_RIGHT character: 0 modifiers: NSShiftKeyMask];
+}
+
+-(void)moveForwardAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_FORWARD character: 0 modifiers: 0];
+}
+
+-(void)moveWordLeft: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_WORD_BACKWARD character: 0 modifiers: 0];
+}
+
+-(void)moveWordBackward: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_WORD_BACKWARD character: 0 modifiers: 0];
+}
+
+-(void)moveWordBackwardAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_WORD_BACKWARD character: 0 modifiers: 0];
+}
+
+-(void)moveWordLeftAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_WORD_BACKWARD character: 0 modifiers: 0];
+}
+
+-(void)moveWordRight: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_WORD_FORWARD character: 0 modifiers: 0];
+}
+
+-(void)moveWordForward: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_WORD_FORWARD character: 0 modifiers: 0];
+}
+
+-(void)moveWordForwardAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_WORD_FORWARD character: 0 modifiers: 0];
+}
+
+-(void)moveWordRightAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_WORD_FORWARD character: 0 modifiers: 0];
+}
+
+-(void)moveToEndOfLine: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_END_OF_LINE character: 0 modifiers: 0];
+}
+
+-(void)moveToRightEndOfLine: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_END_OF_LINE character: 0 modifiers: 0];
+}
+
+-(void)moveToEndOfLineAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_END_OF_LINE character: 0 modifiers: 0];
+}
+
+-(void)moveToRightEndOfLineAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_END_OF_LINE character: 0 modifiers: 0];
+}
+
+-(void)moveToBeginningOfLine: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE character: 0 modifiers: 0];
+}
+
+-(void)moveToLeftEndOfLine: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE character: 0 modifiers: 0];
+}
+
+-(void)moveToBeginningOfLineAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE character: 0 modifiers: 0];
+}
+
+-(void)moveToLeftEndOfLineAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE character: 0 modifiers: 0];
+}
+
+-(void)moveToEndOfParagraph: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH character: 0 modifiers: 0];
+}
+
+-(void)moveToEndOfParagraphAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH character: 0 modifiers: 0];
+}
+
+-(void)moveParagraphForward: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH character: 0 modifiers: 0];
+}
+
+-(void)moveParagraphForwardAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH character: 0 modifiers: 0];
+}
+
+-(void)moveToBeginningOfParagraph: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0];
+}
+
+-(void)moveParagraphBackward: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0];
+}
+
+-(void)moveToBeginningOfParagraphAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0];
+}
+
+-(void)moveParagraphBackwardAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0];
+}
+
+-(void)moveToEndOfDocument: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT character: 0 modifiers: 0];
+}
+
+-(void)scrollToEndOfDocument: (id)aSender
+{
+ // this is not exactly what we should do, but it makes "End" and "Shift-End" behave consistent
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT character: 0 modifiers: 0];
+}
+
+-(void)moveToEndOfDocumentAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT character: 0 modifiers: 0];
+}
+
+-(void)moveToBeginningOfDocument: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT character: 0 modifiers: 0];
+}
+
+-(void)scrollToBeginningOfDocument: (id)aSender
+{
+ // this is not exactly what we should do, but it makes "Home" and "Shift-Home" behave consistent
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT character: 0 modifiers: 0];
+}
+
+-(void)moveToBeginningOfDocumentAndModifySelection: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT character: 0 modifiers: 0];
+}
+
+-(void)moveUp: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: KEY_UP character: 0 modifiers: 0];
+}
+
+-(void)moveDown: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: KEY_DOWN character: 0 modifiers: 0];
+}
+
+-(void)insertNewline: (id)aSender
+{
+ // #i91267# make enter and shift-enter work by evaluating the modifiers
+ [self sendKeyInputAndReleaseToFrame: KEY_RETURN character: '\n' modifiers: mpFrame->mnLastModifierFlags];
+}
+
+-(void)deleteBackward: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: KEY_BACKSPACE character: '\b' modifiers: 0];
+}
+
+-(void)deleteForward: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: KEY_DELETE character: 0x7f modifiers: 0];
+}
+
+-(void)deleteBackwardByDecomposingPreviousCharacter: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: KEY_BACKSPACE character: '\b' modifiers: 0];
+}
+
+-(void)deleteWordBackward: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::DELETE_WORD_BACKWARD character: 0 modifiers: 0];
+}
+
+-(void)deleteWordForward: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::DELETE_WORD_FORWARD character: 0 modifiers: 0];
+}
+
+-(void)deleteToBeginningOfLine: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_LINE character: 0 modifiers: 0];
+}
+
+-(void)deleteToEndOfLine: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::DELETE_TO_END_OF_LINE character: 0 modifiers: 0];
+}
+
+-(void)deleteToBeginningOfParagraph: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0];
+}
+
+-(void)deleteToEndOfParagraph: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::DELETE_TO_END_OF_PARAGRAPH character: 0 modifiers: 0];
+}
+
+-(void)insertLineBreak: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::INSERT_LINEBREAK character: 0 modifiers: 0];
+}
+
+-(void)insertParagraphSeparator: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::INSERT_PARAGRAPH character: 0 modifiers: 0];
+}
+
+-(void)selectWord: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_WORD character: 0 modifiers: 0];
+}
+
+-(void)selectLine: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_LINE character: 0 modifiers: 0];
+}
+
+-(void)selectParagraph: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_PARAGRAPH character: 0 modifiers: 0];
+}
+
+-(void)selectAll: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: com::sun::star::awt::Key::SELECT_ALL character: 0 modifiers: 0];
+}
+
+-(void)cancelOperation: (id)aSender
+{
+ [self sendKeyInputAndReleaseToFrame: KEY_ESCAPE character: 0x1b modifiers: 0];
+}
+
+-(void)noop: (id)aSender
+{
+ if( ! mbKeyHandled )
+ {
+ if( ! [self sendSingleCharacter:mpLastEvent] )
+ {
+ /* prevent recursion */
+ if( mpLastEvent != mpLastSuperEvent && [NSApp respondsToSelector: @selector(sendSuperEvent:)] )
+ {
+ id pLastSuperEvent = mpLastSuperEvent;
+ mpLastSuperEvent = mpLastEvent;
+ [NSApp performSelector:@selector(sendSuperEvent:) withObject: mpLastEvent];
+ mpLastSuperEvent = pLastSuperEvent;
+
+ std::map< NSEvent*, bool >::iterator it = GetSalData()->maKeyEventAnswer.find( mpLastEvent );
+ if( it != GetSalData()->maKeyEventAnswer.end() )
+ it->second = true;
+ }
+ }
+ }
+}
+
+-(MacOSBOOL)sendKeyInputAndReleaseToFrame: (USHORT)nKeyCode character: (sal_Unicode)aChar
+{
+ return [self sendKeyInputAndReleaseToFrame: nKeyCode character: aChar modifiers: mpFrame->mnLastModifierFlags];
+}
+
+-(MacOSBOOL)sendKeyInputAndReleaseToFrame: (USHORT)nKeyCode character: (sal_Unicode)aChar modifiers: (unsigned int)nMod
+{
+ return [self sendKeyToFrameDirect: nKeyCode character: aChar modifiers: nMod] ||
+ [self sendSingleCharacter: mpLastEvent];
+}
+
+-(MacOSBOOL)sendKeyToFrameDirect: (USHORT)nKeyCode character: (sal_Unicode)aChar modifiers: (unsigned int)nMod
+{
+ YIELD_GUARD;
+
+ long nRet = 0;
+ if( AquaSalFrame::isAlive( mpFrame ) )
+ {
+ SalKeyEvent aEvent;
+ aEvent.mnTime = mpFrame->mnLastEventTime;
+ aEvent.mnCode = nKeyCode | ImplGetModifierMask( nMod );
+ aEvent.mnCharCode = aChar;
+ aEvent.mnRepeat = FALSE;
+ nRet = mpFrame->CallCallback( SALEVENT_KEYINPUT, &aEvent );
+ std::map< NSEvent*, bool >::iterator it = GetSalData()->maKeyEventAnswer.find( mpLastEvent );
+ if( it != GetSalData()->maKeyEventAnswer.end() )
+ it->second = nRet ? true : false;
+ if( AquaSalFrame::isAlive( mpFrame ) )
+ mpFrame->CallCallback( SALEVENT_KEYUP, &aEvent );
+ }
+ return nRet ? YES : NO;
+}
+
+
+-(MacOSBOOL)sendSingleCharacter: (NSEvent *)pEvent
+{
+ NSString* pUnmodifiedString = [pEvent charactersIgnoringModifiers];
+
+ if( pUnmodifiedString && [pUnmodifiedString length] == 1 )
+ {
+ unichar keyChar = [pUnmodifiedString characterAtIndex: 0];
+ USHORT nKeyCode = ImplMapCharCode( keyChar );
+ if( nKeyCode != 0 )
+ {
+ // don't send unicodes in the private use area
+ if( keyChar >= 0xf700 && keyChar < 0xf780 )
+ keyChar = 0;
+ MacOSBOOL bRet = [self sendKeyToFrameDirect: nKeyCode character: keyChar modifiers: mpFrame->mnLastModifierFlags];
+ mbInKeyInput = false;
+
+ return bRet;
+ }
+ }
+ return NO;
+}
+
+
+// NSTextInput protocol
+- (NSArray *)validAttributesForMarkedText
+{
+ return [NSArray arrayWithObjects:NSUnderlineStyleAttributeName, nil];
+}
+
+- (MacOSBOOL)hasMarkedText
+{
+ MacOSBOOL bHasMarkedText;
+
+ bHasMarkedText = ( mMarkedRange.location != NSNotFound ) &&
+ ( mMarkedRange.length != 0 );
+ // hack to check keys like "Control-j"
+ if( mbInKeyInput )
+ {
+ mbNeedSpecialKeyHandle = true;
+ }
+
+ // FIXME:
+ // #i106901#
+ // if we come here outside of mbInKeyInput, this is likely to be because
+ // of the keyboard viewer. For unknown reasons having no marked range
+ // in this case causes a crash. So we say we have a marked range anyway
+ // This is a hack, since it is not understood what a) causes that crash
+ // and b) why we should have a marked range at this point.
+ if( ! mbInKeyInput )
+ bHasMarkedText = YES;
+
+ return bHasMarkedText;
+}
+
+- (NSRange)markedRange
+{
+ // FIXME:
+ // #i106901#
+ // if we come here outside of mbInKeyInput, this is likely to be because
+ // of the keyboard viewer. For unknown reasons having no marked range
+ // in this case causes a crash. So we say we have a marked range anyway
+ // This is a hack, since it is not understood what a) causes that crash
+ // and b) why we should have a marked range at this point.
+ if( ! mbInKeyInput )
+ return NSMakeRange( 0, 0 );
+
+ return [self hasMarkedText] ? mMarkedRange : NSMakeRange( NSNotFound, 0 );
+}
+
+- (NSRange)selectedRange
+{
+ return mSelectedRange;
+}
+
+- (void)setMarkedText:(id)aString selectedRange:(NSRange)selRange
+{
+ if( ![aString isKindOfClass:[NSAttributedString class]] )
+ aString = [[[NSAttributedString alloc] initWithString:aString] autorelease];
+ NSRange rangeToReplace = [self hasMarkedText] ? [self markedRange] : [self selectedRange];
+ if( rangeToReplace.location == NSNotFound )
+ {
+ mMarkedRange = NSMakeRange( selRange.location, [aString length] );
+ mSelectedRange = NSMakeRange( selRange.location, selRange.length );
+ }
+ else
+ {
+ mMarkedRange = NSMakeRange( rangeToReplace.location, [aString length] );
+ mSelectedRange = NSMakeRange( rangeToReplace.location + selRange.location, selRange.length );
+ }
+
+ int len = [aString length];
+ SalExtTextInputEvent aInputEvent;
+ aInputEvent.mnTime = mpFrame->mnLastEventTime;
+ aInputEvent.mnDeltaStart = 0;
+ aInputEvent.mbOnlyCursor = FALSE;
+ if( len > 0 ) {
+ NSString *pString = [aString string];
+ OUString aInsertString( GetOUString( pString ) );
+ std::vector<USHORT> aInputFlags = std::vector<USHORT>( std::max( 1, len ), 0 );
+ for ( int i = 0; i < len; i++ )
+ {
+ unsigned int nUnderlineValue;
+ NSRange effectiveRange;
+
+ effectiveRange = NSMakeRange(i, 1);
+ nUnderlineValue = [[aString attribute:NSUnderlineStyleAttributeName atIndex:i effectiveRange:&effectiveRange] unsignedIntValue];
+
+ switch (nUnderlineValue & 0xff) {
+ case NSUnderlineStyleSingle:
+ aInputFlags[i] = SAL_EXTTEXTINPUT_ATTR_UNDERLINE;
+ break;
+ case NSUnderlineStyleThick:
+ aInputFlags[i] = SAL_EXTTEXTINPUT_ATTR_UNDERLINE | SAL_EXTTEXTINPUT_ATTR_HIGHLIGHT;
+ break;
+ case NSUnderlineStyleDouble:
+ aInputFlags[i] = SAL_EXTTEXTINPUT_ATTR_BOLDUNDERLINE;
+ break;
+ default:
+ aInputFlags[i] = SAL_EXTTEXTINPUT_ATTR_HIGHLIGHT;
+ break;
+ }
+ }
+
+ aInputEvent.maText = aInsertString;
+ aInputEvent.mnCursorPos = selRange.location;
+ aInputEvent.mpTextAttr = &aInputFlags[0];
+ mpFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void *)&aInputEvent );
+ } else {
+ aInputEvent.maText = String();
+ aInputEvent.mnCursorPos = 0;
+ aInputEvent.mnCursorFlags = 0;
+ aInputEvent.mpTextAttr = 0;
+ mpFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void *)&aInputEvent );
+ mpFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, 0 );
+ }
+ mbKeyHandled= true;
+}
+
+- (void)unmarkText
+{
+ mSelectedRange = mMarkedRange = NSMakeRange(NSNotFound, 0);
+}
+
+- (NSAttributedString *)attributedSubstringFromRange:(NSRange)theRange
+{
+ // FIXME
+ return nil;
+}
+
+- (unsigned int)characterIndexForPoint:(NSPoint)thePoint
+{
+ // FIXME
+ return 0;
+}
+
+#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
+/* build target 10.5 or greater */
+- (NSInteger)conversationIdentifier
+#else
+/* build target 10.4 */
+- (long)conversationIdentifier
+#endif
+{
+ return (long)self;
+}
+
+- (void)doCommandBySelector:(SEL)aSelector
+{
+ if( AquaSalFrame::isAlive( mpFrame ) )
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ // fprintf( stderr, "SalFrameView: doCommandBySelector %s\n", (char*)aSelector );
+ #endif
+ if( (mpFrame->mnICOptions & SAL_INPUTCONTEXT_TEXT) != 0 &&
+ aSelector != NULL && [self respondsToSelector: aSelector] )
+ {
+ [self performSelector: aSelector];
+ }
+ else
+ {
+ [self sendSingleCharacter:mpLastEvent];
+ }
+ }
+
+ mbKeyHandled = true;
+}
+
+-(void)clearLastEvent
+{
+ mpLastEvent = nil;
+}
+
+- (NSRect)firstRectForCharacterRange:(NSRange)theRange
+{
+ SalExtTextInputPosEvent aPosEvent;
+ mpFrame->CallCallback( SALEVENT_EXTTEXTINPUTPOS, (void *)&aPosEvent );
+
+ NSRect rect;
+
+ rect.origin.x = aPosEvent.mnX + mpFrame->maGeometry.nX;
+ rect.origin.y = aPosEvent.mnY + mpFrame->maGeometry.nY + 4; // add some space for underlines
+ rect.size.width = aPosEvent.mnWidth;
+ rect.size.height = aPosEvent.mnHeight;
+
+ mpFrame->VCLToCocoa( rect );
+ return rect;
+}
+
+-(id)parentAttribute {
+ return (NSView *) mpFrame -> mpWindow;
+}
+
+-(::com::sun::star::accessibility::XAccessibleContext *)accessibleContext
+{
+ if ( mpReferenceWrapper == nil ) {
+ // some frames never become visible ..
+ Window *pWindow = mpFrame -> GetWindow();
+ if ( ! pWindow )
+ return nil;
+
+ mpReferenceWrapper = new ReferenceWrapper;
+ mpReferenceWrapper -> rAccessibleContext = pWindow -> /*GetAccessibleChildWindow( 0 ) ->*/ GetAccessible() -> getAccessibleContext();
+ [ AquaA11yFactory insertIntoWrapperRepository: self forAccessibleContext: mpReferenceWrapper -> rAccessibleContext ];
+ }
+ return [ super accessibleContext ];
+}
+
+-(NSView *)viewElementForParent
+{
+ return (NSView *) mpFrame -> mpWindow;
+}
+
+-(void)registerMouseEventListener: (id)theListener
+{
+ mpMouseEventListener = theListener;
+}
+
+-(void)unregisterMouseEventListener: (id)theListener
+{
+ mpMouseEventListener = nil;
+}
+
+-(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
+{
+ return [mDraggingDestinationHandler draggingEntered: sender];
+}
+
+-(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
+{
+ return [mDraggingDestinationHandler draggingUpdated: sender];
+}
+
+-(void)draggingExited:(id <NSDraggingInfo>)sender
+{
+ [mDraggingDestinationHandler draggingExited: sender];
+}
+
+-(MacOSBOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
+{
+ return [mDraggingDestinationHandler prepareForDragOperation: sender];
+}
+
+-(MacOSBOOL)performDragOperation:(id <NSDraggingInfo>)sender
+{
+ return [mDraggingDestinationHandler performDragOperation: sender];
+}
+
+-(void)concludeDragOperation:(id <NSDraggingInfo>)sender
+{
+ [mDraggingDestinationHandler concludeDragOperation: sender];
+}
+
+-(void)registerDraggingDestinationHandler:(id)theHandler
+{
+ mDraggingDestinationHandler = theHandler;
+}
+
+-(void)unregisterDraggingDestinationHandler:(id)theHandler
+{
+ mDraggingDestinationHandler = nil;
+}
+
+@end
+
diff --git a/vcl/aqua/source/window/salmenu.cxx b/vcl/aqua/source/window/salmenu.cxx
new file mode 100644
index 000000000000..ed3086d8506f
--- /dev/null
+++ b/vcl/aqua/source/window/salmenu.cxx
@@ -0,0 +1,958 @@
+/*************************************************************************
+ *
+ * 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 "saldata.hxx"
+#include "salinst.h"
+#include "salmenu.h"
+#include "salnsmenu.h"
+#include "salframe.h"
+#include "salbmp.h"
+#include "vcl/svids.hrc"
+#include "vcl/cmdevt.hxx"
+#include "vcl/floatwin.hxx"
+#include "vcl/window.h"
+#include "vcl/window.hxx"
+#include "vcl/svapp.hxx"
+
+#include "rtl/ustrbuf.hxx"
+#include "aqua11ywrapper.h"
+
+const AquaSalMenu* AquaSalMenu::pCurrentMenuBar = NULL;
+
+@interface MainMenuSelector : NSObject
+{
+}
+-(void)showDialog: (int)nDialog;
+-(void)showPreferences: (id)sender;
+-(void)showAbout: (id)sender;
+@end
+
+@implementation MainMenuSelector
+-(void)showDialog: (int)nDialog
+{
+ if( AquaSalMenu::pCurrentMenuBar )
+ {
+ const AquaSalFrame* pFrame = AquaSalMenu::pCurrentMenuBar->mpFrame;
+ if( pFrame && AquaSalFrame::isAlive( pFrame ) )
+ {
+ pFrame->CallCallback( SALEVENT_SHOWDIALOG, reinterpret_cast<void*>(nDialog) );
+ }
+ }
+ else
+ {
+ String aDialog;
+ if( nDialog == SHOWDIALOG_ID_ABOUT )
+ aDialog = String( RTL_CONSTASCII_USTRINGPARAM( "ABOUT" ) );
+ else if( nDialog == SHOWDIALOG_ID_PREFERENCES )
+ aDialog = String( RTL_CONSTASCII_USTRINGPARAM( "PREFERENCES" ) );
+ const ApplicationEvent* pAppEvent = new ApplicationEvent( String(),
+ ApplicationAddress(),
+ ByteString( "SHOWDIALOG" ),
+ aDialog );
+ AquaSalInstance::aAppEventList.push_back( pAppEvent );
+ }
+}
+
+-(void)showPreferences: (id) sender
+{
+ [self showDialog: SHOWDIALOG_ID_PREFERENCES];
+}
+-(void)showAbout: (id) sender
+{
+ [self showDialog: SHOWDIALOG_ID_ABOUT];
+}
+@end
+
+
+// FIXME: currently this is leaked
+static MainMenuSelector* pMainMenuSelector = nil;
+
+static void initAppMenu()
+{
+ static bool bOnce = true;
+ if( bOnce )
+ {
+ bOnce = false;
+
+ ResMgr* pMgr = ImplGetResMgr();
+ if( pMgr )
+ {
+ // get the main menu
+ NSMenu* pMainMenu = [NSApp mainMenu];
+ if( pMainMenu != nil )
+ {
+ // create the action selector
+ pMainMenuSelector = [[MainMenuSelector alloc] init];
+
+ // get the proper submenu
+ NSMenu* pAppMenu = [[pMainMenu itemAtIndex: 0] submenu];
+ if( pAppMenu )
+ {
+ // insert about entry
+ String aAbout( ResId( SV_STDTEXT_ABOUT, *pMgr ) );
+ NSString* pString = CreateNSString( aAbout );
+ NSMenuItem* pNewItem = [pAppMenu insertItemWithTitle: pString
+ action: @selector(showAbout:)
+ keyEquivalent: @""
+ atIndex: 0];
+ if (pString)
+ [pString release];
+ if( pNewItem )
+ {
+ [pNewItem setTarget: pMainMenuSelector];
+ [pAppMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
+ }
+
+ // insert preferences entry
+ String aPref( ResId( SV_STDTEXT_PREFERENCES, *pMgr ) );
+ pString = CreateNSString( aPref );
+ pNewItem = [pAppMenu insertItemWithTitle: pString
+ action: @selector(showPreferences:)
+ keyEquivalent: @","
+ atIndex: 2];
+ if (pString)
+ [pString release];
+ if( pNewItem )
+ {
+ [pNewItem setKeyEquivalentModifierMask: NSCommandKeyMask];
+ [pNewItem setTarget: pMainMenuSelector];
+ [pAppMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
+ }
+
+ // WARNING: ultra ugly code ahead
+
+ // rename standard entries
+ // rename "Services"
+ pNewItem = [pAppMenu itemAtIndex: 4];
+ if( pNewItem )
+ {
+ pString = CreateNSString( String( ResId( SV_MENU_MAC_SERVICES, *pMgr ) ) );
+ [pNewItem setTitle: pString];
+ if( pString )
+ [pString release];
+ }
+
+ // rename "Hide NewApplication"
+ pNewItem = [pAppMenu itemAtIndex: 6];
+ if( pNewItem )
+ {
+ pString = CreateNSString( String( ResId( SV_MENU_MAC_HIDEAPP, *pMgr ) ) );
+ [pNewItem setTitle: pString];
+ if( pString )
+ [pString release];
+ }
+
+ // rename "Hide Others"
+ pNewItem = [pAppMenu itemAtIndex: 7];
+ if( pNewItem )
+ {
+ pString = CreateNSString( String( ResId( SV_MENU_MAC_HIDEALL, *pMgr ) ) );
+ [pNewItem setTitle: pString];
+ if( pString )
+ [pString release];
+ }
+
+ // rename "Show all"
+ pNewItem = [pAppMenu itemAtIndex: 8];
+ if( pNewItem )
+ {
+ pString = CreateNSString( String( ResId( SV_MENU_MAC_SHOWALL, *pMgr ) ) );
+ [pNewItem setTitle: pString];
+ if( pString )
+ [pString release];
+ }
+
+ // rename "Quit NewApplication"
+ pNewItem = [pAppMenu itemAtIndex: 10];
+ if( pNewItem )
+ {
+ pString = CreateNSString( String( ResId( SV_MENU_MAC_QUITAPP, *pMgr ) ) );
+ [pNewItem setTitle: pString];
+ if( pString )
+ [pString release];
+ }
+ }
+ }
+ }
+ }
+}
+
+// =======================================================================
+
+SalMenu* AquaSalInstance::CreateMenu( BOOL bMenuBar )
+{
+ initAppMenu();
+
+ AquaSalMenu *pAquaSalMenu = new AquaSalMenu( bMenuBar );
+
+ return pAquaSalMenu;
+}
+
+void AquaSalInstance::DestroyMenu( SalMenu* pSalMenu )
+{
+ delete pSalMenu;
+}
+
+SalMenuItem* AquaSalInstance::CreateMenuItem( const SalItemParams* pItemData )
+{
+ if( !pItemData )
+ return NULL;
+
+ AquaSalMenuItem *pSalMenuItem = new AquaSalMenuItem( pItemData );
+
+ return pSalMenuItem;
+}
+
+void AquaSalInstance::DestroyMenuItem( SalMenuItem* pSalMenuItem )
+{
+ delete pSalMenuItem;
+}
+
+
+// =======================================================================
+
+
+/*
+ * AquaSalMenu
+ */
+
+AquaSalMenu::AquaSalMenu( bool bMenuBar ) :
+ mbMenuBar( bMenuBar ),
+ mpMenu( nil ),
+ mpVCLMenu( NULL ),
+ mpFrame( NULL ),
+ mpParentSalMenu( NULL )
+{
+ if( ! mbMenuBar )
+ {
+ mpMenu = [[SalNSMenu alloc] initWithMenu: this];
+ [mpMenu setDelegate: mpMenu];
+ }
+ else
+ {
+ mpMenu = [NSApp mainMenu];
+ }
+ [mpMenu setAutoenablesItems: NO];
+}
+
+AquaSalMenu::~AquaSalMenu()
+{
+ // actually someone should have done AquaSalFrame::SetMenu( NULL )
+ // on our frame, alas it is not so
+ if( mpFrame && AquaSalFrame::isAlive( mpFrame ) && mpFrame->mpMenu == this )
+ const_cast<AquaSalFrame*>(mpFrame)->mpMenu = NULL;
+
+ // this should normally be empty already, but be careful...
+ for( size_t i = 0; i < maButtons.size(); i++ )
+ releaseButtonEntry( maButtons[i] );
+ maButtons.clear();
+
+ // is this leaking in some cases ? the release often leads to a duplicate release
+ // it seems the parent item gets ownership of the menu
+ if( mpMenu )
+ {
+ if( mbMenuBar )
+ {
+ if( pCurrentMenuBar == this )
+ {
+ // if the current menubar gets destroyed, set the default menubar
+ setDefaultMenu();
+ }
+ }
+ else
+ // the system may still hold a reference on mpMenu
+ {
+ // so set the pointer to this AquaSalMenu to NULL
+ // to protect from calling a dead object
+
+ // in ! mbMenuBar case our mpMenu is actually a SalNSMenu*
+ // so we can safely cast here
+ [static_cast<SalNSMenu*>(mpMenu) setSalMenu: NULL];
+ /* #i89860# FIXME:
+ using [autorelease] here (and in AquaSalMenuItem::~AquaSalMenuItem)
+ instead of [release] fixes an occasional crash. That should
+ indicate that we release menus / menu items in the wrong order
+ somewhere, but I could not find that case.
+ */
+ [mpMenu autorelease];
+ }
+ }
+}
+
+sal_Int32 removeUnusedItemsRunner(NSMenu * pMenu)
+{
+ NSArray * elements = [pMenu itemArray];
+ NSEnumerator * it = [elements objectEnumerator];
+ id elem;
+ NSMenuItem * lastDisplayedMenuItem = nil;
+ sal_Int32 drawnItems = 0;
+ bool firstEnabledItemIsNoSeparator = false;
+ while((elem=[it nextObject]) != nil) {
+ NSMenuItem * item = static_cast<NSMenuItem *>(elem);
+ if( (![item isEnabled] && ![item isSeparatorItem]) || ([item isSeparatorItem] && (lastDisplayedMenuItem != nil && [lastDisplayedMenuItem isSeparatorItem])) ) {
+ [[item menu]removeItem:item];
+ } else {
+ if( ! firstEnabledItemIsNoSeparator && [item isSeparatorItem] ) {
+ [[item menu]removeItem:item];
+ } else {
+ firstEnabledItemIsNoSeparator = true;
+ lastDisplayedMenuItem = item;
+ drawnItems++;
+ if( [item hasSubmenu] ) {
+ removeUnusedItemsRunner( [item submenu] );
+ }
+ }
+ }
+ }
+ if( lastDisplayedMenuItem != nil && [lastDisplayedMenuItem isSeparatorItem]) {
+ [[lastDisplayedMenuItem menu]removeItem:lastDisplayedMenuItem];
+ }
+ return drawnItems;
+}
+
+bool AquaSalMenu::ShowNativePopupMenu(FloatingWindow * pWin, const Rectangle& rRect, ULONG nFlags)
+{
+ // do not use native popup menu when AQUA_NATIVE_MENUS is set to FALSE
+ if( ! VisibleMenuBar() ) {
+ return false;
+ }
+
+ // set offsets for positioning
+ const float offset = 9.0;
+
+ // get the pointers
+ AquaSalFrame * pParentAquaSalFrame = (AquaSalFrame *) pWin->ImplGetWindowImpl()->mpRealParent->ImplGetFrame();
+ NSWindow * pParentNSWindow = pParentAquaSalFrame->mpWindow;
+ NSView * pParentNSView = [pParentNSWindow contentView];
+ NSView * pPopupNSView = ((AquaSalFrame *) pWin->ImplGetWindow()->ImplGetFrame())->mpView;
+ NSRect popupFrame = [pPopupNSView frame];
+
+ // since we manipulate the menu below (removing entries)
+ // let's rather make a copy here and work with that
+ NSMenu* pCopyMenu = [mpMenu copy];
+
+ // filter disabled elements
+ removeUnusedItemsRunner( pCopyMenu );
+
+ // create frame rect
+ NSRect displayPopupFrame = NSMakeRect( rRect.nLeft+(offset-1), rRect.nTop+(offset+1), popupFrame.size.width, 0 );
+ pParentAquaSalFrame->VCLToCocoa(displayPopupFrame, false);
+
+ // do the same strange semantics as vcl popup windows to arrive at a frame geometry
+ // in mirrored UI case; best done by actually executing the same code
+ USHORT nArrangeIndex;
+ pWin->SetPosPixel( pWin->ImplCalcPos( pWin, rRect, nFlags, nArrangeIndex ) );
+ displayPopupFrame.origin.x = pWin->ImplGetFrame()->maGeometry.nX - pParentAquaSalFrame->maGeometry.nX + offset;
+ displayPopupFrame.origin.y = pWin->ImplGetFrame()->maGeometry.nY - pParentAquaSalFrame->maGeometry.nY + offset;
+ pParentAquaSalFrame->VCLToCocoa(displayPopupFrame, false);
+
+ // #i111992# if this menu was opened due to a key event, prevent dispatching that yet again
+ if( [pParentNSView respondsToSelector: @selector(clearLastEvent)] )
+ [pParentNSView performSelector:@selector(clearLastEvent)];
+
+ // open popup menu
+ NSPopUpButtonCell * pPopUpButtonCell = [[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO];
+ [pPopUpButtonCell setMenu: pCopyMenu];
+ [pPopUpButtonCell selectItem:nil];
+ [AquaA11yWrapper setPopupMenuOpen: YES];
+ [pPopUpButtonCell performClickWithFrame:displayPopupFrame inView:pParentNSView];
+ [pPopUpButtonCell release];
+ [AquaA11yWrapper setPopupMenuOpen: NO];
+
+ // clean up the copy
+ [pCopyMenu release];
+ return true;
+}
+
+int AquaSalMenu::getItemIndexByPos( USHORT nPos ) const
+{
+ int nIndex = 0;
+ if( nPos == MENU_APPEND )
+ nIndex = [mpMenu numberOfItems];
+ else
+ nIndex = sal::static_int_cast<int>( mbMenuBar ? nPos+1 : nPos );
+ return nIndex;
+}
+
+const AquaSalFrame* AquaSalMenu::getFrame() const
+{
+ const AquaSalMenu* pMenu = this;
+ while( pMenu && ! pMenu->mpFrame )
+ pMenu = pMenu->mpParentSalMenu;
+ return pMenu ? pMenu->mpFrame : NULL;
+}
+
+void AquaSalMenu::unsetMainMenu()
+{
+ pCurrentMenuBar = NULL;
+
+ // remove items from main menu
+ NSMenu* pMenu = [NSApp mainMenu];
+ for( int nItems = [pMenu numberOfItems]; nItems > 1; nItems-- )
+ [pMenu removeItemAtIndex: 1];
+}
+
+void AquaSalMenu::setMainMenu()
+{
+ DBG_ASSERT( mbMenuBar, "setMainMenu on non menubar" );
+ if( mbMenuBar )
+ {
+ if( pCurrentMenuBar != this )
+ {
+ unsetMainMenu();
+ // insert our items
+ for( unsigned int i = 0; i < maItems.size(); i++ )
+ {
+ NSMenuItem* pItem = maItems[i]->mpMenuItem;
+ [mpMenu insertItem: pItem atIndex: i+1];
+ }
+ pCurrentMenuBar = this;
+
+ // change status item
+ statusLayout();
+ }
+ enableMainMenu( true );
+ }
+}
+
+void AquaSalMenu::setDefaultMenu()
+{
+ NSMenu* pMenu = [NSApp mainMenu];
+
+ unsetMainMenu();
+
+ // insert default items
+ std::vector< NSMenuItem* >& rFallbackMenu( GetSalData()->maFallbackMenu );
+ for( unsigned int i = 0, nAddItems = rFallbackMenu.size(); i < nAddItems; i++ )
+ {
+ NSMenuItem* pItem = rFallbackMenu[i];
+ if( [pItem menu] == nil )
+ [pMenu insertItem: pItem atIndex: i+1];
+ }
+}
+
+void AquaSalMenu::enableMainMenu( bool bEnable )
+{
+ NSMenu* pMainMenu = [NSApp mainMenu];
+ if( pMainMenu )
+ {
+ // enable/disable items from main menu
+ int nItems = [pMainMenu numberOfItems];
+ for( int n = 1; n < nItems; n++ )
+ {
+ NSMenuItem* pItem = [pMainMenu itemAtIndex: n];
+ [pItem setEnabled: bEnable ? YES : NO];
+ }
+ }
+}
+
+void AquaSalMenu::addFallbackMenuItem( NSMenuItem* pNewItem )
+{
+ initAppMenu();
+
+ std::vector< NSMenuItem* >& rFallbackMenu( GetSalData()->maFallbackMenu );
+
+ // prevent duplicate insertion
+ int nItems = rFallbackMenu.size();
+ for( int i = 0; i < nItems; i++ )
+ {
+ if( rFallbackMenu[i] == pNewItem )
+ return;
+ }
+
+ // push the item to the back and retain it
+ [pNewItem retain];
+ rFallbackMenu.push_back( pNewItem );
+
+ if( pCurrentMenuBar == NULL )
+ setDefaultMenu();
+}
+
+void AquaSalMenu::removeFallbackMenuItem( NSMenuItem* pOldItem )
+{
+ std::vector< NSMenuItem* >& rFallbackMenu( GetSalData()->maFallbackMenu );
+
+ // find item
+ unsigned int nItems = rFallbackMenu.size();
+ for( unsigned int i = 0; i < nItems; i++ )
+ {
+ if( rFallbackMenu[i] == pOldItem )
+ {
+ // remove item and release
+ rFallbackMenu.erase( rFallbackMenu.begin() + i );
+ [pOldItem release];
+
+ if( pCurrentMenuBar == NULL )
+ setDefaultMenu();
+
+ return;
+ }
+ }
+}
+
+BOOL AquaSalMenu::VisibleMenuBar()
+{
+ // Enable/disable experimental native menus code?
+ //
+ // To disable native menus, set the environment variable AQUA_NATIVE_MENUS to FALSE
+
+ static const char *pExperimental = getenv ("AQUA_NATIVE_MENUS");
+
+ if ( ImplGetSVData()->mbIsTestTool || (pExperimental && !strcasecmp(pExperimental, "FALSE")) )
+ return FALSE;
+
+ // End of experimental code enable/disable part
+
+ return TRUE;
+}
+
+void AquaSalMenu::SetFrame( const SalFrame *pFrame )
+{
+ mpFrame = static_cast<const AquaSalFrame*>(pFrame);
+}
+
+void AquaSalMenu::InsertItem( SalMenuItem* pSalMenuItem, unsigned nPos )
+{
+ AquaSalMenuItem *pAquaSalMenuItem = static_cast<AquaSalMenuItem*>(pSalMenuItem);
+
+ pAquaSalMenuItem->mpParentMenu = this;
+ DBG_ASSERT( pAquaSalMenuItem->mpVCLMenu == NULL ||
+ pAquaSalMenuItem->mpVCLMenu == mpVCLMenu ||
+ mpVCLMenu == NULL,
+ "resetting menu ?" );
+ if( pAquaSalMenuItem->mpVCLMenu )
+ mpVCLMenu = pAquaSalMenuItem->mpVCLMenu;
+
+ if( nPos == MENU_APPEND || nPos == maItems.size() )
+ maItems.push_back( pAquaSalMenuItem );
+ else if( nPos < maItems.size() )
+ maItems.insert( maItems.begin() + nPos, pAquaSalMenuItem );
+ else
+ {
+ DBG_ERROR( "invalid item index in insert" );
+ return;
+ }
+
+ if( ! mbMenuBar || pCurrentMenuBar == this )
+ [mpMenu insertItem: pAquaSalMenuItem->mpMenuItem atIndex: getItemIndexByPos(nPos)];
+}
+
+void AquaSalMenu::RemoveItem( unsigned nPos )
+{
+ AquaSalMenuItem* pRemoveItem = NULL;
+ if( nPos == MENU_APPEND || nPos == (maItems.size()-1) )
+ {
+ pRemoveItem = maItems.back();
+ maItems.pop_back();
+ }
+ else if( nPos < maItems.size() )
+ {
+ pRemoveItem = maItems[ nPos ];
+ maItems.erase( maItems.begin()+nPos );
+ }
+ else
+ {
+ DBG_ERROR( "invalid item index in remove" );
+ return;
+ }
+
+ pRemoveItem->mpParentMenu = NULL;
+
+ if( ! mbMenuBar || pCurrentMenuBar == this )
+ [mpMenu removeItemAtIndex: getItemIndexByPos(nPos)];
+}
+
+void AquaSalMenu::SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos )
+{
+ AquaSalMenuItem *pAquaSalMenuItem = static_cast<AquaSalMenuItem*>(pSalMenuItem);
+ AquaSalMenu *subAquaSalMenu = static_cast<AquaSalMenu*>(pSubMenu);
+
+ if (subAquaSalMenu)
+ {
+ pAquaSalMenuItem->mpSubMenu = subAquaSalMenu;
+ if( subAquaSalMenu->mpParentSalMenu == NULL )
+ {
+ subAquaSalMenu->mpParentSalMenu = this;
+ [pAquaSalMenuItem->mpMenuItem setSubmenu: subAquaSalMenu->mpMenu];
+
+ // set title of submenu
+ [subAquaSalMenu->mpMenu setTitle: [pAquaSalMenuItem->mpMenuItem title]];
+ }
+ else if( subAquaSalMenu->mpParentSalMenu != this )
+ {
+ // cocoa doesn't allow menus to be submenus of multiple
+ // menu items, so place a copy in the menu item instead ?
+ // let's hope that NSMenu copy does the right thing
+ NSMenu* pCopy = [subAquaSalMenu->mpMenu copy];
+ [pAquaSalMenuItem->mpMenuItem setSubmenu: pCopy];
+
+ // set title of submenu
+ [pCopy setTitle: [pAquaSalMenuItem->mpMenuItem title]];
+ }
+ }
+ else
+ {
+ if( pAquaSalMenuItem->mpSubMenu )
+ {
+ if( pAquaSalMenuItem->mpSubMenu->mpParentSalMenu == this )
+ pAquaSalMenuItem->mpSubMenu->mpParentSalMenu = NULL;
+ }
+ pAquaSalMenuItem->mpSubMenu = NULL;
+ [pAquaSalMenuItem->mpMenuItem setSubmenu: nil];
+ }
+}
+
+void AquaSalMenu::CheckItem( unsigned nPos, BOOL bCheck )
+{
+ if( nPos < maItems.size() )
+ {
+ NSMenuItem* pItem = maItems[nPos]->mpMenuItem;
+ [pItem setState: bCheck ? NSOnState : NSOffState];
+ }
+}
+
+void AquaSalMenu::EnableItem( unsigned nPos, BOOL bEnable )
+{
+ if( nPos < maItems.size() )
+ {
+ NSMenuItem* pItem = maItems[nPos]->mpMenuItem;
+ [pItem setEnabled: bEnable ? YES : NO];
+ }
+}
+
+void AquaSalMenu::SetItemImage( unsigned nPos, SalMenuItem* pSMI, const Image& rImage )
+{
+ AquaSalMenuItem* pSalMenuItem = static_cast<AquaSalMenuItem*>( pSMI );
+ if( ! pSalMenuItem || ! pSalMenuItem->mpMenuItem )
+ return;
+
+ NSImage* pImage = CreateNSImage( rImage );
+
+ [pSalMenuItem->mpMenuItem setImage: pImage];
+ if( pImage )
+ [pImage release];
+}
+
+void AquaSalMenu::SetItemText( unsigned i_nPos, SalMenuItem* i_pSalMenuItem, const XubString& i_rText )
+{
+ if (!i_pSalMenuItem)
+ return;
+
+ AquaSalMenuItem *pAquaSalMenuItem = (AquaSalMenuItem *) i_pSalMenuItem;
+
+ String aText( i_rText );
+
+ // Delete mnemonics
+ aText.EraseAllChars( '~' );
+
+ /* #i90015# until there is a correct solution
+ strip out any appended (.*) in menubar entries
+ */
+ if( mbMenuBar )
+ {
+ xub_StrLen nPos = aText.SearchBackward( sal_Unicode( '(' ) );
+ if( nPos != STRING_NOTFOUND )
+ {
+ xub_StrLen nPos2 = aText.Search( sal_Unicode( ')' ) );
+ if( nPos2 != STRING_NOTFOUND )
+ aText.Erase( nPos, nPos2-nPos+1 );
+ }
+ }
+
+ NSString* pString = CreateNSString( aText );
+ if (pString)
+ {
+ [pAquaSalMenuItem->mpMenuItem setTitle: pString];
+ // if the menu item has a submenu, change its title as well
+ if (pAquaSalMenuItem->mpSubMenu)
+ [pAquaSalMenuItem->mpSubMenu->mpMenu setTitle: pString];
+ [pString release];
+ }
+}
+
+void AquaSalMenu::SetAccelerator( unsigned nPos, SalMenuItem* pSalMenuItem, const KeyCode& rKeyCode, const XubString& rKeyName )
+{
+ USHORT nModifier;
+ sal_Unicode nCommandKey = 0;
+
+ USHORT nKeyCode=rKeyCode.GetCode();
+ if( nKeyCode )
+ {
+ if ((nKeyCode>=KEY_A) && (nKeyCode<=KEY_Z)) // letter A..Z
+ nCommandKey = nKeyCode-KEY_A + 'a';
+ else if ((nKeyCode>=KEY_0) && (nKeyCode<=KEY_9)) // numbers 0..9
+ nCommandKey = nKeyCode-KEY_0 + '0';
+ else if ((nKeyCode>=KEY_F1) && (nKeyCode<=KEY_F26)) // function keys F1..F26
+ nCommandKey = nKeyCode-KEY_F1 + NSF1FunctionKey;
+ else if( nKeyCode == KEY_REPEAT )
+ nCommandKey = NSRedoFunctionKey;
+ else if( nKeyCode == KEY_SPACE )
+ nCommandKey = ' ';
+ else
+ {
+ switch (nKeyCode)
+ {
+ case KEY_ADD:
+ nCommandKey='+';
+ break;
+ case KEY_SUBTRACT:
+ nCommandKey='-';
+ break;
+ case KEY_MULTIPLY:
+ nCommandKey='*';
+ break;
+ case KEY_DIVIDE:
+ nCommandKey='/';
+ break;
+ case KEY_POINT:
+ nCommandKey='.';
+ break;
+ case KEY_LESS:
+ nCommandKey='<';
+ break;
+ case KEY_GREATER:
+ nCommandKey='>';
+ break;
+ case KEY_EQUAL:
+ nCommandKey='=';
+ break;
+ }
+ }
+ }
+ else // not even a code ? nonsense -> ignore
+ return;
+
+ DBG_ASSERT( nCommandKey, "unmapped accelerator key" );
+
+ nModifier=rKeyCode.GetAllModifier();
+
+ // should always use the command key
+ int nItemModifier = 0;
+
+ if (nModifier & KEY_SHIFT)
+ {
+ nItemModifier |= NSShiftKeyMask; // actually useful only for function keys
+ if( nKeyCode >= KEY_A && nKeyCode <= KEY_Z )
+ nCommandKey = nKeyCode - KEY_A + 'A';
+ }
+
+ if (nModifier & KEY_MOD1)
+ nItemModifier |= NSCommandKeyMask;
+
+ if(nModifier & KEY_MOD2)
+ nItemModifier |= NSAlternateKeyMask;
+
+ if(nModifier & KEY_MOD3)
+ nItemModifier |= NSControlKeyMask;
+
+ AquaSalMenuItem *pAquaSalMenuItem = (AquaSalMenuItem *) pSalMenuItem;
+ NSString* pString = CreateNSString( rtl::OUString( &nCommandKey, 1 ) );
+ [pAquaSalMenuItem->mpMenuItem setKeyEquivalent: pString];
+ [pAquaSalMenuItem->mpMenuItem setKeyEquivalentModifierMask: nItemModifier];
+ if (pString)
+ [pString release];
+}
+
+void AquaSalMenu::GetSystemMenuData( SystemMenuData* pData )
+{
+}
+
+AquaSalMenu::MenuBarButtonEntry* AquaSalMenu::findButtonItem( USHORT i_nItemId )
+{
+ for( size_t i = 0; i < maButtons.size(); ++i )
+ {
+ if( maButtons[i].maButton.mnId == i_nItemId )
+ return &maButtons[i];
+ }
+ return NULL;
+}
+
+void AquaSalMenu::statusLayout()
+{
+ if( GetSalData()->mpStatusItem )
+ {
+ NSView* pView = [GetSalData()->mpStatusItem view];
+ if( [pView isMemberOfClass: [OOStatusItemView class]] ) // well of course it is
+ [(OOStatusItemView*)pView layout];
+ else
+ DBG_ERROR( "someone stole our status view" );
+ }
+}
+
+void AquaSalMenu::releaseButtonEntry( MenuBarButtonEntry& i_rEntry )
+{
+ if( i_rEntry.mpNSImage )
+ {
+ [i_rEntry.mpNSImage release];
+ i_rEntry.mpNSImage = nil;
+ }
+ if( i_rEntry.mpToolTipString )
+ {
+ [i_rEntry.mpToolTipString release];
+ i_rEntry.mpToolTipString = nil;
+ }
+}
+
+bool AquaSalMenu::AddMenuBarButton( const SalMenuButtonItem& i_rNewItem )
+{
+ if( ! mbMenuBar || ! VisibleMenuBar() )
+ return false;
+
+ MenuBarButtonEntry* pEntry = findButtonItem( i_rNewItem.mnId );
+ if( pEntry )
+ {
+ releaseButtonEntry( *pEntry );
+ pEntry->maButton = i_rNewItem;
+ pEntry->mpNSImage = CreateNSImage( i_rNewItem.maImage );
+ if( i_rNewItem.maToolTipText.getLength() )
+ pEntry->mpToolTipString = CreateNSString( i_rNewItem.maToolTipText );
+ }
+ else
+ {
+ maButtons.push_back( MenuBarButtonEntry( i_rNewItem ) );
+ maButtons.back().mpNSImage = CreateNSImage( i_rNewItem.maImage );
+ maButtons.back().mpToolTipString = CreateNSString( i_rNewItem.maToolTipText );
+ }
+
+ // lazy create status item
+ SalData::getStatusItem();
+
+ if( pCurrentMenuBar == this )
+ statusLayout();
+
+ return true;
+}
+
+void AquaSalMenu::RemoveMenuBarButton( USHORT i_nId )
+{
+ MenuBarButtonEntry* pEntry = findButtonItem( i_nId );
+ if( pEntry )
+ {
+ releaseButtonEntry( *pEntry );
+ // note: vector guarantees that its contents are in a plain array
+ maButtons.erase( maButtons.begin() + (pEntry - &maButtons[0]) );
+ }
+
+ if( pCurrentMenuBar == this )
+ statusLayout();
+}
+
+Rectangle AquaSalMenu::GetMenuBarButtonRectPixel( USHORT i_nItemId, SalFrame* i_pReferenceFrame )
+{
+ if( GetSalData()->mnSystemVersion < VER_LEOPARD )
+ return Rectangle( Point( -1, -1 ), Size( 1, 1 ) );
+
+ if( ! i_pReferenceFrame || ! AquaSalFrame::isAlive( static_cast<AquaSalFrame*>(i_pReferenceFrame) ) )
+ return Rectangle();
+
+ MenuBarButtonEntry* pEntry = findButtonItem( i_nItemId );
+
+ if( ! pEntry )
+ return Rectangle();
+
+ NSStatusItem* pItem = SalData::getStatusItem();
+ if( ! pItem )
+ return Rectangle();
+
+ NSView* pView = [pItem view];
+ if( ! pView )
+ return Rectangle();
+ NSWindow* pWin = [pView window];
+ if( ! pWin )
+ return Rectangle();
+
+ NSRect aRect = [pWin frame];
+ aRect.origin = [pWin convertBaseToScreen: NSMakePoint( 0, 0 )];
+
+ // make coordinates relative to reference frame
+ static_cast<AquaSalFrame*>(i_pReferenceFrame)->CocoaToVCL( aRect.origin );
+ aRect.origin.x -= i_pReferenceFrame->maGeometry.nX;
+ aRect.origin.y -= i_pReferenceFrame->maGeometry.nY + aRect.size.height;
+
+ return Rectangle( Point(static_cast<long int>(aRect.origin.x),
+ static_cast<long int>(aRect.origin.y)
+ ),
+ Size( static_cast<long int>(aRect.size.width),
+ static_cast<long int>(aRect.size.height)
+ )
+ );
+}
+
+// =======================================================================
+
+/*
+ * SalMenuItem
+ */
+
+AquaSalMenuItem::AquaSalMenuItem( const SalItemParams* pItemData ) :
+ mnId( pItemData->nId ),
+ mpVCLMenu( pItemData->pMenu ),
+ mpParentMenu( NULL ),
+ mpSubMenu( NULL ),
+ mpMenuItem( nil )
+{
+ String aText( pItemData->aText );
+
+ // Delete mnemonics
+ aText.EraseAllChars( '~' );
+
+ if (pItemData->eType == MENUITEM_SEPARATOR)
+ {
+ mpMenuItem = [NSMenuItem separatorItem];
+ // these can go occasionally go in and out of a menu, ensure their lifecycle
+ // also for the release in AquaSalMenuItem destructor
+ [mpMenuItem retain];
+ }
+ else
+ {
+ mpMenuItem = [[SalNSMenuItem alloc] initWithMenuItem: this];
+ [mpMenuItem setEnabled: YES];
+ NSString* pString = CreateNSString( aText );
+ if (pString)
+ {
+ [mpMenuItem setTitle: pString];
+ [pString release];
+ }
+ // anything but a separator should set a menu to dispatch to
+ DBG_ASSERT( mpVCLMenu, "no menu" );
+ }
+}
+
+AquaSalMenuItem::~AquaSalMenuItem()
+{
+ /* #i89860# FIXME:
+ using [autorelease] here (and in AquaSalMenu:::~AquaSalMenu) instead of
+ [release] fixes an occasional crash. That should indicate that we release
+ menus / menu items in the wrong order somewhere, but I
+ could not find that case.
+ */
+ if( mpMenuItem )
+ [mpMenuItem autorelease];
+}
+
+// -------------------------------------------------------------------
+
diff --git a/vcl/aqua/source/window/salnsmenu.mm b/vcl/aqua/source/window/salnsmenu.mm
new file mode 100755
index 000000000000..015c43aed70f
--- /dev/null
+++ b/vcl/aqua/source/window/salnsmenu.mm
@@ -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 "salinst.h"
+#include "saldata.hxx"
+#include "salframe.h"
+#include "salmenu.h"
+#include "salnsmenu.h"
+
+#include "vcl/window.hxx"
+
+@implementation SalNSMenu
+-(id)initWithMenu: (AquaSalMenu*)pMenu
+{
+ mpMenu = pMenu;
+ return [super initWithTitle: [NSString string]];
+}
+
+-(void)menuNeedsUpdate: (NSMenu*)pMenu
+{
+ YIELD_GUARD;
+
+ if( mpMenu )
+ {
+ const AquaSalFrame* pFrame = mpMenu->getFrame();
+ if( pFrame && AquaSalFrame::isAlive( pFrame ) )
+ {
+ SalMenuEvent aMenuEvt;
+ aMenuEvt.mnId = 0;
+ aMenuEvt.mpMenu = mpMenu->mpVCLMenu;
+ if( aMenuEvt.mpMenu )
+ {
+ pFrame->CallCallback(SALEVENT_MENUACTIVATE, &aMenuEvt);
+ pFrame->CallCallback(SALEVENT_MENUDEACTIVATE, &aMenuEvt);
+ }
+ else
+ DBG_ERROR( "unconnected menu" );
+ }
+ }
+}
+
+-(void)setSalMenu: (AquaSalMenu*)pMenu
+{
+ mpMenu = pMenu;
+}
+@end
+
+@implementation SalNSMenuItem
+-(id)initWithMenuItem: (AquaSalMenuItem*)pMenuItem
+{
+ mpMenuItem = pMenuItem;
+ id ret = [super initWithTitle: [NSString string]
+ action: @selector(menuItemTriggered:)
+ keyEquivalent: [NSString string]];
+ [ret setTarget: self];
+ return ret;
+}
+-(void)menuItemTriggered: (id)aSender
+{
+ YIELD_GUARD;
+
+ const AquaSalFrame* pFrame = mpMenuItem->mpParentMenu ? mpMenuItem->mpParentMenu->getFrame() : NULL;
+ if( pFrame && AquaSalFrame::isAlive( pFrame ) && ! pFrame->GetWindow()->IsInModalMode() )
+ {
+ SalMenuEvent aMenuEvt( mpMenuItem->mnId, mpMenuItem->mpVCLMenu );
+ pFrame->CallCallback(SALEVENT_MENUCOMMAND, &aMenuEvt);
+ }
+ else if( mpMenuItem->mpVCLMenu )
+ {
+ // if an item from submenu was selected. the corresponding Window does not exist because
+ // we use native popup menus, so we have to set the selected menuitem directly
+ // incidentally this of course works for top level popup menus, too
+ PopupMenu * pPopupMenu = dynamic_cast<PopupMenu *>(mpMenuItem->mpVCLMenu);
+ if( pPopupMenu )
+ {
+ // FIXME: revise this ugly code
+
+ // select handlers in vcl are dispatch on the original menu
+ // if not consumed by the select handler of the current menu
+ // however since only the starting menu ever came into Execute
+ // the hierarchy is not build up. Workaround this by getting
+ // the menu it should have been
+
+ // get started from hierarchy in vcl menus
+ AquaSalMenu* pParentMenu = mpMenuItem->mpParentMenu;
+ Menu* pCurMenu = mpMenuItem->mpVCLMenu;
+ while( pParentMenu && pParentMenu->mpVCLMenu )
+ {
+ pCurMenu = pParentMenu->mpVCLMenu;
+ pParentMenu = pParentMenu->mpParentSalMenu;
+ }
+
+ pPopupMenu->SetSelectedEntry( mpMenuItem->mnId );
+ pPopupMenu->ImplSelectWithStart( pCurMenu );
+ }
+ else
+ DBG_ERROR( "menubar item without frame !" );
+ }
+}
+@end
+
+@implementation OOStatusItemView
+-(void)drawRect: (NSRect)aRect
+{
+ NSGraphicsContext* pContext = [NSGraphicsContext currentContext];
+ [pContext saveGraphicsState];
+ [SalData::getStatusItem() drawStatusBarBackgroundInRect: aRect withHighlight: NO];
+ if( AquaSalMenu::pCurrentMenuBar )
+ {
+ const std::vector< AquaSalMenu::MenuBarButtonEntry >& rButtons( AquaSalMenu::pCurrentMenuBar->getButtons() );
+ NSRect aFrame = [self frame];
+ NSRect aImgRect = { { 2, 0 }, { 0, 0 } };
+ for( size_t i = 0; i < rButtons.size(); ++i )
+ {
+ NSRect aFromRect = { { 0, 0 },
+ { rButtons[i].maButton.maImage.GetSizePixel().Width(),
+ rButtons[i].maButton.maImage.GetSizePixel().Height() } };
+ aImgRect.origin.y = floor((aFrame.size.height - aFromRect.size.height)/2);
+ aImgRect.size = aFromRect.size;
+ if( rButtons[i].mpNSImage )
+ [rButtons[i].mpNSImage drawInRect: aImgRect fromRect: aFromRect operation: NSCompositeSourceOver fraction: 1.0];
+ aImgRect.origin.x += aFromRect.size.width + 2;
+ }
+ }
+ [pContext restoreGraphicsState];
+}
+
+-(void)mouseUp: (NSEvent *)pEvent
+{
+ /* check if button goes up inside one of our status buttons */
+ if( AquaSalMenu::pCurrentMenuBar )
+ {
+ const std::vector< AquaSalMenu::MenuBarButtonEntry >& rButtons( AquaSalMenu::pCurrentMenuBar->getButtons() );
+ NSRect aFrame = [self frame];
+ NSRect aImgRect = { { 2, 0 }, { 0, 0 } };
+ NSPoint aMousePt = [pEvent locationInWindow];
+ for( size_t i = 0; i < rButtons.size(); ++i )
+ {
+ NSRect aFromRect = { { 0, 0 },
+ { rButtons[i].maButton.maImage.GetSizePixel().Width(),
+ rButtons[i].maButton.maImage.GetSizePixel().Height() } };
+ aImgRect.origin.y = (aFrame.size.height - aFromRect.size.height)/2;
+ aImgRect.size = aFromRect.size;
+ if( aMousePt.x >= aImgRect.origin.x && aMousePt.x <= (aImgRect.origin.x+aImgRect.size.width) &&
+ aMousePt.y >= aImgRect.origin.y && aMousePt.y <= (aImgRect.origin.y+aImgRect.size.height) )
+ {
+ if( AquaSalMenu::pCurrentMenuBar->mpFrame && AquaSalFrame::isAlive( AquaSalMenu::pCurrentMenuBar->mpFrame ) )
+ {
+ SalMenuEvent aMenuEvt( rButtons[i].maButton.mnId, AquaSalMenu::pCurrentMenuBar->mpVCLMenu );
+ AquaSalMenu::pCurrentMenuBar->mpFrame->CallCallback(SALEVENT_MENUBUTTONCOMMAND, &aMenuEvt);
+ }
+ return;
+ }
+
+ aImgRect.origin.x += aFromRect.size.width + 2;
+ }
+ }
+}
+
+-(void)layout
+{
+ NSStatusBar* pStatBar = [NSStatusBar systemStatusBar];
+ NSSize aSize = { 0, [pStatBar thickness] };
+ [self removeAllToolTips];
+ if( AquaSalMenu::pCurrentMenuBar )
+ {
+ const std::vector< AquaSalMenu::MenuBarButtonEntry >& rButtons( AquaSalMenu::pCurrentMenuBar->getButtons() );
+ if( ! rButtons.empty() )
+ {
+ aSize.width = 2;
+ for( size_t i = 0; i < rButtons.size(); ++i )
+ {
+ NSRect aImgRect = { { aSize.width, floor((aSize.height-rButtons[i].maButton.maImage.GetSizePixel().Height())/2) },
+ { rButtons[i].maButton.maImage.GetSizePixel().Width(),
+ rButtons[i].maButton.maImage.GetSizePixel().Height() } };
+ if( rButtons[i].mpToolTipString )
+ [self addToolTipRect: aImgRect owner: rButtons[i].mpToolTipString userData: NULL];
+ aSize.width += 2 + aImgRect.size.width;
+ }
+ }
+ }
+ [self setFrameSize: aSize];
+}
+@end
+
+
diff --git a/vcl/aqua/source/window/salobj.cxx b/vcl/aqua/source/window/salobj.cxx
new file mode 100644
index 000000000000..07d337dcc81a
--- /dev/null
+++ b/vcl/aqua/source/window/salobj.cxx
@@ -0,0 +1,239 @@
+/*************************************************************************
+ *
+ * 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 "saldata.hxx"
+#include "salobj.h"
+#include "salframe.h"
+
+// =======================================================================
+
+AquaSalObject::AquaSalObject( AquaSalFrame* pFrame ) :
+ mpFrame( pFrame ),
+ mnClipX( -1 ),
+ mnClipY( -1 ),
+ mnClipWidth( -1 ),
+ mnClipHeight( -1 ),
+ mbClip( false ),
+ mnX( 0 ),
+ mnY( 0 ),
+ mnWidth( 20 ),
+ mnHeight( 20 )
+{
+ maSysData.nSize = sizeof( maSysData );
+ maSysData.pView = NULL;
+
+ NSRect aInitFrame = { { 0, 0 }, { 20, 20 } };
+ mpClipView = [[NSClipView alloc] initWithFrame: aInitFrame ];
+ if( mpClipView )
+ {
+ [mpFrame->getView() addSubview: mpClipView];
+ [mpClipView setHidden: YES];
+ }
+ maSysData.pView = [[NSView alloc] initWithFrame: aInitFrame];
+ if( maSysData.pView )
+ {
+ if( mpClipView )
+ [mpClipView setDocumentView: maSysData.pView];
+ }
+}
+
+// -----------------------------------------------------------------------
+
+AquaSalObject::~AquaSalObject()
+{
+ if( maSysData.pView )
+ {
+ NSView *pView = maSysData.pView;
+ [pView removeFromSuperview];
+ [pView release];
+ }
+ if( mpClipView )
+ {
+ [mpClipView removeFromSuperview];
+ [mpClipView release];
+ }
+}
+
+/*
+ sadly there seems to be no way to impose clipping on a child view,
+ especially a QTMovieView which seems to ignore the current context
+ completely. Also there is no real way to shape a window; on Aqua a
+ similar effect to non-rectangular windows is achieved by using a
+ non-opaque window and not painting where one wants the background
+ to shine through.
+
+ With respect to SalObject this leaves us to having an NSClipView
+ containing the child view. Even a QTMovieView respects the boundaries of
+ that, which gives us a clip "region" consisting of one rectangle.
+ This is gives us an 80% solution only, though.
+*/
+
+// -----------------------------------------------------------------------
+
+void AquaSalObject::ResetClipRegion()
+{
+ mbClip = false;
+ setClippedPosSize();
+}
+
+// -----------------------------------------------------------------------
+
+USHORT AquaSalObject::GetClipRegionType()
+{
+ return SAL_OBJECT_CLIP_INCLUDERECTS;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalObject::BeginSetClipRegion( ULONG nRectCount )
+{
+ mbClip = false;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalObject::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
+{
+ if( mbClip )
+ {
+ if( nX < mnClipX )
+ {
+ mnClipWidth += mnClipX - nX;
+ mnClipX = nX;
+ }
+ if( nX + nWidth > mnClipX + mnClipWidth )
+ mnClipWidth = nX + nWidth - mnClipX;
+ if( nY < mnClipY )
+ {
+ mnClipHeight += mnClipY - nY;
+ mnClipY = nY;
+ }
+ if( nY + nHeight > mnClipY + mnClipHeight )
+ mnClipHeight = nY + nHeight - mnClipY;
+ }
+ else
+ {
+ mnClipX = nX;
+ mnClipY = nY;
+ mnClipWidth = nWidth;
+ mnClipHeight = nHeight;
+ mbClip = true;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalObject::EndSetClipRegion()
+{
+ setClippedPosSize();
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalObject::SetPosSize( long nX, long nY, long nWidth, long nHeight )
+{
+ mnX = nX;
+ mnY = nY;
+ mnWidth = nWidth;
+ mnHeight = nHeight;
+ setClippedPosSize();
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalObject::setClippedPosSize()
+{
+ NSRect aViewRect = { { 0, 0 }, { mnWidth, mnHeight } };
+ if( maSysData.pView )
+ {
+ NSView *pView = maSysData.pView;
+ [pView setFrame: aViewRect];
+ }
+
+ NSRect aClipViewRect = { { mnX, mnY }, { mnWidth, mnHeight } };
+ NSPoint aClipPt = { 0, 0 };
+ if( mbClip )
+ {
+ aClipViewRect.origin.x += mnClipX;
+ aClipViewRect.origin.y += mnClipY;
+ aClipViewRect.size.width = mnClipWidth;
+ aClipViewRect.size.height = mnClipHeight;
+ aClipPt.x = mnClipX;
+ if( mnClipY == 0 )
+ aClipPt.y = mnHeight - mnClipHeight;;
+ }
+
+ mpFrame->VCLToCocoa( aClipViewRect, false );
+ [mpClipView setFrame: aClipViewRect];
+
+ [mpClipView scrollToPoint: aClipPt];
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalObject::Show( BOOL bVisible )
+{
+ if( mpClipView )
+ [mpClipView setHidden: (bVisible ? NO : YES)];
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalObject::Enable( BOOL bEnable )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalObject::GrabFocus()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalObject::SetBackground()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalObject::SetBackground( SalColor nSalColor )
+{
+}
+
+// -----------------------------------------------------------------------
+
+const SystemEnvData* AquaSalObject::GetSystemData() const
+{
+ return &maSysData;
+}
+
diff --git a/vcl/inc/cupsmgr.hxx b/vcl/inc/cupsmgr.hxx
new file mode 100644
index 000000000000..b413184f477f
--- /dev/null
+++ b/vcl/inc/cupsmgr.hxx
@@ -0,0 +1,108 @@
+/*************************************************************************
+ *
+ * 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 _PSPRINT_CUPSMGR_HXX_
+#define _PSPRINT_CUPSMGR_HXX_
+
+#include "vcl/printerinfomanager.hxx"
+#include "osl/module.h"
+#include "osl/thread.h"
+#include "osl/mutex.hxx"
+
+namespace psp
+{
+
+class CUPSWrapper;
+class PPDParser;
+
+struct FPtrHash
+{
+ size_t operator()(const FILE* pPtr) const
+ { return (size_t)pPtr; }
+};
+
+class CUPSManager : public PrinterInfoManager
+{
+ CUPSWrapper* m_pCUPSWrapper;
+ std::hash_map< FILE*, rtl::OString, FPtrHash > m_aSpoolFiles;
+ int m_nDests;
+ void* m_pDests;
+ bool m_bNewDests;
+ std::hash_map< rtl::OUString, int, rtl::OUStringHash > m_aCUPSDestMap;
+
+ std::hash_map< rtl::OUString, PPDContext, rtl::OUStringHash > m_aDefaultContexts;
+
+ rtl::OString m_aUser;
+ // this is a security risk, but the CUPS API demands
+ // to deliver a pointer to a static buffer containing
+ // the password, so this cannot be helped
+ rtl::OString m_aPassword;
+
+ osl::Mutex m_aCUPSMutex;
+ oslThread m_aDestThread;
+
+ CUPSManager( CUPSWrapper* );
+ virtual ~CUPSManager();
+
+ virtual void initialize();
+
+ void getOptionsFromDocumentSetup( const JobData& rJob, int& rNumOptions, void** rOptions ) const;
+ void runDests();
+public:
+ // public for stub
+ static void runDestThread(void* pMgr);
+
+ static CUPSManager* tryLoadCUPS();
+
+ const PPDParser* createCUPSParser( const rtl::OUString& rPrinter );
+ // wraps cupsGetPPD, so unlink after use !
+
+ const char* authenticateUser( const char* );
+
+ virtual FILE* startSpool( const rtl::OUString& rPrinterName, bool bQuickCommand );
+ virtual int endSpool( const rtl::OUString& rPrinterName, const rtl::OUString& rJobTitle, FILE* pFile, const JobData& rDocumentJobData );
+ virtual void setupJobContextData( JobData& rData );
+
+ // changes the info about a named printer
+ virtual void changePrinterInfo( const ::rtl::OUString& rPrinter, const PrinterInfo& rNewInfo );
+
+ // check if the printer configuration has changed
+ virtual bool checkPrintersChanged( bool bWait );
+
+ // members for administration (->padmin)
+ // disable for CUPS
+ virtual bool addPrinter( const rtl::OUString& rPrinterName, const ::rtl::OUString& rDriverName );
+ virtual bool removePrinter( const rtl::OUString& rPrinterName, bool bCheckOnly = false );
+ virtual bool writePrinterConfig();
+ virtual bool setDefaultPrinter( const rtl::OUString& rPrinterName );
+
+ virtual bool addOrRemovePossible() const;
+};
+
+} // namespace psp
+
+#endif
diff --git a/vcl/inc/list.h b/vcl/inc/list.h
new file mode 100644
index 000000000000..82fff328681b
--- /dev/null
+++ b/vcl/inc/list.h
@@ -0,0 +1,99 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+/*[]---------------------------------------------------[]*/
+/*| |*/
+/*| Implementation of the list data type |*/
+/*| |*/
+/*| |*/
+/*| Author: Alexander Gelfenbain |*/
+/*[]---------------------------------------------------[]*/
+
+#ifndef __CLIST_H
+#define __CLIST_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*
+ * List of void * pointers
+ */
+
+ typedef struct _list *list;
+ typedef void (*list_destructor)(void *);
+
+/*- constructors and a destructor */
+ list listNewEmpty(void);
+#ifdef TEST
+ list listNewCopy(list);
+#endif
+ void listDispose(list);
+ void listSetElementDtor(list, list_destructor); /*- this function will be executed when the element is removed via listRemove() or listClear() */
+
+/*- queries */
+ void * listCurrent(list);
+ int listCount(list);
+ int listIsEmpty(list);
+#ifdef TEST
+ int listAtFirst(list);
+ int listAtLast(list);
+ int listPosition(list); /* Expensive! */
+#endif
+/*- search */
+ int listFind(list, void *); /* Returns true/false */
+
+/*- positioning functions */
+/*- return the number of elements by which the current position in the list changes */
+ int listNext(list);
+ int listSkipForward(list, int n);
+ int listToFirst(list);
+ int listToLast(list);
+ int listPositionAt(list, int n); /* Expensive! */
+
+/*- adding and removing elements */
+ list listAppend(list, void *);
+#ifdef TEST
+ list listPrepend(list, void *);
+ list listInsertAfter(list, void *);
+ list listInsertBefore(list, void *);
+#endif
+ list listRemove(list); /* removes the current element */
+ list listClear(list); /* removes all elements */
+
+#ifdef TEST
+/*- forall */
+ void listForAll(list, void (*f)(void *));
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* __CLIST_H */
diff --git a/vcl/inc/makefile.mk b/vcl/inc/makefile.mk
new file mode 100644
index 000000000000..f1f917284f71
--- /dev/null
+++ b/vcl/inc/makefile.mk
@@ -0,0 +1,49 @@
+#*************************************************************************
+#
+# 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=inc
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+# --- Files --------------------------------------------------------
+# --- Targets -------------------------------------------------------
+
+.INCLUDE : target.mk
+
+.IF "$(ENABLE_PCH)"!=""
+ALLTAR : \
+ $(SLO)$/precompiled.pch \
+ $(SLO)$/precompiled_ex.pch
+
+.ENDIF # "$(ENABLE_PCH)"!=""
+
diff --git a/vcl/inc/pch/precompiled_vcl.cxx b/vcl/inc/pch/precompiled_vcl.cxx
new file mode 100644
index 000000000000..af8e2048bd88
--- /dev/null
+++ b/vcl/inc/pch/precompiled_vcl.cxx
@@ -0,0 +1,29 @@
+/*************************************************************************
+ *
+ * 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"
+
diff --git a/vcl/inc/pch/precompiled_vcl.hxx b/vcl/inc/pch/precompiled_vcl.hxx
new file mode 100644
index 000000000000..37ba36569834
--- /dev/null
+++ b/vcl/inc/pch/precompiled_vcl.hxx
@@ -0,0 +1,33 @@
+/*************************************************************************
+ *
+ * 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): Generated on 2006-09-01 17:50:18.342046
+
+#ifdef PRECOMPILED_HEADERS
+#include <tools/debug.hxx>
+#endif
+
diff --git a/vcl/inc/sft.hxx b/vcl/inc/sft.hxx
new file mode 100644
index 000000000000..88ba2844e1e0
--- /dev/null
+++ b/vcl/inc/sft.hxx
@@ -0,0 +1,630 @@
+/*************************************************************************
+ *
+ * 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 sft.h
+ * @brief Sun Font Tools
+ * @author Alexander Gelfenbain
+ */
+
+/*
+ * If NO_MAPPERS is defined, MapChar() and MapString() and consequently GetTTSimpleCharMetrics()
+ * don't get compiled in. This is done to avoid including a large chunk of code (TranslateXY() from
+ * xlat.c in the projects that don't require it.
+ *
+ * If NO_TYPE3 is defined CreateT3FromTTGlyphs() does not get compiled in.
+ * If NO_TYPE42 is defined Type42-related code is excluded
+ * If NO_TTCR is defined TrueType creation related code is excluded\
+ */
+
+/*
+ * Generated fonts contain an XUID entry in the form of:
+ *
+ * 103 0 T C1 N C2 C3
+ *
+ * 103 - Sun's Adobe assigned XUID number. Contact person: Alexander Gelfenbain <gelf@eng.sun.com>
+ *
+ * T - font type. 0: Type 3, 1: Type 42
+ * C1 - CRC-32 of the entire source TrueType font
+ * N - number of glyphs in the subset
+ * C2 - CRC-32 of the array of glyph IDs used to generate the subset
+ * C3 - CRC-32 of the array of encoding numbers used to generate the subset
+ *
+ */
+
+
+#ifndef __SUBFONT_H
+#define __SUBFONT_H
+
+#ifdef UNX
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+#include <stdio.h>
+
+#include <sal/types.h>
+
+#include <vector>
+
+namespace vcl
+{
+
+/*@{*/
+ typedef sal_Int16 F2Dot14; /**< fixed: 2.14 */
+ typedef sal_Int32 F16Dot16; /**< fixed: 16.16 */
+/*@}*/
+
+ typedef struct {
+ sal_uInt16 s;
+ sal_uInt16 d;
+ } sal_uInt16pair;
+
+/** Return value of OpenTTFont() and CreateT3FromTTGlyphs() */
+ enum SFErrCodes {
+ SF_OK, /**< no error */
+ SF_BADFILE, /**< file not found */
+ SF_FILEIO, /**< file I/O error */
+ SF_MEMORY, /**< memory allocation error */
+ SF_GLYPHNUM, /**< incorrect number of glyphs */
+ SF_BADARG, /**< incorrect arguments */
+ SF_TTFORMAT, /**< incorrect TrueType font format */
+ SF_TABLEFORMAT, /**< incorrect format of a TrueType table */
+ SF_FONTNO /**< incorrect logical font number of a TTC font */
+ };
+
+#ifndef FW_THIN /* WIN32 compilation would conflict */
+/** Value of the weight member of the TTGlobalFontInfo struct */
+ enum WeightClass {
+ FW_THIN = 100, /**< Thin */
+ FW_EXTRALIGHT = 200, /**< Extra-light (Ultra-light) */
+ FW_LIGHT = 300, /**< Light */
+ FW_NORMAL = 400, /**< Normal (Regular) */
+ FW_MEDIUM = 500, /**< Medium */
+ FW_SEMIBOLD = 600, /**< Semi-bold (Demi-bold) */
+ FW_BOLD = 700, /**< Bold */
+ FW_EXTRABOLD = 800, /**< Extra-bold (Ultra-bold) */
+ FW_BLACK = 900 /**< Black (Heavy) */
+ };
+
+/** Value of the width member of the TTGlobalFontInfo struct */
+#ifndef OS2
+ enum WidthClass {
+ FWIDTH_ULTRA_CONDENSED = 1, /**< 50% of normal */
+ FWIDTH_EXTRA_CONDENSED = 2, /**< 62.5% of normal */
+ FWIDTH_CONDENSED = 3, /**< 75% of normal */
+ FWIDTH_SEMI_CONDENSED = 4, /**< 87.5% of normal */
+ FWIDTH_NORMAL = 5, /**< Medium, 100% */
+ FWIDTH_SEMI_EXPANDED = 6, /**< 112.5% of normal */
+ FWIDTH_EXPANDED = 7, /**< 125% of normal */
+ FWIDTH_EXTRA_EXPANDED = 8, /**< 150% of normal */
+ FWIDTH_ULTRA_EXPANDED = 9 /**< 200% of normal */
+ };
+#endif // OS2
+#endif /* FW_THIN */
+
+/** Type of the 'kern' table, stored in _TrueTypeFont::kerntype */
+ enum KernType {
+ KT_NONE = 0, /**< no kern table */
+ KT_APPLE_NEW = 1, /**< new Apple kern table */
+ KT_MICROSOFT = 2 /**< Microsoft table */
+ };
+
+/* Composite glyph flags definition */
+ enum CompositeFlags {
+ ARG_1_AND_2_ARE_WORDS = 1,
+ ARGS_ARE_XY_VALUES = 1<<1,
+ ROUND_XY_TO_GRID = 1<<2,
+ WE_HAVE_A_SCALE = 1<<3,
+ MORE_COMPONENTS = 1<<5,
+ WE_HAVE_AN_X_AND_Y_SCALE = 1<<6,
+ WE_HAVE_A_TWO_BY_TWO = 1<<7,
+ WE_HAVE_INSTRUCTIONS = 1<<8,
+ USE_MY_METRICS = 1<<9,
+ OVERLAP_COMPOUND = 1<<10
+ };
+
+#ifndef NO_TTCR
+/** Flags for TrueType generation */
+ enum TTCreationFlags {
+ TTCF_AutoName = 1, /**< Automatically generate a compact 'name' table.
+ If this flag is not set, name table is generated
+ either from an array of NameRecord structs passed as
+ arguments or if the array is NULL, 'name' table
+ of the generated TrueType file will be a copy
+ of the name table of the original file.
+ If this flag is set the array of NameRecord structs
+ is ignored and a very compact 'name' table is automatically
+ generated. */
+
+ TTCF_IncludeOS2 = 2 /** If this flag is set OS/2 table from the original font will be
+ copied to the subset */
+ };
+#endif
+
+
+
+
+/** Structure used by GetTTSimpleGlyphMetrics() and GetTTSimpleCharMetrics() functions */
+ typedef struct {
+ sal_uInt16 adv; /**< advance width or height */
+ sal_Int16 sb; /**< left or top sidebearing */
+ } TTSimpleGlyphMetrics;
+
+
+
+/** Structure used by the TrueType Creator and GetRawGlyphData() */
+
+ typedef struct {
+ sal_uInt32 glyphID; /**< glyph ID */
+ sal_uInt16 nbytes; /**< number of bytes in glyph data */
+ sal_uInt8 *ptr; /**< pointer to glyph data */
+ sal_uInt16 aw; /**< advance width */
+ sal_Int16 lsb; /**< left sidebearing */
+ sal_uInt16 compflag; /**< 0- if non-composite, 1- otherwise */
+ sal_uInt16 npoints; /**< number of points */
+ sal_uInt16 ncontours; /**< number of contours */
+ /* */
+ sal_uInt32 newID; /**< used internally by the TTCR */
+ } GlyphData;
+
+/** Structure used by the TrueType Creator and CreateTTFromTTGlyphs() */
+ typedef struct {
+ sal_uInt16 platformID; /**< Platform ID */
+ sal_uInt16 encodingID; /**< Platform-specific encoding ID */
+ sal_uInt16 languageID; /**< Language ID */
+ sal_uInt16 nameID; /**< Name ID */
+ sal_uInt16 slen; /**< String length in bytes */
+ sal_uInt8 *sptr; /**< Pointer to string data (not zero-terminated!) */
+ } NameRecord;
+
+
+
+/** Return value of GetTTGlobalFontInfo() */
+
+ typedef struct {
+ char *family; /**< family name */
+ sal_uInt16 *ufamily; /**< family name UCS2 */
+ char *subfamily; /**< subfamily name */
+ sal_uInt16 *usubfamily; /**< subfamily name UCS2 */
+ char *psname; /**< PostScript name */
+ sal_uInt16 macStyle; /**< macstyle bits from 'HEAD' table */
+ int weight; /**< value of WeightClass or 0 if can't be determined */
+ int width; /**< value of WidthClass or 0 if can't be determined */
+ int pitch; /**< 0: proportianal font, otherwise: monospaced */
+ int italicAngle; /**< in counter-clockwise degrees * 65536 */
+ int xMin; /**< global bounding box: xMin */
+ int yMin; /**< global bounding box: yMin */
+ int xMax; /**< global bounding box: xMax */
+ int yMax; /**< global bounding box: yMax */
+ int ascender; /**< typographic ascent. */
+ int descender; /**< typographic descent. */
+ int linegap; /**< typographic line gap.\ Negative values are treated as
+ zero in Win 3.1, System 6 and System 7. */
+ int vascent; /**< typographic ascent for vertical writing mode */
+ int vdescent; /**< typographic descent for vertical writing mode */
+ int typoAscender; /**< OS/2 portable typographic ascender */
+ int typoDescender; /**< OS/2 portable typographic descender */
+ int typoLineGap; /**< OS/2 portable typographc line gap */
+ int winAscent; /**< ascender metric for Windows */
+ int winDescent; /**< descender metric for Windows */
+ int symbolEncoded; /**< 1: MS symbol encoded 0: not symbol encoded */
+ int rangeFlag; /**< if set to 1 Unicode Range flags are applicable */
+ sal_uInt32 ur1; /**< bits 0 - 31 of Unicode Range flags */
+ sal_uInt32 ur2; /**< bits 32 - 63 of Unicode Range flags */
+ sal_uInt32 ur3; /**< bits 64 - 95 of Unicode Range flags */
+ sal_uInt32 ur4; /**< bits 96 - 127 of Unicode Range flags */
+ sal_uInt8 panose[10]; /**< PANOSE classification number */
+ sal_uInt32 typeFlags; /**< type flags (copyright bits + PS-OpenType flag) */
+ } TTGlobalFontInfo;
+
+#define TYPEFLAG_INVALID 0x8000000
+#define TYPEFLAG_COPYRIGHT_MASK 0x000000E
+#define TYPEFLAG_PS_OPENTYPE 0x0010000
+
+/** Structure used by KernGlyphs() */
+ typedef struct {
+ int x; /**< positive: right, negative: left */
+ int y; /**< positive: up, negative: down */
+ } KernData;
+
+
+/** ControlPoint structure used by GetTTGlyphPoints() */
+ typedef struct {
+ sal_uInt32 flags; /**< 00000000 00000000 e0000000 bbbbbbbb */
+ /**< b - byte flags from the glyf array */
+ /**< e == 0 - regular point */
+ /**< e == 1 - end contour */
+ sal_Int16 x; /**< X coordinate in EmSquare units */
+ sal_Int16 y; /**< Y coordinate in EmSquare units */
+ } ControlPoint;
+
+ typedef struct _TrueTypeFont TrueTypeFont;
+
+/**
+ * @defgroup sft Sun Font Tools Exported Functions
+ */
+
+
+/**
+ * Get the number of fonts contained in a TrueType collection
+ * @param fname - file name
+ * @return number of fonts or zero, if file is not a TTC file.
+ * @ingroup sft
+ */
+ int CountTTCFonts(const char* fname);
+
+
+/**
+ * TrueTypeFont constructor.
+ * The font file has to be provided as a memory buffer and length
+ * @param facenum - logical font number within a TTC file. This value is ignored
+ * for TrueType fonts
+ * @return value of SFErrCodes enum
+ * @ingroup sft
+ */
+ int OpenTTFontBuffer(void* pBuffer, sal_uInt32 nLen, sal_uInt32 facenum, TrueTypeFont** ttf); /*FOLD01*/
+#if !defined(WIN32) && !defined(OS2)
+/**
+ * TrueTypeFont constructor.
+ * Reads the font file and allocates the memory for the structure.
+ * on WIN32 the font has to be provided as a memory buffer and length
+ * @param facenum - logical font number within a TTC file. This value is ignored
+ * for TrueType fonts
+ * @return value of SFErrCodes enum
+ * @ingroup sft
+ */
+ int OpenTTFontFile(const char *fname, sal_uInt32 facenum, TrueTypeFont** ttf);
+#endif
+
+/**
+ * TrueTypeFont destructor. Deallocates the memory.
+ * @ingroup sft
+ */
+ void CloseTTFont(TrueTypeFont *);
+
+/**
+ * Extracts TrueType control points, and stores them in an allocated array pointed to
+ * by *pointArray. This function returns the number of extracted points.
+ *
+ * @param ttf pointer to the TrueTypeFont structure
+ * @param glyphID Glyph ID
+ * @param pointArray Return value - address of the pointer to the first element of the array
+ * of points allocated by the function
+ * @return Returns the number of points in *pointArray or -1 if glyphID is
+ * invalid.
+ * @ingroup sft
+ *
+ */
+ int GetTTGlyphPoints(TrueTypeFont *ttf, sal_uInt32 glyphID, ControlPoint **pointArray);
+
+/**
+ * Extracts raw glyph data from the 'glyf' table and returns it in an allocated
+ * GlyphData structure.
+ *
+ * @param ttf pointer to the TrueTypeFont structure
+ * @param glyphID Glyph ID
+ *
+ * @return pointer to an allocated GlyphData structure or NULL if
+ * glyphID is not present in the font
+ * @ingroup sft
+ *
+ */
+ GlyphData *GetTTRawGlyphData(TrueTypeFont *ttf, sal_uInt32 glyphID);
+
+/**
+ * For a specified glyph adds all component glyphs IDs to the list and
+ * return their number. If the glyph is a single glyph it has one component
+ * glyph (which is added to the list) and the function returns 1.
+ * For a composite glyphs it returns the number of component glyphs
+ * and adds all of them to the list.
+ *
+ * @param ttf pointer to the TrueTypeFont structure
+ * @param glyphID Glyph ID
+ * @param glyphlist list of glyphs
+ *
+ * @return number of component glyphs
+ * @ingroup sft
+ *
+ */
+ int GetTTGlyphComponents(TrueTypeFont *ttf, sal_uInt32 glyphID, std::vector< sal_uInt32 >& glyphlist);
+
+/**
+ * Extracts all Name Records from the font and stores them in an allocated
+ * array of NameRecord structs
+ *
+ * @param ttf pointer to the TrueTypeFont struct
+ * @param nr pointer to the array of NameRecord structs
+ *
+ * @return number of NameRecord structs
+ * @ingroup sft
+ */
+
+ int GetTTNameRecords(TrueTypeFont *ttf, NameRecord **nr);
+
+/**
+ * Deallocates previously allocated array of NameRecords.
+ *
+ * @param nr array of NameRecord structs
+ * @param n number of elements in the array
+ *
+ * @ingroup sft
+ */
+ void DisposeNameRecords(NameRecord* nr, int n);
+
+
+#ifndef NO_TYPE3
+/**
+ * Generates a new PostScript Type 3 font and dumps it to <b>outf</b> file.
+ * This functions subsititues glyph 0 for all glyphIDs that are not found in the font.
+ * @param ttf pointer to the TrueTypeFont structure
+ * @param outf the resulting font is written to this stream
+ * @param fname font name for the new font. If it is NULL the PostScript name of the
+ * original font will be used
+ * @param glyphArray pointer to an array of glyphs that are to be extracted from ttf
+ * @param encoding array of encoding values. encoding[i] specifies the position of the glyph
+ * glyphArray[i] in the encoding vector of the resulting Type3 font
+ * @param nGlyphs number of glyph IDs in glyphArray and encoding values in encoding
+ * @param wmode writing mode for the output file: 0 - horizontal, 1 - vertical
+ * @return return the value of SFErrCodes enum
+ * @see SFErrCodes
+ * @ingroup sft
+ *
+ */
+ int CreateT3FromTTGlyphs(TrueTypeFont *ttf, FILE *outf, const char *fname, sal_uInt16 *glyphArray, sal_uInt8 *encoding, int nGlyphs, int wmode);
+#endif
+
+#ifndef NO_TTCR
+/**
+ * Generates a new TrueType font and dumps it to <b>outf</b> file.
+ * This functions subsititues glyph 0 for all glyphIDs that are not found in the font.
+ * @param ttf pointer to the TrueTypeFont structure
+ * @param fname file name for the output TrueType font file
+ * @param glyphArray pointer to an array of glyphs that are to be extracted from ttf. The first
+ * element of this array has to be glyph 0 (default glyph)
+ * @param encoding array of encoding values. encoding[i] specifies character code for
+ * the glyphID glyphArray[i]. Character code 0 usually points to a default
+ * glyph (glyphID 0)
+ * @param nGlyphs number of glyph IDs in glyphArray and encoding values in encoding
+ * @param nNameRecs number of NameRecords for the font, if 0 the name table from the
+ * original font will be used
+ * @param nr array of NameRecords
+ * @param flags or'ed TTCreationFlags
+ * @return return the value of SFErrCodes enum
+ * @see SFErrCodes
+ * @ingroup sft
+ *
+ */
+ int CreateTTFromTTGlyphs(TrueTypeFont *ttf,
+ const char *fname,
+ sal_uInt16 *glyphArray,
+ sal_uInt8 *encoding,
+ int nGlyphs,
+ int nNameRecs,
+ NameRecord *nr,
+ sal_uInt32 flags);
+#endif
+
+#ifndef NO_TYPE42
+/**
+ * Generates a new PostScript Type42 font and dumps it to <b>outf</b> file.
+ * This functions subsititues glyph 0 for all glyphIDs that are not found in the font.
+ * @param ttf pointer to the TrueTypeFont structure
+ * @param outf output stream for a resulting font
+ * @param psname PostScript name of the resulting font
+ * @param glyphArray pointer to an array of glyphs that are to be extracted from ttf. The first
+ * element of this array has to be glyph 0 (default glyph)
+ * @param encoding array of encoding values. encoding[i] specifies character code for
+ * the glyphID glyphArray[i]. Character code 0 usually points to a default
+ * glyph (glyphID 0)
+ * @param nGlyphs number of glyph IDs in glyphArray and encoding values in encoding
+ * @return SF_OK - no errors
+ * SF_GLYPHNUM - too many glyphs (> 255)
+ * SF_TTFORMAT - corrupted TrueType fonts
+ *
+ * @see SFErrCodes
+ * @ingroup sft
+ *
+ */
+ int CreateT42FromTTGlyphs(TrueTypeFont *ttf,
+ FILE *outf,
+ const char *psname,
+ sal_uInt16 *glyphArray,
+ sal_uInt8 *encoding,
+ int nGlyphs);
+#endif
+
+
+/**
+ * Queries glyph metrics. Allocates an array of TTSimpleGlyphMetrics structs and returns it.
+ *
+ * @param ttf pointer to the TrueTypeFont structure
+ * @param glyphArray pointer to an array of glyphs that are to be extracted from ttf
+ * @param nGlyphs number of glyph IDs in glyphArray and encoding values in encoding
+ * @param mode writing mode: 0 - horizontal, 1 - vertical
+ * @ingroup sft
+ *
+ */
+ TTSimpleGlyphMetrics *GetTTSimpleGlyphMetrics(TrueTypeFont *ttf, sal_uInt16 *glyphArray, int nGlyphs, int mode);
+
+#ifndef NO_MAPPERS
+/**
+ * Queries glyph metrics. Allocates an array of TTSimpleGlyphMetrics structs and returns it.
+ * This function behaves just like GetTTSimpleGlyphMetrics() but it takes a range of Unicode
+ * characters instead of an array of glyphs.
+ *
+ * @param ttf pointer to the TrueTypeFont structure
+ * @param firstChar Unicode value of the first character in the range
+ * @param nChars number of Unicode characters in the range
+ * @param mode writing mode: 0 - horizontal, 1 - vertical
+ *
+ * @see GetTTSimpleGlyphMetrics
+ * @ingroup sft
+ *
+ */
+ TTSimpleGlyphMetrics *GetTTSimpleCharMetrics(TrueTypeFont *ttf, sal_uInt16 firstChar, int nChars, int mode);
+
+/**
+ * Maps a Unicode (UCS-2) string to a glyph array. Returns the number of glyphs in the array,
+ * which for TrueType fonts is always the same as the number of input characters.
+ *
+ * @param ttf pointer to the TrueTypeFont structure
+ * @param str pointer to a UCS-2 string
+ * @param nchars number of characters in <b>str</b>
+ * @param glyphArray pointer to the glyph array where glyph IDs are to be recorded.
+ *
+ * @return MapString() returns -1 if the TrueType font has no usable 'cmap' tables.
+ * Otherwise it returns the number of characters processed: <b>nChars</b>
+ *
+ * glyphIDs of TrueType fonts are 2 byte positive numbers. glyphID of 0 denotes a missing
+ * glyph and traditionally defaults to an empty square.
+ * glyphArray should be at least sizeof(sal_uInt16) * nchars bytes long. If glyphArray is NULL
+ * MapString() replaces the UCS-2 characters in str with glyphIDs.
+ * @ingroup sft
+ */
+ int MapString(TrueTypeFont *ttf, sal_uInt16 *str, int nchars, sal_uInt16 *glyphArray, int bvertical);
+
+/**
+ * Maps a Unicode (UCS-2) character to a glyph ID and returns it. Missing glyph has
+ * a glyphID of 0 so this function can be used to test if a character is encoded in the font.
+ *
+ * @param ttf pointer to the TrueTypeFont structure
+ * @param ch Unicode (UCS-2) character
+ * @return glyph ID, if the character is missing in the font, the return value is 0.
+ * @ingroup sft
+ */
+ sal_uInt16 MapChar(TrueTypeFont *ttf, sal_uInt16 ch, int bvertical);
+
+/**
+ * Returns 0 when the font does not substitute vertical glyphs
+ *
+ * @param ttf pointer to the TrueTypeFont structure
+ */
+ int DoesVerticalSubstitution( TrueTypeFont *ttf, int bvertical);
+
+#endif
+
+/**
+ * Returns global font information about the TrueType font.
+ * @see TTGlobalFontInfo
+ *
+ * @param ttf pointer to a TrueTypeFont structure
+ * @param info pointer to a TTGlobalFontInfo structure
+ * @ingroup sft
+ *
+ */
+ void GetTTGlobalFontInfo(TrueTypeFont *ttf, TTGlobalFontInfo *info);
+
+#ifdef TEST5
+/**
+ * Returns kerning information for an array of glyphs.
+ * Kerning is not cumulative.
+ * kern[i] contains kerning information for a pair of glyphs at positions i and i+1
+ *
+ * @param ttf pointer to a TrueTypeFont structure
+ * @param glyphs array of source glyphs
+ * @param nglyphs number of glyphs in the array
+ * @param wmode writing mode: 0 - horizontal, 1 - vertical
+ * @param kern array of KernData structures. It should contain nglyphs-1 elements
+ * @see KernData
+ * @ingroup sft
+ *
+ */
+ void KernGlyphs(TrueTypeFont *ttf, sal_uInt16 *glyphs, int nglyphs, int wmode, KernData *kern);
+#endif
+
+/**
+ * Returns nonzero if font is a symbol encoded font
+ */
+ int CheckSymbolEncoding(TrueTypeFont* ttf);
+
+/**
+ * returns the number of glyphs in a font
+ */
+ int GetTTGlyphCount( TrueTypeFont* ttf );
+
+/**
+ * provide access to the raw data of a SFNT-container's subtable
+ */
+ bool GetSfntTable( TrueTypeFont* ttf, int nSubtableIndex,
+ const sal_uInt8** ppRawBytes, int* pRawLength );
+
+/*- private definitions */ /*FOLD00*/
+
+ struct _TrueTypeFont {
+ sal_uInt32 tag;
+
+ char *fname;
+ sal_Int32 fsize;
+ sal_uInt8 *ptr;
+
+ char *psname;
+ char *family;
+ sal_uInt16 *ufamily;
+ char *subfamily;
+ sal_uInt16 *usubfamily;
+
+ sal_uInt32 ntables;
+ sal_uInt32 *goffsets;
+ sal_uInt32 nglyphs;
+ sal_uInt32 unitsPerEm;
+ sal_uInt32 numberOfHMetrics;
+ sal_uInt32 numOfLongVerMetrics; /* if this number is not 0, font has vertical metrics information */
+ const sal_uInt8* cmap;
+ int cmapType;
+ sal_uInt32 (*mapper)(const sal_uInt8 *, sal_uInt32); /* character to glyphID translation function */
+ const sal_uInt8 **tables; /* array of pointers to raw subtables in SFNT file */
+ sal_uInt32 *tlens; /* array of table lengths */
+ int kerntype; /* Defined in the KernType enum */
+ sal_uInt32 nkern; /* number of kern subtables */
+ const sal_uInt8** kerntables; /* array of pointers to kern subtables */
+ void *pGSubstitution; /* info provided by GSUB for UseGSUB() */
+ };
+
+/* indexes into _TrueTypeFont::tables[] and _TrueTypeFont::tlens[] */
+#define O_maxp 0 /* 'maxp' */
+#define O_glyf 1 /* 'glyf' */
+#define O_head 2 /* 'head' */
+#define O_loca 3 /* 'loca' */
+#define O_name 4 /* 'name' */
+#define O_hhea 5 /* 'hhea' */
+#define O_hmtx 6 /* 'hmtx' */
+#define O_cmap 7 /* 'cmap' */
+#define O_vhea 8 /* 'vhea' */
+#define O_vmtx 9 /* 'vmtx' */
+#define O_OS2 10 /* 'OS/2' */
+#define O_post 11 /* 'post' */
+#define O_kern 12 /* 'kern' */
+#define O_cvt 13 /* 'cvt_' - only used in TT->TT generation */
+#define O_prep 14 /* 'prep' - only used in TT->TT generation */
+#define O_fpgm 15 /* 'fpgm' - only used in TT->TT generation */
+#define O_gsub 16 /* 'GSUB' */
+#define O_CFF 17 /* 'CFF' */
+#define NUM_TAGS 18
+
+} // namespace vcl
+
+#endif /* __SUBFONT_H */
diff --git a/vcl/inc/vcl/ImageListProvider.hxx b/vcl/inc/vcl/ImageListProvider.hxx
new file mode 100644
index 000000000000..5c0640d21ea4
--- /dev/null
+++ b/vcl/inc/vcl/ImageListProvider.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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_IMAGELISTPROVIDER_HXX
+#define _SV_IMAGELISTPROVIDER_HXX
+
+#include <sal/types.h>
+
+namespace com { namespace sun { namespace star { namespace lang { class IllegalArgumentException; }}}}
+
+class ImageList;
+
+
+namespace vcl
+{
+ enum ImageListType
+ {
+ IMAGELISTTYPE_UNKNOWN = 0,
+ HIGHCONTRAST_NO = 1,
+ HIGHCONTRAST_YES = 2
+ };
+
+ /* abstract */ class IImageListProvider
+ {
+ public:
+ virtual ImageList getImageList(ImageListType) SAL_THROW (( com::sun::star::lang::IllegalArgumentException )) = 0;
+ };
+} /* vcl */
+
+#endif /* _SV_IMAGELISTPROVIDER_HXX */
diff --git a/vcl/inc/vcl/abstdlg.hxx b/vcl/inc/vcl/abstdlg.hxx
new file mode 100755
index 000000000000..2fa134af5078
--- /dev/null
+++ b/vcl/inc/vcl/abstdlg.hxx
@@ -0,0 +1,93 @@
+/*************************************************************************
+ *
+ * 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_ABSTDLG_HXX
+#define _VCL_ABSTDLG_HXX
+
+// include ---------------------------------------------------------------
+
+#include <tools/solar.h>
+#include <tools/string.hxx>
+#include <vcl/dllapi.h>
+
+class Window;
+class ResId;
+class Link;
+
+class VCL_DLLPUBLIC VclAbstractDialog
+{
+public:
+ virtual short Execute() = 0;
+ //virtual void Show( BOOL bVisible = TRUE, USHORT nFlags = 0 ) = 0;
+ virtual ~VclAbstractDialog();
+};
+
+class VCL_DLLPUBLIC VclAbstractDialog2
+{
+public:
+ virtual void StartExecuteModal( const Link& rEndDialogHdl ) = 0;
+ virtual long GetResult() = 0;
+ virtual ~VclAbstractDialog2();
+};
+
+class VCL_DLLPUBLIC VclAbstractTerminatedDialog : public VclAbstractDialog
+{
+public:
+ virtual void EndDialog(long nResult =0) = 0;
+};
+
+class VCL_DLLPUBLIC VclAbstractRefreshableDialog : public VclAbstractDialog
+{
+public:
+ virtual void Update() = 0;
+ virtual void Sync() = 0;
+};
+
+class VCL_DLLPUBLIC AbstractPasswordToOpenModifyDialog : public VclAbstractDialog
+{
+public:
+ virtual String GetPasswordToOpen() const = 0;
+ virtual String GetPasswordToModify() const = 0;
+ virtual bool IsRecommendToOpenReadonly() const = 0;
+};
+
+//-------------------------------------------------------------
+
+class VCL_DLLPUBLIC VclAbstractDialogFactory
+{
+public:
+ virtual ~VclAbstractDialogFactory(); // needed for export of vtable
+ static VclAbstractDialogFactory* Create();
+ // nDialogId was previously a ResId without ResMgr; the ResourceId is now
+ // an implementation detail of the factory
+ virtual VclAbstractDialog* CreateVclDialog( Window* pParent, sal_uInt32 nResId ) = 0;
+
+ // creates instance of PasswordToOpenModifyDialog from cui
+ virtual AbstractPasswordToOpenModifyDialog * CreatePasswordToOpenModifyDialog( Window * pParent, sal_uInt16 nMinPasswdLen, sal_uInt16 nMaxPasswdLen, bool bIsPasswordToModify ) = 0;
+};
+
+#endif
+
diff --git a/vcl/inc/vcl/accel.h b/vcl/inc/vcl/accel.h
new file mode 100644
index 000000000000..e726d04e7c99
--- /dev/null
+++ b/vcl/inc/vcl/accel.h
@@ -0,0 +1,59 @@
+/*************************************************************************
+ *
+ * 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_ACCEL_H
+#define _SV_ACCEL_H
+
+#include <vcl/sv.h>
+#ifndef _SV_KEYCOD_HXX
+#include <vcl/keycod.hxx>
+#endif
+
+class Accelerator;
+
+// ------------------
+// - ImplAccelEntry -
+// ------------------
+
+class ImplAccelEntry
+{
+public:
+ USHORT mnId;
+ KeyCode maKeyCode;
+ Accelerator* mpAccel;
+ Accelerator* mpAutoAccel;
+ BOOL mbEnabled;
+};
+
+// -----------------
+// - Hilfemethoden -
+// -----------------
+
+// in KEYCOD.CXX
+void ImplGetKeyCode( KeyFuncType eFunc, USHORT& rCode1, USHORT& rCode2, USHORT& rCode3, USHORT& rCode4 );
+
+#endif // _SV_ACCEL_H
diff --git a/vcl/inc/vcl/accel.hxx b/vcl/inc/vcl/accel.hxx
new file mode 100644
index 000000000000..ad2f03dfd942
--- /dev/null
+++ b/vcl/inc/vcl/accel.hxx
@@ -0,0 +1,128 @@
+/*************************************************************************
+ *
+ * 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_ACCEL_HXX
+#define _SV_ACCEL_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <tools/resid.hxx>
+#include <tools/rc.hxx>
+#include <vcl/keycod.hxx>
+
+class ImplAccelData;
+class ImplAccelEntry;
+
+// ---------------
+// - Accelerator -
+// ---------------
+
+class VCL_DLLPUBLIC Accelerator : public Resource
+{
+ friend class ImplAccelManager;
+
+private:
+ ImplAccelData* mpData;
+ XubString maHelpStr;
+ Link maActivateHdl;
+ Link maDeactivateHdl;
+ Link maSelectHdl;
+
+ // Werden vom AcceleratorManager gesetzt
+ KeyCode maCurKeyCode;
+ USHORT mnCurId;
+ USHORT mnCurRepeat;
+ BOOL mbIsCancel;
+ BOOL* mpDel;
+
+//#if 0 // _SOLAR__PRIVATE
+ SAL_DLLPRIVATE void ImplInit();
+ SAL_DLLPRIVATE void ImplCopyData( ImplAccelData& rAccelData );
+ SAL_DLLPRIVATE void ImplDeleteData();
+ SAL_DLLPRIVATE void ImplInsertAccel( USHORT nItemId, const KeyCode& rKeyCode,
+ BOOL bEnable, Accelerator* pAutoAccel );
+
+ SAL_DLLPRIVATE ImplAccelEntry* ImplGetAccelData( const KeyCode& rKeyCode ) const;
+//#endif
+
+protected:
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+
+public:
+ Accelerator();
+ Accelerator( const Accelerator& rAccel );
+ Accelerator( const ResId& rResId );
+ virtual ~Accelerator();
+
+ virtual void Activate();
+ virtual void Deactivate();
+ virtual void Select();
+
+ void InsertItem( USHORT nItemId, const KeyCode& rKeyCode );
+ void InsertItem( const ResId& rResId );
+ void RemoveItem( USHORT nItemId );
+ void RemoveItem( const KeyCode rKeyCode );
+ void Clear();
+
+ USHORT GetCurItemId() const { return mnCurId; }
+ const KeyCode& GetCurKeyCode() const { return maCurKeyCode; }
+ USHORT GetCurRepeat() const { return mnCurRepeat; }
+ BOOL IsCancel() const { return mbIsCancel; }
+
+ USHORT GetItemCount() const;
+ USHORT GetItemId( USHORT nPos ) const;
+ KeyCode GetItemKeyCode( USHORT nPos ) const;
+ USHORT GetItemId( const KeyCode& rKeyCode ) const;
+ KeyCode GetKeyCode( USHORT nItemId ) const;
+ BOOL IsIdValid( USHORT nItemId ) const;
+ BOOL IsKeyCodeValid( const KeyCode rKeyCode ) const;
+ BOOL Call( const KeyCode& rKeyCode, USHORT nRepeat = 0 );
+
+ void SetAccel( USHORT nItemId, Accelerator* pAccel );
+ Accelerator* GetAccel( USHORT nItemId ) const;
+ void SetAccel( const KeyCode rKeyCode, Accelerator* pAccel );
+ Accelerator* GetAccel( const KeyCode rKeyCode ) const;
+
+ void EnableItem( USHORT nItemId, BOOL bEnable = TRUE );
+ BOOL IsItemEnabled( USHORT nItemId ) const;
+ void EnableItem( const KeyCode rKeyCode, BOOL bEnable = TRUE );
+ BOOL IsItemEnabled( const KeyCode rKeyCode ) const;
+
+ void SetHelpText( const XubString& rHelpText ) { maHelpStr = rHelpText; }
+ const XubString& GetHelpText() const { return maHelpStr; }
+
+ void SetActivateHdl( const Link& rLink ) { maActivateHdl = rLink; }
+ const Link& GetActivateHdl() const { return maActivateHdl; }
+ void SetDeactivateHdl( const Link& rLink ) { maDeactivateHdl = rLink; }
+ const Link& GetDeactivateHdl() const { return maDeactivateHdl; }
+ void SetSelectHdl( const Link& rLink ) { maSelectHdl = rLink; }
+ const Link& GetSelectHdl() const { return maSelectHdl; }
+
+ Accelerator& operator=( const Accelerator& rAccel );
+};
+
+#endif // _SV_ACCEL_HXX
diff --git a/vcl/inc/vcl/accmgr.hxx b/vcl/inc/vcl/accmgr.hxx
new file mode 100644
index 000000000000..a60322eac403
--- /dev/null
+++ b/vcl/inc/vcl/accmgr.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_ACCMGR_HXX
+#define _SV_ACCMGR_HXX
+
+#include <vcl/sv.h>
+
+class ImplAccelList;
+class Accelerator;
+class KeyCode;
+
+// --------------------
+// - ImplAccelManager -
+// --------------------
+
+class ImplAccelManager
+{
+private:
+ ImplAccelList* mpAccelList;
+ ImplAccelList* mpSequenceList;
+
+public:
+ ImplAccelManager()
+ {
+ mpAccelList = NULL;
+ mpSequenceList = NULL;
+ }
+ ~ImplAccelManager();
+
+ BOOL InsertAccel( Accelerator* pAccel );
+ void RemoveAccel( Accelerator* pAccel );
+
+ void EndSequence( BOOL bCancel = FALSE );
+ void FlushAccel() { EndSequence( TRUE ); }
+
+ BOOL IsAccelKey( const KeyCode& rKeyCode, USHORT nRepeat );
+};
+
+#endif // _SV_ACCMGR_HXX
diff --git a/vcl/inc/vcl/alpha.hxx b/vcl/inc/vcl/alpha.hxx
new file mode 100644
index 000000000000..ef48793cf8ce
--- /dev/null
+++ b/vcl/inc/vcl/alpha.hxx
@@ -0,0 +1,111 @@
+/*************************************************************************
+ *
+ * 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_ALPHA_HXX
+#define _SV_ALPHA_HXX
+
+#include <vcl/dllapi.h>
+#include <vcl/bitmap.hxx>
+
+// -------------
+// - AlphaMask -
+// -------------
+
+class ImageList;
+class BitmapEx;
+
+class VCL_DLLPUBLIC AlphaMask : private Bitmap
+{
+ friend class BitmapEx;
+ friend class OutputDevice;
+ friend VCL_DLLPUBLIC SvStream& operator<<( SvStream&, const ImageList& );
+
+private:
+
+ SAL_DLLPRIVATE const Bitmap& ImplGetBitmap() const;
+ SAL_DLLPRIVATE void ImplSetBitmap( const Bitmap& rBitmap );
+
+public:
+
+ AlphaMask();
+ AlphaMask( const Bitmap& rBitmap );
+ AlphaMask( const AlphaMask& rAlphaMask );
+ AlphaMask( const Size& rSizePixel, BYTE* pEraseTransparency = NULL );
+ ~AlphaMask();
+
+ AlphaMask& operator=( const Bitmap& rBitmap );
+ AlphaMask& operator=( const AlphaMask& rAlphaMask ) { return (AlphaMask&) Bitmap::operator=( rAlphaMask ); }
+ BOOL operator!() const { return Bitmap::operator!(); }
+ BOOL operator==( const AlphaMask& rAlphaMask ) const { return Bitmap::operator==( rAlphaMask ); }
+ BOOL operator!=( const AlphaMask& rAlphaMask ) const { return Bitmap::operator!=( rAlphaMask ); }
+
+ const MapMode& GetPrefMapMode() const { return Bitmap::GetPrefMapMode(); }
+ void SetPrefMapMode( const MapMode& rMapMode ) { Bitmap::SetPrefMapMode( rMapMode ); }
+
+ const Size& GetPrefSize() const { return Bitmap::GetPrefSize(); }
+ void SetPrefSize( const Size& rSize ) { Bitmap::SetPrefSize( rSize ); }
+
+ Size GetSizePixel() const { return Bitmap::GetSizePixel(); }
+ void SetSizePixel( const Size& rNewSize ) { Bitmap::SetSizePixel( rNewSize ); }
+
+ ULONG GetSizeBytes() const { return Bitmap::GetSizeBytes(); }
+ ULONG GetChecksum() const { return Bitmap::GetChecksum(); }
+
+ Bitmap GetBitmap() const;
+
+public:
+
+ BOOL Crop( const Rectangle& rRectPixel );
+ BOOL Expand( ULONG nDX, ULONG nDY, BYTE* pInitTransparency = NULL );
+ BOOL CopyPixel( const Rectangle& rRectDst, const Rectangle& rRectSrc, const AlphaMask* pAlphaSrc = NULL );
+ BOOL Erase( BYTE cTransparency );
+ BOOL Invert();
+ BOOL Mirror( ULONG nMirrorFlags );
+ BOOL Scale( const Size& rNewSize, ULONG nScaleFlag = BMP_SCALE_FAST );
+ BOOL Scale( const double& rScaleX, const double& rScaleY, ULONG nScaleFlag = BMP_SCALE_FAST );
+ BOOL Rotate( long nAngle10, BYTE cFillTransparency );
+ BOOL Replace( const Bitmap& rMask, BYTE rReplaceTransparency );
+ BOOL Replace( BYTE cSearchTransparency, BYTE cReplaceTransparency, ULONG nTol = 0UL );
+ BOOL Replace( BYTE* pSearchTransparencies, BYTE* pReplaceTransparencies,
+ ULONG nColorCount, ULONG* pTols = NULL );
+
+public:
+
+ BitmapReadAccess* AcquireReadAccess() { return Bitmap::AcquireReadAccess(); }
+ BitmapWriteAccess* AcquireWriteAccess() { return Bitmap::AcquireWriteAccess(); }
+ void ReleaseAccess( BitmapReadAccess* pAccess );
+
+public:
+
+ BOOL Read( SvStream& rIStm, BOOL bFileHeader = TRUE ) { return Bitmap::Read( rIStm, bFileHeader ); }
+ BOOL Write( SvStream& rOStm, BOOL bCompressed = TRUE, BOOL bFileHeader = TRUE ) const { return Bitmap::Write( rOStm, bCompressed, bFileHeader ); }
+
+ friend VCL_DLLPUBLIC SvStream& operator<<( SvStream& rOStm, const BitmapEx& rBitmapEx );
+ friend VCL_DLLPUBLIC SvStream& operator>>( SvStream& rIStm, BitmapEx& rBitmapEx );
+};
+
+#endif // _SV_ALPHA_HXX
diff --git a/vcl/inc/vcl/animate.hxx b/vcl/inc/vcl/animate.hxx
new file mode 100644
index 000000000000..fc793fc12714
--- /dev/null
+++ b/vcl/inc/vcl/animate.hxx
@@ -0,0 +1,254 @@
+/*************************************************************************
+ *
+ * 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_ANIMATE_HXX
+#define _SV_ANIMATE_HXX
+
+#include <vcl/dllapi.h>
+#include <vcl/timer.hxx>
+#include <vcl/bitmapex.hxx>
+
+// -----------
+// - Defines -
+// -----------
+
+#define ANIMATION_TIMEOUT_ON_CLICK 2147483647L
+
+// ---------
+// - Enums -
+// ---------
+
+enum Disposal
+{
+ DISPOSE_NOT,
+ DISPOSE_BACK,
+ DISPOSE_FULL,
+ DISPOSE_PREVIOUS
+};
+
+enum CycleMode
+{
+ CYCLE_NOT,
+ CYCLE_NORMAL,
+ CYCLE_FALLBACK,
+ CYCLE_REVERS,
+ CYCLE_REVERS_FALLBACK
+};
+
+// -------------------
+// - AnimationBitmap -
+// -------------------
+
+struct VCL_DLLPUBLIC AnimationBitmap
+{
+ BitmapEx aBmpEx;
+ Point aPosPix;
+ Size aSizePix;
+ long nWait;
+ Disposal eDisposal;
+ BOOL bUserInput;
+
+ AnimationBitmap() {}
+ AnimationBitmap( const BitmapEx& rBmpEx, const Point& rPosPix,
+ const Size& rSizePix, long _nWait = 0L,
+ Disposal _eDisposal = DISPOSE_NOT ) :
+ aBmpEx ( rBmpEx ),
+ aPosPix ( rPosPix ),
+ aSizePix ( rSizePix ),
+ nWait ( _nWait ),
+ eDisposal ( _eDisposal ),
+ bUserInput ( FALSE ) {}
+
+ BOOL operator==( const AnimationBitmap& rAnimBmp ) const
+ {
+ return( rAnimBmp.aBmpEx == aBmpEx &&
+ rAnimBmp.aPosPix == aPosPix &&
+ rAnimBmp.aSizePix == aSizePix &&
+ rAnimBmp.nWait == nWait &&
+ rAnimBmp.eDisposal == eDisposal &&
+ rAnimBmp.bUserInput == bUserInput );
+ }
+
+ BOOL operator!=( const AnimationBitmap& rAnimBmp ) const { return !( *this == rAnimBmp ); }
+
+ BOOL IsEqual( const AnimationBitmap& rAnimBmp ) const
+ {
+ return( rAnimBmp.aPosPix == aPosPix &&
+ rAnimBmp.aSizePix == aSizePix &&
+ rAnimBmp.nWait == nWait &&
+ rAnimBmp.eDisposal == eDisposal &&
+ rAnimBmp.bUserInput == bUserInput &&
+ rAnimBmp.aBmpEx.IsEqual( aBmpEx ) );
+ }
+
+ ULONG GetChecksum() const;
+};
+
+// -------------------
+// - AnimationBitmap -
+// -------------------
+
+struct AInfo
+{
+ Bitmap aLastSaveBitmap;
+ Bitmap aBackBitmap;
+ Rectangle aClipRect;
+ Size aLastSaveSize;
+ Point aLastSavePoint;
+ Point aStartOrg;
+ Size aStartSize;
+ OutputDevice* pOutDev;
+ void* pViewData;
+ long nExtraData;
+ BOOL bWithSize;
+ BOOL bPause;
+
+ AInfo() : pOutDev( NULL ),
+ pViewData( NULL ),
+ nExtraData( 0L ),
+ bWithSize( FALSE ),
+ bPause( FALSE ) {}
+};
+
+// -------------------
+// - AnimationBitmap -
+// -------------------
+
+class VCL_DLLPUBLIC Animation
+{
+ SAL_DLLPRIVATE static ULONG mnAnimCount;
+
+ List maList;
+ List maAInfoList;
+ Link maNotifyLink;
+ BitmapEx maBitmapEx;
+ Timer maTimer;
+ Size maGlobalSize;
+ List* mpViewList;
+ void* mpExtraData;
+ long mnLoopCount;
+ long mnLoops;
+ long mnPos;
+ Disposal meLastDisposal;
+ CycleMode meCycleMode;
+ BOOL mbFirst;
+ BOOL mbIsInAnimation;
+ BOOL mbWithSize;
+ BOOL mbLoopTerminated;
+ BOOL mbIsWaiting;
+
+//#if 0 // _SOLAR__PRIVATE
+
+ SAL_DLLPRIVATE void ImplRestartTimer( ULONG nTimeout );
+ DECL_DLLPRIVATE_LINK( ImplTimeoutHdl, Timer* );
+
+public:
+
+ SAL_DLLPRIVATE static void ImplIncAnimCount() { mnAnimCount++; }
+ SAL_DLLPRIVATE static void ImplDecAnimCount() { mnAnimCount--; }
+ SAL_DLLPRIVATE ULONG ImplGetCurPos() const { return mnPos; }
+
+//#endif
+
+public:
+ Animation();
+ Animation( const Animation& rAnimation );
+ ~Animation();
+
+ Animation& operator=( const Animation& rAnimation );
+ BOOL operator==( const Animation& rAnimation ) const;
+ BOOL operator!=( const Animation& rAnimation ) const { return !(*this==rAnimation); }
+
+ BOOL IsEqual( const Animation& rAnimation ) const;
+
+ BOOL IsEmpty() const;
+ void SetEmpty();
+
+ void Clear();
+
+ BOOL Start( OutputDevice* pOutDev, const Point& rDestPt, long nExtraData = 0,
+ OutputDevice* pFirstFrameOutDev = NULL );
+ BOOL Start( OutputDevice* pOutDev, const Point& rDestPt, const Size& rDestSz, long nExtraData = 0,
+ OutputDevice* pFirstFrameOutDev = NULL );
+ void Stop( OutputDevice* pOutDev = NULL, long nExtraData = 0 );
+
+ void Draw( OutputDevice* pOutDev, const Point& rDestPt ) const;
+ void Draw( OutputDevice* pOutDev, const Point& rDestPt, const Size& rDestSz ) const;
+
+ BOOL IsInAnimation() const { return mbIsInAnimation; }
+ BOOL IsTransparent() const;
+ BOOL IsTerminated() const { return mbLoopTerminated; }
+
+ const Size& GetDisplaySizePixel() const { return maGlobalSize; }
+ void SetDisplaySizePixel( const Size& rSize ) { maGlobalSize = rSize; }
+
+ const BitmapEx& GetBitmapEx() const { return maBitmapEx; }
+ void SetBitmapEx( const BitmapEx& rBmpEx ) { maBitmapEx = rBmpEx; }
+
+ ULONG GetLoopCount() const { return mnLoopCount; }
+ void SetLoopCount( const ULONG nLoopCount );
+ void ResetLoopCount();
+
+ void SetCycleMode( CycleMode eMode );
+ CycleMode GetCycleMode() const { return meCycleMode; }
+
+ void SetNotifyHdl( const Link& rLink ) { maNotifyLink = rLink; }
+ const Link& GetNotifyHdl() const { return maNotifyLink; }
+
+ USHORT Count() const { return (USHORT) maList.Count(); }
+ BOOL Insert( const AnimationBitmap& rAnimationBitmap );
+ const AnimationBitmap& Get( USHORT nAnimation ) const;
+ void Replace( const AnimationBitmap& rNewAnimationBmp, USHORT nAnimation );
+
+ List* GetAInfoList() { return &maAInfoList; }
+ ULONG GetSizeBytes() const;
+ ULONG GetChecksum() const;
+
+public:
+
+ BOOL Convert( BmpConversion eConversion );
+ BOOL ReduceColors( USHORT nNewColorCount,
+ BmpReduce eReduce = BMP_REDUCE_SIMPLE );
+ BOOL Invert();
+ BOOL Mirror( ULONG nMirrorFlags );
+ BOOL Dither( ULONG nDitherFlags = BMP_DITHER_MATRIX );
+ BOOL Adjust( short nLuminancePercent = 0,
+ short nContrastPercent = 0,
+ short nChannelRPercent = 0,
+ short nChannelGPercent = 0,
+ short nChannelBPercent = 0,
+ double fGamma = 1.0,
+ BOOL bInvert = FALSE );
+ BOOL Filter( BmpFilter eFilter,
+ const BmpFilterParam* pFilterParam = NULL,
+ const Link* pProgress = NULL );
+
+ friend VCL_DLLPUBLIC SvStream& operator>>( SvStream& rIStream, Animation& rAnimation );
+ friend VCL_DLLPUBLIC SvStream& operator<<( SvStream& rOStream, const Animation& rAnimation );
+};
+
+#endif // _SV_ANIMATE_HXX
diff --git a/vcl/inc/vcl/apptypes.hxx b/vcl/inc/vcl/apptypes.hxx
new file mode 100644
index 000000000000..a2d02dcbb066
--- /dev/null
+++ b/vcl/inc/vcl/apptypes.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _VCL_APPTYPES_HXX
+#define _VCL_APPTYPES_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <tools/rtti.hxx>
+
+// ---------------------
+// - Application-Types -
+// ---------------------
+
+#define EXC_RSCNOTLOADED ((USHORT)0x0100)
+#define EXC_SYSOBJNOTCREATED ((USHORT)0x0200)
+#define EXC_SYSTEM ((USHORT)0x0300)
+#define EXC_DISPLAY ((USHORT)0x0400)
+#define EXC_REMOTE ((USHORT)0x0500)
+#define EXC_USER ((USHORT)0x1000)
+#define EXC_MAJORTYPE ((USHORT)0xFF00)
+#define EXC_MINORTYPE ((USHORT)0x00FF)
+
+#define UNIQUEID_SV_BEGIN 64000
+
+class VCL_DLLPUBLIC ApplicationProperty
+{
+public:
+
+ TYPEINFO();
+};
+
+#define INPUT_MOUSE 0x0001
+#define INPUT_KEYBOARD 0x0002
+#define INPUT_PAINT 0x0004
+#define INPUT_TIMER 0x0008
+#define INPUT_OTHER 0x0010
+#define INPUT_APPEVENT 0x0020
+#define INPUT_MOUSEANDKEYBOARD (INPUT_MOUSE | INPUT_KEYBOARD)
+#define INPUT_ANY (INPUT_MOUSEANDKEYBOARD | INPUT_PAINT | INPUT_TIMER | INPUT_OTHER | INPUT_APPEVENT)
+
+#define DISPATCH_OPEN 0x0001
+#define DISPATCH_PRINT 0x0002
+#define DISPATCH_SERVER 0x0004
+
+// --------------
+// - UserActive -
+// --------------
+
+#define USERACTIVE_MOUSEDRAG ((USHORT)0x0001)
+#define USERACTIVE_INPUT ((USHORT)0x0002)
+#define USERACTIVE_MODALDIALOG ((USHORT)0x0004)
+#define USERACTIVE_ALL ((USHORT)0xFFFF)
+
+#endif // _VCL_APPTYPES_HXX
diff --git a/vcl/inc/vcl/arrange.hxx b/vcl/inc/vcl/arrange.hxx
new file mode 100644
index 000000000000..8846d9bbe948
--- /dev/null
+++ b/vcl/inc/vcl/arrange.hxx
@@ -0,0 +1,422 @@
+/*************************************************************************
+ *
+ * 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_ARRANGE_HXX
+#define _VCL_ARRANGE_HXX
+
+#include "vcl/window.hxx"
+
+#include <vector>
+#include <map>
+#include <boost/shared_ptr.hpp>
+
+namespace vcl
+{
+ /* some helper classes for simple window layouting
+ guidelines:
+ - a WindowArranger is not a Window
+ - a WindowArranger hierarchy manages exactly one level of child windows inside a common parent
+ this is to keep the vcl Window hierarchy flat, as some code like accelerators depend on such behavior
+ - a WindowArranger never becomes owner of a Window, windows need to be destroyed separately
+ - a WindowArranger however always is owner of its child WindowArrangers, that is the
+ WindowArranger hierarchy will keep track of its objects and delete them
+ - a managed element of a WindowArranger can either be a Window (a leaf in the hierarchy)
+ or a child WindowArranger (a node in the hierarchy), but never both
+ */
+
+ class WindowArranger
+ {
+ protected:
+ struct Element
+ {
+ Window* m_pElement;
+ boost::shared_ptr<WindowArranger> m_pChild;
+ sal_Int32 m_nExpandPriority;
+ Size m_aMinSize;
+ bool m_bHidden;
+ long m_nLeftBorder;
+ long m_nTopBorder;
+ long m_nRightBorder;
+ long m_nBottomBorder;
+
+ Element()
+ : m_pElement( NULL )
+ , m_pChild()
+ , m_nExpandPriority( 0 )
+ , m_bHidden( false )
+ , m_nLeftBorder( 0 )
+ , m_nTopBorder( 0 )
+ , m_nRightBorder( 0 )
+ , m_nBottomBorder( 0 )
+ {}
+
+ Element( Window* i_pWin,
+ boost::shared_ptr<WindowArranger> const & i_pChild = boost::shared_ptr<WindowArranger>(),
+ sal_Int32 i_nExpandPriority = 0
+ )
+ : m_pElement( i_pWin )
+ , m_pChild( i_pChild )
+ , m_nExpandPriority( i_nExpandPriority )
+ , m_bHidden( false )
+ , m_nLeftBorder( 0 )
+ , m_nTopBorder( 0 )
+ , m_nRightBorder( 0 )
+ , m_nBottomBorder( 0 )
+ {}
+
+ void deleteChild() { m_pChild.reset(); }
+
+ sal_Int32 getExpandPriority() const;
+ Size getOptimalSize( WindowSizeType ) const;
+ bool isVisible() const;
+ void setPosSize( const Point&, const Size& );
+ };
+
+ Window* m_pParentWindow;
+ WindowArranger* m_pParentArranger;
+ Rectangle m_aManagedArea;
+ long m_nOuterBorder;
+
+ virtual Element* getElement( size_t i_nIndex ) = 0;
+ const Element* getConstElement( size_t i_nIndex ) const
+ { return const_cast<WindowArranger*>(this)->getElement( i_nIndex ); }
+
+
+ public:
+ WindowArranger( WindowArranger* i_pParent = NULL )
+ : m_pParentWindow( i_pParent ? i_pParent->m_pParentWindow : NULL )
+ , m_pParentArranger( i_pParent )
+ , m_nOuterBorder( 0 )
+ {}
+ virtual ~WindowArranger();
+
+ // ask what would be the optimal size
+ virtual Size getOptimalSize( WindowSizeType ) const = 0;
+ // call Resize to trigger layouting inside the managed area
+ // without function while parent window is unset
+ virtual void resize() = 0;
+ // avoid this if possible, using the constructor instead
+ // there can be only one parent window and all managed windows MUST
+ // be direct children of that window
+ // violating that condition will result in undefined behavior
+ virtual void setParentWindow( Window* );
+
+ virtual void setParent( WindowArranger* );
+
+ virtual size_t countElements() const = 0;
+ boost::shared_ptr<WindowArranger> getChild( size_t i_nIndex ) const
+ {
+ const Element* pEle = getConstElement( i_nIndex );
+ return pEle ? pEle->m_pChild : boost::shared_ptr<WindowArranger>();
+ }
+ Window* getWindow( size_t i_nIndex ) const
+ {
+ const Element* pEle = getConstElement( i_nIndex );
+ return pEle ? pEle->m_pElement : NULL;
+ }
+
+ virtual bool isVisible() const; // true if any element is visible
+
+ sal_Int32 getExpandPriority( size_t i_nIndex ) const
+ {
+ const Element* pEle = getConstElement( i_nIndex );
+ return pEle ? pEle->getExpandPriority() : 0;
+ }
+
+ Size getMinimumSize( size_t i_nIndex ) const
+ {
+ const Element* pEle = getConstElement( i_nIndex );
+ return pEle ? pEle->m_aMinSize : Size();
+ }
+
+ bool setMinimumSize( size_t i_nIndex, const Size& i_rMinSize )
+ {
+ Element* pEle = getElement( i_nIndex );
+ if( pEle )
+ pEle->m_aMinSize = i_rMinSize;
+ return pEle != NULL;
+ }
+
+ void setBorders( size_t i_nIndex, long i_nLeft, long i_nTop, long i_nRight, long i_nBottom )
+ {
+ Element* pEle = getElement( i_nIndex );
+ if( pEle )
+ {
+ pEle->m_nLeftBorder = i_nLeft;
+ pEle->m_nRightBorder = i_nRight;
+ pEle->m_nTopBorder = i_nTop;
+ pEle->m_nBottomBorder = i_nBottom;
+ }
+ }
+
+ void show( bool i_bShow = true, bool i_bImmediateUpdate = true );
+
+ void setManagedArea( const Rectangle& i_rArea )
+ {
+ m_aManagedArea = i_rArea;
+ resize();
+ }
+ const Rectangle& getManagedArea() const { return m_aManagedArea; }
+
+ void setOuterBorder( long i_nBorder )
+ {
+ m_nOuterBorder = i_nBorder;
+ resize();
+ }
+ };
+
+ class RowOrColumn : public WindowArranger
+ {
+ long m_nBorderWidth;
+ bool m_bColumn;
+
+ std::vector< WindowArranger::Element > m_aElements;
+
+ void distributeRowWidth( std::vector< Size >& io_rSizes, long i_nUsedWidth, long i_nExtraWidth );
+ void distributeColumnHeight( std::vector< Size >& io_rSizes, long i_nUsedHeight, long i_nExtraHeight );
+ protected:
+ virtual Element* getElement( size_t i_nIndex )
+ { return i_nIndex < m_aElements.size() ? &m_aElements[ i_nIndex ] : 0; }
+
+ public:
+ RowOrColumn( WindowArranger* i_pParent = NULL,
+ bool bColumn = true, long i_nBorderWidth = 5 )
+ : WindowArranger( i_pParent )
+ , m_nBorderWidth( i_nBorderWidth )
+ , m_bColumn( bColumn )
+ {}
+
+ virtual ~RowOrColumn();
+
+ virtual Size getOptimalSize( WindowSizeType ) const;
+ virtual void resize();
+ virtual size_t countElements() const { return m_aElements.size(); }
+
+ // add a managed window at the given index
+ // an index smaller than zero means add the window at the end
+ size_t addWindow( Window*, sal_Int32 i_nExpandPrio = 0, size_t i_nIndex = ~0 );
+ void remove( Window* );
+
+ size_t addChild( boost::shared_ptr<WindowArranger> const &, sal_Int32 i_nExpandPrio = 0, size_t i_nIndex = ~0 );
+ // convenience: use for addChild( new WindowArranger( ... ) ) constructs
+ size_t addChild( WindowArranger* i_pNewChild, sal_Int32 i_nExpandPrio = 0, size_t i_nIndex = ~0 )
+ { return addChild( boost::shared_ptr<WindowArranger>( i_pNewChild ), i_nExpandPrio, i_nIndex ); }
+ void remove( boost::shared_ptr<WindowArranger> const & );
+
+ long getBorderWidth() const { return m_nBorderWidth; }
+ };
+
+ class LabeledElement : public WindowArranger
+ {
+ WindowArranger::Element m_aLabel;
+ WindowArranger::Element m_aElement;
+ long m_nDistance;
+ long m_nLabelColumnWidth;
+ int m_nLabelStyle;
+ protected:
+ virtual Element* getElement( size_t i_nIndex )
+ {
+ if( i_nIndex == 0 )
+ return &m_aLabel;
+ else if( i_nIndex == 1 )
+ return &m_aElement;
+ return 0;
+ }
+
+ public:
+ LabeledElement( WindowArranger* i_pParent = NULL, int i_nLabelStyle = 0, long i_nDistance = 5 )
+ : WindowArranger( i_pParent )
+ , m_nDistance( i_nDistance )
+ , m_nLabelColumnWidth( 0 )
+ , m_nLabelStyle( i_nLabelStyle )
+ {}
+
+ virtual ~LabeledElement();
+
+ virtual Size getOptimalSize( WindowSizeType ) const;
+ virtual void resize();
+ virtual size_t countElements() const { return 2; }
+
+ void setLabel( Window* );
+ void setLabel( boost::shared_ptr<WindowArranger> const & );
+ void setElement( Window* );
+ void setElement( boost::shared_ptr<WindowArranger> const & );
+ void setLabelColumnWidth( long i_nWidth )
+ { m_nLabelColumnWidth = i_nWidth; }
+
+ Size getLabelSize( WindowSizeType i_eType ) const
+ { return m_aLabel.getOptimalSize( i_eType ); }
+ Size getElementSize( WindowSizeType i_eType ) const
+ { return m_aElement.getOptimalSize( i_eType ); }
+ };
+
+ class LabelColumn : public RowOrColumn
+ {
+ long getLabelWidth() const;
+ public:
+ LabelColumn( WindowArranger* i_pParent = NULL, long i_nBorderWidth = 5 )
+ : RowOrColumn( i_pParent, true, i_nBorderWidth )
+ {}
+ virtual ~LabelColumn();
+
+ virtual Size getOptimalSize( WindowSizeType ) const;
+ virtual void resize();
+
+ // returns the index of the added label
+ size_t addRow( Window* i_pLabel, boost::shared_ptr<WindowArranger> const& i_rElement, long i_nIndent = 0 );
+ size_t addRow( Window* i_pLabel, Window* i_pElement, long i_nIndent = 0 );
+ };
+
+ class Indenter : public WindowArranger
+ {
+ long m_nIndent;
+ WindowArranger::Element m_aElement;
+
+ protected:
+ virtual Element* getElement( size_t i_nIndex )
+ { return i_nIndex == 0 ? &m_aElement : NULL; }
+
+ public:
+ Indenter( WindowArranger* i_pParent = NULL, long i_nIndent = 15 )
+ : WindowArranger( i_pParent )
+ , m_nIndent( i_nIndent )
+ {}
+
+ virtual ~Indenter();
+
+ virtual Size getOptimalSize( WindowSizeType ) const;
+ virtual void resize();
+ virtual size_t countElements() const { return (m_aElement.m_pElement != 0 || m_aElement.m_pChild != 0) ? 1 : 0; }
+
+ void setIndent( long i_nIndent )
+ {
+ m_nIndent = i_nIndent;
+ resize();
+ }
+
+ void setWindow( Window*, sal_Int32 i_nExpandPrio = 0 );
+ void setChild( boost::shared_ptr<WindowArranger> const &, sal_Int32 i_nExpandPrio = 0 );
+ // convenience: use for setChild( new WindowArranger( ... ) ) constructs
+ void setChild( WindowArranger* i_pChild, sal_Int32 i_nExpandPrio = 0 )
+ { setChild( boost::shared_ptr<WindowArranger>( i_pChild ), i_nExpandPrio ); }
+ };
+
+ class Spacer : public WindowArranger
+ {
+ WindowArranger::Element m_aElement;
+ Size m_aSize;
+
+ protected:
+ virtual Element* getElement( size_t i_nIndex )
+ { return i_nIndex == 0 ? &m_aElement : NULL; }
+
+ public:
+ Spacer( WindowArranger* i_pParent = NULL, sal_Int32 i_nPrio = 20, const Size& i_rSize = Size( 0, 0 ) )
+ : WindowArranger( i_pParent )
+ , m_aElement( NULL, boost::shared_ptr<WindowArranger>(), i_nPrio )
+ , m_aSize( i_rSize )
+ {}
+
+ virtual ~Spacer() {}
+
+ virtual Size getOptimalSize( WindowSizeType ) const
+ { return m_aSize; }
+ virtual void resize() {}
+ virtual void setParentWindow( Window* ) {}
+ virtual size_t countElements() const { return 1; }
+ virtual bool isVisible() const { return true; }
+ };
+
+ class MatrixArranger : public WindowArranger
+ {
+ long m_nBorderX;
+ long m_nBorderY;
+
+ struct MatrixElement : public WindowArranger::Element
+ {
+ sal_uInt32 m_nX;
+ sal_uInt32 m_nY;
+
+ MatrixElement()
+ : WindowArranger::Element()
+ , m_nX( 0 )
+ , m_nY( 0 )
+ {}
+
+ MatrixElement( Window* i_pWin,
+ sal_uInt32 i_nX, sal_uInt32 i_nY,
+ boost::shared_ptr<WindowArranger> const & i_pChild = boost::shared_ptr<WindowArranger>(),
+ sal_Int32 i_nExpandPriority = 0
+ )
+ : WindowArranger::Element( i_pWin, i_pChild, i_nExpandPriority )
+ , m_nX( i_nX )
+ , m_nY( i_nY )
+ {
+ }
+ };
+
+ std::vector< MatrixElement > m_aElements;
+ std::map< sal_uInt64, size_t > m_aMatrixMap; // maps (x | (y << 32)) to index in m_aElements
+
+ sal_uInt64 getMap( sal_uInt32 i_nX, sal_uInt32 i_nY )
+ { return static_cast< sal_uInt64 >(i_nX) | (static_cast< sal_uInt64>(i_nY) << 32 ); }
+
+ Size getOptimalSize( WindowSizeType, std::vector<long>& o_rColumnWidths, std::vector<long>& o_rRowHeights ) const;
+ protected:
+ virtual Element* getElement( size_t i_nIndex )
+ { return i_nIndex < m_aElements.size() ? &m_aElements[ i_nIndex ] : 0; }
+
+ public:
+ MatrixArranger( WindowArranger* i_pParent = NULL,
+ long i_nBorderX = 5,
+ long i_nBorderY = 5 )
+ : WindowArranger( i_pParent )
+ , m_nBorderX( i_nBorderX )
+ , m_nBorderY( i_nBorderY )
+ {}
+
+ virtual ~MatrixArranger();
+
+ virtual Size getOptimalSize( WindowSizeType ) const;
+ virtual void resize();
+ virtual size_t countElements() const { return m_aElements.size(); }
+
+ // add a managed window at the given matrix position
+ size_t addWindow( Window*, sal_uInt32 i_nX, sal_uInt32 i_nY, sal_Int32 i_nExpandPrio = 0 );
+ void remove( Window* );
+
+ size_t addChild( boost::shared_ptr<WindowArranger> const &, sal_uInt32 i_nX, sal_uInt32 i_nY, sal_Int32 i_nExpandPrio = 0 );
+ // convenience: use for addChild( new WindowArranger( ... ) ) constructs
+ size_t addChild( WindowArranger* i_pNewChild, sal_uInt32 i_nX, sal_uInt32 i_nY, sal_Int32 i_nExpandPrio = 0 )
+ { return addChild( boost::shared_ptr<WindowArranger>( i_pNewChild ), i_nX, i_nY, i_nExpandPrio ); }
+ void remove( boost::shared_ptr<WindowArranger> const & );
+ };
+
+}
+
+#endif
+
diff --git a/vcl/inc/vcl/bitmap.hxx b/vcl/inc/vcl/bitmap.hxx
new file mode 100644
index 000000000000..7483f54014a4
--- /dev/null
+++ b/vcl/inc/vcl/bitmap.hxx
@@ -0,0 +1,854 @@
+/*************************************************************************
+ *
+ * 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_BITMAP_HXX
+#define _SV_BITMAP_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/mapmod.hxx>
+#include <tools/rc.hxx>
+#include <vcl/region.hxx>
+
+// -----------
+// - Defines -
+// -----------
+
+#define BMP_MIRROR_NONE 0x00000000UL
+#define BMP_MIRROR_HORZ 0x00000001UL
+#define BMP_MIRROR_VERT 0x00000002UL
+
+// -----------------------------------------------------------------------------
+
+#define BMP_SCALE_NONE 0x00000000UL
+#define BMP_SCALE_FAST 0x00000001UL
+#define BMP_SCALE_INTERPOLATE 0x00000002UL
+
+// -----------------------------------------------------------------------------
+
+#define BMP_DITHER_NONE 0x00000000UL
+#define BMP_DITHER_MATRIX 0x00000001UL
+#define BMP_DITHER_FLOYD 0x00000002UL
+#define BMP_DITHER_FLOYD_16 0x00000004UL
+
+// -----------------------------------------------------------------------------
+
+#define BMP_VECTORIZE_NONE BMP_VECTORIZE_OUTER
+#define BMP_VECTORIZE_INNER 0x00000001UL
+#define BMP_VECTORIZE_OUTER 0x00000002UL
+#define BMP_VECTORIZE_BOUND_ONLY 0x00000004UL
+#define BMP_VECTORIZE_REDUCE_EDGES 0x00000008UL
+
+// -----------------------------------------------------------------------------
+
+#define BMP_COL_TRANS Color( 252, 3, 251 )
+#define BMP_COLOR_MONOCHROME_THRESHOLD 128
+
+// ---------
+// - Enums -
+// ---------
+
+enum BmpConversion
+{
+ BMP_CONVERSION_NONE = 0,
+ BMP_CONVERSION_1BIT_THRESHOLD = 1,
+ BMP_CONVERSION_1BIT_MATRIX = 2,
+ BMP_CONVERSION_4BIT_GREYS = 3,
+ BMP_CONVERSION_4BIT_COLORS = 4,
+ BMP_CONVERSION_8BIT_GREYS = 5,
+ BMP_CONVERSION_8BIT_COLORS = 6,
+ BMP_CONVERSION_24BIT = 7,
+ BMP_CONVERSION_4BIT_TRANS = 8,
+ BMP_CONVERSION_8BIT_TRANS = 9,
+ BMP_CONVERSION_GHOSTED = 10
+};
+
+// ------------------------------------------------------------------------
+
+enum BmpCombine
+{
+ BMP_COMBINE_COPY = 0,
+ BMP_COMBINE_INVERT = 1,
+ BMP_COMBINE_AND = 2,
+ BMP_COMBINE_NAND = 3,
+ BMP_COMBINE_OR = 4,
+ BMP_COMBINE_NOR = 5,
+ BMP_COMBINE_XOR = 6,
+ BMP_COMBINE_NXOR = 7
+};
+
+// ------------------------------------------------------------------------
+
+enum BmpReduce
+{
+ BMP_REDUCE_SIMPLE = 0,
+ BMP_REDUCE_POPULAR = 1,
+ BMP_REDUCE_MEDIAN = 2
+};
+
+// ------------------------------------------------------------------------
+
+enum BmpEmboss
+{
+ BMP_EMBOSS_TOPLEFT = 0,
+ BMP_EMBOSS_TOP = 1,
+ BMP_EMBOSS_TOPRIGHT = 2,
+ BMP_EMBOSS_LEFT = 3,
+ BMP_EMBOSS_MIDDLE = 4,
+ BMP_EMBOSS_RIGHT = 5,
+ BMP_EMBOSS_BOTTOMLEFT = 6,
+ BMP_EMBOSS_BOTTOM = 7,
+ BMP_EMBOSS_BOTTOMRIGHT = 8
+};
+
+// ------------------------------------------------------------------------
+
+enum BmpFilter
+{
+ BMP_FILTER_SMOOTH = 0,
+ BMP_FILTER_SHARPEN = 1,
+ BMP_FILTER_REMOVENOISE = 2,
+ BMP_FILTER_SOBEL_GREY = 3,
+ BMP_FILTER_EMBOSS_GREY = 4,
+ BMP_FILTER_SOLARIZE = 5,
+ BMP_FILTER_SEPIA = 6,
+ BMP_FILTER_MOSAIC = 7,
+ BMP_FILTER_POPART = 8,
+
+ BMP_FILTER_UNKNOWN = 65535
+};
+
+// ------------------------------------------------------------------------
+
+enum BmpColorMode
+{
+ BMP_COLOR_NORMAL = 0,
+ BMP_COLOR_HIGHCONTRAST = 1,
+ BMP_COLOR_MONOCHROME_BLACK = 2,
+ BMP_COLOR_MONOCHROME_WHITE = 3
+};
+
+// --------------------
+// - FilterParameters -
+// --------------------
+
+class VCL_DLLPUBLIC BmpFilterParam
+{
+ friend class Bitmap;
+ friend class BitmapEx;
+ friend class Animation;
+
+private:
+ BmpFilter meFilter;
+ ULONG mnProgressStart;
+ ULONG mnProgressEnd;
+
+public:
+ struct MosaicTileSize
+ {
+ ULONG mnTileWidth;
+ ULONG mnTileHeight;
+ };
+
+ struct EmbossAngles
+ {
+ USHORT mnAzimuthAngle100;
+ USHORT mnElevationAngle100;
+ };
+
+private:
+ union
+ {
+ USHORT mnSepiaPercent;
+ BYTE mcSolarGreyThreshold;
+
+ MosaicTileSize maMosaicTileSize;
+ EmbossAngles maEmbossAngles;
+ };
+
+public:
+
+ BmpFilterParam( ULONG nProgressStart = 0, ULONG nProgressEnd = 0 ) :
+ meFilter( BMP_FILTER_UNKNOWN ), mnProgressStart( nProgressStart ), mnProgressEnd( nProgressEnd ) {}
+
+ BmpFilterParam( BYTE cSolarGreyThreshold, ULONG nProgressStart = 0, ULONG nProgressEnd = 0 ) :
+ meFilter( BMP_FILTER_SOLARIZE ), mnProgressStart( nProgressStart ), mnProgressEnd( nProgressEnd ),
+ mcSolarGreyThreshold( cSolarGreyThreshold ) {}
+
+ BmpFilterParam( USHORT nSepiaPercent, ULONG nProgressStart = 0, ULONG nProgressEnd = 0 ) :
+ meFilter( BMP_FILTER_SEPIA ), mnProgressStart( nProgressStart ), mnProgressEnd( nProgressEnd ),
+ mnSepiaPercent( nSepiaPercent ) {}
+
+ BmpFilterParam( const Size& rMosaicTileSize, ULONG nProgressStart = 0, ULONG nProgressEnd = 0 ) :
+ meFilter( BMP_FILTER_MOSAIC ), mnProgressStart( nProgressStart ), mnProgressEnd( nProgressEnd )
+ {
+ maMosaicTileSize.mnTileWidth = rMosaicTileSize.Width();
+ maMosaicTileSize.mnTileHeight= rMosaicTileSize.Height();
+ }
+ BmpFilterParam( USHORT nEmbossAzimuthAngle100, USHORT nEmbossElevationAngle100,
+ ULONG nProgressStart = 0, ULONG nProgressEnd = 0 ) :
+ meFilter( BMP_FILTER_EMBOSS_GREY ), mnProgressStart( nProgressStart ), mnProgressEnd( nProgressEnd )
+ {
+ maEmbossAngles.mnAzimuthAngle100 = nEmbossAzimuthAngle100;
+ maEmbossAngles.mnElevationAngle100 = nEmbossElevationAngle100;
+ }
+};
+
+// ----------
+// - Bitmap -
+// ----------
+
+class BitmapReadAccess;
+class BitmapWriteAccess;
+class BitmapPalette;
+class ImpBitmap;
+class Color;
+class SvStream;
+struct DIBInfoHeader;
+class ResId;
+class GDIMetaFile;
+class AlphaMask;
+class OutputDevice;
+class SalBitmap;
+
+struct BitmapSystemData
+{
+ #if defined( WNT ) || defined( OS2 )
+ void* pDIB; // device independent byte buffer
+ void* pDDB; // if not NULL then this is actually an HBITMAP
+ #elif defined( QUARTZ )
+ void* rImageContext; //Image context (CGContextRef)
+ #else
+ void* aPixmap;
+ #endif
+ int mnWidth;
+ int mnHeight;
+};
+
+class VCL_DLLPUBLIC Bitmap
+{
+private:
+
+ ImpBitmap* mpImpBmp;
+ MapMode maPrefMapMode;
+ Size maPrefSize;
+
+//#if 0 // _SOLAR__PRIVATE
+
+public:
+
+ SAL_DLLPRIVATE void ImplReleaseRef();
+ SAL_DLLPRIVATE void ImplMakeUnique();
+ ImpBitmap* ImplGetImpBitmap() const;
+ SAL_DLLPRIVATE void ImplSetImpBitmap( ImpBitmap* pImpBmp );
+ SAL_DLLPRIVATE void ImplAssignWithSize( const Bitmap& rBitmap );
+
+ SAL_DLLPRIVATE static BOOL ImplReadDIB( SvStream& rIStm, Bitmap& rBmp, ULONG nOffset );
+ SAL_DLLPRIVATE static BOOL ImplReadDIBFileHeader( SvStream& rIStm, ULONG& rOffset );
+ SAL_DLLPRIVATE static BOOL ImplReadDIBInfoHeader( SvStream& rIStm, DIBInfoHeader& rHeader, sal_Bool& bTopDown );
+ SAL_DLLPRIVATE static BOOL ImplReadDIBPalette( SvStream& rIStm, BitmapWriteAccess& rAcc, BOOL bQuad );
+ SAL_DLLPRIVATE static BOOL ImplReadDIBBits( SvStream& rIStm, DIBInfoHeader& rHeader, BitmapWriteAccess& rAcc, sal_Bool bTopDown );
+ SAL_DLLPRIVATE BOOL ImplWriteDIB( SvStream& rOStm, BitmapReadAccess& rAcc, BOOL bCompressed ) const;
+ SAL_DLLPRIVATE static BOOL ImplWriteDIBFileHeader( SvStream& rOStm, BitmapReadAccess& rAcc );
+ SAL_DLLPRIVATE static BOOL ImplWriteDIBPalette( SvStream& rOStm, BitmapReadAccess& rAcc );
+ SAL_DLLPRIVATE static BOOL ImplWriteDIBBits( SvStream& rOStm, BitmapReadAccess& rAcc,
+ ULONG nCompression, sal_uInt32& rImageSize );
+ SAL_DLLPRIVATE static void ImplDecodeRLE( BYTE* pBuffer, DIBInfoHeader& rHeader,
+ BitmapWriteAccess& rAcc, BOOL bRLE4 );
+ SAL_DLLPRIVATE static BOOL ImplWriteRLE( SvStream& rOStm, BitmapReadAccess& rAcc, BOOL bRLE4 );
+
+ SAL_DLLPRIVATE BOOL ImplScaleFast( const double& rScaleX, const double& rScaleY );
+ SAL_DLLPRIVATE BOOL ImplScaleInterpolate( const double& rScaleX, const double& rScaleY );
+ SAL_DLLPRIVATE BOOL ImplMakeMono( BYTE cThreshold );
+ SAL_DLLPRIVATE BOOL ImplMakeMonoDither();
+ SAL_DLLPRIVATE BOOL ImplMakeGreyscales( USHORT nGreyscales );
+ SAL_DLLPRIVATE BOOL ImplConvertUp( USHORT nBitCount, Color* pExtColor = NULL );
+ SAL_DLLPRIVATE BOOL ImplConvertDown( USHORT nBitCount, Color* pExtColor = NULL );
+ SAL_DLLPRIVATE BOOL ImplConvertGhosted();
+ SAL_DLLPRIVATE BOOL ImplDitherMatrix();
+ SAL_DLLPRIVATE BOOL ImplDitherFloyd();
+ SAL_DLLPRIVATE BOOL ImplDitherFloyd16();
+ SAL_DLLPRIVATE BOOL ImplReduceSimple( USHORT nColorCount );
+ SAL_DLLPRIVATE BOOL ImplReducePopular( USHORT nColorCount );
+ SAL_DLLPRIVATE BOOL ImplReduceMedian( USHORT nColorCount );
+ SAL_DLLPRIVATE void ImplMedianCut( ULONG* pColBuf, BitmapPalette& rPal,
+ long nR1, long nR2, long nG1, long nG2, long nB1, long nB2,
+ long nColors, long nPixels, long& rIndex );
+ SAL_DLLPRIVATE BOOL ImplConvolute3( const long* pMatrix, long nDivisor,
+ const BmpFilterParam* pFilterParam, const Link* pProgress );
+ SAL_DLLPRIVATE BOOL ImplMedianFilter( const BmpFilterParam* pFilterParam, const Link* pProgress );
+ SAL_DLLPRIVATE BOOL ImplSobelGrey( const BmpFilterParam* pFilterParam, const Link* pProgress );
+ SAL_DLLPRIVATE BOOL ImplEmbossGrey( const BmpFilterParam* pFilterParam, const Link* pProgress );
+ SAL_DLLPRIVATE BOOL ImplSolarize( const BmpFilterParam* pFilterParam, const Link* pProgress );
+ SAL_DLLPRIVATE BOOL ImplSepia( const BmpFilterParam* pFilterParam, const Link* pProgress );
+ SAL_DLLPRIVATE BOOL ImplMosaic( const BmpFilterParam* pFilterParam, const Link* pProgress );
+ SAL_DLLPRIVATE BOOL ImplPopArt( const BmpFilterParam* pFilterParam, const Link* pProgress );
+
+//#endif // PRIVATE
+
+public:
+
+ Bitmap();
+ Bitmap( const Bitmap& rBitmap );
+ Bitmap( const Size& rSizePixel, USHORT nBitCount, const BitmapPalette* pPal = NULL );
+ Bitmap( const ResId& rResId );
+ Bitmap( SalBitmap* pSalBitmap );
+ ~Bitmap();
+
+ Bitmap& operator=( const Bitmap& rBitmap );
+ inline BOOL operator!() const;
+ inline BOOL operator==( const Bitmap& rBitmap ) const;
+ inline BOOL operator!=( const Bitmap& rBitmap ) const;
+
+ inline BOOL IsSameInstance( const Bitmap& rBmp ) const;
+ BOOL IsEqual( const Bitmap& rBmp ) const;
+
+ inline BOOL IsEmpty() const;
+ void SetEmpty();
+
+ inline const MapMode& GetPrefMapMode() const;
+ inline void SetPrefMapMode( const MapMode& rMapMode );
+
+ inline const Size& GetPrefSize() const;
+ inline void SetPrefSize( const Size& rSize );
+
+ Size GetSizePixel() const;
+ void SetSizePixel( const Size& rNewSize );
+
+ /**
+ * The pixel size of a bitmap's source (e.g. an image file)
+ * and the pixel size of its resulting bitmap can differ,
+ * e.g. when the image reader has its preview mode enabled.
+ */
+ Size GetSourceSizePixel() const;
+ void SetSourceSizePixel( const Size& );
+
+
+ USHORT GetBitCount() const;
+ inline ULONG GetColorCount() const;
+ inline ULONG GetSizeBytes() const;
+ BOOL HasGreyPalette() const;
+ /** get system dependent bitmap data
+
+ @param rData
+ The system dependent BitmapSystemData structure to be filled
+
+ @return TRUE if the bitmap has a valid system object (e.g. not empty)
+ */
+ bool GetSystemData( BitmapSystemData& rData ) const;
+
+ ULONG GetChecksum() const;
+
+ Bitmap CreateDisplayBitmap( OutputDevice* pDisplay );
+ Bitmap GetColorTransformedBitmap( BmpColorMode eColorMode ) const;
+
+ static const BitmapPalette& GetGreyPalette( int nEntries );
+
+public:
+
+ BOOL MakeMono( BYTE cThreshold );
+
+
+ /** Convert bitmap format
+
+ @param eConversion
+ The format this bitmap should be converted to.
+
+ @return TRUE, if the conversion was completed successfully.
+ */
+ BOOL Convert( BmpConversion eConversion );
+
+ /** Reduce number of colors for the bitmap
+
+ @param nNewColorCount
+ Maximal number of bitmap colors after the reduce operation
+
+ @param eReduce
+ Algorithm to use for color reduction
+
+ @return TRUE, if the color reduction operation was completed successfully.
+ */
+ BOOL ReduceColors( USHORT nNewColorCount,
+ BmpReduce eReduce = BMP_REDUCE_SIMPLE );
+
+ /** Apply a dither algorithm to the bitmap
+
+ This method dithers the bitmap inplace, i.e. a true color
+ bitmap is converted to a paletted bitmap, reducing the color
+ deviation by error diffusion.
+
+ @param nDitherFlags
+ The algorithm to be used for dithering
+
+ @param pDitherPal
+ A custom palette to be used when dithering (not yet implemented, leave NULL)
+ */
+ BOOL Dither( ULONG nDitherFlags = BMP_DITHER_MATRIX );
+
+ /** Crop the bitmap
+
+ @param rRectPixel
+ A rectangle specifying the crop amounts on all four sides of
+ the bitmap. If the upper left corner of the bitmap is assigned
+ (0,0), then this method cuts out the given rectangle from the
+ bitmap. Note that the rectangle is clipped to the bitmap's
+ dimension, i.e. negative left,top rectangle coordinates or
+ exceeding width or height is ignored.
+
+ @return TRUE, if cropping was performed successfully. If
+ nothing had to be cropped, because e.g. the crop rectangle
+ included the bitmap, FALSE is returned, too!
+ */
+ BOOL Crop( const Rectangle& rRectPixel );
+
+ /** Expand the bitmap by pixel padding
+
+ @param nDX
+ Number of pixel to pad at the right border of the bitmap
+
+ @param nDY
+ Number of scanlines to pad at the bottom border of the bitmap
+
+ @param pInitColor
+ Color to use for padded pixel
+
+ @return TRUE, if padding was performed successfully. FALSE is
+ not only returned when the operation failed, but also if
+ nothing had to be done, e.g. because nDX and nDY were zero.
+ */
+ BOOL Expand( ULONG nDX, ULONG nDY,
+ const Color* pInitColor = NULL );
+
+ /** Copy a rectangular area from another bitmap
+
+ @param rRectDst
+ Destination rectangle in this bitmap. This is clipped to the
+ bitmap dimensions.
+
+ @param rRectSrc
+ Source rectangle in pBmpSrc. This is clipped to the source
+ bitmap dimensions. Note further that no scaling takes place
+ during this copy operation, i.e. only the minimum of source
+ and destination rectangle's width and height are used.
+
+ @param pBmpSrc
+ The source bitmap to copy from. If this argument is NULL, or
+ equal to the object this method is called on, copying takes
+ place within the same bitmap.
+
+ @return TRUE, if the operation completed successfully. FALSE
+ is not only returned when the operation failed, but also if
+ nothing had to be done, e.g. because one of the rectangles are
+ empty.
+ */
+ BOOL CopyPixel( const Rectangle& rRectDst,
+ const Rectangle& rRectSrc,
+ const Bitmap* pBmpSrc = NULL );
+
+ /** Perform boolean operations with another bitmap
+
+ @param rMask
+ The mask bitmap in the selected combine operation
+
+ @param eCombine
+ The combine operation to perform on the bitmap
+
+ @return TRUE, if the operation was completed successfully.
+ */
+ BOOL CombineSimple( const Bitmap& rMask,
+ BmpCombine eCombine );
+
+ /** Alpha-blend the given bitmap against a specified uniform
+ background color.
+
+ @attention This method might convert paletted bitmaps to
+ truecolor, to be able to represent every necessary color. Note
+ that during alpha blending, lots of colors not originally
+ included in the bitmap can be generated.
+
+ @param rAlpha
+ Alpha mask to blend with
+
+ @param rBackgroundColor
+ Background color to use for every pixel during alpha blending
+
+ @return TRUE, if blending was successful, FALSE otherwise
+ */
+ BOOL Blend( const AlphaMask& rAlpha,
+ const Color& rBackgroundColor );
+
+ /** Fill the entire bitmap with the given color
+
+ @param rFillColor
+ Color value to use for filling
+
+ @return TRUE, if the operation was completed successfully.
+ */
+ BOOL Erase( const Color& rFillColor );
+
+ /** Perform the Invert operation on every pixel
+
+ @return TRUE, if the operation was completed successfully.
+ */
+ BOOL Invert();
+
+ /** Mirror the bitmap
+
+ @param nMirrorFlags
+ About which axis (horizontal, vertical, or both) to mirror
+
+ @return TRUE, if the operation was completed successfully.
+ */
+ BOOL Mirror( ULONG nMirrorFlags );
+
+ /** Scale the bitmap
+
+ @param rNewSize
+ The resulting size of the scaled bitmap
+
+ @param nScaleFlag
+ The algorithm to be used for scaling
+
+ @return TRUE, if the operation was completed successfully.
+ */
+ BOOL Scale( const Size& rNewSize,
+ ULONG nScaleFlag = BMP_SCALE_FAST );
+
+ /** Scale the bitmap
+
+ @param rScaleX
+ The scale factor in x direction.
+
+ @param rScaleY
+ The scale factor in y direction.
+
+ @return TRUE, if the operation was completed successfully.
+ */
+ BOOL Scale( const double& rScaleX, const double& rScaleY,
+ ULONG nScaleFlag = BMP_SCALE_FAST );
+
+ /** Rotate bitmap by the specified angle
+
+ @param nAngle10
+ The rotation angle in tenth of a degree. The bitmap is always rotated around its center.
+
+ @param rFillColor
+ The color to use for filling blank areas. During rotation, the
+ bitmap is enlarged such that the whole rotation result fits
+ in. The empty spaces around that rotated original bitmap are
+ then filled with this color.
+
+ @return TRUE, if the operation was completed successfully.
+ */
+ BOOL Rotate( long nAngle10, const Color& rFillColor );
+
+ /** Create on-off mask from bitmap
+
+ This method creates a bitmask from the bitmap, where every
+ pixel that equals rTransColor is set transparent, the rest
+ opaque.
+
+ @param rTransColor
+ Color value where the bitmask should be transparent
+
+ @param nTol
+ Tolerance value. Specifies the maximal difference between
+ rTransColor and the individual pixel values, such that the
+ corresponding pixel is still regarded transparent.
+
+ @return the resulting bitmask.
+ */
+ Bitmap CreateMask( const Color& rTransColor, ULONG nTol = 0UL ) const;
+
+ /** Create region of similar colors in a given rectangle
+
+ @param rColor
+ All pixel which have this color are included in the calculated region
+
+ @param rRect
+ The rectangle within which matching pixel are looked for. This
+ rectangle is always clipped to the bitmap dimensions.
+
+ @return the generated region.
+ */
+ Region CreateRegion( const Color& rColor, const Rectangle& rRect ) const;
+
+ /** Replace all pixel where the given mask is on with the specified color
+
+ @param rMask
+ Mask specifying which pixel should be replaced
+
+ @param rReplaceColor
+ Color to be placed in all changed pixel
+
+ @return TRUE, if the operation was completed successfully.
+ */
+ BOOL Replace( const Bitmap& rMask, const Color& rReplaceColor );
+
+ /** Merge bitmap with given background color according to specified alpha mask
+
+ @param rAlpha
+ Alpha mask specifying the amount of background color to merge in
+
+ @param rMergeColor
+ Background color to be used for merging
+
+ @return TRUE, if the operation was completed successfully.
+ */
+ BOOL Replace( const AlphaMask& rAlpha, const Color& rMergeColor );
+
+ /** Replace all pixel having the search color with the specified color
+
+ @param rSearchColor
+ Color specifying which pixel should be replaced
+
+ @param rReplaceColor
+ Color to be placed in all changed pixel
+
+ @param nTol
+ Tolerance value. Specifies the maximal difference between
+ rSearchColor and the individual pixel values, such that the
+ corresponding pixel is still regarded a match.
+
+ @return TRUE, if the operation was completed successfully.
+ */
+ BOOL Replace( const Color& rSearchColor, const Color& rReplaceColor, ULONG nTol = 0 );
+
+ /** Replace all pixel having one the search colors with the corresponding replace color
+
+ @param pSearchColor
+ Array of colors specifying which pixel should be replaced
+
+ @param pReplaceColor
+ Array of colors to be placed in all changed pixel
+
+ @param nColorCount
+ Size of the aforementioned color arrays
+
+ @param nTol
+ Tolerance value. Specifies the maximal difference between
+ pSearchColor colors and the individual pixel values, such that
+ the corresponding pixel is still regarded a match.
+
+ @return TRUE, if the operation was completed successfully.
+ */
+ BOOL Replace( const Color* pSearchColors, const Color* rReplaceColors,
+ ULONG nColorCount, ULONG* pTols = NULL );
+
+ /** Convert the bitmap to a PolyPolygon
+
+ This works by putting continuous areas of the same color into
+ a polygon, by tracing its bounding line.
+
+ @param rPolyPoly
+ The resulting PolyPolygon
+
+ @param nFlags
+ Whether the inline or the outline of the color areas should be
+ represented by the polygon
+
+ @param pProgress
+ A callback for showing the progress of the vectorization
+
+ @return TRUE, if the operation was completed successfully.
+ */
+ BOOL Vectorize( PolyPolygon& rPolyPoly,
+ ULONG nFlags = BMP_VECTORIZE_OUTER,
+ const Link* pProgress = NULL );
+
+ /** Convert the bitmap to a meta file
+
+ This works by putting continuous areas of the same color into
+ polygons painted in this color, by tracing the area's bounding
+ line.
+
+ @param rMtf
+ The resulting meta file
+
+ @param cReduce
+ If non-null, minimal size of bound rects for individual polygons. Smaller ones are ignored.
+
+ @param nFlags
+ Whether the inline or the outline of the color areas should be
+ represented by the polygon
+
+ @param pProgress
+ A callback for showing the progress of the vectorization
+
+ @return TRUE, if the operation was completed successfully.
+ */
+ BOOL Vectorize( GDIMetaFile& rMtf, BYTE cReduce = 0,
+ ULONG nFlags = BMP_VECTORIZE_INNER,
+ const Link* pProgress = NULL );
+
+ /** Change various global color characteristics
+
+ @param nLuminancePercent
+ Percent of luminance change, valid range [-100,100]. Values outside this range are clipped to the valid range.
+
+ @param nContrastPercent
+ Percent of contrast change, valid range [-100,100]. Values outside this range are clipped to the valid range.
+
+ @param nChannelRPercent
+ Percent of red channel change, valid range [-100,100]. Values outside this range are clipped to the valid range.
+
+ @param nChannelGPercent
+ Percent of green channel change, valid range [-100,100]. Values outside this range are clipped to the valid range.
+
+ @param nChannelBPercent
+ Percent of blue channel change, valid range [-100,100]. Values outside this range are clipped to the valid range.
+
+ @param fGamma
+ Exponent of the gamma function applied to the bitmap. The
+ value 1.0 results in no change, the valid range is
+ (0.0,10.0]. Values outside this range are regarded as 1.0.
+
+ @param bInvert
+ If TRUE, invert the channel values with the logical 'not' operator
+
+ @return TRUE, if the operation was completed successfully.
+ */
+ BOOL Adjust( short nLuminancePercent = 0,
+ short nContrastPercent = 0,
+ short nChannelRPercent = 0,
+ short nChannelGPercent = 0,
+ short nChannelBPercent = 0,
+ double fGamma = 1.0,
+ BOOL bInvert = FALSE );
+
+ /** Apply specified filter to the bitmap
+
+ @param eFilter
+ The filter algorithm to apply
+
+ @param pFilterParam
+ Various parameter for the different bitmap filter algorithms
+
+ @param pProgress
+ A callback for showing the progress of the vectorization
+
+ @return TRUE, if the operation was completed successfully.
+ */
+ BOOL Filter( BmpFilter eFilter,
+ const BmpFilterParam* pFilterParam = NULL,
+ const Link* pProgress = NULL );
+
+public:
+ BitmapReadAccess* AcquireReadAccess();
+ BitmapWriteAccess* AcquireWriteAccess();
+ void ReleaseAccess( BitmapReadAccess* pAccess );
+
+public:
+
+ BOOL Read( SvStream& rIStm, BOOL bFileHeader = TRUE );
+ BOOL Write( SvStream& rOStm, BOOL bCompressed = TRUE, BOOL bFileHeader = TRUE ) const;
+
+ friend VCL_DLLPUBLIC SvStream& operator>>( SvStream& rIStm, Bitmap& rBitmap );
+ friend VCL_DLLPUBLIC SvStream& operator<<( SvStream& rOStm, const Bitmap& rBitmap );
+};
+
+// -----------
+// - Inlines -
+// -----------
+
+inline BOOL Bitmap::operator!() const
+{
+ return( mpImpBmp == NULL );
+}
+
+// ------------------------------------------------------------------
+
+inline BOOL Bitmap::operator==( const Bitmap& rBitmap ) const
+{
+ return( rBitmap.mpImpBmp == mpImpBmp );
+}
+
+// ------------------------------------------------------------------
+
+inline BOOL Bitmap::operator!=( const Bitmap& rBitmap ) const
+{
+ return( rBitmap.mpImpBmp != mpImpBmp );
+}
+
+// ------------------------------------------------------------------
+
+inline BOOL Bitmap::IsSameInstance( const Bitmap& rBitmap ) const
+{
+ return( rBitmap.mpImpBmp == mpImpBmp );
+}
+
+// ------------------------------------------------------------------
+
+inline BOOL Bitmap::IsEmpty() const
+{
+ return( mpImpBmp == NULL );
+}
+
+// ------------------------------------------------------------------
+
+inline const MapMode& Bitmap::GetPrefMapMode() const
+{
+ return maPrefMapMode;
+}
+
+// ------------------------------------------------------------------
+
+inline void Bitmap::SetPrefMapMode( const MapMode& rMapMode )
+{
+ maPrefMapMode = rMapMode;
+}
+
+// ------------------------------------------------------------------
+
+inline const Size& Bitmap::GetPrefSize() const
+{
+ return maPrefSize;
+}
+
+// ------------------------------------------------------------------
+
+inline void Bitmap::SetPrefSize( const Size& rSize )
+{
+ maPrefSize = rSize;
+}
+
+// ------------------------------------------------------------------
+
+inline ULONG Bitmap::GetColorCount() const
+{
+ return( 1UL << (ULONG) GetBitCount() );
+}
+
+// ------------------------------------------------------------------
+
+inline ULONG Bitmap::GetSizeBytes() const
+{
+ const Size aSizePix( GetSizePixel() );
+ return( ( (ULONG) aSizePix.Width() * aSizePix.Height() * GetBitCount() ) >> 3UL );
+}
+
+#endif // _SV_BITMAP_HXX
diff --git a/vcl/inc/vcl/bitmapex.hxx b/vcl/inc/vcl/bitmapex.hxx
new file mode 100644
index 000000000000..c19e1a9cbc39
--- /dev/null
+++ b/vcl/inc/vcl/bitmapex.hxx
@@ -0,0 +1,400 @@
+/*************************************************************************
+ *
+ * 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_BITMAPEX_HXX
+#define _SV_BITMAPEX_HXX
+
+#include <vcl/dllapi.h>
+#include <vcl/bitmap.hxx>
+#include <vcl/alpha.hxx>
+#include <tools/color.hxx>
+
+// -------------------
+// - TransparentType -
+// -------------------
+
+enum TransparentType
+{
+ TRANSPARENT_NONE,
+ TRANSPARENT_COLOR,
+ TRANSPARENT_BITMAP
+};
+
+// ------------
+// - BitmapEx -
+// ------------
+
+class VCL_DLLPUBLIC BitmapEx
+{
+ friend class ImpGraphic;
+
+private:
+
+ Bitmap aBitmap;
+ Bitmap aMask;
+ Size aBitmapSize;
+ Color aTransparentColor;
+ TransparentType eTransparent;
+ BOOL bAlpha;
+
+public:
+
+//#if 0 // _SOLAR__PRIVATE
+
+ SAL_DLLPRIVATE ImpBitmap* ImplGetBitmapImpBitmap() const { return aBitmap.ImplGetImpBitmap(); }
+ SAL_DLLPRIVATE ImpBitmap* ImplGetMaskImpBitmap() const { return aMask.ImplGetImpBitmap(); }
+
+//#endif // PRIVATE
+
+public:
+
+ BitmapEx();
+ BitmapEx( const ResId& rResId );
+ BitmapEx( const BitmapEx& rBitmapEx );
+ BitmapEx( const BitmapEx& rBitmapEx, Point aSrc, Size aSize );
+ BitmapEx( const Bitmap& rBmp );
+ BitmapEx( const Bitmap& rBmp, const Bitmap& rMask );
+ BitmapEx( const Bitmap& rBmp, const AlphaMask& rAlphaMask );
+ BitmapEx( const Bitmap& rBmp, const Color& rTransparentColor );
+ ~BitmapEx();
+
+ BitmapEx& operator=( const BitmapEx& rBitmapEx );
+ BOOL operator==( const BitmapEx& rBitmapEx ) const;
+ BOOL operator!=( const BitmapEx& rBitmapEx ) const { return !(*this==rBitmapEx); }
+ BOOL operator!() const { return !aBitmap; }
+
+ BOOL IsEqual( const BitmapEx& rBmpEx ) const;
+
+ BOOL IsEmpty() const;
+ void SetEmpty();
+ void Clear();
+
+ void Draw( OutputDevice* pOutDev,
+ const Point& rDestPt ) const;
+ void Draw( OutputDevice* pOutDev,
+ const Point& rDestPt, const Size& rDestSize ) const;
+ void Draw( OutputDevice* pOutDev,
+ const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPtPixel, const Size& rSrcSizePixel ) const;
+
+ BOOL IsTransparent() const;
+ TransparentType GetTransparentType() const { return eTransparent; }
+
+ Bitmap GetBitmap( const Color* pTransReplaceColor = NULL ) const;
+ Bitmap GetMask() const;
+
+ BitmapEx GetColorTransformedBitmapEx( BmpColorMode eColorMode ) const;
+
+ BOOL IsAlpha() const;
+ AlphaMask GetAlpha() const;
+
+ const Size& GetSizePixel() const { return aBitmapSize; }
+ void SetSizePixel( const Size& rNewSize );
+
+ const Size& GetPrefSize() const { return aBitmap.GetPrefSize(); }
+ void SetPrefSize( const Size& rPrefSize ) { aBitmap.SetPrefSize( rPrefSize ); }
+
+ const MapMode& GetPrefMapMode() const { return aBitmap.GetPrefMapMode(); }
+ void SetPrefMapMode( const MapMode& rPrefMapMode ) { aBitmap.SetPrefMapMode( rPrefMapMode ); }
+
+ const Color& GetTransparentColor() const { return aTransparentColor; }
+ void SetTransparentColor( const Color& rColor ) { aTransparentColor = rColor; }
+
+ USHORT GetBitCount() const { return aBitmap.GetBitCount(); }
+ ULONG GetSizeBytes() const;
+ ULONG GetChecksum() const;
+
+public:
+
+ /** Convert bitmap format
+
+ @param eConversion
+ The format this bitmap should be converted to.
+
+ @return TRUE, if the conversion was completed successfully.
+ */
+ BOOL Convert( BmpConversion eConversion );
+
+ /** Reduce number of colors for the bitmap
+
+ @param nNewColorCount
+ Maximal number of bitmap colors after the reduce operation
+
+ @param eReduce
+ Algorithm to use for color reduction
+
+ @return TRUE, if the color reduction operation was completed successfully.
+ */
+ BOOL ReduceColors( USHORT nNewColorCount,
+ BmpReduce eReduce = BMP_REDUCE_SIMPLE );
+
+ /** Apply a dither algorithm to the bitmap
+
+ This method dithers the bitmap inplace, i.e. a true color
+ bitmap is converted to a paletted bitmap, reducing the color
+ deviation by error diffusion.
+
+ @param nDitherFlags
+ The algorithm to be used for dithering
+ */
+ BOOL Dither( ULONG nDitherFlags = BMP_DITHER_MATRIX );
+
+ /** Crop the bitmap
+
+ @param rRectPixel
+ A rectangle specifying the crop amounts on all four sides of
+ the bitmap. If the upper left corner of the bitmap is assigned
+ (0,0), then this method cuts out the given rectangle from the
+ bitmap. Note that the rectangle is clipped to the bitmap's
+ dimension, i.e. negative left,top rectangle coordinates or
+ exceeding width or height is ignored.
+
+ @return TRUE, if cropping was performed successfully. If
+ nothing had to be cropped, because e.g. the crop rectangle
+ included the bitmap, FALSE is returned, too!
+ */
+ BOOL Crop( const Rectangle& rRectPixel );
+
+ /** Expand the bitmap by pixel padding
+
+ @param nDX
+ Number of pixel to pad at the right border of the bitmap
+
+ @param nDY
+ Number of scanlines to pad at the bottom border of the bitmap
+
+ @param pInitColor
+ Color to use for padded pixel
+
+ @return TRUE, if padding was performed successfully. FALSE is
+ not only returned when the operation failed, but also if
+ nothing had to be done, e.g. because nDX and nDY were zero.
+ */
+ BOOL Expand( ULONG nDX, ULONG nDY,
+ const Color* pInitColor = NULL,
+ BOOL bExpandTransparent = FALSE );
+
+ /** Copy a rectangular area from another bitmap
+
+ @param rRectDst
+ Destination rectangle in this bitmap. This is clipped to the
+ bitmap dimensions.
+
+ @param rRectSrc
+ Source rectangle in pBmpSrc. This is clipped to the source
+ bitmap dimensions. Note further that no scaling takes place
+ during this copy operation, i.e. only the minimum of source
+ and destination rectangle's width and height are used.
+
+ @param pBmpSrc
+ The source bitmap to copy from. If this argument is NULL, or
+ equal to the object this method is called on, copying takes
+ place within the same bitmap.
+
+ @return TRUE, if the operation completed successfully. FALSE
+ is not only returned when the operation failed, but also if
+ nothing had to be done, e.g. because one of the rectangles are
+ empty.
+ */
+ BOOL CopyPixel( const Rectangle& rRectDst,
+ const Rectangle& rRectSrc,
+ const BitmapEx* pBmpExSrc = NULL );
+
+ /** Fill the entire bitmap with the given color
+
+ @param rFillColor
+ Color value to use for filling. Set the transparency part of
+ the color to fill the mask.
+
+ @return TRUE, if the operation was completed successfully.
+ */
+ BOOL Erase( const Color& rFillColor );
+
+ /** Perform the Invert operation on every pixel
+
+ @return TRUE, if the operation was completed successfully.
+ */
+ BOOL Invert();
+
+ /** Mirror the bitmap
+
+ @param nMirrorFlags
+ About which axis (horizontal, vertical, or both) to mirror
+
+ @return TRUE, if the operation was completed successfully.
+ */
+ BOOL Mirror( ULONG nMirrorFlags );
+
+ /** Scale the bitmap
+
+ @param rNewSize
+ The resulting size of the scaled bitmap
+
+ @param nScaleFlag
+ The algorithm to be used for scaling
+
+ @return TRUE, if the operation was completed successfully.
+ */
+ BOOL Scale( const Size& rNewSize, ULONG nScaleFlag = BMP_SCALE_FAST );
+
+ /** Scale the bitmap
+
+ @param rScaleX
+ The scale factor in x direction.
+
+ @param rScaleY
+ The scale factor in y direction.
+
+ @return TRUE, if the operation was completed successfully.
+ */
+ BOOL Scale( const double& rScaleX, const double& rScaleY, ULONG nScaleFlag = BMP_SCALE_FAST );
+
+ /** Rotate bitmap by the specified angle
+
+ @param nAngle10
+ The rotation angle in tenth of a degree. The bitmap is always rotated around its center.
+
+ @param rFillColor
+ The color to use for filling blank areas. During rotation, the
+ bitmap is enlarged such that the whole rotation result fits
+ in. The empty spaces around that rotated original bitmap are
+ then filled with this color.
+
+ @return TRUE, if the operation was completed successfully.
+ */
+ BOOL Rotate( long nAngle10, const Color& rFillColor );
+
+ /** Replace all pixel having the search color with the specified color
+
+ @param rSearchColor
+ Color specifying which pixel should be replaced
+
+ @param rReplaceColor
+ Color to be placed in all changed pixel
+
+ @param nTol
+ Tolerance value. Specifies the maximal difference between
+ rSearchColor and the individual pixel values, such that the
+ corresponding pixel is still regarded a match.
+
+ @return TRUE, if the operation was completed successfully.
+ */
+ BOOL Replace( const Color& rSearchColor, const Color& rReplaceColor, ULONG nTol = 0 );
+
+ /** Replace all pixel having one the search colors with the corresponding replace color
+
+ @param pSearchColor
+ Array of colors specifying which pixel should be replaced
+
+ @param pReplaceColor
+ Array of colors to be placed in all changed pixel
+
+ @param nColorCount
+ Size of the aforementioned color arrays
+
+ @param nTol
+ Tolerance value. Specifies the maximal difference between
+ pSearchColor colors and the individual pixel values, such that
+ the corresponding pixel is still regarded a match.
+
+ @return TRUE, if the operation was completed successfully.
+ */
+ BOOL Replace( const Color* pSearchColors, const Color* pReplaceColors,
+ ULONG nColorCount, const ULONG* pTols = NULL );
+
+ /** Change various global color characteristics
+
+ @param nLuminancePercent
+ Percent of luminance change, valid range [-100,100]. Values outside this range are clipped to the valid range.
+
+ @param nContrastPercent
+ Percent of contrast change, valid range [-100,100]. Values outside this range are clipped to the valid range.
+
+ @param nChannelRPercent
+ Percent of red channel change, valid range [-100,100]. Values outside this range are clipped to the valid range.
+
+ @param nChannelGPercent
+ Percent of green channel change, valid range [-100,100]. Values outside this range are clipped to the valid range.
+
+ @param nChannelBPercent
+ Percent of blue channel change, valid range [-100,100]. Values outside this range are clipped to the valid range.
+
+ @param fGamma
+ Exponent of the gamma function applied to the bitmap. The
+ value 1.0 results in no change, the valid range is
+ (0.0,10.0]. Values outside this range are regarded as 1.0.
+
+ @param bInvert
+ If TRUE, invert the channel values with the logical 'not' operator
+
+ @return TRUE, if the operation was completed successfully.
+ */
+ BOOL Adjust( short nLuminancePercent = 0,
+ short nContrastPercent = 0,
+ short nChannelRPercent = 0,
+ short nChannelGPercent = 0,
+ short nChannelBPercent = 0,
+ double fGamma = 1.0,
+ BOOL bInvert = FALSE );
+
+ /** Apply specified filter to the bitmap
+
+ @param eFilter
+ The filter algorithm to apply
+
+ @param pFilterParam
+ Various parameter for the different bitmap filter algorithms
+
+ @param pProgress
+ A callback for showing the progress of the vectorization
+
+ @return TRUE, if the operation was completed successfully.
+ */
+ BOOL Filter( BmpFilter eFilter,
+ const BmpFilterParam* pFilterParam = NULL,
+ const Link* pProgress = NULL );
+
+ /** Get transparency at given position
+
+ @param nX
+ integer X-Position in Bitmap
+
+ @param nY
+ integer Y-Position in Bitmap
+
+ @return transparency value in the range of [0 .. 255] where
+ 0 is not transparent, 255 is fully transparent
+ */
+ sal_uInt8 GetTransparency(sal_Int32 nX, sal_Int32 nY) const;
+
+public:
+
+ friend VCL_DLLPUBLIC SvStream& operator<<( SvStream& rOStm, const BitmapEx& rBitmapEx );
+ friend VCL_DLLPUBLIC SvStream& operator>>( SvStream& rIStm, BitmapEx& rBitmapEx );
+};
+
+#endif // _SV_BITMAPEX_HXX
diff --git a/vcl/inc/vcl/bmpacc.hxx b/vcl/inc/vcl/bmpacc.hxx
new file mode 100644
index 000000000000..f83b4c73a903
--- /dev/null
+++ b/vcl/inc/vcl/bmpacc.hxx
@@ -0,0 +1,545 @@
+/*************************************************************************
+ *
+ * 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_BMPACC_HXX
+#define _SV_BMPACC_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/salbtype.hxx>
+#include <vcl/bitmap.hxx>
+
+//#if 0 // _SOLAR__PRIVATE
+
+// --------------------
+// - Access defines -
+// --------------------
+
+#define DECL_FORMAT_GETPIXEL( Format ) \
+static BitmapColor GetPixelFor##Format( ConstScanline pScanline, long nX, const ColorMask& rMask );
+
+#define DECL_FORMAT_SETPIXEL( Format ) \
+static void SetPixelFor##Format( Scanline pScanline, long nX, const BitmapColor& rBitmapColor, const ColorMask& rMask );
+
+#define DECL_FORMAT( Format ) \
+DECL_FORMAT_GETPIXEL( Format ) \
+DECL_FORMAT_SETPIXEL( Format )
+
+#define IMPL_FORMAT_GETPIXEL( Format ) \
+BitmapColor BitmapReadAccess::GetPixelFor##Format( ConstScanline pScanline, long nX, const ColorMask& rMask )
+
+#define IMPL_FORMAT_GETPIXEL_NOMASK( Format ) \
+BitmapColor BitmapReadAccess::GetPixelFor##Format( ConstScanline pScanline, long nX, const ColorMask& )
+
+#define IMPL_FORMAT_SETPIXEL( Format ) \
+void BitmapReadAccess::SetPixelFor##Format( Scanline pScanline, long nX, const BitmapColor& rBitmapColor, const ColorMask& rMask )
+
+#define IMPL_FORMAT_SETPIXEL_NOMASK( Format ) \
+void BitmapReadAccess::SetPixelFor##Format( Scanline pScanline, long nX, const BitmapColor& rBitmapColor, const ColorMask& )
+
+#define CASE_FORMAT( Format ) \
+case( BMP_FORMAT##Format ): \
+{ \
+ mFncGetPixel = GetPixelFor##Format;\
+ mFncSetPixel = SetPixelFor##Format;\
+} \
+break;
+
+//#endif // __PRIVATE
+
+// --------------------
+// - Access functions -
+// --------------------
+
+typedef BitmapColor (*FncGetPixel)( ConstScanline pScanline, long nX, const ColorMask& rMask );
+typedef void (*FncSetPixel)( Scanline pScanline, long nX, const BitmapColor& rBitmapColor, const ColorMask& rMask );
+
+// --------------------
+// - BitmapReadAccess -
+// --------------------
+
+class VCL_DLLPUBLIC BitmapReadAccess
+{
+ friend class BitmapWriteAccess;
+
+private:
+
+ BitmapReadAccess() {}
+ BitmapReadAccess( const BitmapReadAccess& ) {}
+ BitmapReadAccess& operator=( const BitmapReadAccess& ) { return *this; }
+
+protected:
+ Bitmap maBitmap;
+ BitmapBuffer* mpBuffer;
+ Scanline* mpScanBuf;
+ ColorMask maColorMask;
+ FncGetPixel mFncGetPixel;
+ FncSetPixel mFncSetPixel;
+ BOOL mbModify;
+
+//#if 0 // _SOLAR__PRIVATE
+
+SAL_DLLPRIVATE void ImplCreate( Bitmap& rBitmap );
+SAL_DLLPRIVATE void ImplDestroy();
+SAL_DLLPRIVATE BOOL ImplSetAccessPointers( ULONG nFormat );
+
+public:
+
+SAL_DLLPRIVATE void ImplZeroInitUnusedBits();
+SAL_DLLPRIVATE BitmapBuffer* ImplGetBitmapBuffer() const { return mpBuffer; }
+
+ DECL_FORMAT( _1BIT_MSB_PAL )
+ DECL_FORMAT( _1BIT_LSB_PAL )
+ DECL_FORMAT( _4BIT_MSN_PAL )
+ DECL_FORMAT( _4BIT_LSN_PAL )
+ DECL_FORMAT( _8BIT_PAL )
+ DECL_FORMAT( _8BIT_TC_MASK )
+ DECL_FORMAT( _16BIT_TC_MSB_MASK )
+ DECL_FORMAT( _16BIT_TC_LSB_MASK )
+ DECL_FORMAT( _24BIT_TC_BGR )
+ DECL_FORMAT( _24BIT_TC_RGB )
+ DECL_FORMAT( _24BIT_TC_MASK )
+ DECL_FORMAT( _32BIT_TC_ABGR )
+ DECL_FORMAT( _32BIT_TC_ARGB )
+ DECL_FORMAT( _32BIT_TC_BGRA )
+ DECL_FORMAT( _32BIT_TC_RGBA )
+ DECL_FORMAT( _32BIT_TC_MASK )
+//#endif // __PRIVATE
+
+protected:
+ BitmapReadAccess( Bitmap& rBitmap, BOOL bModify );
+
+ void Flush();
+ void ReAccess( BOOL bModify );
+
+public:
+ BitmapReadAccess( Bitmap& rBitmap );
+ virtual ~BitmapReadAccess();
+
+ inline BOOL operator!() const;
+
+ inline long Width() const;
+ inline long Height() const;
+ inline Point TopLeft() const;
+ inline Point BottomRight() const;
+
+ inline BOOL IsTopDown() const;
+ inline BOOL IsBottomUp() const;
+
+ inline ULONG GetScanlineFormat() const;
+ inline ULONG GetScanlineSize() const;
+
+ inline USHORT GetBitCount() const;
+ inline BitmapColor GetBestMatchingColor( const BitmapColor& rBitmapColor );
+
+ inline Scanline GetBuffer() const;
+ inline Scanline GetScanline( long nY ) const;
+
+ inline BOOL HasPalette() const;
+ inline const BitmapPalette& GetPalette() const;
+ inline USHORT GetPaletteEntryCount() const;
+ inline const BitmapColor& GetPaletteColor( USHORT nColor ) const;
+ inline const BitmapColor& GetBestPaletteColor( const BitmapColor& rBitmapColor ) const;
+ USHORT GetBestPaletteIndex( const BitmapColor& rBitmapColor ) const;
+
+ inline BOOL HasColorMask() const;
+ inline ColorMask& GetColorMask() const;
+
+ inline BitmapColor GetPixelFromData( const BYTE* pData, long nX ) const;
+ inline void SetPixelOnData( BYTE* pData, long nX, const BitmapColor& rBitmapColor );
+ inline BitmapColor GetPixel( long nY, long nX ) const;
+ inline BitmapColor GetColor( long nY, long nX ) const;
+ inline BYTE GetLuminance( long nY, long nX ) const;
+};
+
+// ---------------------
+// - BitmapWriteAccess -
+// ---------------------
+
+class VCL_DLLPUBLIC BitmapWriteAccess : public BitmapReadAccess
+{
+public:
+
+ BitmapWriteAccess( Bitmap& rBitmap );
+ virtual ~BitmapWriteAccess();
+
+ void CopyScanline( long nY, const BitmapReadAccess& rReadAcc );
+ void CopyScanline( long nY, ConstScanline aSrcScanline,
+ ULONG nSrcScanlineFormat, ULONG nSrcScanlineSize );
+
+ void CopyBuffer( const BitmapReadAccess& rReadAcc );
+
+ inline void SetPalette( const BitmapPalette& rPalette );
+ inline void SetPaletteEntryCount( USHORT nCount );
+ inline void SetPaletteColor( USHORT nColor, const BitmapColor& rBitmapColor );
+
+ inline void SetPixel( long nY, long nX, const BitmapColor& rBitmapColor );
+
+ void SetLineColor();
+ void SetLineColor( const Color& rColor );
+ Color GetLineColor() const;
+
+ void SetFillColor();
+ void SetFillColor( const Color& rColor );
+ Color GetFillColor() const;
+
+ void Erase( const Color& rColor );
+
+ void DrawLine( const Point& rStart, const Point& rEnd );
+
+ void FillRect( const Rectangle& rRect );
+ void DrawRect( const Rectangle& rRect );
+
+ void FillPolygon( const Polygon& rPoly );
+ void DrawPolygon( const Polygon& rPoly );
+
+ void FillPolyPolygon( const PolyPolygon& rPoly );
+ void DrawPolyPolygon( const PolyPolygon& rPolyPoly );
+
+private:
+
+ BitmapColor* mpLineColor;
+ BitmapColor* mpFillColor;
+
+ BitmapWriteAccess() {}
+ BitmapWriteAccess( const BitmapWriteAccess& ) : BitmapReadAccess() {}
+ BitmapWriteAccess& operator=( const BitmapWriteAccess& ) { return *this; }
+};
+
+// -------------------
+// - Accessor Helper -
+// -------------------
+
+/** This template handles BitmapAccess the RAII way.
+
+ Please don't use directly, but the ready-made typedefs for
+ BitmapReadAccess and BitmapWriteAccess below.
+ */
+template < class Access > class ScopedBitmapAccess
+{
+public:
+ ScopedBitmapAccess( Access* pAccess,
+ Bitmap& rBitmap ) :
+ mpAccess( pAccess ),
+ mrBitmap( rBitmap )
+ {
+ }
+
+ ~ScopedBitmapAccess()
+ {
+ mrBitmap.ReleaseAccess( mpAccess );
+ }
+
+ Access* get() { return mpAccess; }
+ const Access* get() const { return mpAccess; }
+
+ Access* operator->() { return mpAccess; }
+ const Access* operator->() const { return mpAccess; }
+
+ Access& operator*() { return *mpAccess; }
+ const Access& operator*() const { return *mpAccess; }
+
+private:
+ Access* mpAccess;
+ Bitmap& mrBitmap;
+};
+
+/** This wrapper handles BitmapReadAccess the RAII way.
+
+ Use as follows:
+ Bitmap aBitmap
+ ScopedBitmapReadAccess pReadAccess( aBitmap.AcquireReadAccess(), aBitmap );
+ pReadAccess->SetPixel()...
+
+ @attention for practical reasons, ScopedBitmapReadAccess stores a
+ reference to the provided bitmap, thus, make sure that the bitmap
+ specified at construction time lives at least as long as the
+ ScopedBitmapReadAccess.
+*/
+typedef ScopedBitmapAccess< BitmapReadAccess > ScopedBitmapReadAccess;
+
+/** This wrapper handles BitmapWriteAccess the RAII way.
+
+ Use as follows:
+ Bitmap aBitmap
+ ScopedBitmapWriteAccess pWriteAccess( aBitmap.AcquireWriteAccess(), aBitmap );
+ pWriteAccess->SetPixel()...
+
+ @attention for practical reasons, ScopedBitmapWriteAccess stores a
+ reference to the provided bitmap, thus, make sure that the bitmap
+ specified at construction time lives at least as long as the
+ ScopedBitmapWriteAccess.
+*/
+typedef ScopedBitmapAccess< BitmapWriteAccess > ScopedBitmapWriteAccess;
+
+// -----------
+// - Inlines -
+// -----------
+
+inline BOOL BitmapReadAccess::operator!() const
+{
+ return( mpBuffer == NULL );
+}
+
+// ------------------------------------------------------------------
+
+inline long BitmapReadAccess::Width() const
+{
+ return( mpBuffer ? mpBuffer->mnWidth : 0L );
+}
+
+// ------------------------------------------------------------------
+
+inline long BitmapReadAccess::Height() const
+{
+ return( mpBuffer ? mpBuffer->mnHeight : 0L );
+}
+
+// ------------------------------------------------------------------
+
+inline Point BitmapReadAccess::TopLeft() const
+{
+ return Point();
+}
+
+// ------------------------------------------------------------------
+
+inline Point BitmapReadAccess::BottomRight() const
+{
+ return Point( Width() - 1L, Height() - 1L );
+}
+
+// ------------------------------------------------------------------
+
+inline BOOL BitmapReadAccess::IsTopDown() const
+{
+ DBG_ASSERT( mpBuffer, "Access is not valid!" );
+ return( mpBuffer ? sal::static_int_cast<BOOL>( BMP_SCANLINE_ADJUSTMENT( mpBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN ) : FALSE );
+}
+
+// ------------------------------------------------------------------
+
+inline BOOL BitmapReadAccess::IsBottomUp() const
+{
+ return !IsTopDown();
+}
+
+// ------------------------------------------------------------------
+
+inline ULONG BitmapReadAccess::GetScanlineFormat() const
+{
+ DBG_ASSERT( mpBuffer, "Access is not valid!" );
+ return( mpBuffer ? BMP_SCANLINE_FORMAT( mpBuffer->mnFormat ) : 0UL );
+}
+
+// ------------------------------------------------------------------
+
+inline ULONG BitmapReadAccess::GetScanlineSize() const
+{
+ DBG_ASSERT( mpBuffer, "Access is not valid!" );
+ return( mpBuffer ? mpBuffer->mnScanlineSize : 0UL );
+}
+
+// ------------------------------------------------------------------
+
+inline USHORT BitmapReadAccess::GetBitCount() const
+{
+ DBG_ASSERT( mpBuffer, "Access is not valid!" );
+ return( mpBuffer ? mpBuffer->mnBitCount : 0 );
+}
+
+// ------------------------------------------------------------------
+
+inline BitmapColor BitmapReadAccess::GetBestMatchingColor( const BitmapColor& rBitmapColor )
+{
+ if( HasPalette() )
+ return BitmapColor( (BYTE) GetBestPaletteIndex( rBitmapColor ) );
+ else
+ return rBitmapColor;
+}
+
+// ------------------------------------------------------------------
+
+inline Scanline BitmapReadAccess::GetBuffer() const
+{
+ DBG_ASSERT( mpBuffer, "Access is not valid!" );
+ return( mpBuffer ? mpBuffer->mpBits : NULL );
+}
+
+// ------------------------------------------------------------------
+
+inline Scanline BitmapReadAccess::GetScanline( long nY ) const
+{
+ DBG_ASSERT( mpBuffer, "Access is not valid!" );
+ DBG_ASSERT( nY < mpBuffer->mnHeight, "y-coordinate out of range!" );
+ return( mpBuffer ? mpScanBuf[ nY ] : NULL );
+}
+
+// ------------------------------------------------------------------
+
+inline BOOL BitmapReadAccess::HasPalette() const
+{
+ DBG_ASSERT( mpBuffer, "Access is not valid!" );
+ return( mpBuffer && !!mpBuffer->maPalette );
+}
+
+// ------------------------------------------------------------------
+
+inline const BitmapPalette& BitmapReadAccess::GetPalette() const
+{
+ DBG_ASSERT( mpBuffer, "Access is not valid!" );
+ return mpBuffer->maPalette;
+}
+
+// ------------------------------------------------------------------
+
+inline USHORT BitmapReadAccess::GetPaletteEntryCount() const
+{
+ DBG_ASSERT( HasPalette(), "Bitmap has no palette!" );
+ return( HasPalette() ? mpBuffer->maPalette.GetEntryCount() : 0 );
+}
+
+// ------------------------------------------------------------------
+
+inline const BitmapColor& BitmapReadAccess::GetPaletteColor( USHORT nColor ) const
+{
+ DBG_ASSERT( mpBuffer, "Access is not valid!" );
+ DBG_ASSERT( HasPalette(), "Bitmap has no palette!" );
+ return mpBuffer->maPalette[ nColor ];
+}
+
+// ------------------------------------------------------------------
+
+inline const BitmapColor& BitmapReadAccess::GetBestPaletteColor( const BitmapColor& rBitmapColor ) const
+{
+ return GetPaletteColor( GetBestPaletteIndex( rBitmapColor ) );
+}
+
+// ------------------------------------------------------------------
+
+inline BOOL BitmapReadAccess::HasColorMask() const
+{
+ DBG_ASSERT( mpBuffer, "Access is not valid!" );
+ const ULONG nFormat = BMP_SCANLINE_FORMAT( mpBuffer->mnFormat );
+
+ return( 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 );
+}
+
+// ------------------------------------------------------------------
+
+inline ColorMask& BitmapReadAccess::GetColorMask() const
+{
+ DBG_ASSERT( mpBuffer, "Access is not valid!" );
+ return mpBuffer->maColorMask;
+}
+
+// ------------------------------------------------------------------
+
+inline BitmapColor BitmapReadAccess::GetPixel( long nY, long nX ) const
+{
+ DBG_ASSERT( mpBuffer, "Access is not valid!" );
+ DBG_ASSERT( nX < mpBuffer->mnWidth, "x-coordinate out of range!" );
+ DBG_ASSERT( nY < mpBuffer->mnHeight, "y-coordinate out of range!" );
+ return mFncGetPixel( mpScanBuf[ nY ], nX, maColorMask );
+}
+
+// ------------------------------------------------------------------
+
+inline BitmapColor BitmapReadAccess::GetPixelFromData( const BYTE* pData, long nX ) const
+{
+ DBG_ASSERT( pData, "Access is not valid!" );
+ return mFncGetPixel( pData, nX, maColorMask );
+}
+
+// ------------------------------------------------------------------
+
+inline void BitmapReadAccess::SetPixelOnData( BYTE* pData, long nX, const BitmapColor& rBitmapColor )
+{
+ DBG_ASSERT( pData, "Access is not valid!" );
+ mFncSetPixel( pData, nX, rBitmapColor, maColorMask );
+}
+
+// ------------------------------------------------------------------
+
+inline BitmapColor BitmapReadAccess::GetColor( long nY, long nX ) const
+{
+ if( !!mpBuffer->maPalette )
+ {
+ DBG_ASSERT( mpBuffer, "Access is not valid!" );
+ return mpBuffer->maPalette[ GetPixel( nY, nX ).GetIndex() ];
+ }
+ else
+ return GetPixel( nY, nX );
+}
+
+// ------------------------------------------------------------------
+
+inline BYTE BitmapReadAccess::GetLuminance( long nY, long nX ) const
+{
+ return GetColor( nY, nX ).GetLuminance();
+}
+
+// ------------------------------------------------------------------
+
+inline void BitmapWriteAccess::SetPalette( const BitmapPalette& rPalette )
+{
+ DBG_ASSERT( mpBuffer, "Access is not valid!" );
+ mpBuffer->maPalette = rPalette;
+}
+
+// ------------------------------------------------------------------
+
+inline void BitmapWriteAccess::SetPaletteEntryCount( USHORT nCount )
+{
+ DBG_ASSERT( mpBuffer, "Access is not valid!" );
+ mpBuffer->maPalette.SetEntryCount( nCount );
+}
+
+// ------------------------------------------------------------------
+
+inline void BitmapWriteAccess::SetPaletteColor( USHORT nColor, const BitmapColor& rBitmapColor )
+{
+ DBG_ASSERT( mpBuffer, "Access is not valid!" );
+ DBG_ASSERT( HasPalette(), "Bitmap has no palette!" );
+ mpBuffer->maPalette[ nColor ] = rBitmapColor;
+}
+
+// ------------------------------------------------------------------
+
+inline void BitmapWriteAccess::SetPixel( long nY, long nX, const BitmapColor& rBitmapColor )
+{
+ DBG_ASSERT( mpBuffer, "Access is not valid!" );
+ DBG_ASSERT( nX < mpBuffer->mnWidth, "x-coordinate out of range!" );
+ DBG_ASSERT( nY < mpBuffer->mnHeight, "y-coordinate out of range!" );
+ mFncSetPixel( mpScanBuf[ nY ], nX, rBitmapColor, maColorMask );
+}
+
+#endif // _SV_BMPACC_HXX
diff --git a/vcl/inc/vcl/bmpfast.hxx b/vcl/inc/vcl/bmpfast.hxx
new file mode 100644
index 000000000000..de330704b74f
--- /dev/null
+++ b/vcl/inc/vcl/bmpfast.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_BMPFAST_HXX
+#define _SV_BMPFAST_HXX
+
+class BitmapWriteAccess;
+class BitmapReadAccess;
+struct BitmapBuffer;
+class BitmapColor;
+class Size;
+class Point;
+struct SalTwoRect;
+
+// the bmpfast functions have signatures with good compatibility to
+// their canonic counterparts, which employ the GetPixel/SetPixel methods
+
+bool ImplFastBitmapConversion( BitmapBuffer& rDst, const BitmapBuffer& rSrc,
+ const SalTwoRect& rTwoRect );
+
+bool ImplFastBitmapBlending( BitmapWriteAccess& rDst,
+ const BitmapReadAccess& rSrc, const BitmapReadAccess& rMask,
+ const SalTwoRect& rTwoRect );
+
+bool ImplFastEraseBitmap( BitmapBuffer&, const BitmapColor& );
+
+#endif // _SV_BMPFAST_HXX
diff --git a/vcl/inc/vcl/brdwin.hxx b/vcl/inc/vcl/brdwin.hxx
new file mode 100644
index 000000000000..bf76174150e2
--- /dev/null
+++ b/vcl/inc/vcl/brdwin.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_BRDWIN_HXX
+#define _SV_BRDWIN_HXX
+
+#include <vcl/sv.h>
+#include <vcl/window.hxx>
+
+class ImplBorderWindowView;
+
+// --------------------------
+// - ImplBorderWindow-Types -
+// --------------------------
+
+#define BORDERWINDOW_STYLE_OVERLAP ((USHORT)0x0001)
+#define BORDERWINDOW_STYLE_BORDER ((USHORT)0x0002)
+#define BORDERWINDOW_STYLE_FLOAT ((USHORT)0x0004)
+#define BORDERWINDOW_STYLE_FRAME ((USHORT)0x0008)
+#define BORDERWINDOW_STYLE_APP ((USHORT)0x0010)
+
+#define BORDERWINDOW_HITTEST_TITLE ((USHORT)0x0001)
+#define BORDERWINDOW_HITTEST_LEFT ((USHORT)0x0002)
+#define BORDERWINDOW_HITTEST_MENU ((USHORT)0x0004)
+#define BORDERWINDOW_HITTEST_TOP ((USHORT)0x0008)
+#define BORDERWINDOW_HITTEST_RIGHT ((USHORT)0x0010)
+#define BORDERWINDOW_HITTEST_BOTTOM ((USHORT)0x0020)
+#define BORDERWINDOW_HITTEST_TOPLEFT ((USHORT)0x0040)
+#define BORDERWINDOW_HITTEST_TOPRIGHT ((USHORT)0x0080)
+#define BORDERWINDOW_HITTEST_BOTTOMLEFT ((USHORT)0x0100)
+#define BORDERWINDOW_HITTEST_BOTTOMRIGHT ((USHORT)0x0200)
+#define BORDERWINDOW_HITTEST_CLOSE ((USHORT)0x0400)
+#define BORDERWINDOW_HITTEST_ROLL ((USHORT)0x0800)
+#define BORDERWINDOW_HITTEST_DOCK ((USHORT)0x1000)
+#define BORDERWINDOW_HITTEST_HIDE ((USHORT)0x2000)
+#define BORDERWINDOW_HITTEST_HELP ((USHORT)0x4000)
+#define BORDERWINDOW_HITTEST_PIN ((USHORT)0x8000)
+
+#define BORDERWINDOW_DRAW_TITLE ((USHORT)0x0001)
+#define BORDERWINDOW_DRAW_BORDER ((USHORT)0x0002)
+#define BORDERWINDOW_DRAW_FRAME ((USHORT)0x0004)
+#define BORDERWINDOW_DRAW_CLOSE ((USHORT)0x0008)
+#define BORDERWINDOW_DRAW_ROLL ((USHORT)0x0010)
+#define BORDERWINDOW_DRAW_DOCK ((USHORT)0x0020)
+#define BORDERWINDOW_DRAW_HIDE ((USHORT)0x0040)
+#define BORDERWINDOW_DRAW_HELP ((USHORT)0x0080)
+#define BORDERWINDOW_DRAW_PIN ((USHORT)0x0100)
+#define BORDERWINDOW_DRAW_MENU ((USHORT)0x0200)
+#define BORDERWINDOW_DRAW_ALL (BORDERWINDOW_DRAW_TITLE | \
+ BORDERWINDOW_DRAW_BORDER | \
+ BORDERWINDOW_DRAW_FRAME | \
+ BORDERWINDOW_DRAW_CLOSE | \
+ BORDERWINDOW_DRAW_ROLL | \
+ BORDERWINDOW_DRAW_DOCK | \
+ BORDERWINDOW_DRAW_HIDE | \
+ BORDERWINDOW_DRAW_HELP | \
+ BORDERWINDOW_DRAW_PIN | \
+ BORDERWINDOW_DRAW_MENU)
+
+#define BORDERWINDOW_TITLE_NORMAL ((USHORT)0x0001)
+#define BORDERWINDOW_TITLE_SMALL ((USHORT)0x0002)
+#define BORDERWINDOW_TITLE_TEAROFF ((USHORT)0x0004)
+#define BORDERWINDOW_TITLE_NONE ((USHORT)0x0008)
+
+// --------------------
+// - ImplBorderWindow -
+// --------------------
+
+class ImplBorderWindow : public Window
+{
+ friend class Window;
+ friend class ImplBorderWindowView;
+ friend class ImplSmallBorderWindowView;
+ friend class ImplStdBorderWindowView;
+
+private:
+ ImplBorderWindowView* mpBorderView;
+ Window* mpMenuBarWindow;
+ long mnMinWidth;
+ long mnMinHeight;
+ long mnMaxWidth;
+ long mnMaxHeight;
+ long mnRollHeight;
+ long mnOrgMenuHeight;
+ USHORT mnTitleType;
+ USHORT mnBorderStyle;
+ BOOL mbFloatWindow;
+ BOOL mbSmallOutBorder;
+ BOOL mbFrameBorder;
+ BOOL mbPined;
+ BOOL mbRollUp;
+ BOOL mbMenuHide;
+ BOOL mbDockBtn;
+ BOOL mbHideBtn;
+ BOOL mbHelpBtn;
+ BOOL mbMenuBtn;
+ BOOL mbDisplayActive;
+
+ using Window::ImplInit;
+ void ImplInit( Window* pParent,
+ WinBits nStyle, USHORT nTypeStyle,
+ SystemParentData* pParentData );
+ void ImplInit( Window* pParent,
+ WinBits nStyle, USHORT nTypeStyle,
+ const ::com::sun::star::uno::Any& );
+
+ // Copy assignment is forbidden and not implemented.
+ ImplBorderWindow (const ImplBorderWindow &);
+ ImplBorderWindow& operator= (const ImplBorderWindow &);
+
+public:
+ ImplBorderWindow( Window* pParent,
+ SystemParentData* pParentData,
+ WinBits nStyle = 0,
+ USHORT nTypeStyle = 0 );
+ ImplBorderWindow( Window* pParent, WinBits nStyle = 0,
+ USHORT nTypeStyle = 0 );
+ ImplBorderWindow( Window* pParent,
+ WinBits nStyle, USHORT nTypeStyle,
+ const ::com::sun::star::uno::Any& );
+ ~ImplBorderWindow();
+
+ virtual void MouseMove( const MouseEvent& rMEvt );
+ virtual void MouseButtonDown( const MouseEvent& rMEvt );
+ virtual void Tracking( const TrackingEvent& rTEvt );
+ virtual void Paint( const Rectangle& rRect );
+ virtual void Activate();
+ virtual void Deactivate();
+ virtual void Resize();
+ virtual void RequestHelp( const HelpEvent& rHEvt );
+ virtual void StateChanged( StateChangedType nType );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+
+ void InitView();
+ void UpdateView( BOOL bNewView, const Size& rNewOutSize );
+ void InvalidateBorder();
+
+ using Window::Draw;
+ void Draw( const Rectangle& rRect, OutputDevice* pDev, const Point& rPos );
+
+ void SetDisplayActive( BOOL bActive );
+ BOOL IsDisplayActive() const { return mbDisplayActive; }
+ void SetTitleType( USHORT nTitleType, const Size& rSize );
+ void SetBorderStyle( USHORT nStyle );
+ USHORT GetBorderStyle() const { return mnBorderStyle; }
+ void SetPin( BOOL bPin );
+ void SetRollUp( BOOL bRollUp, const Size& rSize );
+ void SetCloser();
+ void SetDockButton( BOOL bDockButton );
+ void SetHideButton( BOOL bHideButton );
+ void SetHelpButton( BOOL bHelpButton );
+ void SetMenuButton( BOOL bMenuButton );
+
+ void UpdateMenuHeight();
+ void SetMenuBarWindow( Window* pWindow );
+ void SetMenuBarMode( BOOL bHide );
+
+ void SetMinOutputSize( long nWidth, long nHeight )
+ { mnMinWidth = nWidth; mnMinHeight = nHeight; }
+ void SetMaxOutputSize( long nWidth, long nHeight )
+ { mnMaxWidth = nWidth; mnMaxHeight = nHeight; }
+
+ void GetBorder( sal_Int32& rLeftBorder, sal_Int32& rTopBorder,
+ sal_Int32& rRightBorder, sal_Int32& rBottomBorder ) const;
+ long CalcTitleWidth() const;
+
+ Rectangle GetMenuRect() const;
+};
+
+// =======================================================================
+
+// -----------------------
+// - ImplBorderFrameData -
+// -----------------------
+
+struct ImplBorderFrameData
+{
+ ImplBorderWindow* mpBorderWindow;
+ OutputDevice* mpOutDev;
+ Rectangle maTitleRect;
+ Rectangle maPinRect;
+ Rectangle maCloseRect;
+ Rectangle maRollRect;
+ Rectangle maDockRect;
+ Rectangle maMenuRect;
+ Rectangle maHideRect;
+ Rectangle maHelpRect;
+ Point maMouseOff;
+ long mnWidth;
+ long mnHeight;
+ long mnTrackX;
+ long mnTrackY;
+ long mnTrackWidth;
+ long mnTrackHeight;
+ sal_Int32 mnLeftBorder;
+ sal_Int32 mnTopBorder;
+ sal_Int32 mnRightBorder;
+ sal_Int32 mnBottomBorder;
+ long mnNoTitleTop;
+ long mnBorderSize;
+ long mnTitleHeight;
+ long mnTitleOff;
+ USHORT mnHitTest;
+ USHORT mnPinState;
+ USHORT mnCloseState;
+ USHORT mnRollState;
+ USHORT mnDockState;
+ USHORT mnMenuState;
+ USHORT mnHideState;
+ USHORT mnHelpState;
+ USHORT mnTitleType;
+ BOOL mbFloatWindow;
+ BOOL mbDragFull;
+ BOOL mbTitleClipped;
+};
+
+// =======================================================================
+
+// ------------------------
+// - ImplBorderWindowView -
+// ------------------------
+
+class ImplBorderWindowView
+{
+public:
+ virtual ~ImplBorderWindowView();
+
+ virtual BOOL MouseMove( const MouseEvent& rMEvt );
+ virtual BOOL MouseButtonDown( const MouseEvent& rMEvt );
+ virtual BOOL Tracking( const TrackingEvent& rTEvt );
+ virtual String RequestHelp( const Point& rPos, Rectangle& rHelpRect );
+
+ virtual void Init( OutputDevice* pDev, long nWidth, long nHeight ) = 0;
+ virtual void GetBorder( sal_Int32& rLeftBorder, sal_Int32& rTopBorder,
+ sal_Int32& rRightBorder, sal_Int32& rBottomBorder ) const = 0;
+ virtual long CalcTitleWidth() const = 0;
+ virtual void DrawWindow( USHORT nDrawFlags, OutputDevice* pOutDev = NULL, const Point* pOffset = NULL ) = 0;
+ virtual Rectangle GetMenuRect() const;
+
+ void ImplInitTitle( ImplBorderFrameData* pData );
+ USHORT ImplHitTest( ImplBorderFrameData* pData, const Point& rPos );
+ BOOL ImplMouseMove( ImplBorderFrameData* pData, const MouseEvent& rMEvt );
+ BOOL ImplMouseButtonDown( ImplBorderFrameData* pData, const MouseEvent& rMEvt );
+ BOOL ImplTracking( ImplBorderFrameData* pData, const TrackingEvent& rTEvt );
+ String ImplRequestHelp( ImplBorderFrameData* pData, const Point& rPos, Rectangle& rHelpRect );
+ long ImplCalcTitleWidth( const ImplBorderFrameData* pData ) const;
+};
+
+// =======================================================================
+
+// --------------------------
+// - ImplNoBorderWindowView -
+// --------------------------
+
+class ImplNoBorderWindowView : public ImplBorderWindowView
+{
+public:
+ ImplNoBorderWindowView( ImplBorderWindow* pBorderWindow );
+
+ virtual void Init( OutputDevice* pDev, long nWidth, long nHeight );
+ virtual void GetBorder( sal_Int32& rLeftBorder, sal_Int32& rTopBorder,
+ sal_Int32& rRightBorder, sal_Int32& rBottomBorder ) const;
+ virtual long CalcTitleWidth() const;
+ virtual void DrawWindow( USHORT nDrawFlags, OutputDevice* pOutDev, const Point* pOffset );
+};
+
+
+// =======================================================================
+
+// -----------------------------
+// - ImplSmallBorderWindowView -
+// -----------------------------
+
+class ImplSmallBorderWindowView : public ImplBorderWindowView
+{
+ ImplBorderWindow* mpBorderWindow;
+ OutputDevice* mpOutDev;
+ long mnWidth;
+ long mnHeight;
+ sal_Int32 mnLeftBorder;
+ sal_Int32 mnTopBorder;
+ sal_Int32 mnRightBorder;
+ sal_Int32 mnBottomBorder;
+ bool mbNWFBorder;
+
+public:
+ ImplSmallBorderWindowView( ImplBorderWindow* pBorderWindow );
+
+ virtual void Init( OutputDevice* pOutDev, long nWidth, long nHeight );
+ virtual void GetBorder( sal_Int32& rLeftBorder, sal_Int32& rTopBorder,
+ sal_Int32& rRightBorder, sal_Int32& rBottomBorder ) const;
+ virtual long CalcTitleWidth() const;
+ virtual void DrawWindow( USHORT nDrawFlags, OutputDevice* pOutDev, const Point* pOffset );
+};
+
+
+// =======================================================================
+
+// ---------------------------
+// - ImplStdBorderWindowView -
+// ---------------------------
+
+
+class ImplStdBorderWindowView : public ImplBorderWindowView
+{
+ ImplBorderFrameData maFrameData;
+ VirtualDevice* mpATitleVirDev;
+ VirtualDevice* mpDTitleVirDev;
+
+public:
+ ImplStdBorderWindowView( ImplBorderWindow* pBorderWindow );
+ ~ImplStdBorderWindowView();
+
+ virtual BOOL MouseMove( const MouseEvent& rMEvt );
+ virtual BOOL MouseButtonDown( const MouseEvent& rMEvt );
+ virtual BOOL Tracking( const TrackingEvent& rTEvt );
+ virtual String RequestHelp( const Point& rPos, Rectangle& rHelpRect );
+ virtual Rectangle GetMenuRect() const;
+
+ virtual void Init( OutputDevice* pDev, long nWidth, long nHeight );
+ virtual void GetBorder( sal_Int32& rLeftBorder, sal_Int32& rTopBorder,
+ sal_Int32& rRightBorder, sal_Int32& rBottomBorder ) const;
+ virtual long CalcTitleWidth() const;
+ virtual void DrawWindow( USHORT nDrawFlags, OutputDevice* pOutDev, const Point* pOffset );
+};
+
+
+#endif // _SV_BRDWIN_HXX
diff --git a/vcl/inc/vcl/btndlg.hxx b/vcl/inc/vcl/btndlg.hxx
new file mode 100644
index 000000000000..dbeb8350a0d4
--- /dev/null
+++ b/vcl/inc/vcl/btndlg.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_BTNDLG_HXX
+#define _SV_BTNDLG_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/dialog.hxx>
+
+struct ImplBtnDlgItem;
+class ImplBtnDlgItemList;
+class PushButton;
+
+// ----------------------
+// - ButtonDialog-Types -
+// ----------------------
+
+#define BUTTONDIALOG_BUTTON_NOTFOUND ((USHORT)0xFFFF)
+
+#define BUTTONDIALOG_DEFBUTTON ((USHORT)0x0001)
+#define BUTTONDIALOG_OKBUTTON ((USHORT)0x0002)
+#define BUTTONDIALOG_CANCELBUTTON ((USHORT)0x0004)
+#define BUTTONDIALOG_HELPBUTTON ((USHORT)0x0008)
+#define BUTTONDIALOG_FOCUSBUTTON ((USHORT)0x0010)
+
+// ----------------
+// - ButtonDialog -
+// ----------------
+
+class VCL_DLLPUBLIC ButtonDialog : public Dialog
+{
+private:
+ ImplBtnDlgItemList* mpItemList;
+ Size maPageSize;
+ Size maCtrlSize;
+ long mnButtonSize;
+ USHORT mnCurButtonId;
+ USHORT mnFocusButtonId;
+ BOOL mbFormat;
+ Link maClickHdl;
+
+ SAL_DLLPRIVATE void ImplInitButtonDialogData();
+ SAL_DLLPRIVATE PushButton* ImplCreatePushButton( USHORT nBtnFlags );
+ SAL_DLLPRIVATE ImplBtnDlgItem* ImplGetItem( USHORT nId ) const;
+ DECL_DLLPRIVATE_LINK( ImplClickHdl, PushButton* pBtn );
+ SAL_DLLPRIVATE void ImplPosControls();
+
+ // Copy assignment is forbidden and not implemented.
+ SAL_DLLPRIVATE ButtonDialog( const ButtonDialog & );
+ SAL_DLLPRIVATE ButtonDialog& operator=( const ButtonDialog& );
+protected:
+ ButtonDialog( WindowType nType );
+ SAL_DLLPRIVATE long ImplGetButtonSize();
+
+public:
+ ButtonDialog( Window* pParent, WinBits nStyle = WB_STDDIALOG );
+ ButtonDialog( Window* pParent, const ResId& rResId );
+ ~ButtonDialog();
+
+ virtual void Resize();
+ virtual void StateChanged( StateChangedType nStateChange );
+
+ virtual void Click();
+
+ void SetPageSizePixel( const Size& rSize ) { maPageSize = rSize; }
+ const Size& GetPageSizePixel() const { return maPageSize; }
+
+ USHORT GetCurButtonId() const { return mnCurButtonId; }
+
+ void AddButton( const XubString& rText, USHORT nId, USHORT nBtnFlags, long nSepPixel = 0 );
+ void AddButton( StandardButtonType eType, USHORT nId, USHORT nBtnFlags, long nSepPixel = 0 );
+ void AddButton( PushButton* pBtn, USHORT nId, USHORT nBtnFlags, long nSepPixel = 0 );
+ void RemoveButton( USHORT nId );
+ void Clear();
+ USHORT GetButtonCount() const;
+ USHORT GetButtonId( USHORT nButton ) const;
+ PushButton* GetPushButton( USHORT nId ) const;
+ void SetButtonText( USHORT nId, const XubString& rText );
+ XubString GetButtonText( USHORT nId ) const;
+ void SetButtonHelpText( USHORT nId, const XubString& rText );
+ XubString GetButtonHelpText( USHORT nId ) const;
+ void SetButtonHelpId( USHORT nId, ULONG nHelpId );
+ ULONG GetButtonHelpId( USHORT nId ) const;
+
+ void SetFocusButton( USHORT nId = BUTTONDIALOG_BUTTON_NOTFOUND ) { mnFocusButtonId = nId; }
+ USHORT GetFocusButton() const { return mnFocusButtonId; }
+
+ void SetClickHdl( const Link& rLink ) { maClickHdl = rLink; }
+ const Link& GetClickHdl() const { return maClickHdl; }
+};
+
+#endif // _SV_BTNDLG_HXX
diff --git a/vcl/inc/vcl/button.hxx b/vcl/inc/vcl/button.hxx
new file mode 100644
index 000000000000..8f4b94bf7b18
--- /dev/null
+++ b/vcl/inc/vcl/button.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_BUTTON_HXX
+#define _SV_BUTTON_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/image.hxx>
+#include <vcl/symbol.hxx>
+#include <vcl/ctrl.hxx>
+#include <vcl/bitmap.hxx>
+#include <vcl/salnativewidgets.hxx>
+
+#include <vector>
+
+class UserDrawEvent;
+class ImplCommonButtonData;
+
+// ----------
+// - Button -
+// ----------
+
+class VCL_DLLPUBLIC Button : public Control
+{
+private:
+ ImplCommonButtonData *mpButtonData;
+ Link maClickHdl;
+
+ // Copy assignment is forbidden and not implemented.
+ SAL_DLLPRIVATE Button (const Button &);
+ SAL_DLLPRIVATE Button & operator= (const Button &);
+public:
+ SAL_DLLPRIVATE USHORT ImplGetButtonState() const;
+ SAL_DLLPRIVATE USHORT& ImplGetButtonState();
+ SAL_DLLPRIVATE USHORT ImplGetTextStyle( XubString& rText, WinBits nWinStyle, ULONG nDrawFlags );
+ SAL_DLLPRIVATE void ImplDrawAlignedImage( OutputDevice* pDev, Point& rPos, Size& rSize,
+ BOOL bLayout, ULONG nImageSep, ULONG nDrawFlags,
+ USHORT nTextStyle, Rectangle *pSymbolRect=NULL, bool bAddImageSep = false );
+ SAL_DLLPRIVATE void ImplSetFocusRect( const Rectangle &rFocusRect );
+ SAL_DLLPRIVATE const Rectangle& ImplGetFocusRect() const;
+ SAL_DLLPRIVATE void ImplSetSymbolAlign( SymbolAlign eAlign );
+ SAL_DLLPRIVATE SymbolAlign ImplGetSymbolAlign() const;
+ SAL_DLLPRIVATE void ImplSetSmallSymbol( BOOL bSmall = TRUE );
+
+protected:
+ Button( WindowType nType );
+
+public:
+ Button( Window* pParent, WinBits nStyle = 0 );
+ Button( Window* pParent, const ResId& rResId );
+ ~Button();
+
+ virtual void Click();
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+
+ void SetClickHdl( const Link& rLink ) { maClickHdl = rLink; }
+ const Link& GetClickHdl() const { return maClickHdl; }
+
+ static XubString GetStandardText( StandardButtonType eButton );
+ static XubString GetStandardHelpText( StandardButtonType eButton );
+
+ BOOL SetModeImage( const Image& rImage, BmpColorMode eMode = BMP_COLOR_NORMAL );
+ const Image GetModeImage( BmpColorMode eMode = BMP_COLOR_NORMAL ) const;
+ BOOL HasImage() const;
+ void SetImageAlign( ImageAlign eAlign );
+ ImageAlign GetImageAlign() const;
+
+ BOOL SetModeBitmap( const BitmapEx& rBitmap, BmpColorMode eMode = BMP_COLOR_NORMAL );
+ BitmapEx GetModeBitmap( BmpColorMode eMode = BMP_COLOR_NORMAL ) const;
+
+ void EnableImageDisplay( BOOL bEnable );
+ BOOL IsImageDisplayEnabled();
+ void EnableTextDisplay( BOOL bEnable );
+ BOOL IsTextDisplayEnabled();
+
+ void SetFocusRect( const Rectangle& rFocusRect );
+ const Rectangle& GetFocusRect() const;
+ void SetSmallSymbol (bool bSmall=true);
+ bool IsSmallSymbol () const;
+};
+
+// --------------------
+// - PushButton-Types -
+// --------------------
+
+#define PUSHBUTTON_DROPDOWN_TOOLBOX ((USHORT)0x0001)
+#define PUSHBUTTON_DROPDOWN_MENUBUTTON ((USHORT)0x0002)
+
+// --------------
+// - PushButton -
+// --------------
+
+class VCL_DLLPUBLIC PushButton : public Button
+{
+protected:
+ SymbolType meSymbol;
+ TriState meState;
+ TriState meSaveValue;
+ USHORT mnDDStyle;
+ BOOL mbPressed;
+ BOOL mbInUserDraw;
+ Link maToggleHdl;
+
+ SAL_DLLPRIVATE void ImplInitPushButtonData();
+ SAL_DLLPRIVATE WinBits ImplInitStyle( const Window* pPrevWindow, WinBits nStyle );
+ SAL_DLLPRIVATE void ImplInitSettings( BOOL bFont, BOOL bForeground, BOOL bBackground );
+ SAL_DLLPRIVATE void ImplDrawPushButtonContent( OutputDevice* pDev, ULONG nDrawFlags,
+ const Rectangle& rRect, bool bLayout );
+ SAL_DLLPRIVATE void ImplDrawPushButton( bool bLayout = false );
+ using Button::ImplGetTextStyle;
+ SAL_DLLPRIVATE USHORT ImplGetTextStyle( ULONG nDrawFlags ) const;
+ SAL_DLLPRIVATE BOOL IsSymbol() const { return ( (meSymbol != SYMBOL_NOSYMBOL) && (meSymbol != SYMBOL_IMAGE) ); }
+ SAL_DLLPRIVATE BOOL IsImage() const { return Button::HasImage(); }
+
+ // Copy assignment is forbidden and not implemented.
+ SAL_DLLPRIVATE PushButton( const PushButton & );
+ SAL_DLLPRIVATE PushButton& operator=( const PushButton & );
+
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle );
+
+ using Control::ImplInitSettings;
+ using Window::ImplInit;
+public:
+ SAL_DLLPRIVATE void ImplSetDefButton( BOOL bSet );
+ SAL_DLLPRIVATE static void ImplDrawPushButtonFrame( Window* pDev, Rectangle& rRect, USHORT nStyle );
+ SAL_DLLPRIVATE static BOOL ImplHitTestPushButton( Window* pDev, const Point& rPos );
+ SAL_DLLPRIVATE BOOL ImplIsDefButton() const;
+
+protected:
+ PushButton( WindowType nType );
+
+ virtual void FillLayoutData() const;
+ virtual const Font&
+ GetCanonicalFont( const StyleSettings& _rStyle ) const;
+ virtual const Color&
+ GetCanonicalTextColor( const StyleSettings& _rStyle ) const;
+public:
+ PushButton( Window* pParent, WinBits nStyle = 0 );
+ PushButton( Window* pParent, const ResId& rResId );
+ ~PushButton();
+
+ virtual void MouseButtonDown( const MouseEvent& rMEvt );
+ virtual void Tracking( const TrackingEvent& rTEvt );
+ virtual void KeyInput( const KeyEvent& rKEvt );
+ virtual void KeyUp( const KeyEvent& rKEvt );
+ virtual void Paint( const Rectangle& rRect );
+ virtual void Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG nFlags );
+ virtual void Resize();
+ virtual void GetFocus();
+ virtual void LoseFocus();
+ virtual void StateChanged( StateChangedType nType );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+ virtual long PreNotify( NotifyEvent& rNEvt );
+ virtual void UserDraw( const UserDrawEvent& rUDEvt );
+
+ virtual void Toggle();
+
+ void SetSymbol( SymbolType eSymbol );
+ SymbolType GetSymbol() const { return meSymbol; }
+ void SetSymbolAlign( SymbolAlign eAlign );
+ SymbolAlign GetSymbolAlign() const;
+
+ void SetDropDown( USHORT nStyle );
+ USHORT GetDropDown() const { return mnDDStyle; }
+
+ void SetState( TriState eState );
+ TriState GetState() const { return meState; }
+
+ void Check( BOOL bCheck = TRUE );
+ BOOL IsChecked() const;
+
+ void SetPressed( BOOL bPressed );
+ BOOL IsPressed() const { return mbPressed; }
+
+ void EndSelection();
+
+ void SaveValue() { meSaveValue = GetState(); }
+ TriState GetSavedValue() const { return meSaveValue; }
+
+ Size CalcMinimumSize( long nMaxWidth = 0 ) const;
+ virtual Size GetOptimalSize(WindowSizeType eType) const;
+
+ void SetToggleHdl( const Link& rLink ) { maToggleHdl = rLink; }
+ const Link& GetToggleHdl() const { return maToggleHdl; }
+};
+
+inline void PushButton::Check( BOOL bCheck )
+{
+ SetState( (bCheck) ? STATE_CHECK : STATE_NOCHECK );
+}
+
+inline BOOL PushButton::IsChecked() const
+{
+ return (GetState() == STATE_CHECK);
+}
+
+// ------------
+// - OKButton -
+// ------------
+
+class VCL_DLLPUBLIC OKButton : public PushButton
+{
+protected:
+ using PushButton::ImplInit;
+private:
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle );
+
+ // Copy assignment is forbidden and not implemented.
+ SAL_DLLPRIVATE OKButton (const OKButton &);
+ SAL_DLLPRIVATE OKButton & operator= (const OKButton &);
+
+public:
+ OKButton( Window* pParent, WinBits nStyle = WB_DEFBUTTON );
+ OKButton( Window* pParent, const ResId& rResId );
+
+ virtual void Click();
+};
+
+// ----------------
+// - CancelButton -
+// ----------------
+
+class VCL_DLLPUBLIC CancelButton : public PushButton
+{
+protected:
+ using PushButton::ImplInit;
+private:
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle );
+
+ // Copy assignment is forbidden and not implemented.
+ SAL_DLLPRIVATE CancelButton (const CancelButton &);
+ SAL_DLLPRIVATE CancelButton & operator= (const CancelButton &);
+
+public:
+ CancelButton( Window* pParent, WinBits nStyle = 0 );
+ CancelButton( Window* pParent, const ResId& rResId );
+
+ virtual void Click();
+};
+
+// --------------
+// - HelpButton -
+// --------------
+
+class VCL_DLLPUBLIC HelpButton : public PushButton
+{
+protected:
+ using PushButton::ImplInit;
+private:
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle );
+
+ // Copy assignment is forbidden and not implemented.
+ SAL_DLLPRIVATE HelpButton( const HelpButton & );
+ SAL_DLLPRIVATE HelpButton & operator= ( const HelpButton & );
+
+public:
+ HelpButton( Window* pParent, WinBits nStyle = 0 );
+ HelpButton( Window* pParent, const ResId& rResId );
+
+ virtual void Click();
+};
+
+// ---------------
+// - RadioButton -
+// ---------------
+
+class VCL_DLLPUBLIC RadioButton : public Button
+{
+private:
+ Rectangle maStateRect;
+ Rectangle maMouseRect;
+ Image maImage;
+ Image maImageHC;
+ BOOL mbChecked;
+ BOOL mbSaveValue;
+ BOOL mbRadioCheck;
+ BOOL mbStateChanged;
+ Link maToggleHdl;
+
+ SAL_DLLPRIVATE void ImplInitRadioButtonData();
+ SAL_DLLPRIVATE WinBits ImplInitStyle( const Window* pPrevWindow, WinBits nStyle );
+ SAL_DLLPRIVATE void ImplInitSettings( BOOL bFont, BOOL bForeground, BOOL bBackground );
+ SAL_DLLPRIVATE void ImplDrawRadioButtonState();
+ SAL_DLLPRIVATE void ImplDraw( OutputDevice* pDev, ULONG nDrawFlags,
+ const Point& rPos, const Size& rSize,
+ const Size& rImageSize, Rectangle& rStateRect,
+ Rectangle& rMouseRect, bool bLayout = false );
+ SAL_DLLPRIVATE void ImplDrawRadioButton( bool bLayout = false );
+ SAL_DLLPRIVATE void ImplInvalidateOrDrawRadioButtonState();
+ SAL_DLLPRIVATE void ImplUncheckAllOther();
+ SAL_DLLPRIVATE Size ImplGetRadioImageSize() const;
+ SAL_DLLPRIVATE long ImplGetImageToTextDistance() const;
+
+ // Copy assignment is forbidden and not implemented.
+ SAL_DLLPRIVATE RadioButton(const RadioButton &);
+ SAL_DLLPRIVATE RadioButton& operator= (const RadioButton &);
+
+protected:
+ using Control::ImplInitSettings;
+ using Window::ImplInit;
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle );
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+
+public:
+ SAL_DLLPRIVATE void ImplCallClick( BOOL bGrabFocus = FALSE, USHORT nFocusFlags = 0 );
+ SAL_DLLPRIVATE void ImplSetMinimumNWFSize();
+
+protected:
+ virtual void FillLayoutData() const;
+ virtual const Font&
+ GetCanonicalFont( const StyleSettings& _rStyle ) const;
+ virtual const Color&
+ GetCanonicalTextColor( const StyleSettings& _rStyle ) const;
+
+ inline void SetMouseRect( const Rectangle& _rMouseRect ) { maMouseRect = _rMouseRect; }
+ inline const Rectangle& GetMouseRect( ) const { return maMouseRect; }
+ inline void SetStateRect( const Rectangle& _rStateRect ) { maStateRect = _rStateRect; }
+ inline const Rectangle& GetStateRect( ) const { return maStateRect; }
+
+ // draws the radio button (the knob image), in it's current state (pressed/checked)
+ // at the usual location, which can be overridden with SetStateRect
+ void DrawRadioButtonState( );
+
+public:
+ RadioButton( Window* pParent, WinBits nWinStyle = 0 );
+ RadioButton( Window* pParent, const ResId& rResId );
+ ~RadioButton();
+
+ virtual void MouseButtonDown( const MouseEvent& rMEvt );
+ virtual void Tracking( const TrackingEvent& rTEvt );
+ virtual void KeyInput( const KeyEvent& rKEvt );
+ virtual void KeyUp( const KeyEvent& rKEvt );
+ virtual void Paint( const Rectangle& rRect );
+ virtual void Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG nFlags );
+ virtual void Resize();
+ virtual void GetFocus();
+ virtual void LoseFocus();
+ virtual void StateChanged( StateChangedType nType );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+ virtual long PreNotify( NotifyEvent& rNEvt );
+
+ virtual void Toggle();
+
+ BOOL IsStateChanged() const { return mbStateChanged; }
+
+ void EnableRadioCheck( BOOL bRadioCheck = TRUE ) { mbRadioCheck = bRadioCheck; }
+ BOOL IsRadioCheckEnabled() const { return mbRadioCheck; }
+
+ BOOL SetModeRadioImage( const Image& rImage, BmpColorMode eMode = BMP_COLOR_NORMAL );
+ const Image& GetModeRadioImage( BmpColorMode eMode = BMP_COLOR_NORMAL ) const;
+
+ void SetState( BOOL bCheck );
+ void Check( BOOL bCheck = TRUE );
+ BOOL IsChecked() const { return mbChecked; }
+
+ void SaveValue() { mbSaveValue = IsChecked(); }
+ BOOL GetSavedValue() const { return mbSaveValue; }
+
+ static Image GetRadioImage( const AllSettings& rSettings, USHORT nFlags );
+
+ Size CalcMinimumSize( long nMaxWidth = 0 ) const;
+ virtual Size GetOptimalSize(WindowSizeType eType) const;
+
+ void SetToggleHdl( const Link& rLink ) { maToggleHdl = rLink; }
+ const Link& GetToggleHdl() const { return maToggleHdl; }
+
+ /** GetRadioButtonGroup returns a list of pointers to <code>RadioButton</code>s in the same group.
+
+ The pointers in the returned list are valid at the time call returns. However rescheduling
+ or giving up the SolarMutex may mean events get executed that lead to the pointers getting
+ invalid.
+
+ @param io_rGroup
+ gets cleared on entering the function. on return contains the <code>RadioButton</code>s
+ in the same group as this <code>RadioButton</code>.
+
+ @param bIncludeThis
+ defines whether <code>this</code> is contained in the returned list
+ */
+ void GetRadioButtonGroup( std::vector<RadioButton*>& io_rGroup, bool bIncludeThis ) const;
+};
+
+// ------------
+// - CheckBox -
+// ------------
+
+class VCL_DLLPUBLIC CheckBox : public Button
+{
+private:
+ Rectangle maStateRect;
+ Rectangle maMouseRect;
+ TriState meState;
+ TriState meSaveValue;
+ BOOL mbTriState;
+ Link maToggleHdl;
+
+ SAL_DLLPRIVATE void ImplInitCheckBoxData();
+ SAL_DLLPRIVATE WinBits ImplInitStyle( const Window* pPrevWindow, WinBits nStyle );
+ SAL_DLLPRIVATE void ImplInitSettings( BOOL bFont, BOOL bForeground, BOOL bBackground );
+ SAL_DLLPRIVATE void ImplInvalidateOrDrawCheckBoxState();
+ SAL_DLLPRIVATE void ImplDraw( OutputDevice* pDev, ULONG nDrawFlags,
+ const Point& rPos, const Size& rSize,
+ const Size& rImageSize, Rectangle& rStateRect,
+ Rectangle& rMouseRect, bool bLayout );
+ SAL_DLLPRIVATE void ImplDrawCheckBox( bool bLayout = false );
+ SAL_DLLPRIVATE long ImplGetImageToTextDistance() const;
+ SAL_DLLPRIVATE Size ImplGetCheckImageSize() const;
+
+ // Copy assignment is forbidden and not implemented.
+ SAL_DLLPRIVATE CheckBox(const CheckBox &);
+ SAL_DLLPRIVATE CheckBox& operator= (const CheckBox &);
+
+protected:
+ using Control::ImplInitSettings;
+ using Window::ImplInit;
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle );
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+ SAL_DLLPRIVATE virtual void FillLayoutData() const;
+ SAL_DLLPRIVATE virtual const Font&
+ GetCanonicalFont( const StyleSettings& _rStyle ) const;
+ SAL_DLLPRIVATE virtual const Color&
+ GetCanonicalTextColor( const StyleSettings& _rStyle ) const;
+
+ SAL_DLLPRIVATE virtual void ImplDrawCheckBoxState();
+ SAL_DLLPRIVATE const Rectangle& GetStateRect() const { return maStateRect; }
+ SAL_DLLPRIVATE const Rectangle& GetMouseRect() const { return maMouseRect; }
+public:
+ SAL_DLLPRIVATE void ImplCheck();
+ SAL_DLLPRIVATE void ImplSetMinimumNWFSize();
+public:
+ CheckBox( Window* pParent, WinBits nStyle = 0 );
+ CheckBox( Window* pParent, const ResId& rResId );
+
+ virtual void MouseButtonDown( const MouseEvent& rMEvt );
+ virtual void Tracking( const TrackingEvent& rTEvt );
+ virtual void KeyInput( const KeyEvent& rKEvt );
+ virtual void KeyUp( const KeyEvent& rKEvt );
+ virtual void Paint( const Rectangle& rRect );
+ virtual void Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG nFlags );
+ virtual void Resize();
+ virtual void GetFocus();
+ virtual void LoseFocus();
+ virtual void StateChanged( StateChangedType nType );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+ virtual long PreNotify( NotifyEvent& rNEvt );
+
+ virtual void Toggle();
+
+ void SetState( TriState eState );
+ TriState GetState() const { return meState; }
+
+ void Check( BOOL bCheck = TRUE );
+ BOOL IsChecked() const;
+
+ void EnableTriState( BOOL bTriState = TRUE );
+ BOOL IsTriStateEnabled() const { return mbTriState; }
+
+ void SaveValue() { meSaveValue = GetState(); }
+ TriState GetSavedValue() const { return meSaveValue; }
+
+ static Image GetCheckImage( const AllSettings& rSettings, USHORT nFlags );
+
+ Size CalcMinimumSize( long nMaxWidth = 0 ) const;
+ virtual Size GetOptimalSize(WindowSizeType eType) const;
+
+ void SetToggleHdl( const Link& rLink ) { maToggleHdl = rLink; }
+ const Link& GetToggleHdl() const { return maToggleHdl; }
+};
+
+inline void CheckBox::Check( BOOL bCheck )
+{
+ SetState( (bCheck) ? STATE_CHECK : STATE_NOCHECK );
+}
+
+inline BOOL CheckBox::IsChecked() const
+{
+ return (GetState() == STATE_CHECK);
+}
+
+// ---------------------------------
+// - Control-Layer fuer alten Code -
+// ---------------------------------
+
+class VCL_DLLPUBLIC ImageButton : public PushButton
+{
+protected:
+ using PushButton::ImplInitStyle;
+private:
+ SAL_DLLPRIVATE void ImplInitStyle();
+
+ // Copy assignment is forbidden and not implemented.
+ SAL_DLLPRIVATE ImageButton( const ImageButton & );
+ SAL_DLLPRIVATE ImageButton & operator= ( const ImageButton & );
+
+protected:
+ ImageButton( WindowType nType );
+
+public:
+ ImageButton( Window* pParent, WinBits nStyle = 0 );
+ ImageButton( Window* pParent, const ResId& rResId );
+ ~ImageButton();
+};
+
+class VCL_DLLPUBLIC ImageRadioButton : public RadioButton
+{
+ // Copy assignment is forbidden and not implemented.
+ SAL_DLLPRIVATE ImageRadioButton( const ImageRadioButton & );
+ SAL_DLLPRIVATE ImageRadioButton & operator= ( const ImageRadioButton & );
+
+public:
+ ImageRadioButton( Window* pParent, WinBits nStyle = 0 );
+ ImageRadioButton( Window* pParent, const ResId& rResId );
+ ~ImageRadioButton();
+};
+
+class VCL_DLLPUBLIC TriStateBox : public CheckBox
+{
+ // Copy assignment is forbidden and not implemented.
+ SAL_DLLPRIVATE TriStateBox( const TriStateBox & );
+ SAL_DLLPRIVATE TriStateBox & operator= ( const TriStateBox & );
+
+public:
+ TriStateBox( Window* pParent, WinBits nStyle = 0 );
+ TriStateBox( Window* pParent, const ResId& rResId );
+ ~TriStateBox();
+};
+
+class VCL_DLLPUBLIC DisclosureButton : public CheckBox
+{
+protected:
+ SAL_DLLPRIVATE virtual void ImplDrawCheckBoxState();
+public:
+ DisclosureButton( Window* pParent, WinBits nStyle = 0 );
+ DisclosureButton( Window* pParent, const ResId& rResId );
+
+ virtual void KeyInput( const KeyEvent& rKEvt );
+};
+
+#endif // _SV_BUTTON_HXX
diff --git a/vcl/inc/vcl/canvasbitmap.hxx b/vcl/inc/vcl/canvasbitmap.hxx
new file mode 100644
index 000000000000..85c0aa795c8c
--- /dev/null
+++ b/vcl/inc/vcl/canvasbitmap.hxx
@@ -0,0 +1,129 @@
+/*************************************************************************
+ *
+ * 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_CANVASBITMAP_HXX
+#define _VCL_CANVASBITMAP_HXX
+
+#include <cppuhelper/compbase3.hxx>
+#include <com/sun/star/rendering/XIntegerReadOnlyBitmap.hpp>
+#include <com/sun/star/rendering/XIntegerBitmapColorSpace.hpp>
+#include <com/sun/star/rendering/XIntegerBitmap.hpp>
+#include <com/sun/star/rendering/XBitmapPalette.hpp>
+
+#include <vcl/bitmapex.hxx>
+#include <vcl/bmpacc.hxx>
+
+namespace vcl
+{
+namespace unotools
+{
+ class VCL_DLLPUBLIC VclCanvasBitmap :
+ public cppu::WeakImplHelper3< com::sun::star::rendering::XIntegerReadOnlyBitmap,
+ com::sun::star::rendering::XBitmapPalette,
+ com::sun::star::rendering::XIntegerBitmapColorSpace >
+ {
+ private:
+ BitmapEx m_aBmpEx;
+ Bitmap m_aBitmap;
+ Bitmap m_aAlpha;
+ BitmapReadAccess* m_pBmpAcc;
+ BitmapReadAccess* m_pAlphaAcc;
+ com::sun::star::uno::Sequence<sal_Int8> m_aComponentTags;
+ com::sun::star::uno::Sequence<sal_Int32> m_aComponentBitCounts;
+ com::sun::star::rendering::IntegerBitmapLayout m_aLayout;
+ sal_Int32 m_nBitsPerInputPixel;
+ sal_Int32 m_nBitsPerOutputPixel;
+ sal_Int32 m_nRedIndex;
+ sal_Int32 m_nGreenIndex;
+ sal_Int32 m_nBlueIndex;
+ sal_Int32 m_nAlphaIndex;
+ sal_Int32 m_nIndexIndex;
+ sal_Int8 m_nEndianness;
+ bool m_bSwap;
+ bool m_bPalette;
+
+ SAL_DLLPRIVATE void setComponentInfo( ULONG redShift, ULONG greenShift, ULONG blueShift );
+
+ virtual ~VclCanvasBitmap();
+
+ public:
+ // XBitmap
+ virtual com::sun::star::geometry::IntegerSize2D SAL_CALL getSize() throw (com::sun::star::uno::RuntimeException);
+ virtual ::sal_Bool SAL_CALL hasAlpha( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual com::sun::star::uno::Reference< com::sun::star::rendering::XBitmap > SAL_CALL getScaledBitmap( const com::sun::star::geometry::RealSize2D& newSize, sal_Bool beFast ) throw (com::sun::star::uno::RuntimeException);
+
+ // XIntegerReadOnlyBitmap
+ virtual ::com::sun::star::uno::Sequence< ::sal_Int8 > SAL_CALL getData( ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout, const ::com::sun::star::geometry::IntegerRectangle2D& rect ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::rendering::VolatileContentDestroyedException, ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::sal_Int8 > SAL_CALL getPixel( ::com::sun::star::rendering::IntegerBitmapLayout& bitmapLayout, const ::com::sun::star::geometry::IntegerPoint2D& pos ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::rendering::VolatileContentDestroyedException, ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmapPalette > SAL_CALL getPalette( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::rendering::IntegerBitmapLayout SAL_CALL getMemoryLayout( ) throw (::com::sun::star::uno::RuntimeException);
+
+ // XBitmapPalette
+ virtual sal_Int32 SAL_CALL getNumberOfEntries() throw (com::sun::star::uno::RuntimeException);
+ virtual ::sal_Bool SAL_CALL getIndex( ::com::sun::star::uno::Sequence< double >& entry, ::sal_Int32 nIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException);
+ virtual ::sal_Bool SAL_CALL setIndex( const ::com::sun::star::uno::Sequence< double >& color, ::sal_Bool transparency, ::sal_Int32 nIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XColorSpace > SAL_CALL getColorSpace( ) throw (::com::sun::star::uno::RuntimeException);
+
+ // XIntegerBitmapColorSpace
+ virtual ::sal_Int8 SAL_CALL getType( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL getComponentTags( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::sal_Int8 SAL_CALL getRenderingIntent( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > SAL_CALL getProperties( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< double > SAL_CALL convertColorSpace( const ::com::sun::star::uno::Sequence< double >& deviceColor, const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XColorSpace >& targetColorSpace ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::com::sun::star::rendering::RGBColor > SAL_CALL convertToRGB( const ::com::sun::star::uno::Sequence< double >& deviceColor ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::com::sun::star::rendering::ARGBColor > SAL_CALL convertToARGB( const ::com::sun::star::uno::Sequence< double >& deviceColor ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::com::sun::star::rendering::ARGBColor > SAL_CALL convertToPARGB( const ::com::sun::star::uno::Sequence< double >& deviceColor ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< double > SAL_CALL convertFromRGB( const ::com::sun::star::uno::Sequence< ::com::sun::star::rendering::RGBColor >& rgbColor ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< double > SAL_CALL convertFromARGB( const ::com::sun::star::uno::Sequence< ::com::sun::star::rendering::ARGBColor >& rgbColor ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< double > SAL_CALL convertFromPARGB( const ::com::sun::star::uno::Sequence< ::com::sun::star::rendering::ARGBColor >& rgbColor ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual ::sal_Int32 SAL_CALL getBitsPerPixel( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::sal_Int32 > SAL_CALL getComponentBitCounts( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::sal_Int8 SAL_CALL getEndianness( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence<double> SAL_CALL convertFromIntegerColorSpace( const ::com::sun::star::uno::Sequence< ::sal_Int8 >& deviceColor, const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XColorSpace >& targetColorSpace ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::sal_Int8 > SAL_CALL convertToIntegerColorSpace( const ::com::sun::star::uno::Sequence< ::sal_Int8 >& deviceColor, const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XIntegerBitmapColorSpace >& targetColorSpace ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::com::sun::star::rendering::RGBColor > SAL_CALL convertIntegerToRGB( const ::com::sun::star::uno::Sequence< ::sal_Int8 >& deviceColor ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::com::sun::star::rendering::ARGBColor > SAL_CALL convertIntegerToARGB( const ::com::sun::star::uno::Sequence< ::sal_Int8 >& deviceColor ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::com::sun::star::rendering::ARGBColor > SAL_CALL convertIntegerToPARGB( const ::com::sun::star::uno::Sequence< ::sal_Int8 >& deviceColor ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromRGB( const ::com::sun::star::uno::Sequence< ::com::sun::star::rendering::RGBColor >& rgbColor ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromARGB( const ::com::sun::star::uno::Sequence< ::com::sun::star::rendering::ARGBColor >& rgbColor ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromPARGB( const ::com::sun::star::uno::Sequence< ::com::sun::star::rendering::ARGBColor >& rgbColor ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+
+ /** Create API wrapper for given BitmapEx
+
+ @param rBitmap
+ Bitmap to wrap. As usual, changes to the original bitmap
+ are not reflected in this object (copy on write).
+ */
+ explicit VclCanvasBitmap( const BitmapEx& rBitmap );
+
+ /// Retrieve contained bitmap. Call me with locked Solar mutex!
+ BitmapEx getBitmapEx() const;
+ };
+}
+}
+
+#endif
diff --git a/vcl/inc/vcl/canvastools.hxx b/vcl/inc/vcl/canvastools.hxx
new file mode 100644
index 000000000000..c6f1710cdae5
--- /dev/null
+++ b/vcl/inc/vcl/canvastools.hxx
@@ -0,0 +1,253 @@
+/*************************************************************************
+ *
+ * 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_CANVASTOOLS_HXX
+#define _VCL_CANVASTOOLS_HXX
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/rendering/XColorSpace.hpp>
+#include <basegfx/numeric/ftools.hxx>
+
+#include <vcl/dllapi.h>
+
+class Point;
+class Size;
+class Rectangle;
+class Polygon;
+class PolyPolygon;
+class Bitmap;
+class BitmapEx;
+class Color;
+
+namespace basegfx
+{
+ class B2DVector;
+ class B2DPoint;
+ class B2DRange;
+ class B2IVector;
+ class B2IPoint;
+ class B2IRange;
+ class B2DPolygon;
+ class B2DPolyPolygon;
+}
+
+namespace com { namespace sun { namespace star { namespace geometry
+{
+ struct RealPoint2D;
+ struct RealSize2D;
+ struct RealRectangle2D;
+ struct IntegerPoint2D;
+ struct IntegerSize2D;
+ struct IntegerRectangle2D;
+ struct RealBezierSegment2D;
+} } } }
+
+namespace com { namespace sun { namespace star { namespace rendering
+{
+ class XGraphicDevice;
+ class XBitmap;
+ class XIntegerBitmap;
+ class XIntegerReadOnlyBitmap;
+ class XPolyPolygon2D;
+} } } }
+
+namespace vcl
+{
+ namespace unotools
+ {
+ // Polygon conversions
+ // ===================================================================
+
+ /** Create an XPolyPolygon from VCL/Tools polygon
+ */
+ ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XPolyPolygon2D >
+ VCL_DLLPUBLIC xPolyPolygonFromPolygon( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XGraphicDevice >& xGraphicDevice,
+ const ::Polygon& inputPolygon );
+
+ /** Create an XPolyPolygon from VCL/Tools polyPolygon
+ */
+ ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XPolyPolygon2D >
+ VCL_DLLPUBLIC xPolyPolygonFromPolyPolygon( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XGraphicDevice >& xGraphicDevice,
+ const ::PolyPolygon& inputPolyPolygon );
+
+ /** Create an VCL/Tools polygon from a point sequence
+ */
+ ::Polygon VCL_DLLPUBLIC polygonFromPoint2DSequence(
+ const ::com::sun::star::uno::Sequence<
+ ::com::sun::star::geometry::RealPoint2D >& rPoints );
+
+ /** Create an VCL/Tools polyPolygon from a point sequence sequence
+ */
+ ::PolyPolygon VCL_DLLPUBLIC polyPolygonFromPoint2DSequenceSequence(
+ const ::com::sun::star::uno::Sequence<
+ ::com::sun::star::uno::Sequence< ::com::sun::star::geometry::RealPoint2D > >& rPoints );
+
+ /** Create an VCL/Tools polygon from a bezier segment sequence
+ */
+ ::Polygon VCL_DLLPUBLIC polygonFromBezier2DSequence(
+ const ::com::sun::star::uno::Sequence<
+ ::com::sun::star::geometry::RealBezierSegment2D >& rPoints );
+
+ /** Create an VCL/Tools polyPolygon from a bezier segment sequence sequence
+ */
+ ::PolyPolygon VCL_DLLPUBLIC polyPolygonFromBezier2DSequenceSequence(
+ const ::com::sun::star::uno::Sequence<
+ ::com::sun::star::uno::Sequence< ::com::sun::star::geometry::RealBezierSegment2D > >& rPoints );
+
+ // Bitmap conversions
+ // ===================================================================
+
+ /** Create an XBitmap from VCL Bitmap
+ */
+ ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmap >
+ VCL_DLLPUBLIC xBitmapFromBitmap( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XGraphicDevice >& xGraphicDevice,
+ const ::Bitmap& inputBitmap );
+
+ /** Create an XBitmap from VCL BitmapEx
+ */
+ ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmap >
+ VCL_DLLPUBLIC xBitmapFromBitmapEx( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XGraphicDevice >& xGraphicDevice,
+ const ::BitmapEx& inputBitmap );
+
+ /** Create a BitmapEx from an XBitmap
+ */
+ ::BitmapEx VCL_DLLPUBLIC bitmapExFromXBitmap( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XIntegerReadOnlyBitmap >& xInputBitmap );
+
+ /** get a unique identifier for identification in XUnoTunnel interface
+ */
+ enum TunnelIdentifierType { Id_BitmapEx = 0 };
+ const com::sun::star::uno::Sequence< sal_Int8 > VCL_DLLPUBLIC getTunnelIdentifier( TunnelIdentifierType eType );
+
+ // Color conversions (vcl/tools Color <-> canvas standard color space)
+ // ===================================================================
+
+ /** Create a device-specific color sequence from VCL/Tools color
+
+ Note that this method assumes a color space equivalent to
+ the one returned from createStandardColorSpace()
+ */
+ ::com::sun::star::uno::Sequence< double >
+ VCL_DLLPUBLIC colorToStdColorSpaceSequence( const Color& rColor );
+
+ /** Convert color to device color sequence
+
+ @param rColor
+ Color to convert
+
+ @param xColorSpace
+ Color space to convert into
+ */
+ ::com::sun::star::uno::Sequence< double >
+ VCL_DLLPUBLIC colorToDoubleSequence( const Color& rColor,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XColorSpace >& xColorSpace );
+
+ /** Convert from standard device color space to VCL/Tools color
+
+ Note that this method assumes a color space equivalent to
+ the one returned from createStandardColorSpace()
+ */
+ Color VCL_DLLPUBLIC stdColorSpaceSequenceToColor(
+ const ::com::sun::star::uno::Sequence< double >& rColor );
+
+ /** Convert color to device color sequence
+
+ @param rColor
+ Color sequence to convert from
+
+ @param xColorSpace
+ Color space to convert from
+ */
+ Color VCL_DLLPUBLIC doubleSequenceToColor( const ::com::sun::star::uno::Sequence< double > rColor,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XColorSpace >& xColorSpace );
+
+ /// Convert [0,1] double value to [0,255] int
+ inline sal_Int8 toByteColor( double val )
+ {
+ return sal::static_int_cast<sal_Int8>(
+ basegfx::fround(val*255.0));
+ }
+
+ /// Convert [0,255] int value to [0,1] double value
+ inline double toDoubleColor( sal_uInt8 val )
+ {
+ return val / 255.0;
+ }
+
+ /// Create a standard color space suitable for VCL RGB color
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XColorSpace> VCL_DLLPUBLIC createStandardColorSpace();
+
+ // Geometry conversions (vcl/tools <-> x)
+ // ===================================================================
+
+ // geometry::Real
+ ::com::sun::star::geometry::RealSize2D VCL_DLLPUBLIC size2DFromSize( const Size& );
+ ::com::sun::star::geometry::RealPoint2D VCL_DLLPUBLIC point2DFromPoint( const Point& );
+ ::com::sun::star::geometry::RealRectangle2D VCL_DLLPUBLIC rectangle2DFromRectangle( const Rectangle& );
+
+ Size VCL_DLLPUBLIC sizeFromRealSize2D( const ::com::sun::star::geometry::RealSize2D& );
+ Point VCL_DLLPUBLIC pointFromRealPoint2D( const ::com::sun::star::geometry::RealPoint2D& );
+ Rectangle VCL_DLLPUBLIC rectangleFromRealRectangle2D( const ::com::sun::star::geometry::RealRectangle2D& );
+
+ // geometry::Integer
+ ::com::sun::star::geometry::IntegerSize2D VCL_DLLPUBLIC integerSize2DFromSize( const Size& );
+ ::com::sun::star::geometry::IntegerPoint2D VCL_DLLPUBLIC integerPoint2DFromPoint( const Point& );
+ ::com::sun::star::geometry::IntegerRectangle2D VCL_DLLPUBLIC integerRectangle2DFromRectangle( const Rectangle& );
+
+ Size VCL_DLLPUBLIC sizeFromIntegerSize2D( const ::com::sun::star::geometry::IntegerSize2D& );
+ Point VCL_DLLPUBLIC pointFromIntegerPoint2D( const ::com::sun::star::geometry::IntegerPoint2D& );
+ Rectangle VCL_DLLPUBLIC rectangleFromIntegerRectangle2D( const ::com::sun::star::geometry::IntegerRectangle2D& );
+
+ // basegfx::B2D
+ Size VCL_DLLPUBLIC sizeFromB2DSize( const ::basegfx::B2DVector& );
+ Point VCL_DLLPUBLIC pointFromB2DPoint( const ::basegfx::B2DPoint& );
+ Rectangle VCL_DLLPUBLIC rectangleFromB2DRectangle( const ::basegfx::B2DRange& );
+
+ basegfx::B2DVector VCL_DLLPUBLIC b2DSizeFromSize( const Size& );
+ basegfx::B2DPoint VCL_DLLPUBLIC b2DPointFromPoint( const Point& );
+ basegfx::B2DRange VCL_DLLPUBLIC b2DRectangleFromRectangle( const Rectangle& );
+
+ // basegfx::B2I
+ Size VCL_DLLPUBLIC sizeFromB2ISize( const ::basegfx::B2IVector& );
+ Point VCL_DLLPUBLIC pointFromB2IPoint( const ::basegfx::B2IPoint& );
+ Rectangle VCL_DLLPUBLIC rectangleFromB2IRectangle( const ::basegfx::B2IRange& );
+
+ basegfx::B2IVector VCL_DLLPUBLIC b2ISizeFromSize( const Size& );
+ basegfx::B2IPoint VCL_DLLPUBLIC b2IPointFromPoint( const Point& );
+ basegfx::B2IRange VCL_DLLPUBLIC b2IRectangleFromRectangle( const Rectangle& );
+ }
+}
+
+#endif /* _VCL_CANVASTOOLS_HXX */
diff --git a/vcl/inc/vcl/cmdevt.h b/vcl/inc/vcl/cmdevt.h
new file mode 100644
index 000000000000..4594da8b7d56
--- /dev/null
+++ b/vcl/inc/vcl/cmdevt.h
@@ -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 _VCL_CMDEVT_H
+#define _VCL_CMDEVT_H
+
+// --------------------
+// - CommandVoiceData -
+// --------------------
+
+#define DICTATIONCOMMAND_SYSTEM 0x1000
+#define DICTATIONCOMMAND_USER 0x2000
+
+#define DICTATIONCOMMAND_UNKNOWN 0x0001
+#define DICTATIONCOMMAND_NEWPARAGRAPH 0x0002
+#define DICTATIONCOMMAND_NEWLINE 0x0003
+#define DICTATIONCOMMAND_BOLD_ON 0x0004
+#define DICTATIONCOMMAND_BOLD_OFF 0x0005
+#define DICTATIONCOMMAND_ITALIC_ON 0x0006
+#define DICTATIONCOMMAND_ITALIC_OFF 0x0007
+#define DICTATIONCOMMAND_UNDERLINE_ON 0x0008
+#define DICTATIONCOMMAND_UNDERLINE_OFF 0x0009
+#define DICTATIONCOMMAND_NUMBERING_ON 0x0010
+#define DICTATIONCOMMAND_NUMBERING_OFF 0x0011
+#define DICTATIONCOMMAND_TAB 0x0012
+#define DICTATIONCOMMAND_LEFT 0x0013
+#define DICTATIONCOMMAND_RIGHT 0x0014
+#define DICTATIONCOMMAND_UP 0x0015
+#define DICTATIONCOMMAND_DOWN 0x0016
+#define DICTATIONCOMMAND_UNDO 0x0017
+#define DICTATIONCOMMAND_REPEAT 0x0018
+#define DICTATIONCOMMAND_DEL 0x0019
+
+#define DICTATIONCOMMAND_COMMANDMODE (DICTATIONCOMMAND_SYSTEM + 1)
+#define DICTATIONCOMMAND_DICTATIONMODE (DICTATIONCOMMAND_SYSTEM + 2)
+
+#endif // _VCL_CMDEVT_H
+
+
diff --git a/vcl/inc/vcl/cmdevt.hxx b/vcl/inc/vcl/cmdevt.hxx
new file mode 100644
index 000000000000..7e968b6c7a54
--- /dev/null
+++ b/vcl/inc/vcl/cmdevt.hxx
@@ -0,0 +1,526 @@
+/*************************************************************************
+ *
+ * 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_CMDEVT_HXX
+#define _VCL_CMDEVT_HXX
+
+#include <tools/gen.hxx>
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/keycod.hxx>
+#include <vcl/font.hxx>
+
+// ---------------------------
+// - CommandExtTextInputData -
+// ---------------------------
+
+#define EXTTEXTINPUT_ATTR_GRAYWAVELINE ((USHORT)0x0100)
+#define EXTTEXTINPUT_ATTR_UNDERLINE ((USHORT)0x0200)
+#define EXTTEXTINPUT_ATTR_BOLDUNDERLINE ((USHORT)0x0400)
+#define EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE ((USHORT)0x0800)
+#define EXTTEXTINPUT_ATTR_DASHDOTUNDERLINE ((USHORT)0x1000)
+#define EXTTEXTINPUT_ATTR_HIGHLIGHT ((USHORT)0x2000)
+#define EXTTEXTINPUT_ATTR_REDTEXT ((USHORT)0x4000)
+#define EXTTEXTINPUT_ATTR_HALFTONETEXT ((USHORT)0x8000)
+
+#define EXTTEXTINPUT_CURSOR_INVISIBLE ((USHORT)0x0001)
+#define EXTTEXTINPUT_CURSOR_OVERWRITE ((USHORT)0x0002)
+
+class VCL_DLLPUBLIC CommandExtTextInputData
+{
+private:
+ XubString maText;
+ USHORT* mpTextAttr;
+ xub_StrLen mnCursorPos;
+ xub_StrLen mnDeltaStart;
+ xub_StrLen mnOldTextLen;
+ USHORT mnCursorFlags;
+ BOOL mbOnlyCursor;
+
+public:
+ CommandExtTextInputData();
+ CommandExtTextInputData( const XubString& rText,
+ const USHORT* pTextAttr,
+ xub_StrLen nCursorPos,
+ USHORT nCursorFlags,
+ xub_StrLen nDeltaStart,
+ xub_StrLen nOldTextLen,
+ BOOL bOnlyCursor );
+ CommandExtTextInputData( const CommandExtTextInputData& rData );
+ ~CommandExtTextInputData();
+
+ const XubString& GetText() const { return maText; }
+ const USHORT* GetTextAttr() const { return mpTextAttr; }
+ USHORT GetCharTextAttr( USHORT nIndex ) const;
+ xub_StrLen GetCursorPos() const { return mnCursorPos; }
+ BOOL IsCursorVisible() const { return (mnCursorFlags & EXTTEXTINPUT_CURSOR_INVISIBLE) == 0; }
+ BOOL IsCursorOverwrite() const { return (mnCursorFlags & EXTTEXTINPUT_CURSOR_OVERWRITE) != 0; }
+ USHORT GetCursorFlags() const { return mnCursorFlags; }
+ xub_StrLen GetDeltaStart() const { return mnDeltaStart; }
+ xub_StrLen GetOldTextLen() const { return mnOldTextLen; }
+ BOOL IsOnlyCursorChanged() const { return mbOnlyCursor; }
+};
+
+inline USHORT CommandExtTextInputData::GetCharTextAttr( USHORT nIndex ) const
+{
+ if ( mpTextAttr && (nIndex < maText.Len()) )
+ return mpTextAttr[nIndex];
+ else
+ return 0;
+}
+
+// ---------------------------
+// - CommandInputContextData -
+// ---------------------------
+
+class VCL_DLLPUBLIC CommandInputContextData
+{
+private:
+ LanguageType meLanguage;
+
+public:
+ CommandInputContextData();
+ CommandInputContextData( LanguageType eLang );
+
+ LanguageType GetLanguage() const { return meLanguage; }
+};
+
+inline CommandInputContextData::CommandInputContextData()
+{
+ meLanguage = LANGUAGE_DONTKNOW;
+}
+
+inline CommandInputContextData::CommandInputContextData( LanguageType eLang )
+{
+ meLanguage = eLang;
+}
+
+// --------------------
+// - CommandWheelData -
+// --------------------
+
+#define COMMAND_WHEEL_SCROLL ((USHORT)0x0001)
+#define COMMAND_WHEEL_ZOOM ((USHORT)0x0002)
+#define COMMAND_WHEEL_DATAZOOM ((USHORT)0x0004)
+
+#define COMMAND_WHEEL_PAGESCROLL ((ULONG)0xFFFFFFFF)
+
+class VCL_DLLPUBLIC CommandWheelData
+{
+private:
+ long mnDelta;
+ long mnNotchDelta;
+ ULONG mnLines;
+ USHORT mnMode;
+ USHORT mnCode;
+ BOOL mbHorz;
+ BOOL mbDeltaIsPixel;
+
+public:
+ CommandWheelData();
+ CommandWheelData( long nWheelDelta, long nWheelNotchDelta,
+ ULONG nScrollLines,
+ USHORT nWheelMode, USHORT nKeyModifier,
+ BOOL bHorz = FALSE, BOOL bDeltaIsPixel = FALSE );
+
+ long GetDelta() const { return mnDelta; }
+ long GetNotchDelta() const { return mnNotchDelta; }
+ ULONG GetScrollLines() const { return mnLines; }
+ BOOL IsHorz() const { return mbHorz; }
+ BOOL IsDeltaPixel() const { return mbDeltaIsPixel; }
+
+ USHORT GetMode() const { return mnMode; }
+
+ USHORT GetModifier() const
+ { return (mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2)); }
+ BOOL IsShift() const
+ { return ((mnCode & KEY_SHIFT) != 0); }
+ BOOL IsMod1() const
+ { return ((mnCode & KEY_MOD1) != 0); }
+ BOOL IsMod2() const
+ { return ((mnCode & KEY_MOD2) != 0); }
+ BOOL IsMod3() const
+ { return ((mnCode & KEY_MOD3) != 0); }
+};
+
+inline CommandWheelData::CommandWheelData()
+{
+ mnDelta = 0;
+ mnNotchDelta = 0;
+ mnLines = 0;
+ mnMode = 0;
+ mnCode = 0;
+ mbHorz = FALSE;
+ mbDeltaIsPixel = FALSE;
+}
+
+inline CommandWheelData::CommandWheelData( long nWheelDelta, long nWheelNotchDelta,
+ ULONG nScrollLines,
+ USHORT nWheelMode, USHORT nKeyModifier,
+ BOOL bHorz, BOOL bDeltaIsPixel )
+{
+ mnDelta = nWheelDelta;
+ mnNotchDelta = nWheelNotchDelta;
+ mnLines = nScrollLines;
+ mnMode = nWheelMode;
+ mnCode = nKeyModifier;
+ mbHorz = bHorz;
+ mbDeltaIsPixel = bDeltaIsPixel;
+}
+
+// ---------------------
+// - CommandScrollData -
+// ---------------------
+
+class VCL_DLLPUBLIC CommandScrollData
+{
+private:
+ long mnDeltaX;
+ long mnDeltaY;
+
+public:
+ CommandScrollData();
+ CommandScrollData( long nDeltaX, long nDeltaY );
+
+ long GetDeltaX() const { return mnDeltaX; }
+ long GetDeltaY() const { return mnDeltaY; }
+};
+
+inline CommandScrollData::CommandScrollData()
+{
+ mnDeltaX = 0;
+ mnDeltaY = 0;
+}
+
+inline CommandScrollData::CommandScrollData( long nDeltaX, long nDeltaY )
+{
+ mnDeltaX = nDeltaX;
+ mnDeltaY = nDeltaY;
+}
+
+// --------------------
+// - CommandVoiceData -
+// --------------------
+
+enum DictationCommandType
+{
+ VOICECOMMANDTYPE_DICTATION,
+ VOICECOMMANDTYPE_CONTROL
+};
+
+class VCL_DLLPUBLIC CommandVoiceData
+{
+private:
+ XubString maText;
+ USHORT mnCommand;
+ DictationCommandType meType;
+
+public:
+ CommandVoiceData();
+ CommandVoiceData( const XubString& rStr,
+ DictationCommandType eType,
+ USHORT nCommand );
+
+ const XubString& GetText() const { return maText; }
+ USHORT GetCommand() const { return mnCommand; }
+ DictationCommandType GetType() const { return meType; }
+};
+
+inline CommandVoiceData::CommandVoiceData()
+{
+ meType = VOICECOMMANDTYPE_DICTATION;
+ mnCommand = 0;
+}
+
+inline CommandVoiceData::CommandVoiceData( const XubString& rStr,
+ DictationCommandType eType,
+ USHORT nCommand ) :
+ maText( rStr ),
+ mnCommand( nCommand ),
+ meType( eType )
+{
+}
+
+// ---------------------
+// - CommandModKeyData -
+// ---------------------
+
+class VCL_DLLPUBLIC CommandModKeyData
+{
+private:
+ USHORT mnCode;
+
+public:
+ CommandModKeyData();
+ CommandModKeyData( USHORT nCode );
+
+ BOOL IsShift() const { return (mnCode & MODKEY_SHIFT) ? TRUE : FALSE; }
+ BOOL IsMod1() const { return (mnCode & MODKEY_MOD1) ? TRUE : FALSE; }
+ BOOL IsMod2() const { return (mnCode & MODKEY_MOD2) ? TRUE : FALSE; }
+ BOOL IsMod3() const { return (mnCode & MODKEY_MOD3) ? TRUE : FALSE; }
+
+ BOOL IsLeftShift() const { return (mnCode & MODKEY_LSHIFT) ? TRUE : FALSE; }
+ BOOL IsLeftMod1() const { return (mnCode & MODKEY_LMOD1) ? TRUE : FALSE; }
+ BOOL IsLeftMod2() const { return (mnCode & MODKEY_LMOD2) ? TRUE : FALSE; }
+ BOOL IsLeftMod3() const { return (mnCode & MODKEY_LMOD3) ? TRUE : FALSE; }
+
+ BOOL IsRightShift() const { return (mnCode & MODKEY_RSHIFT) ? TRUE : FALSE; }
+ BOOL IsRightMod1() const { return (mnCode & MODKEY_RMOD1) ? TRUE : FALSE; }
+ BOOL IsRightMod2() const { return (mnCode & MODKEY_RMOD2) ? TRUE : FALSE; }
+ BOOL IsRightMod3() const { return (mnCode & MODKEY_RMOD3) ? TRUE : FALSE; }
+};
+
+inline CommandModKeyData::CommandModKeyData()
+{
+ mnCode = 0L;
+}
+
+inline CommandModKeyData::CommandModKeyData( USHORT nCode )
+{
+ mnCode = nCode;
+}
+
+// --------------------
+// - CommanDialogData -
+// --------------------
+
+#define SHOWDIALOG_ID_PREFERENCES 1
+#define SHOWDIALOG_ID_ABOUT 2
+
+class VCL_DLLPUBLIC CommandDialogData
+{
+ int m_nDialogId;
+ public:
+ CommandDialogData( int nDialogId = SHOWDIALOG_ID_PREFERENCES )
+ : m_nDialogId( nDialogId )
+ {}
+
+ int GetDialogId() const { return m_nDialogId; }
+};
+
+// --------------
+// Media Commands
+// --------------
+
+#define MEDIA_COMMAND_CHANNEL_DOWN ((sal_Int16)1) // Decrement the channel value, for example, for a TV or radio tuner.
+#define MEDIA_COMMAND_CHANNEL_UP ((sal_Int16)2) // Increment the channel value, for example, for a TV or radio tuner.
+#define MEDIA_COMMAND_NEXTTRACK ((sal_Int16)3) // Go to next media track/slide.
+#define MEDIA_COMMAND_PAUSE ((sal_Int16)4) // Pause. If already paused, take no further action. This is a direct PAUSE command that has no state.
+#define MEDIA_COMMAND_PLAY ((sal_Int16)5) // Begin playing at the current position. If already paused, it will resume. This is a direct PLAY command that has no state.
+#define MEDIA_COMMAND_PLAY_PAUSE ((sal_Int16)6) // Play or pause playback.
+#define MEDIA_COMMAND_PREVIOUSTRACK ((sal_Int16)7) // Go to previous media track/slide.
+#define MEDIA_COMMAND_RECORD ((sal_Int16)8) // Begin recording the current stream.
+#define MEDIA_COMMAND_REWIND ((sal_Int16)9)// Go backward in a stream at a higher rate of speed.
+#define MEDIA_COMMAND_STOP ((sal_Int16)10)// Stop playback.
+#define MEDIA_COMMAND_MIC_ON_OFF_TOGGLE ((sal_Int16)11)// Toggle the microphone.
+#define MEDIA_COMMAND_MICROPHONE_VOLUME_DOWN ((sal_Int16)12)// Increase microphone volume.
+#define MEDIA_COMMAND_MICROPHONE_VOLUME_MUTE ((sal_Int16)13)// Mute the microphone.
+#define MEDIA_COMMAND_MICROPHONE_VOLUME_UP ((sal_Int16)14)// Decrease microphone volume.
+#define MEDIA_COMMAND_VOLUME_DOWN ((sal_Int16)15)// Lower the volume.
+#define MEDIA_COMMAND_VOLUME_MUTE ((sal_Int16)16)// Mute the volume.
+#define MEDIA_COMMAND_VOLUME_UP ((sal_Int16)17)// Raise the volume.
+#define MEDIA_COMMAND_MENU ((sal_Int16)18)// Button Menu pressed.
+#define MEDIA_COMMAND_MENU_HOLD ((sal_Int16)19)// Button Menu (long) pressed.
+#define MEDIA_COMMAND_PLAY_HOLD ((sal_Int16)20)// Button Play (long) pressed.
+#define MEDIA_COMMAND_NEXTTRACK_HOLD ((sal_Int16)21)// Button Right holding pressed.
+#define MEDIA_COMMAND_PREVIOUSTRACK_HOLD ((sal_Int16)22)// Button Left holding pressed.
+
+
+// ------------------------------
+// - CommandSelectionChangeData -
+// ------------------------------
+
+class VCL_DLLPUBLIC CommandSelectionChangeData
+{
+private:
+ ULONG mnStart;
+ ULONG mnEnd;
+
+public:
+ CommandSelectionChangeData();
+ CommandSelectionChangeData( ULONG nStart, ULONG nEnd );
+
+ ULONG GetStart() const { return mnStart; }
+ ULONG GetEnd() const { return mnEnd; }
+};
+
+inline CommandSelectionChangeData::CommandSelectionChangeData()
+{
+ mnStart = mnEnd = 0;
+}
+
+inline CommandSelectionChangeData::CommandSelectionChangeData( ULONG nStart,
+ ULONG nEnd )
+{
+ mnStart = nStart;
+ mnEnd = nEnd;
+}
+
+// ----------------
+// - CommandEvent -
+// ----------------
+
+#define COMMAND_CONTEXTMENU ((USHORT)1)
+#define COMMAND_STARTDRAG ((USHORT)2)
+#define COMMAND_WHEEL ((USHORT)3)
+#define COMMAND_STARTAUTOSCROLL ((USHORT)4)
+#define COMMAND_AUTOSCROLL ((USHORT)5)
+#define COMMAND_VOICE ((USHORT)6)
+#define COMMAND_STARTEXTTEXTINPUT ((USHORT)7)
+#define COMMAND_EXTTEXTINPUT ((USHORT)8)
+#define COMMAND_ENDEXTTEXTINPUT ((USHORT)9)
+#define COMMAND_INPUTCONTEXTCHANGE ((USHORT)10)
+#define COMMAND_CURSORPOS ((USHORT)11)
+#define COMMAND_PASTESELECTION ((USHORT)12)
+#define COMMAND_MODKEYCHANGE ((USHORT)13)
+#define COMMAND_HANGUL_HANJA_CONVERSION ((USHORT)14)
+#define COMMAND_INPUTLANGUAGECHANGE ((USHORT)15)
+#define COMMAND_SHOWDIALOG ((USHORT)16)
+#define COMMAND_MEDIA ((USHORT)17)
+#define COMMAND_SELECTIONCHANGE ((USHORT)18)
+#define COMMAND_PREPARERECONVERSION ((USHORT)19)
+#define COMMAND_USER ((USHORT)4096)
+
+class VCL_DLLPUBLIC CommandEvent
+{
+private:
+ Point maPos;
+ void* mpData;
+ USHORT mnCommand;
+ BOOL mbMouseEvent;
+
+public:
+ CommandEvent();
+ CommandEvent( const Point& rMousePos, USHORT nCmd,
+ BOOL bMEvt = FALSE, const void* pCmdData = NULL );
+
+ USHORT GetCommand() const { return mnCommand; }
+ const Point& GetMousePosPixel() const { return maPos; }
+ BOOL IsMouseEvent() const { return mbMouseEvent; }
+ void* GetData() const { return mpData; }
+
+ const CommandExtTextInputData* GetExtTextInputData() const;
+ const CommandInputContextData* GetInputContextChangeData() const;
+ const CommandWheelData* GetWheelData() const;
+ const CommandScrollData* GetAutoScrollData() const;
+ const CommandVoiceData* GetVoiceData() const;
+ const CommandModKeyData* GetModKeyData() const;
+ const CommandDialogData* GetDialogData() const;
+ sal_Int16 GetMediaCommand() const;
+ const CommandSelectionChangeData* GetSelectionChangeData() const;
+};
+
+inline CommandEvent::CommandEvent()
+{
+ mpData = NULL;
+ mnCommand = 0;
+ mbMouseEvent = FALSE;
+}
+
+inline CommandEvent::CommandEvent( const Point& rMousePos,
+ USHORT nCmd, BOOL bMEvt, const void* pCmdData ) :
+ maPos( rMousePos )
+{
+ mpData = (void*)pCmdData;
+ mnCommand = nCmd;
+ mbMouseEvent = bMEvt;
+}
+
+inline const CommandExtTextInputData* CommandEvent::GetExtTextInputData() const
+{
+ if ( mnCommand == COMMAND_EXTTEXTINPUT )
+ return (const CommandExtTextInputData*)mpData;
+ else
+ return NULL;
+}
+
+inline const CommandInputContextData* CommandEvent::GetInputContextChangeData() const
+{
+ if ( mnCommand == COMMAND_INPUTCONTEXTCHANGE )
+ return (const CommandInputContextData*)mpData;
+ else
+ return NULL;
+}
+
+inline const CommandWheelData* CommandEvent::GetWheelData() const
+{
+ if ( mnCommand == COMMAND_WHEEL )
+ return (const CommandWheelData*)mpData;
+ else
+ return NULL;
+}
+
+inline const CommandScrollData* CommandEvent::GetAutoScrollData() const
+{
+ if ( mnCommand == COMMAND_AUTOSCROLL )
+ return (const CommandScrollData*)mpData;
+ else
+ return NULL;
+}
+
+inline const CommandVoiceData* CommandEvent::GetVoiceData() const
+{
+ if ( mnCommand == COMMAND_VOICE )
+ return (const CommandVoiceData*)mpData;
+ else
+ return NULL;
+}
+
+inline const CommandModKeyData* CommandEvent::GetModKeyData() const
+{
+ if( mnCommand == COMMAND_MODKEYCHANGE )
+ return (const CommandModKeyData*)mpData;
+ else
+ return NULL;
+}
+
+inline const CommandDialogData* CommandEvent::GetDialogData() const
+{
+ if( mnCommand == COMMAND_SHOWDIALOG )
+ return (const CommandDialogData*)mpData;
+ else
+ return NULL;
+}
+
+inline sal_Int16 CommandEvent::GetMediaCommand() const
+{
+ if( mnCommand == COMMAND_MEDIA )
+ return *(const sal_Int16*)(mpData);
+ else
+ return 0;
+}
+
+inline const CommandSelectionChangeData* CommandEvent::GetSelectionChangeData() const
+{
+ if( mnCommand == COMMAND_SELECTIONCHANGE )
+ return (const CommandSelectionChangeData*)mpData;
+ else
+ return NULL;
+}
+
+
+#endif // _VCL_CMDEVT_HXX
diff --git a/vcl/inc/vcl/combobox.h b/vcl/inc/vcl/combobox.h
new file mode 100644
index 000000000000..f4fc39f021b2
--- /dev/null
+++ b/vcl/inc/vcl/combobox.h
@@ -0,0 +1,37 @@
+/*************************************************************************
+ *
+ * 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_COMBOBOX_H
+#define _SV_COMBOBOX_H
+
+#define COMBOBOX_APPEND ((USHORT)0xFFFF)
+#define COMBOBOX_ENTRY_NOTFOUND ((USHORT)0xFFFF)
+#define COMBOBOX_ERROR ((USHORT)0xFFFF)
+
+#define COMBOBOX_USERDRAW_SELECTED ((USHORT)0x0001)
+
+#endif // _SV_COMBOBOX_H
diff --git a/vcl/inc/vcl/combobox.hxx b/vcl/inc/vcl/combobox.hxx
new file mode 100644
index 000000000000..e35474a84d53
--- /dev/null
+++ b/vcl/inc/vcl/combobox.hxx
@@ -0,0 +1,229 @@
+/*************************************************************************
+ *
+ * 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_COMBOBOX_HXX
+#define _SV_COMBOBOX_HXX
+
+#include <vcl/dllapi.h>
+#include <vcl/ctrl.hxx>
+#include <vcl/combobox.h>
+#include <vcl/edit.hxx>
+
+class UserDrawEvent;
+
+class ImplListBoxFloatingWindow;
+class ImplListBox;
+class ImplBtn;
+
+// ------------
+// - ComboBox -
+// ------------
+
+class VCL_DLLPUBLIC ComboBox : public Edit
+{
+private:
+ Edit* mpSubEdit;
+ ImplListBox* mpImplLB;
+ ImplBtn* mpBtn;
+ ImplListBoxFloatingWindow* mpFloatWin;
+ USHORT mnDDHeight;
+ xub_Unicode mcMultiSep;
+ BOOL mbDDAutoSize : 1;
+ BOOL mbSyntheticModify : 1;
+ BOOL mbMatchCase : 1;
+ Link maSelectHdl;
+ Link maDoubleClickHdl;
+
+//#if 0 // _SOLAR__PRIVATE
+private:
+ SAL_DLLPRIVATE void ImplInitComboBoxData();
+ SAL_DLLPRIVATE void ImplUpdateFloatSelection();
+
+ DECL_DLLPRIVATE_LINK( ImplSelectHdl, void* );
+ DECL_DLLPRIVATE_LINK( ImplCancelHdl, void* );
+ DECL_DLLPRIVATE_LINK( ImplDoubleClickHdl, void* );
+ DECL_DLLPRIVATE_LINK( ImplClickBtnHdl, void* );
+ DECL_DLLPRIVATE_LINK( ImplPopupModeEndHdl, void* );
+ DECL_DLLPRIVATE_LINK( ImplSelectionChangedHdl, void* );
+ DECL_DLLPRIVATE_LINK( ImplUserDrawHdl, UserDrawEvent* );
+ DECL_DLLPRIVATE_LINK( ImplAutocompleteHdl, Edit* );
+
+protected:
+ using Window::ImplInit;
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle );
+ SAL_DLLPRIVATE WinBits ImplInitStyle( WinBits nStyle );
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+ SAL_DLLPRIVATE void ImplCalcEditHeight();
+//#endif
+
+protected:
+ ComboBox( WindowType nType );
+ BOOL IsDropDownBox() const { return mpFloatWin ? TRUE : FALSE; }
+
+ virtual void FillLayoutData() const;
+public:
+ ComboBox( Window* pParent, WinBits nStyle = 0 );
+ ComboBox( Window* pParent, const ResId& rResId );
+ ~ComboBox();
+
+ virtual void Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG nFlags );
+ virtual void Resize();
+ virtual long PreNotify( NotifyEvent& rNEvt );
+ virtual long Notify( NotifyEvent& rNEvt );
+ virtual void StateChanged( StateChangedType nType );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+
+ virtual void UserDraw( const UserDrawEvent& rUDEvt );
+ virtual void Select();
+ virtual void DoubleClick();
+
+ virtual void Modify();
+
+ virtual const Wallpaper& GetDisplayBackground() const;
+
+ virtual void SetPosSizePixel( long nX, long nY, long nWidth, long nHeight, USHORT nFlags = WINDOW_POSSIZE_ALL );
+ void SetPosSizePixel( const Point& rNewPos, const Size& rNewSize )
+ { Edit::SetPosSizePixel( rNewPos, rNewSize ); }
+ void SetDropDownSizePixel( const Size& rNewSize )
+ { if( IsDropDownBox() ) SetPosSizePixel( 0, 0, rNewSize.Width(), rNewSize.Height(), WINDOW_POSSIZE_SIZE | WINDOW_POSSIZE_DROPDOWN ); }
+
+ Rectangle GetDropDownPosSizePixel() const;
+ Rectangle GetListPosSizePixel() const;
+ // returns empty rectangle in DropDown mode,
+ // else it returns the PosSize of the ListBox
+
+ void SetDropDownLineCount( USHORT nLines );
+ USHORT GetDropDownLineCount() const;
+
+ void EnableAutoSize( BOOL bAuto );
+ BOOL IsAutoSizeEnabled() const { return mbDDAutoSize; }
+
+ void EnableDDAutoWidth( BOOL b );
+ BOOL IsDDAutoWidthEnabled() const;
+
+ void SetText( const XubString& rStr );
+ void SetText( const XubString& rStr, const Selection& rNewSelection );
+
+ USHORT InsertEntry( const XubString& rStr, USHORT nPos = COMBOBOX_APPEND );
+ USHORT InsertEntry( const XubString& rStr, const Image& rImage, USHORT nPos = COMBOBOX_APPEND );
+
+ void RemoveEntry( const XubString& rStr );
+ void RemoveEntry( USHORT nPos );
+
+ void Clear();
+
+ USHORT GetEntryPos( const XubString& rStr ) const;
+ USHORT GetEntryPos( const void* pData ) const;
+ XubString GetEntry( USHORT nPos ) const;
+ USHORT GetEntryCount() const;
+
+ BOOL IsTravelSelect() const;
+ BOOL IsInDropDown() const;
+ void ToggleDropDown();
+
+ long CalcWindowSizePixel( USHORT nLines ) const;
+
+ void SetUserItemSize( const Size& rSz );
+ const Size& GetUserItemSize() const;
+
+ void EnableUserDraw( BOOL bUserDraw );
+ BOOL IsUserDrawEnabled() const;
+
+ void DrawEntry( const UserDrawEvent& rEvt, BOOL bDrawImage, BOOL bDrawText, BOOL bDrawTextAtImagePos = FALSE );
+ void SetBorderStyle( USHORT nBorderStyle );
+
+ void SetSeparatorPos( USHORT n );
+ void SetSeparatorPos();
+ USHORT GetSeparatorPos() const;
+
+ void EnableAutocomplete( BOOL bEnable, BOOL bMatchCase = FALSE );
+ BOOL IsAutocompleteEnabled() const;
+
+ void EnableMultiSelection( BOOL bMulti );
+ BOOL IsMultiSelectionEnabled() const;
+ void SetMultiSelectionSeparator( xub_Unicode cSep ) { mcMultiSep = cSep; }
+ xub_Unicode GetMultiSelectionSeparator() const { return mcMultiSep; }
+
+ void SetSelectHdl( const Link& rLink ) { maSelectHdl = rLink; }
+ const Link& GetSelectHdl() const { return maSelectHdl; }
+ void SetDoubleClickHdl( const Link& rLink ) { maDoubleClickHdl = rLink; }
+ const Link& GetDoubleClickHdl() const { return maDoubleClickHdl; }
+
+ Size CalcMinimumSize() const;
+ virtual Size GetOptimalSize(WindowSizeType eType) const;
+ Size CalcAdjustedSize( const Size& rPrefSize ) const;
+ using Edit::CalcSize;
+ Size CalcSize( USHORT nColumns, USHORT nLines ) const;
+ void GetMaxVisColumnsAndLines( USHORT& rnCols, USHORT& rnLines ) const;
+
+ void SetMRUEntries( const XubString& rEntries, xub_Unicode cSep = ';' );
+ XubString GetMRUEntries( xub_Unicode cSep = ';' ) const;
+ void SetMaxMRUCount( USHORT n );
+ USHORT GetMaxMRUCount() const;
+
+ void SetEntryData( USHORT nPos, void* pNewData );
+ void* GetEntryData( USHORT nPos ) const;
+
+ void SetTopEntry( USHORT nPos );
+ void ShowProminentEntry( USHORT nPos );
+ USHORT GetTopEntry() const;
+
+ void SetProminentEntryType( ProminentEntry eType );
+ ProminentEntry GetProminentEntryType() const;
+
+ USHORT GetDisplayLineCount() const;
+
+ USHORT GetSelectEntryCount() const;
+ USHORT GetSelectEntryPos( USHORT nSelIndex = 0 ) const;
+ BOOL IsEntryPosSelected( USHORT nPos ) const;
+ void SelectEntryPos( USHORT nPos, BOOL bSelect = TRUE );
+ void SetNoSelection();
+ Rectangle GetBoundingRectangle( USHORT nItem ) const;
+
+ /** checks whether a certain point lies within the bounds of
+ a list item and returns the item as well as the character position
+ the point is at.
+
+ <p>If the point is inside an item the item pos is put into <code>rPos</code> and
+ the item-relative character index is returned. If the point is not inside
+ an item -1 is returned and rPos is unchanged.</p>
+
+ @param rPoint
+ tells the point for which an item is requested.
+
+ @param rPos
+ gets the item at the specified point <code>rPoint</code>
+
+ @returns
+ the item-relative character index at point <code>rPos</code> or -1
+ if no item is at that point.
+ */
+ using Control::GetIndexForPoint;
+ long GetIndexForPoint( const Point& rPoint, USHORT& rPos ) const;
+};
+
+#endif // _COMBOBOX_HXX
diff --git a/vcl/inc/vcl/configsettings.hxx b/vcl/inc/vcl/configsettings.hxx
new file mode 100644
index 000000000000..779c6450e804
--- /dev/null
+++ b/vcl/inc/vcl/configsettings.hxx
@@ -0,0 +1,73 @@
+/*************************************************************************
+ *
+ * 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_INC_CONFIGSETTINGS_HXX
+#define VCL_INC_CONFIGSETTINGS_HXX
+
+#include <rtl/ustring.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <unotools/configitem.hxx>
+#include <vcl/dllapi.h>
+
+#include <hash_map>
+
+//........................................................................
+namespace vcl
+{
+//........................................................................
+
+ typedef std::hash_map< rtl::OUString, rtl::OUString, rtl::OUStringHash > OUStrMap;
+ class SmallOUStrMap : public OUStrMap { public: SmallOUStrMap() : OUStrMap(1) {} };
+
+ //====================================================================
+ //= SettingsConfigItem
+ //====================================================================
+ class VCL_DLLPUBLIC SettingsConfigItem : public ::utl::ConfigItem
+ {
+
+ std::hash_map< rtl::OUString, SmallOUStrMap, rtl::OUStringHash > m_aSettings;
+
+ virtual void Notify( const com::sun::star::uno::Sequence< rtl::OUString >& rPropertyNames );
+
+ void getValues();
+ SettingsConfigItem();
+ public:
+ virtual ~SettingsConfigItem();
+
+ static SettingsConfigItem* get();
+
+ const rtl::OUString& getValue( const rtl::OUString& rGroup, const rtl::OUString& rKey ) const;
+ void setValue( const rtl::OUString& rGroup, const rtl::OUString& rKey, const rtl::OUString& rValue );
+
+ virtual void Commit();
+ };
+
+//........................................................................
+} // namespace vcl
+//........................................................................
+
+#endif // VCL_INC_CONFIGSETTINGS_HXX
+
diff --git a/vcl/inc/vcl/controldata.hxx b/vcl/inc/vcl/controldata.hxx
new file mode 100644
index 000000000000..0be0f5bd402e
--- /dev/null
+++ b/vcl/inc/vcl/controldata.hxx
@@ -0,0 +1,62 @@
+/*************************************************************************
+ *
+ * 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_CONTROLDATA_HXX
+#define VCL_CONTROLDATA_HXX
+
+#include <vcl/controllayout.hxx>
+
+//........................................................................
+namespace vcl
+{
+//........................................................................
+
+ //====================================================================
+ //= ImplControlData
+ //====================================================================
+ struct ImplControlData
+ {
+ mutable ControlLayoutData* mpLayoutData;
+ OutputDevice* mpReferenceDevice;
+
+ ImplControlData()
+ :mpLayoutData( NULL )
+ ,mpReferenceDevice( NULL )
+ {
+ }
+
+ ~ImplControlData()
+ {
+ delete mpLayoutData;
+ }
+ };
+
+//........................................................................
+} // namespace vcl
+//........................................................................
+
+#endif // VCL_CONTROLDATA_HXX
diff --git a/vcl/inc/vcl/controllayout.hxx b/vcl/inc/vcl/controllayout.hxx
new file mode 100644
index 000000000000..574d80ea9e02
--- /dev/null
+++ b/vcl/inc/vcl/controllayout.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _VCL_CONTROLLAYOUT_HXX
+#define _VCL_CONTROLLAYOUT_HXX
+
+#include <vector>
+#include <tools/gen.hxx>
+#include <tools/string.hxx>
+#include <vcl/dllapi.h>
+
+class Control;
+
+namespace vcl
+{
+
+struct VCL_DLLPUBLIC ControlLayoutData
+{
+ // contains the string really displayed
+ // there must be exactly one bounding rectangle in m_aUnicodeBoundRects
+ // for every character in m_aDisplayText
+ String m_aDisplayText;
+ // the bounding rectangle of every character
+ // where one character may consist of many glyphs
+ std::vector< Rectangle > m_aUnicodeBoundRects;
+ // start indices of lines
+ std::vector< long > m_aLineIndices;
+ // notify parent control on destruction
+ const Control* m_pParent;
+
+ ControlLayoutData() : m_pParent( NULL ) {}
+ ~ControlLayoutData();
+
+ Rectangle GetCharacterBounds( long nIndex ) const;
+ // returns the character index for corresponding to rPoint (in control coordinates)
+ // -1 is returned if no character is at that point
+ long GetIndexForPoint( const Point& rPoint ) const;
+ // returns the number of lines in the result of GetDisplayText()
+ long GetLineCount() const;
+ // returns the interval [start,end] of line nLine
+ // returns [-1,-1] for an invalid line
+ Pair GetLineStartEnd( long nLine ) const;
+ /** ToRelativeLineIndex changes a layout data index to a count relative to its line.
+
+ <p>This is equivalent to getting the line start/end pairs with
+ <member>GetLineStartEnd</member> until the index lies within [start,end] of a line
+ </p>
+
+ @param nIndex
+ the absolute index inside the display text to be changed to a relative index
+
+ @returns
+ the relative index inside the displayed line or -1 if the absolute index does
+ not match any line
+ */
+ long ToRelativeLineIndex( long nIndex ) const;
+};
+
+} // namespace vcl
+
+#endif // _VCL_CONTROLLAYOUT_HXX
diff --git a/vcl/inc/vcl/ctrl.hxx b/vcl/inc/vcl/ctrl.hxx
new file mode 100644
index 000000000000..3838b29a6d0a
--- /dev/null
+++ b/vcl/inc/vcl/ctrl.hxx
@@ -0,0 +1,201 @@
+/*************************************************************************
+ *
+ * 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_CTRL_HXX
+#define _SV_CTRL_HXX
+
+#include <tools/link.hxx>
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/window.hxx>
+#include <vcl/salnativewidgets.hxx>
+
+// forward
+namespace vcl { struct ImplControlData; struct ControlLayoutData; }
+
+// -----------
+// - Control -
+// -----------
+
+class VCL_DLLPUBLIC Control : public Window
+{
+protected:
+ ::vcl::ImplControlData* mpControlData;
+
+private:
+ BOOL mbHasFocus;
+ Link maGetFocusHdl;
+ Link maLoseFocusHdl;
+
+ SAL_DLLPRIVATE void ImplInitControlData();
+
+ // Copy assignment is forbidden and not implemented.
+ SAL_DLLPRIVATE Control (const Control &);
+ SAL_DLLPRIVATE Control & operator= (const Control &);
+
+protected:
+ Control( WindowType nType );
+ virtual void FillLayoutData() const;
+
+ // helper method for composite controls
+ void AppendLayoutData( const Control& rSubControl ) const;
+
+ /// creates the mpData->mpLayoutData structure
+ void CreateLayoutData() const;
+ /// determines whether we currently have layout data
+ bool HasLayoutData() const;
+ /// returns the current layout data
+ ::vcl::ControlLayoutData*
+ GetLayoutData() const;
+
+ /** this calls both our event listeners, and a specified handler
+
+ If the Control instance is destroyed during any of those calls, the
+ method properly handles this (in particular, it doesn't crash :)
+
+ @param nEvent
+ the event to notify to our event listeners
+ @param rHandler
+ the handler to call
+ @param pCaller
+ the parameter to pass to the handler call
+ @return
+ if the Control instance has been destroyed in any of the call
+ */
+ BOOL ImplCallEventListenersAndHandler(
+ ULONG nEvent, const Link& rHandler, void* pCaller
+ );
+
+ /** draws the given text onto the given device
+
+ If no reference device is set, the draw request will simply be forwarded to OutputDevice::DrawText. Otherwise,
+ the text will be rendered according to the metrics at the reference device.
+
+ Note that the given rectangle might be modified, it will contain the result of a GetTextRect call (either
+ directly at the target device, or taking the reference device into account) when returning.
+ */
+ void DrawControlText( OutputDevice& _rTargetDevice, Rectangle& _io_rRect,
+ const XubString& _rStr, USHORT _nStyle,
+ MetricVector* _pVector, String* _pDisplayText ) const;
+
+ virtual const Font&
+ GetCanonicalFont( const StyleSettings& _rStyle ) const;
+ virtual const Color&
+ GetCanonicalTextColor( const StyleSettings& _rStyle ) const;
+
+ void ImplInitSettings( const BOOL _bFont, const BOOL _bForeground );
+
+//#if 0 // _SOLAR__PRIVATE
+public:
+ SAL_DLLPRIVATE void ImplClearLayoutData() const;
+ /** draws a frame around the give rectangle, onto the given device
+
+ only to be used from within the <member>Window::Draw</member> method of your sub class.
+
+ The frame is always drawn with a single line (without 3D effects). In addition, any mono
+ color set at the control's settings is respected. Yet more additionally, if we're living
+ in a themed desktop, this theming is ignored.
+
+ Note that this makes sense, since the *only known* clients of <member>Window::Draw</member>
+ are form controls, when printed or print-previewed. For form controls embedded in office documents,
+ you don't want to have the theme look.
+
+ @param pDev
+ the device to draw onto
+ @param rRect
+ the rect for drawing the frame. Upon returning from the call, the rect will be inflated
+ by the space occupied by the drawn pixels.
+ */
+ SAL_DLLPRIVATE void ImplDrawFrame( OutputDevice* pDev, Rectangle& rRect );
+//#endif
+
+public:
+ Control( Window* pParent, WinBits nWinStyle = 0 );
+ Control( Window* pParent, const ResId& rResId );
+ ~Control();
+
+ virtual void GetFocus();
+ virtual void LoseFocus();
+ virtual long Notify( NotifyEvent& rNEvt );
+ virtual void StateChanged( StateChangedType nStateChange );
+ virtual void Resize();
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+
+ // invalidates layout data
+ virtual void SetText( const String& rStr );
+ // gets the displayed text
+ virtual String GetDisplayText() const;
+ // returns the bounding box for the character at index nIndex (in control coordinates)
+ Rectangle GetCharacterBounds( long nIndex ) const;
+ // returns the character index for corresponding to rPoint (in control coordinates)
+ // -1 is returned if no character is at that point
+ long GetIndexForPoint( const Point& rPoint ) const;
+ // returns the number of lines in the result of GetDisplayText()
+ long GetLineCount() const;
+ // returns the interval [start,end] of line nLine
+ // returns [-1,-1] for an invalid line
+ Pair GetLineStartEnd( long nLine ) const;
+ /** ToRelativeLineIndex changes a layout data index to a count relative to its line.
+
+ <p>This is equivalent to getting the line start/end pairs with
+ <member>GetLineStartEnd</member> until the index lies within [start,end] of a line
+ </p>
+
+ @param nIndex
+ the absolute index inside the display text to be changed to a relative index
+
+ @returns
+ the relative index inside the displayed line or -1 if the absolute index does
+ not match any line
+ */
+ long ToRelativeLineIndex( long nIndex ) const;
+
+ void SetGetFocusHdl( const Link& rLink ) { maGetFocusHdl = rLink; }
+ const Link& GetGetFocusHdl() const { return maGetFocusHdl; }
+ void SetLoseFocusHdl( const Link& rLink ) { maLoseFocusHdl = rLink; }
+ const Link& GetLoseFocusHdl() const { return maLoseFocusHdl; }
+
+ void SetLayoutDataParent( const Control* pParent ) const;
+
+ virtual Size GetOptimalSize(WindowSizeType eType) const;
+
+ /** sets a reference device used for rendering control text
+ @seealso DrawControlText
+ */
+ void SetReferenceDevice( OutputDevice* _referenceDevice );
+ OutputDevice* GetReferenceDevice() const;
+
+ Font GetUnzoomedControlPointFont() const
+ {
+ Font aFont( GetCanonicalFont( GetSettings().GetStyleSettings() ) );
+ if ( IsControlFont() )
+ aFont.Merge( GetControlFont() );
+ return aFont;
+ }
+};
+
+#endif // _SV_CTRL_HXX
diff --git a/vcl/inc/vcl/cursor.hxx b/vcl/inc/vcl/cursor.hxx
new file mode 100644
index 000000000000..db8f5efd0566
--- /dev/null
+++ b/vcl/inc/vcl/cursor.hxx
@@ -0,0 +1,119 @@
+/*************************************************************************
+ *
+ * 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_CURSOR_HXX
+#define _SV_CURSOR_HXX
+
+#include <tools/gen.hxx>
+#include <tools/link.hxx>
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+
+class AutoTimer;
+struct ImplCursorData;
+class Window;
+
+// -----------------
+// - Cursor-Styles -
+// -----------------
+
+#define CURSOR_SHADOW ((USHORT)0x0001)
+#define CURSOR_DIRECTION_NONE ((unsigned char)0x00)
+#define CURSOR_DIRECTION_LTR ((unsigned char)0x01)
+#define CURSOR_DIRECTION_RTL ((unsigned char)0x02)
+
+// ----------
+// - Cursor -
+// ----------
+
+class VCL_DLLPUBLIC Cursor
+{
+private:
+ ImplCursorData* mpData; // Interne Daten
+ Window* mpWindow; // Window (only for shadow cursor)
+ long mnSlant; // Schraegstellung
+ long mnOffsetY; // Offset fuer Rotation
+ Size maSize; // Groesse
+ Point maPos; // Position
+ short mnOrientation; // Rotation
+ USHORT mnStyle; // Style
+ BOOL mbVisible; // Ist Cursor sichtbar
+ unsigned char mnDirection; // indicates direction
+
+//#if 0 // _SOLAR__PRIVATE
+public:
+ SAL_DLLPRIVATE void ImplDraw();
+ SAL_DLLPRIVATE void ImplRestore();
+ DECL_DLLPRIVATE_LINK( ImplTimerHdl, AutoTimer* );
+ SAL_DLLPRIVATE void ImplShow( BOOL bDrawDirect = TRUE );
+ SAL_DLLPRIVATE void ImplHide();
+ SAL_DLLPRIVATE void ImplNew();
+//#endif
+
+public:
+ Cursor();
+ Cursor( const Cursor& rCursor );
+ ~Cursor();
+
+ void SetStyle( USHORT nStyle );
+ USHORT GetStyle() const { return mnStyle; }
+
+ void Show();
+ void Hide();
+ BOOL IsVisible() const { return mbVisible; }
+
+ void SetWindow( Window* pWindow );
+ Window* GetWindow() const { return mpWindow; }
+
+ void SetPos( const Point& rNewPos );
+ const Point& GetPos() const { return maPos; }
+ void SetOffsetY( long mnOffsetY = 0 );
+ long GetOffsetY() const { return mnOffsetY; }
+
+ void SetSize( const Size& rNewSize );
+ const Size& GetSize() const { return maSize; }
+ void SetWidth( long nNewWidth );
+ long GetWidth() const { return maSize.Width(); }
+ void SetHeight( long nNewHeight );
+ long GetHeight() const { return maSize.Height(); }
+
+ void SetSlant( long nSlant = 0 );
+ long GetSlant() const { return mnSlant; }
+
+ void SetOrientation( short nOrientation = 0 );
+ short GetOrientation() const { return mnOrientation; }
+
+ void SetDirection( unsigned char nDirection = 0 );
+ unsigned char GetDirection() const { return mnDirection; }
+
+ Cursor& operator=( const Cursor& rCursor );
+ BOOL operator==( const Cursor& rCursor ) const;
+ BOOL operator!=( const Cursor& rCursor ) const
+ { return !(Cursor::operator==( rCursor )); }
+};
+
+#endif // _SV_CURSOR_HXX
diff --git a/vcl/inc/vcl/cvtgrf.hxx b/vcl/inc/vcl/cvtgrf.hxx
new file mode 100644
index 000000000000..97541c1b8f9f
--- /dev/null
+++ b/vcl/inc/vcl/cvtgrf.hxx
@@ -0,0 +1,70 @@
+/*************************************************************************
+ *
+ * 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_CVTGRF_HXX
+#define _SV_CVTGRF_HXX
+
+#include <vcl/dllapi.h>
+#include <tools/link.hxx>
+#include <vcl/salctype.hxx>
+
+// --------------------
+// - GraphicConverter -
+// --------------------
+
+struct ConvertData;
+class Graphic;
+
+class VCL_DLLPUBLIC GraphicConverter
+{
+private:
+
+ Link maFilterHdl;
+ ConvertData* mpConvertData;
+
+//#if 0 // _SOLAR__PRIVATE
+public:
+ SAL_DLLPRIVATE ULONG ImplConvert( ULONG nInFormat, void* pInBuffer, ULONG nInBufSize,
+ void** ppOutBuffer, ULONG nOutFormat );
+//#endif // __PRIVATE
+
+public:
+
+ GraphicConverter();
+ ~GraphicConverter();
+
+ static ULONG Import( SvStream& rIStm, Graphic& rGraphic, ULONG nFormat = CVT_UNKNOWN );
+ static ULONG Export( SvStream& rOStm, const Graphic& rGraphic, ULONG nFormat );
+
+ ConvertData* GetConvertData() { return mpConvertData; }
+
+ void SetFilterHdl( const Link& rLink ) { maFilterHdl = rLink; }
+ const Link& GetFilterHdl() const { return maFilterHdl; }
+};
+
+#endif // _SV_CVTGRF_HXX
+
diff --git a/vcl/inc/vcl/cvtsvm.hxx b/vcl/inc/vcl/cvtsvm.hxx
new file mode 100644
index 000000000000..03948ac56690
--- /dev/null
+++ b/vcl/inc/vcl/cvtsvm.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_CVTMTF_HXX
+#define _SV_CVTMTF_HXX
+
+#include <vcl/dllapi.h>
+#include <vcl/metaact.hxx>
+#include <vcl/gdimtf.hxx>
+
+// -----------
+// - Defines -
+// -----------
+
+#define CONVERT_TO_SVM1 0x00000001UL
+#define CONVERT_FROM_SVM1 0x00000002UL
+
+#define GDI_PIXEL_ACTION 1
+#define GDI_POINT_ACTION 2
+#define GDI_LINE_ACTION 3
+#define GDI_RECT_ACTION 4
+#define GDI_ELLIPSE_ACTION 5
+#define GDI_ARC_ACTION 6
+#define GDI_PIE_ACTION 7
+#define GDI_INVERTRECT_ACTION 8
+#define GDI_HIGHLIGHTRECT_ACTION 9
+#define GDI_POLYLINE_ACTION 10
+#define GDI_POLYGON_ACTION 11
+#define GDI_POLYPOLYGON_ACTION 12
+#define GDI_TEXT_ACTION 13
+#define GDI_TEXTARRAY_ACTION 14
+#define GDI_STRETCHTEXT_ACTION 15
+#define GDI_ICON_ACTION 16
+#define GDI_BITMAP_ACTION 17
+#define GDI_BITMAPSCALE_ACTION 18
+#define GDI_PEN_ACTION 19
+#define GDI_FONT_ACTION 20
+#define GDI_BACKBRUSH_ACTION 21
+#define GDI_FILLBRUSH_ACTION 22
+#define GDI_MAPMODE_ACTION 23
+#define GDI_CLIPREGION_ACTION 24
+#define GDI_RASTEROP_ACTION 25
+#define GDI_PUSH_ACTION 26
+#define GDI_POP_ACTION 27
+#define GDI_MOVECLIPREGION_ACTION 28
+#define GDI_ISECTCLIPREGION_ACTION 29
+#define GDI_MTF_ACTION 30
+#define GDI_BITMAPSCALEPART_ACTION 32
+#define GDI_GRADIENT_ACTION 33
+
+#define GDI_TRANSPARENT_COMMENT 1024
+#define GDI_HATCH_COMMENT 1025
+#define GDI_REFPOINT_COMMENT 1026
+#define GDI_TEXTLINECOLOR_COMMENT 1027
+#define GDI_TEXTLINE_COMMENT 1028
+#define GDI_FLOATTRANSPARENT_COMMENT 1029
+#define GDI_GRADIENTEX_COMMENT 1030
+#define GDI_COMMENT_COMMENT 1031
+#define GDI_UNICODE_COMMENT 1032
+
+#define GDI_LINEJOIN_ACTION 1033
+#define GDI_EXTENDEDPOLYGON_ACTION 1034
+#define GDI_LINEDASHDOT_ACTION 1035
+
+// ----------------
+// - SVMConverter -
+// ----------------
+
+class Stack;
+
+class VCL_DLLPUBLIC SVMConverter
+{
+private:
+//#if 0 // _SOLAR__PRIVATE
+ SAL_DLLPRIVATE void ImplConvertFromSVM1( SvStream& rIStm, GDIMetaFile& rMtf );
+ SAL_DLLPRIVATE void ImplConvertToSVM1( SvStream& rOStm, GDIMetaFile& rMtf );
+ SAL_DLLPRIVATE ULONG ImplWriteActions( SvStream& rOStm, GDIMetaFile& rMtf,
+ VirtualDevice& rSaveVDev, BOOL& rRop_0_1,
+ Color& rLineCol, Stack& rLineColStack,
+ rtl_TextEncoding& rActualCharSet );
+//#endif
+
+public:
+ SVMConverter( SvStream& rIStm, GDIMetaFile& rMtf, ULONG nConvertMode );
+ ~SVMConverter() {}
+
+private:
+ // Not implemented
+ SVMConverter( const SVMConverter& );
+ SVMConverter& operator=( const SVMConverter& );
+};
+
+#endif // _SV_CVTMTF_HXX
diff --git a/vcl/inc/vcl/dbggui.hxx b/vcl/inc/vcl/dbggui.hxx
new file mode 100644
index 000000000000..7ed23706e6f3
--- /dev/null
+++ b/vcl/inc/vcl/dbggui.hxx
@@ -0,0 +1,74 @@
+/*************************************************************************
+ *
+ * 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_DBGGUI_HXX
+#define _SV_DBGGUI_HXX
+
+#include <vcl/sv.h>
+
+// ------------
+// - DBG_UITL -
+// ------------
+
+#ifdef DBG_UTIL
+
+class Window;
+class XubString;
+
+void DbgGUIInit();
+void DbgGUIDeInit();
+void DbgGUIStart();
+void DbgDialogTest( Window* pWindow );
+
+/** registers a named user-defined channel for emitting the diagnostic messages
+ @return
+ a unique number for this channel, which can be used for ->DbgData::nErrorOut,
+ ->DbgData::nWarningOut and ->DbgData::nTraceOut
+ @see DBG_OUT_USER_CHANNEL_0
+*/
+USHORT DbgRegisterNamedUserChannel( const XubString& _rChannelUIName, DbgPrintLine pProc );
+
+#define DBGGUI_INIT() DbgGUIInit()
+#define DBGGUI_DEINIT() DbgGUIDeInit()
+#define DBGGUI_START() DbgGUIStart()
+
+#define DBG_DIALOGTEST( pWindow ) \
+ if ( DbgIsDialog() ) \
+ DbgDialogTest( pWindow );
+
+#else
+
+
+#define DBGGUI_INIT()
+#define DBGGUI_DEINIT()
+#define DBGGUI_START()
+
+#define DBG_DIALOGTEST( pWindow )
+
+#endif
+
+#endif // _SV_DBGGUI_HXX
diff --git a/vcl/inc/vcl/decoview.hxx b/vcl/inc/vcl/decoview.hxx
new file mode 100644
index 000000000000..2412ceda8431
--- /dev/null
+++ b/vcl/inc/vcl/decoview.hxx
@@ -0,0 +1,110 @@
+/*************************************************************************
+ *
+ * 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_DECOVIEW_HXX
+#define _SV_DECOVIEW_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/symbol.hxx>
+
+class Rectangle;
+class Point;
+class Color;
+class OutputDevice;
+
+// ------------------------
+// - DecorationView-Types -
+// ------------------------
+
+// Flags for DrawSymbol()
+#define SYMBOL_DRAW_MONO ((USHORT)0x0001)
+#define SYMBOL_DRAW_DISABLE ((USHORT)0x0002)
+
+// Flags for DrawFrame()
+#define FRAME_DRAW_IN ((USHORT)0x0001)
+#define FRAME_DRAW_OUT ((USHORT)0x0002)
+#define FRAME_DRAW_GROUP ((USHORT)0x0003)
+#define FRAME_DRAW_DOUBLEIN ((USHORT)0x0004)
+#define FRAME_DRAW_DOUBLEOUT ((USHORT)0x0005)
+#define FRAME_DRAW_MENU ((USHORT)0x0010)
+#define FRAME_DRAW_WINDOWBORDER ((USHORT)0x0020)
+#define FRAME_DRAW_BORDERWINDOWBORDER ((USHORT)0x0040)
+#define FRAME_DRAW_MONO ((USHORT)0x1000)
+#define FRAME_DRAW_NODRAW ((USHORT)0x8000)
+#define FRAME_DRAW_STYLE ((USHORT)0x000F)
+
+// Flags for DrawHighlightFrame()
+#define FRAME_HIGHLIGHT_IN ((USHORT)0x0001)
+#define FRAME_HIGHLIGHT_OUT ((USHORT)0x0002)
+#define FRAME_HIGHLIGHT_TESTBACKGROUND ((USHORT)0x4000)
+#define FRAME_HIGHLIGHT_STYLE ((USHORT)0x000F)
+
+// Flags for DrawButton()
+#define BUTTON_DRAW_DEFAULT ((USHORT)0x0001)
+#define BUTTON_DRAW_NOLIGHTBORDER ((USHORT)0x0002)
+#define BUTTON_DRAW_PRESSED ((USHORT)0x0004)
+#define BUTTON_DRAW_CHECKED ((USHORT)0x0008)
+#define BUTTON_DRAW_DONTKNOW ((USHORT)0x0010)
+#define BUTTON_DRAW_MONO ((USHORT)0x0020)
+#define BUTTON_DRAW_NOFILL ((USHORT)0x0040)
+#define BUTTON_DRAW_DISABLED ((USHORT)0x0080)
+#define BUTTON_DRAW_HIGHLIGHT ((USHORT)0x0100)
+#define BUTTON_DRAW_FLAT ((USHORT)0x0200)
+#define BUTTON_DRAW_NOTOPLIGHTBORDER ((USHORT)0x0400)
+#define BUTTON_DRAW_NOBOTTOMSHADOWBORDER ((USHORT)0x0800)
+#define BUTTON_DRAW_NOLEFTLIGHTBORDER ((USHORT)0x1000)
+#define BUTTON_DRAW_NOTEXT ((USHORT)0x2000)
+#define BUTTON_DRAW_NOIMAGE ((USHORT)0x4000)
+#define BUTTON_DRAW_NODRAW ((USHORT)0x8000)
+
+// ------------------
+// - DecorationView -
+// ------------------
+
+class VCL_DLLPUBLIC DecorationView
+{
+private:
+ OutputDevice* mpOutDev;
+
+public:
+ DecorationView( OutputDevice* pOutDev )
+ { mpOutDev = pOutDev; }
+
+ void DrawSymbol( const Rectangle& rRect, SymbolType eType,
+ const Color& rColor, USHORT nStyle = 0 );
+ void DrawFrame( const Rectangle& rRect,
+ const Color& rLeftTopColor,
+ const Color& rRightBottomColor );
+ void DrawHighlightFrame( const Rectangle& rRect,
+ USHORT nStyle = FRAME_HIGHLIGHT_OUT );
+ Rectangle DrawFrame( const Rectangle& rRect, USHORT nStyle = FRAME_DRAW_OUT );
+ Rectangle DrawButton( const Rectangle& rRect, USHORT nStyle );
+ void DrawSeparator( const Point& rStart, const Point& rStop, bool bVertical = true );
+};
+
+#endif // _SV_DECOVIEW_HXX
diff --git a/vcl/inc/vcl/dialog.hxx b/vcl/inc/vcl/dialog.hxx
new file mode 100644
index 000000000000..60fe97225b4b
--- /dev/null
+++ b/vcl/inc/vcl/dialog.hxx
@@ -0,0 +1,162 @@
+/*************************************************************************
+ *
+ * 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_DIALOG_HXX
+#define _SV_DIALOG_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/syswin.hxx>
+
+// parameter to pass to the dialogue constructor if really no parent is wanted
+// whereas NULL chooses the deafult dialogue parent
+#define DIALOG_NO_PARENT ((Window*)0xffffffff)
+
+// ----------
+// - Dialog -
+// ----------
+
+struct DialogImpl;
+
+class VCL_DLLPUBLIC Dialog : public SystemWindow
+{
+private:
+ Window* mpDialogParent;
+ Dialog* mpPrevExecuteDlg;
+ DialogImpl* mpDialogImpl;
+ long mnMousePositioned;
+ BOOL mbInExecute;
+ BOOL mbOldSaveBack;
+ BOOL mbInClose;
+ BOOL mbModalMode;
+
+ SAL_DLLPRIVATE void ImplInitDialogData();
+ SAL_DLLPRIVATE void ImplInitSettings();
+
+//#if 0 // _SOLAR__PRIVATE
+ // Copy assignment is forbidden and not implemented.
+ SAL_DLLPRIVATE Dialog (const Dialog &);
+ SAL_DLLPRIVATE Dialog & operator= (const Dialog &);
+
+ DECL_DLLPRIVATE_LINK( ImplAsyncCloseHdl, void* );
+protected:
+ using Window::ImplInit;
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle );
+ SAL_DLLPRIVATE void ImplDialogRes( const ResId& rResId );
+ SAL_DLLPRIVATE void ImplCenterDialog();
+
+public:
+ SAL_DLLPRIVATE BOOL IsInClose() const { return mbInClose; }
+//#endif
+
+protected:
+ Dialog( WindowType nType );
+ virtual void Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG nFlags );
+
+public:
+ Dialog( Window* pParent, WinBits nStyle = WB_STDDIALOG );
+ Dialog( Window* pParent, const ResId& rResId );
+ virtual ~Dialog();
+
+ virtual long Notify( NotifyEvent& rNEvt );
+ virtual void StateChanged( StateChangedType nStateChange );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+
+ virtual BOOL Close();
+
+ virtual short Execute();
+ BOOL IsInExecute() const { return mbInExecute; }
+
+ ////////////////////////////////////////
+ // Dialog::Execute replacement API
+public:
+ // Link impl: DECL_LINK( MyEndDialogHdl, Dialog* ); <= param is dialog just ended
+ virtual void StartExecuteModal( const Link& rEndDialogHdl );
+ BOOL IsStartedModal() const;
+ long GetResult() const;
+private:
+ BOOL ImplStartExecuteModal();
+ void ImplEndExecuteModal();
+public:
+
+ // Dialog::Execute replacement API
+ ////////////////////////////////////////
+
+ void EndDialog( long nResult = 0 );
+ static void EndAllDialogs( Window* pParent=NULL );
+
+ void GetDrawWindowBorder( sal_Int32& rLeftBorder, sal_Int32& rTopBorder,
+ sal_Int32& rRightBorder, sal_Int32& rBottomBorder ) const;
+
+ void SetModalInputMode( BOOL bModal );
+ void SetModalInputMode( BOOL bModal, BOOL bSubModalDialogs );
+ BOOL IsModalInputMode() const { return mbModalMode; }
+
+ void GrabFocusToFirstControl();
+};
+
+// ------------------
+// - ModelessDialog -
+// ------------------
+
+class VCL_DLLPUBLIC ModelessDialog : public Dialog
+{
+//#if 0 // _SOLAR__PRIVATE
+ // Copy assignment is forbidden and not implemented.
+ SAL_DLLPRIVATE ModelessDialog (const ModelessDialog &);
+ SAL_DLLPRIVATE ModelessDialog & operator= (const ModelessDialog &);
+//#endif
+
+public:
+ ModelessDialog( Window* pParent, WinBits nStyle = WB_STDMODELESS );
+ ModelessDialog( Window* pParent, const ResId& rResId );
+};
+
+// ---------------
+// - ModalDialog -
+// ---------------
+
+class VCL_DLLPUBLIC ModalDialog : public Dialog
+{
+public:
+ ModalDialog( Window* pParent, WinBits nStyle = WB_STDMODAL );
+ ModalDialog( Window* pParent, const ResId& rResId );
+
+private:
+ using Window::Show;
+ void Show( BOOL bVisible = TRUE );
+ using Window::Hide;
+ void Hide();
+
+//#if 0 // _SOLAR__PRIVATE
+ // Copy assignment is forbidden and not implemented.
+ SAL_DLLPRIVATE ModalDialog (const ModalDialog &);
+ SAL_DLLPRIVATE ModalDialog & operator= (const ModalDialog &);
+//#endif
+};
+
+#endif // _SV_DIALOG_HXX
diff --git a/vcl/inc/vcl/dllapi.h b/vcl/inc/vcl/dllapi.h
new file mode 100644
index 000000000000..bcf4001aa671
--- /dev/null
+++ b/vcl/inc/vcl/dllapi.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _VCL_DLLAPI_H
+#define _VCL_DLLAPI_H
+
+#include "sal/config.h"
+#include "sal/types.h"
+
+#if defined VCL_DLLIMPLEMENTATION
+#define VCL_DLLPUBLIC SAL_DLLPUBLIC_EXPORT
+#else
+#define VCL_DLLPUBLIC SAL_DLLPUBLIC_IMPORT
+#endif
+
+#endif
diff --git a/vcl/inc/vcl/dndhelp.hxx b/vcl/inc/vcl/dndhelp.hxx
new file mode 100644
index 000000000000..3929bc1ebafc
--- /dev/null
+++ b/vcl/inc/vcl/dndhelp.hxx
@@ -0,0 +1,126 @@
+/*************************************************************************
+ *
+ * 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_DNDHELP_HXX
+#define _VCL_DNDHELP_HXX
+
+#include <vcl/dllapi.h>
+#include <cppuhelper/weak.hxx>
+#include <com/sun/star/datatransfer/dnd/XDragGestureListener.hpp>
+#include <com/sun/star/datatransfer/dnd/XDragSourceListener.hpp>
+#include <com/sun/star/datatransfer/dnd/XDropTargetListener.hpp>
+
+namespace com {
+namespace sun {
+namespace star {
+
+namespace datatransfer {
+namespace dnd {
+ struct DragGestureEvent;
+ struct DragSourceDragEvent;
+ struct DragSourceDropEvent;
+ struct DragSourceEvent;
+ struct DropTargetDragEvent;
+ struct DropTargetDragEnterEvent;
+ struct DropTargetDropEvent;
+ struct DropTargetEvent;
+}}
+
+}}}
+
+namespace vcl
+{
+
+namespace unohelper
+{
+
+class VCL_DLLPUBLIC DragAndDropClient
+{
+public:
+ virtual ~DragAndDropClient();
+
+ // ::com::sun::star::datatransfer::dnd::XDragGestureListener
+ virtual void dragGestureRecognized( const ::com::sun::star::datatransfer::dnd::DragGestureEvent& dge ) throw (::com::sun::star::uno::RuntimeException);
+
+ // ::com::sun::star::datatransfer::dnd::XDragSourceListener
+ virtual void dragDropEnd( const ::com::sun::star::datatransfer::dnd::DragSourceDropEvent& dsde ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void dragEnter( const ::com::sun::star::datatransfer::dnd::DragSourceDragEvent& dsde ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void dragExit( const ::com::sun::star::datatransfer::dnd::DragSourceEvent& dse ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void dragOver( const ::com::sun::star::datatransfer::dnd::DragSourceDragEvent& dsde ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void dropActionChanged( const ::com::sun::star::datatransfer::dnd::DragSourceDragEvent& dsde ) throw (::com::sun::star::uno::RuntimeException);
+
+ // ::com::sun::star::datatransfer::dnd::XDropTargetListener
+ virtual void drop( const ::com::sun::star::datatransfer::dnd::DropTargetDropEvent& dtde ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void dragEnter( const ::com::sun::star::datatransfer::dnd::DropTargetDragEnterEvent& dtdee ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void dragExit( const ::com::sun::star::datatransfer::dnd::DropTargetEvent& dte ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void dragOver( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& dtde ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void dropActionChanged( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& dtde ) throw (::com::sun::star::uno::RuntimeException);
+};
+
+class VCL_DLLPUBLIC DragAndDropWrapper :
+ public ::com::sun::star::datatransfer::dnd::XDragGestureListener,
+ public ::com::sun::star::datatransfer::dnd::XDragSourceListener,
+ public ::com::sun::star::datatransfer::dnd::XDropTargetListener,
+ public ::cppu::OWeakObject
+{
+private:
+ DragAndDropClient* mpClient;
+
+public:
+ DragAndDropWrapper( DragAndDropClient* pClient );
+ ~DragAndDropWrapper();
+
+ // ::com::sun::star::uno::XInterface
+ ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type & rType ) throw(::com::sun::star::uno::RuntimeException);
+ void SAL_CALL acquire() throw() { OWeakObject::acquire(); }
+ void SAL_CALL release() throw() { OWeakObject::release(); }
+
+ // ::com::sun::star::lang::XEventListener
+ void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw (::com::sun::star::uno::RuntimeException);
+
+ // ::com::sun::star::datatransfer::dnd::XDragGestureListener
+ void SAL_CALL dragGestureRecognized( const ::com::sun::star::datatransfer::dnd::DragGestureEvent& dge ) throw (::com::sun::star::uno::RuntimeException);
+
+ // ::com::sun::star::datatransfer::dnd::XDragSourceListener
+ void SAL_CALL dragDropEnd( const ::com::sun::star::datatransfer::dnd::DragSourceDropEvent& dsde ) throw (::com::sun::star::uno::RuntimeException);
+ void SAL_CALL dragEnter( const ::com::sun::star::datatransfer::dnd::DragSourceDragEvent& dsde ) throw (::com::sun::star::uno::RuntimeException);
+ void SAL_CALL dragExit( const ::com::sun::star::datatransfer::dnd::DragSourceEvent& dse ) throw (::com::sun::star::uno::RuntimeException);
+ void SAL_CALL dragOver( const ::com::sun::star::datatransfer::dnd::DragSourceDragEvent& dsde ) throw (::com::sun::star::uno::RuntimeException);
+ void SAL_CALL dropActionChanged( const ::com::sun::star::datatransfer::dnd::DragSourceDragEvent& dsde ) throw (::com::sun::star::uno::RuntimeException);
+
+ // ::com::sun::star::datatransfer::dnd::XDropTargetListener
+ void SAL_CALL drop( const ::com::sun::star::datatransfer::dnd::DropTargetDropEvent& dtde ) throw (::com::sun::star::uno::RuntimeException);
+ void SAL_CALL dragEnter( const ::com::sun::star::datatransfer::dnd::DropTargetDragEnterEvent& dtdee ) throw (::com::sun::star::uno::RuntimeException);
+ void SAL_CALL dragExit( const ::com::sun::star::datatransfer::dnd::DropTargetEvent& dte ) throw (::com::sun::star::uno::RuntimeException);
+ void SAL_CALL dragOver( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& dtde ) throw (::com::sun::star::uno::RuntimeException);
+ void SAL_CALL dropActionChanged( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& dtde ) throw (::com::sun::star::uno::RuntimeException);
+};
+
+}} // namespace vcl::unohelper
+
+#endif // _VCL_DNDHELP_HXX
+
diff --git a/vcl/inc/vcl/dockingarea.hxx b/vcl/inc/vcl/dockingarea.hxx
new file mode 100644
index 000000000000..848ecac72770
--- /dev/null
+++ b/vcl/inc/vcl/dockingarea.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_DOCKINGAREA_HXX
+#define _SV_DOCKINGAREA_HXX
+
+#include <vcl/sv.h>
+#include <vcl/window.hxx>
+
+// ------------------------------------------
+// A simple container for docked toolbars
+// - its main purpose is theming support
+// ------------------------------------------
+
+class VCL_DLLPUBLIC DockingAreaWindow : public Window
+{
+ class ImplData;
+
+private:
+ ImplData* mpImplData;
+
+ // Copy assignment is forbidden and not implemented.
+ SAL_DLLPRIVATE DockingAreaWindow (const DockingAreaWindow &);
+ SAL_DLLPRIVATE DockingAreaWindow & operator= (const DockingAreaWindow &);
+
+public:
+ DockingAreaWindow( Window *pParent );
+ ~DockingAreaWindow();
+
+ void SetAlign( WindowAlign eNewAlign );
+ WindowAlign GetAlign() const;
+ BOOL IsHorizontal() const;
+
+ virtual void Paint( const Rectangle& rRect );
+ virtual void Resize();
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+ virtual void StateChanged( StateChangedType nType );
+
+};
+
+#endif // _SV_SYSWIN_HXX
diff --git a/vcl/inc/vcl/dockwin.hxx b/vcl/inc/vcl/dockwin.hxx
new file mode 100644
index 000000000000..61464400d595
--- /dev/null
+++ b/vcl/inc/vcl/dockwin.hxx
@@ -0,0 +1,452 @@
+/*************************************************************************
+ *
+ * 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_DOCKWIN_HXX
+#define _SV_DOCKWIN_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/floatwin.hxx>
+#include <vector>
+
+// data to be sent with docking events
+struct DockingData
+{
+ Point maMousePos; // in
+ Rectangle maTrackRect; // in/out
+ BOOL mbFloating; // out
+ BOOL mbLivemode; // in
+ BOOL mbInteractive; // in
+
+ DockingData() {};
+ DockingData( const Point& rPt, const Rectangle& rRect, BOOL b) :
+ maMousePos( rPt ), maTrackRect( rRect ), mbFloating( b ), mbLivemode( FALSE ), mbInteractive( TRUE )
+ {};
+};
+
+struct EndDockingData
+{
+ Rectangle maWindowRect; // in
+ BOOL mbFloating; // in
+ BOOL mbCancelled; // in
+
+ EndDockingData() {};
+ EndDockingData( const Rectangle& rRect, BOOL b, BOOL bCancelled ) :
+ maWindowRect( rRect ), mbFloating( b ), mbCancelled( bCancelled )
+ {};
+};
+
+struct EndPopupModeData
+{
+ Point maFloatingPos; // in
+ BOOL mbTearoff; // in
+
+ EndPopupModeData() {};
+ EndPopupModeData( const Point& rPos, BOOL bTearoff ) :
+ maFloatingPos( rPos ), mbTearoff( bTearoff )
+ {};
+};
+
+/** ImplDockingWindowWrapper
+ *
+ * ImplDockingWindowWrapper obsoletes the DockingWindow class.
+ * It is better because it can make a "normal window" dockable.
+ * All DockingWindows should be converted the new class.
+ */
+
+class ImplDockingWindowWrapper
+{
+ friend class Window;
+ friend class DockingManager;
+ friend class DockingWindow;
+
+private:
+
+ // the original 'Docking'window
+ Window *mpDockingWindow;
+
+ // the original DockingWindow members
+ FloatingWindow* mpFloatWin;
+ Window* mpOldBorderWin;
+ Window* mpParent;
+ Point maFloatPos;
+ Point maDockPos;
+ Point maMouseOff;
+ Point maMouseStart;
+ Size maRollUpOutSize;
+ Size maMinOutSize;
+ Size maMaxOutSize;
+ Rectangle maDragArea;
+ long mnTrackX;
+ long mnTrackY;
+ long mnTrackWidth;
+ long mnTrackHeight;
+ sal_Int32 mnDockLeft;
+ sal_Int32 mnDockTop;
+ sal_Int32 mnDockRight;
+ sal_Int32 mnDockBottom;
+ WinBits mnFloatBits;
+ BOOL mbDockCanceled:1,
+ mbFloatPrevented:1,
+ mbDockable:1,
+ mbDocking:1,
+ mbDragFull:1,
+ mbLastFloatMode:1,
+ mbStartFloat:1,
+ mbTrackDock:1,
+ mbPined:1,
+ mbRollUp:1,
+ mbDockBtn:1,
+ mbHideBtn:1,
+ mbStartDockingEnabled:1,
+ mbLocked:1;
+
+ void ImplInitData();
+
+ DECL_LINK( PopupModeEnd, void* );
+ void ImplEnableStartDocking( BOOL bEnable = TRUE ) { mbStartDockingEnabled = bEnable; }
+ BOOL ImplStartDockingEnabled() { return mbStartDockingEnabled; }
+
+public:
+ ImplDockingWindowWrapper( const Window *pWindow );
+ virtual ~ImplDockingWindowWrapper();
+
+ Window* GetWindow() { return mpDockingWindow; }
+ BOOL ImplStartDocking( const Point& rPos );
+
+ // those methods actually call the corresponding handlers
+ void StartDocking( const Point& rPos, Rectangle& rRect );
+ BOOL Docking( const Point& rPos, Rectangle& rRect );
+ void EndDocking( const Rectangle& rRect, BOOL bFloatMode );
+ BOOL PrepareToggleFloatingMode();
+ void ToggleFloatingMode();
+
+ void SetDragArea( const Rectangle& rRect );
+ Rectangle GetDragArea() const;
+
+ void Lock();
+ void Unlock();
+ BOOL IsLocked() const;
+
+ void StartPopupMode( ToolBox* pParentToolBox, ULONG nPopupModeFlags );
+ BOOL IsInPopupMode() const;
+
+ void TitleButtonClick( USHORT nButton );
+ void Pin();
+ void Roll();
+ void PopupModeEnd();
+ void Resizing( Size& rSize );
+ BOOL Close();
+ void Tracking( const TrackingEvent& rTEvt );
+ long Notify( NotifyEvent& rNEvt );
+
+ void ShowTitleButton( USHORT nButton, BOOL bVisible = TRUE );
+ BOOL IsTitleButtonVisible( USHORT nButton ) const;
+
+ void SetPin( BOOL bPin );
+ BOOL IsPined() const;
+
+ void RollUp();
+ void RollDown();
+ BOOL IsRollUp() const;
+
+ void SetRollUpOutputSizePixel( const Size& rSize );
+ Size GetRollUpOutputSizePixel() const;
+
+ void SetMinOutputSizePixel( const Size& rSize );
+ const Size& GetMinOutputSizePixel() const;
+
+ void SetMaxOutputSizePixel( const Size& rSize );
+ const Size& GetMaxOutputSizePixel() const;
+
+ BOOL IsDocking() const { return mbDocking; }
+ BOOL IsDockable() const { return mbDockable; }
+ BOOL IsDockingCanceled() const { return mbDockCanceled; }
+ BOOL IsFloatingPrevented() const { return mbFloatPrevented; }
+
+ void SetFloatingMode( BOOL bFloatMode = FALSE );
+ BOOL IsFloatingMode() const;
+ FloatingWindow* GetFloatingWindow() const { return mpFloatWin; }
+
+ void SetFloatingPos( const Point& rNewPos );
+ Point GetFloatingPos() const;
+
+ void SetFloatStyle( WinBits nWinStyle );
+ WinBits GetFloatStyle() const;
+ void SetTabStop();
+
+ virtual void SetPosSizePixel( long nX, long nY,
+ long nWidth, long nHeight,
+ USHORT nFlags = WINDOW_POSSIZE_ALL );
+ void SetPosSizePixel( const Point& rNewPos,
+ const Size& rNewSize )
+ { mpDockingWindow->SetPosSizePixel( rNewPos, rNewSize ); }
+ Point GetPosPixel() const;
+ Size GetSizePixel() const;
+ void SetOutputSizePixel( const Size& rNewSize );
+ Size GetOutputSizePixel() const;
+};
+
+class VCL_DLLPUBLIC DockingManager
+{
+protected:
+ ::std::vector<ImplDockingWindowWrapper *> mDockingWindows;
+
+public:
+ DockingManager();
+ ~DockingManager();
+
+ void AddWindow( const Window *pWin );
+ void RemoveWindow( const Window *pWin );
+
+ ImplDockingWindowWrapper* GetDockingWindowWrapper( const Window *pWin );
+ BOOL IsDockable( const Window *pWin );
+
+ BOOL IsFloating( const Window *pWin );
+ void SetFloatingMode( const Window *pWin, BOOL bFloating );
+
+ void Lock( const Window *pWin );
+ void Unlock( const Window *pWin );
+ BOOL IsLocked( const Window *pWin );
+
+ void StartPopupMode( ToolBox *pParentToolBox, const Window *pWin );
+ void StartPopupMode( ToolBox *pParentToolBox, const Window *pWin, ULONG nPopupModeFlags );
+
+ BOOL IsInPopupMode( const Window *pWin );
+ void EndPopupMode( const Window *pWin );
+
+ // required because those methods are not virtual in Window (!!!) and must
+ // be availbale from the toolkit
+ void SetPosSizePixel( Window *pWin, long nX, long nY,
+ long nWidth, long nHeight,
+ USHORT nFlags = WINDOW_POSSIZE_ALL );
+ Rectangle GetPosSizePixel( const Window *pWin );
+};
+
+// -----------------
+// - DockingWindow -
+// -----------------
+
+class VCL_DLLPUBLIC DockingWindow : public Window
+{
+ class ImplData;
+private:
+ FloatingWindow* mpFloatWin;
+ Window* mpOldBorderWin;
+ ImplData* mpImplData;
+ Point maFloatPos;
+ Point maDockPos;
+ Point maMouseOff;
+ Point maMouseStart;
+ Size maRollUpOutSize;
+ Size maMinOutSize;
+ long mnTrackX;
+ long mnTrackY;
+ long mnTrackWidth;
+ long mnTrackHeight;
+ sal_Int32 mnDockLeft;
+ sal_Int32 mnDockTop;
+ sal_Int32 mnDockRight;
+ sal_Int32 mnDockBottom;
+ WinBits mnFloatBits;
+ BOOL mbDockCanceled:1,
+ mbDockPrevented:1,
+ mbFloatPrevented:1,
+ mbDockable:1,
+ mbDocking:1,
+ mbDragFull:1,
+ mbLastFloatMode:1,
+ mbStartFloat:1,
+ mbTrackDock:1,
+ mbPined:1,
+ mbRollUp:1,
+ mbDockBtn:1,
+ mbHideBtn:1;
+
+//#if 0 // _SOLAR__PRIVATE
+ SAL_DLLPRIVATE void ImplInitDockingWindowData();
+
+ // Copy assignment is forbidden and not implemented.
+ SAL_DLLPRIVATE DockingWindow (const DockingWindow &);
+ SAL_DLLPRIVATE DockingWindow & operator= (const DockingWindow &);
+
+protected:
+ using Window::ImplInit;
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle );
+ SAL_DLLPRIVATE void ImplInitSettings();
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+
+public:
+ SAL_DLLPRIVATE BOOL ImplStartDocking( const Point& rPos );
+//#endif
+
+protected:
+ DockingWindow( WindowType nType );
+
+public:
+ DockingWindow( Window* pParent, WinBits nStyle = WB_STDDOCKWIN );
+ DockingWindow( Window* pParent, const ResId& rResId );
+ ~DockingWindow();
+
+ virtual void StartDocking();
+ virtual BOOL Docking( const Point& rPos, Rectangle& rRect );
+ virtual void EndDocking( const Rectangle& rRect, BOOL bFloatMode );
+ virtual BOOL PrepareToggleFloatingMode();
+ virtual void ToggleFloatingMode();
+
+ virtual void TitleButtonClick( USHORT nButton );
+ virtual void Pin();
+ virtual void Roll();
+ virtual void PopupModeEnd();
+ virtual void Resizing( Size& rSize );
+ virtual BOOL Close();
+ virtual void Tracking( const TrackingEvent& rTEvt );
+ virtual long Notify( NotifyEvent& rNEvt );
+ virtual void StateChanged( StateChangedType nType );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+
+ void ShowTitleButton( USHORT nButton, BOOL bVisible = TRUE );
+ BOOL IsTitleButtonVisible( USHORT nButton ) const;
+
+ void SetPin( BOOL bPin );
+ BOOL IsPined() const;
+
+ void RollUp();
+ void RollDown();
+ BOOL IsRollUp() const;
+
+ void SetRollUpOutputSizePixel( const Size& rSize );
+ Size GetRollUpOutputSizePixel() const;
+
+ void SetMinOutputSizePixel( const Size& rSize );
+ const Size& GetMinOutputSizePixel() const;
+
+ void SetMaxOutputSizePixel( const Size& rSize );
+ const Size& GetMaxOutputSizePixel() const;
+
+ BOOL IsDocking() const { return mbDocking; }
+ BOOL IsDockable() const { return mbDockable; }
+ BOOL IsDockingCanceled() const { return mbDockCanceled; }
+ BOOL IsDockingPrevented() const { return mbDockPrevented; }
+ BOOL IsFloatingPrevented() const { return mbFloatPrevented; }
+
+ void SetFloatingMode( BOOL bFloatMode = FALSE );
+ BOOL IsFloatingMode() const;
+ FloatingWindow* GetFloatingWindow() const { return mpFloatWin; }
+
+ void SetFloatingPos( const Point& rNewPos );
+ Point GetFloatingPos() const;
+
+ void SetFloatStyle( WinBits nWinStyle );
+ WinBits GetFloatStyle() const;
+ void SetTabStop();
+
+ virtual void SetPosSizePixel( long nX, long nY,
+ long nWidth, long nHeight,
+ USHORT nFlags = WINDOW_POSSIZE_ALL );
+ void SetPosSizePixel( const Point& rNewPos,
+ const Size& rNewSize )
+ { Window::SetPosSizePixel( rNewPos, rNewSize ); }
+ Point GetPosPixel() const;
+ Size GetSizePixel() const;
+ void SetOutputSizePixel( const Size& rNewSize );
+ Size GetOutputSizePixel() const;
+};
+
+inline void DockingWindow::SetPin( BOOL bPin )
+{
+ if ( mpFloatWin )
+ mpFloatWin->SetPin( bPin );
+ mbPined = bPin;
+}
+
+inline BOOL DockingWindow::IsPined() const
+{
+ if ( mpFloatWin )
+ return mpFloatWin->IsPined();
+ return mbPined;
+}
+
+inline void DockingWindow::RollUp()
+{
+ if ( mpFloatWin )
+ mpFloatWin->RollUp();
+ mbRollUp = TRUE;
+}
+
+inline void DockingWindow::RollDown()
+{
+ if ( mpFloatWin )
+ mpFloatWin->RollDown();
+ mbRollUp = FALSE;
+}
+
+inline BOOL DockingWindow::IsRollUp() const
+{
+ if ( mpFloatWin )
+ return mpFloatWin->IsRollUp();
+ return mbRollUp;
+}
+
+inline void DockingWindow::SetRollUpOutputSizePixel( const Size& rSize )
+{
+ if ( mpFloatWin )
+ mpFloatWin->SetRollUpOutputSizePixel( rSize );
+ maRollUpOutSize = rSize;
+}
+
+inline Size DockingWindow::GetRollUpOutputSizePixel() const
+{
+ if ( mpFloatWin )
+ return mpFloatWin->GetRollUpOutputSizePixel();
+ return maRollUpOutSize;
+}
+
+inline void DockingWindow::SetMinOutputSizePixel( const Size& rSize )
+{
+ if ( mpFloatWin )
+ mpFloatWin->SetMinOutputSizePixel( rSize );
+ maMinOutSize = rSize;
+}
+
+inline const Size& DockingWindow::GetMinOutputSizePixel() const
+{
+ if ( mpFloatWin )
+ return mpFloatWin->GetMinOutputSizePixel();
+ return maMinOutSize;
+}
+
+inline void DockingWindow::SetFloatingPos( const Point& rNewPos )
+{
+ if ( mpFloatWin )
+ mpFloatWin->SetPosPixel( rNewPos );
+ else
+ maFloatPos = rNewPos;
+}
+
+
+#endif // _SV_DOCKWIN_HXX
diff --git a/vcl/inc/vcl/edit.hxx b/vcl/inc/vcl/edit.hxx
new file mode 100644
index 000000000000..a40de9503367
--- /dev/null
+++ b/vcl/inc/vcl/edit.hxx
@@ -0,0 +1,260 @@
+/*************************************************************************
+ *
+ * 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_EDIT_HXX
+#define _SV_EDIT_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/timer.hxx>
+#include <vcl/ctrl.hxx>
+#include <vcl/menu.hxx>
+#include <vcl/dndhelp.hxx>
+#include <com/sun/star/uno/Reference.h>
+
+namespace com {
+namespace sun {
+namespace star {
+namespace i18n {
+ class XBreakIterator;
+ class XExtendedInputSequenceChecker;
+}}}}
+
+class ImplSubEdit;
+struct DDInfo;
+struct Impl_IMEInfos;
+
+// --------------
+// - Edit-Types -
+// --------------
+
+#define EDIT_NOLIMIT STRING_LEN
+#define EDIT_UPDATEDATA_TIMEOUT 350
+
+typedef XubString (*FncGetSpecialChars)( Window* pWin, const Font& rFont );
+
+// --------
+// - Edit -
+// --------
+
+enum AutocompleteAction{ AUTOCOMPLETE_KEYINPUT, AUTOCOMPLETE_TABFORWARD, AUTOCOMPLETE_TABBACKWARD };
+
+class VCL_DLLPUBLIC Edit : public Control, public vcl::unohelper::DragAndDropClient
+{
+private:
+ Edit* mpSubEdit;
+ Timer* mpUpdateDataTimer;
+ DDInfo* mpDDInfo;
+ Impl_IMEInfos* mpIMEInfos;
+ XubString maText;
+ XubString maSaveValue;
+ XubString maUndoText;
+ XubString maRedoText;
+ long mnXOffset;
+ Selection maSelection;
+ USHORT mnAlign;
+ xub_StrLen mnMaxTextLen;
+ AutocompleteAction meAutocompleteAction;
+ xub_Unicode mcEchoChar;
+ BOOL mbModified:1,
+ mbInternModified:1,
+ mbReadOnly:1,
+ mbInsertMode:1,
+ mbClickedInSelection:1,
+ mbIsSubEdit:1,
+ mbInMBDown:1,
+ mbActivePopup:1;
+ Link maModifyHdl;
+ Link maUpdateDataHdl;
+ Link maAutocompleteHdl;
+
+ DECL_DLLPRIVATE_LINK( ImplUpdateDataHdl, Timer* );
+
+ SAL_DLLPRIVATE bool ImplTruncateToMaxLen( rtl::OUString&, sal_uInt32 nSelectionLen ) const;
+ SAL_DLLPRIVATE void ImplInitEditData();
+ SAL_DLLPRIVATE void ImplModified();
+ SAL_DLLPRIVATE XubString ImplGetText() const;
+ SAL_DLLPRIVATE void ImplRepaint( xub_StrLen nStart = 0, xub_StrLen nEnd = STRING_LEN, bool bLayout = false );
+ SAL_DLLPRIVATE void ImplInvalidateOrRepaint( xub_StrLen nStart = 0, xub_StrLen nEnd = STRING_LEN );
+ SAL_DLLPRIVATE void ImplDelete( const Selection& rSelection, BYTE nDirection, BYTE nMode );
+ SAL_DLLPRIVATE void ImplSetText( const XubString& rStr, const Selection* pNewSelection = 0 );
+ SAL_DLLPRIVATE void ImplInsertText( const XubString& rStr, const Selection* pNewSelection = 0, sal_Bool bIsUserInput = sal_False );
+ SAL_DLLPRIVATE String ImplGetValidString( const String& rString ) const;
+ SAL_DLLPRIVATE void ImplClearBackground( long nXStart, long nXEnd );
+ SAL_DLLPRIVATE void ImplShowCursor( BOOL bOnlyIfVisible = TRUE );
+ SAL_DLLPRIVATE void ImplAlign();
+ SAL_DLLPRIVATE void ImplAlignAndPaint();
+ SAL_DLLPRIVATE xub_StrLen ImplGetCharPos( const Point& rWindowPos ) const;
+ SAL_DLLPRIVATE void ImplSetCursorPos( xub_StrLen nChar, BOOL bSelect );
+ SAL_DLLPRIVATE void ImplShowDDCursor();
+ SAL_DLLPRIVATE void ImplHideDDCursor();
+ SAL_DLLPRIVATE BOOL ImplHandleKeyEvent( const KeyEvent& rKEvt );
+ SAL_DLLPRIVATE void ImplCopyToSelectionClipboard();
+ SAL_DLLPRIVATE void ImplCopy( ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboard >& rxClipboard );
+ SAL_DLLPRIVATE void ImplPaste( ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboard >& rxClipboard );
+ SAL_DLLPRIVATE long ImplGetExtraOffset() const;
+ SAL_DLLPRIVATE long ImplGetTextYPosition() const;
+ SAL_DLLPRIVATE ::com::sun::star::uno::Reference < ::com::sun::star::i18n::XExtendedInputSequenceChecker > ImplGetInputSequenceChecker() const;
+ SAL_DLLPRIVATE ::com::sun::star::uno::Reference < ::com::sun::star::i18n::XBreakIterator > ImplGetBreakIterator() const;
+
+protected:
+ using Control::ImplInitSettings;
+ using Window::ImplInit;
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle );
+ SAL_DLLPRIVATE WinBits ImplInitStyle( WinBits nStyle );
+ SAL_DLLPRIVATE void ImplInitSettings( BOOL bFont, BOOL bForeground, BOOL bBackground );
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+ SAL_DLLPRIVATE void ImplSetSelection( const Selection& rSelection, BOOL bPaint = TRUE );
+ SAL_DLLPRIVATE int ImplGetNativeControlType();
+ static SAL_DLLPRIVATE void ImplInvalidateOutermostBorder( Window* pWin );
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSourceListener > mxDnDListener;
+
+ // DragAndDropClient
+ using vcl::unohelper::DragAndDropClient::dragEnter;
+ using vcl::unohelper::DragAndDropClient::dragExit;
+ using vcl::unohelper::DragAndDropClient::dragOver;
+ virtual void dragGestureRecognized( const ::com::sun::star::datatransfer::dnd::DragGestureEvent& dge ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void dragDropEnd( const ::com::sun::star::datatransfer::dnd::DragSourceDropEvent& dsde ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void drop( const ::com::sun::star::datatransfer::dnd::DropTargetDropEvent& dtde ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void dragEnter( const ::com::sun::star::datatransfer::dnd::DropTargetDragEnterEvent& dtdee ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void dragExit( const ::com::sun::star::datatransfer::dnd::DropTargetEvent& dte ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void dragOver( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& dtde ) throw (::com::sun::star::uno::RuntimeException);
+
+ protected:
+ virtual void FillLayoutData() const;
+
+ Edit( WindowType nType );
+
+public:
+ // public because needed in button.cxx
+ SAL_DLLPRIVATE bool ImplUseNativeBorder( WinBits nStyle );
+
+ Edit( Window* pParent, WinBits nStyle = WB_BORDER );
+ Edit( Window* pParent, const ResId& rResId );
+ Edit( Window* pParent, const ResId& rResId, bool bDisableAccessibleLabeledByRelation );
+ virtual ~Edit();
+
+ virtual void MouseButtonDown( const MouseEvent& rMEvt );
+ virtual void MouseButtonUp( const MouseEvent& rMEvt );
+ virtual void KeyInput( const KeyEvent& rKEvt );
+ virtual void Paint( const Rectangle& rRect );
+ virtual void Resize();
+ virtual void Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG nFlags );
+ virtual void GetFocus();
+ virtual void LoseFocus();
+ virtual void Tracking( const TrackingEvent& rTEvt );
+ virtual void Command( const CommandEvent& rCEvt );
+ virtual void StateChanged( StateChangedType nType );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+ virtual Window* GetPreferredKeyInputWindow();
+
+ virtual void Modify();
+ virtual void UpdateData();
+
+ static BOOL IsCharInput( const KeyEvent& rKEvt );
+
+ virtual void SetModifyFlag();
+ virtual void ClearModifyFlag();
+ virtual BOOL IsModified() const { return mpSubEdit ? mpSubEdit->mbModified : mbModified; }
+
+ virtual void EnableUpdateData( ULONG nTimeout = EDIT_UPDATEDATA_TIMEOUT );
+ virtual void DisableUpdateData() { delete mpUpdateDataTimer; mpUpdateDataTimer = NULL; }
+ virtual ULONG IsUpdateDataEnabled() const;
+
+ void SetEchoChar( xub_Unicode c );
+ xub_Unicode GetEchoChar() const { return mcEchoChar; }
+
+ virtual void SetReadOnly( BOOL bReadOnly = TRUE );
+ virtual BOOL IsReadOnly() const { return mbReadOnly; }
+
+ void SetInsertMode( BOOL bInsert );
+ BOOL IsInsertMode() const;
+
+ virtual void SetMaxTextLen( xub_StrLen nMaxLen = EDIT_NOLIMIT );
+ virtual xub_StrLen GetMaxTextLen() const { return mnMaxTextLen; }
+
+ virtual void SetSelection( const Selection& rSelection );
+ virtual const Selection& GetSelection() const;
+
+ virtual void ReplaceSelected( const XubString& rStr );
+ virtual void DeleteSelected();
+ virtual XubString GetSelected() const;
+
+ virtual void Cut();
+ virtual void Copy();
+ virtual void Paste();
+ void Undo();
+
+ virtual void SetText( const XubString& rStr );
+ virtual void SetText( const XubString& rStr, const Selection& rNewSelection );
+ virtual XubString GetText() const;
+
+ void SaveValue() { maSaveValue = GetText(); }
+ const XubString& GetSavedValue() const { return maSaveValue; }
+
+ virtual void SetModifyHdl( const Link& rLink ) { maModifyHdl = rLink; }
+ virtual const Link& GetModifyHdl() const { return maModifyHdl; }
+ virtual void SetUpdateDataHdl( const Link& rLink ) { maUpdateDataHdl = rLink; }
+ virtual const Link& GetUpdateDataHdl() const { return maUpdateDataHdl; }
+
+ void SetSubEdit( Edit* pEdit );
+ Edit* GetSubEdit() const { return mpSubEdit; }
+
+ void SetAutocompleteHdl( const Link& rHdl );
+ const Link& GetAutocompleteHdl() const { return maAutocompleteHdl; }
+ AutocompleteAction GetAutocompleteAction() const { return meAutocompleteAction; }
+
+ virtual Size CalcMinimumSize() const;
+ virtual Size GetOptimalSize(WindowSizeType eType) const;
+ virtual Size CalcSize( USHORT nChars ) const;
+ virtual xub_StrLen GetMaxVisChars() const;
+
+ xub_StrLen GetCharPos( const Point& rWindowPos ) const;
+
+ // shows a warning box saying "text too long, truncated"
+ static void ShowTruncationWarning( Window* pParent );
+
+ static void SetGetSpecialCharsFunction( FncGetSpecialChars fn );
+ static FncGetSpecialChars GetGetSpecialCharsFunction();
+
+ static PopupMenu* CreatePopupMenu();
+ static void DeletePopupMenu( PopupMenu* pMenu );
+
+ virtual XubString GetSurroundingText() const;
+ virtual Selection GetSurroundingTextSelection() const;
+};
+
+inline ULONG Edit::IsUpdateDataEnabled() const
+{
+ if ( mpUpdateDataTimer )
+ return mpUpdateDataTimer->GetTimeout();
+ else
+ return FALSE;
+}
+
+#endif // _SV_EDIT_HXX
diff --git a/vcl/inc/vcl/event.hxx b/vcl/inc/vcl/event.hxx
new file mode 100644
index 000000000000..9458a4298c33
--- /dev/null
+++ b/vcl/inc/vcl/event.hxx
@@ -0,0 +1,479 @@
+/*************************************************************************
+ *
+ * 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_EVENT_HXX
+#define _SV_EVENT_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <tools/gen.hxx>
+#include <vcl/keycod.hxx>
+#include <vcl/cmdevt.hxx>
+
+class AllSettings;
+class OutputDevice;
+class Window;
+struct IDataObject;
+
+namespace com { namespace sun { namespace star { namespace awt {
+ struct KeyEvent;
+ struct MouseEvent;
+} } } }
+
+enum TextDirectionality {
+ TextDirectionality_LeftToRight_TopToBottom,
+ TextDirectionality_RightToLeft_TopToBottom,
+ TextDirectionality_TopToBottom_RightToLeft
+};
+
+// ------------
+// - KeyEvent -
+// ------------
+class VCL_DLLPUBLIC KeyEvent
+{
+private:
+ KeyCode maKeyCode;
+ USHORT mnRepeat;
+ xub_Unicode mnCharCode;
+
+public:
+ KeyEvent();
+ KeyEvent( xub_Unicode nChar, const KeyCode& rKeyCode,
+ USHORT nRepeat = 0 );
+
+ /** inits this vcl KeyEvent with all settings from the given awt event **/
+ KeyEvent( const ::com::sun::star::awt::KeyEvent& rEvent );
+
+ /** fills out the given awt KeyEvent with all settings from this vcl event **/
+ void InitKeyEvent( ::com::sun::star::awt::KeyEvent& rEvent ) const;
+
+ xub_Unicode GetCharCode() const { return mnCharCode; }
+ const KeyCode& GetKeyCode() const { return maKeyCode; }
+ USHORT GetRepeat() const { return mnRepeat; }
+
+ KeyEvent LogicalTextDirectionality (TextDirectionality eMode) const;
+ KeyEvent (const KeyEvent& rKeyEvent);
+
+};
+
+inline KeyEvent::KeyEvent()
+{
+ mnCharCode = 0;
+ mnRepeat = 0;
+}
+
+inline KeyEvent::KeyEvent( xub_Unicode nChar, const KeyCode& rKeyCode,
+ USHORT nRepeat ) :
+ maKeyCode( rKeyCode )
+
+{
+ mnCharCode = nChar;
+ mnRepeat = nRepeat;
+}
+
+// --------------------
+// - MouseEvent-Types -
+// --------------------
+
+// Maus-Move-Modi
+#define MOUSE_SIMPLEMOVE ((USHORT)0x0001)
+#define MOUSE_DRAGMOVE ((USHORT)0x0002)
+#define MOUSE_DRAGCOPY ((USHORT)0x0004)
+#define MOUSE_ENTERWINDOW ((USHORT)0x0010)
+#define MOUSE_LEAVEWINDOW ((USHORT)0x0020)
+#define MOUSE_SYNTHETIC ((USHORT)0x0040)
+#define MOUSE_MODIFIERCHANGED ((USHORT)0x0080)
+
+// Maus-Button-Down/Up-Modi
+#define MOUSE_SIMPLECLICK ((USHORT)0x0001)
+#define MOUSE_SELECT ((USHORT)0x0002)
+#define MOUSE_MULTISELECT ((USHORT)0x0004)
+#define MOUSE_RANGESELECT ((USHORT)0x0008)
+
+// Maus-Buttons
+#define MOUSE_LEFT ((USHORT)0x0001)
+#define MOUSE_MIDDLE ((USHORT)0x0002)
+#define MOUSE_RIGHT ((USHORT)0x0004)
+
+// --------------
+// - MouseEvent -
+// --------------
+
+class VCL_DLLPUBLIC MouseEvent
+{
+private:
+ Point maPos;
+ USHORT mnMode;
+ USHORT mnClicks;
+ USHORT mnCode;
+
+public:
+ MouseEvent();
+ MouseEvent( const Point& rPos, USHORT nClicks = 1,
+ USHORT nMode = 0, USHORT nButtons = 0,
+ USHORT nModifier = 0 );
+
+ const Point& GetPosPixel() const { return maPos; }
+ USHORT GetMode() const { return mnMode; }
+ /** inits this vcl KeyEvent with all settings from the given awt event **/
+ MouseEvent( const ::com::sun::star::awt::MouseEvent& rEvent );
+
+ /** fills out the given awt KeyEvent with all settings from this vcl event **/
+ void InitMouseEvent( ::com::sun::star::awt::MouseEvent& rEvent ) const;
+
+ USHORT GetClicks() const { return mnClicks; }
+
+ BOOL IsEnterWindow() const
+ { return ((mnMode & MOUSE_ENTERWINDOW) != 0); }
+ BOOL IsLeaveWindow() const
+ { return ((mnMode & MOUSE_LEAVEWINDOW) != 0); }
+ BOOL IsSynthetic() const
+ { return ((mnMode & MOUSE_SYNTHETIC) != 0); }
+ BOOL IsModifierChanged() const
+ { return ((mnMode & MOUSE_MODIFIERCHANGED) != 0); }
+
+ USHORT GetButtons() const
+ { return (mnCode & (MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT)); }
+ BOOL IsLeft() const
+ { return ((mnCode & MOUSE_LEFT) != 0); }
+ BOOL IsMiddle() const
+ { return ((mnCode & MOUSE_MIDDLE) != 0); }
+ BOOL IsRight() const
+ { return ((mnCode & MOUSE_RIGHT) != 0); }
+
+ USHORT GetModifier() const
+ { return (mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2)); }
+ BOOL IsShift() const
+ { return ((mnCode & KEY_SHIFT) != 0); }
+ BOOL IsMod1() const
+ { return ((mnCode & KEY_MOD1) != 0); }
+ BOOL IsMod2() const
+ { return ((mnCode & KEY_MOD2) != 0); }
+ BOOL IsMod3() const
+ { return ((mnCode & KEY_MOD3) != 0); }
+};
+
+inline MouseEvent::MouseEvent()
+{
+ mnMode = 0;
+ mnClicks = 0;
+ mnCode = 0;
+}
+
+inline MouseEvent::MouseEvent( const Point& rPos, USHORT nClicks,
+ USHORT nMode,
+ USHORT nButtons, USHORT nModifier ) :
+ maPos( rPos )
+{
+ mnClicks = nClicks;
+ mnMode = nMode;
+ mnCode = nButtons | nModifier;
+}
+
+// -------------
+// - HelpEvent -
+// -------------
+
+#define HELPMODE_CONTEXT ((USHORT)0x0001)
+#define HELPMODE_EXTENDED ((USHORT)0x0002)
+#define HELPMODE_BALLOON ((USHORT)0x0004)
+#define HELPMODE_QUICK ((USHORT)0x0008)
+
+class VCL_DLLPUBLIC HelpEvent
+{
+private:
+ Point maPos;
+ USHORT mnMode;
+ BOOL mbKeyboardActivated;
+
+public:
+ HelpEvent();
+ HelpEvent( USHORT nHelpMode );
+ HelpEvent( const Point& rMousePos, USHORT nHelpMode );
+
+ const Point& GetMousePosPixel() const;
+ USHORT GetMode() const { return mnMode; }
+ BOOL KeyboardActivated() const { return mbKeyboardActivated; }
+ void SetKeyboardActivated( BOOL bKeyboard ) { mbKeyboardActivated = bKeyboard; }
+};
+
+inline HelpEvent::HelpEvent()
+{
+ mnMode = HELPMODE_CONTEXT;
+ mbKeyboardActivated = TRUE;
+}
+
+inline HelpEvent::HelpEvent( const Point& rMousePos, USHORT nHelpMode ) :
+ maPos( rMousePos )
+{
+ mnMode = nHelpMode;
+ mbKeyboardActivated = FALSE;
+}
+
+inline HelpEvent::HelpEvent( USHORT nHelpMode )
+{
+ mnMode = nHelpMode;
+ mbKeyboardActivated = TRUE;
+}
+
+// -----------------
+// - UserDrawEvent -
+// -----------------
+
+class VCL_DLLPUBLIC UserDrawEvent
+{
+private:
+ OutputDevice* mpOutDev;
+ Rectangle maOutRect;
+ USHORT mnItemId;
+ USHORT mnStyle;
+
+public:
+ UserDrawEvent();
+ UserDrawEvent( OutputDevice* pOut,
+ const Rectangle& rOutRect,
+ USHORT nId, USHORT nStyle = 0 );
+
+ OutputDevice* GetDevice() const { return mpOutDev; }
+ const Rectangle& GetRect() const { return maOutRect; }
+ USHORT GetItemId() const { return mnItemId; }
+ USHORT GetStyle() const { return mnStyle; }
+};
+
+inline UserDrawEvent::UserDrawEvent()
+{
+ mpOutDev = NULL;
+ mnItemId = 0;
+ mnStyle = 0;
+}
+
+inline UserDrawEvent::UserDrawEvent( OutputDevice* pOut,
+ const Rectangle& rOutRect,
+ USHORT nId, USHORT nStyle ) :
+ maOutRect( rOutRect )
+{
+ mpOutDev = pOut;
+ mnItemId = nId;
+ mnStyle = nStyle;
+}
+
+// ------------------
+// - Tracking-Types -
+// ------------------
+
+#define ENDTRACK_CANCEL ((USHORT)0x0001)
+#define ENDTRACK_KEY ((USHORT)0x0002)
+#define ENDTRACK_FOCUS ((USHORT)0x0004)
+#define ENDTRACK_END ((USHORT)0x1000)
+#define ENDTRACK_DONTCALLHDL ((USHORT)0x8000)
+
+#define TRACKING_REPEAT ((USHORT)0x0100)
+
+// -----------------
+// - TrackingEvent -
+// -----------------
+
+class VCL_DLLPUBLIC TrackingEvent
+{
+private:
+ MouseEvent maMEvt;
+ USHORT mnFlags;
+
+public:
+ TrackingEvent();
+ TrackingEvent( const MouseEvent& rMEvt,
+ USHORT nTrackFlags = 0 );
+
+ const MouseEvent& GetMouseEvent() const { return maMEvt; }
+
+ BOOL IsTrackingRepeat() const
+ { return ((mnFlags & TRACKING_REPEAT) != 0); }
+
+ BOOL IsTrackingEnded() const
+ { return ((mnFlags & ENDTRACK_END) != 0); }
+ BOOL IsTrackingCanceled() const
+ { return ((mnFlags & ENDTRACK_CANCEL) != 0); }
+ USHORT GetTrackingFlags() const { return mnFlags; }
+};
+
+inline TrackingEvent::TrackingEvent()
+{
+ mnFlags = 0;
+}
+
+inline TrackingEvent::TrackingEvent( const MouseEvent& rMEvt,
+ USHORT nTrackFlags ) :
+ maMEvt( rMEvt )
+{
+ mnFlags = nTrackFlags;
+}
+
+// ---------------
+// - NotifyEvent -
+// ---------------
+
+#define EVENT_MOUSEBUTTONDOWN 1
+#define EVENT_MOUSEBUTTONUP 2
+#define EVENT_MOUSEMOVE 3
+#define EVENT_KEYINPUT 4
+#define EVENT_KEYUP 5
+#define EVENT_GETFOCUS 6
+#define EVENT_LOSEFOCUS 7
+#define EVENT_COMMAND 8
+#define EVENT_DESTROY 9
+#define EVENT_INPUTENABLE 10
+#define EVENT_INPUTDISABLE 11
+#define EVENT_EXECUTEDIALOG 100
+#define EVENT_ENDEXECUTEDIALOG 101
+#define EVENT_USER 10000
+
+class VCL_DLLPUBLIC NotifyEvent
+{
+private:
+ Window* mpWindow;
+ void* mpData;
+ USHORT mnType;
+ long mnRetValue;
+
+public:
+ NotifyEvent();
+ NotifyEvent( USHORT nType,
+ Window* pWindow,
+ const void* pEvent = NULL,
+ long nRet = 0 );
+
+ USHORT GetType() const { return mnType; }
+ Window* GetWindow() const { return mpWindow; }
+ void* GetData() const { return mpData; }
+
+ void SetReturnValue( long nRet ) { mnRetValue = nRet; }
+ long GetReturnValue() const { return mnRetValue; }
+
+ const KeyEvent* GetKeyEvent() const;
+ const MouseEvent* GetMouseEvent() const;
+ const CommandEvent* GetCommandEvent() const;
+};
+
+inline NotifyEvent::NotifyEvent()
+{
+ mpWindow = NULL;
+ mpData = NULL;
+ mnType = 0;
+ mnRetValue = 0;
+}
+
+inline NotifyEvent::NotifyEvent( USHORT nType, Window* pWindow,
+ const void* pEvent, long nRet )
+{
+ mpWindow = pWindow;
+ mpData = (void*)pEvent;
+ mnType = nType;
+ mnRetValue = nRet;
+}
+
+inline const KeyEvent* NotifyEvent::GetKeyEvent() const
+{
+ if ( (mnType == EVENT_KEYINPUT) || (mnType == EVENT_KEYUP) )
+ return (const KeyEvent*)mpData;
+ else
+ return NULL;
+}
+
+inline const MouseEvent* NotifyEvent::GetMouseEvent() const
+{
+ if ( (mnType >= EVENT_MOUSEBUTTONDOWN) && (mnType <= EVENT_MOUSEMOVE) )
+ return (const MouseEvent*)mpData;
+ else
+ return NULL;
+}
+
+inline const CommandEvent* NotifyEvent::GetCommandEvent() const
+{
+ if ( mnType == EVENT_COMMAND )
+ return (const CommandEvent*)mpData;
+ else
+ return NULL;
+}
+
+// --------------------
+// - DataChangedEvent -
+// --------------------
+
+#define DATACHANGED_SETTINGS ((USHORT)1)
+#define DATACHANGED_DISPLAY ((USHORT)2)
+#define DATACHANGED_DATETIME ((USHORT)3)
+#define DATACHANGED_FONTS ((USHORT)4)
+#define DATACHANGED_PRINTER ((USHORT)5)
+#define DATACHANGED_FONTSUBSTITUTION ((USHORT)6)
+#define DATACHANGED_USER ((USHORT)10000)
+
+class VCL_DLLPUBLIC DataChangedEvent
+{
+private:
+ void* mpData;
+ ULONG mnFlags;
+ USHORT mnType;
+
+public:
+ DataChangedEvent();
+ DataChangedEvent( USHORT nType,
+ const void* pData = NULL,
+ ULONG nFlags = 0 );
+
+ USHORT GetType() const { return mnType; }
+ void* GetData() const { return mpData; }
+ ULONG GetFlags() const { return mnFlags; }
+
+ const AllSettings* GetOldSettings() const;
+};
+
+inline DataChangedEvent::DataChangedEvent()
+{
+ mpData = NULL;
+ mnFlags = 0;
+ mnType = 0;
+}
+
+inline DataChangedEvent::DataChangedEvent( USHORT nType,
+ const void* pData,
+ ULONG nChangeFlags )
+{
+ mpData = (void*)pData;
+ mnFlags = nChangeFlags;
+ mnType = nType;
+}
+
+inline const AllSettings* DataChangedEvent::GetOldSettings() const
+{
+ if ( mnType == DATACHANGED_SETTINGS )
+ return (const AllSettings*)mpData;
+ else
+ return NULL;
+}
+
+#endif // _SV_EVENT_HXX
+
diff --git a/vcl/inc/vcl/evntpost.hxx b/vcl/inc/vcl/evntpost.hxx
new file mode 100644
index 000000000000..9e9badb7157b
--- /dev/null
+++ b/vcl/inc/vcl/evntpost.hxx
@@ -0,0 +1,59 @@
+/*************************************************************************
+ *
+ * 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_EVNTPOST_HXX
+#define _VCL_EVNTPOST_HXX
+
+#include <tools/link.hxx>
+#include <vcl/dllapi.h>
+
+//===================================================================
+
+namespace vcl
+{
+ struct UserEvent
+ {
+ ULONG m_nWhich;
+ void* m_pData;
+ };
+
+ class VCL_DLLPUBLIC EventPoster
+ {
+ ULONG m_nId;
+ Link m_aLink;
+
+//#if 0 // _SOLAR__PRIVATE
+ DECL_DLLPRIVATE_LINK( DoEvent_Impl, UserEvent* );
+//#endif
+
+ public:
+ EventPoster( const Link& rLink );
+ ~EventPoster();
+ void Post( UserEvent* pEvent );
+ };
+}
+
+#endif
diff --git a/vcl/inc/vcl/extoutdevdata.hxx b/vcl/inc/vcl/extoutdevdata.hxx
new file mode 100644
index 000000000000..cfe7b74533d8
--- /dev/null
+++ b/vcl/inc/vcl/extoutdevdata.hxx
@@ -0,0 +1,47 @@
+/*************************************************************************
+ *
+ * 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_EXTOUTDEVDATA_HXX
+#define _VCL_EXTOUTDEVDATA_HXX
+
+#include <tools/rtti.hxx>
+#include <vcl/dllapi.h>
+
+namespace vcl
+{
+
+class VCL_DLLPUBLIC ExtOutDevData
+{
+public:
+
+ TYPEINFO();
+ virtual ~ExtOutDevData();
+};
+
+}
+
+#endif // _VCL_PDFWRITER_HXX
diff --git a/vcl/inc/vcl/field.hxx b/vcl/inc/vcl/field.hxx
new file mode 100644
index 000000000000..e1f39cc78966
--- /dev/null
+++ b/vcl/inc/vcl/field.hxx
@@ -0,0 +1,884 @@
+/*************************************************************************
+ *
+ * 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_FIELD_HXX
+#define _SV_FIELD_HXX
+
+#include <vcl/dllapi.h>
+#include <tools/link.hxx>
+#include <tools/date.hxx>
+#include <tools/time.hxx>
+#include <vcl/spinfld.hxx>
+#include <vcl/combobox.hxx>
+#include <vcl/fldunit.hxx>
+
+namespace com { namespace sun { namespace star { namespace lang { struct Locale; } } } }
+
+class CalendarWrapper;
+class LocaleDataWrapper;
+
+// -----------------
+// - FormatterBase -
+// -----------------
+
+class VCL_DLLPUBLIC FormatterBase
+{
+private:
+ Edit* mpField;
+ LocaleDataWrapper* mpLocaleDataWrapper;
+ Link maErrorLink;
+ BOOL mbReformat;
+ BOOL mbStrictFormat;
+ BOOL mbEmptyFieldValue;
+ BOOL mbEmptyFieldValueEnabled;
+ BOOL mbDefaultLocale;
+
+protected:
+ SAL_DLLPRIVATE void ImplSetText( const XubString& rText, Selection* pNewSel = NULL );
+ SAL_DLLPRIVATE BOOL ImplGetEmptyFieldValue() const { return mbEmptyFieldValue; }
+
+ void SetFieldText( const XubString& rText, BOOL bKeepSelection );
+ void SetEmptyFieldValueData( BOOL bValue ) { mbEmptyFieldValue = bValue; }
+
+ SAL_DLLPRIVATE LocaleDataWrapper& ImplGetLocaleDataWrapper() const;
+ BOOL IsDefaultLocale() const { return mbDefaultLocale; }
+
+public:
+ FormatterBase( Edit* pField = NULL );
+ virtual ~FormatterBase();
+
+ const LocaleDataWrapper& GetLocaleDataWrapper() const;
+
+ void SetField( Edit* pField ) { mpField = pField; }
+ Edit* GetField() const { return mpField; }
+
+ BOOL MustBeReformatted() const { return mbReformat; }
+ void MarkToBeReformatted( BOOL b ) { mbReformat = b; }
+
+ void SetStrictFormat( BOOL bStrict );
+ BOOL IsStrictFormat() const { return mbStrictFormat; }
+
+ virtual void Reformat();
+ virtual void ReformatAll();
+
+ virtual void SetLocale( const ::com::sun::star::lang::Locale& rLocale );
+ const ::com::sun::star::lang::Locale& GetLocale() const;
+
+ const AllSettings& GetFieldSettings() const;
+
+ void SetErrorHdl( const Link& rLink ) { maErrorLink = rLink; }
+ const Link& GetErrorHdl() const { return maErrorLink; }
+
+ void SetEmptyFieldValue();
+ BOOL IsEmptyFieldValue() const;
+
+ void EnableEmptyFieldValue( BOOL bEnable ) { mbEmptyFieldValueEnabled = bEnable; }
+ BOOL IsEmptyFieldValueEnabled() const { return mbEmptyFieldValueEnabled; }
+};
+
+
+// --------------------
+// - PatternFormatter -
+// --------------------
+
+#define PATTERN_FORMAT_EMPTYLITERALS ((USHORT)0x0001)
+
+class VCL_DLLPUBLIC PatternFormatter : public FormatterBase
+{
+private:
+ ByteString maEditMask;
+ XubString maFieldString;
+ XubString maLiteralMask;
+ USHORT mnFormatFlags;
+ BOOL mbSameMask;
+ BOOL mbInPattKeyInput;
+
+protected:
+ PatternFormatter();
+
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+ SAL_DLLPRIVATE void ImplSetMask( const ByteString& rEditMask, const XubString& rLiteralMask );
+ SAL_DLLPRIVATE BOOL ImplIsSameMask() const { return mbSameMask; }
+ SAL_DLLPRIVATE BOOL& ImplGetInPattKeyInput() { return mbInPattKeyInput; }
+
+public:
+ ~PatternFormatter();
+
+ virtual void Reformat();
+
+ void SetMask( const ByteString& rEditMask,
+ const XubString& rLiteralMask );
+ const ByteString& GetEditMask() const { return maEditMask; }
+ const XubString& GetLiteralMask() const { return maLiteralMask; }
+
+ void SetFormatFlags( USHORT nFlags ) { mnFormatFlags = nFlags; }
+ USHORT GetFormatFlags() const { return mnFormatFlags; }
+
+ void SetString( const XubString& rStr );
+ XubString GetString() const;
+ BOOL IsStringModified() const { return !(GetString().Equals( maFieldString )); }
+
+ void SelectFixedFont();
+};
+
+// --------------------
+// - NumericFormatter -
+// --------------------
+
+class VCL_DLLPUBLIC NumericFormatter : public FormatterBase
+{
+private:
+ SAL_DLLPRIVATE void ImplInit();
+
+protected:
+ sal_Int64 mnFieldValue;
+ sal_Int64 mnLastValue;
+ sal_Int64 mnMin;
+ sal_Int64 mnMax;
+ sal_Int64 mnCorrectedValue;
+ USHORT mnType;
+ USHORT mnDecimalDigits;
+ BOOL mbThousandSep;
+ BOOL mbShowTrailingZeros;
+
+ // the members below are used in all derivatives of NumericFormatter
+ // not in NumericFormatter itself.
+ sal_Int64 mnSpinSize;
+ sal_Int64 mnFirst;
+ sal_Int64 mnLast;
+
+protected:
+ NumericFormatter();
+
+ virtual XubString CreateFieldText( sal_Int64 nValue ) const;
+
+ void FieldUp();
+ void FieldDown();
+ void FieldFirst();
+ void FieldLast();
+
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+ SAL_DLLPRIVATE BOOL ImplNumericReformat( const XubString& rStr, double& rValue, XubString& rOutStr );
+ SAL_DLLPRIVATE void ImplNewFieldValue( sal_Int64 nNewValue );
+ SAL_DLLPRIVATE void ImplSetUserValue( sal_Int64 nNewValue, Selection* pNewSelection = NULL );
+
+public:
+ ~NumericFormatter();
+
+ virtual void Reformat();
+
+ void SetMin( sal_Int64 nNewMin );
+ sal_Int64 GetMin() const { return mnMin; }
+ void SetMax( sal_Int64 nNewMax );
+ sal_Int64 GetMax() const { return mnMax; }
+
+ void SetFirst( sal_Int64 nNewFirst ) { mnFirst = nNewFirst; }
+ sal_Int64 GetFirst() const { return mnFirst; }
+ void SetLast( sal_Int64 nNewLast ) { mnLast = nNewLast; }
+ sal_Int64 GetLast() const { return mnLast; }
+ void SetSpinSize( sal_Int64 nNewSize ) { mnSpinSize = nNewSize; }
+ sal_Int64 GetSpinSize() const { return mnSpinSize; }
+
+ void SetDecimalDigits( USHORT nDigits );
+ USHORT GetDecimalDigits() const;
+
+ void SetUseThousandSep( BOOL b );
+ BOOL IsUseThousandSep() const { return mbThousandSep; }
+
+ void SetShowTrailingZeros( BOOL bShowTrailingZeros );
+ BOOL IsShowTrailingZeros() const { return mbShowTrailingZeros; }
+
+
+ void SetUserValue( sal_Int64 nNewValue );
+ virtual void SetValue( sal_Int64 nNewValue );
+ virtual sal_Int64 GetValue() const;
+ BOOL IsValueModified() const;
+ sal_Int64 GetCorrectedValue() const { return mnCorrectedValue; }
+
+ Fraction ConvertToFraction( sal_Int64 nValue );
+ sal_Int64 ConvertToLong( const Fraction& rValue );
+ sal_Int64 Normalize( sal_Int64 nValue ) const;
+ sal_Int64 Denormalize( sal_Int64 nValue ) const;
+};
+
+// -------------------
+// - MetricFormatter -
+// -------------------
+
+class VCL_DLLPUBLIC MetricFormatter : public NumericFormatter
+{
+private:
+ SAL_DLLPRIVATE void ImplInit();
+
+protected:
+ XubString maCustomUnitText;
+ XubString maCurUnitText;
+ sal_Int64 mnBaseValue;
+ FieldUnit meUnit;
+ Link maCustomConvertLink;
+
+protected:
+ MetricFormatter();
+
+ virtual XubString CreateFieldText( sal_Int64 nValue ) const;
+
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+ SAL_DLLPRIVATE BOOL ImplMetricReformat( const XubString& rStr, double& rValue, XubString& rOutStr );
+
+public:
+ ~MetricFormatter();
+
+ virtual void CustomConvert() = 0;
+ virtual void Reformat();
+
+ void SetUnit( FieldUnit meUnit );
+ FieldUnit GetUnit() const { return meUnit; }
+ void SetCustomUnitText( const XubString& rStr );
+ const XubString& GetCustomUnitText() const { return maCustomUnitText; }
+ const XubString& GetCurUnitText() const { return maCurUnitText; }
+
+ using NumericFormatter::SetMax;
+ void SetMax( sal_Int64 nNewMax, FieldUnit eInUnit );
+ using NumericFormatter::GetMax;
+ sal_Int64 GetMax( FieldUnit eOutUnit ) const;
+ using NumericFormatter::SetMin;
+ void SetMin( sal_Int64 nNewMin, FieldUnit eInUnit );
+ using NumericFormatter::GetMin;
+ sal_Int64 GetMin( FieldUnit eOutUnit ) const;
+ void SetBaseValue( sal_Int64 nNewBase, FieldUnit eInUnit = FUNIT_NONE );
+ sal_Int64 GetBaseValue( FieldUnit eOutUnit = FUNIT_NONE ) const;
+
+ virtual void SetValue( sal_Int64 nNewValue, FieldUnit eInUnit );
+ virtual void SetValue( sal_Int64 nValue );
+ using NumericFormatter::SetUserValue;
+ void SetUserValue( sal_Int64 nNewValue, FieldUnit eInUnit );
+ virtual sal_Int64 GetValue( FieldUnit eOutUnit ) const;
+ virtual sal_Int64 GetValue() const;
+ using NumericFormatter::GetCorrectedValue;
+ sal_Int64 GetCorrectedValue( FieldUnit eOutUnit ) const;
+
+ void SetCustomConvertHdl( const Link& rLink ) { maCustomConvertLink = rLink; }
+ const Link& GetCustomConvertHdl() const { return maCustomConvertLink; }
+};
+
+
+// ---------------------
+// - CurrencyFormatter -
+// ---------------------
+
+class VCL_DLLPUBLIC CurrencyFormatter : public NumericFormatter
+{
+private:
+ String maCurrencySymbol;
+
+ SAL_DLLPRIVATE void ImplInit();
+
+protected:
+ CurrencyFormatter();
+ virtual XubString CreateFieldText( sal_Int64 nValue ) const;
+ SAL_DLLPRIVATE BOOL ImplCurrencyReformat( const XubString& rStr, XubString& rOutStr );
+
+public:
+ ~CurrencyFormatter();
+
+ virtual void Reformat();
+
+ void SetCurrencySymbol( const String& rStr );
+ String GetCurrencySymbol() const;
+
+ virtual void SetValue( sal_Int64 nNewValue );
+ virtual sal_Int64 GetValue() const;
+};
+
+
+// -----------------
+// - DateFormatter -
+// -----------------
+
+class VCL_DLLPUBLIC DateFormatter : public FormatterBase
+{
+private:
+ CalendarWrapper* mpCalendarWrapper;
+ Date maFieldDate;
+ Date maLastDate;
+ Date maMin;
+ Date maMax;
+ Date maCorrectedDate;
+ BOOL mbLongFormat;
+ BOOL mbEmptyDate;
+ BOOL mbShowDateCentury;
+ USHORT mnDateFormat;
+ ULONG mnExtDateFormat;
+ BOOL mbEnforceValidValue;
+
+ SAL_DLLPRIVATE void ImplInit();
+
+protected:
+ DateFormatter();
+
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+ SAL_DLLPRIVATE const Date& ImplGetFieldDate() const { return maFieldDate; }
+ SAL_DLLPRIVATE BOOL ImplDateReformat( const XubString& rStr, XubString& rOutStr,
+ const AllSettings& rSettings );
+ SAL_DLLPRIVATE void ImplSetUserDate( const Date& rNewDate,
+ Selection* pNewSelection = NULL );
+ SAL_DLLPRIVATE XubString ImplGetDateAsText( const Date& rDate,
+ const AllSettings& rSettings ) const;
+ SAL_DLLPRIVATE void ImplNewFieldValue( const Date& rDate );
+ CalendarWrapper& GetCalendarWrapper() const;
+
+ SAL_DLLPRIVATE BOOL ImplAllowMalformedInput() const;
+
+public:
+ ~DateFormatter();
+
+ virtual void Reformat();
+ virtual void ReformatAll();
+
+ virtual void SetLocale( const ::com::sun::star::lang::Locale& rLocale );
+
+
+ void SetExtDateFormat( ExtDateFieldFormat eFormat );
+ ExtDateFieldFormat GetExtDateFormat( BOOL bResolveSystemFormat = FALSE ) const;
+
+ void SetMin( const Date& rNewMin );
+ const Date& GetMin() const { return maMin; }
+
+ void SetMax( const Date& rNewMax );
+ const Date& GetMax() const { return maMax; }
+
+
+ // --------------------------------------------------------------
+ // MT: Remove these methods too, ExtDateFormat should be enough!
+ // What should happen if using DDMMYYYY, but ShowCentury=FALSE?
+ // --------------------------------------------------------------
+ void SetLongFormat( BOOL bLong );
+ BOOL IsLongFormat() const { return mbLongFormat; }
+ void SetShowDateCentury( BOOL bShowCentury );
+ BOOL IsShowDateCentury() const { return mbShowDateCentury; }
+ // --------------------------------------------------------------
+
+ void SetDate( const Date& rNewDate );
+ void SetUserDate( const Date& rNewDate );
+ Date GetDate() const;
+ Date GetRealDate() const;
+ BOOL IsDateModified() const;
+ void SetEmptyDate();
+ BOOL IsEmptyDate() const;
+ Date GetCorrectedDate() const { return maCorrectedDate; }
+
+ void ResetLastDate() { maLastDate = Date( 0, 0, 0 ); }
+
+ static void ExpandCentury( Date& rDate );
+ static void ExpandCentury( Date& rDate, USHORT nTwoDigitYearStart );
+
+ static Date GetInvalidDate() { return Date( 0, 0, 0 ); }
+
+ /** enables or disables the enforcement of valid values
+
+ If this is set to <TRUE/> (which is the default), then GetDate will always return a valid
+ date, no matter whether the current text can really be interpreted as date. (Note: this
+ is the compatible bahavior).
+
+ If this is set to <FALSE/>, the GetDate will return GetInvalidDate, in case the current text
+ cannot be interpreted as date.
+
+ In addition, if this is set to <FALSE/>, the text in the field will <em>not</em> be corrected
+ when the control loses the focus - instead, the invalid input will be preserved.
+ */
+ void EnforceValidValue( BOOL _bEnforce ) { mbEnforceValidValue = _bEnforce; }
+ inline BOOL IsEnforceValidValue( ) const { return mbEnforceValidValue; }
+};
+
+
+// -----------------
+// - TimeFormatter -
+// -----------------
+
+class VCL_DLLPUBLIC TimeFormatter : public FormatterBase
+{
+private:
+ Time maLastTime;
+ Time maMin;
+ Time maMax;
+ Time maCorrectedTime;
+ TimeFieldFormat meFormat;
+ USHORT mnTimeFormat;
+ BOOL mbDuration;
+ BOOL mbEmptyTime;
+ BOOL mbEnforceValidValue;
+
+ SAL_DLLPRIVATE void ImplInit();
+
+protected:
+ Time maFieldTime;
+
+ TimeFormatter();
+
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+ SAL_DLLPRIVATE BOOL ImplTimeReformat( const XubString& rStr, XubString& rOutStr );
+ SAL_DLLPRIVATE void ImplNewFieldValue( const Time& rTime );
+ SAL_DLLPRIVATE void ImplSetUserTime( const Time& rNewTime, Selection* pNewSelection = NULL );
+ SAL_DLLPRIVATE BOOL ImplAllowMalformedInput() const;
+
+public:
+
+ enum TimeFormat {
+ HOUR_12,
+ HOUR_24
+ };
+
+ ~TimeFormatter();
+
+ virtual void Reformat();
+ virtual void ReformatAll();
+
+ void SetMin( const Time& rNewMin );
+ const Time& GetMin() const { return maMin; }
+ void SetMax( const Time& rNewMax );
+ const Time& GetMax() const { return maMax; }
+
+ void SetTimeFormat( TimeFormat eNewFormat );
+ TimeFormat GetTimeFormat() const;
+
+ void SetFormat( TimeFieldFormat eNewFormat );
+ TimeFieldFormat GetFormat() const { return meFormat; }
+
+ void SetDuration( BOOL mbDuration );
+ BOOL IsDuration() const { return mbDuration; }
+
+ void SetTime( const Time& rNewTime );
+ void SetUserTime( const Time& rNewTime );
+ Time GetTime() const;
+ Time GetRealTime() const;
+ BOOL IsTimeModified() const;
+ void SetEmptyTime() { FormatterBase::SetEmptyFieldValue(); }
+ BOOL IsEmptyTime() const { return FormatterBase::IsEmptyFieldValue(); }
+ Time GetCorrectedTime() const { return maCorrectedTime; }
+
+ static Time GetInvalidTime() { return Time( 99, 99, 99 ); }
+
+ /** enables or disables the enforcement of valid values
+
+ If this is set to <TRUE/> (which is the default), then GetTime will always return a valid
+ time, no matter whether the current text can really be interpreted as time. (Note: this
+ is the compatible bahavior).
+
+ If this is set to <FALSE/>, the GetTime will return GetInvalidTime, in case the current text
+ cannot be interpreted as time.
+
+ In addition, if this is set to <FALSE/>, the text in the field will <em>not</em> be corrected
+ when the control loses the focus - instead, the invalid input will be preserved.
+ */
+ void EnforceValidValue( BOOL _bEnforce ) { mbEnforceValidValue = _bEnforce; }
+ inline BOOL IsEnforceValidValue( ) const { return mbEnforceValidValue; }
+};
+
+
+// ----------------
+// - PatternField -
+// ----------------
+
+class VCL_DLLPUBLIC PatternField : public SpinField, public PatternFormatter
+{
+public:
+ PatternField( Window* pParent, WinBits nWinStyle );
+ PatternField( Window* pParent, const ResId& rResId );
+ ~PatternField();
+
+ virtual long PreNotify( NotifyEvent& rNEvt );
+ virtual long Notify( NotifyEvent& rNEvt );
+ virtual void Modify();
+};
+
+
+// ----------------
+// - NumericField -
+// ----------------
+
+class VCL_DLLPUBLIC NumericField : public SpinField, public NumericFormatter
+{
+protected:
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+
+public:
+ NumericField( Window* pParent, WinBits nWinStyle );
+ NumericField( Window* pParent, const ResId& rResId );
+ ~NumericField();
+
+ virtual long PreNotify( NotifyEvent& rNEvt );
+ virtual long Notify( NotifyEvent& rNEvt );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+
+ virtual void Modify();
+
+ virtual void Up();
+ virtual void Down();
+ virtual void First();
+ virtual void Last();
+};
+
+
+// ----------------
+// - MetricField -
+// ----------------
+
+class VCL_DLLPUBLIC MetricField : public SpinField, public MetricFormatter
+{
+protected:
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+
+public:
+ MetricField( Window* pParent, WinBits nWinStyle );
+ MetricField( Window* pParent, const ResId& rResId );
+ ~MetricField();
+
+ virtual long PreNotify( NotifyEvent& rNEvt );
+ virtual long Notify( NotifyEvent& rNEvt );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+
+ virtual void Modify();
+
+ virtual void Up();
+ virtual void Down();
+ virtual void First();
+ virtual void Last();
+ virtual void CustomConvert();
+
+ void SetFirst( sal_Int64 nNewFirst, FieldUnit eInUnit );
+ inline void SetFirst(sal_Int64 first) { SetFirst(first, FUNIT_NONE); }
+ sal_Int64 GetFirst( FieldUnit eOutUnit ) const;
+ inline sal_Int64 GetFirst() const { return GetFirst(FUNIT_NONE); }
+ void SetLast( sal_Int64 nNewLast, FieldUnit eInUnit );
+ inline void SetLast(sal_Int64 last) { SetLast(last, FUNIT_NONE); }
+ sal_Int64 GetLast( FieldUnit eOutUnit ) const;
+ inline sal_Int64 GetLast() const { return GetLast(FUNIT_NONE); }
+
+ static void SetDefaultUnit( FieldUnit eDefaultUnit );
+ static FieldUnit GetDefaultUnit();
+ static sal_Int64 ConvertValue( sal_Int64 nValue, sal_Int64 mnBaseValue, USHORT nDecDigits,
+ FieldUnit eInUnit, FieldUnit eOutUnit );
+ static sal_Int64 ConvertValue( sal_Int64 nValue, USHORT nDecDigits,
+ FieldUnit eInUnit, MapUnit eOutUnit );
+ static sal_Int64 ConvertValue( sal_Int64 nValue, USHORT nDecDigits,
+ MapUnit eInUnit, FieldUnit eOutUnit );
+
+ // for backwards compatibility
+ // caution: conversion to double loses precision
+ static double ConvertDoubleValue( double nValue, sal_Int64 mnBaseValue, USHORT nDecDigits,
+ FieldUnit eInUnit, FieldUnit eOutUnit );
+ static double ConvertDoubleValue( double nValue, USHORT nDecDigits,
+ FieldUnit eInUnit, MapUnit eOutUnit );
+ static double ConvertDoubleValue( double nValue, USHORT nDecDigits,
+ MapUnit eInUnit, FieldUnit eOutUnit );
+
+ // for backwards compatibility
+ // caution: conversion to double loses precision
+ static double ConvertDoubleValue( sal_Int64 nValue, sal_Int64 nBaseValue, USHORT nDecDigits,
+ FieldUnit eInUnit, FieldUnit eOutUnit )
+ { return ConvertDoubleValue( static_cast<double>(nValue), nBaseValue, nDecDigits, eInUnit, eOutUnit ); }
+ static double ConvertDoubleValue( sal_Int64 nValue, USHORT nDecDigits,
+ FieldUnit eInUnit, MapUnit eOutUnit )
+ { return ConvertDoubleValue( static_cast<double>(nValue), nDecDigits, eInUnit, eOutUnit ); }
+ static double ConvertDoubleValue( sal_Int64 nValue, USHORT nDecDigits,
+ MapUnit eInUnit, FieldUnit eOutUnit )
+ { return ConvertDoubleValue( static_cast<double>(nValue), nDecDigits, eInUnit, eOutUnit ); }
+};
+
+
+// -----------------
+// - CurrencyField -
+// -----------------
+
+class VCL_DLLPUBLIC CurrencyField : public SpinField, public CurrencyFormatter
+{
+protected:
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+
+public:
+ CurrencyField( Window* pParent, WinBits nWinStyle );
+ CurrencyField( Window* pParent, const ResId& rResId );
+ ~CurrencyField();
+
+ virtual long PreNotify( NotifyEvent& rNEvt );
+ virtual long Notify( NotifyEvent& rNEvt );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+
+ virtual void Modify();
+
+ virtual void Up();
+ virtual void Down();
+ virtual void First();
+ virtual void Last();
+};
+
+
+// -------------
+// - DateField -
+// -------------
+
+class VCL_DLLPUBLIC DateField : public SpinField, public DateFormatter
+{
+private:
+ Date maFirst;
+ Date maLast;
+
+protected:
+ SAL_DLLPRIVATE void ImplDateSpinArea( BOOL bUp );
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+
+public:
+ DateField( Window* pParent, WinBits nWinStyle );
+ DateField( Window* pParent, const ResId& rResId );
+ ~DateField();
+
+ virtual long PreNotify( NotifyEvent& rNEvt );
+ virtual long Notify( NotifyEvent& rNEvt );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+
+ virtual void Modify();
+
+ virtual void Up();
+ virtual void Down();
+ virtual void First();
+ virtual void Last();
+
+ void SetFirst( const Date& rNewFirst ) { maFirst = rNewFirst; }
+ Date GetFirst() const { return maFirst; }
+ void SetLast( const Date& rNewLast ) { maLast = rNewLast; }
+ Date GetLast() const { return maLast; }
+};
+
+// -------------
+// - TimeField -
+// -------------
+
+class VCL_DLLPUBLIC TimeField : public SpinField, public TimeFormatter
+{
+private:
+ Time maFirst;
+ Time maLast;
+
+protected:
+ SAL_DLLPRIVATE void ImplTimeSpinArea( BOOL bUp );
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+
+public:
+ TimeField( Window* pParent, WinBits nWinStyle );
+ TimeField( Window* pParent, const ResId& rResId );
+ ~TimeField();
+
+ virtual long PreNotify( NotifyEvent& rNEvt );
+ virtual long Notify( NotifyEvent& rNEvt );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+
+ virtual void Modify();
+
+ virtual void Up();
+ virtual void Down();
+ virtual void First();
+ virtual void Last();
+
+ void SetFirst( const Time& rNewFirst ) { maFirst = rNewFirst; }
+ Time GetFirst() const { return maFirst; }
+ void SetLast( const Time& rNewLast ) { maLast = rNewLast; }
+ Time GetLast() const { return maLast; }
+
+ void SetExtFormat( ExtTimeFieldFormat eFormat );
+};
+
+
+// --------------
+// - PatternBox -
+// --------------
+
+class VCL_DLLPUBLIC PatternBox : public ComboBox, public PatternFormatter
+{
+public:
+ PatternBox( Window* pParent, WinBits nWinStyle );
+ PatternBox( Window* pParent, const ResId& rResId );
+ ~PatternBox();
+
+ virtual long PreNotify( NotifyEvent& rNEvt );
+ virtual long Notify( NotifyEvent& rNEvt );
+
+ virtual void Modify();
+
+ virtual void ReformatAll();
+
+ void InsertString( const XubString& rStr,
+ USHORT nPos = COMBOBOX_APPEND );
+ void RemoveString( const XubString& rStr );
+ using PatternFormatter::GetString;
+ XubString GetString( USHORT nPos ) const;
+ USHORT GetStringPos( const XubString& rStr ) const;
+};
+
+
+// --------------
+// - NumericBox -
+// --------------
+
+class VCL_DLLPUBLIC NumericBox : public ComboBox, public NumericFormatter
+{
+public:
+ NumericBox( Window* pParent, WinBits nWinStyle );
+ NumericBox( Window* pParent, const ResId& rResId );
+ ~NumericBox();
+
+ virtual long PreNotify( NotifyEvent& rNEvt );
+ virtual long Notify( NotifyEvent& rNEvt );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+
+ virtual void Modify();
+
+ virtual void ReformatAll();
+
+ void InsertValue( sal_Int64 nValue, USHORT nPos = COMBOBOX_APPEND );
+ void RemoveValue( sal_Int64 nValue );
+ using NumericFormatter::GetValue;
+ sal_Int64 GetValue( USHORT nPos ) const;
+ USHORT GetValuePos( sal_Int64 nPos ) const;
+};
+
+
+// -------------
+// - MetricBox -
+// -------------
+
+class VCL_DLLPUBLIC MetricBox : public ComboBox, public MetricFormatter
+{
+public:
+ MetricBox( Window* pParent, WinBits nWinStyle );
+ MetricBox( Window* pParent, const ResId& rResId );
+ ~MetricBox();
+
+ virtual long PreNotify( NotifyEvent& rNEvt );
+ virtual long Notify( NotifyEvent& rNEvt );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+
+ virtual void Modify();
+
+ virtual void CustomConvert();
+ virtual void ReformatAll();
+
+ void InsertValue( sal_Int64 nValue, FieldUnit eInUnit = FUNIT_NONE,
+ USHORT nPos = COMBOBOX_APPEND );
+ void RemoveValue( sal_Int64 nValue, FieldUnit eInUnit = FUNIT_NONE );
+ sal_Int64 GetValue( USHORT nPos, FieldUnit eOutUnit = FUNIT_NONE ) const;
+ USHORT GetValuePos( sal_Int64 nValue,
+ FieldUnit eInUnit = FUNIT_NONE ) const;
+
+ // Needed, because GetValue() with nPos hide these functions
+ virtual sal_Int64 GetValue( FieldUnit eOutUnit ) const;
+ virtual sal_Int64 GetValue() const;
+};
+
+
+// ---------------
+// - CurrencyBox -
+// ---------------
+
+class VCL_DLLPUBLIC CurrencyBox : public ComboBox, public CurrencyFormatter
+{
+public:
+ CurrencyBox( Window* pParent, WinBits nWinStyle );
+ CurrencyBox( Window* pParent, const ResId& rResId );
+ ~CurrencyBox();
+
+ virtual long PreNotify( NotifyEvent& rNEvt );
+ virtual long Notify( NotifyEvent& rNEvt );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+
+ virtual void Modify();
+
+ virtual void ReformatAll();
+
+ void InsertValue( sal_Int64 nValue, USHORT nPos = COMBOBOX_APPEND );
+ void RemoveValue( sal_Int64 nValue );
+ sal_Int64 GetValue( USHORT nPos ) const;
+ USHORT GetValuePos( sal_Int64 nValue ) const;
+
+ // Needed, because GetValue() with nPos hide this function
+ virtual sal_Int64 GetValue() const;
+};
+
+
+// -----------
+// - DateBox -
+// -----------
+
+class VCL_DLLPUBLIC DateBox : public ComboBox, public DateFormatter
+{
+public:
+ DateBox( Window* pParent, WinBits nWinStyle );
+ DateBox( Window* pParent, const ResId& rResId );
+ ~DateBox();
+
+ virtual long PreNotify( NotifyEvent& rNEvt );
+ virtual long Notify( NotifyEvent& rNEvt );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+
+ virtual void Modify();
+
+ virtual void ReformatAll();
+
+ void InsertDate( const Date& rDate, USHORT nPos = COMBOBOX_APPEND );
+ void RemoveDate( const Date& rDate );
+ using DateFormatter::GetDate;
+ Date GetDate( USHORT nPos ) const;
+ USHORT GetDatePos( const Date& rDate ) const;
+};
+
+
+// -----------
+// - TimeBox -
+// -----------
+
+class VCL_DLLPUBLIC TimeBox : public ComboBox, public TimeFormatter
+{
+public:
+ TimeBox( Window* pParent, WinBits nWinStyle );
+ TimeBox( Window* pParent, const ResId& rResId );
+ ~TimeBox();
+
+ virtual long PreNotify( NotifyEvent& rNEvt );
+ virtual long Notify( NotifyEvent& rNEvt );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+
+ virtual void Modify();
+
+ virtual void ReformatAll();
+
+ void InsertTime( const Time& rTime, USHORT nPos = COMBOBOX_APPEND );
+ void RemoveTime( const Time& rTime );
+ using TimeFormatter::GetTime;
+ Time GetTime( USHORT nPos ) const;
+ USHORT GetTimePos( const Time& rTime ) const;
+};
+
+#endif // _SV_FIELD_HXX
diff --git a/vcl/inc/vcl/fixbrd.hxx b/vcl/inc/vcl/fixbrd.hxx
new file mode 100644
index 000000000000..2bf0d8e1cb31
--- /dev/null
+++ b/vcl/inc/vcl/fixbrd.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_FIXBRD_HXX
+#define _SV_FIXBRD_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/decoview.hxx>
+#include <vcl/ctrl.hxx>
+
+// ---------------------
+// - FixedBorder-Types -
+// ---------------------
+
+#define FIXEDBORDER_TYPE_IN (FRAME_DRAW_IN)
+#define FIXEDBORDER_TYPE_OUT (FRAME_DRAW_OUT)
+#define FIXEDBORDER_TYPE_GROUP (FRAME_DRAW_GROUP)
+#define FIXEDBORDER_TYPE_DOUBLEIN (FRAME_DRAW_DOUBLEIN)
+#define FIXEDBORDER_TYPE_DOUBLEOUT (FRAME_DRAW_DOUBLEOUT)
+
+// ---------------
+// - FixedBorder -
+// ---------------
+
+class VCL_DLLPUBLIC FixedBorder : public Control
+{
+private:
+ USHORT mnType;
+ BOOL mbTransparent;
+
+private:
+ using Control::ImplInitSettings;
+ using Window::ImplInit;
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle );
+ SAL_DLLPRIVATE WinBits ImplInitStyle( WinBits nStyle );
+ SAL_DLLPRIVATE void ImplInitSettings();
+ SAL_DLLPRIVATE void ImplDraw( OutputDevice* pDev, ULONG nDrawFlags,
+ const Point& rPos, const Size& rSize );
+
+public:
+ FixedBorder( Window* pParent, WinBits nStyle = 0 );
+ FixedBorder( Window* pParent, const ResId& rResId );
+ ~FixedBorder();
+
+ virtual void Paint( const Rectangle& rRect );
+ virtual void Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG nFlags );
+ virtual void Resize();
+ virtual void StateChanged( StateChangedType nType );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+
+ void SetTransparent( BOOL bTransparent );
+ BOOL IsTransparent() const { return mbTransparent; }
+ void SetBorderType( USHORT nType );
+ USHORT GetBorderType() const { return mnType; }
+};
+
+#endif // _SV_FIXBRD_HXX
diff --git a/vcl/inc/vcl/fixed.hxx b/vcl/inc/vcl/fixed.hxx
new file mode 100644
index 000000000000..4460694420a0
--- /dev/null
+++ b/vcl/inc/vcl/fixed.hxx
@@ -0,0 +1,199 @@
+/*************************************************************************
+ *
+ * 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_FIXED_HXX
+#define _SV_FIXED_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/bitmap.hxx>
+#include <vcl/image.hxx>
+#include <vcl/ctrl.hxx>
+
+class UserDrawEvent;
+
+// -------------
+// - FixedText -
+// -------------
+
+class VCL_DLLPUBLIC FixedText : public Control
+{
+//#if 0 // _SOLAR__PRIVATE
+private:
+ using Control::ImplInitSettings;
+ using Window::ImplInit;
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle );
+ SAL_DLLPRIVATE WinBits ImplInitStyle( WinBits nStyle );
+ SAL_DLLPRIVATE void ImplInitSettings( BOOL bFont, BOOL bForeground, BOOL bBackground );
+ SAL_DLLPRIVATE void ImplDraw( OutputDevice* pDev, ULONG nDrawFlags,
+ const Point& rPos, const Size& rSize, bool bFillLayout = false ) const;
+public:
+ SAL_DLLPRIVATE static USHORT ImplGetTextStyle( WinBits nWinBits );
+//#endif
+protected:
+ virtual void FillLayoutData() const;
+ virtual const Font&
+ GetCanonicalFont( const StyleSettings& _rStyle ) const;
+ virtual const Color&
+ GetCanonicalTextColor( const StyleSettings& _rStyle ) const;
+
+public:
+ FixedText( Window* pParent, WinBits nStyle = 0 );
+ FixedText( Window* pParent, const ResId& rResId );
+ FixedText( Window* pParent, const ResId& rResId, bool bDisableAccessibleLabelForRelation );
+
+ virtual void Paint( const Rectangle& rRect );
+ virtual void Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG nFlags );
+ virtual void Resize();
+ virtual void StateChanged( StateChangedType nType );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+
+ static Size CalcMinimumTextSize( Control const* pControl, long nMaxWidth = 0 );
+ Size CalcMinimumSize( long nMaxWidth = 0 ) const;
+ virtual Size GetOptimalSize(WindowSizeType eType) const;
+};
+
+// -------------
+// - FixedLine -
+// -------------
+
+class VCL_DLLPUBLIC FixedLine : public Control
+{
+private:
+ using Control::ImplInitSettings;
+ using Window::ImplInit;
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle );
+ SAL_DLLPRIVATE WinBits ImplInitStyle( WinBits nStyle );
+ SAL_DLLPRIVATE void ImplInitSettings( BOOL bFont, BOOL bForeground, BOOL bBackground );
+ SAL_DLLPRIVATE void ImplDraw( bool bLayout = false );
+
+protected:
+ virtual void FillLayoutData() const;
+ virtual const Font&
+ GetCanonicalFont( const StyleSettings& _rStyle ) const;
+ virtual const Color&
+ GetCanonicalTextColor( const StyleSettings& _rStyle ) const;
+
+public:
+ FixedLine( Window* pParent, WinBits nStyle = WB_HORZ );
+ FixedLine( Window* pParent, const ResId& rResId );
+
+ virtual void Paint( const Rectangle& rRect );
+ virtual void Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG nFlags );
+ virtual void Resize();
+ virtual void StateChanged( StateChangedType nType );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+
+ virtual Size GetOptimalSize(WindowSizeType eType) const;
+};
+
+// ---------------
+// - FixedBitmap -
+// ---------------
+
+class VCL_DLLPUBLIC FixedBitmap : public Control
+{
+private:
+ Bitmap maBitmap;
+ Bitmap maBitmapHC;
+
+ using Control::ImplInitSettings;
+ using Window::ImplInit;
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle );
+ SAL_DLLPRIVATE WinBits ImplInitStyle( WinBits nStyle );
+ SAL_DLLPRIVATE void ImplInitSettings();
+ SAL_DLLPRIVATE void ImplDraw( OutputDevice* pDev, ULONG nDrawFlags,
+ const Point& rPos, const Size& rSize );
+
+protected:
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+
+public:
+ FixedBitmap( Window* pParent, WinBits nStyle = 0 );
+ FixedBitmap( Window* pParent, const ResId& rResId );
+ ~FixedBitmap();
+
+ virtual void Paint( const Rectangle& rRect );
+ virtual void Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG nFlags );
+ virtual void Resize();
+ virtual void StateChanged( StateChangedType nType );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+
+ void SetBitmap( const Bitmap& rBitmap );
+ using OutputDevice::GetBitmap;
+ const Bitmap& GetBitmap() const { return maBitmap; }
+ BOOL SetModeBitmap( const Bitmap& rBitmap, BmpColorMode eMode = BMP_COLOR_NORMAL );
+ const Bitmap& GetModeBitmap( BmpColorMode eMode = BMP_COLOR_NORMAL ) const;
+};
+
+// --------------
+// - FixedImage -
+// --------------
+
+class VCL_DLLPUBLIC FixedImage : public Control
+{
+private:
+ Image maImage;
+ Image maImageHC;
+ BOOL mbInUserDraw;
+
+private:
+ using Control::ImplInitSettings;
+ using Window::ImplInit;
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle );
+ SAL_DLLPRIVATE WinBits ImplInitStyle( WinBits nStyle );
+ SAL_DLLPRIVATE void ImplInitSettings();
+ SAL_DLLPRIVATE void ImplDraw( OutputDevice* pDev, ULONG nDrawFlags,
+ const Point& rPos, const Size& rSize );
+
+protected:
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+
+public:
+ FixedImage( Window* pParent, WinBits nStyle = 0 );
+ FixedImage( Window* pParent, const ResId& rResId );
+ ~FixedImage();
+
+ virtual void Paint( const Rectangle& rRect );
+ virtual void Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG nFlags );
+ virtual void Resize();
+ virtual void StateChanged( StateChangedType nType );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+ virtual void UserDraw( const UserDrawEvent& rUDEvt );
+ virtual Size GetOptimalSize(WindowSizeType eType) const;
+
+ void SetImage( const Image& rImage );
+ const Image& GetImage() const { return maImage; }
+
+ BOOL SetModeImage( const Image& rImage, BmpColorMode eMode = BMP_COLOR_NORMAL );
+ const Image& GetModeImage( BmpColorMode eMode = BMP_COLOR_NORMAL ) const;
+
+ Point CalcImagePos( const Point& rPos,
+ const Size& rObjSize, const Size& rWinSize );
+};
+
+#endif // _SV_FIXED_HXX
diff --git a/vcl/inc/vcl/fldunit.hxx b/vcl/inc/vcl/fldunit.hxx
new file mode 100644
index 000000000000..aa76f34332d6
--- /dev/null
+++ b/vcl/inc/vcl/fldunit.hxx
@@ -0,0 +1,33 @@
+/*************************************************************************
+ *
+ * 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_FLDUNIT_HXX
+#define _VCL_FLDUNIT_HXX
+
+#include <tools/fldunit.hxx>
+
+#endif // _VCL_FLDUNIT_HXX
diff --git a/vcl/inc/vcl/floatwin.hxx b/vcl/inc/vcl/floatwin.hxx
new file mode 100644
index 000000000000..8b7c9be6499c
--- /dev/null
+++ b/vcl/inc/vcl/floatwin.hxx
@@ -0,0 +1,161 @@
+/*************************************************************************
+ *
+ * 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_FLOATWIN_HXX
+#define _SV_FLOATWIN_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/syswin.hxx>
+
+class ToolBox;
+class PopupModeEvent;
+
+// ------------------------
+// - FloatingWindow-Types -
+// ------------------------
+
+#define FLOATWIN_POPUPMODE_ALLOWTEAROFF ((ULONG)0x00000001)
+#define FLOATWIN_POPUPMODE_ANIMATIONSLIDE ((ULONG)0x00000002)
+#define FLOATWIN_POPUPMODE_NOAUTOARRANGE ((ULONG)0x00000004)
+#define FLOATWIN_POPUPMODE_NOANIMATION ((ULONG)0x00000008)
+#define FLOATWIN_POPUPMODE_DOWN ((ULONG)0x00000010)
+#define FLOATWIN_POPUPMODE_UP ((ULONG)0x00000020)
+#define FLOATWIN_POPUPMODE_LEFT ((ULONG)0x00000040)
+#define FLOATWIN_POPUPMODE_RIGHT ((ULONG)0x00000080)
+#define FLOATWIN_POPUPMODE_NOFOCUSCLOSE ((ULONG)0x00000100)
+#define FLOATWIN_POPUPMODE_NOKEYCLOSE ((ULONG)0x00000200)
+#define FLOATWIN_POPUPMODE_NOMOUSECLOSE ((ULONG)0x00000400)
+#define FLOATWIN_POPUPMODE_NOMOUSERECTCLOSE ((ULONG)0x00000800)
+#define FLOATWIN_POPUPMODE_ALLMOUSEBUTTONCLOSE ((ULONG)0x00001000)
+#define FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE ((ULONG)0x00002000)
+#define FLOATWIN_POPUPMODE_PATHMOUSECANCELCLICK ((ULONG)0x00004000)
+#define FLOATWIN_POPUPMODE_NEWLEVEL ((ULONG)0x00008000)
+#define FLOATWIN_POPUPMODE_NOMOUSEUPCLOSE ((ULONG)0x00010000)
+#define FLOATWIN_POPUPMODE_GRABFOCUS ((ULONG)0x00020000)
+
+#define FLOATWIN_POPUPMODEEND_CANCEL ((USHORT)0x0001)
+#define FLOATWIN_POPUPMODEEND_TEAROFF ((USHORT)0x0002)
+#define FLOATWIN_POPUPMODEEND_DONTCALLHDL ((USHORT)0x0004)
+#define FLOATWIN_POPUPMODEEND_CLOSEALL ((USHORT)0x0008)
+
+#define FLOATWIN_TITLE_NORMAL ((USHORT)0x0001)
+#define FLOATWIN_TITLE_TEAROFF ((USHORT)0x0002)
+#define FLOATWIN_TITLE_NONE ((USHORT)0x0004)
+
+// ------------------
+// - FloatingWindow -
+// ------------------
+
+class VCL_DLLPUBLIC FloatingWindow : public SystemWindow
+{
+ class ImplData;
+private:
+ FloatingWindow* mpNextFloat;
+ Window* mpFirstPopupModeWin;
+ ImplData* mpImplData;
+ Rectangle maFloatRect;
+ ULONG mnPostId;
+ ULONG mnPopupModeFlags;
+ USHORT mnTitle;
+ USHORT mnOldTitle;
+ BOOL mbInPopupMode;
+ BOOL mbPopupMode;
+ BOOL mbPopupModeCanceled;
+ BOOL mbPopupModeTearOff;
+ BOOL mbMouseDown;
+ BOOL mbOldSaveBackMode;
+ BOOL mbGrabFocus; // act as key input window, although focus is not set
+ BOOL mbInCleanUp;
+ Link maPopupModeEndHdl;
+
+//#if 0 // _SOLAR__PRIVATE
+ SAL_DLLPRIVATE void ImplCallPopupModeEnd();
+ DECL_DLLPRIVATE_LINK( ImplEndPopupModeHdl, void* );
+
+ // Copy assignment is forbidden and not implemented.
+ SAL_DLLPRIVATE FloatingWindow (const FloatingWindow &);
+ SAL_DLLPRIVATE FloatingWindow & operator= (const FloatingWindow &);
+
+protected:
+ using Window::ImplInit;
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle );
+ SAL_DLLPRIVATE void ImplInitSettings();
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+
+public:
+#define IMPL_FLOATWIN_HITTEST_OUTSIDE ((USHORT)0x0001)
+#define IMPL_FLOATWIN_HITTEST_WINDOW ((USHORT)0x0002)
+#define IMPL_FLOATWIN_HITTEST_RECT ((USHORT)0x0004)
+ SAL_DLLPRIVATE FloatingWindow* ImplFloatHitTest( Window* pReference, const Point& rPos, USHORT& rHitTest );
+ SAL_DLLPRIVATE FloatingWindow* ImplFindLastLevelFloat();
+ SAL_DLLPRIVATE BOOL ImplIsFloatPopupModeWindow( const Window* pWindow );
+ SAL_DLLPRIVATE void ImplSetMouseDown() { mbMouseDown = TRUE; }
+ SAL_DLLPRIVATE BOOL ImplIsMouseDown() const { return mbMouseDown; }
+ SAL_DLLPRIVATE static Point ImplCalcPos( Window* pWindow,
+ const Rectangle& rRect, ULONG nFlags,
+ USHORT& rArrangeIndex );
+ SAL_DLLPRIVATE void ImplEndPopupMode( USHORT nFlags = 0, ULONG nFocusId = 0 );
+ SAL_DLLPRIVATE Rectangle& ImplGetItemEdgeClipRect();
+ SAL_DLLPRIVATE BOOL ImplIsInPrivatePopupMode() const { return mbInPopupMode; }
+//#endif
+
+public:
+ FloatingWindow( Window* pParent, WinBits nStyle = WB_STDFLOATWIN );
+ FloatingWindow( Window* pParent, const ResId& rResId );
+ ~FloatingWindow();
+
+ virtual long Notify( NotifyEvent& rNEvt );
+ virtual void StateChanged( StateChangedType nType );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+
+ virtual void PopupModeEnd();
+
+ void SetTitleType( USHORT nTitle );
+ USHORT GetTitleType() const { return mnTitle; }
+
+ void StartPopupMode( const Rectangle& rRect, ULONG nFlags = 0 );
+ void StartPopupMode( ToolBox* pBox, ULONG nFlags = 0 );
+ void EndPopupMode( USHORT nFlags = 0 );
+ void AddPopupModeWindow( Window* pWindow );
+ void RemovePopupModeWindow( Window* pWindow );
+ ULONG GetPopupModeFlags() const { return mnPopupModeFlags; }
+ void SetPopupModeFlags( ULONG nFlags ) { mnPopupModeFlags = nFlags; }
+ BOOL IsInPopupMode() const { return mbPopupMode; }
+ BOOL IsInCleanUp() const { return mbInCleanUp; }
+ BOOL IsPopupModeCanceled() const { return mbPopupModeCanceled; }
+ BOOL IsPopupModeTearOff() const { return mbPopupModeTearOff; }
+
+ void SetPopupModeEndHdl( const Link& rLink ) { maPopupModeEndHdl = rLink; }
+ const Link& GetPopupModeEndHdl() const { return maPopupModeEndHdl; }
+
+ BOOL GrabsFocus() const { return mbGrabFocus; }
+
+ static Point CalcFloatingPosition( Window* pWindow, const Rectangle& rRect, ULONG nFlags, USHORT& rArrangeIndex );
+};
+
+#endif // _SV_FLOATWIN_HXX
diff --git a/vcl/inc/vcl/fntstyle.hxx b/vcl/inc/vcl/fntstyle.hxx
new file mode 100644
index 000000000000..4b4ccc9f6d02
--- /dev/null
+++ b/vcl/inc/vcl/fntstyle.hxx
@@ -0,0 +1,53 @@
+/*************************************************************************
+ *
+ * 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_FNTSTYLE_HXX
+#define _VCL_FNTSTYLE_HXX
+
+#include <tools/solar.h>
+#include <sal/types.h>
+
+// --------------
+// - Font enums -
+// --------------
+
+#ifndef ENUM_FONTRELIEF_DECLARED
+#define ENUM_FONTRELIEF_DECLARED
+
+enum FontRelief { RELIEF_NONE, RELIEF_EMBOSSED, RELIEF_ENGRAVED, FontRelief_FORCE_EQUAL_SIZE=SAL_MAX_ENUM };
+
+#endif
+
+// --------------
+// - Font types -
+// --------------
+
+typedef BYTE FontKerning;
+#define KERNING_FONTSPECIFIC ((FontKerning)0x01)
+#define KERNING_ASIAN ((FontKerning)0x02)
+
+#endif // _VCL_FNTSTYLE_HXX
diff --git a/vcl/inc/vcl/font.hxx b/vcl/inc/vcl/font.hxx
new file mode 100644
index 000000000000..80fd31ebf6dc
--- /dev/null
+++ b/vcl/inc/vcl/font.hxx
@@ -0,0 +1,140 @@
+/*************************************************************************
+ *
+ * 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_FONT_HXX
+#define _SV_FONT_HXX
+
+#include <vcl/dllapi.h>
+#include <tools/gen.hxx>
+#include <tools/string.hxx>
+#include <i18npool/lang.h>
+#include <tools/color.hxx>
+#include <vcl/vclenum.hxx>
+#include <vcl/fntstyle.hxx>
+
+class SvStream;
+#define FontAlign TextAlign
+
+class Impl_Font;
+class ImplFontAttributes;
+
+// --------
+// - Font -
+// --------
+
+class VCL_DLLPUBLIC Font
+{
+private:
+ Impl_Font* mpImplFont;
+ void MakeUnique();
+
+public:
+ Font();
+ Font( const Font& );
+ Font( const String& rFamilyName, const Size& );
+ Font( const String& rFamilyName, const String& rStyleName, const Size& );
+ Font( FontFamily eFamily, const Size& );
+ ~Font();
+
+ void SetColor( const Color& );
+ const Color& GetColor() const;
+ void SetFillColor( const Color& );
+ const Color& GetFillColor() const;
+ void SetTransparent( BOOL bTransparent );
+ BOOL IsTransparent() const;
+ void SetAlign( FontAlign );
+ FontAlign GetAlign() const;
+
+ void SetName( const String& rFamilyName );
+ const String& GetName() const;
+ void SetStyleName( const String& rStyleName );
+ const String& GetStyleName() const;
+ void SetSize( const Size& );
+ const Size& GetSize() const;
+ void SetHeight( long nHeight );
+ long GetHeight() const;
+ void SetWidth( long nWidth );
+ long GetWidth() const;
+
+ void SetFamily( FontFamily );
+ FontFamily GetFamily() const;
+ void SetCharSet( rtl_TextEncoding );
+ rtl_TextEncoding GetCharSet() const;
+ void SetLanguage( LanguageType );
+ LanguageType GetLanguage() const;
+ void SetCJKContextLanguage( LanguageType );
+ LanguageType GetCJKContextLanguage() const;
+ void SetPitch( FontPitch ePitch );
+ FontPitch GetPitch() const;
+
+ void SetOrientation( short nLineOrientation );
+ short GetOrientation() const;
+ void SetVertical( BOOL bVertical );
+ BOOL IsVertical() const;
+ void SetKerning( FontKerning nKerning );
+ FontKerning GetKerning() const;
+ BOOL IsKerning() const;
+
+ void SetWeight( FontWeight );
+ FontWeight GetWeight() const;
+ void SetWidthType( FontWidth );
+ FontWidth GetWidthType() const;
+ void SetItalic( FontItalic );
+ FontItalic GetItalic() const;
+ void SetOutline( BOOL bOutline );
+ BOOL IsOutline() const;
+ void SetShadow( BOOL bShadow );
+ BOOL IsShadow() const;
+ void SetRelief( FontRelief );
+ FontRelief GetRelief() const;
+ void SetUnderline( FontUnderline );
+ FontUnderline GetUnderline() const;
+ void SetOverline( FontUnderline );
+ FontUnderline GetOverline() const;
+ void SetStrikeout( FontStrikeout );
+ FontStrikeout GetStrikeout() const;
+ void SetEmphasisMark( FontEmphasisMark );
+ FontEmphasisMark GetEmphasisMark() const;
+ void SetWordLineMode( BOOL bWordLine );
+ BOOL IsWordLineMode() const;
+
+ void Merge( const Font& rFont );
+ void GetFontAttributes( ImplFontAttributes& rAttrs ) const;
+
+ Font& operator=( const Font& );
+ BOOL operator==( const Font& ) const;
+ BOOL operator!=( const Font& rFont ) const
+ { return !(Font::operator==( rFont )); }
+ BOOL IsSameInstance( const Font& ) const;
+
+ friend VCL_DLLPUBLIC SvStream& operator>>( SvStream& rIStm, Font& );
+ friend VCL_DLLPUBLIC SvStream& operator<<( SvStream& rOStm, const Font& );
+
+ static Font identifyFont( const void* pBuffer, sal_uInt32 nLen );
+};
+
+#endif // _VCL_FONT_HXX
diff --git a/vcl/inc/vcl/fontcache.hxx b/vcl/inc/vcl/fontcache.hxx
new file mode 100644
index 000000000000..b18748ed5791
--- /dev/null
+++ b/vcl/inc/vcl/fontcache.hxx
@@ -0,0 +1,99 @@
+/*************************************************************************
+ *
+ * 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 _PSPRINT_FONTCACHE_HXX
+#define _PSPRINT_FONTCACHE_HXX
+
+#include "vcl/dllapi.h"
+#include "vcl/fontmanager.hxx"
+
+#include "tools/string.hxx"
+
+#include <hash_map>
+
+namespace psp
+{
+
+class VCL_DLLPUBLIC FontCache
+{
+ struct FontDir;
+ friend class FontDir;
+ struct FontFile;
+ friend class FontFile;
+
+ typedef std::list< PrintFontManager::PrintFont* > FontCacheEntry;
+ struct FontFile
+ {
+ FontCacheEntry m_aEntry;
+ };
+
+ typedef std::hash_map< ::rtl::OString, FontFile, ::rtl::OStringHash > FontDirMap;
+ struct FontDir
+ {
+ sal_Int64 m_nTimestamp;
+ bool m_bNoFiles;
+ bool m_bUserOverrideOnly;
+ FontDirMap m_aEntries;
+
+ FontDir() : m_nTimestamp(0), m_bNoFiles(false), m_bUserOverrideOnly( false ) {}
+ };
+
+ typedef std::hash_map< int, FontDir > FontCacheData;
+ FontCacheData m_aCache;
+ String m_aCacheFile;
+ bool m_bDoFlush;
+
+ void read();
+ void clearCache();
+
+ void copyPrintFont( const PrintFontManager::PrintFont* pFrom, PrintFontManager::PrintFont* pTo ) const;
+ bool equalsPrintFont( const PrintFontManager::PrintFont* pLeft, PrintFontManager::PrintFont* pRight ) const;
+ PrintFontManager::PrintFont* clonePrintFont( const PrintFontManager::PrintFont* pFont ) const;
+
+ void createCacheDir( int nDirID );
+public:
+ FontCache();
+ ~FontCache();
+
+ bool getFontCacheFile( int nDirID, const rtl::OString& rFile, std::list< PrintFontManager::PrintFont* >& rNewFonts ) const;
+ void updateFontCacheEntry( const PrintFontManager::PrintFont*, bool bFlush );
+ void markEmptyDir( int nDirID, bool bNoFiles = true );
+
+ // returns false for non cached directory
+ // a cached but empty directory will return true but not append anything
+ bool listDirectory( const rtl::OString& rDir, std::list< PrintFontManager::PrintFont* >& rNewFonts ) const;
+ // returns true for directoris that contain only user overridden fonts
+ bool scanAdditionalFiles( const rtl::OString& rDir );
+
+ void flush();
+
+ void updateDirTimestamp( int nDirID );
+};
+
+} // namespace psp
+
+#endif // _PSPRINT_FONTCACHE_HXX
diff --git a/vcl/inc/vcl/fontmanager.hxx b/vcl/inc/vcl/fontmanager.hxx
new file mode 100644
index 000000000000..33fece8d88e1
--- /dev/null
+++ b/vcl/inc/vcl/fontmanager.hxx
@@ -0,0 +1,745 @@
+/*************************************************************************
+ *
+ * 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 _PSPRINT_FONTMANAGER_HXX_
+#define _PSPRINT_FONTMANAGER_HXX_
+
+#include <hash_map>
+#include <map>
+#include <list>
+#include <set>
+
+#include "vcl/dllapi.h"
+#include "vcl/helper.hxx"
+
+#include "com/sun/star/lang/Locale.hpp"
+
+#define ATOM_FAMILYNAME 2
+#define ATOM_PSNAME 3
+
+/*
+ * some words on metrics: every length returned by PrintFontManager and
+ * friends are PostScript afm style, that is they are 1/1000 font height
+ */
+
+// forward declarations
+namespace utl { class MultiAtomProvider; } // see unotools/atom.hxx
+class FontSubsetInfo;
+class ImplFontOptions;
+
+namespace psp {
+class PPDParser; // see ppdparser.hxx
+
+namespace italic
+{
+enum type {
+ Upright = 0,
+ Oblique = 1,
+ Italic = 2,
+ Unknown = 3
+};
+}
+
+namespace width
+{
+enum type {
+ Unknown = 0,
+ UltraCondensed = 1,
+ ExtraCondensed = 2,
+ Condensed = 3,
+ SemiCondensed = 4,
+ Normal = 5,
+ SemiExpanded = 6,
+ Expanded = 7,
+ ExtraExpanded = 8,
+ UltraExpanded = 9
+};
+}
+
+namespace pitch
+{
+enum type {
+ Unknown = 0,
+ Fixed = 1,
+ Variable = 2
+};
+}
+
+namespace weight
+{
+enum type {
+ Unknown = 0,
+ Thin = 1,
+ UltraLight = 2,
+ Light = 3,
+ SemiLight = 4,
+ Normal = 5,
+ Medium = 6,
+ SemiBold = 7,
+ Bold = 8,
+ UltraBold = 9,
+ Black = 10
+};
+}
+
+namespace family
+{
+enum type {
+ Unknown = 0,
+ Decorative = 1,
+ Modern = 2,
+ Roman = 3,
+ Script = 4,
+ Swiss = 5,
+ System = 6
+};
+}
+
+namespace fonttype
+{
+enum type {
+ Unknown = 0,
+ Type1 = 1,
+ TrueType = 2,
+ Builtin = 3
+};
+}
+
+namespace fcstatus
+{
+enum type {
+ istrue,
+ isunset,
+ isfalse
+};
+}
+
+/*
+ * the difference between FastPrintFontInfo and PrintFontInfo
+ * is that the information in FastPrintFontInfo can usually
+ * be gathered without openening either the font file or
+ * an afm metric file. they are gathered from fonts.dir alone.
+ * if only FastPrintFontInfo is gathered and PrintFontInfo
+ * on demand and for less fonts, then performance in startup
+ * increases considerably
+ */
+
+struct FastPrintFontInfo
+{
+ fontID m_nID; // FontID
+ fonttype::type m_eType;
+
+ // font attributes
+ rtl::OUString m_aFamilyName;
+ rtl::OUString m_aStyleName;
+ std::list< rtl::OUString > m_aAliases;
+ family::type m_eFamilyStyle;
+ italic::type m_eItalic;
+ width::type m_eWidth;
+ weight::type m_eWeight;
+ pitch::type m_ePitch;
+ rtl_TextEncoding m_aEncoding;
+ bool m_bSubsettable;
+ bool m_bEmbeddable;
+
+ FastPrintFontInfo() :
+ m_nID( 0 ),
+ m_eType( fonttype::Unknown ),
+ m_eFamilyStyle( family::Unknown ),
+ m_eItalic( italic::Unknown ),
+ m_eWidth( width::Unknown ),
+ m_eWeight( weight::Unknown ),
+ m_ePitch( pitch::Unknown ),
+ m_aEncoding( RTL_TEXTENCODING_DONTKNOW )
+ {}
+};
+
+struct PrintFontInfo : public FastPrintFontInfo
+{
+ int m_nAscend;
+ int m_nDescend;
+ int m_nLeading;
+ int m_nWidth;
+
+ PrintFontInfo() :
+ FastPrintFontInfo(),
+ m_nAscend( 0 ),
+ m_nDescend( 0 ),
+ m_nLeading( 0 ),
+ m_nWidth( 0 )
+ {}
+};
+
+// the values are per thousand of the font size
+// note: width, height contain advances, not bounding box
+struct CharacterMetric
+{
+ short int width, height;
+
+ CharacterMetric() : width( 0 ), height( 0 ) {}
+ bool operator==( const CharacterMetric& rOther ) const
+ { return rOther.width == width && rOther.height == height; }
+ bool operator!=( const CharacterMetric& rOther ) const
+ { return rOther.width != width || rOther.height != height; }
+};
+
+struct KernPair
+{
+ sal_Unicode first, second;
+ short int kern_x, kern_y;
+
+ KernPair() : first( 0 ), second( 0 ), kern_x( 0 ), kern_y( 0 ) {}
+};
+
+class FontCache;
+
+// a class to manage printable fonts
+// aims are type1 and truetype fonts
+
+class FontCache;
+
+class VCL_DLLPUBLIC PrintFontManager
+{
+ struct PrintFont;
+ struct TrueTypeFontFile;
+ struct Type1FontFile;
+ struct BuiltinFont;
+ friend struct PrintFont;
+ friend struct TrueTypeFontFile;
+ friend struct Type1FontFile;
+ friend struct BuiltinFont;
+ friend class FontCache;
+
+ struct PrintFontMetrics
+ {
+ // character metrics are stored by the following keys:
+ // lower two bytes contain a sal_Unicode (a UCS2 character)
+ // upper byte contains: 0 for horizontal metric
+ // 1 for vertical metric
+ // highest byte: 0 for now
+ std::hash_map< int, CharacterMetric > m_aMetrics;
+ // contains the unicode blocks for which metrics were queried
+ // this implies that metrics should be queried in terms of
+ // unicode blocks. here a unicode block is identified
+ // by the upper byte of the UCS2 encoding.
+ // note that the corresponding bit should be set even
+ // if the font does not support a single character of that page
+ // this map shows, which pages were queried already
+ // if (like in AFM metrics) all metrics are queried in
+ // a single pass, then all bits should be set
+ char m_aPages[32];
+
+ bool m_bKernPairsQueried;
+ std::list< KernPair > m_aXKernPairs;
+ std::list< KernPair > m_aYKernPairs;
+ std::hash_map< sal_Unicode, bool > m_bVerticalSubstitutions;
+
+ PrintFontMetrics() : m_bKernPairsQueried( false ) {}
+
+ bool isEmpty() const { return m_aMetrics.empty(); }
+ };
+
+ struct PrintFont
+ {
+ fonttype::type m_eType;
+
+ // font attributes
+ int m_nFamilyName; // atom
+ std::list< int > m_aAliases;
+ int m_nPSName; // atom
+ rtl::OUString m_aStyleName;
+ italic::type m_eItalic;
+ width::type m_eWidth;
+ weight::type m_eWeight;
+ pitch::type m_ePitch;
+ rtl_TextEncoding m_aEncoding;
+ bool m_bFontEncodingOnly; // set if font should be only accessed by builtin encoding
+ CharacterMetric m_aGlobalMetricX;
+ CharacterMetric m_aGlobalMetricY;
+ PrintFontMetrics* m_pMetrics;
+ int m_nAscend;
+ int m_nDescend;
+ int m_nLeading;
+ int m_nXMin; // font bounding box
+ int m_nYMin;
+ int m_nXMax;
+ int m_nYMax;
+ bool m_bHaveVerticalSubstitutedGlyphs;
+ bool m_bUserOverride;
+
+ std::map< sal_Unicode, sal_Int32 > m_aEncodingVector;
+ std::map< sal_Unicode, rtl::OString > m_aNonEncoded;
+
+ PrintFont( fonttype::type eType );
+ virtual ~PrintFont();
+ virtual bool queryMetricPage( int nPage, utl::MultiAtomProvider* pProvider ) = 0;
+
+ bool readAfmMetrics( const rtl::OString& rFileName, utl::MultiAtomProvider* pProvider, bool bFillEncodingvector, bool bOnlyGlobalAttributes );
+ };
+
+ struct Type1FontFile : public PrintFont
+ {
+ int m_nDirectory; // atom containing system dependent path
+ rtl::OString m_aFontFile; // relative to directory
+ rtl::OString m_aMetricFile; // dito
+ rtl::OString m_aXLFD; // mainly for administration, contains the XLFD from fonts.dir
+
+ /* note: m_aFontFile and Metric file are not atoms
+ because they should be fairly unique */
+
+ Type1FontFile() : PrintFont( fonttype::Type1 ), m_nDirectory( 0 ) {}
+ virtual ~Type1FontFile();
+ virtual bool queryMetricPage( int nPage, utl::MultiAtomProvider* pProvider );
+ };
+
+ struct TrueTypeFontFile : public PrintFont
+ {
+ int m_nDirectory; // atom containing system dependent path
+ rtl::OString m_aFontFile; // relative to directory
+ rtl::OString m_aXLFD; // mainly for administration, contains the XLFD from fonts.dir
+ int m_nCollectionEntry; // -1 for regular fonts, 0 to ... for fonts stemming from collections
+ unsigned int m_nTypeFlags; // copyright bits and PS-OpenType flag
+
+ TrueTypeFontFile();
+ virtual ~TrueTypeFontFile();
+ virtual bool queryMetricPage( int nPage, utl::MultiAtomProvider* pProvider );
+ };
+
+ struct BuiltinFont : public PrintFont
+ {
+ int m_nDirectory; // atom containing system dependent path
+ rtl::OString m_aMetricFile;
+
+ BuiltinFont() : PrintFont( fonttype::Builtin ) {}
+ virtual ~BuiltinFont();
+ virtual bool queryMetricPage( int nPage, utl::MultiAtomProvider* pProvider );
+ };
+
+ struct XLFDEntry
+ {
+ static const int MaskFoundry = 1;
+ static const int MaskFamily = 2;
+ static const int MaskAddStyle = 4;
+ static const int MaskItalic = 8;
+ static const int MaskWeight = 16;
+ static const int MaskWidth = 32;
+ static const int MaskPitch = 64;
+ static const int MaskEncoding = 128;
+
+ int nMask; // contains a bit set for every valid member
+
+ rtl::OString aFoundry;
+ rtl::OString aFamily;
+ rtl::OString aAddStyle;
+ italic::type eItalic;
+ weight::type eWeight;
+ width::type eWidth;
+ pitch::type ePitch;
+ rtl_TextEncoding aEncoding;
+
+ XLFDEntry() { nMask = 0; }
+
+ bool operator<(const XLFDEntry& rRight) const;
+ bool operator==(const XLFDEntry& rRight) const;
+ };
+
+ static rtl::OString s_aEmptyOString;
+
+ fontID m_nNextFontID;
+ std::hash_map< fontID, PrintFont* > m_aFonts;
+ std::hash_map< int, family::type > m_aFamilyTypes;
+ std::list< rtl::OUString > m_aPrinterDrivers;
+ std::list< rtl::OString > m_aFontDirectories;
+ std::list< int > m_aPrivateFontDirectories;
+ std::map< struct XLFDEntry, std::list< struct XLFDEntry > >
+ m_aXLFD_Aliases;
+ utl::MultiAtomProvider* m_pAtoms;
+ // for speeding up findFontFileID
+ std::hash_map< rtl::OString, std::set< fontID >, rtl::OStringHash >
+ m_aFontFileToFontID;
+
+ std::hash_map< rtl::OString, int, rtl::OStringHash >
+ m_aDirToAtom;
+ std::hash_map< int, rtl::OString > m_aAtomToDir;
+ int m_nNextDirAtom;
+
+ std::hash_multimap< rtl::OString, sal_Unicode, rtl::OStringHash >
+ m_aAdobenameToUnicode;
+ std::hash_multimap< sal_Unicode, rtl::OString >
+ m_aUnicodeToAdobename;
+ std::hash_multimap< sal_Unicode, sal_uInt8 > m_aUnicodeToAdobecode;
+ std::hash_multimap< sal_uInt8, sal_Unicode > m_aAdobecodeToUnicode;
+
+ mutable FontCache* m_pFontCache;
+ bool m_bFontconfigSuccess;
+
+ mutable std::vector< fontID > m_aOverrideFonts;
+
+ rtl::OString getAfmFile( PrintFont* pFont ) const;
+ rtl::OString getFontFile( PrintFont* pFont ) const;
+
+ void getFontAttributesFromXLFD( PrintFont* pFont, const std::list< rtl::OString >& rXLFDs ) const;
+
+ bool analyzeFontFile( int nDirID, const rtl::OString& rFileName, const std::list< rtl::OString >& rXLFDs, std::list< PrintFont* >& rNewFonts ) const;
+ rtl::OUString convertTrueTypeName( void* pNameRecord ) const; // actually a NameRecord* formt font subsetting code
+ void analyzeTrueTypeFamilyName( void* pTTFont, std::list< rtl::OUString >& rnames ) const; // actually a TrueTypeFont* from font subsetting code
+ bool analyzeTrueTypeFile( PrintFont* pFont ) const;
+ // finds the FIRST id for this font file; there may be more
+ // for TrueType collections
+ fontID findFontFileID( int nDirID, const rtl::OString& rFile ) const;
+ fontID findFontBuiltinID( int nPSNameAtom ) const;
+
+ family::type matchFamilyName( const rtl::OUString& rFamily ) const;
+
+ PrintFont* getFont( fontID nID ) const
+ {
+ std::hash_map< fontID, PrintFont* >::const_iterator it;
+ it = m_aFonts.find( nID );
+ return it == m_aFonts.end() ? NULL : it->second;
+ }
+ rtl::OString getXLFD( PrintFont* pFont ) const;
+ void fillPrintFontInfo( PrintFont* pFont, FastPrintFontInfo& rInfo ) const;
+ void fillPrintFontInfo( PrintFont* pFont, PrintFontInfo& rInfo ) const;
+
+ const rtl::OString& getDirectory( int nAtom ) const;
+ int getDirectoryAtom( const rtl::OString& rDirectory, bool bCreate = false );
+
+ /* try to initialize fonts from libfontconfig
+
+ called from <code>initialize()</code>
+
+ @returns
+ true if at least one font was added by libfontconfig
+ false else (e.g. no libfontconfig found)
+ */
+ bool initFontconfig();
+ int countFontconfigFonts( std::hash_map<rtl::OString, int, rtl::OStringHash>& o_rVisitedPaths );
+ /* deinitialize fontconfig
+ */
+ void deinitFontconfig();
+
+ /* register an application specific font directory for libfontconfig
+
+ since fontconfig is asked for font substitutes before OOo will check for font availability
+ and fontconfig will happily substitute fonts it doesn't know (e.g. "Arial Narrow" -> "DejaVu Sans Book"!)
+ it becomes necessary to tell the library about all the hidden font treasures
+
+ @returns
+ true if libfontconfig accepted the directory
+ false else (e.g. no libfontconfig found)
+ */
+ bool addFontconfigDir(const rtl::OString& rDirectory);
+
+ static bool parseXLFD( const rtl::OString& rXLFD, XLFDEntry& rEntry );
+ void parseXLFD_appendAliases( const std::list< rtl::OString >& rXLFDs, std::list< XLFDEntry >& rEntries ) const;
+ void initFontsAlias();
+
+ bool readOverrideMetrics();
+
+ PrintFontManager();
+ ~PrintFontManager();
+public:
+ static PrintFontManager& get(); // one instance only
+
+ int addFontFile( const rtl::OString& rFileName, int nFaceNum );
+
+ void initialize();
+
+ // returns the number of managed fonts
+ int getFontCount() const { return m_aFonts.size(); }
+
+ // caution: the getFontList* methods can change the font list on demand
+ // depending on the pParser argument. That is getFontCount() may
+ // return a larger value after getFontList()
+
+ // returns the ids of all managed fonts. on pParser != NULL
+ // all fonttype::Builtin type fonts are not listed
+ // which do not occur in the PPD of pParser
+ void getFontList( std::list< fontID >& rFontIDs, const PPDParser* pParser = NULL, bool bUseOverrideMetrics = false );
+ // get the font list and detailed font info. see getFontList for pParser
+ void getFontListWithInfo( std::list< PrintFontInfo >& rFonts, const PPDParser* pParser = NULL, bool bUseOverrideMetrics = false );
+ // get the font list and fast font info. see getFontList for pParser
+ void getFontListWithFastInfo( std::list< FastPrintFontInfo >& rFonts, const PPDParser* pParser = NULL, bool bUseOverrideMetrics = false );
+
+ // get font info for a specific font
+ bool getFontInfo( fontID nFontID, PrintFontInfo& rInfo ) const;
+ // get fast font info for a specific font
+ bool getFontFastInfo( fontID nFontID, FastPrintFontInfo& rInfo ) const;
+
+ // routines to get font info in small pieces
+
+ // get a specific fonts family name
+ const rtl::OUString& getFontFamily( fontID nFontID ) const;
+ // get a specific fonts PSName name
+ const rtl::OUString& getPSName( fontID nFontID ) const;
+
+ // get a specific fonts style family
+ family::type getFontFamilyType( fontID nFontID ) const;
+
+ // get a specific fonts family name aliases
+ void getFontFamilyAliases( fontID nFontID ) const;
+
+ // get a specific fonts type
+ fonttype::type getFontType( fontID nFontID ) const
+ {
+ PrintFont* pFont = getFont( nFontID );
+ return pFont ? pFont->m_eType : fonttype::Unknown;
+ }
+
+ // get a specific fonts italic type
+ italic::type getFontItalic( fontID nFontID ) const
+ {
+ PrintFont* pFont = getFont( nFontID );
+ return pFont ? pFont->m_eItalic : italic::Unknown;
+ }
+
+ // get a specific fonts width type
+ width::type getFontWidth( fontID nFontID ) const
+ {
+ PrintFont* pFont = getFont( nFontID );
+ return pFont ? pFont->m_eWidth : width::Unknown;
+ }
+
+ // get a specific fonts weight type
+ weight::type getFontWeight( fontID nFontID ) const
+ {
+ PrintFont* pFont = getFont( nFontID );
+ return pFont ? pFont->m_eWeight : weight::Unknown;
+ }
+
+ // get a specific fonts pitch type
+ pitch::type getFontPitch( fontID nFontID ) const
+ {
+ PrintFont* pFont = getFont( nFontID );
+ return pFont ? pFont->m_ePitch : pitch::Unknown;
+ }
+
+ // get a specific fonts encoding
+ rtl_TextEncoding getFontEncoding( fontID nFontID ) const
+ {
+ PrintFont* pFont = getFont( nFontID );
+ return pFont ? pFont->m_aEncoding : RTL_TEXTENCODING_DONTKNOW;
+ }
+
+ // should i only use font's builtin encoding ?
+ bool getUseOnlyFontEncoding( fontID nFontID ) const
+ {
+ PrintFont* pFont = getFont( nFontID );
+ return pFont ? pFont->m_bFontEncodingOnly : false;
+ }
+
+ // get a specific fonts system dependent filename
+ rtl::OString getFontFileSysPath( fontID nFontID ) const
+ {
+ return getFontFile( getFont( nFontID ) );
+ }
+
+ // get the ttc face number
+ int getFontFaceNumber( fontID nFontID ) const;
+
+ // get a specific fonts global metrics
+ const CharacterMetric& getGlobalFontMetric( fontID nFontID, bool bHorizontal ) const;
+
+ // get a specific fonts ascend
+ int getFontAscend( fontID nFontID ) const;
+
+ // get a specific fonts descent
+ int getFontDescend( fontID nFontID ) const;
+
+ // get a specific fonts leading
+ int getFontLeading( fontID nFontID ) const;
+
+ // get a fonts glyph bounding box
+ bool getFontBoundingBox( fontID nFont, int& xMin, int& yMin, int& xMax, int& yMax );
+
+ // info whether there are vertical substitutions
+ bool hasVerticalSubstitutions( fontID nFontID ) const;
+
+ // info whether an array of glyphs has vertical substitutions
+ void hasVerticalSubstitutions( fontID nFontID, const sal_Unicode* pCharacters,
+ int nCharacters, bool* pHasSubst ) const;
+
+ // get the XLFD for a font that originated from the X fontpath
+ // note: this may not be the original line that was in the fonts.dir
+ // returns a string for every font, but only TrueType and Type1
+ // fonts originated from the X font path, so check for the font type
+ rtl::OUString getFontXLFD( fontID nFontID ) const;
+
+ // get a specific fonts metrics
+
+ // get metrics for a sal_Unicode range
+ // the user is responsible to allocate pArray large enough
+ bool getMetrics( fontID nFontID, sal_Unicode minCharacter, sal_Unicode maxCharacter, CharacterMetric* pArray, bool bVertical = false ) const;
+ // get metrics for an array of sal_Unicode characters
+ // the user is responsible to allocate pArray large enough
+ bool getMetrics( fontID nFontID, const sal_Unicode* pString, int nLen, CharacterMetric* pArray, bool bVertical = false ) const;
+
+ // get encoding vector of font, currently only for Type1 and Builtin fonts
+ // returns NULL if encoding vector is empty or font is neither type1 or
+ // builtin; if ppNonEncoded is set and non encoded type1 glyphs exist
+ // then *ppNonEncoded is set to the mapping for nonencoded glyphs.
+ // the encoding vector contains -1 for non encoded glyphs
+ const std::map< sal_Unicode, sal_Int32 >* getEncodingMap( fontID nFontID, const std::map< sal_Unicode, rtl::OString >** ppNonEncoded ) const;
+
+ // to get font substitution transparently use the
+ // getKernPairs method of PrinterGfx
+ const std::list< KernPair >& getKernPairs( fontID nFontID, bool bVertical = false ) const;
+
+ // evaluates copyright flags for TrueType fonts
+ // type1 fonts do not have such a feature, so return for them is true
+ // returns true for builtin fonts (surprise!)
+ bool isFontDownloadingAllowed( fontID nFont ) const;
+
+ // helper for type 1 fonts
+ std::list< rtl::OString > getAdobeNameFromUnicode( sal_Unicode aChar ) const;
+
+ std::pair< std::hash_multimap< sal_Unicode, sal_uInt8 >::const_iterator,
+ std::hash_multimap< sal_Unicode, sal_uInt8 >::const_iterator >
+ getAdobeCodeFromUnicode( sal_Unicode aChar ) const
+ {
+ return m_aUnicodeToAdobecode.equal_range( aChar );
+ }
+ std::list< sal_Unicode > getUnicodeFromAdobeName( const rtl::OString& rName ) const;
+ std::pair< std::hash_multimap< sal_uInt8, sal_Unicode >::const_iterator,
+ std::hash_multimap< sal_uInt8, sal_Unicode >::const_iterator >
+ getUnicodeFromAdobeCode( sal_uInt8 aChar ) const
+ {
+ return m_aAdobecodeToUnicode.equal_range( aChar );
+ }
+
+ // creates a new font subset of an existing TrueType font
+ // returns true in case of success, else false
+ // nFont: the font to be subsetted
+ // rOutFile: the file to put the new subset into;
+ // must be a valid osl file URL
+ // pGlyphIDs: input array of glyph ids for new font
+ // pNewEncoding: the corresponding encoding in the new font
+ // pWidths: output array of widths of requested glyphs
+ // nGlyphs: number of glyphs in arrays
+ // pCapHeight:: capital height of the produced font
+ // pXMin, pYMin, pXMax, pYMax: outgoing font bounding box
+ // TODO: callers of this method should use its FontSubsetInfo counterpart directly
+ bool createFontSubset( FontSubsetInfo&,
+ fontID nFont,
+ const rtl::OUString& rOutFile,
+ sal_Int32* pGlyphIDs,
+ sal_uInt8* pNewEncoding,
+ sal_Int32* pWidths,
+ int nGlyphs,
+ bool bVertical = false
+ );
+ void getGlyphWidths( fontID nFont,
+ bool bVertical,
+ std::vector< sal_Int32 >& rWidths,
+ std::map< sal_Unicode, sal_uInt32 >& rUnicodeEnc );
+
+
+ // font administration functions
+
+ // for importFonts to provide the user feedback
+ class ImportFontCallback
+ {
+ public:
+ enum FailCondition { NoWritableDirectory, NoAfmMetric, AfmCopyFailed, FontCopyFailed };
+ virtual void importFontsFailed( FailCondition eReason ) = 0;
+ virtual void progress( const rtl::OUString& rFile ) = 0;
+ virtual bool queryOverwriteFile( const rtl::OUString& rFile ) = 0;
+ virtual void importFontFailed( const rtl::OUString& rFile, FailCondition ) = 0;
+ virtual bool isCanceled() = 0;
+ };
+
+ // checks wether font import would fail due to no writeable directory
+ bool checkImportPossible() const;
+ // expects system paths not UNC paths
+ // returns the number of fonts successfully imported
+ int importFonts( const std::list< rtl::OString >& rFiles, bool bLinkOnly = false, ImportFontCallback* pCallback = NULL );
+
+ // check wether changeFontProperties would fail due to not writable fonts.dir
+ bool checkChangeFontPropertiesPossible( fontID nFont ) const;
+ // change fonts.dir entry for font
+ bool changeFontProperties( fontID nFont, const rtl::OUString& rXLFD );
+
+ // get properties of a not imported font file
+ bool getImportableFontProperties( const rtl::OString& rFile, std::list< FastPrintFontInfo >& rFontProps );
+
+ // get fonts that come from the same font file
+ bool getFileDuplicates( fontID nFont, std::list< fontID >& rFonts ) const;
+ // remove font files
+ bool removeFonts( const std::list< fontID >& rFonts );
+
+ bool isPrivateFontFile( fontID ) const;
+
+ // returns false if there were not any
+ bool getAlternativeFamilyNames( fontID nFont, std::list< rtl::OUString >& rNames ) const;
+
+ /* system dependendent font matching
+
+ <p>
+ <code>matchFont</code> matches a pattern of font characteristics
+ and returns the closest match if possibe. If a match was found
+ the <code>FastPrintFontInfo</code> passed in as parameter
+ will be update to the found matching font.
+ </p>
+ <p>
+ implementation note: currently the function is only implemented
+ for fontconfig.
+ </p>
+
+ @param rInfo
+ out of the FastPrintFontInfo structure the following
+ fields will be used for the match:
+ <ul>
+ <li>family name</li>
+ <li>italic</li>
+ <li>width</li>
+ <li>weight</li>
+ <li>pitch</li>
+ </ul>
+
+ @param rLocale
+ if <code>rLocal</code> contains non empty strings the corresponding
+ locale will be used for font matching also; e.g. "Sans" can result
+ in different fonts in e.g. english and japanese
+
+ @returns
+ true if a match was found
+ false else
+ */
+ bool matchFont( FastPrintFontInfo& rInfo, const com::sun::star::lang::Locale& rLocale );
+ bool getFontOptions( const FastPrintFontInfo&, int nSize, void (*subcallback)(void*), ImplFontOptions& rResult ) const;
+
+ rtl::OUString Substitute( const rtl::OUString& rFontName, rtl::OUString& rMissingCodes,
+ const rtl::OString& rLangAttrib, italic::type& rItalic, weight::type& rWeight,
+ width::type& rWidth, pitch::type& rPitch) const;
+ bool hasFontconfig() const { return m_bFontconfigSuccess; }
+
+ int FreeTypeCharIndex( void *pFace, sal_uInt32 aChar );
+};
+
+} // namespace
+
+#endif // _PSPRINT_FONTMANAGER_HXX_
diff --git a/vcl/inc/vcl/fontsubset.hxx b/vcl/inc/vcl/fontsubset.hxx
new file mode 100644
index 000000000000..a34212128741
--- /dev/null
+++ b/vcl/inc/vcl/fontsubset.hxx
@@ -0,0 +1,97 @@
+/*************************************************************************
+ *
+ * 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_FONTSUBSET_HXX
+#define _SV_FONTSUBSET_HXX
+
+#include <tools/gen.hxx>
+#include <tools/string.hxx>
+#include <cstdio>
+
+namespace vcl { struct _TrueTypeFont; } // SFT's idea of a TTF font
+
+class FontSubsetInfo
+{
+public:
+ explicit FontSubsetInfo( void );
+ virtual ~FontSubsetInfo( void );
+
+ enum FontType {
+ NO_FONT = 0,
+ SFNT_TTF = 1<<1, // SFNT container with TrueType glyphs
+ SFNT_CFF = 1<<2, // SFNT container with CFF-container
+ TYPE1_PFA = 1<<3, // PSType1 Postscript Font Ascii
+ TYPE1_PFB = 1<<4, // PSType1 Postscript Font Binary
+ CFF_FONT = 1<<5, // CFF-container with PSType2 glyphs
+ TYPE3_FONT = 1<<6, // PSType3 Postscript font
+ TYPE42_FONT = 1<<7, // PSType42 wrapper for an SFNT_TTF
+ ANY_SFNT = SFNT_TTF | SFNT_CFF,
+ ANY_TYPE1 = TYPE1_PFA | TYPE1_PFB,
+ ANY_FONT = 0xFF
+ };
+
+ bool LoadFont( FontType eInFontType,
+ const unsigned char* pFontBytes, int nByteLength );
+ bool LoadFont( vcl::_TrueTypeFont* pSftTrueTypeFont );
+
+ bool CreateFontSubset( int nOutFontTypeMask,
+ FILE* pOutFile, const char* pOutFontName,
+ const long* pReqGlyphIds, const sal_uInt8* pEncodedIds,
+ int nReqGlyphCount, sal_Int32* pOutGlyphWidths = NULL );
+
+public: // TODO: make subsetter results private and provide accessor methods instead
+ // subsetter-provided subset details needed by e.g. Postscript or PDF
+ String m_aPSName;
+ int m_nAscent; // all metrics in PS font units
+ int m_nDescent;
+ int m_nCapHeight;
+ Rectangle m_aFontBBox;
+ FontType m_nFontType; // font-type of subset result
+
+private:
+ // input-font-specific details
+ unsigned const char* mpInFontBytes;
+ int mnInByteLength;
+ FontType meInFontType; // allowed mask of input font-types
+ vcl::_TrueTypeFont* mpSftTTFont;
+
+ // subset-request details
+ int mnReqFontTypeMask; // allowed subset-target font types
+ FILE* mpOutFile;
+ const char* mpReqFontName;
+ const long* mpReqGlyphIds;
+ const sal_uInt8* mpReqEncodedIds;
+ int mnReqGlyphCount;
+
+protected:
+ bool CreateFontSubsetFromCff( sal_Int32* pOutGlyphWidths = NULL );
+ bool CreateFontSubsetFromSfnt( sal_Int32* pOutGlyphWidths = NULL );
+ bool CreateFontSubsetFromType1( sal_Int32* pOutGlyphWidths = NULL );
+};
+
+#endif // _SV_FONTSUBSET_HXX
+
diff --git a/vcl/inc/vcl/gdimtf.hxx b/vcl/inc/vcl/gdimtf.hxx
new file mode 100644
index 000000000000..06f7a0d14a2e
--- /dev/null
+++ b/vcl/inc/vcl/gdimtf.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_GDIMTF_HXX
+#define _SV_GDIMTF_HXX
+
+#include <vcl/dllapi.h>
+#include <tools/gen.hxx>
+#include <tools/list.hxx>
+#include <tools/link.hxx>
+#include <tools/string.hxx>
+#include <vcl/mapmod.hxx>
+
+class OutputDevice;
+class ImpLabelList;
+class MetaAction;
+class SvStream;
+class Color;
+class BitmapEx;
+class Polygon;
+class PolyPolygon;
+class Gradient;
+
+// ---------------------
+// - GDIMetaFile-Types -
+// ---------------------
+
+#define GDI_METAFILE_END ((ULONG)0xFFFFFFFF)
+#define GDI_METAFILE_LABEL_NOTFOUND ((ULONG)0xFFFFFFFF)
+
+#ifndef METAFILE_END
+#define METAFILE_END GDI_METAFILE_END
+#endif
+
+#ifndef METAFILE_LABEL_NOTFOUND
+#define METAFILE_LABEL_NOTFOUND GDI_METAFILE_LABEL_NOTFOUND
+#endif
+
+// -----------
+// - Defines -
+// -----------
+
+#define MTF_MIRROR_NONE 0x00000000UL
+#define MTF_MIRROR_HORZ 0x00000001UL
+#define MTF_MIRROR_VERT 0x00000002UL
+
+// ---------
+// - Enums -
+// ---------
+
+enum MtfConversion
+{
+ MTF_CONVERSION_NONE = 0,
+ MTF_CONVERSION_1BIT_THRESHOLD = 1,
+ MTF_CONVERSION_8BIT_GREYS = 2
+};
+
+// -----------------------------
+// - Color conversion routines -
+// -----------------------------
+
+//#if 0 // _SOLAR__PRIVATE
+
+typedef Color (*ColorExchangeFnc)( const Color& rColor, const void* pColParam );
+typedef BitmapEx (*BmpExchangeFnc)( const BitmapEx& rBmpEx, const void* pBmpParam );
+
+//#endif // __PRIVATE
+
+// ---------------
+// - GDIMetaFile -
+// ---------------
+
+class VCL_DLLPUBLIC GDIMetaFile : protected List
+{
+private:
+
+ MapMode aPrefMapMode;
+ Size aPrefSize;
+ Link aHookHdlLink;
+ GDIMetaFile* pPrev;
+ GDIMetaFile* pNext;
+ OutputDevice* pOutDev;
+ ImpLabelList* pLabelList;
+ BOOL bPause;
+ BOOL bRecord;
+
+//#if 0 // _SOLAR__PRIVATE
+
+ SAL_DLLPRIVATE static Color ImplColAdjustFnc( const Color& rColor, const void* pColParam );
+ SAL_DLLPRIVATE static BitmapEx ImplBmpAdjustFnc( const BitmapEx& rBmpEx, const void* pBmpParam );
+
+ SAL_DLLPRIVATE static Color ImplColConvertFnc( const Color& rColor, const void* pColParam );
+ SAL_DLLPRIVATE static BitmapEx ImplBmpConvertFnc( const BitmapEx& rBmpEx, const void* pBmpParam );
+
+ SAL_DLLPRIVATE static Color ImplColMonoFnc( const Color& rColor, const void* pColParam );
+ SAL_DLLPRIVATE static BitmapEx ImplBmpMonoFnc( const BitmapEx& rBmpEx, const void* pBmpParam );
+
+ SAL_DLLPRIVATE static Color ImplColReplaceFnc( const Color& rColor, const void* pColParam );
+ SAL_DLLPRIVATE static BitmapEx ImplBmpReplaceFnc( const BitmapEx& rBmpEx, const void* pBmpParam );
+
+ SAL_DLLPRIVATE void ImplExchangeColors( ColorExchangeFnc pFncCol, const void* pColParam,
+ BmpExchangeFnc pFncBmp, const void* pBmpParam );
+
+ SAL_DLLPRIVATE Point ImplGetRotatedPoint( const Point& rPt, const Point& rRotatePt,
+ const Size& rOffset, double fSin, double fCos );
+ SAL_DLLPRIVATE Polygon ImplGetRotatedPolygon( const Polygon& rPoly, const Point& rRotatePt,
+ const Size& rOffset, double fSin, double fCos );
+ SAL_DLLPRIVATE PolyPolygon ImplGetRotatedPolyPolygon( const PolyPolygon& rPoly, const Point& rRotatePt,
+ const Size& rOffset, double fSin, double fCos );
+ SAL_DLLPRIVATE void ImplAddGradientEx( GDIMetaFile& rMtf,
+ const OutputDevice& rMapDev,
+ const PolyPolygon& rPolyPoly,
+ const Gradient& rGrad );
+
+//#endif // __PRIVATE
+
+protected:
+
+ virtual void Linker( OutputDevice* pOut, BOOL bLink );
+ virtual long Hook();
+
+public:
+ GDIMetaFile();
+ GDIMetaFile( const GDIMetaFile& rMtf );
+ virtual ~GDIMetaFile();
+
+ using List::operator==;
+ using List::operator!=;
+ GDIMetaFile& operator=( const GDIMetaFile& rMtf );
+ BOOL operator==( const GDIMetaFile& rMtf ) const;
+ BOOL operator!=( const GDIMetaFile& rMtf ) const { return !( *this == rMtf ); }
+
+ void Clear();
+ sal_Bool IsEqual( const GDIMetaFile& rMtf ) const;
+ BOOL Mirror( ULONG nMirrorFlags );
+ void Move( long nX, long nY );
+ void Scale( double fScaleX, double fScaleY );
+ void Scale( const Fraction& rScaleX, const Fraction& rScaleY );
+ void Rotate( long nAngle10 );
+ void Clip( const Rectangle& );
+ /* get the bound rect of the contained actions
+ * caveats:
+ * - clip actions will limit the contained actions,
+ * but the current clipregion of the passed OutputDevice will not
+ * - coordinates of actions will be transformed to preferred mapmode
+ * - the returned rectangle is relative to the preferred mapmode of the metafile
+ */
+ Rectangle GetBoundRect( OutputDevice& i_rReference );
+
+ void Adjust( short nLuminancePercent = 0, short nContrastPercent = 0,
+ short nChannelRPercent = 0, short nChannelGPercent = 0,
+ short nChannelBPercent = 0, double fGamma = 1.0, BOOL bInvert = FALSE );
+ void Convert( MtfConversion eConversion );
+ void ReplaceColors( const Color& rSearchColor, const Color& rReplaceColor, ULONG nTol = 0 );
+ void ReplaceColors( const Color* pSearchColors, const Color* rReplaceColors,
+ ULONG nColorCount, ULONG* pTols = NULL );
+
+ GDIMetaFile GetMonochromeMtf( const Color& rCol ) const;
+
+ void Record( OutputDevice* pOutDev );
+ BOOL IsRecord() const { return bRecord; }
+
+ void Play( GDIMetaFile& rMtf, ULONG nPos = GDI_METAFILE_END );
+ void Play( OutputDevice* pOutDev, ULONG nPos = GDI_METAFILE_END );
+ void Play( OutputDevice* pOutDev, const Point& rPos,
+ const Size& rSize, ULONG nPos = GDI_METAFILE_END );
+
+ void Pause( BOOL bPause );
+ BOOL IsPause() const { return bPause; }
+
+ void Stop();
+
+ void WindStart();
+ void WindEnd();
+ void Wind( ULONG nAction );
+ void WindPrev();
+ void WindNext();
+
+ ULONG GetActionCount() const { return Count(); }
+ void AddAction( MetaAction* pAction );
+ void AddAction( MetaAction* pAction, ULONG nPos );
+ void RemoveAction( ULONG nPos );
+ MetaAction* CopyAction( ULONG nPos ) const;
+ MetaAction* GetCurAction() const { return (MetaAction*) GetCurObject(); }
+ MetaAction* GetAction( ULONG nAction ) const { return (MetaAction*) GetObject( nAction ); }
+ MetaAction* FirstAction() { return (MetaAction*) First(); }
+ MetaAction* NextAction() { return (MetaAction*) Next(); }
+ MetaAction* ReplaceAction( MetaAction* pAction, ULONG nAction ) { return (MetaAction*) Replace( pAction, nAction ); }
+
+ ULONG GetActionPos( const String& rLabel );
+ BOOL InsertLabel( const String& rLabel, ULONG nActionPos );
+ void RemoveLabel( const String& rLabel );
+ void RenameLabel( const String& rLabel, const String& rNewLabel );
+ ULONG GetLabelCount() const;
+ String GetLabel( ULONG nLabel );
+
+ BOOL SaveStatus();
+
+ const Size& GetPrefSize() const { return aPrefSize; }
+ void SetPrefSize( const Size& rSize ) { aPrefSize = rSize; }
+
+ const MapMode& GetPrefMapMode() const { return aPrefMapMode; }
+ void SetPrefMapMode( const MapMode& rMapMode ) { aPrefMapMode = rMapMode; }
+
+ void SetHookHdl( const Link& rLink ) { aHookHdlLink = rLink; }
+ const Link& GetHookHdl() const { return aHookHdlLink; }
+
+ ULONG GetChecksum() const;
+ ULONG GetSizeBytes() const;
+
+ // Methoden zum Lesen und Schreiben des neuen Formats;
+ // die Read-Methode kann auch das alte Format lesen
+ SvStream& Read( SvStream& rIStm );
+ SvStream& Write( SvStream& rOStm );
+
+ // Stream-Operatoren schreiben das alte Format (noch)
+ // und lesen sowohl das alte wie auch das neue Format
+ friend VCL_DLLPUBLIC SvStream& operator>>( SvStream& rIStm, GDIMetaFile& rGDIMetaFile );
+ friend VCL_DLLPUBLIC SvStream& operator<<( SvStream& rOStm, const GDIMetaFile& rGDIMetaFile );
+
+ BOOL CreateThumbnail( sal_uInt32 nMaximumExtent, BitmapEx& rBmpEx, const BitmapEx* pOverlay = NULL, const Rectangle* pOverlayRect = NULL ) const;
+};
+
+#endif // _SV_GDIMTF_HXX
+
diff --git a/vcl/inc/vcl/gfxlink.hxx b/vcl/inc/vcl/gfxlink.hxx
new file mode 100644
index 000000000000..3b3938ec848b
--- /dev/null
+++ b/vcl/inc/vcl/gfxlink.hxx
@@ -0,0 +1,188 @@
+/*************************************************************************
+ *
+ * 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_GFXLINK_HXX
+#define _SV_GFXLINK_HXX
+
+#include <vcl/dllapi.h>
+#include <vcl/sv.h>
+#include <vcl/mapmod.hxx>
+#include <tools/stream.hxx>
+
+//#if 0 // _SOLAR__PRIVATE
+#include <tools/urlobj.hxx>
+
+// -------------
+// - ImpBuffer -
+// -------------
+
+struct ImpBuffer
+{
+ ULONG mnRefCount;
+ BYTE* mpBuffer;
+
+ ImpBuffer( ULONG nSize )
+ {
+ mnRefCount = 1UL;
+ mpBuffer = nSize ? new BYTE[ nSize ] : NULL;
+ }
+
+ ImpBuffer( BYTE* pBuf ) { mnRefCount = 1UL; mpBuffer = pBuf; }
+
+ ~ImpBuffer() { delete[] mpBuffer; }
+};
+
+// -----------
+// - ImpSwap -
+// -----------
+
+struct ImpSwap
+{
+ INetURLObject maURL;
+ ULONG mnDataSize;
+ ULONG mnRefCount;
+
+ ImpSwap( BYTE* pData, ULONG nDataSize );
+ ~ImpSwap();
+
+ BYTE* GetData() const;
+
+ BOOL IsSwapped() const { return maURL.GetMainURL( INetURLObject::NO_DECODE ).getLength() > 0; }
+
+ void WriteTo( SvStream& rOStm ) const;
+};
+
+// --------------
+// - ImpGfxLink -
+// --------------
+
+struct ImpGfxLink
+{
+ MapMode maPrefMapMode;
+ Size maPrefSize;
+ bool mbPrefMapModeValid;
+ bool mbPrefSizeValid;
+
+ ImpGfxLink() :
+ maPrefMapMode(),
+ maPrefSize(),
+ mbPrefMapModeValid( false ),
+ mbPrefSizeValid( false )
+ {}
+};
+
+//#endif // __PRIVATE
+
+// ---------------
+// - GfxLinkType -
+// ---------------
+
+enum GfxLinkType
+{
+ GFX_LINK_TYPE_NONE = 0,
+ GFX_LINK_TYPE_EPS_BUFFER = 1,
+ GFX_LINK_TYPE_NATIVE_GIF = 2, // Don't forget to update the following defines
+ GFX_LINK_TYPE_NATIVE_JPG = 3, // Don't forget to update the following defines
+ GFX_LINK_TYPE_NATIVE_PNG = 4, // Don't forget to update the following defines
+ GFX_LINK_TYPE_NATIVE_TIF = 5, // Don't forget to update the following defines
+ GFX_LINK_TYPE_NATIVE_WMF = 6, // Don't forget to update the following defines
+ GFX_LINK_TYPE_NATIVE_MET = 7, // Don't forget to update the following defines
+ GFX_LINK_TYPE_NATIVE_PCT = 8, // Don't forget to update the following defines
+ GFX_LINK_TYPE_USER = 0xffff
+};
+
+#define GFX_LINK_FIRST_NATIVE_ID GFX_LINK_TYPE_NATIVE_GIF
+#define GFX_LINK_LAST_NATIVE_ID GFX_LINK_TYPE_NATIVE_PCT
+
+// -----------
+// - GfxLink -
+// -----------
+
+struct ImpBuffer;
+struct ImpSwap;
+struct ImpGfxLink;
+class Graphic;
+
+class VCL_DLLPUBLIC GfxLink
+{
+private:
+
+ GfxLinkType meType;
+ ImpBuffer* mpBuf;
+ ImpSwap* mpSwap;
+ sal_uInt32 mnBufSize;
+ sal_uInt32 mnUserId;
+ ImpGfxLink* mpImpData;
+ ULONG mnExtra2;
+
+ SAL_DLLPRIVATE void ImplCopy( const GfxLink& rGfxLink );
+
+public:
+ GfxLink();
+ GfxLink( const GfxLink& );
+ GfxLink( const String& rPath, GfxLinkType nType );
+ GfxLink( BYTE* pBuf, sal_uInt32 nBufSize, GfxLinkType nType, BOOL bOwns );
+ ~GfxLink();
+
+ GfxLink& operator=( const GfxLink& );
+ sal_Bool IsEqual( const GfxLink& ) const;
+
+ GfxLinkType GetType() const;
+
+ void SetUserId( sal_uInt32 nUserId ) { mnUserId = nUserId; }
+ sal_uInt32 GetUserId() const { return mnUserId; }
+
+ sal_uInt32 GetDataSize() const;
+ void SetData( BYTE* pBuf, sal_uInt32 nSize, GfxLinkType nType, BOOL bOwns );
+ const BYTE* GetData() const;
+
+ const Size& GetPrefSize() const;
+ void SetPrefSize( const Size& rPrefSize );
+ bool IsPrefSizeValid();
+
+ const MapMode& GetPrefMapMode() const;
+ void SetPrefMapMode( const MapMode& rPrefMapMode );
+ bool IsPrefMapModeValid();
+
+ BOOL IsNative() const;
+ BOOL IsUser() const { return( GFX_LINK_TYPE_USER == meType ); }
+
+ BOOL LoadNative( Graphic& rGraphic );
+
+ BOOL ExportNative( SvStream& rOStream ) const;
+
+ void SwapOut();
+ void SwapIn();
+ BOOL IsSwappedOut() const { return( mpSwap != NULL ); }
+
+public:
+
+ friend VCL_DLLPUBLIC SvStream& operator<<( SvStream& rOStream, const GfxLink& rGfxLink );
+ friend VCL_DLLPUBLIC SvStream& operator>>( SvStream& rIStream, GfxLink& rGfxLink );
+};
+
+#endif
diff --git a/vcl/inc/vcl/glyphcache.hxx b/vcl/inc/vcl/glyphcache.hxx
new file mode 100644
index 000000000000..a77c1626dc24
--- /dev/null
+++ b/vcl/inc/vcl/glyphcache.hxx
@@ -0,0 +1,381 @@
+/*************************************************************************
+ *
+ * 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_GLYPHCACHE_HXX
+#define _SV_GLYPHCACHE_HXX
+
+#include <vcl/dllapi.h>
+
+class GlyphCache;
+class GlyphMetric;
+class GlyphData;
+class ServerFont;
+class GlyphCachePeer;
+class ServerFontLayoutEngine;
+class ServerFontLayout;
+class ExtraKernInfo;
+struct ImplKernPairData;
+class ImplFontOptions;
+
+#include <tools/gen.hxx>
+#include <hash_map>
+#include <hash_set>
+
+namespace basegfx { class B2DPolyPolygon; }
+
+class RawBitmap;
+class CmapResult;
+
+#include <vcl/outfont.hxx>
+#include <vcl/impfont.hxx>
+
+class ServerFontLayout;
+#include <vcl/sallayout.hxx>
+
+// =======================================================================
+
+class VCL_DLLPUBLIC GlyphCache
+{
+public:
+ explicit GlyphCache( GlyphCachePeer& );
+ /*virtual*/ ~GlyphCache();
+
+ static GlyphCache& GetInstance();
+ void LoadFonts();
+
+ void ClearFontPath();
+ void AddFontPath( const String& rFontPath );
+ void AddFontFile( const rtl::OString& rNormalizedName,
+ int nFaceNum, sal_IntPtr nFontId, const ImplDevFontAttributes&,
+ const ExtraKernInfo* = NULL );
+ void AnnounceFonts( ImplDevFontList* ) const;
+
+ ServerFont* CacheFont( const ImplFontSelectData& );
+ void UncacheFont( ServerFont& );
+ void InvalidateAllGlyphs();
+
+protected:
+ GlyphCachePeer& mrPeer;
+
+private:
+ friend class ServerFont;
+ // used by ServerFont class only
+ void AddedGlyph( ServerFont&, GlyphData& );
+ void RemovingGlyph( ServerFont&, GlyphData&, int nGlyphIndex );
+ void UsingGlyph( ServerFont&, GlyphData& );
+ void GrowNotify();
+
+private:
+ ULONG CalcByteCount() const;
+ void GarbageCollect();
+
+ // the GlyphCache's FontList matches a font request to a serverfont instance
+ // the FontList key's mpFontData member is reinterpreted as integer font id
+ struct IFSD_Equal{ bool operator()( const ImplFontSelectData&, const ImplFontSelectData& ) const; };
+ struct IFSD_Hash{ size_t operator()( const ImplFontSelectData& ) const; };
+ typedef ::std::hash_map<ImplFontSelectData,ServerFont*,IFSD_Hash,IFSD_Equal > FontList;
+ FontList maFontList;
+ ULONG mnMaxSize; // max overall cache size in bytes
+ mutable ULONG mnBytesUsed;
+ mutable long mnLruIndex;
+ mutable int mnGlyphCount;
+ ServerFont* mpCurrentGCFont;
+
+ class FreetypeManager* mpFtManager;
+};
+
+// =======================================================================
+
+class GlyphMetric
+{
+public:
+ Point GetOffset() const { return maOffset; }
+ Point GetDelta() const { return maDelta; }
+ Size GetSize() const { return maSize; }
+ long GetCharWidth() const { return mnAdvanceWidth; }
+
+protected:
+ friend class GlyphData;
+ void SetOffset( int nX, int nY ) { maOffset = Point( nX, nY); }
+ void SetDelta( int nX, int nY ) { maDelta = Point( nX, nY); }
+ void SetSize( const Size& s ) { maSize = s; }
+ void SetCharWidth( long nW ) { mnAdvanceWidth = nW; }
+
+private:
+ long mnAdvanceWidth;
+ Point maDelta;
+ Point maOffset;
+ Size maSize;
+};
+
+// -----------------------------------------------------------------------
+
+// the glyph specific data needed by a GlyphCachePeer is usually trivial,
+// not attaching it to the corresponding GlyphData would be overkill
+struct ExtGlyphData
+{
+ int meInfo;
+ void* mpData;
+
+ ExtGlyphData() : meInfo(0), mpData(NULL) {}
+};
+
+// -----------------------------------------------------------------------
+
+class GlyphData
+{
+public:
+ const GlyphMetric& GetMetric() const { return maMetric; }
+ Size GetSize() const { return maMetric.GetSize(); }
+
+ void SetSize( const Size& s) { maMetric.SetSize( s ); }
+ void SetOffset( int nX, int nY ) { maMetric.SetOffset( nX, nY ); }
+ void SetDelta( int nX, int nY ) { maMetric.SetDelta( nX, nY ); }
+ void SetCharWidth( long nW ) { maMetric.SetCharWidth( nW ); }
+
+ void SetLruValue( int n ) const { mnLruValue = n; }
+ long GetLruValue() const { return mnLruValue;}
+
+ ExtGlyphData& ExtDataRef() { return maExtData; }
+ const ExtGlyphData& ExtDataRef() const { return maExtData; }
+
+private:
+ GlyphMetric maMetric;
+ ExtGlyphData maExtData;
+
+ // used by GlyphCache for cache LRU algorithm
+ mutable long mnLruValue;
+};
+
+// =======================================================================
+
+class VCL_DLLPUBLIC ServerFont
+{
+public:
+ virtual const ::rtl::OString* GetFontFileName() const { return NULL; }
+ virtual int GetFontFaceNumber() const { return 0; }
+ virtual bool TestFont() const { return true; }
+ virtual void* GetFtFace() const { return 0; }
+ virtual int GetLoadFlags() const { return 0; }
+ virtual void SetFontOptions( const ImplFontOptions&) {}
+ virtual bool NeedsArtificialBold() const { return false; }
+ virtual bool NeedsArtificialItalic() const { return false; }
+
+ const ImplFontSelectData& GetFontSelData() const { return maFontSelData; }
+
+ virtual void FetchFontMetric( ImplFontMetricData&, long& rFactor ) const = 0;
+ virtual ULONG GetKernPairs( ImplKernPairData** ) const { return 0; }
+ virtual int GetGlyphKernValue( int, int ) const { return 0; }
+ virtual bool GetFontCodeRanges( CmapResult& ) const { return false; }
+ Point TransformPoint( const Point& ) const;
+
+ GlyphData& GetGlyphData( int nGlyphIndex );
+ const GlyphMetric& GetGlyphMetric( int nGlyphIndex )
+ { return GetGlyphData( nGlyphIndex ).GetMetric(); }
+
+ virtual int GetGlyphIndex( sal_UCS4 ) const = 0;
+ virtual bool GetGlyphOutline( int nGlyphIndex, ::basegfx::B2DPolyPolygon& ) const = 0;
+ virtual bool GetAntialiasAdvice( void ) const = 0;
+ bool IsGlyphInvisible( int nGlyphIndex );
+ virtual bool GetGlyphBitmap1( int nGlyphIndex, RawBitmap& ) const = 0;
+ virtual bool GetGlyphBitmap8( int nGlyphIndex, RawBitmap& ) const = 0;
+
+ void SetExtended( int nInfo, void* ppVoid );
+ int GetExtInfo() { return mnExtInfo; }
+ void* GetExtPointer() { return mpExtData; }
+
+protected:
+ friend class GlyphCache;
+ friend class ServerFontLayout;
+ explicit ServerFont( const ImplFontSelectData& );
+ virtual ~ServerFont();
+
+ void AddRef() const { ++mnRefCount; }
+ long GetRefCount() const { return mnRefCount; }
+ long Release() const;
+ ULONG GetByteCount() const { return mnBytesUsed; }
+
+ virtual void InitGlyphData( int nGlyphIndex, GlyphData& ) const = 0;
+ virtual void GarbageCollect( long );
+ void ReleaseFromGarbageCollect();
+
+ virtual ServerFontLayoutEngine* GetLayoutEngine() { return NULL; }
+
+private:
+ typedef ::std::hash_map<int,GlyphData> GlyphList;
+ mutable GlyphList maGlyphList;
+
+ const ImplFontSelectData maFontSelData;
+
+ // info for GlyphcachePeer
+ int mnExtInfo;
+ void* mpExtData;
+
+ // used by GlyphCache for cache LRU algorithm
+ mutable long mnRefCount;
+ mutable ULONG mnBytesUsed;
+
+ ServerFont* mpPrevGCFont;
+ ServerFont* mpNextGCFont;
+
+protected:
+ // 16.16 fixed point values used for a rotated font
+ long mnCos;
+ long mnSin;
+private:
+ int mnZWJ;
+ int mnZWNJ;
+ bool mbCollectedZW;
+};
+
+// =======================================================================
+
+// a class for cache entries for physical font instances that are based on serverfonts
+class VCL_DLLPUBLIC ImplServerFontEntry : public ImplFontEntry
+{
+private:
+ ServerFont* mpServerFont;
+ ImplFontOptions maFontOptions;
+ bool mbGotFontOptions;
+ bool mbValidFontOptions;
+
+public:
+ ImplServerFontEntry( ImplFontSelectData& );
+ virtual ~ImplServerFontEntry();
+ void SetServerFont( ServerFont* p) { mpServerFont = p; }
+ void HandleFontOptions();
+};
+
+// =======================================================================
+
+class VCL_DLLPUBLIC ServerFontLayout : public GenericSalLayout
+{
+private:
+ ServerFont& mrServerFont;
+
+ // enforce proper copy semantic
+ SAL_DLLPRIVATE ServerFontLayout( const ServerFontLayout& );
+ SAL_DLLPRIVATE ServerFontLayout& operator=( const ServerFontLayout& );
+
+public:
+ ServerFontLayout( ServerFont& );
+ virtual bool LayoutText( ImplLayoutArgs& );
+ virtual void AdjustLayout( ImplLayoutArgs& );
+ virtual void DrawText( SalGraphics& ) const;
+ ServerFont& GetServerFont() const { return mrServerFont; }
+};
+
+// =======================================================================
+
+class ServerFontLayoutEngine
+{
+public:
+ virtual ~ServerFontLayoutEngine() {}
+ virtual bool operator()( ServerFontLayout&, ImplLayoutArgs& );
+};
+
+// =======================================================================
+
+class GlyphCachePeer
+{
+protected:
+ GlyphCachePeer() : mnBytesUsed(0) {}
+ virtual ~GlyphCachePeer() {}
+
+public:
+ sal_Int32 GetByteCount() const { return mnBytesUsed; }
+ virtual void RemovingFont( ServerFont& ) {}
+ virtual void RemovingGlyph( ServerFont&, GlyphData&, int ) {}
+
+protected:
+ sal_Int32 mnBytesUsed;
+};
+
+// =======================================================================
+
+class VCL_DLLPUBLIC RawBitmap
+{
+public:
+ RawBitmap();
+ ~RawBitmap();
+ bool Rotate( int nAngle );
+
+public:
+ unsigned char* mpBits;
+ ULONG mnAllocated;
+
+ ULONG mnWidth;
+ ULONG mnHeight;
+
+ ULONG mnScanlineSize;
+ ULONG mnBitCount;
+
+ int mnXOffset;
+ int mnYOffset;
+};
+
+// =======================================================================
+
+inline void ServerFont::SetExtended( int nInfo, void* pVoid )
+{
+ mnExtInfo = nInfo;
+ mpExtData = pVoid;
+}
+
+// =======================================================================
+
+// ExtraKernInfo allows an on-demand query of extra kerning info #i29881#
+// The kerning values have to be scaled to match the font size before use
+class VCL_DLLPUBLIC ExtraKernInfo
+{
+public:
+ ExtraKernInfo( sal_IntPtr nFontId );
+ virtual ~ExtraKernInfo() {}
+
+ bool HasKernPairs() const;
+ int GetUnscaledKernPairs( ImplKernPairData** ) const;
+ int GetUnscaledKernValue( sal_Unicode cLeft, sal_Unicode cRight ) const;
+
+protected:
+ mutable bool mbInitialized;
+ virtual void Initialize() const = 0;
+
+protected:
+ sal_IntPtr mnFontId;
+
+ // container to map a unicode pair to an unscaled kerning value
+ struct PairEqual{ int operator()(const ImplKernPairData& rA, const ImplKernPairData& rB) const
+ { return (rA.mnChar1 == rB.mnChar1) && (rA.mnChar2 == rB.mnChar2); } };
+ struct PairHash{ int operator()(const ImplKernPairData& rA) const
+ { return (rA.mnChar1) * 256 ^ rA.mnChar2; } };
+ typedef std::hash_set< ImplKernPairData, PairHash, PairEqual > UnicodeKernPairs;
+ mutable UnicodeKernPairs maUnicodeKernPairs;
+};
+
+// =======================================================================
+
+#endif // _SV_GLYPHCACHE_HXX
diff --git a/vcl/inc/vcl/gradient.hxx b/vcl/inc/vcl/gradient.hxx
new file mode 100644
index 000000000000..8938627cf684
--- /dev/null
+++ b/vcl/inc/vcl/gradient.hxx
@@ -0,0 +1,132 @@
+/*************************************************************************
+ *
+ * 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_GRADIENT_HXX
+#define _SV_GRADIENT_HXX
+
+#include <vcl/dllapi.h>
+#include <tools/color.hxx>
+
+#include <vcl/vclenum.hxx>
+
+// ------------------
+// - Gradient-Types -
+// ------------------
+
+/*
+#ifndef ENUM_GRADIENTSTYLE_DECLARED
+#define ENUM_GRADIENTSTYLE_DECLARED
+enum GradientStyle { GRADIENT_LINEAR, GRADIENT_AXIAL, GRADIENT_RADIAL,
+ GRADIENT_ELLIPTICAL, GRADIENT_SQUARE, GRADIENT_RECT };
+#endif
+*/
+
+// ----------------
+// - Impl_Gradient -
+// ----------------
+
+class SvStream;
+
+class Impl_Gradient
+{
+public:
+ ULONG mnRefCount;
+ GradientStyle meStyle;
+ Color maStartColor;
+ Color maEndColor;
+ USHORT mnAngle;
+ USHORT mnBorder;
+ USHORT mnOfsX;
+ USHORT mnOfsY;
+ USHORT mnIntensityStart;
+ USHORT mnIntensityEnd;
+ USHORT mnStepCount;
+
+ friend SvStream& operator>>( SvStream& rIStm, Impl_Gradient& rImplGradient );
+ friend SvStream& operator<<( SvStream& rOStm, const Impl_Gradient& rImplGradient );
+
+ Impl_Gradient();
+ Impl_Gradient( const Impl_Gradient& rImplGradient );
+};
+
+// ------------
+// - Gradient -
+// ------------
+
+class VCL_DLLPUBLIC Gradient
+{
+private:
+ Impl_Gradient* mpImplGradient;
+ void MakeUnique();
+
+public:
+ Gradient();
+ Gradient( const Gradient& rGradient );
+ Gradient( GradientStyle eStyle );
+ Gradient( GradientStyle eStyle,
+ const Color& rStartColor,
+ const Color& rEndColor );
+ ~Gradient();
+
+ void SetStyle( GradientStyle eStyle );
+ GradientStyle GetStyle() const { return mpImplGradient->meStyle; }
+
+ void SetStartColor( const Color& rColor );
+ const Color& GetStartColor() const { return mpImplGradient->maStartColor; }
+ void SetEndColor( const Color& rColor );
+ const Color& GetEndColor() const { return mpImplGradient->maEndColor; }
+
+ void SetAngle( USHORT nAngle );
+ USHORT GetAngle() const { return mpImplGradient->mnAngle; }
+
+ void SetBorder( USHORT nBorder );
+ USHORT GetBorder() const { return mpImplGradient->mnBorder; }
+ void SetOfsX( USHORT nOfsX );
+ USHORT GetOfsX() const { return mpImplGradient->mnOfsX; }
+ void SetOfsY( USHORT nOfsY );
+ USHORT GetOfsY() const { return mpImplGradient->mnOfsY; }
+
+ void SetStartIntensity( USHORT nIntens );
+ USHORT GetStartIntensity() const { return mpImplGradient->mnIntensityStart; }
+ void SetEndIntensity( USHORT nIntens );
+ USHORT GetEndIntensity() const { return mpImplGradient->mnIntensityEnd; }
+
+ void SetSteps( USHORT nSteps );
+ USHORT GetSteps() const { return mpImplGradient->mnStepCount; }
+
+ Gradient& operator=( const Gradient& rGradient );
+ BOOL operator==( const Gradient& rGradient ) const;
+ BOOL operator!=( const Gradient& rGradient ) const
+ { return !(Gradient::operator==( rGradient )); }
+ BOOL IsSameInstance( const Gradient& rGradient ) const
+ { return (mpImplGradient == rGradient.mpImplGradient); }
+
+ friend VCL_DLLPUBLIC SvStream& operator>>( SvStream& rIStm, Gradient& rGradient );
+ friend VCL_DLLPUBLIC SvStream& operator<<( SvStream& rOStm, const Gradient& rGradient );
+};
+
+#endif // _SV_GRADIENT_HXX
diff --git a/vcl/inc/vcl/graph.h b/vcl/inc/vcl/graph.h
new file mode 100644
index 000000000000..c50a54b8802d
--- /dev/null
+++ b/vcl/inc/vcl/graph.h
@@ -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 _SV_GRAPH_H
+#define _SV_GRAPH_H
+
+#include <vcl/dllapi.h>
+#include <tools/string.hxx>
+#include <vcl/sv.h>
+
+// ---------------
+// - GraphicType -
+// ---------------
+
+enum GraphicType
+{
+ GRAPHIC_NONE,
+ GRAPHIC_BITMAP,
+ GRAPHIC_GDIMETAFILE,
+ GRAPHIC_DEFAULT
+};
+
+// -----------------
+// - GraphicReader -
+// -----------------
+
+class ReaderData;
+
+class VCL_DLLPUBLIC GraphicReader
+{
+protected:
+
+ String maUpperName;
+ ReaderData* mpReaderData;
+ BOOL mbIsReading;
+
+ GraphicReader() :
+ mpReaderData( NULL ),
+ mbIsReading( FALSE ) {}
+
+public:
+
+ virtual ~GraphicReader();
+
+ const String& GetUpperFilterName() const { return maUpperName; }
+ ReaderData* GetReaderData() const { return mpReaderData; }
+ BOOL IsReading() const { return mbIsReading; }
+
+ // TODO: when incompatible changes are possible again
+ // the preview size hint should be redone
+ BOOL IsPreviewModeEnabled() const;
+ void DisablePreviewMode();
+ void SetPreviewSize( const Size& );
+ Size GetPreviewSize() const;
+};
+
+#endif // _SV_GRAPH_H
diff --git a/vcl/inc/vcl/graph.hxx b/vcl/inc/vcl/graph.hxx
new file mode 100644
index 000000000000..aa860273fdb7
--- /dev/null
+++ b/vcl/inc/vcl/graph.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_GRAPH_HXX
+#define _SV_GRAPH_HXX
+
+#include <tools/stream.hxx>
+#include <vcl/dllapi.h>
+#include <vcl/sv.h>
+#include <vcl/bitmap.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/animate.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/graph.h>
+#include <vcl/gfxlink.hxx>
+#include <com/sun/star/uno/Reference.hxx>
+
+namespace com { namespace sun { namespace star { namespace graphic { class XGraphic;} } } }
+
+// -----------
+// - Graphic -
+// -----------
+
+class ImpGraphic;
+class OutputDevice;
+class Font;
+class GfxLink;
+
+class VCL_DLLPUBLIC GraphicConversionParameters
+{
+private:
+ Size maSizePixel; // default is (0,0)
+
+ // bitfield
+ unsigned mbUnlimitedSize : 1; // default is false
+ unsigned mbAntiAliase : 1; // default is false
+ unsigned mbSnapHorVerLines : 1; // default is false
+
+public:
+ GraphicConversionParameters(
+ const Size& rSizePixel = Size(),
+ bool bUnlimitedSize = false,
+ bool bAntiAliase = false,
+ bool bSnapHorVerLines = false)
+ : maSizePixel(rSizePixel),
+ mbUnlimitedSize(bUnlimitedSize),
+ mbAntiAliase(bAntiAliase),
+ mbSnapHorVerLines(bSnapHorVerLines)
+ {
+ }
+
+ // data read access
+ const Size getSizePixel() const { return maSizePixel; }
+ bool getUnlimitedSize() const { return mbUnlimitedSize; }
+ bool getAntiAliase() const { return mbAntiAliase; }
+ bool getSnapHorVerLines() const { return mbSnapHorVerLines; }
+};
+
+class VCL_DLLPUBLIC Graphic : public SvDataCopyStream
+{
+private:
+
+ ImpGraphic* mpImpGraphic;
+
+//#if 0 // _SOLAR__PRIVATE
+
+public:
+
+ SAL_DLLPRIVATE void ImplTestRefCount();
+ SAL_DLLPRIVATE ImpGraphic* ImplGetImpGraphic() const { return mpImpGraphic; }
+
+//#endif
+
+public:
+
+ TYPEINFO();
+
+ Graphic();
+ Graphic( const Graphic& rGraphic );
+ Graphic( const Bitmap& rBmp );
+ Graphic( const BitmapEx& rBmpEx );
+ Graphic( const Animation& rAnimation );
+ Graphic( const GDIMetaFile& rMtf );
+ Graphic( const ::com::sun::star::uno::Reference< ::com::sun::star::graphic::XGraphic >& rxGraphic );
+ virtual ~Graphic();
+
+ Graphic& operator=( const Graphic& rGraphic );
+ BOOL operator==( const Graphic& rGraphic ) const;
+ BOOL operator!=( const Graphic& rGraphic ) const;
+ BOOL operator!() const;
+
+ void Clear();
+
+ GraphicType GetType() const;
+ void SetDefaultType();
+ BOOL IsSupportedGraphic() const;
+
+ BOOL IsTransparent() const;
+ BOOL IsAlpha() const;
+ BOOL IsAnimated() const;
+
+ // #i102089# Access of Bitmap potentially will have to rasterconvert the Graphic
+ // if it is a MetaFile. To be able to control this conversion it is necessary to
+ // allow giving parameters which control AntiAliasing and LineSnapping of the
+ // MetaFile when played. Defaults will use a no-AAed, not snapped conversion as
+ // before.
+ Bitmap GetBitmap(const GraphicConversionParameters& rParameters = GraphicConversionParameters()) const;
+ BitmapEx GetBitmapEx(const GraphicConversionParameters& rParameters = GraphicConversionParameters()) const;
+
+ Animation GetAnimation() const;
+ const GDIMetaFile& GetGDIMetaFile() const;
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::graphic::XGraphic > GetXGraphic() const;
+
+ Size GetPrefSize() const;
+ void SetPrefSize( const Size& rPrefSize );
+
+ MapMode GetPrefMapMode() const;
+ void SetPrefMapMode( const MapMode& rPrefMapMode );
+
+ Size GetSizePixel( const OutputDevice* pRefDevice = NULL ) const;
+
+ ULONG GetSizeBytes() const;
+
+ void Draw( OutputDevice* pOutDev,
+ const Point& rDestPt ) const;
+ void Draw( OutputDevice* pOutDev,
+ const Point& rDestPt,
+ const Size& rDestSize ) const;
+ static void Draw( OutputDevice* pOutDev, const String& rText,
+ Font& rFont, const Bitmap& rBitmap,
+ const Point& rDestPt, const Size& rDestSize );
+ static void DrawEx( OutputDevice* pOutDev, const String& rText,
+ Font& rFont, const BitmapEx& rBitmap,
+ const Point& rDestPt, const Size& rDestSize );
+
+ void StartAnimation( OutputDevice* pOutDev,
+ const Point& rDestPt,
+ long nExtraData = 0L,
+ OutputDevice* pFirstFrameOutDev = NULL );
+ void StartAnimation( OutputDevice* pOutDev,
+ const Point& rDestPt,
+ const Size& rDestSize,
+ long nExtraData = 0L,
+ OutputDevice* pFirstFrameOutDev = NULL );
+ void StopAnimation( OutputDevice* pOutputDevice = NULL,
+ long nExtraData = 0L );
+
+ void SetAnimationNotifyHdl( const Link& rLink );
+ Link GetAnimationNotifyHdl() const;
+
+ ULONG GetAnimationLoopCount() const;
+ void ResetAnimationLoopCount();
+
+ List* GetAnimationInfoList() const;
+
+ ULONG GetChecksum() const;
+
+public:
+
+ GraphicReader* GetContext();
+ void SetContext( GraphicReader* pReader );
+
+public:
+
+ static USHORT GetGraphicsCompressMode( SvStream& rIStm );
+
+ void SetDocFileName( const String& rName, ULONG nFilePos );
+ const String& GetDocFileName() const;
+ ULONG GetDocFilePos() const;
+
+ BOOL ReadEmbedded( SvStream& rIStream, BOOL bSwap = FALSE );
+ BOOL WriteEmbedded( SvStream& rOStream );
+
+ BOOL SwapOut();
+ BOOL SwapOut( SvStream* pOStm );
+ BOOL SwapIn();
+ BOOL SwapIn( SvStream* pIStm );
+ BOOL IsSwapOut() const;
+
+ void SetLink( const GfxLink& );
+ GfxLink GetLink() const;
+ BOOL IsLink() const;
+
+ BOOL ExportNative( SvStream& rOStream ) const;
+
+ friend VCL_DLLPUBLIC SvStream& operator<<( SvStream& rOStream, const Graphic& rGraphic );
+ friend VCL_DLLPUBLIC SvStream& operator>>( SvStream& rIStream, Graphic& rGraphic );
+
+public:
+
+ virtual void Load( SvStream& );
+ virtual void Save( SvStream& );
+ virtual void Assign( const SvDataCopyStream& );
+};
+
+#endif // _SV_GRAPH_HXX
+
diff --git a/vcl/inc/vcl/graphictools.hxx b/vcl/inc/vcl/graphictools.hxx
new file mode 100644
index 000000000000..3e3b9b3dc5b5
--- /dev/null
+++ b/vcl/inc/vcl/graphictools.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _VCL_GRAPHICTOOLS_HXX_
+#define _VCL_GRAPHICTOOLS_HXX_
+
+#include <vcl/dllapi.h>
+#include <sal/types.h>
+#include <rtl/string.hxx>
+#include <tools/color.hxx>
+#include <tools/poly.hxx>
+#include <tools/stream.hxx>
+#include <vcl/graph.hxx>
+
+#ifndef INCLUDED_MEMORY
+#include <memory>
+#define INCLUDED_MEMORY
+#endif
+
+#ifndef INCLUDED_VECTOR
+#include <vector>
+#define INCLUDED_VECTOR
+#endif
+
+/** Encapsulates geometry and associated attributes of a graphical 'pen stroke'
+
+ @attention Widespread use is deprecated. See declarations above
+ for the way to go. Especially the copied enums from svx/xenum.hxx
+ are troublesome.
+
+ Use this class to store geometry and attributes of a graphical
+ 'pen stroke', such as pen width, dashing etc. The geometry is the
+ so-called 'path' along which the stroke is traced, with the given
+ pen width. The cap type determines how the open ends of the path
+ should be drawn. If the geometry consists of more than one
+ segment, the join type determines in which way the segments are
+ joined.
+ */
+class VCL_DLLPUBLIC SvtGraphicStroke
+{
+public:
+ /// Style for open stroke ends
+ enum CapType
+ {
+ /// No additional cap
+ capButt=0,
+ /// Half-round cap at the line end, the center lying at the end point
+ capRound,
+ /// Half-square cap at the line end, the center lying at the end point
+ capSquare
+ };
+ /// Style for joins of individual stroke segments
+ enum JoinType
+ {
+ /// Extend segment edges, until they cross
+ joinMiter=0,
+ /// Connect segments by a filled round arc
+ joinRound,
+ /// Connect segments by a direct straight line
+ joinBevel,
+ /// Perform no join, leads to visible gaps between thick line segments
+ joinNone
+ };
+ enum
+ {
+ /// Width of stroke start/end arrow to exactly fit the joining stroke
+ normalizedArrowWidth=65536
+ };
+ typedef ::std::vector< double > DashArray;
+
+ SvtGraphicStroke();
+ /** All in one constructor
+
+ See accessor method descriptions for argument description
+ */
+ SvtGraphicStroke( const Polygon& rPath,
+ const PolyPolygon& rStartArrow,
+ const PolyPolygon& rEndArrow,
+ double fTransparency,
+ double fStrokeWidth,
+ CapType aCap,
+ JoinType aJoin,
+ double fMiterLimit,
+ const DashArray& rDashArray ); // TODO: Dash array offset (position where to start, see PS)
+
+ // accessors
+ /// Query path to stroke
+ void getPath ( Polygon& ) const;
+ /** Get the polygon that is put at the start of the line
+
+ The polygon is in a special normalized position: the center of
+ the stroked path will meet the given polygon at (0,0) from
+ negative y values. Thus, an arrow would have its baseline on
+ the x axis, going upwards to positive y values. Furthermore,
+ the polygon is also scaled in a special way: the width of the
+ joining stroke is defined to be
+ SvtGraphicStroke::normalizedArrowWidth (0x10000), i.e. ranging
+ from x=-0x8000 to x=0x8000. So, if the arrow does have this
+ width, it has to fit every stroke with every stroke width
+ exactly.
+ */
+ void getStartArrow ( PolyPolygon& ) const;
+ /** Get the polygon that is put at the end of the line
+
+ The polygon is in a special normalized position, and already
+ scaled to the desired size: the center of the stroked path
+ will meet the given polygon at (0,0) from negative y
+ values. Thus, an arrow would have its baseline on the x axis,
+ going upwards to positive y values. Furthermore, the polygon
+ is also scaled in a special way: the width of the joining
+ stroke is defined to be SvtGraphicStroke::normalizedArrowWidth
+ (0x10000), i.e. ranging from x=-0x8000 to x=0x8000. So, if the
+ arrow does have this width, it has to fit every stroke with
+ every stroke width exactly.
+ */
+ void getEndArrow ( PolyPolygon& ) const;
+ /** Get stroke transparency
+
+ @return the transparency, ranging from 0.0 (opaque) to 1.0 (fully translucent)
+ */
+ double getTransparency () const;
+ /// Get width of the stroke
+ double getStrokeWidth () const;
+ /// Get the style in which open stroke ends are drawn
+ CapType getCapType () const;
+ /// Get the style in which the stroke segments are joined
+ JoinType getJoinType () const;
+ /// Get the maximum length of mitered joins
+ double getMiterLimit () const;
+ /// Get an array of "on" and "off" lengths for stroke dashing
+ void getDashArray ( DashArray& ) const;
+ /// Query a textual representation of the object's content
+ ::rtl::OString toString () const;
+
+ // mutators
+ /// Set path to stroke
+ void setPath ( const Polygon& );
+ /** Set the polygon that is put at the start of the line
+
+ The polygon has to be in a special normalized position, and
+ already scaled to the desired size: the center of the stroked
+ path will meet the given polygon at (0,0) from negative y
+ values. Thus, an arrow would have its baseline on the x axis,
+ going upwards to positive y values. Furthermore, the polygon
+ also has to be scaled appropriately: the width of the joining
+ stroke is defined to be SvtGraphicStroke::normalizedArrowWidth
+ (0x10000), i.e. ranging from x=-0x8000 to x=0x8000. If your
+ arrow does have this width, it will fit every stroke with
+ every stroke width exactly.
+ */
+ void setStartArrow ( const PolyPolygon& );
+ /** Set the polygon that is put at the end of the line
+
+ The polygon has to be in a special normalized position, and
+ already scaled to the desired size: the center of the stroked
+ path will meet the given polygon at (0,0) from negative y
+ values. Thus, an arrow would have its baseline on the x axis,
+ going upwards to positive y values. Furthermore, the polygon
+ also has to be scaled appropriately: the width of the joining
+ stroke is defined to be SvtGraphicStroke::normalizedArrowWidth
+ (0x10000), i.e. ranging from x=-0x8000 to x=0x8000. If your
+ arrow does have this width, it will fit every stroke with
+ every stroke width exactly.
+ */
+ void setEndArrow ( const PolyPolygon& );
+ /** Set stroke transparency
+
+ @param fTrans
+ The transparency, ranging from 0.0 (opaque) to 1.0 (fully translucent)
+ */
+ void setTransparency ( double fTrans );
+ /// Set width of the stroke
+ void setStrokeWidth ( double );
+ /// Set the style in which open stroke ends are drawn
+ void setCapType ( CapType );
+ /// Set the style in which the stroke segments are joined
+ void setJoinType ( JoinType );
+ /// Set the maximum length of mitered joins
+ void setMiterLimit ( double );
+ /// Set the array of "on" and "off" lengths for stroke dashing
+ void setDashArray ( const DashArray& );
+
+private:
+ // friends
+ VCL_DLLPUBLIC friend SvStream& operator<<( SvStream& rOStm, const SvtGraphicStroke& rClass );
+ VCL_DLLPUBLIC friend SvStream& operator>>( SvStream& rIStm, SvtGraphicStroke& rClass );
+
+ Polygon maPath;
+ PolyPolygon maStartArrow;
+ PolyPolygon maEndArrow;
+ double mfTransparency;
+ double mfStrokeWidth;
+ CapType maCapType;
+ JoinType maJoinType;
+ double mfMiterLimit;
+ DashArray maDashArray;
+};
+
+/** Encapsulates geometry and associated attributes of a filled area
+
+ @attention Widespread use is deprecated. See declarations above
+ for the way to go. Especially the copied enums from svx/xenum.hxx
+ is troublesome.
+
+ Use this class to store geometry and attributes of a filled area,
+ such as fill color, transparency, texture or hatch. The geometry
+ is the so-called 'path', whose inner area will get filled
+ according to the attributes set. If the path is intersecting, or
+ one part of the path is lying fully within another part, then the
+ fill rule determines which parts are filled and which are not.
+ */
+class VCL_DLLPUBLIC SvtGraphicFill
+{
+public:
+ /// Type of fill algorithm used
+ enum FillRule
+ {
+ /** Non-zero winding rule
+
+ Fill shape scanline-wise. Starting at the left, determine
+ the winding number as follows: every segment crossed that
+ runs counter-clockwise adds one to the winding number,
+ every segment crossed that runs clockwise subtracts
+ one. The part of the scanline where the winding number is
+ non-zero gets filled.
+ */
+ fillNonZero=0,
+ /** Even-odd fill rule
+
+ Fill shape scanline-wise. Starting at the left, count the
+ number of segments crossed. If this number is odd, the
+ part of the scanline is filled, otherwise not.
+ */
+ fillEvenOdd
+ };
+ /// Type of filling used
+ enum FillType
+ {
+ /// Fill with a specified solid color
+ fillSolid=0,
+ /// Fill with the specified gradient
+ fillGradient,
+ /// Fill with the specified hatch
+ fillHatch,
+ /// Fill with the specified texture (a Graphic object)
+ fillTexture
+ };
+ /// Type of hatching used
+ enum HatchType
+ {
+ /// horizontal parallel lines, one unit apart
+ hatchSingle=0,
+ /// horizontal and verticall orthogonally crossing lines, one unit apart
+ hatchDouble,
+ /// three crossing lines, like HatchType::hatchDouble, but
+ /// with an additional diagonal line, rising to the upper
+ /// right corner. The first diagonal line goes through the
+ /// upper left corner, the other are each spaced a unit apart.
+ hatchTriple
+ };
+ /// Type of gradient used
+ enum GradientType {gradientLinear=0, gradientRadial, gradientRectangular};
+ /// Special values for gradient step count
+ enum { gradientStepsInfinite=0 };
+ /** Homogeneous 2D transformation matrix
+
+ This is a 2x3 matrix representing an affine transformation on
+ the R^2, in the usual C/C++ row major form. It is structured as follows:
+ <pre>
+ a b t_x
+ c d t_y
+ 0 0 1
+ </pre>
+ where the lowest line is not stored in the matrix, since it is
+ constant. Variables t_x and t_y contain translational
+ components, a to d rotation, scale and shear (for details,
+ look up your favorite linear algebra/computer graphics book).
+ */
+ struct VCL_DLLPUBLIC Transform
+ {
+ enum { MatrixSize=6 };
+ Transform();
+ double matrix[MatrixSize];
+ };
+
+ SvtGraphicFill();
+ /** All in one constructor
+
+ See accessor method descriptions for argument description
+ */
+ SvtGraphicFill( const PolyPolygon& rPath,
+ Color aFillColor,
+ double fTransparency,
+ FillRule aFillRule,
+ FillType aFillType, // TODO: Multitexturing
+ const Transform& aFillTransform,
+ bool bTiling,
+ HatchType aHatchType, // TODO: vector of directions and start points
+ Color aHatchColor,
+ GradientType aGradientType, // TODO: Transparent gradients (orthogonal to normal ones)
+ Color aGradient1stColor, // TODO: vector of colors and offsets
+ Color aGradient2ndColor,
+ int aGradientStepCount, // numbers of steps to render the gradient. gradientStepsInfinite means infinitely many.
+ const Graphic& aFillGraphic );
+
+ // accessors
+ /// Query path to fill
+ void getPath ( PolyPolygon& ) const;
+ /// Get color used for solid fills
+ Color getFillColor () const;
+ /** Get stroke transparency
+
+ @return the transparency, ranging from 0.0 (opaque) to 1.0 (fully translucent)
+ */
+ double getTransparency () const;
+ /// Get fill rule used
+ FillRule getFillRule () const;
+ /** Get fill type used
+
+ Currently, only one of the fill types can be used
+ simultaneously. If you specify e.g. FillRule::fillGradient,
+ hatching, texture and solid fill color are ignored.
+ */
+ FillType getFillType () const;
+ /** Get transformation applied to hatch, gradient or texture during fill
+
+ A fill operation generally starts at the top left position of
+ the object's bounding box. At that position (if tiling is on,
+ also all successive positions), the specified fill graphic is
+ rendered, after applying the fill transformation to it. For
+ example, if the fill transformation contains a translation,
+ the fill graphic is rendered at the object's bounding box's
+ top left corner plus the translation components.
+
+ */
+ void getTransform ( Transform& ) const;
+ /// deprecated
+ bool IsTiling () const;
+ /** Query state of texture tiling
+
+ @return true, if texture is tiled, false, if output only once.
+ */
+ bool isTiling () const;
+ /// Get type of hatch used
+ HatchType getHatchType () const;
+ /// Get color used for drawing the hatch
+ Color getHatchColor () const;
+ /// Get type of gradient used
+ GradientType getGradientType () const;
+ /// Get start color of the gradient
+ Color getGradient1stColor () const;
+ /// Get end color of the gradient
+ Color getGradient2ndColor () const;
+ /** Get the numbers of steps to render the gradient.
+
+ @return the step count. gradientStepsInfinite means infinitely many.
+ */
+ int getGradientStepCount() const;
+ /** Get the texture graphic used
+
+ The Graphic object returned is used to fill the geometry, if
+ the FillType is fillTexture. The Graphic object is always
+ assumed to be of size 1x1, the transformation is used to scale
+ it to the appropriate size.
+ */
+ void getGraphic ( Graphic& ) const;
+ /// Query a textual representation of the object's content
+ ::rtl::OString toString () const;
+
+ // mutators
+ /// Set path to fill
+ void setPath ( const PolyPolygon& rPath );
+ /// Set color used for solid fills
+ void setFillColor ( Color aFillColor );
+ /** Set stroke transparency
+
+ @param fTransparency
+ The transparency, ranging from 0.0 (opaque) to 1.0 (fully translucent)
+ */
+ void setTransparency ( double fTransparency );
+ /// Set fill rule used
+ void setFillRule ( FillRule aFillRule );
+ /** Set fill type used
+
+ Currently, only one of the fill types can be used
+ simultaneously. If you specify e.g. FillRule::fillGradient,
+ hatching, texture and solid fill color are ignored.
+ */
+ void setFillType ( FillType aFillType );
+ /// Set transformation applied to hatch, gradient or texture during fill
+ void setTransform ( const Transform& pTransform );
+ /** Set state of texture tiling
+
+ @param bTiling
+ If set to true, texture is tiled, if set to false, texture is output only once.
+ */
+ void setTiling ( bool bTiling = true );
+ /// Set type of hatch used
+ void setHatchType ( HatchType aHatchType );
+ /// Set color used for drawing the hatch
+ void setHatchColor ( Color aHatchColor );
+ /// Set type of gradient used
+ void setGradientType ( GradientType aGradType );
+ /// Set start color of the gradient
+ void setGradient1stColor ( Color aColor );
+ /// Set end color of the gradient
+ void setGradient2ndColor ( Color aColor );
+ /** Set the numbers of steps to render the gradient.
+
+ @param aCount
+ The step count. gradientStepsInfinite means use infinitely many.
+ */
+ void setGradientStepCount( int aCount );
+ /// Set the texture graphic used
+ void setGraphic ( const Graphic& rGraphic );
+
+private:
+ // friends
+ VCL_DLLPUBLIC friend SvStream& operator<<( SvStream& rOStm, const SvtGraphicFill& rClass );
+ VCL_DLLPUBLIC friend SvStream& operator>>( SvStream& rIStm, SvtGraphicFill& rClass );
+
+ PolyPolygon maPath;
+ Color maFillColor;
+ double mfTransparency;
+ FillRule maFillRule;
+ FillType maFillType;
+ Transform maFillTransform;
+ bool mbTiling;
+ HatchType maHatchType;
+ Color maHatchColor;
+ GradientType maGradientType;
+ Color maGradient1stColor;
+ Color maGradient2ndColor;
+ int maGradientStepCount;
+ Graphic maFillGraphic;
+};
+
+#endif /* _VCL_GRAPHICTOOLS_HXX_ */
diff --git a/vcl/inc/vcl/graphite_adaptors.hxx b/vcl/inc/vcl/graphite_adaptors.hxx
new file mode 100644
index 000000000000..43c2e37a5fb2
--- /dev/null
+++ b/vcl/inc/vcl/graphite_adaptors.hxx
@@ -0,0 +1,152 @@
+/*************************************************************************
+ *
+ * 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_GRAPHITEADAPTORS_HXX
+#define _SV_GRAPHITEADAPTORS_HXX
+
+// 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.
+//
+#ifndef MSC
+// SAL/VCL types
+class ServerFont;
+class FreetypeServerFont;
+
+// Graphite types
+
+struct FontProperties : gr::FontProps
+{
+ FontProperties(const FreetypeServerFont & font) throw();
+};
+
+namespace grutils
+{
+ class GrFeatureParser;
+}
+
+// This class adapts the Sal font and graphics services to form required by
+// the Graphite engine.
+// @author tse
+//
+class VCL_DLLPUBLIC GraphiteFontAdaptor : public gr::Font
+{
+typedef std::map<const gr::gid16, std::pair<gr::Rect, gr::Point> > GlyphMetricMap;
+
+public:
+ static bool IsGraphiteEnabledFont(ServerFont &) throw();
+
+ GraphiteFontAdaptor(ServerFont & font, const sal_Int32 dpi_x, const sal_Int32 dpi_y);
+ GraphiteFontAdaptor(const GraphiteFontAdaptor &) throw();
+ ~GraphiteFontAdaptor() throw();
+
+ gr::Font * copyThis();
+
+ // Basic attribute accessors.
+ virtual float ascent();
+ virtual float descent();
+ virtual bool bold();
+ virtual bool italic();
+ virtual float height();
+ virtual unsigned int getDPIx();
+ virtual unsigned int getDPIy();
+
+ // Font access methods.
+ virtual const void * getTable(gr::fontTableId32 tableID, size_t * pcbSize);
+ virtual void getFontMetrics(float * ascent_out, float * descent_out = 0, float * em_square_out = 0);
+
+ // Glyph metrics.
+ virtual void getGlyphMetrics(gr::gid16 glyphID, gr::Rect & boundingBox, gr::Point & advances);
+
+ // Adaptor attributes.
+ const FontProperties & fontProperties() const throw();
+ FreetypeServerFont & font() const throw();
+ const grutils::GrFeatureParser * features() const { return mpFeatures; };
+
+private:
+ virtual void UniqueCacheInfo(ext_std::wstring &, bool &, bool &);
+
+ FreetypeServerFont& mrFont;
+ FontProperties maFontProperties;
+ const unsigned int mnDpiX, mnDpiY;
+ const float mfAscent,
+ mfDescent,
+ mfEmUnits;
+ grutils::GrFeatureParser * mpFeatures;
+ GlyphMetricMap maGlyphMetricMap;
+};
+
+// Partial implementation of class GraphiteFontAdaptor.
+//
+inline const FontProperties & GraphiteFontAdaptor::fontProperties() const throw() {
+ return maFontProperties;
+}
+
+inline FreetypeServerFont & GraphiteFontAdaptor::font() const throw() {
+ return mrFont;
+}
+#endif // not MFC
+
+// Partial implementation of class TextSourceAdaptor.
+//
+//inline const ImplLayoutArgs & TextSourceAdaptor::layoutArgs() const throw() {
+// return _layout_args;
+//}
+
+
+#endif // _SV_GRAPHITEADAPTORS_HXX
diff --git a/vcl/inc/vcl/graphite_cache.hxx b/vcl/inc/vcl/graphite_cache.hxx
new file mode 100644
index 000000000000..5472b32dd62f
--- /dev/null
+++ b/vcl/inc/vcl/graphite_cache.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+// Description: Classes to cache Graphite Segments to try to improve
+// rendering performance.
+
+#ifndef GraphiteSegmentCache_h
+#define GraphiteSegmentCache_h
+
+#include <tools/solar.h>
+#include <rtl/ustring.h>
+
+#define GRCACHE_REUSE_VECTORS 1
+
+//#include <rope>
+#include <hash_map>
+
+class TextSourceAdaptor;
+/**
+* GrSegRecord stores a Graphite Segment and its associated text
+*/
+class GrSegRecord {
+public:
+ GrSegRecord(rtl::OUString * rope, TextSourceAdaptor * textSrc, gr::Segment * seg, bool bIsRtl);
+
+ ~GrSegRecord();
+
+ void reuse(rtl::OUString * rope, TextSourceAdaptor * textSrc, gr::Segment * seg, bool bIsRtl);
+
+ void clearVectors();
+ void clear();
+#ifdef GRCACHE_REUSE_VECTORS
+ void setGlyphVectors(long nWidth, GraphiteLayout::Glyphs & vGlyphs, std::vector<int> vCharDxs,
+ std::vector<int> & vChar2Base, std::vector<int> & vGlyph2Char, float fScale)
+ {
+ clearVectors();
+ mnWidth = nWidth;
+ m_fontScale = fScale;
+ mvGlyphs.insert(mvGlyphs.begin(), vGlyphs.begin(), vGlyphs.end());
+ mvCharDxs.insert(mvCharDxs.begin(),vCharDxs.begin(),vCharDxs.end());
+ mvChar2BaseGlyph.insert(mvChar2BaseGlyph.begin(),vChar2Base.begin(),vChar2Base.end());
+ mvGlyph2Char.insert(mvGlyph2Char.begin(),vGlyph2Char.begin(),vGlyph2Char.end());
+ }
+#endif
+ gr::Segment * getSegment() { return m_seg; }
+ TextSourceAdaptor * getTextSrc() { return m_text; }
+ void unlock() { --m_lockCount; }
+ bool isRtl() const { return mbIsRtl; }
+#ifdef GRCACHE_REUSE_VECTORS
+ const long & width() const { return mnWidth; }
+ const GraphiteLayout::Glyphs & glyphs() const { return mvGlyphs; }
+ const std::vector<int> & charDxs() const { return mvCharDxs; }
+ const std::vector<int> & char2BaseGlyph() const { return mvChar2BaseGlyph; }
+ const std::vector<int> & glyph2Char() const { return mvGlyph2Char; }
+ float & fontScale() { return m_fontScale; }
+#endif
+private:
+ rtl::OUString * m_rope;
+ TextSourceAdaptor * m_text;
+ gr::Segment * m_seg;
+ const xub_Unicode * m_nextKey;
+ const xub_Unicode* m_pStr;
+ size_t m_startChar;
+ float m_fontScale;
+ long mnWidth;
+ GraphiteLayout::Glyphs mvGlyphs; // glyphs in display order
+ std::vector<int> mvCharDxs; // right hand side x offset of each glyph
+ std::vector<int> mvChar2BaseGlyph;
+ std::vector<int> mvGlyph2Char;
+ bool mbIsRtl;
+ int m_lockCount;
+ friend class GraphiteSegmentCache;
+};
+
+typedef std::hash_map<long, GrSegRecord*, std::hash<long> > GraphiteSegMap;
+typedef std::hash_multimap<size_t, GrSegRecord*> GraphiteRopeMap;
+typedef std::pair<GraphiteRopeMap::iterator, GraphiteRopeMap::iterator> GrRMEntry;
+
+/**
+* GraphiteSegmentCache contains the cached Segments for one particular font size
+*/
+class GraphiteSegmentCache
+{
+ enum {
+ // not really sure what good values are here,
+ // bucket size should be >> cache size
+ SEG_BUCKET_SIZE = 4096,
+ SEG_CACHE_SIZE = 255
+ };
+public:
+ GraphiteSegmentCache()
+ : m_segMap(SEG_BUCKET_SIZE),
+ m_oldestKey(NULL) {};
+ ~GraphiteSegmentCache()
+ {
+ m_ropeMap.clear();
+ GraphiteSegMap::iterator i = m_segMap.begin();
+ while (i != m_segMap.end())
+ {
+ GrSegRecord *r = i->second;
+ delete r;
+ ++i;
+ }
+ m_segMap.clear();
+ };
+ GrSegRecord * getSegment(ImplLayoutArgs & layoutArgs, bool bIsRtl, int segCharLimit)
+ {
+ GrSegRecord * found = NULL;
+ // try to find a segment starting at correct place, if not, try to find a
+ // match for the complete buffer
+ GraphiteSegMap::iterator iMap =
+ m_segMap.find(reinterpret_cast<long>(layoutArgs.mpStr +
+ layoutArgs.mnMinCharPos));
+ if (iMap != m_segMap.end())
+ {
+ found = iMap->second;
+ }
+ else
+ {
+ iMap = m_segMap.find(reinterpret_cast<long>(layoutArgs.mpStr));
+ if (iMap != m_segMap.end())
+ {
+ found = iMap->second;
+ }
+ }
+ if (found)
+ {
+ if (found->m_seg->startCharacter() <= layoutArgs.mnMinCharPos &&
+ found->m_seg->stopCharacter() >= layoutArgs.mnEndCharPos)
+ {
+ DBG_ASSERT(found && found->m_seg, "null entry in GraphiteSegmentCache");
+ // restore original start character, in case it has changed
+ found->m_seg->setTextSourceOffset(found->m_startChar);
+ // check that characters are the same, at least in the range of
+ // interest
+ // We could use substr and ==, but substr does a copy,
+ // so its probably faster to do it like this
+ for (int i = layoutArgs.mnMinCharPos; i < segCharLimit; i++)
+ {
+ //if (!found->m_rope->match(rtl::OUString(layoutArgs.mpStr[i], layoutArgs.mnLength), i - found->m_seg->startCharacter()))
+ if (found->m_rope->getStr()[i-found->m_seg->startCharacter()] != layoutArgs.mpStr[i])
+ return NULL;
+ }
+ if (found->isRtl() != bIsRtl)
+ {
+ return NULL;
+ }
+ if (found->m_seg->stopCharacter() > layoutArgs.mnEndCharPos &&
+ static_cast<int>(found->char2BaseGlyph().size()) > layoutArgs.mnEndCharPos)
+ {
+ // check that the requested end character isn't mid cluster
+ if (found->char2BaseGlyph()[layoutArgs.mnEndCharPos-layoutArgs.mnMinCharPos] == -1)
+ {
+ return NULL;
+ }
+ }
+// if (found->m_lockCount != 0)
+// OutputDebugString("Multple users of SegRecord!");
+ found->m_lockCount++;
+ }
+ else found = NULL;
+ }
+ else
+ {
+ // the pointers aren't the same, but we might still have the same text in a segment
+ // this is expecially needed when editing a large paragraph
+ // each edit changes the pointers, but if we don't reuse any segments it gets very
+ // slow.
+ rtl::OUString * rope = new rtl::OUString(layoutArgs.mpStr + layoutArgs.mnMinCharPos,
+ segCharLimit - layoutArgs.mnMinCharPos);
+ if (!rope) return NULL;
+ size_t nHash = (*(rope)).hashCode();
+ GrRMEntry range = m_ropeMap.equal_range(nHash);
+ while (range.first != range.second)
+ {
+ found = range.first->second;
+ if (found->m_lockCount == 0)
+ {
+ if(rope->match(*(found->m_rope)))
+ {
+ // found, but the pointers are all wrong
+ found->m_seg->setTextSourceOffset(layoutArgs.mnMinCharPos);
+ // the switch is done in graphite_layout.cxx
+ //found->m_text->switchLayoutArgs(layoutArgs);
+ found->m_lockCount++;
+ break;
+ }
+ else
+ found = NULL;
+ }
+ else
+ found = NULL;
+ ++(range.first);
+ }
+ delete rope;
+ }
+ return found;
+ };
+ GrSegRecord * cacheSegment(TextSourceAdaptor * adapter, gr::Segment * seg, bool bIsRtl);
+private:
+ GraphiteSegMap m_segMap;
+ GraphiteRopeMap m_ropeMap;
+ const xub_Unicode * m_oldestKey;
+ const xub_Unicode * m_prevKey;
+};
+
+typedef std::hash_map<int, GraphiteSegmentCache *, std::hash<int> > GraphiteCacheMap;
+
+/**
+* GraphiteCacheHandler maps a particular font, style, size to a GraphiteSegmentCache
+*/
+class GraphiteCacheHandler
+{
+public:
+ GraphiteCacheHandler() : m_cacheMap(255) {};
+ ~GraphiteCacheHandler()
+ {
+ GraphiteCacheMap::iterator i = m_cacheMap.begin();
+ while (i != m_cacheMap.end())
+ {
+ GraphiteSegmentCache *r = i->second;
+ delete r;
+ ++i;
+ }
+ m_cacheMap.clear();
+ };
+
+ static GraphiteCacheHandler instance;
+
+ GraphiteSegmentCache * getCache(sal_Int32 & fontHash)
+ {
+ if (m_cacheMap.count(fontHash) > 0)
+ {
+ return m_cacheMap.find(fontHash)->second;
+ }
+ GraphiteSegmentCache *pCache = new GraphiteSegmentCache();
+ m_cacheMap[fontHash] = pCache;
+ return pCache;
+ }
+private:
+ GraphiteCacheMap m_cacheMap;
+};
+
+#endif
+
diff --git a/vcl/inc/vcl/graphite_features.hxx b/vcl/inc/vcl/graphite_features.hxx
new file mode 100644
index 000000000000..47f4c3a01e7f
--- /dev/null
+++ b/vcl/inc/vcl/graphite_features.hxx
@@ -0,0 +1,75 @@
+/*************************************************************************
+ *
+ * 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
+#include <tools/preextstl.h>
+#include <graphite/GrClient.h>
+#include <graphite/Font.h>
+#include <graphite/GrFeature.h>
+#include <tools/postextstl.h>
+
+namespace grutils
+{
+
+ class GrFeatureParser
+ {
+ public:
+ enum { MAX_FEATURES = 64 };
+ static const char FEAT_PREFIX;
+ static const char FEAT_SEPARATOR;
+ static const char FEAT_ID_VALUE_SEPARATOR;
+ static const std::string ISO_LANG;
+ GrFeatureParser(gr::Font & font, const std::string features, const std::string lang);
+ GrFeatureParser(gr::Font & font, const std::string lang);
+ GrFeatureParser(const GrFeatureParser & copy);
+ ~GrFeatureParser();
+ size_t getFontFeatures(gr::FeatureSetting settings[MAX_FEATURES]) const;
+ bool parseErrors() { return mbErrors; };
+ static bool isValid(gr::Font & font, gr::FeatureSetting & setting);
+ gr::isocode getLanguage() const { return maLang; };
+ bool hasLanguage() const { return (maLang.rgch[0] != '\0'); }
+ sal_Int32 hashCode() const;
+ private:
+ void setLang(gr::Font & font, const std::string & lang);
+ bool isCharId(const std::string & id, size_t offset, size_t length);
+ int getCharId(const std::string & id, size_t offset, size_t length);
+ int getIntValue(const std::string & id, size_t offset, size_t length);
+ size_t mnNumSettings;
+ gr::isocode maLang;
+ bool mbErrors;
+ gr::FeatureSetting maSettings[64];
+ };
+
+ union FeatId
+ {
+ gr::featid num;
+ unsigned char label[5];
+ };
+}
diff --git a/vcl/inc/vcl/graphite_layout.hxx b/vcl/inc/vcl/graphite_layout.hxx
new file mode 100644
index 000000000000..520f4620cd90
--- /dev/null
+++ b/vcl/inc/vcl/graphite_layout.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_GRAPHITELAYOUT_HXX
+#define _SV_GRAPHITELAYOUT_HXX
+// Description: An implementation of the SalLayout interface that uses the
+// Graphite engine.
+
+// We need this to enable namespace support in libgrengine headers.
+#define GR_NAMESPACE
+
+#define GRCACHE 1
+
+// Standard Library
+#include <memory>
+#include <vector>
+#include <utility>
+// Libraries
+#include <tools/preextstl.h>
+#include <graphite/GrClient.h>
+#include <graphite/Font.h>
+#include <graphite/GrConstants.h>
+#include <graphite/GrAppData.h>
+#include <graphite/SegmentAux.h>
+#include <tools/postextstl.h>
+// Platform
+#include <vcl/sallayout.hxx>
+#include <vcl/dllapi.h>
+// Module
+
+// For backwards compatibility with 2.4.x
+#if (SUPD == 680)
+typedef sal_Int32 sal_GlyphId;
+#endif
+
+
+// Module type definitions and forward declarations.
+//
+class TextSourceAdaptor;
+class GraphiteFontAdaptor;
+class GrSegRecord;
+// SAL/VCL types
+class ServerFont;
+// Graphite types
+namespace gr { class Segment; class GlyphIterator; }
+namespace grutils { class GrFeatureParser; }
+
+// This class uses the SIL Graphite engine to provide complex text layout services to the VCL
+// @author tse
+//
+class VCL_DLLPUBLIC GraphiteLayout : public SalLayout
+{
+public:
+ // Mask to allow Word break status to be stored within mvChar2BaseGlyph
+ enum {
+ WORD_BREAK_BEFORE = 0x40000000,
+ HYPHEN_BREAK_BEFORE = 0x80000000,
+ BREAK_MASK = 0xC0000000,
+ GLYPH_INDEX_MASK = 0x3FFFFFFF
+ } LineBreakMask;
+
+ class Glyphs : public std::vector<GlyphItem>
+ {
+ public:
+ typedef std::pair<Glyphs::const_iterator, Glyphs::const_iterator> iterator_pair_t;
+
+ void fill_from(gr::Segment & rSeg, ImplLayoutArgs & rArgs,
+ bool bRtl, long &rWidth, float fScaling,
+ std::vector<int> & rChar2Base, std::vector<int> & rGlyph2Char,
+ std::vector<int> & rCharDxs);
+ void move_glyph(Glyphs::iterator, long dx);
+
+ const_iterator cluster_base(const_iterator) const;
+ iterator_pair_t neighbour_clusters(const_iterator) const;
+ private:
+ std::pair<float,float> appendCluster(gr::Segment & rSeg, ImplLayoutArgs & rArgs,
+ bool bRtl, int nFirstCharInCluster, int nNextChar,
+ int nFirstGlyphInCluster, int nNextGlyph, float fScaling,
+ std::vector<int> & rChar2Base, std::vector<int> & rGlyph2Char,
+ std::vector<int> & rCharDxs, long & rDXOffset);
+ void append(gr::Segment & rSeg, ImplLayoutArgs & rArgs, gr::GlyphInfo & rGi, float nextGlyphOrigin, float fScaling, std::vector<int> & rChar2Base, std::vector<int> & rGlyph2Char, std::vector<int> & rCharDxs, long & rDXOffset, bool bIsBase);
+ };
+
+ mutable Glyphs mvGlyphs;
+ void clear();
+
+private:
+ TextSourceAdaptor * mpTextSrc; // Text source.
+ gr::LayoutEnvironment maLayout;
+ const gr::Font &mrFont;
+ long mnWidth;
+ std::vector<int> mvCharDxs;
+ std::vector<int> mvChar2BaseGlyph;
+ std::vector<int> mvGlyph2Char;
+ float mfScaling;
+ const grutils::GrFeatureParser * mpFeatures;
+
+public:
+ GraphiteLayout(const gr::Font & font, const grutils::GrFeatureParser * features = NULL) throw();
+
+ // used by upper layers
+ virtual bool LayoutText( ImplLayoutArgs& ); // first step of layout
+ // split into two stages to allow dc to be restored on the segment
+#ifdef GRCACHE
+ gr::Segment * CreateSegment(ImplLayoutArgs& rArgs, GrSegRecord ** pRecord = NULL);
+ bool LayoutGlyphs(ImplLayoutArgs& rArgs, gr::Segment * pSegment, GrSegRecord * pSegRecord);
+#else
+ gr::Segment * CreateSegment(ImplLayoutArgs& rArgs);
+ bool LayoutGlyphs(ImplLayoutArgs& rArgs, gr::Segment * pSegment);
+#endif
+
+ virtual void AdjustLayout( ImplLayoutArgs& ); // adjusting positions
+
+ // methods using string indexing
+ virtual int GetTextBreak( long nMaxWidth, long nCharExtra=0, int nFactor=1 ) const;
+ virtual long FillDXArray( sal_Int32* pDXArray ) const;
+ virtual void ApplyDXArray(ImplLayoutArgs &rArgs, std::vector<int> & rDeltaWidth);
+
+ virtual void GetCaretPositions( int nArraySize, sal_Int32* pCaretXArray ) const;
+
+ // methods using glyph indexing
+ virtual int GetNextGlyphs(int nLen, sal_GlyphId* pGlyphIdxAry, ::Point & rPos, int&,
+ sal_Int32* pGlyphAdvAry = 0, int* pCharPosAry = 0 ) const;
+
+ // used by glyph+font+script fallback
+ virtual void MoveGlyph( int nStart, long nNewXPos );
+ virtual void DropGlyph( int nStart );
+ virtual void Simplify( bool bIsBase );
+
+ // Dummy implementation so layout can be shared between Linux/Windows
+ virtual void DrawText(SalGraphics&) const {};
+
+ virtual ~GraphiteLayout() throw();
+ void SetFeatures(grutils::GrFeatureParser * aFeature) { mpFeatures = aFeature; }
+ void SetFontScale(float s) { mfScaling = s; };
+ const TextSourceAdaptor * textSrc() const { return mpTextSrc; };
+ virtual sal_GlyphId getKashidaGlyph(int & width) = 0;
+ void kashidaJustify(std::vector<int> & rDeltaWidth, sal_GlyphId, int width);
+
+ static const int EXTRA_CONTEXT_LENGTH;
+private:
+ int glyph_to_char(Glyphs::iterator);
+ std::pair<int,int> glyph_to_chars(const GlyphItem &) const;
+
+ std::pair<long,long> caret_positions(size_t) const;
+ void expandOrCondense(ImplLayoutArgs &rArgs);
+};
+
+
+
+#endif // _SV_GRAPHITELAYOUT_HXX
diff --git a/vcl/inc/vcl/graphite_serverfont.hxx b/vcl/inc/vcl/graphite_serverfont.hxx
new file mode 100644
index 000000000000..19eb70b11908
--- /dev/null
+++ b/vcl/inc/vcl/graphite_serverfont.hxx
@@ -0,0 +1,100 @@
+/*************************************************************************
+ *
+ * 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_GRAPHITESERVERFONT_HXX
+#define _SV_GRAPHITESERVERFONT_HXX
+
+// We need this to enable namespace support in libgrengine headers.
+#define GR_NAMESPACE
+
+#ifndef MSC
+#include <vcl/graphite_layout.hxx>
+#include <vcl/graphite_adaptors.hxx>
+
+// Modules
+
+class VCL_DLLPUBLIC GraphiteLayoutImpl : public GraphiteLayout
+{
+public:
+ GraphiteLayoutImpl(const gr::Font & font, const grutils::GrFeatureParser * features, GraphiteFontAdaptor * pFont) throw()
+ : GraphiteLayout(font, features), mpFont(pFont) {};
+ virtual ~GraphiteLayoutImpl() throw() {};
+ virtual sal_GlyphId getKashidaGlyph(int & width);
+private:
+ GraphiteFontAdaptor * mpFont;
+};
+
+// This class implments the server font specific parts.
+// @author tse
+//
+class VCL_DLLPUBLIC GraphiteServerFontLayout : public ServerFontLayout
+{
+private:
+ mutable GraphiteFontAdaptor * mpFont;
+ // mutable so that the DrawOffset/DrawBase can be set
+ mutable GraphiteLayoutImpl maImpl;
+public:
+ GraphiteServerFontLayout(GraphiteFontAdaptor * font) throw();
+
+ virtual bool LayoutText( ImplLayoutArgs& rArgs) { SalLayout::AdjustLayout(rArgs); return maImpl.LayoutText(rArgs); }; // first step of layout
+ virtual void AdjustLayout( ImplLayoutArgs& rArgs)
+ {
+ SalLayout::AdjustLayout(rArgs);
+ maImpl.DrawBase() = maDrawBase;
+ maImpl.DrawOffset() = maDrawOffset;
+ maImpl.AdjustLayout(rArgs);
+ };
+ virtual long GetTextWidth() const { return maImpl.GetTextWidth(); }
+ virtual long FillDXArray( sal_Int32* dxa ) const { return maImpl.FillDXArray(dxa); }
+ virtual int GetTextBreak( long mw, long ce, int f ) const { return maImpl.GetTextBreak(mw, ce, f); }
+ virtual void GetCaretPositions( int as, sal_Int32* cxa ) const { maImpl.GetCaretPositions(as, cxa); }
+
+ // used by display layers
+ virtual int GetNextGlyphs( int l, sal_GlyphId* gia, Point& p, int& s,
+ sal_Int32* gaa = NULL, int* cpa = NULL ) const
+ {
+ maImpl.DrawBase() = maDrawBase;
+ maImpl.DrawOffset() = maDrawOffset;
+ return maImpl.GetNextGlyphs(l, gia, p, s, gaa, cpa);
+ }
+
+ virtual void MoveGlyph( int nStart, long nNewXPos ) { maImpl.MoveGlyph(nStart, nNewXPos); };
+ virtual void DropGlyph( int nStart ) { maImpl.DropGlyph(nStart); };
+ virtual void Simplify( bool bIsBase ) { maImpl.Simplify(bIsBase); };
+
+ virtual ~GraphiteServerFontLayout() throw();
+
+// For use with PspGraphics
+ const sal_Unicode* getTextPtr() const;
+ int getMinCharPos() const { return mnMinCharPos; }
+ int getMaxCharPos() const { return mnEndCharPos; }
+};
+
+
+
+#endif
+#endif //_SV_GRAPHITESERVERFONT_HXX
diff --git a/vcl/inc/vcl/group.hxx b/vcl/inc/vcl/group.hxx
new file mode 100644
index 000000000000..48461ec18ac0
--- /dev/null
+++ b/vcl/inc/vcl/group.hxx
@@ -0,0 +1,67 @@
+/*************************************************************************
+ *
+ * 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_GROUP_HXX
+#define _SV_GROUP_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/ctrl.hxx>
+
+// ------------
+// - GroupBox -
+// ------------
+
+class VCL_DLLPUBLIC GroupBox : public Control
+{
+private:
+ using Control::ImplInitSettings;
+ using Window::ImplInit;
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle );
+ SAL_DLLPRIVATE WinBits ImplInitStyle( WinBits nStyle );
+ SAL_DLLPRIVATE void ImplInitSettings( BOOL bFont, BOOL bForeground, BOOL bBackground );
+ SAL_DLLPRIVATE void ImplDraw( OutputDevice* pDev, ULONG nDrawFlags,
+ const Point& rPos, const Size& rSize, bool bLayout = false );
+
+ virtual void FillLayoutData() const;
+ virtual const Font&
+ GetCanonicalFont( const StyleSettings& _rStyle ) const;
+ virtual const Color&
+ GetCanonicalTextColor( const StyleSettings& _rStyle ) const;
+
+public:
+ GroupBox( Window* pParent, WinBits nStyle = 0 );
+ GroupBox( Window* pParent, const ResId& rResId );
+
+ virtual void Paint( const Rectangle& rRect );
+ virtual void Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG nFlags );
+ virtual void Resize();
+ virtual void StateChanged( StateChangedType nType );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+};
+
+#endif // _SV_GROUP_HXX
diff --git a/vcl/inc/vcl/hatch.hxx b/vcl/inc/vcl/hatch.hxx
new file mode 100644
index 000000000000..5a8e36088f2e
--- /dev/null
+++ b/vcl/inc/vcl/hatch.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_HATCH_HXX
+#define _SV_HATCH_HXX
+
+#include <tools/color.hxx>
+#include <vcl/dllapi.h>
+
+#include <vcl/vclenum.hxx>
+
+// --------------
+// - Impl_Hatch -
+// --------------
+
+class SvStream;
+
+struct ImplHatch
+{
+ ULONG mnRefCount;
+ Color maColor;
+ HatchStyle meStyle;
+ long mnDistance;
+ USHORT mnAngle;
+
+ ImplHatch();
+ ImplHatch( const ImplHatch& rImplHatch );
+
+ friend SvStream& operator>>( SvStream& rIStm, ImplHatch& rImplHatch );
+ friend SvStream& operator<<( SvStream& rOStm, const ImplHatch& rImplHatch );
+};
+
+// ---------
+// - Hatch -
+// ---------
+
+class VCL_DLLPUBLIC Hatch
+{
+private:
+
+ ImplHatch* mpImplHatch;
+ SAL_DLLPRIVATE void ImplMakeUnique();
+
+public:
+
+ Hatch();
+ Hatch( const Hatch& rHatch );
+ Hatch( HatchStyle eStyle, const Color& rHatchColor, long nDistance, USHORT nAngle10 = 0 );
+ ~Hatch();
+
+ Hatch& operator=( const Hatch& rHatch );
+ BOOL operator==( const Hatch& rHatch ) const;
+ BOOL operator!=( const Hatch& rHatch ) const { return !(Hatch::operator==( rHatch ) ); }
+ BOOL IsSameInstance( const Hatch& rHatch ) const { return( mpImplHatch == rHatch.mpImplHatch ); }
+
+ void SetStyle( HatchStyle eStyle );
+ HatchStyle GetStyle() const { return mpImplHatch->meStyle; }
+
+ void SetColor( const Color& rColor );
+ const Color& GetColor() const { return mpImplHatch->maColor; }
+
+ void SetDistance( long nDistance );
+ long GetDistance() const { return mpImplHatch->mnDistance; }
+
+ void SetAngle( USHORT nAngle10 );
+ USHORT GetAngle() const { return mpImplHatch->mnAngle; }
+
+ friend VCL_DLLPUBLIC SvStream& operator>>( SvStream& rIStm, Hatch& rHatch );
+ friend VCL_DLLPUBLIC SvStream& operator<<( SvStream& rOStm, const Hatch& rHatch );
+};
+
+#endif // _SV_HATCH_HXX
diff --git a/vcl/inc/vcl/help.hxx b/vcl/inc/vcl/help.hxx
new file mode 100644
index 000000000000..30308aa8a723
--- /dev/null
+++ b/vcl/inc/vcl/help.hxx
@@ -0,0 +1,123 @@
+/*************************************************************************
+ *
+ * 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_HELP_HXX
+#define _SV_HELP_HXX
+
+#include <tools/string.hxx>
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+
+class Point;
+class Rectangle;
+class Window;
+
+// --------------
+// - Help-Types -
+// --------------
+
+#define QUICKHELP_LEFT ((USHORT)0x0001)
+#define QUICKHELP_CENTER ((USHORT)0x0002)
+#define QUICKHELP_RIGHT ((USHORT)0x0004)
+#define QUICKHELP_TOP ((USHORT)0x0008)
+#define QUICKHELP_VCENTER ((USHORT)0x0010)
+#define QUICKHELP_BOTTOM ((USHORT)0x0020)
+#define QUICKHELP_NOAUTOPOS (QUICKHELP_LEFT | QUICKHELP_CENTER | QUICKHELP_RIGHT | QUICKHELP_TOP | QUICKHELP_VCENTER | QUICKHELP_BOTTOM)
+#define QUICKHELP_CTRLTEXT ((USHORT)0x0040)
+#define QUICKHELP_NOEVADEPOINTER ((USHORT)0x4000)
+#define QUICKHELP_BIDI_RTL ((USHORT)0x8000)
+
+// By changes you must also change: rsc/vclrsc.hxx
+#define OOO_HELP_INDEX ((ULONG)0xFFFFFFFF)
+#define OOO_HELP_HELPONHELP ((ULONG)0xFFFFFFFE)
+
+// --------
+// - Help -
+// --------
+
+class VCL_DLLPUBLIC Help
+{
+private:
+ String maHelpFile;
+
+public:
+ Help();
+ virtual ~Help();
+
+ void SetHelpFile( const String& rFileName ) { maHelpFile = rFileName; }
+ const String& GetHelpFile() const { return maHelpFile; }
+
+ virtual BOOL Start( ULONG nHelpId, const Window* pWindow );
+ virtual BOOL Start( const XubString& rKeyWord, const Window* pWindow );
+ virtual void OpenHelpAgent( ULONG nHelpId );
+ virtual XubString GetHelpText( ULONG nHelpId, const Window* pWindow );
+ virtual XubString GetHelpText( const String& aHelpURL, const Window* pWindow );
+
+ static void EnableContextHelp();
+ static void DisableContextHelp();
+ static BOOL IsContextHelpEnabled();
+ static BOOL StartContextHelp();
+
+ static void EnableExtHelp();
+ static void DisableExtHelp();
+ static BOOL IsExtHelpEnabled();
+ static BOOL StartExtHelp();
+ static BOOL EndExtHelp();
+ static BOOL IsExtHelpActive();
+
+ static void EnableBalloonHelp();
+ static void DisableBalloonHelp();
+ static BOOL IsBalloonHelpEnabled();
+ static BOOL ShowBalloon( Window* pParent,
+ const Point& rScreenPos,
+ const XubString& rHelpText );
+ static BOOL ShowBalloon( Window* pParent,
+ const Point& rScreenPos,
+ const Rectangle&,
+ const XubString& rHelpText );
+
+ static void EnableQuickHelp();
+ static void DisableQuickHelp();
+ static BOOL IsQuickHelpEnabled();
+ static BOOL ShowQuickHelp( Window* pParent,
+ const Rectangle& rScreenRect,
+ const XubString& rHelpText,
+ const XubString& rLongHelpText,
+ USHORT nStyle = 0 );
+ static BOOL ShowQuickHelp( Window* pParent,
+ const Rectangle& rScreenRect,
+ const XubString& rHelpText,
+ USHORT nStyle = 0 )
+ { return Help::ShowQuickHelp( pParent, rScreenRect, rHelpText, XubString(), nStyle ); }
+
+ static ULONG ShowTip( Window* pParent,
+ const Rectangle& rScreenRect,
+ const XubString& rText, USHORT nStyle = 0 );
+ static void HideTip( ULONG nId );
+};
+
+#endif // _SV_HELP_HXX
diff --git a/vcl/inc/vcl/helper.hxx b/vcl/inc/vcl/helper.hxx
new file mode 100644
index 000000000000..9047079f6be1
--- /dev/null
+++ b/vcl/inc/vcl/helper.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _PSPRINT_HELPER_HXX_
+#define _PSPRINT_HELPER_HXX_
+
+#include <list>
+
+#include "vcl/dllapi.h"
+
+#include "rtl/ustring.hxx"
+
+
+// forwards
+namespace osl { class File; }
+
+namespace psp {
+typedef int fontID;
+
+void VCL_DLLPUBLIC getPrinterPathList( std::list< rtl::OUString >& rPathList, const char* pSubDir );
+
+// note: gcc 3.4.1 warns about visibility if we retunr a const rtl::OUString& here
+// seems to be a bug in gcc, now we return an object instead of a reference
+rtl::OUString VCL_DLLPUBLIC getFontPath();
+
+bool VCL_DLLPUBLIC convertPfbToPfa( osl::File& rInFile, osl::File& rOutFile );
+
+// normalized path (equivalent to realpath)
+void VCL_DLLPUBLIC normPath( rtl::OString& rPath );
+
+// splits rOrgPath into dirname and basename
+// rOrgPath will be subject to normPath
+void VCL_DLLPUBLIC splitPath( rtl::OString& rOrgPath, rtl::OString& rDir, rtl::OString& rBase );
+
+enum whichOfficePath { NetPath, UserPath, ConfigPath };
+// note: gcc 3.4.1 warns about visibility if we retunr a const rtl::OUString& here
+// seems to be a bug in gcc, now we return an object instead of a reference
+rtl::OUString VCL_DLLPUBLIC getOfficePath( enum whichOfficePath ePath );
+} // namespace
+
+#endif // _PSPRINT_HELPER_HXX_
diff --git a/vcl/inc/vcl/helpwin.hxx b/vcl/inc/vcl/helpwin.hxx
new file mode 100644
index 000000000000..244ae1b7d846
--- /dev/null
+++ b/vcl/inc/vcl/helpwin.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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_HELPWIN_HXX
+#define _SV_HELPWIN_HXX
+
+#include <vcl/floatwin.hxx>
+#include <vcl/timer.hxx>
+
+// ------------------
+// - HelpTextWindow -
+// ------------------
+
+class HelpTextWindow : public FloatingWindow
+{
+private:
+ Point maPos;
+ Rectangle maHelpArea; // Wenn naechste Hilfe fuers gleiche Rectangle, gleicher Text, dann Fenster stehen lassen
+
+ Rectangle maTextRect; // Bei umgebrochenen Text in QuickHelp
+
+ String maHelpText;
+ String maStatusText;
+
+ Timer maShowTimer;
+ Timer maHideTimer;
+
+ USHORT mnHelpWinStyle;
+ USHORT mnStyle;
+
+protected:
+ DECL_LINK( TimerHdl, Timer* );
+ virtual void Paint( const Rectangle& );
+ virtual void RequestHelp( const HelpEvent& rHEvt );
+ virtual String GetText() const;
+ void ImplShow();
+
+public:
+ HelpTextWindow( Window* pParent, const String& rText, USHORT nHelpWinStyle, USHORT nStyle );
+ ~HelpTextWindow();
+
+ const String& GetHelpText() const { return maHelpText; }
+ void SetHelpText( const String& rHelpText );
+ USHORT GetWinStyle() const { return mnHelpWinStyle; }
+
+ // Nur merken:
+ void SetStatusText( const String& rStatusText ) { maStatusText = rStatusText; }
+ void SetHelpArea( const Rectangle& rRect ) { maHelpArea = rRect; }
+
+ void ShowHelp( USHORT nDelayMode );
+
+ Size CalcOutSize() const;
+ const Rectangle& GetHelpArea() const { return maHelpArea; }
+
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > CreateAccessible();
+
+ BOOL RegisterAccessibleParent();
+ void RevokeAccessibleParent();
+};
+
+void ImplShowHelpWindow( Window* pParent, USHORT nHelpWinStyle, USHORT nStyle,
+ const String& rHelpText, const String& rStatusText,
+ const Point& rScreenPos, const Rectangle* pHelpArea = NULL );
+void ImplDestroyHelpWindow( bool bUpdateHideTime );
+void ImplSetHelpWindowPos( Window* pHelpWindow, USHORT nHelpWinStyle, USHORT nStyle,
+ const Point& rPos, const Rectangle* pHelpArea );
+
+#endif // _SV_HELPWIN_HXX
diff --git a/vcl/inc/vcl/i18nhelp.hxx b/vcl/inc/vcl/i18nhelp.hxx
new file mode 100644
index 000000000000..8f6a12f95761
--- /dev/null
+++ b/vcl/inc/vcl/i18nhelp.hxx
@@ -0,0 +1,97 @@
+/*************************************************************************
+ *
+ * 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_I18NHELP_HXX
+#define _VCL_I18NHELP_HXX
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/lang/Locale.hpp>
+#include <osl/mutex.hxx>
+#include <tools/string.hxx>
+#include <vcl/dllapi.h>
+
+namespace com {
+namespace sun {
+namespace star {
+namespace lang {
+ class XMultiServiceFactory;
+}
+}}}
+
+namespace utl {
+ class TransliterationWrapper;
+}
+
+class LocaleDataWrapper;
+
+class Date;
+
+namespace vcl
+{
+
+class VCL_DLLPUBLIC I18nHelper
+{
+private:
+ ::osl::Mutex maMutex;
+ ::com::sun::star::lang::Locale maLocale;
+ ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > mxMSF;
+
+ LocaleDataWrapper* mpLocaleDataWrapper;
+ utl::TransliterationWrapper* mpTransliterationWrapper;
+
+ sal_Bool mbTransliterateIgnoreCase;
+
+ SAL_DLLPRIVATE void ImplDestroyWrappers();
+
+protected:
+ ::osl::Mutex& GetMutex() { return maMutex; }
+
+ SAL_DLLPRIVATE utl::TransliterationWrapper& ImplGetTransliterationWrapper() const;
+ SAL_DLLPRIVATE LocaleDataWrapper& ImplGetLocaleDataWrapper() const;
+
+public:
+
+ I18nHelper( ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& rxMSF, const ::com::sun::star::lang::Locale& rLocale );
+ ~I18nHelper();
+
+ const ::com::sun::star::lang::Locale& getLocale() const;
+
+ sal_Int32 CompareString( const String& rStr1, const String& rStr2 ) const;
+
+ sal_Bool MatchString( const String& rStr1, const String& rStr2 ) const;
+ sal_Bool MatchMnemonic( const String& rString, sal_Unicode cMnemonicChar ) const;
+
+ String GetDate( const Date& rDate ) const;
+ String GetNum( long nNumber, USHORT nDecimals, BOOL bUseThousandSep = TRUE, BOOL bTrailingZeros = TRUE ) const;
+
+ static String filterFormattingChars( const String& );
+};
+
+} // namespace vcl
+
+#endif // _VCL_I18NHELP_HXX
+
diff --git a/vcl/inc/vcl/idlemgr.hxx b/vcl/inc/vcl/idlemgr.hxx
new file mode 100644
index 000000000000..6d7d7c8e531f
--- /dev/null
+++ b/vcl/inc/vcl/idlemgr.hxx
@@ -0,0 +1,60 @@
+/*************************************************************************
+ *
+ * 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_IDLEMGR_HXX
+#define _SV_IDLEMGR_HXX
+
+#include <vcl/sv.h>
+#include <vcl/timer.hxx>
+
+class ImplIdleList;
+
+// ---------------
+// - ImplIdleMgr -
+// ---------------
+
+class ImplIdleMgr
+{
+private:
+ ImplIdleList* mpIdleList;
+ AutoTimer maTimer;
+
+public:
+ ImplIdleMgr();
+ ~ImplIdleMgr();
+
+ BOOL InsertIdleHdl( const Link& rLink, USHORT nPriority );
+ void RemoveIdleHdl( const Link& rLink );
+
+ void RestartIdler()
+ { if ( maTimer.IsActive() ) maTimer.Start(); }
+
+ // Timer* kann auch NULL sein
+ DECL_LINK( TimeoutHdl, Timer* );
+};
+
+#endif // _SV_IDLEMGR_HXX
diff --git a/vcl/inc/vcl/ilstbox.hxx b/vcl/inc/vcl/ilstbox.hxx
new file mode 100644
index 000000000000..33f60a1e8a2f
--- /dev/null
+++ b/vcl/inc/vcl/ilstbox.hxx
@@ -0,0 +1,641 @@
+/*************************************************************************
+ *
+ * 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_ILSTBOX_HXX
+#define _SV_ILSTBOX_HXX
+
+#include <vcl/sv.h>
+#include <vcl/image.hxx>
+#include <vcl/ctrl.hxx>
+#include <vcl/button.hxx>
+#include <vcl/floatwin.hxx>
+#include <vcl/lstbox.h>
+#include <vcl/timer.hxx>
+
+
+class ScrollBar;
+class ScrollBarBox;
+
+// -----------------
+// - ListBox-Types -
+// -----------------
+
+#define HORZ_SCROLL 4
+#define IMG_TXT_DISTANCE 6
+
+enum LB_EVENT_TYPE
+{
+ LET_MBDOWN,
+ LET_TRACKING,
+ LET_TRACKING_END,
+ LET_KEYMOVE,
+ LET_KEYSPACE
+};
+
+// -----------------
+// - ImplEntryType -
+// -----------------
+
+struct ImplEntryType
+{
+ XubString maStr;
+ Image maImage;
+ void* mpUserData;
+ BOOL mbIsSelected;
+ long mnFlags;
+ long mnHeight;
+
+ ImplEntryType( const XubString& rStr, const Image& rImage ) :
+ maStr( rStr ),
+ maImage( rImage ),
+ mnFlags( 0 ),
+ mnHeight( 0 )
+ {
+ mbIsSelected = FALSE;
+ mpUserData = NULL;
+ }
+
+ ImplEntryType( const XubString& rStr ) :
+ maStr( rStr ),
+ mnFlags( 0 ),
+ mnHeight( 0 )
+ {
+ mbIsSelected = FALSE;
+ mpUserData = NULL;
+ }
+
+ ImplEntryType( const Image& rImage ) :
+ maImage( rImage ),
+ mnFlags( 0 ),
+ mnHeight( 0 )
+ {
+ mbIsSelected = FALSE;
+ mpUserData = NULL;
+ }
+};
+
+// -----------------
+// - ImplEntryList -
+// -----------------
+
+class ImplEntryList : private List
+{
+private:
+ Window* mpWindow; // For getting the current locale when matching strings
+ USHORT mnLastSelected;
+ USHORT mnSelectionAnchor;
+ USHORT mnImages;
+
+ USHORT mnMRUCount;
+ USHORT mnMaxMRUCount;
+
+ Link maSelectionChangedHdl;
+ BOOL mbCallSelectionChangedHdl;
+
+ ImplEntryType* GetEntry( USHORT nPos ) const { return (ImplEntryType*)List::GetObject( nPos ); }
+
+public:
+ ImplEntryList( Window* pWindow );
+ ~ImplEntryList();
+
+ USHORT InsertEntry( USHORT nPos, ImplEntryType* pNewEntry, BOOL bSort );
+ void RemoveEntry( USHORT nPos );
+ const ImplEntryType* GetEntryPtr( USHORT nPos ) const { return (const ImplEntryType*) GetObject( nPos ); }
+ ImplEntryType* GetMutableEntryPtr( USHORT nPos ) const { return (ImplEntryType*) GetObject( nPos ); }
+ void Clear();
+
+ USHORT FindMatchingEntry( const XubString& rStr, USHORT nStart = 0, BOOL bForward = TRUE, BOOL bLazy = TRUE ) const;
+ USHORT FindEntry( const XubString& rStr, BOOL bSearchMRUArea = FALSE ) const;
+ USHORT FindEntry( const void* pData ) const;
+
+ // helper: add up heights up to index nEndIndex.
+ // GetAddedHeight( 0 ) returns 0
+ // GetAddedHeight( LISTBOX_ENTRY_NOTFOUND ) returns 0
+ // GetAddedHeight( i, k ) with k > i is equivalent -GetAddedHeight( k, i )
+ long GetAddedHeight( USHORT nEndIndex, USHORT nBeginIndex = 0, long nBeginHeight = 0 ) const;
+ long GetEntryHeight( USHORT nPos ) const;
+
+ USHORT GetEntryCount() const { return (USHORT)List::Count(); }
+ BOOL HasImages() const { return mnImages ? TRUE : FALSE; }
+
+ XubString GetEntryText( USHORT nPos ) const;
+
+ BOOL HasEntryImage( USHORT nPos ) const;
+ Image GetEntryImage( USHORT nPos ) const;
+
+ void SetEntryData( USHORT nPos, void* pNewData );
+ void* GetEntryData( USHORT nPos ) const;
+
+ void SetEntryFlags( USHORT nPos, long nFlags );
+ long GetEntryFlags( USHORT nPos ) const;
+
+ void SelectEntry( USHORT nPos, BOOL bSelect );
+
+ USHORT GetSelectEntryCount() const;
+ XubString GetSelectEntry( USHORT nIndex ) const;
+ USHORT GetSelectEntryPos( USHORT nIndex ) const;
+ BOOL IsEntrySelected( const XubString& rStr ) const;
+ BOOL IsEntryPosSelected( USHORT nIndex ) const;
+
+ void SetLastSelected( USHORT nPos ) { mnLastSelected = nPos; }
+ USHORT GetLastSelected() const { return mnLastSelected; }
+
+ void SetSelectionAnchor( USHORT nPos ) { mnSelectionAnchor = nPos; }
+ USHORT GetSelectionAnchor() const { return mnSelectionAnchor; }
+
+
+ void SetSelectionChangedHdl( const Link& rLnk ) { maSelectionChangedHdl = rLnk; }
+ void SetCallSelectionChangedHdl( BOOL bCall ) { mbCallSelectionChangedHdl = bCall; }
+
+ void SetMRUCount( USHORT n ) { mnMRUCount = n; }
+ USHORT GetMRUCount() const { return mnMRUCount; }
+
+ void SetMaxMRUCount( USHORT n ) { mnMaxMRUCount = n; }
+ USHORT GetMaxMRUCount() const { return mnMaxMRUCount; }
+
+ /** An Entry is selectable if its mnFlags does not have the
+ LISTBOX_ENTRY_FLAG_DISABLE_SELECTION flag set. */
+ bool IsEntrySelectable( USHORT nPos ) const;
+
+ /** returns the first entry found from the given position nPos that is selectable
+ or LISTBOX_ENTRY_NOTFOUND if non is found. If the entry at nPos is not selectable,
+ it returns the first selectable entry after nPos if bForward is true and the
+ first selectable entry after nPos is bForward is false.
+ */
+ USHORT FindFirstSelectable( USHORT nPos, bool bForward = true );
+};
+
+// ---------------------
+// - ImplListBoxWindow -
+// ---------------------
+
+class ImplListBoxWindow : public Control
+{
+private:
+ ImplEntryList* mpEntryList; // EntryListe
+ Rectangle maFocusRect;
+ String maSearchStr;
+ Timer maSearchTimeout;
+
+ Size maUserItemSize;
+
+ long mnMaxTxtHeight; // Maximale Hoehe eines Text-Items
+ long mnMaxTxtWidth; // Maximale Breite eines Text-Items
+ // Entry ohne Image
+ long mnMaxImgTxtWidth;// Maximale Breite eines Text-Items
+ // Entry UND Image
+ long mnMaxImgWidth; // Maximale Breite eines Image-Items
+ long mnMaxImgHeight; // Maximale Hoehe eines Image-Items
+ long mnMaxWidth; // Maximale Breite eines Eintrags
+ long mnMaxHeight; // Maximale Hoehe eines Eintrags
+
+ USHORT mnCurrentPos; // Position (Focus)
+ USHORT mnTrackingSaveSelection; // Selektion vor Tracking();
+
+ USHORT mnSeparatorPos; // Separator
+
+ USHORT mnUserDrawEntry;
+
+ USHORT mnTop; // Ausgabe ab Zeile
+ long mnLeft; // Ausgabe ab Spalte
+ long mnBorder; // Abstand Rahmen - Text
+ long mnTextHeight; // Texthoehe
+ ProminentEntry meProminentType; // where is the "prominent" entry
+
+ USHORT mnSelectModifier; // Modifiers
+
+ BOOL mbHasFocusRect: 1,
+ mbSort: 1, // ListBox sortiert
+ mbTrack: 1, // Tracking
+ mbMulti: 1, // MultiListBox
+ mbStackMode: 1, // StackSelection
+ mbSimpleMode: 1, // SimpleMode fuer MultiListBox
+ mbImgsDiffSz: 1, // Images haben verschiedene Groessen
+ mbTravelSelect: 1, // TravelSelect
+ mbTrackingSelect: 1, // Selektiert bei MouseMove
+ mbSelectionChanged: 1, // Select() nicht zu oft rufen...
+ mbMouseMoveSelect: 1, // Selektieren bei MouseMove
+ mbGrabFocus: 1, // Focus bei MBDown grabben
+ mbUserDrawEnabled: 1, // UserDraw possible
+ mbInUserDraw: 1, // In UserDraw
+ mbReadOnly: 1, // ReadOnly
+ mbMirroring: 1, // pb: #106948# explicit mirroring for calc
+ mbRight: 1, // right align Text output
+ mbCenter: 1; // center Text output
+
+ Link maScrollHdl;
+ Link maSelectHdl;
+ Link maCancelHdl;
+ Link maDoubleClickHdl;
+ Link maUserDrawHdl;
+ Link maMRUChangedHdl;
+
+protected:
+ DECL_LINK( SearchStringTimeout, Timer* );
+
+ virtual void KeyInput( const KeyEvent& rKEvt );
+ virtual void MouseButtonDown( const MouseEvent& rMEvt );
+ virtual void MouseMove( const MouseEvent& rMEvt );
+ virtual void Tracking( const TrackingEvent& rTEvt );
+ virtual void Paint( const Rectangle& rRect );
+ virtual void Resize();
+ virtual void GetFocus();
+ virtual void LoseFocus();
+
+ BOOL SelectEntries( USHORT nSelect, LB_EVENT_TYPE eLET, BOOL bShift = FALSE, BOOL bCtrl = FALSE );
+ void ImplPaint( USHORT nPos, BOOL bErase = FALSE, bool bLayout = false );
+ void ImplDoPaint( const Rectangle& rRect, bool bLayout = false );
+ void ImplCalcMetrics();
+ void ImplUpdateEntryMetrics( ImplEntryType& rEntry );
+ void ImplCallSelect();
+
+ void ImplShowFocusRect();
+ void ImplHideFocusRect();
+
+
+ virtual void StateChanged( StateChangedType nType );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+
+public:
+ virtual void FillLayoutData() const;
+
+ ImplListBoxWindow( Window* pParent, WinBits nWinStyle );
+ ~ImplListBoxWindow();
+
+ ImplEntryList* GetEntryList() const { return mpEntryList; }
+
+ USHORT InsertEntry( USHORT nPos, ImplEntryType* pNewEntry );
+ void RemoveEntry( USHORT nPos );
+ void Clear();
+ void ResetCurrentPos() { mnCurrentPos = LISTBOX_ENTRY_NOTFOUND; }
+ USHORT GetCurrentPos() const { return mnCurrentPos; }
+ USHORT GetDisplayLineCount() const;
+ void SetEntryFlags( USHORT nPos, long nFlags );
+
+ void DrawEntry( USHORT nPos, BOOL bDrawImage, BOOL bDrawText, BOOL bDrawTextAtImagePos = FALSE, bool bLayout = false );
+
+ void SelectEntry( USHORT nPos, BOOL bSelect );
+ void DeselectAll();
+ USHORT GetEntryPosForPoint( const Point& rPoint ) const;
+ USHORT GetLastVisibleEntry() const;
+
+ BOOL ProcessKeyInput( const KeyEvent& rKEvt );
+
+ void SetTopEntry( USHORT nTop );
+ USHORT GetTopEntry() const { return mnTop; }
+ // ShowProminentEntry will set the entry correspoding to nEntryPos
+ // either at top or in the middle depending on the chosen style
+ void ShowProminentEntry( USHORT nEntryPos );
+ void SetProminentEntryType( ProminentEntry eType ) { meProminentType = eType; }
+ ProminentEntry GetProminentEntryType() const { return meProminentType; }
+ using Window::IsVisible;
+ BOOL IsVisible( USHORT nEntry ) const;
+
+ long GetLeftIndent() const { return mnLeft; }
+ void SetLeftIndent( long n );
+ void ScrollHorz( long nDiff );
+
+ void AllowGrabFocus( BOOL b ) { mbGrabFocus = b; }
+ BOOL IsGrabFocusAllowed() const { return mbGrabFocus; }
+
+ void SetSeparatorPos( USHORT n ) { mnSeparatorPos = n; }
+ USHORT GetSeparatorPos() const { return mnSeparatorPos; }
+
+ void SetTravelSelect( BOOL bTravelSelect ) { mbTravelSelect = bTravelSelect; }
+ BOOL IsTravelSelect() const { return mbTravelSelect; }
+ BOOL IsTrackingSelect() const { return mbTrackingSelect; }
+
+ void SetUserItemSize( const Size& rSz );
+ const Size& GetUserItemSize() const { return maUserItemSize; }
+
+ void EnableUserDraw( BOOL bUserDraw ) { mbUserDrawEnabled = bUserDraw; }
+ BOOL IsUserDrawEnabled() const { return mbUserDrawEnabled; }
+
+ void EnableMultiSelection( BOOL bMulti, BOOL bStackMode ) { mbMulti = bMulti; mbStackMode = bStackMode; }
+ BOOL IsMultiSelectionEnabled() const { return mbMulti; }
+
+ void SetMultiSelectionSimpleMode( BOOL bSimple ) { mbSimpleMode = bSimple; }
+ BOOL IsMultiSelectionSimpleMode() const { return mbSimpleMode; }
+
+ void EnableMouseMoveSelect( BOOL bMouseMoveSelect ) { mbMouseMoveSelect = bMouseMoveSelect; }
+ BOOL IsMouseMoveSelectEnabled() const { return mbMouseMoveSelect; }
+ BOOL IsMouseMoveSelect() const { return mbMouseMoveSelect||mbStackMode; }
+
+ Size CalcSize( USHORT nMaxLines ) const;
+ Rectangle GetBoundingRectangle( USHORT nItem ) const;
+
+ long GetEntryHeight() const { return mnMaxHeight; }
+ long GetMaxEntryWidth() const { return mnMaxWidth; }
+
+ void SetScrollHdl( const Link& rLink ) { maScrollHdl = rLink; }
+ const Link& GetScrollHdl() const { return maScrollHdl; }
+ void SetSelectHdl( const Link& rLink ) { maSelectHdl = rLink; }
+ const Link& GetSelectHdl() const { return maSelectHdl; }
+ void SetCancelHdl( const Link& rLink ) { maCancelHdl = rLink; }
+ const Link& GetCancelHdl() const { return maCancelHdl; }
+ void SetDoubleClickHdl( const Link& rLink ) { maDoubleClickHdl = rLink; }
+ const Link& GetDoubleClickHdl() const { return maDoubleClickHdl; }
+ void SetUserDrawHdl( const Link& rLink ) { maUserDrawHdl = rLink; }
+ const Link& GetUserDrawHdl() const { return maUserDrawHdl; }
+ void SetMRUChangedHdl( const Link& rLink ) { maMRUChangedHdl = rLink; }
+ const Link& GetMRUChangedHdl() const { return maMRUChangedHdl; }
+
+ BOOL IsSelectionChanged() const { return mbSelectionChanged; }
+ USHORT GetSelectModifier() const { return mnSelectModifier; }
+
+ void EnableSort( BOOL b ) { mbSort = b; }
+
+ void SetReadOnly( BOOL bReadOnly ) { mbReadOnly = bReadOnly; }
+ BOOL IsReadOnly() const { return mbReadOnly; }
+
+ using Control::ImplInitSettings;
+ void ImplInitSettings( BOOL bFont, BOOL bForeground, BOOL bBackground );
+ USHORT ImplGetTextStyle() const;
+
+ // pb: #106948# explicit mirroring for calc
+ inline void EnableMirroring() { mbMirroring = TRUE; }
+ inline BOOL IsMirroring() const { return mbMirroring; }
+};
+
+// ---------------
+// - ImplListBox -
+// ---------------
+
+class ImplListBox : public Control
+{
+private:
+ ImplListBoxWindow maLBWindow;
+ ScrollBar* mpHScrollBar;
+ ScrollBar* mpVScrollBar;
+ ScrollBarBox* mpScrollBarBox;
+ BOOL mbVScroll : 1, // VScroll an oder aus
+ mbHScroll : 1, // HScroll an oder aus
+ mbAutoHScroll : 1; // AutoHScroll an oder aus
+ Link maScrollHdl; // Weil der vom ImplListBoxWindow selbst benoetigt wird.
+
+protected:
+ virtual void GetFocus();
+ virtual void StateChanged( StateChangedType nType );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+
+ long Notify( NotifyEvent& rNEvt );
+
+ void ImplResizeControls();
+ void ImplCheckScrollBars();
+ void ImplInitScrollBars();
+
+ DECL_LINK( ScrollBarHdl, ScrollBar* );
+ DECL_LINK( LBWindowScrolled, void* );
+ DECL_LINK( MRUChanged, void* );
+
+public:
+ ImplListBox( Window* pParent, WinBits nWinStyle );
+ ~ImplListBox();
+
+ const ImplEntryList* GetEntryList() const { return maLBWindow.GetEntryList(); }
+ ImplListBoxWindow* GetMainWindow() { return &maLBWindow; }
+
+ virtual void Resize();
+ virtual const Wallpaper& GetDisplayBackground() const;
+ virtual Window* GetPreferredKeyInputWindow();
+
+ USHORT InsertEntry( USHORT nPos, const XubString& rStr );
+ USHORT InsertEntry( USHORT nPos, const Image& rImage );
+ USHORT InsertEntry( USHORT nPos, const XubString& rStr, const Image& rImage );
+ void RemoveEntry( USHORT nPos );
+ void SetEntryData( USHORT nPos, void* pNewData ) { maLBWindow.GetEntryList()->SetEntryData( nPos, pNewData ); }
+ void Clear();
+
+ void SetEntryFlags( USHORT nPos, long nFlags );
+ long GetEntryFlags( USHORT nPos ) const;
+
+ void SelectEntry( USHORT nPos, BOOL bSelect );
+ void SetNoSelection();
+ void ResetCurrentPos() { maLBWindow.ResetCurrentPos(); }
+ USHORT GetCurrentPos() const { return maLBWindow.GetCurrentPos(); }
+
+ BOOL ProcessKeyInput( const KeyEvent& rKEvt ) { return maLBWindow.ProcessKeyInput( rKEvt ); }
+ BOOL HandleWheelAsCursorTravel( const CommandEvent& rCEvt );
+
+ void SetSeparatorPos( USHORT n ) { maLBWindow.SetSeparatorPos( n ); }
+ USHORT GetSeparatorPos() const { return maLBWindow.GetSeparatorPos(); }
+
+ void SetTopEntry( USHORT nTop ) { maLBWindow.SetTopEntry( nTop ); }
+ USHORT GetTopEntry() const { return maLBWindow.GetTopEntry(); }
+ void ShowProminentEntry( USHORT nPos ) { maLBWindow.ShowProminentEntry( nPos ); }
+ using Window::IsVisible;
+ BOOL IsVisible( USHORT nEntry ) const { return maLBWindow.IsVisible( nEntry ); }
+
+ void SetProminentEntryType( ProminentEntry eType ) { maLBWindow.SetProminentEntryType( eType ); }
+ ProminentEntry GetProminentEntryType() const { return maLBWindow.GetProminentEntryType(); }
+
+ long GetLeftIndent() const { return maLBWindow.GetLeftIndent(); }
+ void SetLeftIndent( USHORT n ) { maLBWindow.SetLeftIndent( n ); }
+ void ScrollHorz( short nDiff ) { maLBWindow.ScrollHorz( nDiff ); }
+
+ void SetTravelSelect( BOOL bTravelSelect ) { maLBWindow.SetTravelSelect( bTravelSelect ); }
+ BOOL IsTravelSelect() const { return maLBWindow.IsTravelSelect(); }
+ BOOL IsTrackingSelect() const { return maLBWindow.IsTrackingSelect(); }
+
+ void EnableMultiSelection( BOOL bMulti, BOOL bStackMode ) { maLBWindow.EnableMultiSelection( bMulti, bStackMode ); }
+ BOOL IsMultiSelectionEnabled() const { return maLBWindow.IsMultiSelectionEnabled(); }
+
+ void SetMultiSelectionSimpleMode( BOOL bSimple ) { maLBWindow.SetMultiSelectionSimpleMode( bSimple ); }
+ BOOL IsMultiSelectionSimpleMode() const { return maLBWindow.IsMultiSelectionSimpleMode(); }
+
+ void SetReadOnly( BOOL b ) { maLBWindow.SetReadOnly( b ); }
+ BOOL IsReadOnly() const { return maLBWindow.IsReadOnly(); }
+
+
+ Size CalcSize( USHORT nMaxLines ) const { return maLBWindow.CalcSize( nMaxLines ); }
+ long GetEntryHeight() const { return maLBWindow.GetEntryHeight(); }
+ long GetMaxEntryWidth() const { return maLBWindow.GetMaxEntryWidth(); }
+
+ void SetScrollHdl( const Link& rLink ) { maScrollHdl = rLink; }
+ const Link& GetScrollHdl() const { return maScrollHdl; }
+ void SetSelectHdl( const Link& rLink ) { maLBWindow.SetSelectHdl( rLink ); }
+ const Link& GetSelectHdl() const { return maLBWindow.GetSelectHdl(); }
+ void SetCancelHdl( const Link& rLink ) { maLBWindow.SetCancelHdl( rLink ); }
+ const Link& GetCancelHdl() const { return maLBWindow.GetCancelHdl(); }
+ void SetDoubleClickHdl( const Link& rLink ) { maLBWindow.SetDoubleClickHdl( rLink ); }
+ const Link& GetDoubleClickHdl() const { return maLBWindow.GetDoubleClickHdl(); }
+ void SetUserDrawHdl( const Link& rLink ) { maLBWindow.SetUserDrawHdl( rLink ); }
+ const Link& GetUserDrawHdl() const { return maLBWindow.GetUserDrawHdl(); }
+
+ void SetSelectionChangedHdl( const Link& rLnk ) { maLBWindow.GetEntryList()->SetSelectionChangedHdl( rLnk ); }
+ void SetCallSelectionChangedHdl( BOOL bCall ) { maLBWindow.GetEntryList()->SetCallSelectionChangedHdl( bCall ); }
+ BOOL IsSelectionChanged() const { return maLBWindow.IsSelectionChanged(); }
+ USHORT GetSelectModifier() const { return maLBWindow.GetSelectModifier(); }
+
+ void SetMRUEntries( const XubString& rEntries, xub_Unicode cSep );
+ XubString GetMRUEntries( xub_Unicode cSep ) const;
+ void SetMaxMRUCount( USHORT n ) { maLBWindow.GetEntryList()->SetMaxMRUCount( n ); }
+ USHORT GetMaxMRUCount() const { return maLBWindow.GetEntryList()->GetMaxMRUCount(); }
+ USHORT GetDisplayLineCount() const
+ { return maLBWindow.GetDisplayLineCount(); }
+
+ // pb: #106948# explicit mirroring for calc
+ inline void EnableMirroring() { maLBWindow.EnableMirroring(); }
+};
+
+// -----------------------------
+// - ImplListBoxFloatingWindow -
+// -----------------------------
+
+class ImplListBoxFloatingWindow : public FloatingWindow
+{
+private:
+ ImplListBox* mpImplLB;
+ Size maPrefSz;
+ USHORT mnDDLineCount;
+ USHORT mnPopupModeStartSaveSelection;
+ BOOL mbAutoWidth;
+
+protected:
+ long PreNotify( NotifyEvent& rNEvt );
+
+public:
+ ImplListBoxFloatingWindow( Window* pParent );
+
+ void SetImplListBox( ImplListBox* pLB ) { mpImplLB = pLB; }
+
+ void SetPrefSize( const Size& rSz ) { maPrefSz = rSz; }
+ const Size& GetPrefSize() const { return maPrefSz; }
+
+ void SetAutoWidth( BOOL b ) { mbAutoWidth = b; }
+ BOOL IsAutoWidth() const { return mbAutoWidth; }
+
+ Size CalcFloatSize();
+ void StartFloat( BOOL bStartTracking );
+
+ virtual void SetPosSizePixel( long nX, long nY,
+ long nWidth, long nHeight, USHORT nFlags = WINDOW_POSSIZE_ALL );
+ void SetPosSizePixel( const Point& rNewPos, const Size& rNewSize )
+ { FloatingWindow::SetPosSizePixel( rNewPos, rNewSize ); }
+
+ void SetDropDownLineCount( USHORT n ) { mnDDLineCount = n; }
+ USHORT GetDropDownLineCount() const { return mnDDLineCount; }
+
+ USHORT GetPopupModeStartSaveSelection() const { return mnPopupModeStartSaveSelection; }
+
+ virtual void Resize();
+};
+
+// -----------
+// - ImplWin -
+// -----------
+
+class ImplWin : public Control
+{
+private:
+
+ USHORT mnItemPos; // wegen UserDraw muss ich wissen, welches Item ich darstelle.
+ XubString maString;
+ Image maImage;
+ Image maImageHC;
+
+ Rectangle maFocusRect;
+ Size maUserItemSize;
+
+ Link maMBDownHdl;
+ Link maUserDrawHdl;
+
+ BOOL mbUserDrawEnabled : 1,
+ mbInUserDraw : 1;
+
+
+ void ImplDraw( bool bLayout = false );
+protected:
+ virtual void FillLayoutData() const;
+public:
+
+ ImplWin( Window* pParent, WinBits nWinStyle = 0 );
+ ~ImplWin() {};
+
+ virtual void MouseButtonDown( const MouseEvent& rMEvt );
+ virtual void Paint( const Rectangle& rRect );
+ virtual void Resize();
+ virtual void GetFocus();
+ virtual void LoseFocus();
+ virtual long PreNotify( NotifyEvent& rNEvt );
+
+ USHORT GetItemPos() const { return mnItemPos; }
+ void SetItemPos( USHORT n ) { mnItemPos = n; }
+
+ const XubString& GetString() const { return maString; }
+ void SetString( const XubString& rStr ) { maString = rStr; }
+
+ const Image& GetImage() const { return maImage; }
+ void SetImage( const Image& rImg ) { maImage = rImg; }
+
+ BOOL SetModeImage( const Image& rImage, BmpColorMode eMode = BMP_COLOR_NORMAL );
+ const Image& GetModeImage( BmpColorMode eMode = BMP_COLOR_NORMAL ) const;
+
+
+ virtual void MBDown();
+ void SetMBDownHdl( const Link& rLink ) { maMBDownHdl = rLink; }
+ const Link& GetMBDownHdl() const { return maMBDownHdl; }
+
+ void SetUserDrawHdl( const Link& rLink ) { maUserDrawHdl = rLink; }
+ const Link& GetUserDrawHdl() const { return maUserDrawHdl; }
+
+ void SetUserItemSize( const Size& rSz ) { maUserItemSize = rSz; }
+ const Size& GetUserItemSize() const { return maUserItemSize; }
+
+ void EnableUserDraw( BOOL bUserDraw ) { mbUserDrawEnabled = bUserDraw; }
+ BOOL IsUserDrawEnabled() const { return mbUserDrawEnabled; }
+
+ void DrawEntry( BOOL bDrawImage, BOOL bDrawText, BOOL bDrawTextAtImagePos = FALSE, bool bLayout = false );
+};
+
+// -----------
+// - ImplBtn -
+// -----------
+
+class ImplBtn : public PushButton
+{
+private:
+ BOOL mbDown;
+
+ Link maMBDownHdl;
+
+public:
+ ImplBtn( Window* pParent, WinBits nWinStyle = 0 );
+ ~ImplBtn() {};
+
+ virtual void MouseButtonDown( const MouseEvent& rMEvt );
+
+ virtual void MBDown();
+ void SetMBDownHdl( const Link& rLink ) { maMBDownHdl = rLink; }
+ const Link& GetMBDownHdl() const { return maMBDownHdl; }
+};
+
+
+void ImplInitFieldSettings( Window* pWin, BOOL bFont, BOOL bForeground, BOOL bBackground );
+void ImplInitDropDownButton( PushButton* pButton );
+
+#endif // _SV_ILSTBOX_HXX
diff --git a/vcl/inc/vcl/image.h b/vcl/inc/vcl/image.h
new file mode 100644
index 000000000000..023b2c2d1a2c
--- /dev/null
+++ b/vcl/inc/vcl/image.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_IMAGE_H
+#define _SV_IMAGE_H
+
+#include <vcl/bitmapex.hxx>
+
+#include <hash_map>
+
+// ----------------
+// - ImplImageBmp -
+// ----------------
+
+class ImplImageBmp
+{
+public:
+
+ ImplImageBmp();
+ ~ImplImageBmp();
+
+ void Create( long nItemWidth, long nItemHeight, USHORT nInitSize );
+ void Create( const BitmapEx& rBmpEx, long nItemWidth, long nItemHeight,USHORT nInitSize );
+
+ void Expand( USHORT nGrowSize );
+
+ void Replace( USHORT nPos, USHORT nSrcPos );
+ void Replace( USHORT nPos, const ImplImageBmp& rImageBmp, USHORT nSrcPos );
+ void Replace( USHORT nPos, const BitmapEx& rBmpEx );
+
+ void ReplaceColors( const Color* pSrcColors, const Color* pDstColors, ULONG nColorCount );
+ void ColorTransform( BmpColorMode eColorMode );
+ void Invert();
+
+ BitmapEx GetBitmapEx( USHORT nPosCount, USHORT* pPosAry ) const;
+
+ void Draw( USHORT nPos, OutputDevice* pDev, const Point& rPos, USHORT nStyle, const Size* pSize = NULL );
+
+private:
+
+ BitmapEx maBmpEx;
+ BitmapEx maDisabledBmpEx;
+ BitmapEx* mpDisplayBmp;
+ Size maSize;
+ BYTE* mpInfoAry;
+ USHORT mnSize;
+
+ void ImplUpdateDisplayBmp( OutputDevice* pOutDev );
+ void ImplUpdateDisabledBmpEx( int nPos );
+
+private: // prevent assignment and copy construction
+ ImplImageBmp( const ImplImageBmp& );
+ void operator=( const ImplImageBmp& );
+};
+
+// --------------
+// - ImageTypes -
+// --------------
+
+enum ImageType { IMAGETYPE_BITMAP, IMAGETYPE_IMAGE };
+
+// -----------------
+// - ImplImageList -
+// -----------------
+
+struct ImageAryData
+{
+ ::rtl::OUString maName;
+ // Images identified by either name, or by id
+ USHORT mnId;
+ BitmapEx maBitmapEx;
+
+ ImageAryData();
+ ImageAryData( const rtl::OUString &aName,
+ USHORT nId, const BitmapEx &aBitmap );
+ ImageAryData( const ImageAryData& rData );
+ ~ImageAryData();
+
+ bool IsLoadable() { return maBitmapEx.IsEmpty() && maName.getLength(); }
+ void Load(const rtl::OUString &rPrefix);
+
+ ImageAryData& operator=( const ImageAryData& rData );
+};
+
+// ------------------------------------------------------------------------------
+
+struct ImplImageList
+{
+ typedef std::vector<ImageAryData *> ImageAryDataVec;
+ typedef std::hash_map< rtl::OUString, ImageAryData *, rtl::OUStringHash >
+ ImageAryDataNameHash;
+
+ ImageAryDataVec maImages;
+ ImageAryDataNameHash maNameHash;
+ rtl::OUString maPrefix;
+ Size maImageSize;
+ ULONG mnRefCount;
+
+ ImplImageList();
+ ImplImageList( const ImplImageList &aSrc );
+ ~ImplImageList();
+
+ void AddImage( const ::rtl::OUString &aName,
+ USHORT nId, const BitmapEx &aBitmapEx );
+ void RemoveImage( USHORT nPos );
+ USHORT GetImageCount() const;
+};
+
+// --------------------
+// - ImplImageRefData -
+// --------------------
+
+struct ImplImageRefData
+{
+ ImplImageList* mpImplData;
+ USHORT mnIndex;
+
+ ImplImageRefData() {} // Um Warning zu umgehen
+ ~ImplImageRefData();
+
+ BOOL IsEqual( const ImplImageRefData& rData );
+};
+
+// ----------------
+// - ImpImageData -
+// ----------------
+
+struct ImplImageData
+{
+ ImplImageBmp* mpImageBitmap;
+ BitmapEx maBmpEx;
+
+ ImplImageData( const BitmapEx& rBmpEx );
+ ~ImplImageData();
+
+ BOOL IsEqual( const ImplImageData& rData );
+};
+
+// -------------
+// - ImplImage -
+// -------------
+
+struct ImplImage
+{
+ ULONG mnRefCount;
+ // TODO: use inheritance to get rid of meType+mpData
+ void* mpData;
+ ImageType meType;
+
+ ImplImage();
+ ~ImplImage();
+
+private: // prevent assignment and copy construction
+ ImplImage( const ImplImage&);
+ void operator=( const ImplImage&);
+};
+
+#endif // _SV_IMAGE_H
diff --git a/vcl/inc/vcl/image.hxx b/vcl/inc/vcl/image.hxx
new file mode 100644
index 000000000000..f4f642656783
--- /dev/null
+++ b/vcl/inc/vcl/image.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_IMAGE_HXX
+#define _SV_IMAGE_HXX
+
+#include <vcl/dllapi.h>
+#include <tools/gen.hxx>
+#include <tools/resid.hxx>
+#include <vcl/sv.h>
+#include <vcl/bitmapex.hxx>
+#include <com/sun/star/uno/Reference.hxx>
+
+#include <vector>
+
+struct ImplImage;
+struct ImplImageList;
+namespace com { namespace sun { namespace star { namespace graphic { class XGraphic;} } } }
+
+// -----------
+// - Defines -
+// -----------
+
+#define IMAGE_STDBTN_COLOR Color( 0xC0, 0xC0, 0xC0 )
+#define IMAGELIST_IMAGE_NOTFOUND ((USHORT)0xFFFF)
+
+// -----------------------
+// - ImageColorTransform -
+// -----------------------
+
+enum ImageColorTransform
+{
+ IMAGECOLORTRANSFORM_NONE = 0,
+ IMAGECOLORTRANSFORM_HIGHCONTRAST = 1,
+ IMAGECOLORTRANSFORM_MONOCHROME_BLACK = 2,
+ IMAGECOLORTRANSFORM_MONOCHROME_WHITE = 3
+};
+
+// ---------
+// - Image -
+// ---------
+
+class VCL_DLLPUBLIC Image
+{
+ friend class ImageList;
+ friend class OutputDevice;
+
+public:
+ Image();
+ Image( const ResId& rResId );
+ Image( const Image& rImage );
+ Image( const BitmapEx& rBitmapEx );
+ Image( const Bitmap& rBitmap );
+ Image( const Bitmap& rBitmap, const Bitmap& rMaskBitmap );
+ Image( const Bitmap& rBitmap, const Color& rColor );
+ Image( const ::com::sun::star::uno::Reference< ::com::sun::star::graphic::XGraphic >& rxGraphic );
+ ~Image();
+
+ Size GetSizePixel() const;
+
+ BitmapEx GetBitmapEx() const;
+ ::com::sun::star::uno::Reference< ::com::sun::star::graphic::XGraphic > GetXGraphic() const;
+
+ Image GetColorTransformedImage( ImageColorTransform eColorTransform ) const;
+ static void GetColorTransformArrays( ImageColorTransform eColorTransform, Color*& rpSrcColor, Color*& rpDstColor, ULONG& rColorCount );
+
+ void Invert();
+
+ BOOL operator!() const { return( !mpImplData ? true : false ); }
+ Image& operator=( const Image& rImage );
+ BOOL operator==( const Image& rImage ) const;
+ BOOL operator!=( const Image& rImage ) const { return !(Image::operator==( rImage )); }
+
+private:
+
+ ImplImage* mpImplData;
+
+ SAL_DLLPRIVATE void ImplInit( const BitmapEx& rBmpEx );
+};
+
+// -------------
+// - ImageList -
+// -------------
+
+class VCL_DLLPUBLIC ImageList
+{
+public:
+ ImageList( USHORT nInit = 8, USHORT nGrow = 4 );
+ ImageList( const ResId& rResId );
+ ImageList( const ::std::vector< ::rtl::OUString >& rNameVector,
+ const ::rtl::OUString& rPrefix,
+ const Color* pMaskColor = NULL );
+ ImageList( const ImageList& rImageList );
+ ~ImageList();
+
+ void Clear();
+ void InsertFromHorizontalStrip( const BitmapEx &rBitmapEx,
+ const std::vector< rtl::OUString > &rNameVector );
+ void InsertFromHorizontalBitmap( const ResId& rResId,
+ USHORT nCount,
+ const Color *pNonAlphaMaskColor,
+ const Color *pSearchColors = NULL,
+ const Color *pReplaceColors = NULL,
+ ULONG nColorCount = 0);
+ BitmapEx GetAsHorizontalStrip() const;
+ USHORT GetImageCount() const;
+ Size GetImageSize() const;
+
+ void AddImage( USHORT nNewId, const Image& rImage );
+ void AddImage( const ::rtl::OUString& rImageName, const Image& rImage );
+
+ void ReplaceImage( USHORT nId, const Image& rImage );
+ void ReplaceImage( const ::rtl::OUString& rImageName, const Image& rImage );
+
+ void ReplaceImage( USHORT nId, USHORT nReplaceId );
+ void ReplaceImage( const ::rtl::OUString& rImageName, const ::rtl::OUString& rReplaceName );
+
+ void RemoveImage( USHORT nId );
+ void RemoveImage( const ::rtl::OUString& rImageName );
+
+ Image GetImage( USHORT nId ) const;
+ Image GetImage( const ::rtl::OUString& rImageName ) const;
+
+ USHORT GetImagePos( USHORT nId ) const;
+ bool HasImageAtPos( USHORT nId ) const;
+ USHORT GetImagePos( const ::rtl::OUString& rImageName ) const;
+
+ USHORT GetImageId( USHORT nPos ) const;
+ void GetImageIds( ::std::vector< USHORT >& rIds ) const;
+
+ ::rtl::OUString GetImageName( USHORT nPos ) const;
+ void GetImageNames( ::std::vector< ::rtl::OUString >& rNames ) const;
+
+ ImageList& operator=( const ImageList& rImageList );
+ BOOL operator==( const ImageList& rImageList ) const;
+ BOOL operator!=( const ImageList& rImageList ) const { return !(ImageList::operator==( rImageList )); }
+
+private:
+
+ ImplImageList* mpImplData;
+ USHORT mnInitSize;
+ USHORT mnGrowSize;
+
+ SAL_DLLPRIVATE void ImplInitBitmapEx( const ::rtl::OUString& rUserImageName,
+ const ::std::vector< ::rtl::OUString >& rImageNames,
+ const ::rtl::OUString& rSymbolsStyle,
+ BitmapEx& rBmpEx,
+ const Color* pMaskColor ) const;
+ SAL_DLLPRIVATE void ImplInit( USHORT nItems, const Size &rSize );
+ SAL_DLLPRIVATE USHORT ImplGetImageId( const ::rtl::OUString& rImageName ) const;
+ SAL_DLLPRIVATE void ImplMakeUnique();
+};
+
+#endif // _SV_IMAGE_HXX
diff --git a/vcl/inc/vcl/imagerepository.hxx b/vcl/inc/vcl/imagerepository.hxx
new file mode 100644
index 000000000000..f5809650fcf3
--- /dev/null
+++ b/vcl/inc/vcl/imagerepository.hxx
@@ -0,0 +1,70 @@
+/*************************************************************************
+ *
+ * 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_IMAGEREPOSITORY_HXX
+#define VCL_IMAGEREPOSITORY_HXX
+
+#include <vcl/dllapi.h>
+#include <rtl/ustring.hxx>
+
+class BitmapEx;
+
+//........................................................................
+namespace vcl
+{
+//........................................................................
+
+ //====================================================================
+ //= ImageRepository
+ //====================================================================
+ // provides access to the application's image repository (image.zip)
+ class VCL_DLLPUBLIC ImageRepository
+ {
+ public:
+ /** loads an image from the application's image repository
+ @param _rName
+ the name of the image to load.
+ @param _out_rImage
+ will take the image upon successful return.
+ @param bSearchLanguageDependent
+ determines whether a language-dependent image is to be searched.
+ @return
+ whether or not the image could be loaded successfully.
+ */
+ static bool loadImage(
+ const ::rtl::OUString& _rName,
+ BitmapEx& _out_rImage,
+ bool bSearchLanguageDependent
+ );
+ };
+
+//........................................................................
+} // namespace vcl
+//........................................................................
+
+#endif // VCL_IMAGEREPOSITORY_HXX
+
diff --git a/vcl/inc/vcl/imgcons.hxx b/vcl/inc/vcl/imgcons.hxx
new file mode 100644
index 000000000000..2f582fec15c3
--- /dev/null
+++ b/vcl/inc/vcl/imgcons.hxx
@@ -0,0 +1,105 @@
+/*************************************************************************
+ *
+ * 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 _IMGCONS_HXX
+#define _IMGCONS_HXX
+
+#include <vcl/dllapi.h>
+
+#include <vcl/bitmap.hxx>
+
+// -----------------
+// - ImageConsumer -
+// -----------------
+
+class ImageProducer;
+class ImplColorMapper;
+class BitmapEx;
+class Image;
+
+#define IMAGEERROR 1
+#define SINGLEFRAMEDONE 2
+#define STATICIMAGEDONE 3
+#define IMAGEABORTED 4
+
+class VCL_DLLPUBLIC ImageConsumer
+{
+private:
+
+ Bitmap maBitmap;
+ Bitmap maMask;
+ Rectangle maChangedRect;
+ Size maSize;
+ ImplColorMapper* mpMapper;
+ Color* mpPal;
+ Link maChgLink;
+ Link maDoneLink;
+ sal_uInt32 mnFormat;
+ sal_uInt32 mnStatus;
+ BOOL mbTrans;
+
+protected:
+
+ virtual void DataChanged();
+
+public:
+
+ ImageConsumer();
+ virtual ~ImageConsumer();
+
+ BOOL GetData( BitmapEx& rBmpEx ) const;
+ BOOL GetData( Image& rImage ) const;
+ const Rectangle& GetChangedRect() const { return maChangedRect; }
+ sal_uInt32 GetStatus() const;
+
+ void SetDataChangedLink( const Link& rLink ) { maChgLink = rLink; }
+ const Link& GetDataChangedLink() const { return maChgLink; }
+
+ void SetDoneLink( const Link& rLink ) { maDoneLink = rLink; }
+ const Link& GetDoneLink() const { return maDoneLink; }
+
+public:
+
+ virtual void Init( sal_uInt32 nWidth, sal_uInt32 nHeight );
+
+ virtual void SetColorModel( USHORT nBitCount,
+ sal_uInt32 nPalEntries, const sal_uInt32* pRGBAPal,
+ sal_uInt32 nRMask, sal_uInt32 nGMask, sal_uInt32 nBMask, sal_uInt32 nAMask );
+
+ virtual void SetPixelsByBytes( sal_uInt32 nConsX, sal_uInt32 nConsY,
+ sal_uInt32 nConsWidth, sal_uInt32 nConsHeight,
+ const BYTE* pProducerData, sal_uInt32 nOffset, sal_uInt32 nScanSize );
+
+ virtual void SetPixelsByLongs( sal_uInt32 nConsX, sal_uInt32 nConsY,
+ sal_uInt32 nConsWidth, sal_uInt32 nConsHeight,
+ const sal_uInt32* pProducerData, sal_uInt32 nOffset, sal_uInt32 nScanSize );
+
+ virtual void Completed( sal_uInt32 nStatus );
+// virtual void Completed( sal_uInt32 nStatus, ImageProducer& rProducer );
+};
+
+#endif // _IMGCONS_HXX
diff --git a/vcl/inc/vcl/imgctrl.hxx b/vcl/inc/vcl/imgctrl.hxx
new file mode 100644
index 000000000000..fa3b01463f34
--- /dev/null
+++ b/vcl/inc/vcl/imgctrl.hxx
@@ -0,0 +1,67 @@
+/*************************************************************************
+ *
+ * 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_IMGCTRL_HXX
+#define _SV_IMGCTRL_HXX
+
+#include <vcl/dllapi.h>
+
+#include <vcl/fixed.hxx>
+#include <vcl/bitmapex.hxx>
+
+// ----------------
+// - ImageControl -
+// ----------------
+
+class VCL_DLLPUBLIC ImageControl : public FixedImage
+{
+private:
+ BitmapEx maBmp;
+ BitmapEx maBmpHC;
+ ::sal_Int16 mnScaleMode;
+
+public:
+ ImageControl( Window* pParent, WinBits nStyle = 0 );
+
+ // set/get the scale mode. This is one of the css.awt.ImageScaleMode constants
+ void SetScaleMode( const ::sal_Int16 _nMode );
+ ::sal_Int16 GetScaleMode() const { return mnScaleMode; }
+
+ virtual void Resize();
+ virtual void UserDraw( const UserDrawEvent& rUDEvt );
+ virtual void Paint( const Rectangle& rRect );
+ virtual void GetFocus();
+ virtual void LoseFocus();
+
+ void SetBitmap( const BitmapEx& rBmp );
+ using OutputDevice::GetBitmap;
+ const BitmapEx& GetBitmap() const { return maBmp; }
+ BOOL SetModeBitmap( const BitmapEx& rBitmap, BmpColorMode eMode = BMP_COLOR_NORMAL );
+ const BitmapEx& GetModeBitmap( BmpColorMode eMode = BMP_COLOR_NORMAL ) const;
+};
+
+#endif // _SV_IMGCTRL_HXX
diff --git a/vcl/inc/vcl/impbmp.hxx b/vcl/inc/vcl/impbmp.hxx
new file mode 100644
index 000000000000..dc40fdcd3181
--- /dev/null
+++ b/vcl/inc/vcl/impbmp.hxx
@@ -0,0 +1,108 @@
+/*************************************************************************
+ *
+ * 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_IMPBMP_HXX
+#define _SV_IMPBMP_HXX
+
+#include <tools/gen.hxx>
+#include <vcl/sv.h>
+
+// ---------------
+// - ImpBitmap -
+// ---------------
+
+struct BitmapBuffer;
+class SalBitmap;
+class BitmapPalette;
+class SalGraphics;
+class ImplServerBitmap;
+class Bitmap;
+class OutputDevice;
+class Color;
+class AlphaMask;
+
+class ImpBitmap
+{
+private:
+
+ ULONG mnRefCount;
+ ULONG mnChecksum;
+ SalBitmap* mpSalBitmap;
+ Size maSourceSize;
+
+public:
+
+ ImpBitmap();
+ ~ImpBitmap();
+
+#if _SOLAR__PRIVATE
+
+public:
+
+ void ImplSetSalBitmap( SalBitmap* pSalBitmap );
+ SalBitmap* ImplGetSalBitmap() const { return mpSalBitmap; }
+
+public:
+
+ BOOL ImplCreate( const Size& rSize, USHORT nBitCount, const BitmapPalette& rPal );
+ BOOL ImplCreate( const ImpBitmap& rImpBitmap );
+ BOOL ImplCreate( const ImpBitmap& rImpBitmap, SalGraphics* pGraphics );
+ BOOL ImplCreate( const ImpBitmap& rImpBitmap, USHORT nNewBitCount );
+
+ void ImplDestroy();
+
+ Size ImplGetSize() const;
+ Size ImplGetSourceSize() const;
+ void ImplSetSourceSize( const Size&);
+ USHORT ImplGetBitCount() const;
+
+ BitmapBuffer* ImplAcquireBuffer( BOOL bReadOnly );
+ void ImplReleaseBuffer( BitmapBuffer* pBuffer, BOOL bReadOnly );
+
+public:
+
+ ULONG ImplGetRefCount() const { return mnRefCount; }
+ void ImplIncRefCount() { mnRefCount++; }
+ void ImplDecRefCount() { mnRefCount--; }
+
+ inline void ImplSetChecksum( ULONG nChecksum ) { mnChecksum = nChecksum; }
+ inline ULONG ImplGetChecksum() const { return mnChecksum; }
+
+#endif // PRIVATE
+};
+
+inline Size ImpBitmap::ImplGetSourceSize() const
+{
+ return maSourceSize;
+}
+
+inline void ImpBitmap::ImplSetSourceSize( const Size& rSize)
+{
+ maSourceSize = rSize;
+}
+
+#endif // _SV_IMPBMP_HXX
diff --git a/vcl/inc/vcl/impbmpconv.hxx b/vcl/inc/vcl/impbmpconv.hxx
new file mode 100644
index 000000000000..d95da9a4093a
--- /dev/null
+++ b/vcl/inc/vcl/impbmpconv.hxx
@@ -0,0 +1,39 @@
+/*************************************************************************
+ *
+ * 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_IMPBMPCONV_HXX_
+#define _VCL_IMPBMPCONV_HXX_
+
+#include <com/sun/star/script/XInvocation.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+
+namespace vcl
+{
+com::sun::star::uno::Reference< com::sun::star::script::XInvocation > createBmpConverter();
+}
+
+#endif
diff --git a/vcl/inc/vcl/impdel.hxx b/vcl/inc/vcl/impdel.hxx
new file mode 100644
index 000000000000..fc1796f0e402
--- /dev/null
+++ b/vcl/inc/vcl/impdel.hxx
@@ -0,0 +1,87 @@
+/*************************************************************************
+ *
+ * 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_IMPDEL_HXX
+ #define _VCL_IMPDEL_HXX
+
+ #include <list>
+
+ namespace vcl
+ {
+
+ class DeletionListener;
+
+ class DeletionNotifier
+ {
+ std::list< DeletionListener* > m_aListeners;
+ protected:
+ DeletionNotifier() {}
+
+ ~DeletionNotifier()
+ { notifyDelete(); }
+
+ inline void notifyDelete();
+
+ public:
+ void addDel( DeletionListener* pListener )
+ { m_aListeners.push_back( pListener ); }
+
+ void removeDel( DeletionListener* pListener )
+ { m_aListeners.remove( pListener ); }
+ };
+
+ class DeletionListener
+ {
+ DeletionNotifier* m_pNotifier;
+ public:
+ DeletionListener( DeletionNotifier* pNotifier )
+ : m_pNotifier( pNotifier )
+ {
+ if( m_pNotifier )
+ m_pNotifier->addDel( this );
+ }
+ ~DeletionListener()
+ {
+ if( m_pNotifier )
+ m_pNotifier->removeDel( this );
+ }
+ void deleted() { m_pNotifier = NULL; }
+ bool isDeleted() const { return (m_pNotifier == NULL); }
+ };
+
+ inline void DeletionNotifier::notifyDelete()
+ {
+ for( std::list< DeletionListener* >::const_iterator it =
+ m_aListeners.begin(); it != m_aListeners.end(); ++it )
+ (*it)->deleted();
+
+ m_aListeners.clear();
+ }
+
+ } // namespace vcl
+
+ #endif // _VCL_IMPDEL_HXX
diff --git a/vcl/inc/vcl/impfont.hxx b/vcl/inc/vcl/impfont.hxx
new file mode 100644
index 000000000000..a1104bbf4a86
--- /dev/null
+++ b/vcl/inc/vcl/impfont.hxx
@@ -0,0 +1,243 @@
+/*************************************************************************
+ *
+ * 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_IMPFONT_HXX
+#define _SV_IMPFONT_HXX
+
+#include <tools/gen.hxx>
+#include <tools/string.hxx>
+#include <i18npool/lang.h>
+#include <tools/color.hxx>
+#include <vcl/dllapi.h>
+#include <vcl/vclenum.hxx>
+#include <vcl/fntstyle.hxx>
+
+// ------------
+// - Impl_Font -
+// ------------
+
+class Impl_Font
+{
+public:
+ Impl_Font();
+ Impl_Font( const Impl_Font& );
+
+ bool operator==( const Impl_Font& ) const;
+
+ FontPitch GetPitch() { if(mePitch==PITCH_DONTKNOW) AskConfig(); return mePitch; }
+ FontFamily GetFamily() { if(meFamily==FAMILY_DONTKNOW) AskConfig(); return meFamily; }
+ FontItalic GetItalic() { if(meItalic==ITALIC_DONTKNOW) AskConfig(); return meItalic; }
+ FontWeight GetWeight() { if(meWeight==WEIGHT_DONTKNOW) AskConfig(); return meWeight; }
+ FontWidth GetWidthType() { if(meWidthType==WIDTH_DONTKNOW)AskConfig(); return meWidthType; }
+
+private:
+ friend class Font;
+ void AskConfig();
+
+ int mnRefCount;
+ String maFamilyName;
+ String maStyleName;
+ Size maSize;
+ Color maColor; // compatibility, now on output device
+ Color maFillColor; // compatibility, now on output device
+ rtl_TextEncoding meCharSet;
+ LanguageType meLanguage;
+ LanguageType meCJKLanguage;
+ FontFamily meFamily;
+ FontPitch mePitch;
+ TextAlign meAlign;
+ FontWeight meWeight;
+ FontWidth meWidthType;
+ FontItalic meItalic;
+ FontUnderline meUnderline;
+ FontUnderline meOverline;
+ FontStrikeout meStrikeout;
+ FontRelief meRelief;
+ FontEmphasisMark meEmphasisMark;
+ FontType meType; // used by metrics only
+ short mnOrientation;
+ FontKerning mnKerning;
+ BOOL mbWordLine:1,
+ mbOutline:1,
+ mbConfigLookup:1, // there was a config lookup
+ mbShadow:1,
+ mbVertical:1,
+ mbTransparent:1; // compatibility, now on output device
+
+ friend SvStream& operator>>( SvStream& rIStm, Impl_Font& );
+ friend SvStream& operator<<( SvStream& rOStm, const Impl_Font& );
+};
+
+// ------------------
+// - ImplFontMetric -
+// ------------------
+
+class ImplFontMetric
+{
+ friend class OutputDevice;
+
+private:
+ long mnAscent; // Ascent
+ long mnDescent; // Descent
+ long mnIntLeading; // Internal Leading
+ long mnExtLeading; // External Leading
+ long mnLineHeight; // Ascent+Descent+EmphasisMark
+ long mnSlant; // Slant
+ USHORT mnMiscFlags; // Misc Flags
+ UINT32 mnRefCount; // Reference Counter
+
+ enum { DEVICE_FLAG=1, SCALABLE_FLAG=2, LATIN_FLAG=4, CJK_FLAG=8, CTL_FLAG=16 };
+
+public:
+ ImplFontMetric();
+ void AddReference();
+ void DeReference();
+
+ long GetAscent() const { return mnAscent; }
+ long GetDescent() const { return mnDescent; }
+ long GetIntLeading() const { return mnIntLeading; }
+ long GetExtLeading() const { return mnExtLeading; }
+ long GetLineHeight() const { return mnLineHeight; }
+ long GetSlant() const { return mnSlant; }
+
+ bool IsDeviceFont() const { return ((mnMiscFlags & DEVICE_FLAG) != 0); }
+ bool IsScalable() const { return ((mnMiscFlags & SCALABLE_FLAG) != 0); }
+ bool SupportsLatin() const { return ((mnMiscFlags & LATIN_FLAG) != 0); }
+ bool SupportsCJK() const { return ((mnMiscFlags & CJK_FLAG) != 0); }
+ bool SupportsCTL() const { return ((mnMiscFlags & CTL_FLAG) != 0); }
+
+ bool operator==( const ImplFontMetric& ) const;
+};
+
+// ------------------
+// - ImplFontHints -
+// ------------------
+
+class ImplFontOptions
+{
+public:
+ FontEmbeddedBitmap meEmbeddedBitmap; // whether the embedded bitmaps should be used
+ FontAntiAlias meAntiAlias; // whether the font should be antialiased
+ FontAutoHint meAutoHint; // whether the font should be autohinted
+ FontHinting meHinting; // whether the font should be hinted
+ FontHintStyle meHintStyle; // type of font hinting to be used
+public:
+ ImplFontOptions() :
+ meEmbeddedBitmap(EMBEDDEDBITMAP_DONTKNOW),
+ meAntiAlias(ANTIALIAS_DONTKNOW),
+ meAutoHint(AUTOHINT_DONTKNOW),
+ meHinting(HINTING_DONTKNOW),
+ meHintStyle(HINT_SLIGHT)
+ {}
+ ImplFontOptions( FontEmbeddedBitmap eEmbeddedBitmap, FontAntiAlias eAntiAlias,
+ FontAutoHint eAutoHint, FontHinting eHinting, FontHintStyle eHintStyle) :
+ meEmbeddedBitmap(eEmbeddedBitmap),
+ meAntiAlias(eAntiAlias),
+ meAutoHint(eAutoHint),
+ meHinting(eHinting),
+ meHintStyle(eHintStyle)
+ {}
+ FontAutoHint GetUseAutoHint() const { return meAutoHint; }
+ FontHintStyle GetHintStyle() const { return meHintStyle; }
+ bool DontUseEmbeddedBitmaps() const { return meEmbeddedBitmap == EMBEDDEDBITMAP_FALSE; }
+ bool DontUseAntiAlias() const { return meAntiAlias == ANTIALIAS_FALSE; }
+ bool DontUseHinting() const { return (meHinting == HINTING_FALSE) || (GetHintStyle() == HINT_NONE); }
+};
+
+// -------------------
+// - ImplFontCharMap -
+// -------------------
+
+class CmapResult;
+
+class VCL_DLLPUBLIC ImplFontCharMap
+{
+public:
+ explicit ImplFontCharMap( const CmapResult& );
+ virtual ~ImplFontCharMap();
+
+ static ImplFontCharMap* GetDefaultMap( bool bSymbols=false);
+
+ bool IsDefaultMap() const;
+ bool HasChar( sal_uInt32 ) const;
+ int CountCharsInRange( sal_uInt32 cMin, sal_uInt32 cMax ) const;
+ int GetCharCount() const;
+
+ sal_uInt32 GetFirstChar() const;
+ sal_uInt32 GetLastChar() const;
+
+ sal_uInt32 GetNextChar( sal_uInt32 ) const;
+ sal_uInt32 GetPrevChar( sal_uInt32 ) const;
+
+ int GetIndexFromChar( sal_uInt32 ) const;
+ sal_uInt32 GetCharFromIndex( int ) const;
+
+ void AddReference();
+ void DeReference();
+
+ int GetGlyphIndex( sal_uInt32 ) const;
+
+private:
+ int ImplFindRangeIndex( sal_uInt32 ) const;
+
+ // prevent assignment and copy construction
+ explicit ImplFontCharMap( const ImplFontCharMap& );
+ void operator=( const ImplFontCharMap& );
+
+private:
+ const sal_uInt32* mpRangeCodes; // pairs of StartCode/(EndCode+1)
+ const int* mpStartGlyphs; // range-specific mapper to glyphs
+ const USHORT* mpGlyphIds; // individual glyphid mappings
+ int mnRangeCount;
+ int mnCharCount;
+ int mnRefCount;
+};
+
+// CmapResult is a normalized version of the many CMAP formats
+class
+#ifdef UNX
+ VCL_DLLPUBLIC // vcl-plugins need it
+#endif // UNX
+CmapResult
+{
+public:
+ explicit CmapResult( bool bSymbolic = false,
+ const sal_uInt32* pRangeCodes = NULL, int nRangeCount = 0,
+ const int* pStartGlyphs = 0, const USHORT* pGlyphIds = NULL );
+
+ const sal_uInt32* mpRangeCodes;
+ const int* mpStartGlyphs;
+ const USHORT* mpGlyphIds;
+ int mnRangeCount;
+ bool mbSymbolic;
+ bool mbRecoded;
+};
+
+bool ParseCMAP( const unsigned char* pRawData, int nRawLength, CmapResult& );
+
+#endif // _SV_IMPFONT_HXX
+
diff --git a/vcl/inc/vcl/impgraph.hxx b/vcl/inc/vcl/impgraph.hxx
new file mode 100644
index 000000000000..bb28d801fe12
--- /dev/null
+++ b/vcl/inc/vcl/impgraph.hxx
@@ -0,0 +1,176 @@
+/*************************************************************************
+ *
+ * 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_IMPGRAPH_HXX
+#define _SV_IMPGRAPH_HXX
+
+#include <tools/urlobj.hxx>
+#include <vcl/bitmap.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/animate.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/graph.h>
+
+// ---------------
+// - ImpSwapInfo -
+// ---------------
+
+struct ImpSwapInfo
+{
+ MapMode maPrefMapMode;
+ Size maPrefSize;
+};
+
+// --------------
+// - ImpGraphic -
+// --------------
+
+class OutputDevice;
+class GfxLink;
+struct ImpSwapFile;
+class GraphicConversionParameters;
+
+class ImpGraphic
+{
+ friend class Graphic;
+
+private:
+
+ GDIMetaFile maMetaFile;
+ BitmapEx maEx;
+ ImpSwapInfo maSwapInfo;
+ Animation* mpAnimation;
+ GraphicReader* mpContext;
+ ImpSwapFile* mpSwapFile;
+ GfxLink* mpGfxLink;
+ GraphicType meType;
+ String maDocFileURLStr;
+ ULONG mnDocFilePos;
+ mutable ULONG mnSizeBytes;
+ ULONG mnRefCount;
+ BOOL mbSwapOut;
+ BOOL mbSwapUnderway;
+
+private:
+
+ ImpGraphic();
+ ImpGraphic( const ImpGraphic& rImpGraphic );
+ ImpGraphic( const Bitmap& rBmp );
+ ImpGraphic( const BitmapEx& rBmpEx );
+ ImpGraphic( const Animation& rAnimation );
+ ImpGraphic( const GDIMetaFile& rMtf );
+ virtual ~ImpGraphic();
+
+ ImpGraphic& operator=( const ImpGraphic& rImpGraphic );
+ BOOL operator==( const ImpGraphic& rImpGraphic ) const;
+ BOOL operator!=( const ImpGraphic& rImpGraphic ) const { return !( *this == rImpGraphic ); }
+
+ void ImplClearGraphics( BOOL bCreateSwapInfo );
+ void ImplClear();
+
+ GraphicType ImplGetType() const;
+ void ImplSetDefaultType();
+ BOOL ImplIsSupportedGraphic() const;
+
+ BOOL ImplIsTransparent() const;
+ BOOL ImplIsAlpha() const;
+ BOOL ImplIsAnimated() const;
+
+ Bitmap ImplGetBitmap(const GraphicConversionParameters& rParameters) const;
+ BitmapEx ImplGetBitmapEx(const GraphicConversionParameters& rParameters) const;
+ Animation ImplGetAnimation() const;
+ const GDIMetaFile& ImplGetGDIMetaFile() const;
+
+ Size ImplGetPrefSize() const;
+ void ImplSetPrefSize( const Size& rPrefSize );
+
+ MapMode ImplGetPrefMapMode() const;
+ void ImplSetPrefMapMode( const MapMode& rPrefMapMode );
+
+ ULONG ImplGetSizeBytes() const;
+
+ void ImplDraw( OutputDevice* pOutDev,
+ const Point& rDestPt ) const;
+ void ImplDraw( OutputDevice* pOutDev,
+ const Point& rDestPt,
+ const Size& rDestSize ) const;
+
+ void ImplStartAnimation( OutputDevice* pOutDev,
+ const Point& rDestPt,
+ long nExtraData = 0,
+ OutputDevice* pFirstFrameOutDev = NULL );
+ void ImplStartAnimation( OutputDevice* pOutDev,
+ const Point& rDestPt,
+ const Size& rDestSize,
+ long nExtraData = 0,
+ OutputDevice* pFirstFrameOutDev = NULL );
+ void ImplStopAnimation( OutputDevice* pOutputDevice = NULL,
+ long nExtraData = 0 );
+
+ void ImplSetAnimationNotifyHdl( const Link& rLink );
+ Link ImplGetAnimationNotifyHdl() const;
+
+ ULONG ImplGetAnimationLoopCount() const;
+ void ImplResetAnimationLoopCount();
+
+ List* ImplGetAnimationInfoList() const;
+
+private:
+
+ GraphicReader* ImplGetContext();
+ void ImplSetContext( GraphicReader* pReader );
+
+private:
+
+ void ImplSetDocFileName( const String& rName, ULONG nFilePos );
+ const String& ImplGetDocFileName() const;
+ ULONG ImplGetDocFilePos() const;
+
+ BOOL ImplReadEmbedded( SvStream& rIStream, BOOL bSwap = FALSE );
+ BOOL ImplWriteEmbedded( SvStream& rOStream );
+
+ BOOL ImplSwapIn();
+ BOOL ImplSwapIn( SvStream* pIStm );
+
+ BOOL ImplSwapOut();
+ BOOL ImplSwapOut( SvStream* pOStm );
+
+ BOOL ImplIsSwapOut() const;
+
+ void ImplSetLink( const GfxLink& );
+ GfxLink ImplGetLink();
+ BOOL ImplIsLink() const;
+
+ ULONG ImplGetChecksum() const;
+
+ BOOL ImplExportNative( SvStream& rOStm ) const;
+
+ friend SvStream& operator<<( SvStream& rOStm, const ImpGraphic& rImpGraphic );
+ friend SvStream& operator>>( SvStream& rIStm, ImpGraphic& rImpGraphic );
+};
+
+#endif // _SV_IMPGRAPH_HXX
diff --git a/vcl/inc/vcl/impimagetree.hxx b/vcl/inc/vcl/impimagetree.hxx
new file mode 100644
index 000000000000..9649fe2f5ec8
--- /dev/null
+++ b/vcl/inc/vcl/impimagetree.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 INCLUDED_VCL_IMPIMAGETREE_HXX
+#define INCLUDED_VCL_IMPIMAGETREE_HXX
+
+#include "sal/config.h"
+
+#include <list>
+#include <utility>
+#include <vector>
+
+#include <hash_map>
+
+#include "boost/noncopyable.hpp"
+#include "com/sun/star/uno/Reference.hxx"
+#include "rtl/ustring.hxx"
+#include "salhelper/singletonref.hxx"
+
+namespace com { namespace sun { namespace star { namespace container {
+ class XNameAccess;
+} } } }
+class BitmapEx;
+
+class ImplImageTree: private boost::noncopyable {
+public:
+ ImplImageTree();
+
+ ~ImplImageTree();
+
+ // check whether the icon style is installed
+ bool checkStyle(rtl::OUString const & style);
+
+ bool loadImage(
+ rtl::OUString const & name, rtl::OUString const & style,
+ BitmapEx & bitmap, bool localized = false );
+
+ void shutDown();
+ // a crude form of life cycle control (called from DeInitVCL; otherwise,
+ // if the ImplImageTree singleton were destroyed during exit that would
+ // be too late for the destructors of the bitmaps in m_iconCache)
+
+private:
+ typedef std::list<
+ std::pair<
+ rtl::OUString,
+ com::sun::star::uno::Reference<
+ com::sun::star::container::XNameAccess > > > Zips;
+
+ typedef std::hash_map<
+ rtl::OUString, bool, rtl::OUStringHash > CheckStyleCache;
+ typedef std::hash_map<
+ rtl::OUString, std::pair< bool, BitmapEx >, rtl::OUStringHash > IconCache;
+
+ rtl::OUString m_style;
+ Zips m_zips;
+ CheckStyleCache m_checkStyleCache;
+ IconCache m_iconCache;
+
+ void setStyle(rtl::OUString const & style );
+
+ void resetZips();
+
+ bool checkStyleCacheLookup( rtl::OUString const & style, bool &exists );
+ bool iconCacheLookup( rtl::OUString const & name, bool localized, BitmapEx & bitmap );
+
+ bool find(std::vector< rtl::OUString > const & paths, BitmapEx & bitmap );
+};
+
+typedef salhelper::SingletonRef< ImplImageTree > ImplImageTreeSingletonRef;
+
+#endif
diff --git a/vcl/inc/vcl/impoct.hxx b/vcl/inc/vcl/impoct.hxx
new file mode 100644
index 000000000000..543ab19d6a57
--- /dev/null
+++ b/vcl/inc/vcl/impoct.hxx
@@ -0,0 +1,176 @@
+/*************************************************************************
+ *
+ * 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_IMPOCT_HXX
+#define _SV_IMPOCT_HXX
+
+#include <vcl/octree.hxx>
+
+// ----------------
+// - ImpErrorQuad -
+// ----------------
+
+class ImpErrorQuad
+{
+ long nRed;
+ long nGreen;
+ long nBlue;
+ long nReserved;
+
+public:
+
+ inline ImpErrorQuad() {}
+ inline ImpErrorQuad( const BitmapColor& rColor ) :
+ nRed ( (long) rColor.GetRed() << 5L ),
+ nGreen ( (long) rColor.GetGreen() << 5L ),
+ nBlue ( (long) rColor.GetBlue() << 5L ) {}
+
+ inline void operator=( const BitmapColor& rColor );
+ inline ImpErrorQuad& operator-=( const BitmapColor& rColor );
+
+ inline void ImplAddColorError1( const ImpErrorQuad& rErrQuad );
+ inline void ImplAddColorError3( const ImpErrorQuad& rErrQuad );
+ inline void ImplAddColorError5( const ImpErrorQuad& rErrQuad );
+ inline void ImplAddColorError7( const ImpErrorQuad& rErrQuad );
+
+ inline BitmapColor ImplGetColor();
+};
+
+// ------------------------------------------------------------------------
+
+inline void ImpErrorQuad::operator=( const BitmapColor& rColor )
+{
+ nRed = (long) rColor.GetRed() << 5L;
+ nGreen = (long) rColor.GetGreen() << 5L;
+ nBlue = (long) rColor.GetBlue() << 5L;
+}
+
+// ------------------------------------------------------------------------
+
+inline ImpErrorQuad& ImpErrorQuad::operator-=( const BitmapColor& rColor )
+{
+ nRed -= ( (long) rColor.GetRed() << 5L );
+ nGreen -= ( (long) rColor.GetGreen() << 5L );
+ nBlue -= ( (long) rColor.GetBlue() << 5L );
+
+ return *this;
+}
+
+// ------------------------------------------------------------------------
+
+inline void ImpErrorQuad::ImplAddColorError1( const ImpErrorQuad& rErrQuad )
+{
+ nRed += ( rErrQuad.nRed >> 4L );
+ nGreen += ( rErrQuad.nGreen >> 4L );
+ nBlue += ( rErrQuad.nBlue >> 4L );
+}
+
+// ------------------------------------------------------------------------
+
+inline void ImpErrorQuad::ImplAddColorError3( const ImpErrorQuad& rErrQuad )
+{
+ nRed += ( rErrQuad.nRed * 3L >> 4L );
+ nGreen += ( rErrQuad.nGreen * 3L >> 4L );
+ nBlue += ( rErrQuad.nBlue * 3L >> 4L );
+}
+
+// ------------------------------------------------------------------------
+
+inline void ImpErrorQuad::ImplAddColorError5( const ImpErrorQuad& rErrQuad )
+{
+ nRed += ( rErrQuad.nRed * 5L >> 4L );
+ nGreen += ( rErrQuad.nGreen * 5L >> 4L );
+ nBlue += ( rErrQuad.nBlue * 5L >> 4L );
+}
+
+// ------------------------------------------------------------------------
+
+inline void ImpErrorQuad::ImplAddColorError7( const ImpErrorQuad& rErrQuad )
+{
+ nRed += ( rErrQuad.nRed * 7L >> 4L );
+ nGreen += ( rErrQuad.nGreen * 7L >> 4L );
+ nBlue += ( rErrQuad.nBlue *7L >> 4L );
+}
+
+// ------------------------------------------------------------------------
+
+inline BitmapColor ImpErrorQuad::ImplGetColor()
+{
+ return BitmapColor( (BYTE) ( ( nRed < 0L ? 0L : nRed > 8160L ? 8160L : nRed ) >> 5L ),
+ (BYTE) ( ( nGreen < 0L ? 0L : nGreen > 8160L ? 8160L : nGreen ) >> 5L ),
+ (BYTE) ( ( nBlue < 0L ? 0L : nBlue > 8160L ? 8160L : nBlue ) >> 5L ) );
+}
+
+// -------------
+// - NodeCache -
+// -------------
+
+class ImpNodeCache
+{
+ OctreeNode* pActNode;
+ ULONG nNew;
+ ULONG nDelete;
+ ULONG nGet;
+ ULONG nRelease;
+
+public:
+
+ ImpNodeCache( const ULONG nInitSize );
+ ~ImpNodeCache();
+
+ inline OctreeNode* ImplGetFreeNode();
+ inline void ImplReleaseNode( OctreeNode* pNode );
+};
+
+// ------------------------------------------------------------------------
+
+inline OctreeNode* ImpNodeCache::ImplGetFreeNode()
+{
+ OctreeNode* pNode;
+
+ if ( !pActNode )
+ {
+ pActNode = new NODE;
+ pActNode->pNextInCache = NULL;
+ }
+
+ pNode = pActNode;
+ pActNode = pNode->pNextInCache;
+ memset( pNode, 0, sizeof( NODE ) );
+
+ return pNode;
+}
+
+// ------------------------------------------------------------------------
+
+inline void ImpNodeCache::ImplReleaseNode( OctreeNode* pNode )
+{
+ pNode->pNextInCache = pActNode;
+ pActNode = pNode;
+}
+
+#endif // _SV_IMPOCT_HXX
diff --git a/vcl/inc/vcl/impprn.hxx b/vcl/inc/vcl/impprn.hxx
new file mode 100644
index 000000000000..954b2340d0c7
--- /dev/null
+++ b/vcl/inc/vcl/impprn.hxx
@@ -0,0 +1,140 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#if 0
+#define _SV_IMPPRN_HXX
+
+#include <vcl/print.hxx>
+#include <vcl/timer.hxx>
+#ifndef _VCL_IMPDEL_HXX
+#include <vcl/impdel.hxx>
+#endif
+
+#include <vector>
+
+struct QueuePage;
+
+// ----------------
+// - ImplQPrinter -
+// ----------------
+
+/*
+ ImplQPrinter is on most systems a simple buffer that allows a potential
+ lengthy print job to be printed in the background. For this it saves all
+ normal drawing operations for each printed page to a metafile, then spooling
+ the metafiles timer based to a normal printer. The application can act in the meantime
+ including changing the original document without influencing the print job.
+
+ On some systems (currently Mac/Aqua Cocoa) ImplQPrinter has the additional
+ purpose of adapting to the print system: here theprint systems starts a
+ job and will not return from that function until it has ended; to do so
+ it queries for each consecutive page to be printed. Also the Cocoa print system
+ needs to know the number of pages BEFORE starting a print job. Since our Printer
+ does not know that, we need to do the completing spooling to ImplQPrinter before
+ we can actually print to the real print system. Let's call this the pull model
+ instead of the push model (because the systems pulls the pages).
+*/
+
+class ImplQPrinter : public Printer, public vcl::DeletionNotifier
+{
+private:
+ Printer* mpParent;
+ std::vector< QueuePage* > maQueue;
+ AutoTimer maTimer;
+ bool mbAborted;
+ bool mbUserCopy;
+ bool mbDestroyAllowed;
+ bool mbDestroyed;
+
+ GDIMetaFile maCurPageMetaFile;
+ long mnMaxBmpDPIX;
+ long mnMaxBmpDPIY;
+ ULONG mnRestoreDrawMode;
+ int mnCurCopyCount;
+
+ DECL_LINK( ImplPrintHdl, Timer* );
+
+ ~ImplQPrinter();
+
+ void ImplPrintMtf( GDIMetaFile& rMtf, long nMaxBmpDPIX, long nMaxBmpDPIY );
+
+ ImplQPrinter( const ImplQPrinter& rPrinter );
+ Printer& operator =( const ImplQPrinter& rPrinter );
+
+ void PrePrintPage( QueuePage* );
+ void PostPrintPage();
+
+public:
+
+ ImplQPrinter( Printer* pParent );
+ void Destroy();
+
+ void StartQueuePrint();
+ void EndQueuePrint();
+ void AbortQueuePrint();
+ void AddQueuePage( GDIMetaFile* pPage, USHORT nPage, BOOL bNewJobSetup );
+
+ bool IsUserCopy() const { return mbUserCopy; }
+ void SetUserCopy( bool bSet ) { mbUserCopy = bSet; }
+
+ /**
+ used by pull implementation to emit the next page
+ */
+ void PrintPage( unsigned int nPage );
+ /**
+ used by pull implementation to get the number of physical pages
+ (that is how often PrintNextPage should be called)
+ */
+ ULONG GetPrintPageCount() const;
+
+ /**
+ used by pull implementation to get ranges of physical pages that
+ are to be printed on the same paper. If bIncludeOrientationChanges is true
+ then orientation changes will not break a page run; the implementation has
+ to rotate the page contents accordingly in that case.
+
+ The returned vector contains all pages indices beginning a new medium and additionally
+ the index that of the last page+1 (for convenience, so the length of a range
+ is always v[i+1] - v[i])
+
+ Example: 5 pages, all A4
+ return: [0 5]
+
+ Example: 6 pages, beginning A4, switching tol A5 on fourth page, back to A4 on fifth page
+ return [0 3 4 6]
+
+ returns an false in push model (error condition)
+ */
+ bool GetPaperRanges( std::vector< ULONG >& o_rRanges, bool i_bIncludeOrientationChanges ) const;
+
+ /**
+ get the jobsetup for a page
+ */
+ ImplJobSetup* GetPageSetup( unsigned int nPage ) const;
+};
+
+#endif // _SV_IMPPRN_HXX
diff --git a/vcl/inc/vcl/inputctx.hxx b/vcl/inc/vcl/inputctx.hxx
new file mode 100644
index 000000000000..5e7cffa29dc6
--- /dev/null
+++ b/vcl/inc/vcl/inputctx.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _VCL_INPUTCTX_HXX
+#define _VCL_INPUTCTX_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/font.hxx>
+
+// ----------------------
+// - InputContext-Flags -
+// ----------------------
+
+#define INPUTCONTEXT_TEXT ((ULONG)0x00000001)
+#define INPUTCONTEXT_EXTTEXTINPUT ((ULONG)0x00000002)
+#define INPUTCONTEXT_EXTTEXTINPUT_ON ((ULONG)0x00000004)
+#define INPUTCONTEXT_EXTTEXTINPUT_OFF ((ULONG)0x00000008)
+
+// ----------------
+// - InputContext -
+// ----------------
+
+class VCL_DLLPUBLIC InputContext
+{
+private:
+ Font maFont;
+ ULONG mnOptions;
+
+public:
+ InputContext() { mnOptions = 0; }
+ InputContext( const InputContext& rInputContext ) :
+ maFont( rInputContext.maFont )
+ { mnOptions = rInputContext.mnOptions; }
+ InputContext( const Font& rFont, ULONG nOptions = 0 ) :
+ maFont( rFont )
+ { mnOptions = nOptions; }
+
+ void SetFont( const Font& rFont ) { maFont = rFont; }
+ const Font& GetFont() const { return maFont; }
+
+ void SetOptions( ULONG nOptions ) { mnOptions = nOptions; }
+ ULONG GetOptions() const { return mnOptions; }
+
+ InputContext& operator=( const InputContext& rInputContext );
+ BOOL operator==( const InputContext& rInputContext ) const;
+ BOOL operator!=( const InputContext& rInputContext ) const
+ { return !(InputContext::operator==( rInputContext )); }
+};
+
+inline InputContext& InputContext::operator=( const InputContext& rInputContext )
+{
+ maFont = rInputContext.maFont;
+ mnOptions = rInputContext.mnOptions;
+ return *this;
+}
+
+inline BOOL InputContext::operator==( const InputContext& rInputContext ) const
+{
+ return ((mnOptions == rInputContext.mnOptions) &&
+ (maFont == rInputContext.maFont));
+}
+
+#endif // _VCL_INPUTCTX_HXX
diff --git a/vcl/inc/vcl/introwin.hxx b/vcl/inc/vcl/introwin.hxx
new file mode 100644
index 000000000000..40644019bc15
--- /dev/null
+++ b/vcl/inc/vcl/introwin.hxx
@@ -0,0 +1,53 @@
+/*************************************************************************
+ *
+ * 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_INTROWIN_HXX
+#define _SV_INTROWIN_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/wrkwin.hxx>
+#include <vcl/bitmapex.hxx>
+
+// --------------
+// - IntroWindow -
+// --------------
+
+class VCL_DLLPUBLIC IntroWindow : public WorkWindow
+{
+private:
+ SAL_DLLPRIVATE void ImplInitIntroWindowData();
+
+public:
+ IntroWindow();
+ ~IntroWindow();
+
+ void SetBackgroundBitmap( const Bitmap& rBitmap );
+ void SetBackgroundBitmap( const BitmapEx& rBitmapEx );
+};
+
+#endif // _SV_INTROWIN_HXX
diff --git a/vcl/inc/vcl/javachild.hxx b/vcl/inc/vcl/javachild.hxx
new file mode 100644
index 000000000000..62b447f26571
--- /dev/null
+++ b/vcl/inc/vcl/javachild.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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_JAVACHILD_HXX
+#define _SV_JAVACHILD_HXX
+
+#include <vcl/dllapi.h>
+#include <vcl/syschild.hxx>
+
+// -------------------
+// - JavaChildWindow -
+// -------------------
+
+class VCL_DLLPUBLIC JavaChildWindow : public SystemChildWindow
+{
+public:
+
+ JavaChildWindow( Window* pParent, WinBits nStyle = 0 );
+ JavaChildWindow( Window* pParent, const ResId& rResId );
+ ~JavaChildWindow();
+
+ sal_IntPtr getParentWindowHandleForJava();
+
+private:
+
+ SAL_DLLPRIVATE void implTestJavaException( void* pEnv );
+
+ // Copy assignment is forbidden and not implemented.
+ SAL_DLLPRIVATE JavaChildWindow (const JavaChildWindow &);
+ SAL_DLLPRIVATE JavaChildWindow & operator= (const JavaChildWindow &);
+};
+
+#endif // _SV_JAVACHILD_HXX
diff --git a/vcl/inc/vcl/jobdata.hxx b/vcl/inc/vcl/jobdata.hxx
new file mode 100644
index 000000000000..f576b816dab0
--- /dev/null
+++ b/vcl/inc/vcl/jobdata.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _PSPRINT_JOBDATA_HXX_
+#define _PSPRINT_JOBDATA_HXX_
+
+#include "vcl/ppdparser.hxx"
+
+namespace psp {
+
+namespace orientation {
+enum type {
+ Portrait,
+ Landscape
+};
+}
+
+struct JobData
+{
+ int m_nCopies;
+ int m_nLeftMarginAdjust;
+ int m_nRightMarginAdjust;
+ int m_nTopMarginAdjust;
+ int m_nBottomMarginAdjust;
+ // user overrides for PPD
+ int m_nColorDepth;
+ int m_nPSLevel; // 0: no override, else languaglevel to use
+ int m_nColorDevice; // 0: no override, -1 grey scale, +1 color
+ orientation::type m_eOrientation;
+ ::rtl::OUString m_aPrinterName;
+ const PPDParser* m_pParser;
+ PPDContext m_aContext;
+
+ JobData() :
+ m_nCopies( 1 ),
+ m_nLeftMarginAdjust( 0 ),
+ m_nRightMarginAdjust( 0 ),
+ m_nTopMarginAdjust( 0 ),
+ m_nBottomMarginAdjust( 0 ),
+ m_nColorDepth( 24 ),
+ m_nPSLevel( 0 ),
+ m_nColorDevice( 0 ),
+ m_eOrientation( orientation::Portrait ),
+ m_pParser( NULL ) {}
+
+ JobData& operator=(const psp::JobData& rRight);
+
+ JobData( const JobData& rData ) { *this = rData; }
+
+ void setCollate( bool bCollate );
+
+ // creates a new buffer using new
+ // it is up to the user to delete it again
+ bool getStreamBuffer( void*& pData, int& bytes );
+ static bool constructFromStreamBuffer( void* pData, int bytes, JobData& rJobData );
+};
+
+} // namespace
+
+
+#endif // PSPRINT_JOBDATA_HXX
diff --git a/vcl/inc/vcl/jobset.h b/vcl/inc/vcl/jobset.h
new file mode 100644
index 000000000000..2a8be4a6999e
--- /dev/null
+++ b/vcl/inc/vcl/jobset.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_JOBSET_H
+#define _SV_JOBSET_H
+
+#include <tools/string.hxx>
+#include <vcl/sv.h>
+#include <vcl/prntypes.hxx>
+#include <hash_map>
+#include <rtl/ustring.hxx>
+
+// ------------------
+// - JobSetup-Types -
+// ------------------
+
+// see com.sun.star.portal.client.JobSetupSystem.idl:
+#define JOBSETUP_SYSTEM_DONTKNOW 0
+#define JOBSETUP_SYSTEM_WINDOWS 1
+#define JOBSETUP_SYSTEM_OS2 2
+#define JOBSETUP_SYSTEM_UNIX 3
+#define JOBSETUP_SYSTEM_MAC 4
+#define JOBSETUP_SYSTEM_JAVA 5
+
+// ----------------
+// - ImplJobSetup -
+// ----------------
+
+struct ImplJobSetup
+{
+ USHORT mnRefCount; // RefCount (only independ data)
+ USHORT mnSystem; // Sytem - JOBSETUP_SYSTEM_xxxx
+ String maPrinterName; // Printer-Name
+ String maDriver; // Driver-Name
+ Orientation meOrientation; // Orientation
+ DuplexMode meDuplexMode; // Duplex
+ USHORT mnPaperBin; // paper bin / in tray
+ Paper mePaperFormat; // paper format
+ long mnPaperWidth; // paper width (100th mm)
+ long mnPaperHeight; // paper height (100th mm)
+ ULONG mnDriverDataLen; // length of system specific data
+ BYTE* mpDriverData; // system specific data (will be streamed a byte block)
+ ::std::hash_map< ::rtl::OUString, ::rtl::OUString, ::rtl::OUStringHash > maValueMap;
+
+ ImplJobSetup();
+ ImplJobSetup( const ImplJobSetup& rJobSetup );
+ ~ImplJobSetup();
+};
+
+// Papierformat wird wenn PAPER_USER im unabhaengigen Teil automatisch aus
+// Papierbreite/hoehe berechnet
+// Papierbreite/hoehe wird wenn 0 im unabhaengigen Teil automatisch aus
+// Papierformat berechnet, wenn dieses ungleich PAPER_USER ist
+
+#endif // _SV_JOBSET_H
diff --git a/vcl/inc/vcl/jobset.hxx b/vcl/inc/vcl/jobset.hxx
new file mode 100644
index 000000000000..4228fc8e90e1
--- /dev/null
+++ b/vcl/inc/vcl/jobset.hxx
@@ -0,0 +1,83 @@
+/*************************************************************************
+ *
+ * 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_JOBSET_HXX
+#define _SV_JOBSET_HXX
+
+#include <tools/string.hxx>
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/prntypes.hxx>
+
+class SvStream;
+struct ImplJobSetup;
+
+// ------------
+// - JobSetup -
+// ------------
+
+class VCL_DLLPUBLIC JobSetup
+{
+ friend class Printer;
+
+private:
+ ImplJobSetup* mpData;
+
+//#if 0 // _SOLAR__PRIVATE
+public:
+ SAL_DLLPRIVATE ImplJobSetup* ImplGetData();
+ SAL_DLLPRIVATE ImplJobSetup* ImplGetConstData();
+ SAL_DLLPRIVATE const ImplJobSetup* ImplGetConstData() const;
+//#endif
+
+public:
+ JobSetup();
+ JobSetup( const JobSetup& rJob );
+ ~JobSetup();
+
+ String GetPrinterName() const;
+ String GetDriverName() const;
+
+ /* Get/SetValue are used to read/store additional
+ * Parameters in the job setup that may be used
+ * by the printer driver. One possible use are phone
+ * numbers for faxes (which disguise as printers)
+ */
+ String GetValue( const String& rKey ) const;
+ void SetValue( const String& rKey, const String& rValue );
+
+ JobSetup& operator=( const JobSetup& rJob );
+
+ BOOL operator==( const JobSetup& rJobSetup ) const;
+ BOOL operator!=( const JobSetup& rJobSetup ) const
+ { return !(JobSetup::operator==( rJobSetup )); }
+
+ friend VCL_DLLPUBLIC SvStream& operator>>( SvStream& rIStream, JobSetup& rJobSetup );
+ friend VCL_DLLPUBLIC SvStream& operator<<( SvStream& rOStream, const JobSetup& rJobSetup );
+};
+
+#endif // _SV_JOBSET_HXX
diff --git a/vcl/inc/vcl/keycod.hxx b/vcl/inc/vcl/keycod.hxx
new file mode 100644
index 000000000000..487dea1d7c2f
--- /dev/null
+++ b/vcl/inc/vcl/keycod.hxx
@@ -0,0 +1,157 @@
+/*************************************************************************
+ *
+ * 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_KEYCODE_HXX
+#define _SV_KEYCODE_HXX
+
+#include <tools/string.hxx>
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <tools/resid.hxx>
+#include <vcl/keycodes.hxx>
+
+#include <vcl/vclenum.hxx>
+
+class Window;
+
+// -------------
+// - Key-Types -
+// -------------
+
+// Logische KeyFunktionen
+/*
+#ifndef ENUM_KEYFUNCTYPE_DECLARED
+#define ENUM_KEYFUNCTYPE_DECLARED
+enum KeyFuncType { KEYFUNC_DONTKNOW, KEYFUNC_NEW, KEYFUNC_OPEN,
+ KEYFUNC_SAVE, KEYFUNC_SAVEAS, KEYFUNC_PRINT,
+ KEYFUNC_CLOSE, KEYFUNC_QUIT,
+ KEYFUNC_CUT, KEYFUNC_COPY, KEYFUNC_PASTE, KEYFUNC_UNDO,
+ KEYFUNC_REDO, KEYFUNC_DELETE, KEYFUNC_REPEAT,
+ KEYFUNC_FIND, KEYFUNC_FINDBACKWARD, KEYFUNC_PROPERTIES,
+ KEYFUNC_FRONT };
+#endif
+*/
+// -----------
+// - KeyCode -
+// -----------
+
+class VCL_DLLPUBLIC KeyCode
+{
+private:
+ USHORT nCode;
+ KeyFuncType eFunc;
+
+public:
+ KeyCode() { nCode = 0; eFunc = KEYFUNC_DONTKNOW; }
+ KeyCode( const ResId& rResId );
+ KeyCode( USHORT nKey, USHORT nModifier = 0 )
+ { nCode = nKey | nModifier; eFunc = KEYFUNC_DONTKNOW; }
+ KeyCode( USHORT nKey, BOOL bShift, BOOL bMod1, BOOL bMod2, BOOL bMod3 );
+ KeyCode( KeyFuncType eFunction );
+
+ USHORT GetFullCode() const { return nCode; }
+ USHORT GetFullKeyCode() const { return (nCode) ; }
+ KeyFuncType GetFullFunction() const { return eFunc; }
+ BOOL IsDefinedKeyCodeEqual( const KeyCode& rKeyCode ) const;
+
+ USHORT GetCode() const
+ { return (nCode & KEY_CODE); }
+
+ USHORT GetModifier() const
+ { return (nCode & KEY_MODTYPE); }
+ USHORT GetAllModifier() const
+ { return (nCode & KEY_ALLMODTYPE); }
+ BOOL IsShift() const
+ { return ((nCode & KEY_SHIFT) != 0); }
+ BOOL IsMod1() const
+ { return ((nCode & KEY_MOD1) != 0); }
+ BOOL IsMod2() const
+ { return ((nCode & KEY_MOD2) != 0); }
+ BOOL IsMod3() const
+ { return ((nCode & KEY_MOD3) != 0); }
+ USHORT GetGroup() const
+ { return (nCode & KEYGROUP_TYPE); }
+
+ XubString GetName( Window* pWindow = NULL ) const;
+ XubString GetSymbolName( const XubString& rFontName, Window* pWindow = NULL ) const;
+
+ BOOL IsFunction() const
+ { return ((eFunc != KEYFUNC_DONTKNOW) ? TRUE : FALSE); }
+
+ KeyFuncType GetFunction() const;
+
+ KeyCode& operator = ( const KeyCode& rKeyCode );
+ BOOL operator ==( const KeyCode& rKeyCode ) const;
+ BOOL operator !=( const KeyCode& rKeyCode ) const;
+};
+
+inline KeyCode::KeyCode( USHORT nKey, BOOL bShift, BOOL bMod1, BOOL bMod2, BOOL bMod3 )
+{
+ nCode = nKey;
+ if( bShift )
+ nCode |= KEY_SHIFT;
+ if( bMod1 )
+ nCode |= KEY_MOD1;
+ if( bMod2 )
+ nCode |= KEY_MOD2;
+ if( bMod3 )
+ nCode |= KEY_MOD3;
+ eFunc = KEYFUNC_DONTKNOW;
+}
+
+inline BOOL KeyCode::operator ==( const KeyCode& rKeyCode ) const
+{
+ if ( (eFunc == KEYFUNC_DONTKNOW) && (rKeyCode.eFunc == KEYFUNC_DONTKNOW) )
+ return (nCode == rKeyCode.nCode);
+ else
+ return (GetFunction() == rKeyCode.GetFunction());
+}
+
+inline BOOL KeyCode::operator !=( const KeyCode& rKeyCode ) const
+{
+ if ( (eFunc == KEYFUNC_DONTKNOW) && (rKeyCode.eFunc == KEYFUNC_DONTKNOW) )
+ return (nCode != rKeyCode.nCode);
+ else
+ return (GetFunction() != rKeyCode.GetFunction());
+}
+
+inline BOOL KeyCode::IsDefinedKeyCodeEqual( const KeyCode& rKeyCode ) const
+{
+ if ( (eFunc == KEYFUNC_DONTKNOW) && (rKeyCode.eFunc == KEYFUNC_DONTKNOW) )
+ return (GetFullKeyCode() == rKeyCode.GetFullKeyCode());
+ return (GetFunction() == rKeyCode.GetFunction());
+}
+
+inline KeyCode& KeyCode::operator = ( const KeyCode& rKeyCode )
+{
+ nCode = rKeyCode.nCode;
+ eFunc = rKeyCode.eFunc;
+
+ return *this;
+}
+
+#endif // _SV_KEYCODE_HXX
diff --git a/vcl/inc/vcl/keycodes.hxx b/vcl/inc/vcl/keycodes.hxx
new file mode 100644
index 000000000000..cfd4d11c9a7c
--- /dev/null
+++ b/vcl/inc/vcl/keycodes.hxx
@@ -0,0 +1,191 @@
+/*************************************************************************
+ *
+ * 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_KEYCODES_HXX
+#define _SV_KEYCODES_HXX
+
+#include <vcl/sv.h>
+#include <com/sun/star/awt/Key.hpp>
+#include <com/sun/star/awt/KeyGroup.hpp>
+
+// -----------------
+// - KeyCode-Types -
+// -----------------
+
+// By changes you must also change: rsc/vclrsc.hxx
+
+// Key-Gruppen
+#define KEYGROUP_NUM ((USHORT)::com::sun::star::awt::KeyGroup::NUM)
+#define KEYGROUP_ALPHA ((USHORT)::com::sun::star::awt::KeyGroup::ALPHA)
+#define KEYGROUP_FKEYS ((USHORT)::com::sun::star::awt::KeyGroup::FKEYS)
+#define KEYGROUP_CURSOR ((USHORT)::com::sun::star::awt::KeyGroup::CURSOR)
+#define KEYGROUP_MISC ((USHORT)::com::sun::star::awt::KeyGroup::MISC)
+#define KEYGROUP_TYPE ((USHORT)::com::sun::star::awt::KeyGroup::TYPE)
+
+// Key-Codes
+#define KEY_0 ((USHORT)::com::sun::star::awt::Key::NUM0)
+#define KEY_1 ((USHORT)::com::sun::star::awt::Key::NUM1)
+#define KEY_2 ((USHORT)::com::sun::star::awt::Key::NUM2)
+#define KEY_3 ((USHORT)::com::sun::star::awt::Key::NUM3)
+#define KEY_4 ((USHORT)::com::sun::star::awt::Key::NUM4)
+#define KEY_5 ((USHORT)::com::sun::star::awt::Key::NUM5)
+#define KEY_6 ((USHORT)::com::sun::star::awt::Key::NUM6)
+#define KEY_7 ((USHORT)::com::sun::star::awt::Key::NUM7)
+#define KEY_8 ((USHORT)::com::sun::star::awt::Key::NUM8)
+#define KEY_9 ((USHORT)::com::sun::star::awt::Key::NUM9)
+
+#define KEY_A ((USHORT)::com::sun::star::awt::Key::A)
+#define KEY_B ((USHORT)::com::sun::star::awt::Key::B)
+#define KEY_C ((USHORT)::com::sun::star::awt::Key::C)
+#define KEY_D ((USHORT)::com::sun::star::awt::Key::D)
+#define KEY_E ((USHORT)::com::sun::star::awt::Key::E)
+#define KEY_F ((USHORT)::com::sun::star::awt::Key::F)
+#define KEY_G ((USHORT)::com::sun::star::awt::Key::G)
+#define KEY_H ((USHORT)::com::sun::star::awt::Key::H)
+#define KEY_I ((USHORT)::com::sun::star::awt::Key::I)
+#define KEY_J ((USHORT)::com::sun::star::awt::Key::J)
+#define KEY_K ((USHORT)::com::sun::star::awt::Key::K)
+#define KEY_L ((USHORT)::com::sun::star::awt::Key::L)
+#define KEY_M ((USHORT)::com::sun::star::awt::Key::M)
+#define KEY_N ((USHORT)::com::sun::star::awt::Key::N)
+#define KEY_O ((USHORT)::com::sun::star::awt::Key::O)
+#define KEY_P ((USHORT)::com::sun::star::awt::Key::P)
+#define KEY_Q ((USHORT)::com::sun::star::awt::Key::Q)
+#define KEY_R ((USHORT)::com::sun::star::awt::Key::R)
+#define KEY_S ((USHORT)::com::sun::star::awt::Key::S)
+#define KEY_T ((USHORT)::com::sun::star::awt::Key::T)
+#define KEY_U ((USHORT)::com::sun::star::awt::Key::U)
+#define KEY_V ((USHORT)::com::sun::star::awt::Key::V)
+#define KEY_W ((USHORT)::com::sun::star::awt::Key::W)
+#define KEY_X ((USHORT)::com::sun::star::awt::Key::X)
+#define KEY_Y ((USHORT)::com::sun::star::awt::Key::Y)
+#define KEY_Z ((USHORT)::com::sun::star::awt::Key::Z)
+
+#define KEY_F1 ((USHORT)::com::sun::star::awt::Key::F1)
+#define KEY_F2 ((USHORT)::com::sun::star::awt::Key::F2)
+#define KEY_F3 ((USHORT)::com::sun::star::awt::Key::F3)
+#define KEY_F4 ((USHORT)::com::sun::star::awt::Key::F4)
+#define KEY_F5 ((USHORT)::com::sun::star::awt::Key::F5)
+#define KEY_F6 ((USHORT)::com::sun::star::awt::Key::F6)
+#define KEY_F7 ((USHORT)::com::sun::star::awt::Key::F7)
+#define KEY_F8 ((USHORT)::com::sun::star::awt::Key::F8)
+#define KEY_F9 ((USHORT)::com::sun::star::awt::Key::F9)
+#define KEY_F10 ((USHORT)::com::sun::star::awt::Key::F10)
+#define KEY_F11 ((USHORT)::com::sun::star::awt::Key::F11)
+#define KEY_F12 ((USHORT)::com::sun::star::awt::Key::F12)
+#define KEY_F13 ((USHORT)::com::sun::star::awt::Key::F13)
+#define KEY_F14 ((USHORT)::com::sun::star::awt::Key::F14)
+#define KEY_F15 ((USHORT)::com::sun::star::awt::Key::F15)
+#define KEY_F16 ((USHORT)::com::sun::star::awt::Key::F16)
+#define KEY_F17 ((USHORT)::com::sun::star::awt::Key::F17)
+#define KEY_F18 ((USHORT)::com::sun::star::awt::Key::F18)
+#define KEY_F19 ((USHORT)::com::sun::star::awt::Key::F19)
+#define KEY_F20 ((USHORT)::com::sun::star::awt::Key::F20)
+#define KEY_F21 ((USHORT)::com::sun::star::awt::Key::F21)
+#define KEY_F22 ((USHORT)::com::sun::star::awt::Key::F22)
+#define KEY_F23 ((USHORT)::com::sun::star::awt::Key::F23)
+#define KEY_F24 ((USHORT)::com::sun::star::awt::Key::F24)
+#define KEY_F25 ((USHORT)::com::sun::star::awt::Key::F25)
+#define KEY_F26 ((USHORT)::com::sun::star::awt::Key::F26)
+
+#define KEY_DOWN ((USHORT)::com::sun::star::awt::Key::DOWN)
+#define KEY_UP ((USHORT)::com::sun::star::awt::Key::UP)
+#define KEY_LEFT ((USHORT)::com::sun::star::awt::Key::LEFT)
+#define KEY_RIGHT ((USHORT)::com::sun::star::awt::Key::RIGHT)
+#define KEY_HOME ((USHORT)::com::sun::star::awt::Key::HOME)
+#define KEY_END ((USHORT)::com::sun::star::awt::Key::END)
+#define KEY_PAGEUP ((USHORT)::com::sun::star::awt::Key::PAGEUP)
+#define KEY_PAGEDOWN ((USHORT)::com::sun::star::awt::Key::PAGEDOWN)
+
+#define KEY_RETURN ((USHORT)::com::sun::star::awt::Key::RETURN)
+#define KEY_ESCAPE ((USHORT)::com::sun::star::awt::Key::ESCAPE)
+#define KEY_TAB ((USHORT)::com::sun::star::awt::Key::TAB)
+#define KEY_BACKSPACE ((USHORT)::com::sun::star::awt::Key::BACKSPACE)
+#define KEY_SPACE ((USHORT)::com::sun::star::awt::Key::SPACE)
+#define KEY_INSERT ((USHORT)::com::sun::star::awt::Key::INSERT)
+#define KEY_DELETE ((USHORT)::com::sun::star::awt::Key::DELETE)
+
+#define KEY_ADD ((USHORT)::com::sun::star::awt::Key::ADD)
+#define KEY_SUBTRACT ((USHORT)::com::sun::star::awt::Key::SUBTRACT)
+#define KEY_MULTIPLY ((USHORT)::com::sun::star::awt::Key::MULTIPLY)
+#define KEY_DIVIDE ((USHORT)::com::sun::star::awt::Key::DIVIDE)
+#define KEY_POINT ((USHORT)::com::sun::star::awt::Key::POINT)
+#define KEY_COMMA ((USHORT)::com::sun::star::awt::Key::COMMA)
+#define KEY_LESS ((USHORT)::com::sun::star::awt::Key::LESS)
+#define KEY_GREATER ((USHORT)::com::sun::star::awt::Key::GREATER)
+#define KEY_EQUAL ((USHORT)::com::sun::star::awt::Key::EQUAL)
+
+#define KEY_OPEN ((USHORT)::com::sun::star::awt::Key::OPEN)
+#define KEY_CUT ((USHORT)::com::sun::star::awt::Key::CUT)
+#define KEY_COPY ((USHORT)::com::sun::star::awt::Key::COPY)
+#define KEY_PASTE ((USHORT)::com::sun::star::awt::Key::PASTE)
+#define KEY_UNDO ((USHORT)::com::sun::star::awt::Key::UNDO)
+#define KEY_REPEAT ((USHORT)::com::sun::star::awt::Key::REPEAT)
+#define KEY_FIND ((USHORT)::com::sun::star::awt::Key::FIND)
+#define KEY_PROPERTIES ((USHORT)::com::sun::star::awt::Key::PROPERTIES)
+#define KEY_FRONT ((USHORT)::com::sun::star::awt::Key::FRONT)
+#define KEY_CONTEXTMENU ((USHORT)::com::sun::star::awt::Key::CONTEXTMENU)
+#define KEY_MENU ((USHORT)::com::sun::star::awt::Key::MENU)
+#define KEY_HELP ((USHORT)::com::sun::star::awt::Key::HELP)
+#define KEY_HANGUL_HANJA ((USHORT)::com::sun::star::awt::Key::HANGUL_HANJA)
+#define KEY_DECIMAL ((USHORT)::com::sun::star::awt::Key::DECIMAL)
+#define KEY_TILDE ((USHORT)::com::sun::star::awt::Key::TILDE)
+#define KEY_QUOTELEFT ((USHORT)::com::sun::star::awt::Key::QUOTELEFT)
+
+#define KEY_CODE ((USHORT)0x0FFF)
+
+// Modifier-Tasten
+#define KEY_SHIFT ((USHORT)0x1000)
+#define KEY_MOD1 ((USHORT)0x2000)
+#define KEY_MOD2 ((USHORT)0x4000)
+#define KEY_MOD3 ((USHORT)0x8000)
+#define KEY_MODTYPE ((USHORT)0xF000)
+#define KEY_ALLMODTYPE ((USHORT)0xF000)
+
+// extended Modifier-Keys (only used for modkey events)
+#define MODKEY_LSHIFT 0x0001
+#define MODKEY_RSHIFT 0x0002
+#define MODKEY_LMOD1 0x0004
+#define MODKEY_RMOD1 0x0008
+#define MODKEY_LMOD2 0x0010
+#define MODKEY_RMOD2 0x0020
+#define MODKEY_LMOD3 0x0040
+#define MODKEY_RMOD3 0x0080
+#define MODKEY_SHIFT (MODKEY_LSHIFT|MODKEY_RSHIFT)
+#define MODKEY_MOD1 (MODKEY_LMOD1|MODKEY_RMOD1)
+#define MODKEY_MOD2 (MODKEY_LMOD2|MODKEY_RMOD2)
+#define MODKEY_MOD3 (MODKEY_LMOD3|MODKEY_RMOD3)
+
+// ---------------
+// - Mouse-Types -
+// ---------------
+
+#define MOUSE_LEFT ((USHORT)0x0001)
+#define MOUSE_MIDDLE ((USHORT)0x0002)
+#define MOUSE_RIGHT ((USHORT)0x0004)
+
+#endif // _SV_KEYCODES_HXX
diff --git a/vcl/inc/vcl/lazydelete.hxx b/vcl/inc/vcl/lazydelete.hxx
new file mode 100644
index 000000000000..4176d5b4454f
--- /dev/null
+++ b/vcl/inc/vcl/lazydelete.hxx
@@ -0,0 +1,262 @@
+/*************************************************************************
+ *
+ * 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_LAZYDELETE_HXX
+#define _VCL_LAZYDELETE_HXX
+
+#include "dllapi.h"
+
+#include <vector>
+#include <hash_map>
+#include <algorithm>
+
+#if OSL_DEBUG_LEVEL > 2
+#include <typeinfo>
+#include <stdio.h>
+#endif
+
+namespace vcl
+{
+ /* Helpers for lazy object deletion
+
+ With vcl it is often necessary to delete objects (especially Windows)
+ in the right order as well as in a way ensuring that the deleted objects
+ are not still on the stack (e.g. deleting a Window in its key handler). To
+ make this easier a helper class is given here which takes care of both
+ sorting as well as lazy deletion.
+
+ The grisly details:
+ LazyDelete is a class that LazyDeletor register to. When vcl's event
+ loop (that is Application::Yield or Application::Reschedule) comes out
+ of the last level, the LazyDelete::flush is called. This will cause
+ LazyDelete to delete all registered LazyDeletor objects.
+
+ LazyDeletor<T> is a one instance object that contains a list of
+ <T> objects to be deleted in sorted order. It is derived from
+ LazyDeletorBase as to be able to register itself in LazyDelete.
+
+ The user calls the static method LazyDeletor<T>::Delete( T* ) with the
+ object to be destroyed lazy. The static method creates the LazyDeletor<T>
+ (which in turn registers itself in LazyDelete) if this is the first time
+ a T* is to be destroyed lazy. It then inserts the object. When the LazyDeletor<T>
+ gets delte it will delete the stored objects in a fashion
+ that will ensure the correct order of deletion via the specialized is_less method
+ (e.g. if a Window is a child of another Window and therefore should be destroyed
+ first it is "less" in this sense)
+
+ LazyDelete::flush will be called when the top of the nested event loop is
+ reached again and will then destroy each registered LazyDeletor<T> which
+ in turn destroys the objects needed to be destroyed lazily. After this
+ the state is as before entering the event loop.
+
+ Preconditions:
+ - The class <T> of which objects are to be destroyed needs a virtual
+ destructor or must be final, else the wrong type will be destroyed.
+ - The destructor of <T> should call LazyDeletor<T>::Undelete( this ). This
+ prevents duplicate deletionin case someone destroys the object prematurely.
+ */
+
+ class LazyDeletorBase;
+ class VCL_DLLPUBLIC LazyDelete
+ {
+ public:
+ /** flush all registered object lists
+ */
+ static void flush();
+ /** register an object list to be destroyed
+ */
+ static void addDeletor( LazyDeletorBase* pDeletor );
+ };
+
+ class VCL_DLLPUBLIC LazyDeletorBase
+ {
+ friend void LazyDelete::flush();
+ protected:
+ LazyDeletorBase();
+ virtual ~LazyDeletorBase();
+ };
+
+ template < typename T >
+ class VCL_DLLPUBLIC LazyDeletor : public LazyDeletorBase
+ {
+ static LazyDeletor< T >* s_pOneInstance;
+
+ struct DeleteObjectEntry
+ {
+ T* m_pObject;
+ bool m_bDeleted;
+
+ DeleteObjectEntry() :
+ m_pObject( NULL ),
+ m_bDeleted( false )
+ {}
+
+ DeleteObjectEntry( T* i_pObject ) :
+ m_pObject( i_pObject ),
+ m_bDeleted( false )
+ {}
+ };
+
+ std::vector< DeleteObjectEntry > m_aObjects;
+ typedef std::hash_map< sal_IntPtr, unsigned int > PtrToIndexMap;
+ PtrToIndexMap m_aPtrToIndex;
+
+ /** strict weak ordering funtion to bring objects to be destroyed lazily
+ in correct order, e.g. for Window objects children before parents
+ */
+ static bool is_less( T* left, T* right );
+
+ LazyDeletor() { LazyDelete::addDeletor( this ); }
+ virtual ~LazyDeletor()
+ {
+ #if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, "%s %p deleted\n",
+ typeid(*this).name(), this );
+ #endif
+ if( s_pOneInstance == this ) // sanity check
+ s_pOneInstance = NULL;
+
+ // do the actual work
+ unsigned int nCount = m_aObjects.size();
+ std::vector<T*> aRealDelete;
+ aRealDelete.reserve( nCount );
+ for( unsigned int i = 0; i < nCount; i++ )
+ {
+ if( ! m_aObjects[i].m_bDeleted )
+ {
+ aRealDelete.push_back( m_aObjects[i].m_pObject );
+ }
+ }
+ // sort the vector of objects to be destroyed
+ std::sort( aRealDelete.begin(), aRealDelete.end(), is_less );
+ nCount = aRealDelete.size();
+ for( unsigned int n = 0; n < nCount; n++ )
+ {
+ #if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, "%s deletes object %p of type %s\n",
+ typeid(*this).name(),
+ aRealDelete[n],
+ typeid(*aRealDelete[n]).name() );
+ #endif
+ // check if the object to be deleted is not already destroyed
+ // as a side effect of a previous lazily destroyed object
+ if( ! m_aObjects[ m_aPtrToIndex[ reinterpret_cast<sal_IntPtr>(aRealDelete[n]) ] ].m_bDeleted )
+ delete aRealDelete[n];
+ }
+ }
+
+ public:
+ /** mark an object for lazy deletion
+ */
+ static void Delete( T* i_pObject )
+ {
+ if( s_pOneInstance == NULL )
+ s_pOneInstance = new LazyDeletor<T>();
+
+ // is this object already in the list ?
+ // if so mark it as not to be deleted; else insert it
+ PtrToIndexMap::const_iterator dup = s_pOneInstance->m_aPtrToIndex.find( reinterpret_cast<sal_IntPtr>(i_pObject) );
+ if( dup != s_pOneInstance->m_aPtrToIndex.end() )
+ {
+ s_pOneInstance->m_aObjects[ dup->second ].m_bDeleted = false;
+ }
+ else
+ {
+ s_pOneInstance->m_aPtrToIndex[ reinterpret_cast<sal_IntPtr>(i_pObject) ] = s_pOneInstance->m_aObjects.size();
+ s_pOneInstance->m_aObjects.push_back( DeleteObjectEntry( i_pObject ) );
+ }
+ }
+ /** unmark an object already marked for lazy deletion
+ */
+ static void Undelete( T* i_pObject )
+ {
+ if( s_pOneInstance )
+ {
+ PtrToIndexMap::const_iterator it = s_pOneInstance->m_aPtrToIndex.find( reinterpret_cast<sal_IntPtr>(i_pObject) );
+ if( it != s_pOneInstance->m_aPtrToIndex.end() )
+ s_pOneInstance->m_aObjects[ it->second ].m_bDeleted = true;
+ }
+ }
+ };
+
+ /*
+ class DeleteOnDeinit matches a similar need as LazyDelete for static objects:
+ you may not access vcl objects after DeInitVCL has been called this includes their destruction
+ therefore disallowing the existance of static vcl object like e.g. a static BitmapEx
+ To work around this use DeleteOnDeinit<BitmapEx> which will allow you to have a static object container,
+ that will have its contents destroyed on DeinitVCL. The single drawback is that you need to check on the
+ container object whether it still contains content before actually accessing it.
+
+ caveat: when constructing a vcl object, you certainly want to ensure that InitVCL has run already.
+ However this is not necessarily the case when using a class static member or a file level static variable.
+ In these cases make judicious use of the set() method of DeleteOnDeinit, but beware of the changing
+ ownership.
+
+ example use case: use a lazy initialized on call BitmapEx in a paint method. Of course a paint method
+ would not normally be called after DeInitVCL anyway, so the check might not be necessary in a
+ Window::Paint implementation, but always checking is a good idea.
+
+ SomeWindow::Paint()
+ {
+ static vcl::DeleteOnDeinit< BitmapEx > aBmp( new BitmapEx( ResId( 1000, myResMgr ) ) );
+
+ if( aBmp.get() ) // check whether DeInitVCL has been called already
+ DrawBitmapEx( Point( 10, 10 ), *aBmp.get() );
+ }
+ */
+
+ class VCL_DLLPUBLIC DeleteOnDeinitBase
+ {
+ public:
+ static void SAL_DLLPRIVATE ImplDeleteOnDeInit();
+ virtual ~DeleteOnDeinitBase();
+ protected:
+ static void addDeinitContainer( DeleteOnDeinitBase* i_pContainer );
+
+ virtual void doCleanup() = 0;
+ };
+
+ template < typename T >
+ class DeleteOnDeinit : public DeleteOnDeinitBase
+ {
+ T* m_pT;
+ virtual void doCleanup() { delete m_pT; m_pT = NULL; }
+ public:
+ DeleteOnDeinit( T* i_pT ) : m_pT( i_pT ) { addDeinitContainer( this ); }
+ virtual ~DeleteOnDeinit() {}
+
+ // get contents
+ T* get() { return m_pT; }
+
+ // set contents, returning old contents
+ // ownership is transfered !
+ T* set( T* i_pNew ) { T* pOld = m_pT; m_pT = i_pNew; return pOld; }
+ };
+}
+
+#endif
+
diff --git a/vcl/inc/vcl/lineinfo.hxx b/vcl/inc/vcl/lineinfo.hxx
new file mode 100644
index 000000000000..9b12966a52ff
--- /dev/null
+++ b/vcl/inc/vcl/lineinfo.hxx
@@ -0,0 +1,132 @@
+/*************************************************************************
+ *
+ * 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_LINEINFO_HXX
+#define _SV_LINEINFO_HXX
+
+#include <vcl/dllapi.h>
+#include <tools/gen.hxx>
+#include <vcl/vclenum.hxx>
+#include <basegfx/vector/b2enums.hxx>
+
+// ----------------
+// - ImplLineInfo -
+// ----------------
+
+class SvStream;
+namespace basegfx { class B2DPolyPolygon; }
+
+struct ImplLineInfo
+{
+ ULONG mnRefCount;
+ LineStyle meStyle;
+ long mnWidth;
+ USHORT mnDashCount;
+ long mnDashLen;
+ USHORT mnDotCount;
+ long mnDotLen;
+ long mnDistance;
+
+ basegfx::B2DLineJoin meLineJoin;
+
+ ImplLineInfo();
+ ImplLineInfo( const ImplLineInfo& rImplLineInfo );
+
+ friend SvStream& operator>>( SvStream& rIStm, ImplLineInfo& rImplLineInfo );
+ friend SvStream& operator<<( SvStream& rOStm, const ImplLineInfo& rImplLineInfo );
+};
+
+// ------------
+// - LineInfo -
+// ------------
+
+class VCL_DLLPUBLIC LineInfo
+{
+private:
+
+ ImplLineInfo* mpImplLineInfo;
+ long n1;
+ long n2;
+ long n3;
+
+ SAL_DLLPRIVATE void ImplMakeUnique();
+
+public:
+
+ LineInfo( LineStyle eLineStyle = LINE_SOLID, long nWidth = 0L );
+ LineInfo( const LineInfo& rLineInfo );
+ ~LineInfo();
+
+ LineInfo& operator=( const LineInfo& rLineInfo );
+ BOOL operator==( const LineInfo& rLineInfo ) const;
+ BOOL operator!=( const LineInfo& rLineInfo ) const { return !(LineInfo::operator==( rLineInfo ) ); }
+ BOOL IsSameInstance( const LineInfo& rLineInfo ) const { return( mpImplLineInfo == rLineInfo.mpImplLineInfo ); }
+
+ void SetStyle( LineStyle eStyle );
+ LineStyle GetStyle() const { return mpImplLineInfo->meStyle; }
+
+ void SetWidth( long nWidth );
+ long GetWidth() const { return mpImplLineInfo->mnWidth; }
+
+ void SetDashCount( USHORT nDashCount );
+ USHORT GetDashCount() const { return mpImplLineInfo->mnDashCount; }
+
+ void SetDashLen( long nDashLen );
+ long GetDashLen() const { return mpImplLineInfo->mnDashLen; }
+
+ void SetDotCount( USHORT nDotCount );
+ USHORT GetDotCount() const { return mpImplLineInfo->mnDotCount; }
+
+ void SetDotLen( long nDotLen );
+ long GetDotLen() const { return mpImplLineInfo->mnDotLen; }
+
+ void SetDistance( long nDistance );
+ long GetDistance() const { return mpImplLineInfo->mnDistance; }
+
+ void SetLineJoin(basegfx::B2DLineJoin eLineJoin);
+ basegfx::B2DLineJoin GetLineJoin() const { return mpImplLineInfo->meLineJoin; }
+
+ BOOL IsDefault() const { return( !mpImplLineInfo->mnWidth && ( LINE_SOLID == mpImplLineInfo->meStyle ) ); }
+
+ friend VCL_DLLPUBLIC SvStream& operator>>( SvStream& rIStm, LineInfo& rLineInfo );
+ friend VCL_DLLPUBLIC SvStream& operator<<( SvStream& rOStm, const LineInfo& rLineInfo );
+
+ // helper to check if line width or DashDot is used
+ bool isDashDotOrFatLineUsed() const;
+
+ // helper to get decomposed polygon data with the LineInfo applied. The source
+ // hairline polygon is given in io_rLinePolyPolygon. Both given polygons may
+ // contain results; e.g. when no fat line but DasDot is defined, the resut will
+ // be in io_rLinePolyPolygon while o_rFillPolyPolygon will be empty. When fat line
+ // is defined, it will be vice-versa. If none is defined, io_rLinePolyPolygon will
+ // not be changed (but o_rFillPolyPolygon will be freed)
+ void applyToB2DPolyPolygon(
+ basegfx::B2DPolyPolygon& io_rLinePolyPolygon,
+ basegfx::B2DPolyPolygon& o_rFillPolyPolygon) const;
+};
+
+#endif // _SV_LINEINFO_HXX
diff --git a/vcl/inc/vcl/longcurr.hxx b/vcl/inc/vcl/longcurr.hxx
new file mode 100644
index 000000000000..39bd75439ad9
--- /dev/null
+++ b/vcl/inc/vcl/longcurr.hxx
@@ -0,0 +1,162 @@
+/*************************************************************************
+ *
+ * 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 _LONGCURR_HXX
+#define _LONGCURR_HXX
+
+#include <vcl/dllapi.h>
+#include <tools/bigint.hxx>
+#ifndef _FIELD_HXX
+#include <vcl/field.hxx>
+#endif
+
+class LocaleDataWrapper;
+
+// -------------------------
+// - LongCurrencyFormatter -
+// -------------------------
+
+class VCL_DLLPUBLIC LongCurrencyFormatter : public FormatterBase
+{
+private:
+ SAL_DLLPRIVATE friend BOOL ImplLongCurrencyReformat( const XubString&, BigInt, BigInt, USHORT, const LocaleDataWrapper&, XubString&, LongCurrencyFormatter& );
+ SAL_DLLPRIVATE void ImpInit();
+
+protected:
+ BigInt mnFieldValue;
+ BigInt mnLastValue;
+ BigInt mnMin;
+ BigInt mnMax;
+ BigInt mnCorrectedValue;
+ String maCurrencySymbol;
+ USHORT mnType;
+ USHORT mnDecimalDigits;
+ BOOL mbThousandSep;
+
+ LongCurrencyFormatter();
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+
+public:
+ ~LongCurrencyFormatter();
+
+ virtual void Reformat();
+ virtual void ReformatAll();
+
+ void SetUseThousandSep( BOOL b );
+ BOOL IsUseThousandSep() const { return mbThousandSep; }
+
+ void SetCurrencySymbol( const String& rStr );
+ String GetCurrencySymbol() const;
+
+ void SetMin( BigInt nNewMin );
+ BigInt GetMin() const { return mnMin; }
+ void SetMax( BigInt nNewMax );
+ BigInt GetMax() const { return mnMax; }
+
+ void SetDecimalDigits( USHORT nDigits );
+ USHORT GetDecimalDigits() const;
+ void SetValue( BigInt nNewValue );
+ void SetUserValue( BigInt nNewValue );
+ BigInt GetValue() const;
+ BOOL IsValueModified() const;
+
+ void SetEmptyValue();
+ BOOL IsEmptyValue() const { return !GetField()->GetText().Len(); }
+
+ BigInt GetCorrectedValue() const { return mnCorrectedValue; }
+
+ BigInt Normalize( BigInt nValue ) const;
+ BigInt Denormalize( BigInt nValue ) const;
+};
+
+// ---------------------
+// - LongCurrencyField -
+// ---------------------
+
+class VCL_DLLPUBLIC LongCurrencyField : public SpinField, public LongCurrencyFormatter
+{
+//#if 0 // _SOLAR__PRIVATE
+ friend void ImplNewLongCurrencyFieldValue( LongCurrencyField*, BigInt );
+//#endif
+
+private:
+ BigInt mnSpinSize;
+ BigInt mnFirst;
+ BigInt mnLast;
+
+protected:
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+
+public:
+ LongCurrencyField( Window* pParent, WinBits nWinStyle );
+ LongCurrencyField( Window* pParent, const ResId& rResId );
+ ~LongCurrencyField();
+
+ long PreNotify( NotifyEvent& rNEvt );
+ long Notify( NotifyEvent& rNEvt );
+
+ void Modify();
+ void Up();
+ void Down();
+ void First();
+ void Last();
+
+ void SetFirst( BigInt nNewFirst ) { mnFirst = nNewFirst; }
+ BigInt GetFirst() const { return mnFirst; }
+ void SetLast( BigInt nNewLast ) { mnLast = nNewLast; }
+ BigInt GetLast() const { return mnLast; }
+ void SetSpinSize( BigInt nNewSize ) { mnSpinSize = nNewSize; }
+ BigInt GetSpinSize() const { return mnSpinSize; }
+};
+
+// -------------------
+// - LongCurrencyBox -
+// -------------------
+
+class VCL_DLLPUBLIC LongCurrencyBox : public ComboBox, public LongCurrencyFormatter
+{
+public:
+ LongCurrencyBox( Window* pParent, WinBits nWinStyle );
+ LongCurrencyBox( Window* pParent, const ResId& rResId );
+ ~LongCurrencyBox();
+
+ long PreNotify( NotifyEvent& rNEvt );
+ long Notify( NotifyEvent& rNEvt );
+
+ void Modify();
+ void ReformatAll();
+
+ void InsertValue( BigInt nValue,
+ USHORT nPos = COMBOBOX_APPEND );
+ void RemoveValue( BigInt nValue );
+ BigInt GetValue() const
+ { return LongCurrencyFormatter::GetValue(); }
+ BigInt GetValue( USHORT nPos ) const;
+ USHORT GetValuePos( BigInt nValue ) const;
+};
+
+#endif // _LONGCURR_HXX
diff --git a/vcl/inc/vcl/lstbox.h b/vcl/inc/vcl/lstbox.h
new file mode 100644
index 000000000000..db800229b2d2
--- /dev/null
+++ b/vcl/inc/vcl/lstbox.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_LSTBOX_H
+#define _SV_LSTBOX_H
+
+#define LISTBOX_APPEND ((USHORT)0xFFFF)
+#define LISTBOX_ENTRY_NOTFOUND ((USHORT)0xFFFF)
+#define LISTBOX_ERROR ((USHORT)0xFFFF)
+
+#define LISTBOX_USERDRAW_SELECTED ((USHORT)0x0001)
+
+// --------------------------------------------------------------------
+
+// the following defines can be used for the SetEntryFlags()
+// and GetEntryFlags() methods
+
+// !! Do not use these flags for user data as they are reserved !!
+// !! to change the internal behaviour of the ListBox implementation !!
+// !! for specific entries. !!
+
+/** this flag disables a selection of an entry completly. It is not
+ possible to select such entries either from the user interface
+ nor from the ListBox methods. Cursor traveling is handled correctly.
+ This flag can be used to add titles to a ListBox.
+*/
+#define LISTBOX_ENTRY_FLAG_DISABLE_SELECTION 0x0000001
+
+/** this flag can be used to make an entry multine capable
+ A normal entry is single line and will therefore be clipped
+ at the right listbox border. Setting this flag enables
+ word breaks for the entry text.
+*/
+#define LISTBOX_ENTRY_FLAG_MULTILINE 0x0000002
+
+/** this flags lets the item be drawn disabled (e.g. in grey text)
+ usage only guaranteed with LISTBOX_ENTRY_FLAG_DISABLE_SELECTION
+*/
+#define LISTBOX_ENTRY_FLAG_DRAW_DISABLED 0x0000004
+
+#endif // _SV_LSTBOX_H
diff --git a/vcl/inc/vcl/lstbox.hxx b/vcl/inc/vcl/lstbox.hxx
new file mode 100644
index 000000000000..3659e5aee485
--- /dev/null
+++ b/vcl/inc/vcl/lstbox.hxx
@@ -0,0 +1,266 @@
+/*************************************************************************
+ *
+ * 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_LSTBOX_HXX
+#define _SV_LSTBOX_HXX
+
+#include <vcl/dllapi.h>
+#include <vcl/ctrl.hxx>
+#include <vcl/lstbox.h>
+
+class Image;
+class ImplListBox;
+class ImplListBoxFloatingWindow;
+class ImplBtn;
+class ImplWin;
+
+// --------------------------------------------------------------------
+// - ListBox -
+// --------------------------------------------------------------------
+
+class VCL_DLLPUBLIC ListBox : public Control
+{
+private:
+ ImplListBox* mpImplLB;
+ ImplListBoxFloatingWindow* mpFloatWin;
+ ImplWin* mpImplWin;
+ ImplBtn* mpBtn;
+ USHORT mnDDHeight;
+ USHORT mnSaveValue;
+ BOOL mbDDAutoSize;
+ Link maSelectHdl;
+ Link maDoubleClickHdl;
+ USHORT mnLineCount;
+
+//#if 0 // _SOLAR__PRIVATE
+private:
+ SAL_DLLPRIVATE void ImplInitListBoxData();
+
+ DECL_DLLPRIVATE_LINK( ImplSelectHdl, void* );
+ DECL_DLLPRIVATE_LINK( ImplScrollHdl, void* );
+ DECL_DLLPRIVATE_LINK( ImplCancelHdl, void* );
+ DECL_DLLPRIVATE_LINK( ImplDoubleClickHdl, void* );
+ DECL_DLLPRIVATE_LINK( ImplClickBtnHdl, void* );
+ DECL_DLLPRIVATE_LINK( ImplPopupModeEndHdl, void* );
+ DECL_DLLPRIVATE_LINK( ImplSelectionChangedHdl, void* );
+ DECL_DLLPRIVATE_LINK( ImplUserDrawHdl, UserDrawEvent* );
+
+protected:
+ using Window::ImplInit;
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle );
+ SAL_DLLPRIVATE WinBits ImplInitStyle( WinBits nStyle );
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+//#endif
+ BOOL IsDropDownBox() const { return mpFloatWin ? TRUE : FALSE; }
+
+protected:
+ ListBox( WindowType nType );
+
+ virtual void FillLayoutData() const;
+
+public:
+ ListBox( Window* pParent, WinBits nStyle = WB_BORDER );
+ ListBox( Window* pParent, const ResId& rResId );
+ ~ListBox();
+
+ virtual void Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG nFlags );
+ virtual void Resize();
+ virtual long PreNotify( NotifyEvent& rNEvt );
+ virtual void StateChanged( StateChangedType nType );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+ virtual void UserDraw( const UserDrawEvent& rUDEvt );
+
+ virtual void Select();
+ virtual void DoubleClick();
+ virtual void GetFocus();
+ virtual void LoseFocus();
+ virtual Window* GetPreferredKeyInputWindow();
+
+ virtual const Wallpaper& GetDisplayBackground() const;
+
+ virtual void SetPosSizePixel( long nX, long nY,
+ long nWidth, long nHeight, USHORT nFlags = WINDOW_POSSIZE_ALL );
+ void SetPosSizePixel( const Point& rNewPos, const Size& rNewSize )
+ { Control::SetPosSizePixel( rNewPos, rNewSize ); }
+ void SetDropDownSizePixel( const Size& rNewSize )
+ { if( IsDropDownBox() ) SetPosSizePixel( 0, 0, rNewSize.Width(), rNewSize.Height(), WINDOW_POSSIZE_SIZE | WINDOW_POSSIZE_DROPDOWN ); }
+
+ Rectangle GetDropDownPosSizePixel() const;
+
+ void SetDropDownLineCount( USHORT nLines );
+ USHORT GetDropDownLineCount() const;
+
+ void EnableAutoSize( BOOL bAuto );
+ BOOL IsAutoSizeEnabled() const { return mbDDAutoSize; }
+
+ void EnableDDAutoWidth( BOOL b );
+ BOOL IsDDAutoWidthEnabled() const;
+
+ virtual USHORT InsertEntry( const XubString& rStr, USHORT nPos = LISTBOX_APPEND );
+ virtual USHORT InsertEntry( const Image& rImage, USHORT nPos = LISTBOX_APPEND );
+ virtual USHORT InsertEntry( const XubString& rStr, const Image& rImage, USHORT nPos = LISTBOX_APPEND );
+ virtual void RemoveEntry( const XubString& rStr );
+ virtual void RemoveEntry( USHORT nPos );
+
+ virtual void Clear();
+
+ virtual USHORT GetEntryPos( const XubString& rStr ) const;
+ virtual USHORT GetEntryPos( const void* pData ) const;
+ Image GetEntryImage( USHORT nPos ) const;
+ virtual XubString GetEntry( USHORT nPos ) const;
+ virtual USHORT GetEntryCount() const;
+
+ virtual void SelectEntry( const XubString& rStr, BOOL bSelect = TRUE );
+ virtual void SelectEntryPos( USHORT nPos, BOOL bSelect = TRUE );
+
+ virtual USHORT GetSelectEntryCount() const;
+ virtual XubString GetSelectEntry( USHORT nSelIndex = 0 ) const;
+ virtual USHORT GetSelectEntryPos( USHORT nSelIndex = 0 ) const;
+
+ virtual BOOL IsEntrySelected( const XubString& rStr ) const;
+ virtual BOOL IsEntryPosSelected( USHORT nPos ) const;
+ virtual void SetNoSelection();
+
+ void SetEntryData( USHORT nPos, void* pNewData );
+ void* GetEntryData( USHORT nPos ) const;
+
+ /** this methods stores a combination of flags from the
+ LISTBOX_ENTRY_FLAG_* defines at the given entry.
+ See description of the possible LISTBOX_ENTRY_FLAG_* flags
+ for details.
+ Do not use these flags for user data as they are reserved
+ to change the internal behaviour of the ListBox implementation
+ for specific entries.
+ */
+ void SetEntryFlags( USHORT nPos, long nFlags );
+
+ /** this methods gets the current combination of flags from the
+ LISTBOX_ENTRY_FLAG_* defines from the given entry.
+ See description of the possible LISTBOX_ENTRY_FLAG_* flags
+ for details.
+ */
+ long GetEntryFlags( USHORT nPos ) const;
+
+ void SetTopEntry( USHORT nPos );
+ void ShowProminentEntry( USHORT nPos );
+ void SetTopEntryStr( const XubString& rStr );
+ USHORT GetTopEntry() const;
+
+ void SetProminentEntryType( ProminentEntry eType );
+ ProminentEntry GetProminentEntryType() const;
+
+ void SaveValue() { mnSaveValue = GetSelectEntryPos(); }
+ USHORT GetSavedValue() const { return mnSaveValue; }
+
+ void SetSeparatorPos( USHORT n );
+ void SetSeparatorPos();
+ USHORT GetSeparatorPos() const;
+
+ BOOL IsTravelSelect() const;
+ BOOL IsInDropDown() const;
+ void ToggleDropDown();
+
+ void EnableMultiSelection( BOOL bMulti, BOOL bStackSelection );
+ void EnableMultiSelection( BOOL bMulti );
+ BOOL IsMultiSelectionEnabled() const;
+
+ void SetReadOnly( BOOL bReadOnly = TRUE );
+ BOOL IsReadOnly() const;
+
+ long CalcWindowSizePixel( USHORT nLines ) const;
+ Rectangle GetBoundingRectangle( USHORT nItem ) const;
+
+ void SetUserItemSize( const Size& rSz );
+ const Size& GetUserItemSize() const;
+
+ void EnableUserDraw( BOOL bUserDraw );
+ BOOL IsUserDrawEnabled() const;
+
+ void DrawEntry( const UserDrawEvent& rEvt, BOOL bDrawImage, BOOL bDrawText, BOOL bDrawTextAtImagePos = FALSE );
+
+ void SetSelectHdl( const Link& rLink ) { maSelectHdl = rLink; }
+ const Link& GetSelectHdl() const { return maSelectHdl; }
+ void SetDoubleClickHdl( const Link& rLink ) { maDoubleClickHdl = rLink; }
+ const Link& GetDoubleClickHdl() const { return maDoubleClickHdl; }
+
+ Size CalcMinimumSize() const;
+ virtual Size GetOptimalSize(WindowSizeType eType) const;
+ Size CalcAdjustedSize( const Size& rPrefSize ) const;
+ Size CalcSize( USHORT nColumns, USHORT nLines ) const;
+ void GetMaxVisColumnsAndLines( USHORT& rnCols, USHORT& rnLines ) const;
+
+ void SetMRUEntries( const XubString& rEntries, xub_Unicode cSep = ';' );
+ XubString GetMRUEntries( xub_Unicode cSep = ';' ) const;
+ void SetMaxMRUCount( USHORT n );
+ USHORT GetMaxMRUCount() const;
+
+ USHORT GetDisplayLineCount() const;
+
+ void EnableMirroring();
+
+ /** checks whether a certain point lies within the bounds of
+ a listbox item and returns the item as well as the character position
+ the point is at.
+
+ <p>If the point is inside an item the item pos is put into <code>rPos</code> and
+ the item-relative character index is returned. If the point is not inside
+ an item -1 is returned and rPos is unchanged.</p>
+
+ @param rPoint
+ tells the point for which an item is requested.
+
+ @param rPos
+ gets the item at the specified point <code>rPoint</code>
+
+ @returns
+ the item-relative character index at point <code>rPos</code> or -1
+ if no item is at that point.
+ */
+ using Control::GetIndexForPoint;
+ long GetIndexForPoint( const Point& rPoint, USHORT& rPos ) const;
+};
+
+// ----------------
+// - MultiListBox -
+// ----------------
+
+class VCL_DLLPUBLIC MultiListBox : public ListBox
+{
+public:
+ using ListBox::SaveValue;
+ using ListBox::GetSavedValue;
+private:
+ // Bei MultiListBox nicht erlaubt...
+ void SaveValue();
+ USHORT GetSavedValue();
+
+public:
+ MultiListBox( Window* pParent, WinBits nStyle = 0 );
+ MultiListBox( Window* pParent, const ResId& rResId );
+};
+
+#endif // _SV_LSTBOX_HXX
diff --git a/vcl/inc/vcl/mapmod.hxx b/vcl/inc/vcl/mapmod.hxx
new file mode 100644
index 000000000000..b2ea32958e90
--- /dev/null
+++ b/vcl/inc/vcl/mapmod.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_MAPMOD_HXX
+#define _SV_MAPMOD_HXX
+
+#include <tools/gen.hxx>
+#include <tools/fract.hxx>
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <tools/resid.hxx>
+#include <vcl/mapunit.hxx>
+
+class SvStream;
+
+// --------------
+// - ImplMapMode -
+// --------------
+
+class OutputDevice;
+
+class ImplMapMode
+{
+ friend class MapMode;
+ friend class OutputDevice;
+
+private:
+ ULONG mnRefCount;
+ MapUnit meUnit;
+ Point maOrigin;
+ Fraction maScaleX;
+ Fraction maScaleY;
+ BOOL mbSimple;
+
+ friend SvStream& operator>>( SvStream& rIStm, ImplMapMode& rMapMode );
+ friend SvStream& operator<<( SvStream& rOStm, const ImplMapMode& rMapMode );
+
+ static ImplMapMode* ImplGetStaticMapMode( MapUnit eUnit );
+public:
+ ImplMapMode();
+ ImplMapMode( const ImplMapMode& rImpMapMode );
+};
+
+// -----------
+// - MapMode -
+// -----------
+
+class VCL_DLLPUBLIC MapMode
+{
+ friend class OutputDevice;
+
+private:
+ ImplMapMode* mpImplMapMode;
+
+ SAL_DLLPRIVATE void ImplMakeUnique();
+
+public:
+ MapMode();
+ MapMode( const MapMode& rMapMode );
+ MapMode( MapUnit eUnit );
+ MapMode( MapUnit eUnit, const Point& rLogicOrg,
+ const Fraction& rScaleX, const Fraction& rScaleY );
+ ~MapMode();
+
+ void SetMapUnit( MapUnit eUnit );
+ MapUnit GetMapUnit() const
+ { return mpImplMapMode->meUnit; }
+
+ void SetOrigin( const Point& rOrigin );
+ const Point& GetOrigin() const
+ { return mpImplMapMode->maOrigin; }
+
+ void SetScaleX( const Fraction& rScaleX );
+ const Fraction& GetScaleX() const
+ { return mpImplMapMode->maScaleX; }
+ void SetScaleY( const Fraction& rScaleY );
+ const Fraction& GetScaleY() const
+ { return mpImplMapMode->maScaleY; }
+
+ MapMode& operator=( const MapMode& rMapMode );
+ BOOL operator==( const MapMode& rMapMode ) const;
+ BOOL operator!=( const MapMode& rMapMode ) const
+ { return !(MapMode::operator==( rMapMode )); }
+ BOOL IsDefault() const;
+ BOOL IsSameInstance( const MapMode& rMapMode ) const
+ { return (mpImplMapMode == rMapMode.mpImplMapMode); }
+
+ friend VCL_DLLPUBLIC SvStream& operator>>( SvStream& rIStm, MapMode& rMapMode );
+ friend VCL_DLLPUBLIC SvStream& operator<<( SvStream& rOStm, const MapMode& rMapMode );
+};
+
+#endif // _SV_MAPMOD_HXX
diff --git a/vcl/inc/vcl/mapunit.hxx b/vcl/inc/vcl/mapunit.hxx
new file mode 100644
index 000000000000..b4c757c538e6
--- /dev/null
+++ b/vcl/inc/vcl/mapunit.hxx
@@ -0,0 +1,33 @@
+/*************************************************************************
+ *
+ * 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_MAPUNIT_HXX
+#define _VCL_MAPUNIT_HXX
+
+#include <tools/mapunit.hxx>
+
+#endif // _VCL_MAPUNIT_HXX
diff --git a/vcl/inc/vcl/menu.hxx b/vcl/inc/vcl/menu.hxx
new file mode 100644
index 000000000000..908f3e30319c
--- /dev/null
+++ b/vcl/inc/vcl/menu.hxx
@@ -0,0 +1,534 @@
+/*************************************************************************
+ *
+ * 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_MENU_HXX
+#define _SV_MENU_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <tools/rc.hxx>
+#include <tools/resid.hxx>
+#include <vcl/bitmapex.hxx>
+#include <tools/color.hxx>
+#include <vcl/vclevent.hxx>
+#include <com/sun/star/uno/Reference.hxx>
+
+struct MenuItemData;
+class Point;
+class Size;
+class Rectangle;
+class Menu;
+class MenuItemList;
+class HelpEvent;
+class Image;
+class PopupMenu;
+class KeyCode;
+class KeyEvent;
+class AppBarWindow;
+class MenuFloatingWindow;
+class Window;
+class SalMenu;
+struct SystemMenuData;
+
+namespace com {
+namespace sun {
+namespace star {
+namespace accessibility {
+ class XAccessible;
+}}}}
+
+namespace vcl { struct MenuLayoutData; }
+
+// --------------
+// - Menu-Types -
+// --------------
+
+#define MENU_APPEND ((USHORT)0xFFFF)
+#define MENU_ITEM_NOTFOUND ((USHORT)0xFFFF)
+
+#define POPUPMENU_EXECUTE_DOWN ((USHORT)0x0001)
+#define POPUPMENU_EXECUTE_UP ((USHORT)0x0002)
+#define POPUPMENU_EXECUTE_LEFT ((USHORT)0x0004)
+#define POPUPMENU_EXECUTE_RIGHT ((USHORT)0x0008)
+
+#define POPUPMENU_NOMOUSEUPCLOSE ((USHORT)0x0010)
+
+// By changes you must also change: rsc/vclrsc.hxx
+enum MenuItemType { MENUITEM_DONTKNOW, MENUITEM_STRING, MENUITEM_IMAGE,
+ MENUITEM_STRINGIMAGE, MENUITEM_SEPARATOR };
+
+// By changes you must also change: rsc/vclrsc.hxx
+typedef USHORT MenuItemBits;
+#define MIB_CHECKABLE ((MenuItemBits)0x0001)
+#define MIB_RADIOCHECK ((MenuItemBits)0x0002)
+#define MIB_AUTOCHECK ((MenuItemBits)0x0004)
+#define MIB_ABOUT ((MenuItemBits)0x0008)
+#define MIB_HELP ((MenuItemBits)0x0010)
+#define MIB_POPUPSELECT ((MenuItemBits)0x0020)
+// not in rsc/vclsrc.hxx because only a prelimitary solution
+#define MIB_NOSELECT ((MenuItemBits)0x0040)
+#define MIB_ICON ((MenuItemBits)0x0080)
+#define MIB_TEXT ((MenuItemBits)0x0100)
+
+#define MENU_FLAG_NOAUTOMNEMONICS 0x0001
+#define MENU_FLAG_HIDEDISABLEDENTRIES 0x0002
+
+// overrides default hiding of disabled entries in popup menus
+#define MENU_FLAG_ALWAYSSHOWDISABLEDENTRIES 0x0004
+
+// forces images & toggle visibility for toolbar config popup
+#define MENU_FLAG_SHOWCHECKIMAGES 0x0008
+
+struct ImplMenuDelData
+{
+ ImplMenuDelData* mpNext;
+ const Menu* mpMenu;
+
+ ImplMenuDelData( const Menu* pMenu );
+ ~ImplMenuDelData();
+
+ bool isDeleted() const { return mpMenu == 0; }
+};
+
+// --------
+// - Menu -
+// --------
+
+struct MenuLogo
+{
+ BitmapEx aBitmap;
+ Color aStartColor;
+ Color aEndColor;
+};
+
+class VCL_DLLPUBLIC Menu : public Resource
+{
+ friend class MenuBar;
+ friend class MenuBarWindow;
+ friend class MenuFloatingWindow;
+ friend class PopupMenu;
+ friend class SystemWindow;
+ friend struct ImplMenuDelData;
+private:
+ ImplMenuDelData* mpFirstDel;
+ MenuItemList* pItemList; // Liste mit den MenuItems
+ MenuLogo* pLogo;
+ Menu* pStartedFrom;
+ Window* pWindow;
+
+ Link aActivateHdl; // Active-Handler
+ Link aDeactivateHdl; // Deactivate-Handler
+ Link aHighlightHdl; // Highlight-Handler
+ Link aSelectHdl; // Highlight-Handler
+
+ VclEventListeners maEventListeners;
+ VclEventListeners maChildEventListeners;
+
+ XubString aTitleText; // PopupMenu-Text
+
+ ULONG nEventId;
+ USHORT mnHighlightedItemPos; // for native menues: keeps track of the highlighted item
+ USHORT nMenuFlags;
+ USHORT nDefaultItem; // Id vom Default-Item
+ USHORT nSelectedId;
+
+ // Fuer Ausgabe:
+ USHORT nCheckPos;
+ USHORT nImagePos;
+ USHORT nTextPos;
+
+ BOOL bIsMenuBar : 1, // Handelt es sich um den MenuBar
+ bCanceled : 1, // Waehrend eines Callbacks abgebrochen
+ bInCallback : 1, // In Activate/Deactivate
+ bKilled : 1; // Gekillt...
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > mxAccessible;
+ mutable vcl::MenuLayoutData* mpLayoutData;
+ SalMenu* mpSalMenu;
+
+protected:
+ SAL_DLLPRIVATE void ImplInit();
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+ SAL_DLLPRIVATE Menu* ImplGetStartMenu();
+ SAL_DLLPRIVATE Menu* ImplFindSelectMenu();
+ SAL_DLLPRIVATE Menu* ImplFindMenu( USHORT nId );
+ SAL_DLLPRIVATE Size ImplCalcSize( Window* pWin );
+ SAL_DLLPRIVATE BOOL ImplIsVisible( USHORT nPos ) const;
+ SAL_DLLPRIVATE BOOL ImplIsSelectable( USHORT nPos ) const;
+ SAL_DLLPRIVATE USHORT ImplGetVisibleItemCount() const;
+ SAL_DLLPRIVATE USHORT ImplGetFirstVisible() const;
+ SAL_DLLPRIVATE USHORT ImplGetPrevVisible( USHORT nPos ) const;
+ SAL_DLLPRIVATE USHORT ImplGetNextVisible( USHORT nPos ) const;
+ SAL_DLLPRIVATE void ImplPaint( Window* pWin, USHORT nBorder, long nOffY = 0, MenuItemData* pThisDataOnly = 0, BOOL bHighlighted = FALSE, bool bLayout = false ) const;
+ SAL_DLLPRIVATE void ImplSelect();
+ SAL_DLLPRIVATE void ImplCallHighlight( USHORT nHighlightItem );
+ SAL_DLLPRIVATE void ImplCallEventListeners( ULONG nEvent, USHORT nPos );
+ DECL_DLLPRIVATE_LINK( ImplCallSelect, Menu* );
+
+ SAL_DLLPRIVATE void ImplFillLayoutData() const;
+ SAL_DLLPRIVATE SalMenu* ImplGetSalMenu() { return mpSalMenu; }
+ SAL_DLLPRIVATE void ImplSetSalMenu( SalMenu *pMenu );
+ SAL_DLLPRIVATE const XubString& ImplGetHelpText( USHORT nItemId ) const;
+
+ // returns native check and option menu symbol height;
+ // return value is Max( rCheckHeight, rRadioHeight )
+ SAL_DLLPRIVATE long ImplGetNativeCheckAndRadioSize( Window*, long& rCheckHeight, long& rRadioHeight, long &rMaxWidth ) const;
+
+ SAL_DLLPRIVATE void ImplAddDel( ImplMenuDelData &rDel );
+ SAL_DLLPRIVATE void ImplRemoveDel( ImplMenuDelData &rDel );
+public:
+ SAL_DLLPRIVATE void ImplKillLayoutData() const;
+ SAL_DLLPRIVATE Menu* ImplGetStartedFrom() const;
+
+ Menu();
+ Menu( BOOL bMenuBar );
+ SAL_DLLPRIVATE Window* ImplGetWindow() const { return pWindow; }
+
+
+ SAL_DLLPRIVATE void ImplSelectWithStart( Menu* pStartMenu = NULL );
+public:
+ virtual ~Menu();
+
+ virtual void Activate();
+ virtual void Deactivate();
+ virtual void Highlight();
+ virtual void Select();
+ virtual void RequestHelp( const HelpEvent& rHEvt );
+
+ void InsertItem( USHORT nItemId, const XubString& rStr,
+ MenuItemBits nItemBits = 0,
+ USHORT nPos = MENU_APPEND );
+ void InsertItem( USHORT nItemId, const Image& rImage,
+ MenuItemBits nItemBits = 0,
+ USHORT nPos = MENU_APPEND );
+ void InsertItem( USHORT nItemId,
+ const XubString& rString, const Image& rImage,
+ MenuItemBits nItemBits = 0,
+ USHORT nPos = MENU_APPEND );
+ void InsertItem( const ResId& rResId, USHORT nPos = MENU_APPEND );
+ void InsertSeparator( USHORT nPos = MENU_APPEND );
+ void RemoveItem( USHORT nPos );
+ void CopyItem( const Menu& rMenu, USHORT nPos,
+ USHORT nNewPos = MENU_APPEND );
+ void Clear();
+
+ void CreateAutoMnemonics();
+
+ void SetMenuFlags( USHORT nFlags ) { nMenuFlags = nFlags; }
+ USHORT GetMenuFlags() const { return nMenuFlags; }
+
+ USHORT GetItemCount() const;
+ USHORT GetItemId( USHORT nPos ) const;
+ USHORT GetItemPos( USHORT nItemId ) const;
+ MenuItemType GetItemType( USHORT nPos ) const;
+ USHORT GetCurItemId() const;
+
+ void SetDefaultItem( USHORT nItemId ) { nDefaultItem = nItemId; }
+ USHORT GetDefaultItem() const { return nDefaultItem; }
+
+ void SetItemBits( USHORT nItemId, MenuItemBits nBits );
+ MenuItemBits GetItemBits( USHORT nItemId ) const;
+
+ void SetUserValue( USHORT nItemId, ULONG nValue );
+ ULONG GetUserValue( USHORT nItemId ) const;
+
+ void SetPopupMenu( USHORT nItemId, PopupMenu* pMenu );
+ PopupMenu* GetPopupMenu( USHORT nItemId ) const;
+
+ void SetAccelKey( USHORT nItemId, const KeyCode& rKeyCode );
+ KeyCode GetAccelKey( USHORT nItemId ) const;
+
+ void CheckItem( USHORT nItemId, BOOL bCheck = TRUE );
+ BOOL IsItemChecked( USHORT nItemId ) const;
+
+ void SelectItem( USHORT nItemId );
+ void DeSelect() { SelectItem( 0xFFFF ); } // MENUITEMPOS_INVALID
+
+ void EnableItem( USHORT nItemId, BOOL bEnable = TRUE );
+ BOOL IsItemEnabled( USHORT nItemId ) const;
+
+ void ShowItem( USHORT nItemId, BOOL bVisible = TRUE );
+ void HideItem( USHORT nItemId ) { ShowItem( nItemId, FALSE ); }
+
+ BOOL IsItemVisible( USHORT nItemId ) const;
+ BOOL IsItemPosVisible( USHORT nItemPos ) const;
+ BOOL IsMenuVisible() const;
+ BOOL IsMenuBar() const { return bIsMenuBar; }
+
+ void RemoveDisabledEntries( BOOL bCheckPopups = TRUE, BOOL bRemoveEmptyPopups = FALSE );
+ BOOL HasValidEntries( BOOL bCheckPopups = TRUE );
+
+ void SetItemText( USHORT nItemId, const XubString& rStr );
+ XubString GetItemText( USHORT nItemId ) const;
+
+ void SetItemImage( USHORT nItemId, const Image& rImage );
+ Image GetItemImage( USHORT nItemId ) const;
+ void SetItemImageAngle( USHORT nItemId, long nAngle10 );
+ long GetItemImageAngle( USHORT nItemId ) const;
+ void SetItemImageMirrorMode( USHORT nItemId, BOOL bMirror );
+ BOOL GetItemImageMirrorMode( USHORT ) const;
+
+ void SetItemCommand( USHORT nItemId, const XubString& rCommand );
+ const XubString& GetItemCommand( USHORT nItemId ) const;
+
+ void SetHelpText( USHORT nItemId, const XubString& rString );
+ const XubString& GetHelpText( USHORT nItemId ) const;
+
+ void SetTipHelpText( USHORT nItemId, const XubString& rString );
+ const XubString& GetTipHelpText( USHORT nItemId ) const;
+
+ void SetHelpCommand( USHORT nItemId, const XubString& rString );
+ const XubString& GetHelpCommand( USHORT nItemId ) const;
+
+ void SetHelpId( USHORT nItemId, ULONG nHelpId );
+ ULONG GetHelpId( USHORT nItemId ) const;
+
+ void SetActivateHdl( const Link& rLink ) { aActivateHdl = rLink; }
+ const Link& GetActivateHdl() const { return aActivateHdl; }
+
+ void SetDeactivateHdl( const Link& rLink ) { aDeactivateHdl = rLink; }
+ const Link& GetDeactivateHdl() const { return aDeactivateHdl; }
+
+ void SetHighlightHdl( const Link& rLink ) { aHighlightHdl = rLink; }
+ const Link& GetHighlightHdl() const { return aHighlightHdl; }
+
+ void SetSelectHdl( const Link& rLink ) { aSelectHdl = rLink; }
+ const Link& GetSelectHdl() const { return aSelectHdl; }
+
+ void SetLogo( const MenuLogo& rLogo );
+ void SetLogo();
+ BOOL HasLogo() const { return pLogo ? TRUE : FALSE; }
+ MenuLogo GetLogo() const;
+
+ void AddEventListener( const Link& rEventListener );
+ void RemoveEventListener( const Link& rEventListener );
+ //void AddChildEventListener( const Link& rEventListener );
+ //void RemoveChildEventListener( const Link& rEventListener );
+
+ Menu& operator =( const Menu& rMenu );
+
+ // Fuer Menu-'Funktionen'
+ MenuItemList* GetItemList() const { return pItemList; }
+
+ // returns the system's menu handle if native menues are supported
+ // pData must point to a SystemMenuData structure
+ BOOL GetSystemMenuData( SystemMenuData* pData ) const;
+
+ // accessibility helpers
+
+ // gets the displayed text
+ String GetDisplayText() const;
+ // returns the bounding box for the character at index nIndex
+ // where nIndex is relative to the starting index of the item
+ // with id nItemId (in coordinates of the displaying window)
+ Rectangle GetCharacterBounds( USHORT nItemId, long nIndex ) const;
+ // -1 is returned if no character is at that point
+ // if an index is found the corresponding item id is filled in (else 0)
+ long GetIndexForPoint( const Point& rPoint, USHORT& rItemID ) const;
+ // returns the number of lines in the result of GetDisplayText()
+ long GetLineCount() const;
+ // returns the interval [start,end] of line nLine
+ // returns [-1,-1] for an invalid line
+ Pair GetLineStartEnd( long nLine ) const;
+ // like GetLineStartEnd but first finds the line number for the item
+ Pair GetItemStartEnd( USHORT nItemId ) const;
+ // returns the item id for line nLine or 0 if nLine is invalid
+ USHORT GetDisplayItemId( long nLine ) const;
+ // returns the bounding rectangle for an item at pos nItemPos
+ Rectangle GetBoundingRectangle( USHORT nItemPos ) const;
+ BOOL ConvertPoint( Point& rPoint, Window* pReferenceWindow ) const;
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > GetAccessible();
+ void SetAccessible( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& rxAccessible );
+
+ // gets the activation key of the specified item
+ KeyEvent GetActivationKey( USHORT nItemId ) const;
+
+ Window* GetWindow() const { return pWindow; }
+
+ void SetAccessibleName( USHORT nItemId, const XubString& rStr );
+ XubString GetAccessibleName( USHORT nItemId ) const;
+
+ void SetAccessibleDescription( USHORT nItemId, const XubString& rStr );
+ XubString GetAccessibleDescription( USHORT nItemId ) const;
+
+ // returns whether the item a position nItemPos is highlighted or not.
+ bool IsHighlighted( USHORT nItemPos ) const;
+
+ void HighlightItem( USHORT nItemPos );
+ void DeHighlight() { HighlightItem( 0xFFFF ); } // MENUITEMPOS_INVALID
+
+
+ void doLazyDelete();
+};
+
+// -----------
+// - MenuBar -
+// -----------
+
+class VCL_DLLPUBLIC MenuBar : public Menu
+{
+ Link maCloserHdl;
+ Link maFloatHdl;
+ Link maHideHdl;
+ BOOL mbCloserVisible;
+ BOOL mbFloatBtnVisible;
+ BOOL mbHideBtnVisible;
+ BOOL mbDisplayable;
+
+//#if 0 // _SOLAR__PRIVATE
+ friend class Application;
+ friend class Menu;
+ friend class MenuBarWindow;
+ friend class MenuFloatingWindow;
+ friend class SystemWindow;
+
+ SAL_DLLPRIVATE static Window* ImplCreate( Window* pParent, Window* pWindow, MenuBar* pMenu );
+ SAL_DLLPRIVATE static void ImplDestroy( MenuBar* pMenu, BOOL bDelete );
+ SAL_DLLPRIVATE BOOL ImplHandleKeyEvent( const KeyEvent& rKEvent, BOOL bFromMenu = TRUE );
+//#endif
+
+public:
+ MenuBar();
+ MenuBar( const ResId& rResId );
+ MenuBar( const MenuBar& rMenu );
+ ~MenuBar();
+
+ MenuBar& operator =( const MenuBar& rMenu );
+
+ void ShowCloser( BOOL bShow = TRUE );
+ BOOL HasCloser() const { return mbCloserVisible; }
+ void ShowFloatButton( BOOL bShow = TRUE );
+ BOOL HasFloatButton() const { return mbFloatBtnVisible; }
+ void ShowHideButton( BOOL bShow = TRUE );
+ BOOL HasHideButton() const { return mbHideBtnVisible; }
+ void ShowButtons( BOOL bClose, BOOL bFloat, BOOL bHide );
+
+ void SelectEntry( USHORT nId );
+ BOOL HandleMenuActivateEvent( Menu *pMenu ) const;
+ BOOL HandleMenuDeActivateEvent( Menu *pMenu ) const;
+ BOOL HandleMenuHighlightEvent( Menu *pMenu, USHORT nEventId ) const;
+ BOOL HandleMenuCommandEvent( Menu *pMenu, USHORT nEventId ) const;
+ BOOL HandleMenuButtonEvent( Menu *pMenu, USHORT nEventId ) const;
+
+ void SetCloserHdl( const Link& rLink ) { maCloserHdl = rLink; }
+ const Link& GetCloserHdl() const { return maCloserHdl; }
+ void SetFloatButtonClickHdl( const Link& rLink ) { maFloatHdl = rLink; }
+ const Link& GetFloatButtonClickHdl() const { return maFloatHdl; }
+ void SetHideButtonClickHdl( const Link& rLink ) { maHideHdl = rLink; }
+ const Link& GetHideButtonClickHdl() const { return maHideHdl; }
+
+ // - by default a menubar is displayable
+ // - if a menubar is not displayable, its MenuBarWindow will never be shown
+ // and it will be hidden if it was visible before
+ // - note: if a menubar is diplayable, this does not necessarily mean that it is currently visible
+ void SetDisplayable( BOOL bDisplayable );
+ BOOL IsDisplayable() const { return mbDisplayable; }
+
+ struct MenuBarButtonCallbackArg
+ {
+ USHORT nId; // Id of the button
+ bool bHighlight; // highlight on/off
+ MenuBar* pMenuBar; // menubar the button belongs to
+ };
+ // add an arbitrary button to the menubar (will appear next to closer)
+ // passed link will be call with a MenuBarButtonCallbackArg on press
+ USHORT AddMenuBarButton( const Image&, const Link&, USHORT nPos = 0 );
+ // add an arbitrary button to the menubar (will appear next to closer)
+ // passed link will be call with a MenuBarButtonCallbackArg on press
+ // passed string will be set as tooltip
+ USHORT AddMenuBarButton( const Image&, const Link&, const String&, USHORT nPos = 0 );
+ // set the highlight link for additional button with ID nId
+ // highlight link will be called with a MenuBarButtonHighlightArg
+ // the bHighlight member of that struct shall contain the new state
+ void SetMenuBarButtonHighlightHdl( USHORT nId, const Link& );
+ // returns the rectangle occupied by the additional button named nId
+ // coordinates are relative to the systemwindiow the menubar is attached to
+ // if the menubar is unattached an empty rectangle is returned
+ Rectangle GetMenuBarButtonRectPixel( USHORT nId );
+ void RemoveMenuBarButton( USHORT nId );
+};
+
+inline MenuBar& MenuBar::operator =( const MenuBar& rMenu )
+{
+ Menu::operator =( rMenu );
+ return *this;
+}
+
+
+// -------------
+// - PopupMenu -
+// -------------
+
+class VCL_DLLPUBLIC PopupMenu : public Menu
+{
+ friend class Menu;
+ friend class MenuFloatingWindow;
+ friend class MenuBarWindow;
+ friend struct MenuItemData;
+
+private:
+ Menu** pRefAutoSubMenu; // keeps track if a pointer to this Menu is stored in the MenuItemData
+
+ SAL_DLLPRIVATE MenuFloatingWindow* ImplGetFloatingWindow() const { return (MenuFloatingWindow*)Menu::ImplGetWindow(); }
+
+protected:
+ SAL_DLLPRIVATE USHORT ImplExecute( Window* pWindow, const Rectangle& rRect, ULONG nPopupFlags, Menu* pStaredFrom, BOOL bPreSelectFirst );
+ SAL_DLLPRIVATE long ImplCalcHeight( USHORT nEntries ) const;
+ SAL_DLLPRIVATE USHORT ImplCalcVisEntries( long nMaxHeight, USHORT nStartEntry = 0, USHORT* pLastVisible = NULL ) const;
+
+public:
+ PopupMenu();
+ PopupMenu( const PopupMenu& rMenu );
+ PopupMenu( const ResId& rResId );
+ ~PopupMenu();
+
+ void SetText( const XubString& rTitle ) { aTitleText = rTitle; }
+ const XubString& GetText() const { return aTitleText; }
+
+ USHORT Execute( Window* pWindow, const Point& rPopupPos );
+ USHORT Execute( Window* pWindow, const Rectangle& rRect, USHORT nFlags = 0 );
+
+ // Fuer das TestTool
+ void EndExecute( USHORT nSelect = 0 );
+ void SelectEntry( USHORT nId );
+ void SetSelectedEntry( USHORT nId ); // for use by native submenu only
+
+ static BOOL IsInExecute();
+ static PopupMenu* GetActivePopupMenu();
+
+ PopupMenu& operator =( const PopupMenu& rMenu );
+};
+
+inline PopupMenu& PopupMenu::operator =( const PopupMenu& rMenu )
+{
+ Menu::operator =( rMenu );
+ return *this;
+}
+
+#endif // _SV_MENU_HXX
+
diff --git a/vcl/inc/vcl/menubtn.hxx b/vcl/inc/vcl/menubtn.hxx
new file mode 100644
index 000000000000..1c7122054a4f
--- /dev/null
+++ b/vcl/inc/vcl/menubtn.hxx
@@ -0,0 +1,98 @@
+/*************************************************************************
+ *
+ * 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_MENUBTN_HXX
+#define _SV_MENUBTN_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/button.hxx>
+
+class Timer;
+class PopupMenu;
+
+// --------------------
+// - MenuButton-Types -
+// --------------------
+
+#define MENUBUTTON_MENUMODE_TIMED ((USHORT)0x0001)
+
+// --------------
+// - MenuButton -
+// --------------
+
+class VCL_DLLPUBLIC MenuButton : public PushButton
+{
+private:
+ Rectangle maFocusRect;
+ Timer* mpMenuTimer;
+ PopupMenu* mpOwnMenu;
+ PopupMenu* mpMenu;
+ USHORT mnCurItemId;
+ USHORT mnMenuMode;
+ Link maActivateHdl;
+ Link maSelectHdl;
+
+ SAL_DLLPRIVATE void ImplInitMenuButtonData();
+ SAL_DLLPRIVATE void ImplExecuteMenu();
+ DECL_DLLPRIVATE_LINK( ImplMenuTimeoutHdl, Timer* );
+
+ // Copy assignment is forbidden and not implemented.
+ SAL_DLLPRIVATE MenuButton( const MenuButton & );
+ SAL_DLLPRIVATE MenuButton& operator=( const MenuButton & );
+
+protected:
+ using Window::ImplInit;
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle );
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+
+public:
+ MenuButton( Window* pParent, WinBits nStyle = 0 );
+ MenuButton( Window* pParent, const ResId& rResId );
+ ~MenuButton();
+
+ virtual void MouseButtonDown( const MouseEvent& rMEvt );
+ virtual void KeyInput( const KeyEvent& rKEvt );
+
+ virtual void Activate();
+ virtual void Select();
+
+ void SetMenuMode( USHORT nMode );
+ USHORT GetMenuMode() const { return mnMenuMode; }
+
+ void SetPopupMenu( PopupMenu* pNewMenu );
+ PopupMenu* GetPopupMenu() const { return mpMenu; }
+
+ USHORT GetCurItemId() const { return mnCurItemId; }
+
+ void SetActivateHdl( const Link& rLink ) { maActivateHdl = rLink; }
+ const Link& GetActivateHdl() const { return maActivateHdl; }
+ void SetSelectHdl( const Link& rLink ) { maSelectHdl = rLink; }
+ const Link& GetSelectHdl() const { return maSelectHdl; }
+};
+
+#endif // _SV_MENUBTN_HXX
diff --git a/vcl/inc/vcl/metaact.hxx b/vcl/inc/vcl/metaact.hxx
new file mode 100644
index 000000000000..38ceff6e0690
--- /dev/null
+++ b/vcl/inc/vcl/metaact.hxx
@@ -0,0 +1,1546 @@
+/*************************************************************************
+ *
+ * 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_METAACT_HXX
+#define _SV_METAACT_HXX
+
+#include <vcl/dllapi.h>
+#include <vcl/gradient.hxx>
+#include <vcl/hatch.hxx>
+#include <vcl/wall.hxx>
+#include <vcl/font.hxx>
+#include <tools/poly.hxx>
+#include <vcl/bitmap.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/region.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/gfxlink.hxx>
+#include <vcl/lineinfo.hxx>
+
+class SvStream;
+
+// -----------
+// - Defines -
+// -----------
+
+#define META_NULL_ACTION (0)
+#define META_PIXEL_ACTION (100)
+#define META_POINT_ACTION (101)
+#define META_LINE_ACTION (102)
+#define META_RECT_ACTION (103)
+#define META_ROUNDRECT_ACTION (104)
+#define META_ELLIPSE_ACTION (105)
+#define META_ARC_ACTION (106)
+#define META_PIE_ACTION (107)
+#define META_CHORD_ACTION (108)
+#define META_POLYLINE_ACTION (109)
+#define META_POLYGON_ACTION (110)
+#define META_POLYPOLYGON_ACTION (111)
+#define META_TEXT_ACTION (112)
+#define META_TEXTARRAY_ACTION (113)
+#define META_STRETCHTEXT_ACTION (114)
+#define META_TEXTRECT_ACTION (115)
+#define META_BMP_ACTION (116)
+#define META_BMPSCALE_ACTION (117)
+#define META_BMPSCALEPART_ACTION (118)
+#define META_BMPEX_ACTION (119)
+#define META_BMPEXSCALE_ACTION (120)
+#define META_BMPEXSCALEPART_ACTION (121)
+#define META_MASK_ACTION (122)
+#define META_MASKSCALE_ACTION (123)
+#define META_MASKSCALEPART_ACTION (124)
+#define META_GRADIENT_ACTION (125)
+#define META_HATCH_ACTION (126)
+#define META_WALLPAPER_ACTION (127)
+#define META_CLIPREGION_ACTION (128)
+#define META_ISECTRECTCLIPREGION_ACTION (129)
+#define META_ISECTREGIONCLIPREGION_ACTION (130)
+#define META_MOVECLIPREGION_ACTION (131)
+#define META_LINECOLOR_ACTION (132)
+#define META_FILLCOLOR_ACTION (133)
+#define META_TEXTCOLOR_ACTION (134)
+#define META_TEXTFILLCOLOR_ACTION (135)
+#define META_TEXTALIGN_ACTION (136)
+#define META_MAPMODE_ACTION (137)
+#define META_FONT_ACTION (138)
+#define META_PUSH_ACTION (139)
+#define META_POP_ACTION (140)
+#define META_RASTEROP_ACTION (141)
+#define META_TRANSPARENT_ACTION (142)
+#define META_EPS_ACTION (143)
+#define META_REFPOINT_ACTION (144)
+#define META_TEXTLINECOLOR_ACTION (145)
+#define META_TEXTLINE_ACTION (146)
+#define META_FLOATTRANSPARENT_ACTION (147)
+#define META_GRADIENTEX_ACTION (148)
+#define META_LAYOUTMODE_ACTION (149)
+#define META_TEXTLANGUAGE_ACTION (150)
+#define META_OVERLINECOLOR_ACTION (151)
+
+#define META_COMMENT_ACTION (512)
+
+// ------------------------------------------------------------------------
+
+struct ImplMetaReadData
+{
+ rtl_TextEncoding meActualCharSet;
+};
+
+// ------------------------------------------------------------------------
+
+struct ImplMetaWriteData
+{
+ rtl_TextEncoding meActualCharSet;
+};
+
+// ------------------------------------------------------------------------
+
+#define DECL_META_ACTION( Name, nType ) \
+ Meta##Name##Action(); \
+protected: \
+ virtual ~Meta##Name##Action(); \
+public: \
+ virtual void Execute( OutputDevice* pOut ); \
+ virtual MetaAction* Clone(); \
+ virtual void Write( SvStream& rOStm, ImplMetaWriteData* pData ); \
+ virtual void Read( SvStream& rIStm, ImplMetaReadData* pData );
+
+#define IMPL_META_ACTION( Name, nType ) \
+Meta##Name##Action::Meta##Name##Action() : \
+ MetaAction( nType ) {} \
+Meta##Name##Action::~Meta##Name##Action() {}
+
+// --------------
+// - MetaAction -
+// --------------
+
+class VCL_DLLPUBLIC MetaAction
+{
+private:
+ ULONG mnRefCount;
+ UINT16 mnType;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+protected:
+ virtual ~MetaAction();
+
+public:
+ MetaAction();
+ MetaAction( USHORT nType );
+
+ virtual void Execute( OutputDevice* pOut );
+
+ virtual MetaAction* Clone();
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ virtual void Write( SvStream& rOStm, ImplMetaWriteData* pData );
+ virtual void Read( SvStream& rIStm, ImplMetaReadData* pData );
+
+ sal_Bool IsEqual( const MetaAction& ) const;
+
+ USHORT GetType() const { return mnType; }
+ ULONG GetRefCount() const { return mnRefCount; }
+ void ResetRefCount() { mnRefCount = 1; }
+ void Duplicate() { mnRefCount++; }
+ void Delete() { if ( 0 == --mnRefCount ) delete this; }
+
+public:
+ static MetaAction* ReadMetaAction( SvStream& rIStm, ImplMetaReadData* pData );
+};
+
+// -------------------
+// - MetaPixelAction -
+// -------------------
+
+class VCL_DLLPUBLIC MetaPixelAction : public MetaAction
+{
+private:
+ Point maPt;
+ Color maColor;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( Pixel, META_PIXEL_ACTION )
+
+ MetaPixelAction( const Point& rPt, const Color& rColor );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const Point& GetPoint() const { return maPt; }
+ const Color& GetColor() const { return maColor; }
+};
+
+// -------------------
+// - MetaPointAction -
+// -------------------
+
+class VCL_DLLPUBLIC MetaPointAction : public MetaAction
+{
+private:
+ Point maPt;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( Point, META_POINT_ACTION )
+
+ MetaPointAction( const Point& rPt );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const Point& GetPoint() const { return maPt; }
+};
+
+// ------------------
+// - MetaLineAction -
+// ------------------
+
+class VCL_DLLPUBLIC MetaLineAction : public MetaAction
+{
+private:
+
+ LineInfo maLineInfo;
+ Point maStartPt;
+ Point maEndPt;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( Line, META_LINE_ACTION )
+
+ MetaLineAction( const Point& rStart, const Point& rEnd );
+ MetaLineAction( const Point& rStart, const Point& rEnd,
+ const LineInfo& rLineInfo );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const Point& GetStartPoint() const { return maStartPt; }
+ const Point& GetEndPoint() const { return maEndPt; }
+ const LineInfo& GetLineInfo() const { return maLineInfo; }
+};
+
+// ------------------
+// - MetaRectAction -
+// ------------------
+
+class VCL_DLLPUBLIC MetaRectAction : public MetaAction
+{
+private:
+
+ Rectangle maRect;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+public:
+ DECL_META_ACTION( Rect, META_RECT_ACTION )
+
+ MetaRectAction( const Rectangle& rRect );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const Rectangle& GetRect() const { return maRect; }
+};
+
+// -----------------------
+// - MetaRoundRectAction -
+// -----------------------
+
+class VCL_DLLPUBLIC MetaRoundRectAction : public MetaAction
+{
+private:
+
+ Rectangle maRect;
+ sal_uInt32 mnHorzRound;
+ sal_uInt32 mnVertRound;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( RoundRect, META_ROUNDRECT_ACTION )
+
+ MetaRoundRectAction( const Rectangle& rRect,
+ sal_uInt32 nHorzRound, sal_uInt32 nVertRound );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const Rectangle& GetRect() const { return maRect; }
+ sal_uInt32 GetHorzRound() const { return mnHorzRound; }
+ sal_uInt32 GetVertRound() const { return mnVertRound; }
+};
+
+// ---------------------
+// - MetaEllipseAction -
+// ---------------------
+
+class VCL_DLLPUBLIC MetaEllipseAction : public MetaAction
+{
+private:
+
+ Rectangle maRect;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( Ellipse, META_ELLIPSE_ACTION )
+
+ MetaEllipseAction( const Rectangle& rRect );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const Rectangle& GetRect() const { return maRect; }
+};
+
+// -----------------
+// - MetaArcAction -
+// -----------------
+
+class VCL_DLLPUBLIC MetaArcAction : public MetaAction
+{
+private:
+
+ Rectangle maRect;
+ Point maStartPt;
+ Point maEndPt;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( Arc, META_ARC_ACTION )
+
+ MetaArcAction( const Rectangle& rRect,
+ const Point& rStart, const Point& rEnd );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const Rectangle& GetRect() const { return maRect; }
+ const Point& GetStartPoint() const { return maStartPt; }
+ const Point& GetEndPoint() const { return maEndPt; }
+};
+
+// -----------------
+// - MetaPieAction -
+// -----------------
+
+class VCL_DLLPUBLIC MetaPieAction : public MetaAction
+{
+private:
+
+ Rectangle maRect;
+ Point maStartPt;
+ Point maEndPt;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( Pie, META_PIE_ACTION )
+
+ MetaPieAction( const Rectangle& rRect,
+ const Point& rStart, const Point& rEnd );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const Rectangle& GetRect() const { return maRect; }
+ const Point& GetStartPoint() const { return maStartPt; }
+ const Point& GetEndPoint() const { return maEndPt; }
+};
+
+// -------------------
+// - MetaChordAction -
+// -------------------
+
+class VCL_DLLPUBLIC MetaChordAction : public MetaAction
+{
+private:
+
+ Rectangle maRect;
+ Point maStartPt;
+ Point maEndPt;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( Chord, META_CHORD_ACTION )
+
+ MetaChordAction( const Rectangle& rRect,
+ const Point& rStart, const Point& rEnd );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const Rectangle& GetRect() const { return maRect; }
+ const Point& GetStartPoint() const { return maStartPt; }
+ const Point& GetEndPoint() const { return maEndPt; }
+};
+
+// ----------------------
+// - MetaPolyLineAction -
+// ----------------------
+
+class VCL_DLLPUBLIC MetaPolyLineAction : public MetaAction
+{
+private:
+
+ LineInfo maLineInfo;
+ Polygon maPoly;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( PolyLine, META_POLYLINE_ACTION )
+
+ MetaPolyLineAction( const Polygon& rPoly );
+ MetaPolyLineAction( const Polygon& rPoly, const LineInfo& rLineInfo );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const Polygon& GetPolygon() const { return maPoly; }
+ const LineInfo& GetLineInfo() const { return maLineInfo; }
+};
+
+// ---------------------
+// - MetaPolygonAction -
+// ---------------------
+
+class VCL_DLLPUBLIC MetaPolygonAction : public MetaAction
+{
+private:
+
+ Polygon maPoly;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( Polygon, META_POLYGON_ACTION )
+
+ MetaPolygonAction( const Polygon& rPoly );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const Polygon& GetPolygon() const { return maPoly; }
+};
+
+// -------------------------
+// - MetaPolyPolygonAction -
+// -------------------------
+
+class VCL_DLLPUBLIC MetaPolyPolygonAction : public MetaAction
+{
+private:
+
+ PolyPolygon maPolyPoly;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( PolyPolygon, META_POLYPOLYGON_ACTION )
+
+ MetaPolyPolygonAction( const PolyPolygon& rPolyPoly );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const PolyPolygon& GetPolyPolygon() const { return maPolyPoly; }
+};
+
+// ------------------
+// - MetaTextAction -
+// ------------------
+
+class VCL_DLLPUBLIC MetaTextAction : public MetaAction
+{
+private:
+
+ Point maPt;
+ XubString maStr;
+ USHORT mnIndex;
+ USHORT mnLen;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( Text, META_TEXT_ACTION )
+
+ MetaTextAction( const Point& rPt, const XubString& rStr,
+ USHORT nIndex, USHORT nLen );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const Point& GetPoint() const { return maPt; }
+ const XubString& GetText() const { return maStr; }
+ USHORT GetIndex() const { return mnIndex; }
+ USHORT GetLen() const { return mnLen; }
+};
+
+// -----------------------
+// - MetaTextArrayAction -
+// -----------------------
+
+class VCL_DLLPUBLIC MetaTextArrayAction : public MetaAction
+{
+private:
+
+ Point maStartPt;
+ XubString maStr;
+ sal_Int32* mpDXAry;
+ USHORT mnIndex;
+ USHORT mnLen;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+protected:
+ virtual ~MetaTextArrayAction();
+
+public:
+ MetaTextArrayAction();
+ MetaTextArrayAction( const MetaTextArrayAction& rAction );
+ MetaTextArrayAction( const Point& rStartPt,
+ const XubString& rStr,
+ const sal_Int32* pDXAry,
+ USHORT nIndex,
+ USHORT nLen );
+
+ virtual void Execute( OutputDevice* pOut );
+
+ virtual MetaAction* Clone();
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ virtual void Write( SvStream& rOStm, ImplMetaWriteData* pData );
+ virtual void Read( SvStream& rIStm, ImplMetaReadData* pData );
+
+ const Point& GetPoint() const { return maStartPt; }
+ const XubString& GetText() const { return maStr; }
+ USHORT GetIndex() const { return mnIndex; }
+ USHORT GetLen() const { return mnLen; }
+ sal_Int32* GetDXArray() const { return mpDXAry; }
+};
+
+// -------------------------
+// - MetaStretchTextAction -
+// -------------------------
+
+class VCL_DLLPUBLIC MetaStretchTextAction : public MetaAction
+{
+private:
+
+ Point maPt;
+ XubString maStr;
+ sal_uInt32 mnWidth;
+ USHORT mnIndex;
+ USHORT mnLen;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( StretchText, META_STRETCHTEXT_ACTION )
+
+ MetaStretchTextAction( const Point& rPt, sal_uInt32 nWidth,
+ const XubString& rStr,
+ USHORT nIndex, USHORT nLen );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const Point& GetPoint() const { return maPt; }
+ const XubString& GetText() const { return maStr; }
+ sal_uInt32 GetWidth() const { return mnWidth; }
+ USHORT GetIndex() const { return mnIndex; }
+ USHORT GetLen() const { return mnLen; }
+};
+
+// ----------------------
+// - MetaTextRectAction -
+// ----------------------
+
+class VCL_DLLPUBLIC MetaTextRectAction : public MetaAction
+{
+private:
+
+ Rectangle maRect;
+ XubString maStr;
+ USHORT mnStyle;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( TextRect, META_TEXTRECT_ACTION )
+
+ MetaTextRectAction( const Rectangle& rRect,
+ const XubString& rStr, USHORT nStyle );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const Rectangle& GetRect() const { return maRect; }
+ const XubString& GetText() const { return maStr; }
+ USHORT GetStyle() const { return mnStyle; }
+};
+
+// ----------------------
+// - MetaTextLineAction -
+// ----------------------
+
+class VCL_DLLPUBLIC MetaTextLineAction : public MetaAction
+{
+private:
+
+ Point maPos;
+ long mnWidth;
+ FontStrikeout meStrikeout;
+ FontUnderline meUnderline;
+ FontUnderline meOverline;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( TextLine, META_TEXTLINE_ACTION )
+
+ MetaTextLineAction( const Point& rPos, long nWidth,
+ FontStrikeout eStrikeout,
+ FontUnderline eUnderline,
+ FontUnderline eOverline );
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const Point& GetStartPoint() const { return maPos; }
+ long GetWidth() const { return mnWidth; }
+ FontStrikeout GetStrikeout() const { return meStrikeout; }
+ FontUnderline GetUnderline() const { return meUnderline; }
+ FontUnderline GetOverline() const { return meOverline; }
+};
+
+// -----------------
+// - MetaBmpAction -
+// -----------------
+
+class VCL_DLLPUBLIC MetaBmpAction : public MetaAction
+{
+private:
+
+ Bitmap maBmp;
+ Point maPt;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( Bmp, META_BMP_ACTION )
+
+ MetaBmpAction( const Point& rPt, const Bitmap& rBmp );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const Bitmap& GetBitmap() const { return maBmp; }
+ const Point& GetPoint() const { return maPt; }
+};
+
+// ----------------------
+// - MetaBmpScaleAction -
+// ----------------------
+
+class VCL_DLLPUBLIC MetaBmpScaleAction : public MetaAction
+{
+private:
+
+ Bitmap maBmp;
+ Point maPt;
+ Size maSz;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( BmpScale, META_BMPSCALE_ACTION )
+
+ MetaBmpScaleAction( const Point& rPt, const Size& rSz,
+ const Bitmap& rBmp );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const Bitmap& GetBitmap() const { return maBmp; }
+ const Point& GetPoint() const { return maPt; }
+ const Size& GetSize() const { return maSz; }
+};
+
+// --------------------------
+// - MetaBmpScalePartAction -
+// --------------------------
+
+class VCL_DLLPUBLIC MetaBmpScalePartAction : public MetaAction
+{
+private:
+
+ Bitmap maBmp;
+ Point maDstPt;
+ Size maDstSz;
+ Point maSrcPt;
+ Size maSrcSz;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( BmpScalePart, META_BMPSCALEPART_ACTION )
+
+ MetaBmpScalePartAction( const Point& rDstPt, const Size& rDstSz,
+ const Point& rSrcPt, const Size& rSrcSz,
+ const Bitmap& rBmp );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const Bitmap& GetBitmap() const { return maBmp; }
+ const Point& GetDestPoint() const { return maDstPt; }
+ const Size& GetDestSize() const { return maDstSz; }
+ const Point& GetSrcPoint() const { return maSrcPt; }
+ const Size& GetSrcSize() const { return maSrcSz; }
+};
+
+// -----------------
+// - MetaBmpExAction -
+// -----------------
+
+class VCL_DLLPUBLIC MetaBmpExAction : public MetaAction
+{
+private:
+
+ BitmapEx maBmpEx;
+ Point maPt;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( BmpEx, META_BMPEX_ACTION )
+
+ MetaBmpExAction( const Point& rPt, const BitmapEx& rBmpEx );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const BitmapEx& GetBitmapEx() const { return maBmpEx; }
+ const Point& GetPoint() const { return maPt; }
+};
+
+// ----------------------
+// - MetaBmpExScaleAction -
+// ----------------------
+
+class VCL_DLLPUBLIC MetaBmpExScaleAction : public MetaAction
+{
+private:
+
+ BitmapEx maBmpEx;
+ Point maPt;
+ Size maSz;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( BmpExScale, META_BMPEXSCALE_ACTION )
+
+ MetaBmpExScaleAction( const Point& rPt, const Size& rSz,
+ const BitmapEx& rBmpEx ) ;
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const BitmapEx& GetBitmapEx() const { return maBmpEx; }
+ const Point& GetPoint() const { return maPt; }
+ const Size& GetSize() const { return maSz; }
+};
+
+// ----------------------------
+// - MetaBmpExScalePartAction -
+// ----------------------------
+
+class VCL_DLLPUBLIC MetaBmpExScalePartAction : public MetaAction
+{
+private:
+
+ BitmapEx maBmpEx;
+ Point maDstPt;
+ Size maDstSz;
+ Point maSrcPt;
+ Size maSrcSz;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( BmpExScalePart, META_BMPEXSCALEPART_ACTION )
+
+ MetaBmpExScalePartAction( const Point& rDstPt, const Size& rDstSz,
+ const Point& rSrcPt, const Size& rSrcSz,
+ const BitmapEx& rBmpEx );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const BitmapEx& GetBitmapEx() const { return maBmpEx; }
+ const Point& GetDestPoint() const { return maDstPt; }
+ const Size& GetDestSize() const { return maDstSz; }
+ const Point& GetSrcPoint() const { return maSrcPt; }
+ const Size& GetSrcSize() const { return maSrcSz; }
+};
+
+// ------------------
+// - MetaMaskAction -
+// ------------------
+
+class VCL_DLLPUBLIC MetaMaskAction : public MetaAction
+{
+private:
+
+ Bitmap maBmp;
+ Color maColor;
+ Point maPt;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( Mask, META_MASK_ACTION )
+
+ MetaMaskAction( const Point& rPt,
+ const Bitmap& rBmp,
+ const Color& rColor );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const Bitmap& GetBitmap() const { return maBmp; }
+ const Color& GetColor() const { return maColor; }
+ const Point& GetPoint() const { return maPt; }
+};
+
+// -----------------------
+// - MetaMaskScaleAction -
+// -----------------------
+
+class VCL_DLLPUBLIC MetaMaskScaleAction : public MetaAction
+{
+private:
+
+ Bitmap maBmp;
+ Color maColor;
+ Point maPt;
+ Size maSz;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( MaskScale, META_MASKSCALE_ACTION )
+
+ MetaMaskScaleAction( const Point& rPt, const Size& rSz,
+ const Bitmap& rBmp,
+ const Color& rColor );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const Bitmap& GetBitmap() const { return maBmp; }
+ const Color& GetColor() const { return maColor; }
+ const Point& GetPoint() const { return maPt; }
+ const Size& GetSize() const { return maSz; }
+};
+
+// ---------------------------
+// - MetaMaskScalePartAction -
+// ---------------------------
+
+class VCL_DLLPUBLIC MetaMaskScalePartAction : public MetaAction
+{
+private:
+
+ Bitmap maBmp;
+ Color maColor;
+ Point maDstPt;
+ Size maDstSz;
+ Point maSrcPt;
+ Size maSrcSz;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( MaskScalePart, META_MASKSCALEPART_ACTION )
+
+ MetaMaskScalePartAction( const Point& rDstPt, const Size& rDstSz,
+ const Point& rSrcPt, const Size& rSrcSz,
+ const Bitmap& rBmp,
+ const Color& rColor );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const Bitmap& GetBitmap() const { return maBmp; }
+ const Color& GetColor() const { return maColor; }
+ const Point& GetDestPoint() const { return maDstPt; }
+ const Size& GetDestSize() const { return maDstSz; }
+ const Point& GetSrcPoint() const { return maSrcPt; }
+ const Size& GetSrcSize() const { return maSrcSz; }
+};
+
+// ----------------------
+// - MetaGradientAction -
+// ----------------------
+
+class VCL_DLLPUBLIC MetaGradientAction : public MetaAction
+{
+private:
+
+ Rectangle maRect;
+ Gradient maGradient;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( Gradient, META_GRADIENT_ACTION )
+
+ MetaGradientAction( const Rectangle& rRect, const Gradient& rGradient );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const Rectangle& GetRect() const { return maRect; }
+ const Gradient& GetGradient() const { return maGradient; }
+};
+
+// ------------------------
+// - MetaGradientExAction -
+// ------------------------
+
+class VCL_DLLPUBLIC MetaGradientExAction : public MetaAction
+{
+private:
+
+ PolyPolygon maPolyPoly;
+ Gradient maGradient;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( GradientEx, META_GRADIENTEX_ACTION )
+
+ MetaGradientExAction( const PolyPolygon& rPolyPoly, const Gradient& rGradient );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const PolyPolygon& GetPolyPolygon() const { return maPolyPoly; }
+ const Gradient& GetGradient() const { return maGradient; }
+};
+
+// -------------------
+// - MetaHatchAction -
+// -------------------
+
+class VCL_DLLPUBLIC MetaHatchAction : public MetaAction
+{
+private:
+
+ PolyPolygon maPolyPoly;
+ Hatch maHatch;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( Hatch, META_HATCH_ACTION )
+
+ MetaHatchAction( const PolyPolygon& rPolyPoly, const Hatch& rHatch );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const PolyPolygon& GetPolyPolygon() const { return maPolyPoly; }
+ const Hatch& GetHatch() const { return maHatch; }
+};
+
+// -----------------------
+// - MetaWallpaperAction -
+// -----------------------
+
+class VCL_DLLPUBLIC MetaWallpaperAction : public MetaAction
+{
+private:
+
+ Rectangle maRect;
+ Wallpaper maWallpaper;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( Wallpaper, META_WALLPAPER_ACTION )
+
+ MetaWallpaperAction( const Rectangle& rRect,
+ const Wallpaper& rPaper );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const Rectangle& GetRect() const { return maRect; }
+ const Wallpaper& GetWallpaper() const { return maWallpaper; }
+};
+
+// ------------------------
+// - MetaClipRegionAction -
+// ------------------------
+
+class VCL_DLLPUBLIC MetaClipRegionAction : public MetaAction
+{
+private:
+
+ Region maRegion;
+ BOOL mbClip;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( ClipRegion, META_CLIPREGION_ACTION )
+
+ MetaClipRegionAction( const Region& rRegion, BOOL bClip );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const Region& GetRegion() const { return maRegion; }
+ BOOL IsClipping() const { return mbClip; }
+};
+
+// ---------------------------------
+// - MetaISectRectClipRegionAction -
+// ---------------------------------
+
+class VCL_DLLPUBLIC MetaISectRectClipRegionAction : public MetaAction
+{
+private:
+
+ Rectangle maRect;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( ISectRectClipRegion, META_ISECTRECTCLIPREGION_ACTION )
+
+ MetaISectRectClipRegionAction( const Rectangle& rRect );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const Rectangle& GetRect() const { return maRect; }
+};
+
+// -----------------------------------
+// - MetaISectRegionClipRegionAction -
+// -----------------------------------
+
+class VCL_DLLPUBLIC MetaISectRegionClipRegionAction : public MetaAction
+{
+private:
+
+ Region maRegion;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( ISectRegionClipRegion, META_ISECTREGIONCLIPREGION_ACTION )
+
+ MetaISectRegionClipRegionAction( const Region& rRegion );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const Region& GetRegion() const { return maRegion; }
+};
+
+// ----------------------------
+// - MetaMoveClipRegionAction -
+// ----------------------------
+
+class VCL_DLLPUBLIC MetaMoveClipRegionAction : public MetaAction
+{
+private:
+
+ long mnHorzMove;
+ long mnVertMove;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( MoveClipRegion, META_MOVECLIPREGION_ACTION )
+
+ MetaMoveClipRegionAction( long nHorzMove, long nVertMove );
+
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ long GetHorzMove() const { return mnHorzMove; }
+ long GetVertMove() const { return mnVertMove; }
+};
+
+// -----------------------
+// - MetaLineColorAction -
+// -----------------------
+
+class VCL_DLLPUBLIC MetaLineColorAction : public MetaAction
+{
+private:
+
+ Color maColor;
+ BOOL mbSet;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( LineColor, META_LINECOLOR_ACTION )
+
+ MetaLineColorAction( const Color& rColor, BOOL bSet );
+
+ const Color& GetColor() const { return maColor; }
+ BOOL IsSetting() const { return mbSet; }
+};
+
+// -----------------------
+// - MetaFillColorAction -
+// -----------------------
+
+class VCL_DLLPUBLIC MetaFillColorAction : public MetaAction
+{
+private:
+
+ Color maColor;
+ BOOL mbSet;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( FillColor, META_FILLCOLOR_ACTION )
+
+ MetaFillColorAction( const Color& rColor, BOOL bSet );
+
+ const Color& GetColor() const { return maColor; }
+ BOOL IsSetting() const { return mbSet; }
+};
+
+// -----------------------
+// - MetaTextColorAction -
+// -----------------------
+
+class VCL_DLLPUBLIC MetaTextColorAction : public MetaAction
+{
+private:
+
+ Color maColor;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( TextColor, META_TEXTCOLOR_ACTION )
+
+ MetaTextColorAction( const Color& rColor );
+
+ const Color& GetColor() const { return maColor; }
+};
+
+// ---------------------------
+// - MetaTextFillColorAction -
+// ---------------------------
+
+class VCL_DLLPUBLIC MetaTextFillColorAction : public MetaAction
+{
+private:
+
+ Color maColor;
+ BOOL mbSet;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( TextFillColor, META_TEXTFILLCOLOR_ACTION )
+
+ MetaTextFillColorAction( const Color& rColor, BOOL bSet );
+
+ const Color& GetColor() const { return maColor; }
+ BOOL IsSetting() const { return mbSet; }
+};
+
+// ---------------------------
+// - MetaTextLineColorAction -
+// ---------------------------
+
+class VCL_DLLPUBLIC MetaTextLineColorAction : public MetaAction
+{
+private:
+
+ Color maColor;
+ BOOL mbSet;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( TextLineColor, META_TEXTLINECOLOR_ACTION )
+
+ MetaTextLineColorAction( const Color& rColor, BOOL bSet );
+
+ const Color& GetColor() const { return maColor; }
+ BOOL IsSetting() const { return mbSet; }
+};
+
+// ---------------------------
+// - MetaOverlineColorAction -
+// ---------------------------
+
+class VCL_DLLPUBLIC MetaOverlineColorAction : public MetaAction
+{
+private:
+
+ Color maColor;
+ BOOL mbSet;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( OverlineColor, META_OVERLINECOLOR_ACTION )
+
+ MetaOverlineColorAction( const Color& rColor, BOOL bSet );
+
+ const Color& GetColor() const { return maColor; }
+ BOOL IsSetting() const { return mbSet; }
+};
+
+// -----------------------
+// - MetaTextAlignAction -
+// -----------------------
+
+class VCL_DLLPUBLIC MetaTextAlignAction : public MetaAction
+{
+private:
+
+ TextAlign maAlign;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( TextAlign, META_TEXTALIGN_ACTION )
+
+ MetaTextAlignAction( TextAlign aAlign );
+
+ TextAlign GetTextAlign() const { return maAlign; }
+};
+
+// ---------------------
+// - MetaMapModeAction -
+// ---------------------
+
+class VCL_DLLPUBLIC MetaMapModeAction : public MetaAction
+{
+private:
+
+ MapMode maMapMode;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( MapMode, META_MAPMODE_ACTION )
+
+ MetaMapModeAction( const MapMode& rMapMode );
+
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const MapMode& GetMapMode() const { return maMapMode; }
+};
+
+// ---------------------
+// - MetaFontAction -
+// ---------------------
+
+class VCL_DLLPUBLIC MetaFontAction : public MetaAction
+{
+private:
+
+ Font maFont;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( Font, META_FONT_ACTION )
+
+ MetaFontAction( const Font& rFont );
+
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const Font& GetFont() const { return maFont; }
+};
+
+// ------------------
+// - MetaPushAction -
+// ------------------
+
+class VCL_DLLPUBLIC MetaPushAction : public MetaAction
+{
+private:
+
+ USHORT mnFlags;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( Push, META_PUSH_ACTION )
+
+ MetaPushAction( USHORT nFlags );
+
+ USHORT GetFlags() const { return mnFlags; }
+};
+
+// -----------------
+// - MetaPopAction -
+// -----------------
+
+class VCL_DLLPUBLIC MetaPopAction : public MetaAction
+{
+public:
+
+ DECL_META_ACTION( Pop, META_POP_ACTION )
+};
+
+// ----------------------
+// - MetaRasterOpAction -
+// ----------------------
+
+class VCL_DLLPUBLIC MetaRasterOpAction : public MetaAction
+{
+private:
+
+ RasterOp meRasterOp;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( RasterOp, META_RASTEROP_ACTION )
+
+ MetaRasterOpAction( RasterOp eRasterOp );
+
+ RasterOp GetRasterOp() const { return meRasterOp; }
+};
+
+// -------------------------
+// - MetaTransparentAction -
+// -------------------------
+
+class VCL_DLLPUBLIC MetaTransparentAction : public MetaAction
+{
+private:
+
+ PolyPolygon maPolyPoly;
+ USHORT mnTransPercent;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( Transparent, META_TRANSPARENT_ACTION )
+
+ MetaTransparentAction( const PolyPolygon& rPolyPoly, USHORT nTransPercent );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const PolyPolygon& GetPolyPolygon() const { return maPolyPoly; }
+ USHORT GetTransparence() const { return mnTransPercent; }
+};
+
+// ------------------------------
+// - MetaFloatTransparentAction -
+// ------------------------------
+
+class VCL_DLLPUBLIC MetaFloatTransparentAction : public MetaAction
+{
+private:
+
+ GDIMetaFile maMtf;
+ Point maPoint;
+ Size maSize;
+ Gradient maGradient;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( FloatTransparent, META_FLOATTRANSPARENT_ACTION )
+
+ MetaFloatTransparentAction( const GDIMetaFile& rMtf, const Point& rPos,
+ const Size& rSize, const Gradient& rGradient );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const GDIMetaFile& GetGDIMetaFile() const { return maMtf; }
+ const Point& GetPoint() const { return maPoint; }
+ const Size& GetSize() const { return maSize; }
+ const Gradient& GetGradient() const { return maGradient; }
+};
+
+// ---------------------
+// - MetaDrawEPSAction -
+// ---------------------
+
+class VCL_DLLPUBLIC MetaEPSAction : public MetaAction
+{
+private:
+
+ GfxLink maGfxLink;
+ GDIMetaFile maSubst;
+ Point maPoint;
+ Size maSize;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( EPS, META_EPS_ACTION )
+
+ MetaEPSAction( const Point& rPoint, const Size& rSize,
+ const GfxLink& rGfxLink, const GDIMetaFile& rSubst );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ const GfxLink& GetLink() const { return maGfxLink; }
+ const GDIMetaFile& GetSubstitute() const { return maSubst; }
+ const Point& GetPoint() const { return maPoint; }
+ const Size& GetSize() const { return maSize; }
+};
+
+// ----------------------
+// - MetaRefPointAction -
+// ----------------------
+
+class VCL_DLLPUBLIC MetaRefPointAction : public MetaAction
+{
+private:
+
+ Point maRefPoint;
+ BOOL mbSet;
+
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( RefPoint, META_REFPOINT_ACTION )
+
+ MetaRefPointAction( const Point& rRefPoint, BOOL bSet );
+
+ const Point& GetRefPoint() const { return maRefPoint; }
+ BOOL IsSetting() const { return mbSet; }
+};
+
+// ---------------------
+// - MetaCommentAction -
+// ---------------------
+
+class VCL_DLLPUBLIC MetaCommentAction : public MetaAction
+{
+private:
+
+ ByteString maComment;
+ sal_Int32 mnValue;
+ sal_uInt32 mnDataSize;
+ BYTE* mpData;
+
+ SAL_DLLPRIVATE void ImplInitDynamicData( const BYTE* pData, sal_uInt32 nDataSize );
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+protected:
+ ~MetaCommentAction();
+
+public:
+ MetaCommentAction( sal_Int32 nValue = 0L );
+ MetaCommentAction( const MetaCommentAction& rAct );
+ MetaCommentAction( const ByteString& rComment, sal_Int32 nValue = 0L, const BYTE* pData = NULL, sal_uInt32 nDataSize = 0UL );
+ MetaCommentAction( const BYTE* pData, sal_uInt32 nDataSize );
+
+ virtual void Move( long nHorzMove, long nVertMove );
+ virtual void Scale( double fScaleX, double fScaleY );
+
+ virtual void Execute( OutputDevice* pOut );
+ virtual MetaAction* Clone();
+ virtual void Write( SvStream& rOStm, ImplMetaWriteData* pData );
+ virtual void Read( SvStream& rIStm, ImplMetaReadData* pData );
+
+ const ByteString& GetComment() const { return maComment; }
+ sal_Int32 GetValue() const { return mnValue; }
+ sal_uInt32 GetDataSize() const { return mnDataSize; }
+ const BYTE* GetData() const { return mpData; }
+};
+
+// ------------------------
+// - MetaLayoutModeAction -
+// ------------------------
+
+class VCL_DLLPUBLIC MetaLayoutModeAction : public MetaAction
+{
+private:
+
+ sal_uInt32 mnLayoutMode;
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( LayoutMode, META_LAYOUTMODE_ACTION )
+
+ MetaLayoutModeAction( sal_uInt32 nLayoutMode );
+
+ sal_uInt32 GetLayoutMode() const { return mnLayoutMode; }
+};
+
+// ------------------------
+// - MetaTextLanguageAction -
+// ------------------------
+
+class VCL_DLLPUBLIC MetaTextLanguageAction : public MetaAction
+{
+private:
+
+ LanguageType meTextLanguage;
+ virtual sal_Bool Compare( const MetaAction& ) const;
+
+public:
+ DECL_META_ACTION( TextLanguage, META_TEXTLANGUAGE_ACTION )
+
+ MetaTextLanguageAction( LanguageType );
+
+ LanguageType GetTextLanguage() const { return meTextLanguage; }
+};
+
+#endif // _SV_METAACT_HXX
diff --git a/vcl/inc/vcl/metric.hxx b/vcl/inc/vcl/metric.hxx
new file mode 100644
index 000000000000..eae6b38c5f9d
--- /dev/null
+++ b/vcl/inc/vcl/metric.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_METRIC_HXX
+#define _SV_METRIC_HXX
+
+#include <vcl/dllapi.h>
+#include <vcl/font.hxx>
+
+class ImplFontMetric;
+class ImplFontCharMap;
+
+typedef sal_uInt32 sal_UCS4;
+
+// ------------
+// - FontInfo -
+// ------------
+
+class VCL_DLLPUBLIC FontInfo : public Font
+{
+ friend class OutputDevice;
+
+protected:
+ ImplFontMetric* mpImplMetric; // Implementation
+
+public:
+ FontInfo();
+ FontInfo( const FontInfo& );
+ ~FontInfo();
+
+ FontType GetType() const;
+ BOOL IsDeviceFont() const;
+ BOOL SupportsLatin() const;
+ BOOL SupportsCJK() const;
+ BOOL SupportsCTL() const;
+
+ FontInfo& operator=( const FontInfo& );
+ BOOL operator==( const FontInfo& ) const;
+ BOOL operator!=( const FontInfo& rInfo ) const
+ { return !operator==( rInfo ); }
+};
+
+// --------------
+// - FontMetric -
+// --------------
+
+class VCL_DLLPUBLIC FontMetric : public FontInfo
+{
+public:
+ FontMetric() {}
+ FontMetric( const FontMetric& );
+ ~FontMetric() {}
+
+ long GetAscent() const;
+ long GetDescent() const;
+ long GetIntLeading() const;
+ long GetExtLeading() const;
+ long GetLineHeight() const;
+ long GetSlant() const;
+
+ FontMetric& operator=( const FontMetric& rMetric );
+ BOOL operator==( const FontMetric& rMetric ) const;
+ BOOL operator!=( const FontMetric& rMetric ) const
+ { return !operator==( rMetric ); }
+};
+
+// ---------------
+// - FontCharMap -
+// ---------------
+
+class VCL_DLLPUBLIC FontCharMap
+{
+private:
+ ImplFontCharMap* mpImpl;
+
+public:
+ FontCharMap();
+ ~FontCharMap();
+
+ BOOL IsDefaultMap() const;
+ BOOL HasChar( sal_uInt32 ) const;
+ int CountCharsInRange( sal_uInt32 cMin, sal_uInt32 cMax ) const;
+ int GetCharCount() const;
+
+ sal_uInt32 GetFirstChar() const;
+ sal_uInt32 GetLastChar() const;
+
+ sal_uInt32 GetNextChar( sal_uInt32 ) const;
+ sal_uInt32 GetPrevChar( sal_uInt32 ) const;
+
+ int GetIndexFromChar( sal_uInt32 ) const;
+ sal_uInt32 GetCharFromIndex( int ) const;
+
+
+private:
+ friend class OutputDevice;
+ void Reset( ImplFontCharMap* pNewMap = NULL );
+
+ // prevent assignment and copy construction
+ FontCharMap( const FontCharMap& );
+ void operator=( const FontCharMap& );
+};
+
+// ----------------
+// - TextRectInfo -
+// ----------------
+
+class VCL_DLLPUBLIC TextRectInfo
+{
+ friend class OutputDevice;
+
+private:
+ long mnMaxWidth;
+ USHORT mnLineCount;
+ BOOL mbEllipsis;
+
+public:
+ TextRectInfo();
+
+ USHORT GetLineCount() const { return mnLineCount; }
+ long GetMaxLineWidth() const { return mnMaxWidth; }
+ BOOL IsEllipses() const { return mbEllipsis; }
+
+ BOOL operator ==( const TextRectInfo& rInfo ) const
+ { return ((mnMaxWidth == rInfo.mnMaxWidth) &&
+ (mnLineCount == rInfo.mnLineCount) &&
+ (mbEllipsis == rInfo.mbEllipsis)); }
+ BOOL operator !=( const TextRectInfo& rInfo ) const
+ { return !(TextRectInfo::operator==( rInfo )); }
+};
+
+inline TextRectInfo::TextRectInfo()
+{
+ mnMaxWidth = 0;
+ mnLineCount = 0;
+ mbEllipsis = FALSE;
+}
+
+#endif // _SV_METRIC_HXX
diff --git a/vcl/inc/vcl/mnemonic.hxx b/vcl/inc/vcl/mnemonic.hxx
new file mode 100644
index 000000000000..804b261b79b4
--- /dev/null
+++ b/vcl/inc/vcl/mnemonic.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_MNEMONIC_HXX
+#define _SV_MNEMONIC_HXX
+
+#include <vcl/dllapi.h>
+#include <tools/string.hxx>
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/i18n/XCharacterClassification.hpp>
+
+// ---------------------
+// - ImplMnemonicTypes -
+// ---------------------
+
+// Mnemonic Chars, which we want support
+// Latin 0-9
+#define MNEMONIC_RANGE_1_START 0x30
+#define MNEMONIC_RANGE_1_END 0x39
+// Latin A-Z
+#define MNEMONIC_RANGE_2_START 0x41
+#define MNEMONIC_RANGE_2_END 0x5A
+// Cyrillic
+#define MNEMONIC_RANGE_3_START 0x0410
+#define MNEMONIC_RANGE_3_END 0x042F
+// Greek
+#define MNEMONIC_RANGE_4_START 0x0391
+#define MNEMONIC_RANGE_4_END 0x03AB
+#define MNEMONIC_RANGES 4
+#define MAX_MNEMONICS ((MNEMONIC_RANGE_1_END-MNEMONIC_RANGE_1_START+1)+\
+ (MNEMONIC_RANGE_2_END-MNEMONIC_RANGE_2_START+1)+\
+ (MNEMONIC_RANGE_3_END-MNEMONIC_RANGE_3_START+1)+\
+ (MNEMONIC_RANGE_4_END-MNEMONIC_RANGE_4_START+1))
+
+#define MNEMONIC_CHAR ((sal_Unicode)'~')
+#define MNEMONIC_INDEX_NOTFOUND ((USHORT)0xFFFF)
+
+// -------------------------
+// - MnemonicGenerator -
+// -------------------------
+
+class VCL_DLLPUBLIC MnemonicGenerator
+{
+private:
+ // 0 == Mnemonic; >0 == count of characters
+ BYTE maMnemonics[MAX_MNEMONICS];
+ ::com::sun::star::uno::Reference< ::com::sun::star::i18n::XCharacterClassification > mxCharClass;
+
+protected:
+ SAL_DLLPRIVATE USHORT ImplGetMnemonicIndex( sal_Unicode c );
+ SAL_DLLPRIVATE sal_Unicode ImplFindMnemonic( const XubString& rKey );
+
+public:
+ MnemonicGenerator();
+
+ void RegisterMnemonic( const XubString& rKey );
+ BOOL CreateMnemonic( XubString& rKey );
+ ::com::sun::star::uno::Reference< ::com::sun::star::i18n::XCharacterClassification > GetCharClass();
+
+ // returns a string where all '~'-characters and CJK mnemonics of the form (~A) are completely removed
+ static String EraseAllMnemonicChars( const String& rStr );
+};
+
+#endif // _SV_MNEMONIC_HXX
diff --git a/vcl/inc/vcl/mnemonicengine.hxx b/vcl/inc/vcl/mnemonicengine.hxx
new file mode 100644
index 000000000000..d12b3db2417e
--- /dev/null
+++ b/vcl/inc/vcl/mnemonicengine.hxx
@@ -0,0 +1,158 @@
+/*************************************************************************
+ *
+ * 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_MNEMONICENGINE_HXX
+#define VCL_MNEMONICENGINE_HXX
+
+#include "dllapi.h"
+
+#include <sal/config.h>
+#include <sal/types.h>
+
+#include <memory>
+
+class String;
+class KeyEvent;
+
+//........................................................................
+namespace vcl
+{
+//........................................................................
+
+ //====================================================================
+ //= IMnemonicEntryList
+ //====================================================================
+ /// callback for a MnemonicEngine
+ class SAL_NO_VTABLE VCL_DLLPUBLIC IMnemonicEntryList
+ {
+ public:
+ /** returns the first list entry for the mnemonic search
+
+ @return
+ a pointer which can be used to unuquely identify the entry.
+ The MenomonicEngine itself does not use this value, it
+ is only passed to other methods of this callback interface.
+
+ If this value is <NULL/>, searching stops.
+ */
+ virtual const void* FirstSearchEntry( String& _rEntryText ) = 0;
+
+ /** returns the next list entry for the mnemonic search
+
+ @return
+ a pointer which can be used to unuquely identify the entry.
+ The MenomonicEngine itself does not use this value, it
+ is only passed to other methods of this callback interface.
+
+ If this value is <NULL/>, searching stops.
+
+ If this value is the same as returned by the previous call
+ to <member>FirstSearchEntry</member> (i.e. you cycled
+ around), then searching stops, too.
+ */
+ virtual const void* NextSearchEntry( const void* _pCurrentSearchEntry, String& _rEntryText ) = 0;
+
+ /** "selects" a given entry.
+
+ Note: The semantics of "select" depends on your implementation. You
+ might actually really select the entry (in the sense of a selected
+ list box entry, for example), you might make it the current entry,
+ if your implementation supports this - whatever.
+
+ @param _pEntry
+ the entry to select. This is the return value of a previous call
+ to <member>FirstSearchEntry</member> or <member>NextSearchEntry</member>.
+ */
+ virtual void SelectSearchEntry( const void* _pEntry ) = 0;
+
+ /** "executes" the current search entry, i.e. the one returned
+ in the previous <member>NextSearchEntry</member> call.
+
+ Note: The semantics of "execute" depends on your implementation. You
+ might even have a list of entries which cannot be executed at all.
+
+ This method is called after <member>SelectSearchEntry</member>,
+ if and only if the current entry's mnemonic is unambiguous.
+
+ For instance, imagine a list which has two entries with the same mnemonic
+ character, say "c". Now if the user presses <code>Alt-C</code>, the MnemonicEngine
+ will call <member>SelectCurrentEntry</member> as soon as it encounters
+ the first entry, but it'll never call <member>ExecuteSearchEntry</member>.
+
+ If, however, "c" is a unique mnemonic character in your entry list, then the
+ call of <member>SelectSearchEntry</member> will be followed by a
+ call to <member>ExecuteSearchEntry</member>.
+
+ This way, you can implement cyclic selection of entries: In
+ <member>FirstSearchEntry</member>, return the entry which was previously
+ selected, and in <member>NextSearchEntry</member>, interlly cycle around
+ in your list. Then, multiple user inputs of <code>Alt-C</code> will
+ cycle through all entries with the mnemonic being "c".
+
+ @param _pEntry
+ the entry to select. This is the return value of a previous call
+ to <member>FirstSearchEntry</member> or <member>NextSearchEntry</member>.
+ */
+ virtual void ExecuteSearchEntry( const void* _pEntry ) = 0;
+ };
+
+ //====================================================================
+ //= MnemonicEngine
+ //====================================================================
+ struct MnemonicEngine_Data;
+ class VCL_DLLPUBLIC MnemonicEngine
+ {
+ ::std::auto_ptr< MnemonicEngine_Data > m_pData;
+
+ public:
+ MnemonicEngine( IMnemonicEntryList& _rEntryList );
+ ~MnemonicEngine();
+
+ /** handles a key event
+
+ If the key event denotes pressing an accelerator key, then the
+ entry list is searched for a matching entry. If such an entry is
+ found, <member>IMnemonicEntryList::SelectSearchEntry</member>
+ is called.
+
+ If the entry is the only one with the given mnemonic character, then
+ also <member>IMnemonicEntryList::ExecuteSearchEntry</member>
+ is called.
+
+ @return
+ if the key event has been handled, and should thus not be processed
+ further.
+ */
+ bool HandleKeyEvent( const KeyEvent& _rKEvt );
+ };
+
+//........................................................................
+} // namespace vcl
+//........................................................................
+
+#endif // VCL_MNEMONICENGINE_HXX
+
diff --git a/vcl/inc/vcl/morebtn.hxx b/vcl/inc/vcl/morebtn.hxx
new file mode 100644
index 000000000000..687ef7c40a01
--- /dev/null
+++ b/vcl/inc/vcl/morebtn.hxx
@@ -0,0 +1,95 @@
+/*************************************************************************
+ *
+ * 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_MOREBTN_HXX
+#define _SV_MOREBTN_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/mapmod.hxx>
+#include <vcl/button.hxx>
+
+struct ImplMoreButtonData;
+
+// --------------
+// - MoreButton -
+// --------------
+
+class VCL_DLLPUBLIC MoreButton : public PushButton
+{
+private:
+ ImplMoreButtonData* mpMBData;
+ ULONG mnDelta;
+ MapUnit meUnit;
+ BOOL mbState;
+
+ // Copy assignment is forbidden and not implemented.
+ SAL_DLLPRIVATE MoreButton( const MoreButton & );
+ SAL_DLLPRIVATE MoreButton& operator=( const MoreButton & );
+ SAL_DLLPRIVATE void ShowState();
+
+protected:
+ using Window::ImplInit;
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle );
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+
+public:
+ MoreButton( Window* pParent, WinBits nStyle = 0 );
+ MoreButton( Window* pParent, const ResId& rResId );
+ ~MoreButton();
+
+ void Click();
+
+ void AddWindow( Window* pWindow );
+ void RemoveWindow( Window* pWindow );
+
+ void SetDelta( ULONG nNewDelta ) { mnDelta = nNewDelta; }
+ ULONG GetDelta() const { return mnDelta; }
+
+ void SetMapUnit( MapUnit eNewUnit = MAP_PIXEL ) { meUnit = eNewUnit; }
+ MapUnit GetMapUnit() const { return meUnit; }
+
+ using PushButton::SetState;
+ void SetState( BOOL bNewState = TRUE );
+ BOOL GetState() const { return mbState; }
+
+ void SetText( const XubString& rNewText );
+ XubString GetText() const;
+
+ void SetMoreText( const XubString& rNewText );
+ void SetLessText( const XubString& rNewText );
+ XubString GetMoreText() const;
+ XubString GetLessText() const;
+};
+
+inline void MoreButton::SetState( BOOL bNewState )
+{
+ if ( mbState != bNewState )
+ Click();
+}
+
+#endif // _SV_MOREBTN_HXX
diff --git a/vcl/inc/vcl/msgbox.hxx b/vcl/inc/vcl/msgbox.hxx
new file mode 100644
index 000000000000..a6cd60a9d5e3
--- /dev/null
+++ b/vcl/inc/vcl/msgbox.hxx
@@ -0,0 +1,190 @@
+/*************************************************************************
+ *
+ * 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_MSGBOX_HXX
+#define _SV_MSGBOX_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/btndlg.hxx>
+#include <vcl/image.hxx>
+#include <vcl/bitmap.hxx>
+class FixedText;
+class FixedImage;
+class CheckBox;
+
+// -----------------
+// - MessBox-Types -
+// -----------------
+
+// Return-Werte von Execute
+//!!! bei Aenderungen \basic\source\runtime\methods.cxx msgbox anpassen
+
+#define RET_OK TRUE
+#define RET_CANCEL FALSE
+#define RET_YES 2
+#define RET_NO 3
+#define RET_RETRY 4
+#define RET_IGNORE 5
+
+#define BUTTONID_OK RET_OK
+#define BUTTONID_CANCEL RET_CANCEL
+#define BUTTONID_YES RET_YES
+#define BUTTONID_NO RET_NO
+#define BUTTONID_RETRY RET_RETRY
+#define BUTTONID_IGNORE RET_IGNORE
+#define BUTTONID_HELP 10
+
+// -----------
+// - MessBox -
+// -----------
+
+class VCL_DLLPUBLIC MessBox : public ButtonDialog
+{
+protected:
+ FixedText* mpFixedText;
+ FixedImage* mpFixedImage;
+ XubString maMessText;
+ Image maImage;
+ Image maImageHC;
+ USHORT mnSoundType;
+ BOOL mbHelpBtn;
+ BOOL mbSound;
+ CheckBox* mpCheckBox;
+ XubString maCheckBoxText;
+ BOOL mbCheck;
+
+ SAL_DLLPRIVATE void ImplInitMessBoxData();
+ SAL_DLLPRIVATE void ImplInitButtons();
+ SAL_DLLPRIVATE void ImplPosControls();
+
+protected:
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+ MessBox( WindowType nType );
+
+public:
+ MessBox( Window* pParent, WinBits nStyle,
+ const XubString& rTitle, const XubString& rMessage );
+ MessBox( Window* pParent, const ResId& rResId );
+ ~MessBox();
+
+ virtual void StateChanged( StateChangedType nStateChange );
+
+ void SetMessText( const XubString& rText ) { maMessText = rText; }
+ const XubString& GetMessText() const { return maMessText; }
+
+ void SetImage( const Image& rImage ) { maImage = rImage; }
+ const Image& GetImage() const { return maImage; }
+
+ BOOL SetModeImage( const Image& rImage, BmpColorMode eMode = BMP_COLOR_NORMAL );
+ const Image& GetModeImage( BmpColorMode eMode = BMP_COLOR_NORMAL ) const;
+
+ void SetDefaultCheckBoxText();
+ void SetCheckBoxText( const XubString& rText ) { maCheckBoxText = rText;}
+ const XubString& GetCheckBoxText() const { return maCheckBoxText;}
+ void SetCheckBoxState( BOOL bCheck );
+ BOOL GetCheckBoxState() const;
+
+ virtual Size GetOptimalSize(WindowSizeType eType) const;
+};
+
+// -----------
+// - InfoBox -
+// -----------
+
+class VCL_DLLPUBLIC InfoBox : public MessBox
+{
+private:
+ SAL_DLLPRIVATE void ImplInitInfoBoxData();
+
+public:
+ InfoBox( Window* pParent, const XubString& rMessage );
+ InfoBox( Window* pParent, const ResId & rResId );
+
+ static Image GetStandardImage();
+ static Image GetStandardImageHC();
+};
+
+// --------------
+// - WarningBox -
+// --------------
+
+class VCL_DLLPUBLIC WarningBox : public MessBox
+{
+private:
+ SAL_DLLPRIVATE void ImplInitWarningBoxData();
+
+public:
+ WarningBox( Window* pParent, WinBits nStyle,
+ const XubString& rMessage );
+ WarningBox( Window* pParent, const ResId& rResId );
+
+ void SetDefaultCheckBoxText();
+
+ static Image GetStandardImage();
+ static Image GetStandardImageHC();
+};
+
+// ------------
+// - ErrorBox -
+// ------------
+
+class VCL_DLLPUBLIC ErrorBox : public MessBox
+{
+private:
+ SAL_DLLPRIVATE void ImplInitErrorBoxData();
+
+public:
+ ErrorBox( Window* pParent, WinBits nStyle,
+ const XubString& rMessage );
+ ErrorBox( Window* pParent, const ResId& rResId );
+
+ static Image GetStandardImage();
+ static Image GetStandardImageHC();
+};
+
+// ------------
+// - QueryBox -
+// ------------
+
+class VCL_DLLPUBLIC QueryBox : public MessBox
+{
+private:
+ SAL_DLLPRIVATE void ImplInitQueryBoxData();
+
+public:
+ QueryBox( Window* pParent, WinBits nStyle,
+ const XubString& rMessage );
+ QueryBox( Window* pParent, const ResId& rResId );
+
+ void SetDefaultCheckBoxText();
+
+ static Image GetStandardImage();
+ static Image GetStandardImageHC();
+};
+
+#endif // _SV_MSGBOX_HXX
diff --git a/vcl/inc/vcl/octree.hxx b/vcl/inc/vcl/octree.hxx
new file mode 100644
index 000000000000..a7ce5e49c31d
--- /dev/null
+++ b/vcl/inc/vcl/octree.hxx
@@ -0,0 +1,161 @@
+/*************************************************************************
+ *
+ * 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_OCTREE_HXX
+#define _SV_OCTREE_HXX
+
+#include <vcl/salbtype.hxx>
+#include <vcl/dllapi.h>
+
+// -----------
+// - Defines -
+// -----------
+
+#define OCTREE_BITS 5
+#define OCTREE_BITS_1 10
+
+// --------------
+// - OctreeNode -
+// --------------
+
+typedef struct OctreeNode
+{
+ ULONG nCount;
+ ULONG nRed;
+ ULONG nGreen;
+ ULONG nBlue;
+ OctreeNode* pChild[ 8 ];
+ OctreeNode* pNext;
+ OctreeNode* pNextInCache;
+ USHORT nPalIndex;
+ BOOL bLeaf;
+} NODE;
+
+typedef NODE* PNODE;
+typedef PNODE* PPNODE;
+
+// ----------
+// - Octree -
+// ----------
+
+class ImpNodeCache;
+class BitmapReadAccess;
+
+class VCL_DLLPUBLIC Octree
+{
+private:
+
+ BitmapPalette aPal;
+ ULONG nMax;
+ ULONG nLeafCount;
+ ULONG nLevel;
+ PNODE pTree;
+ PNODE pReduce[ OCTREE_BITS + 1 ];
+ BitmapColor* pColor;
+ ImpNodeCache* pNodeCache;
+ const BitmapReadAccess* pAcc;
+ USHORT nPalIndex;
+
+ Octree() {};
+
+ void CreatePalette( PNODE pNode );
+ void GetPalIndex( PNODE pNode );
+
+ SAL_DLLPRIVATE void ImplCreateOctree();
+ SAL_DLLPRIVATE void ImplDeleteOctree( PPNODE ppNode );
+ SAL_DLLPRIVATE void ImplAdd( PPNODE ppNode );
+ SAL_DLLPRIVATE void ImplReduce();
+
+public:
+
+ Octree( const BitmapReadAccess& rReadAcc, ULONG nColors );
+ Octree( ULONG nColors );
+ ~Octree();
+
+ void AddColor( const BitmapColor& rColor );
+
+ inline const BitmapPalette& GetPalette();
+ inline USHORT GetBestPaletteIndex( const BitmapColor& rColor );
+};
+
+// ------------------------------------------------------------------------
+
+inline const BitmapPalette& Octree::GetPalette()
+{
+ aPal.SetEntryCount( (USHORT) nLeafCount );
+ nPalIndex = 0;
+ CreatePalette( pTree );
+ return aPal;
+}
+
+// ------------------------------------------------------------------------
+
+inline USHORT Octree::GetBestPaletteIndex( const BitmapColor& rColor )
+{
+ pColor = &(BitmapColor&) rColor;
+ nPalIndex = 65535;
+ nLevel = 0L;
+ GetPalIndex( pTree );
+ return nPalIndex;
+}
+
+// -------------------
+// - InverseColorMap -
+// -------------------
+
+class VCL_DLLPUBLIC InverseColorMap
+{
+private:
+
+ BYTE* pBuffer;
+ BYTE* pMap;
+ const ULONG nBits;
+
+//#if 0 // _SOLAR__PRIVATE
+
+ SAL_DLLPRIVATE void ImplCreateBuffers( const ULONG nMax );
+
+//#endif // __PRIVATE
+
+public:
+
+ InverseColorMap( const BitmapPalette& rPal );
+ ~InverseColorMap();
+
+ inline USHORT GetBestPaletteIndex( const BitmapColor& rColor );
+};
+
+// ------------------------------------------------------------------------
+
+inline USHORT InverseColorMap::GetBestPaletteIndex( const BitmapColor& rColor )
+{
+ return pMap[ ( ( (ULONG) rColor.GetRed() >> nBits ) << OCTREE_BITS_1 ) |
+ ( ( (ULONG) rColor.GetGreen() >> nBits ) << OCTREE_BITS ) |
+ ( (ULONG) rColor.GetBlue() >> nBits ) ];
+}
+
+#endif // _SV_OCTREE_HXX
diff --git a/vcl/inc/vcl/oldprintadaptor.hxx b/vcl/inc/vcl/oldprintadaptor.hxx
new file mode 100644
index 000000000000..3d7ccedc2ca1
--- /dev/null
+++ b/vcl/inc/vcl/oldprintadaptor.hxx
@@ -0,0 +1,52 @@
+/*************************************************************************
+ *
+ * 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_OLDPRINTADAPTOR
+#define _VCL_OLDPRINTADAPTOR
+
+#include "vcl/print.hxx"
+
+namespace vcl
+{
+ struct ImplOldStyleAdaptorData;
+ class VCL_DLLPUBLIC OldStylePrintAdaptor : public PrinterController
+ {
+ ImplOldStyleAdaptorData* mpData;
+ public:
+ OldStylePrintAdaptor( const boost::shared_ptr< Printer >& );
+ virtual ~OldStylePrintAdaptor();
+
+ void StartPage();
+ void EndPage();
+
+ virtual int getPageCount() const;
+ virtual com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue > getPageParameters( int i_nPage ) const;
+ virtual void printPage( int i_nPage ) const;
+ };
+}
+
+#endif
diff --git a/vcl/inc/vcl/outdata.hxx b/vcl/inc/vcl/outdata.hxx
new file mode 100644
index 000000000000..5d2852444767
--- /dev/null
+++ b/vcl/inc/vcl/outdata.hxx
@@ -0,0 +1,49 @@
+/*************************************************************************
+ *
+ * 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_OUTDATA_HXX
+#define _SV_OUTDATA_HXX
+
+#include <vcl/sv.h>
+#include <tools/color.hxx>
+#include <vcl/salgtype.hxx>
+
+// -----------------
+// - Hilfemethoden -
+// -----------------
+
+inline SalColor ImplColorToSal( Color aColor )
+{
+ return MAKE_SALCOLOR( aColor.GetRed(), aColor.GetGreen(), aColor.GetBlue() );
+}
+
+inline int ImplIsColorTransparent( Color aColor )
+{
+ return aColor.GetTransparency();
+}
+
+#endif // _SV_OUTDATA_HXX
diff --git a/vcl/inc/vcl/outdev.h b/vcl/inc/vcl/outdev.h
new file mode 100644
index 000000000000..43a1e9cf2cea
--- /dev/null
+++ b/vcl/inc/vcl/outdev.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_OUTDEV_H
+#define _SV_OUTDEV_H
+
+#include <tools/solar.h>
+#include <vcl/outfont.hxx>
+
+#include <vector>
+#include <list>
+#include <set>
+
+class Size;
+class Font;
+class VirtualDevice;
+class ImplServerGraphics;
+class ImplGetDevFontList;
+class GetDevSizeList;
+
+// -----------------------
+// - ImplDevFontListData -
+// -----------------------
+
+// flags for mnMatchType member
+#define IMPL_DEVFONT_SCALABLE ((ULONG)0x00000001)
+#define IMPL_DEVFONT_SYMBOL ((ULONG)0x00000002)
+#define IMPL_DEVFONT_NONESYMBOL ((ULONG)0x00000004)
+#define IMPL_DEVFONT_LIGHT ((ULONG)0x00000010)
+#define IMPL_DEVFONT_BOLD ((ULONG)0x00000020)
+#define IMPL_DEVFONT_NORMAL ((ULONG)0x00000040)
+#define IMPL_DEVFONT_NONEITALIC ((ULONG)0x00000100)
+#define IMPL_DEVFONT_ITALIC ((ULONG)0x00000200)
+
+// TODO: rename ImplDevFontListData to PhysicalFontFamily
+class ImplDevFontListData
+{
+public:
+ ImplDevFontListData( const String& rSearchName );
+ ~ImplDevFontListData();
+
+ const String& GetFamilyName() const { return maName; }
+ const String& GetSearchName() const { return maSearchName; }
+ const String& GetAliasNames() const { return maMapNames; }
+ bool IsScalable() const { return mpFirst->IsScalable(); }
+ int GetMinQuality() const { return mnMinQuality; }
+
+ bool AddFontFace( ImplFontData* );
+ void InitMatchData( const utl::FontSubstConfiguration&,
+ const String& rSearchName );
+ ImplFontData* FindBestFontFace( const ImplFontSelectData& rFSD ) const;
+
+ void GetFontHeights( std::set<int>& rHeights ) const;
+ void UpdateDevFontList( ImplGetDevFontList& ) const;
+ void UpdateCloneFontList( ImplDevFontList&,
+ bool bScalable, bool bEmbeddable ) const;
+
+private:
+friend class ImplDevFontList; // TODO: remove soon
+ ImplFontData* mpFirst; // linked list of physical font faces
+ String maName; // Fontname (original font family name)
+ String maSearchName; // normalized font family name
+ String maMapNames; // fontname aliases
+ ULONG mnTypeFaces; // Typeface Flags
+ ULONG mnMatchType; // MATCH - Type
+ String maMatchFamilyName; // MATCH - FamilyName
+ FontWeight meMatchWeight; // MATCH - Weight
+ FontWidth meMatchWidth; // MATCH - Width
+ FontFamily meFamily;
+ FontPitch mePitch;
+ int mnMinQuality; // quality of the worst font face
+};
+
+
+// ----------------------
+// - ImplGetDevFontList -
+// ----------------------
+
+// an ImplGetDevFontList is created by an ImplDevFontList
+// it becomes invalid when original ImplDevFontList is modified
+class ImplGetDevFontList
+{
+private:
+ std::vector<ImplFontData*> maDevFontVector;
+
+public:
+ ImplGetDevFontList() { maDevFontVector.reserve(1024); }
+ void Add( ImplFontData* pFace ) { maDevFontVector.push_back( pFace ); }
+ ImplFontData* Get( int nIndex ) const { return maDevFontVector[ nIndex ]; }
+ int Count() const { return maDevFontVector.size(); }
+};
+
+// ----------------------
+// - ImplGetDevSizeList -
+// ----------------------
+
+class ImplGetDevSizeList
+{
+private:
+ String maFontName;
+ std::vector<int> maSizeList;
+
+public:
+ ImplGetDevSizeList( const String& rFontName )
+ : maFontName( rFontName ) { maSizeList.reserve( 32 ); }
+ void Add( int nHeight ) { maSizeList.push_back( nHeight ); }
+ int Count() const { return maSizeList.size(); }
+ int Get( int nIndex ) const { return maSizeList[ nIndex ]; }
+ const String& GetFontName() const { return maFontName; }
+};
+
+// ------------------------
+// - ImplFontSubstitution -
+// ------------------------
+// nowadays these substitutions are needed for backward compatibility and tight platform integration:
+// - substitutions from configuration entries (Tools->Options->FontReplacement and/or fontconfig)
+// - device specific substitutions (e.g. for PS printer builtin fonts)
+// - substitutions for missing fonts defined by configuration entries (generic and/or platform dependent fallbacks)
+// - substitutions for missing fonts defined by multi-token fontnames (e.g. fontname="SpecialFont;FallbackA;FallbackB")
+// - substitutions for incomplete fonts (implicit, generic, EUDC and/or platform dependent fallbacks)
+// - substitutions for missing symbol fonts by translating code points into other symbol fonts
+
+class ImplFontSubstitution
+{
+ // TODO: there is more commonality between the different substitutions
+protected:
+ virtual ~ImplFontSubstitution() {}
+};
+
+// ImplDirectFontSubstitution is for Tools->Options->FontReplacement and PsPrinter substitutions
+// The clss is just a simple port of the unmaintainable manual-linked-list based mechanism
+// TODO: get rid of this class when the Tools->Options->FontReplacement tabpage is gone for good
+
+struct ImplFontSubstEntry
+{
+ String maName;
+ String maReplaceName;
+ String maSearchName;
+ String maSearchReplaceName;
+ USHORT mnFlags;
+
+ ImplFontSubstEntry( const String& rFontName, const String& rSubstFontName, USHORT nSubstFlags );
+};
+
+class ImplDirectFontSubstitution
+: public ImplFontSubstitution
+{
+private:
+ typedef std::list<ImplFontSubstEntry> FontSubstList;
+ FontSubstList maFontSubstList;
+public:
+ void AddFontSubstitute( const String& rFontName, const String& rSubstName, USHORT nFlags );
+ void RemoveFontSubstitute( int nIndex );
+ bool GetFontSubstitute( int nIndex, String& rFontName, String& rSubstName, USHORT& rFlags ) const;
+ int GetFontSubstituteCount() const { return maFontSubstList.size(); };
+ bool Empty() const { return maFontSubstList.empty(); }
+ void Clear() { maFontSubstList.clear(); }
+
+ bool FindFontSubstitute( String& rSubstName, const String& rFontName, USHORT nFlags ) const;
+};
+
+// PreMatchFontSubstitution
+// abstracts the concept of a configured font substitution
+// before the availability of the originally selected font has been checked
+class ImplPreMatchFontSubstitution
+: public ImplFontSubstitution
+{
+public:
+ virtual bool FindFontSubstitute( ImplFontSelectData& ) const = 0;
+};
+
+// ImplGlyphFallbackFontSubstitution
+// abstracts the concept of finding the best font to support an incomplete font
+class ImplGlyphFallbackFontSubstitution
+: public ImplFontSubstitution
+{
+public:
+ virtual bool FindFontSubstitute( ImplFontSelectData&, rtl::OUString& rMissingCodes ) const = 0;
+};
+
+// -----------------
+// - ImplFontCache -
+// -----------------
+// TODO: closely couple with ImplDevFontList
+
+class ImplFontCache
+{
+private:
+ ImplFontEntry* mpFirstEntry;
+ int mnRef0Count; // number of unreferenced ImplFontEntries
+ bool mbPrinter;
+
+ // cache of recently used font instances
+ struct IFSD_Equal { bool operator()( const ImplFontSelectData&, const ImplFontSelectData& ) const; };
+ struct IFSD_Hash { size_t operator()( const ImplFontSelectData& ) const; };
+ typedef ::std::hash_map<ImplFontSelectData,ImplFontEntry*,IFSD_Hash,IFSD_Equal > FontInstanceList;
+ FontInstanceList maFontInstanceList;
+
+ // cache of recently requested font names vs. selected font names
+ typedef ::std::hash_map<String,String,FontNameHash> FontNameList;
+ FontNameList maFontNameList;
+
+public:
+ ImplFontCache( bool bPrinter );
+ ~ImplFontCache();
+
+ ImplFontEntry* GetFontEntry( ImplDevFontList*,
+ const Font&, const Size& rPixelSize, float fExactHeight,
+ ImplDirectFontSubstitution* pDevSpecific );
+ ImplFontEntry* GetFontEntry( ImplDevFontList*,
+ ImplFontSelectData&, ImplDirectFontSubstitution* pDevSpecific );
+ ImplFontEntry* GetGlyphFallbackFont( ImplDevFontList*, ImplFontSelectData&,
+ int nFallbackLevel, rtl::OUString& rMissingCodes );
+ void Release( ImplFontEntry* );
+ void Invalidate();
+};
+
+// ------------------
+// - ImplOutDevData -
+// ------------------
+
+namespace vcl { struct ControlLayoutData; }
+// #i75163#
+namespace basegfx { class B2DHomMatrix; }
+
+struct ImplOutDevData
+{
+ VirtualDevice* mpRotateDev;
+ vcl::ControlLayoutData* mpRecordLayout;
+ Rectangle maRecordRect;
+ ImplDirectFontSubstitution maDevFontSubst;
+
+ // #i75163#
+ basegfx::B2DHomMatrix* mpViewTransform;
+ basegfx::B2DHomMatrix* mpInverseViewTransform;
+};
+
+void ImplFreeOutDevFontData();
+
+#endif // _SV_OUTDEV_H
diff --git a/vcl/inc/vcl/outdev.hxx b/vcl/inc/vcl/outdev.hxx
new file mode 100644
index 000000000000..9b748f2b5937
--- /dev/null
+++ b/vcl/inc/vcl/outdev.hxx
@@ -0,0 +1,1226 @@
+/*************************************************************************
+ *
+ * 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_OUTDEV_HXX
+#define _SV_OUTDEV_HXX
+
+#include <tools/gen.hxx>
+#include <tools/string.hxx>
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <tools/rc.hxx>
+#include <tools/color.hxx>
+#include <vcl/font.hxx>
+#include <vcl/region.hxx>
+#include <vcl/mapmod.hxx>
+#include <vcl/wall.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/salnativewidgets.hxx>
+#include <tools/poly.hxx>
+#include <basegfx/vector/b2enums.hxx>
+#include <com/sun/star/uno/Reference.h>
+#include <unotools/fontdefs.hxx>
+
+#include <vector>
+
+struct ImplOutDevData;
+class ImplFontEntry;
+struct ImplObjStack;
+struct ImplKernPairData;
+struct SystemGraphicsData;
+struct SystemFontData;
+struct SystemTextLayoutData;
+class ImplFontCache;
+class ImplDevFontList;
+class ImplGetDevFontList;
+class ImplGetDevSizeList;
+class ImplMultiTextLineInfo;
+class SalGraphics;
+class Gradient;
+class Hatch;
+class Bitmap;
+class BitmapReadAccess;
+class BitmapEx;
+class Image;
+class TextRectInfo;
+class FontInfo;
+class FontMetric;
+class GDIMetaFile;
+class List;
+class GfxLink;
+class Line;
+class LineInfo;
+class AlphaMask;
+class FontCharMap;
+class SalLayout;
+class ImplLayoutArgs;
+class ImplFontAttributes;
+class VirtualDevice;
+
+namespace com {
+namespace sun {
+namespace star {
+namespace rendering {
+ class XCanvas;
+}}}}
+namespace basegfx {
+ class B2DHomMatrix;
+ class B2DPolygon;
+ class B2DPolyPolygon;
+ typedef ::std::vector< B2DPolyPolygon > B2DPolyPolygonVector;
+}
+
+namespace com {
+namespace sun {
+namespace star {
+namespace awt {
+ class XGraphics;
+} } } }
+
+typedef std::vector< Rectangle > MetricVector;
+
+namespace vcl
+{
+ class PDFWriterImpl;
+ class ExtOutDevData;
+ class ITextLayout;
+}
+
+#define OUTDEV_BUFFER_SIZE 128
+
+
+// ---------------------
+// - OutputDevice-Data -
+// ---------------------
+
+struct ImplMapRes
+{
+ long mnMapOfsX; // Offset in X Richtung
+ long mnMapOfsY; // Offset in Y Richtung
+ long mnMapScNumX; // Skal.-faktor Zaehler X Richtung
+ long mnMapScNumY; // Skal.-faktor Zaehler Y Richtung
+ long mnMapScDenomX; // Skal.-faktor Nenner X Richtung
+ long mnMapScDenomY; // Skal.-faktor Nenner Y Richtung
+};
+
+struct ImplThresholdRes
+{
+ long mnThresLogToPixX; // Schwellenwerte fuer Berechnung
+ long mnThresLogToPixY; // mit BigInts
+ long mnThresPixToLogX; // ""
+ long mnThresPixToLogY; // ""
+};
+
+// ---------------
+// - KerningPair -
+// ---------------
+
+struct KerningPair
+{
+ sal_Unicode nChar1;
+ sal_Unicode nChar2;
+ long nKern;
+};
+
+// ----------------------
+// - OutputDevice-Types -
+// ----------------------
+
+// Flags for Push()
+#define PUSH_LINECOLOR ((USHORT)0x0001)
+#define PUSH_FILLCOLOR ((USHORT)0x0002)
+#define PUSH_FONT ((USHORT)0x0004)
+#define PUSH_TEXTCOLOR ((USHORT)0x0008)
+#define PUSH_MAPMODE ((USHORT)0x0010)
+#define PUSH_CLIPREGION ((USHORT)0x0020)
+#define PUSH_RASTEROP ((USHORT)0x0040)
+#define PUSH_TEXTFILLCOLOR ((USHORT)0x0080)
+#define PUSH_TEXTALIGN ((USHORT)0x0100)
+#define PUSH_REFPOINT ((USHORT)0x0200)
+#define PUSH_TEXTLINECOLOR ((USHORT)0x0400)
+#define PUSH_TEXTLAYOUTMODE ((USHORT)0x0800)
+#define PUSH_TEXTLANGUAGE ((USHORT)0x1000)
+#define PUSH_OVERLINECOLOR ((USHORT)0x2000)
+#define PUSH_ALLTEXT (PUSH_TEXTCOLOR | PUSH_TEXTFILLCOLOR | PUSH_TEXTLINECOLOR | PUSH_OVERLINECOLOR | PUSH_TEXTALIGN | PUSH_TEXTLAYOUTMODE | PUSH_TEXTLANGUAGE)
+#define PUSH_ALLFONT (PUSH_ALLTEXT | PUSH_FONT)
+#define PUSH_ALL ((USHORT)0xFFFF)
+
+// Flags for DrawText()
+#define TEXT_DRAW_DISABLE ((USHORT)0x0001)
+#define TEXT_DRAW_MNEMONIC ((USHORT)0x0002)
+#define TEXT_DRAW_MONO ((USHORT)0x0004)
+#define TEXT_DRAW_CLIP ((USHORT)0x0008)
+#define TEXT_DRAW_LEFT ((USHORT)0x0010)
+#define TEXT_DRAW_CENTER ((USHORT)0x0020)
+#define TEXT_DRAW_RIGHT ((USHORT)0x0040)
+#define TEXT_DRAW_TOP ((USHORT)0x0080)
+#define TEXT_DRAW_VCENTER ((USHORT)0x0100)
+#define TEXT_DRAW_BOTTOM ((USHORT)0x0200)
+#define TEXT_DRAW_ENDELLIPSIS ((USHORT)0x0400)
+#define TEXT_DRAW_PATHELLIPSIS ((USHORT)0x0800)
+#define TEXT_DRAW_MULTILINE ((USHORT)0x1000)
+#define TEXT_DRAW_WORDBREAK ((USHORT)0x2000)
+#define TEXT_DRAW_NEWSELLIPSIS ((USHORT)0x4000)
+
+#define TEXT_DRAW_WORDBREAK_HYPHENATION (((USHORT)0x8000) | TEXT_DRAW_WORDBREAK)
+
+// Flags for CopyArea()
+#define COPYAREA_WINDOWINVALIDATE ((USHORT)0x0001)
+
+// Flags for DrawImage()
+#define IMAGE_DRAW_DISABLE ((USHORT)0x0001)
+#define IMAGE_DRAW_HIGHLIGHT ((USHORT)0x0002)
+#define IMAGE_DRAW_DEACTIVE ((USHORT)0x0004)
+#define IMAGE_DRAW_COLORTRANSFORM ((USHORT)0x0008)
+#define IMAGE_DRAW_SEMITRANSPARENT ((USHORT)0x0010)
+#define IMAGE_DRAW_MONOCHROME_BLACK ((USHORT)0x0020)
+#define IMAGE_DRAW_MONOCHROME_WHITE ((USHORT)0x0040)
+#define IMAGE_DRAW_3DLOOK 0
+#define IMAGE_DRAW_BTNLOOK 0
+
+// WaveLine
+#define WAVE_FLAT 1
+#define WAVE_SMALL 2
+#define WAVE_NORMAL 3
+
+// Grid
+#define GRID_DOTS ((ULONG)0x00000001)
+#define GRID_HORZLINES ((ULONG)0x00000002)
+#define GRID_VERTLINES ((ULONG)0x00000004)
+#define GRID_LINES (GRID_HORZLINES | GRID_VERTLINES)
+
+// LayoutModes for Complex Text Layout
+#define TEXT_LAYOUT_DEFAULT ((ULONG)0x00000000)
+#define TEXT_LAYOUT_BIDI_LTR ((ULONG)0x00000000)
+#define TEXT_LAYOUT_BIDI_RTL ((ULONG)0x00000001)
+#define TEXT_LAYOUT_BIDI_STRONG ((ULONG)0x00000002)
+#define TEXT_LAYOUT_TEXTORIGIN_LEFT ((ULONG)0x00000004)
+#define TEXT_LAYOUT_TEXTORIGIN_RIGHT ((ULONG)0x00000008)
+#define TEXT_LAYOUT_COMPLEX_DISABLED ((ULONG)0x00000100)
+#define TEXT_LAYOUT_ENABLE_LIGATURES ((ULONG)0x00000200)
+#define TEXT_LAYOUT_SUBSTITUTE_DIGITS ((ULONG)0x00000400)
+
+// DrawModes
+#define DRAWMODE_DEFAULT ((ULONG)0x00000000)
+#define DRAWMODE_BLACKLINE ((ULONG)0x00000001)
+#define DRAWMODE_BLACKFILL ((ULONG)0x00000002)
+#define DRAWMODE_BLACKTEXT ((ULONG)0x00000004)
+#define DRAWMODE_BLACKBITMAP ((ULONG)0x00000008)
+#define DRAWMODE_BLACKGRADIENT ((ULONG)0x00000010)
+#define DRAWMODE_GRAYLINE ((ULONG)0x00000020)
+#define DRAWMODE_GRAYFILL ((ULONG)0x00000040)
+#define DRAWMODE_GRAYTEXT ((ULONG)0x00000080)
+#define DRAWMODE_GRAYBITMAP ((ULONG)0x00000100)
+#define DRAWMODE_GRAYGRADIENT ((ULONG)0x00000200)
+#define DRAWMODE_NOFILL ((ULONG)0x00000400)
+#define DRAWMODE_NOBITMAP ((ULONG)0x00000800)
+#define DRAWMODE_NOGRADIENT ((ULONG)0x00001000)
+#define DRAWMODE_GHOSTEDLINE ((ULONG)0x00002000)
+#define DRAWMODE_GHOSTEDFILL ((ULONG)0x00004000)
+#define DRAWMODE_GHOSTEDTEXT ((ULONG)0x00008000)
+#define DRAWMODE_GHOSTEDBITMAP ((ULONG)0x00010000)
+#define DRAWMODE_GHOSTEDGRADIENT ((ULONG)0x00020000)
+#define DRAWMODE_WHITELINE ((ULONG)0x00100000)
+#define DRAWMODE_WHITEFILL ((ULONG)0x00200000)
+#define DRAWMODE_WHITETEXT ((ULONG)0x00400000)
+#define DRAWMODE_WHITEBITMAP ((ULONG)0x00800000)
+#define DRAWMODE_WHITEGRADIENT ((ULONG)0x01000000)
+#define DRAWMODE_SETTINGSLINE ((ULONG)0x02000000)
+#define DRAWMODE_SETTINGSFILL ((ULONG)0x04000000)
+#define DRAWMODE_SETTINGSTEXT ((ULONG)0x08000000)
+#define DRAWMODE_SETTINGSGRADIENT ((ULONG)0x10000000)
+#define DRAWMODE_NOTRANSPARENCY ((ULONG)0x80000000)
+
+// Antialiasing
+#define ANTIALIASING_DISABLE_TEXT ((USHORT)0x0001)
+#define ANTIALIASING_ENABLE_B2DDRAW ((USHORT)0x0002)
+#define ANTIALIASING_PIXELSNAPHAIRLINE ((USHORT)0x0004)
+
+// AddFontSubstitute
+#define FONT_SUBSTITUTE_ALWAYS ((USHORT)0x0001)
+#define FONT_SUBSTITUTE_SCREENONLY ((USHORT)0x0002)
+
+#define DEFAULTFONT_FLAGS_ONLYONE ((ULONG)0x00000001)
+
+enum OutDevType { OUTDEV_DONTKNOW, OUTDEV_WINDOW, OUTDEV_PRINTER, OUTDEV_VIRDEV };
+
+enum OutDevViewType { OUTDEV_VIEWTYPE_DONTKNOW, OUTDEV_VIEWTYPE_PRINTPREVIEW, OUTDEV_VIEWTYPE_SLIDESHOW };
+
+// ----------------
+// - OutputDevice -
+// ----------------
+
+class VirtualDevice;
+class Printer;
+
+const char* ImplDbgCheckOutputDevice( const void* pObj );
+
+class VCL_DLLPUBLIC OutputDevice : public Resource
+{
+ friend class Application;
+ friend class Bitmap;
+ friend class ImplImageBmp;
+ friend class ImplQPrinter;
+ friend class Printer;
+ friend class SalGraphicsLayout;
+ friend class System;
+ friend class VirtualDevice;
+ friend class Window;
+ friend class WorkWindow;
+ friend class vcl::PDFWriterImpl;
+ friend const char* ImplDbgCheckOutputDevice( const void* pObj );
+ friend void ImplHandleResize( Window* pWindow, long nNewWidth, long nNewHeight );
+
+private:
+ mutable SalGraphics* mpGraphics;
+ mutable OutputDevice* mpPrevGraphics;
+ mutable OutputDevice* mpNextGraphics;
+ GDIMetaFile* mpMetaFile;
+ mutable ImplFontEntry* mpFontEntry;
+ mutable ImplFontCache* mpFontCache;
+ mutable ImplDevFontList* mpFontList;
+ mutable ImplGetDevFontList* mpGetDevFontList;
+ mutable ImplGetDevSizeList* mpGetDevSizeList;
+ ImplObjStack* mpObjStack;
+ ImplOutDevData* mpOutDevData;
+ List* mpUnoGraphicsList;
+ vcl::PDFWriterImpl* mpPDFWriter;
+ vcl::ExtOutDevData* mpExtOutDevData;
+
+ // TEMP TEMP TEMP
+ VirtualDevice* mpAlphaVDev;
+
+ /// Additional output pixel offset, applied in LogicToPixel (used by SetPixelOffset/GetPixelOffset)
+ long mnOutOffOrigX;
+ /// Additional output offset in _logical_ coordinates, applied in PixelToLogic (used by SetPixelOffset/GetPixelOffset)
+ long mnOutOffLogicX;
+ /// Additional output pixel offset, applied in LogicToPixel (used by SetPixelOffset/GetPixelOffset)
+ long mnOutOffOrigY;
+ /// Additional output offset in _logical_ coordinates, applied in PixelToLogic (used by SetPixelOffset/GetPixelOffset)
+ long mnOutOffLogicY;
+ /// Output offset for device output in pixel (pseudo window offset within window system's frames)
+ long mnOutOffX;
+ /// Output offset for device output in pixel (pseudo window offset within window system's frames)
+ long mnOutOffY;
+ long mnOutWidth;
+ long mnOutHeight;
+ sal_Int32 mnDPIX;
+ sal_Int32 mnDPIY;
+ /// font specific text alignment offsets in pixel units
+ mutable long mnTextOffX;
+ mutable long mnTextOffY;
+ mutable long mnEmphasisAscent;
+ mutable long mnEmphasisDescent;
+ ULONG mnDrawMode;
+ ULONG mnTextLayoutMode;
+ ImplMapRes maMapRes;
+ ImplThresholdRes maThresRes;
+ OutDevType meOutDevType;
+ OutDevViewType meOutDevViewType;
+ Region maRegion; // contains the clip region, see SetClipRegion(...)
+ Color maLineColor;
+ Color maFillColor;
+ Font maFont;
+ Color maTextColor;
+ Color maTextLineColor;
+ Color maOverlineColor;
+ TextAlign meTextAlign;
+ RasterOp meRasterOp;
+ Wallpaper maBackground;
+ AllSettings maSettings;
+ MapMode maMapMode;
+ Point maRefPoint;
+ USHORT mnAntialiasing;
+ LanguageType meTextLanguage;
+ mutable BOOL mbMap:1,
+ mbMapIsDefault:1,
+ mbClipRegion:1,
+ mbBackground:1,
+ mbOutput:1,
+ mbDevOutput:1,
+ mbOutputClipped:1,
+ mbLineColor:1,
+ mbFillColor:1,
+ mbInitLineColor:1,
+ mbInitFillColor:1,
+ mbInitFont:1,
+ mbInitTextColor:1,
+ mbInitClipRegion:1,
+ mbClipRegionSet:1,
+ mbKerning:1,
+ mbNewFont:1,
+ mbTextLines:1,
+ mbTextSpecial:1,
+ mbRefPoint:1,
+ mbEnableRTL:1;
+
+public:
+ SAL_DLLPRIVATE sal_Int32 ImplGetDPIX() const { return mnDPIX; }
+ SAL_DLLPRIVATE sal_Int32 ImplGetDPIY() const { return mnDPIY; }
+ SAL_DLLPRIVATE int ImplGetGraphics() const;
+ SAL_DLLPRIVATE void ImplReleaseGraphics( BOOL bRelease = TRUE );
+ SAL_DLLPRIVATE BOOL ImplHasMirroredGraphics();
+ SAL_DLLPRIVATE void ImplReMirror( Point &rPoint ) const;
+ SAL_DLLPRIVATE void ImplReMirror( Rectangle &rRect ) const;
+ SAL_DLLPRIVATE void ImplReMirror( Region &rRegion ) const;
+ SAL_DLLPRIVATE void ImplInitOutDevData();
+ SAL_DLLPRIVATE void ImplDeInitOutDevData();
+ SAL_DLLPRIVATE void ImplInitLineColor();
+ SAL_DLLPRIVATE void ImplInitFillColor();
+ SAL_DLLPRIVATE bool ImplNewFont() const;
+ SAL_DLLPRIVATE void ImplInitFont() const;
+ SAL_DLLPRIVATE void ImplInitTextColor();
+ SAL_DLLPRIVATE void ImplInitClipRegion();
+ SAL_DLLPRIVATE bool ImplSelectClipRegion( const Region&, SalGraphics* pGraphics = NULL );
+ SAL_DLLPRIVATE void ImplSetClipRegion( const Region* pRegion );
+ SAL_DLLPRIVATE void ImplSetTriangleClipRegion( const PolyPolygon &rPolyPolygon );
+
+ SAL_DLLPRIVATE SalLayout* ImplLayout( const String&, xub_StrLen nIndex,
+ xub_StrLen nLen, const Point& rLogicPos = Point(0,0),
+ long nLogicWidth=0, const sal_Int32* pLogicDXArray=NULL,
+ bool bFilter = false ) const;
+ SAL_DLLPRIVATE ImplLayoutArgs ImplPrepareLayoutArgs( String&,
+ xub_StrLen nIndex, xub_StrLen nLen,
+ long nPixelWidth,
+ const sal_Int32* pPixelDXArray ) const;
+ SAL_DLLPRIVATE SalLayout* ImplGlyphFallbackLayout( SalLayout*, ImplLayoutArgs& ) const;
+
+ SAL_DLLPRIVATE long ImplGetTextWidth( const SalLayout& ) const;
+ static
+ SAL_DLLPRIVATE XubString ImplGetEllipsisString( const OutputDevice& rTargetDevice, const XubString& rStr,
+ long nMaxWidth, USHORT nStyle, const ::vcl::ITextLayout& _rLayout );
+ static
+ SAL_DLLPRIVATE void ImplDrawText( OutputDevice& rTargetDevice, const Rectangle& rRect,
+ const String& rOrigStr, USHORT nStyle,
+ MetricVector* pVector, String* pDisplayText, ::vcl::ITextLayout& _rLayout );
+ SAL_DLLPRIVATE void ImplDrawTextBackground( const SalLayout& );
+ SAL_DLLPRIVATE void ImplDrawTextLines( SalLayout&, FontStrikeout eStrikeout, FontUnderline eUnderline, FontUnderline eOverline, BOOL bWordLine, BOOL bUnderlineAbove );
+ SAL_DLLPRIVATE bool ImplDrawRotateText( SalLayout& );
+ SAL_DLLPRIVATE void ImplDrawTextDirect( SalLayout&, BOOL bTextLines );
+ SAL_DLLPRIVATE void ImplDrawSpecialText( SalLayout& );
+ SAL_DLLPRIVATE void ImplDrawText( SalLayout& );
+ SAL_DLLPRIVATE Rectangle ImplGetTextBoundRect( const SalLayout& );
+ SAL_DLLPRIVATE void ImplDrawEmphasisMarks( SalLayout& );
+
+ SAL_DLLPRIVATE void ImplDrawTextRect( long nBaseX, long nBaseY, long nX, long nY, long nWidth, long nHeight );
+
+ SAL_DLLPRIVATE void ImplInitTextLineSize();
+ SAL_DLLPRIVATE void ImplInitAboveTextLineSize();
+ SAL_DLLPRIVATE void ImplDrawWaveLine( long nBaseX, long nBaseY, long nStartX, long nStartY, long nWidth, long nHeight, long nLineWidth, short nOrientation, const Color& rColor );
+ SAL_DLLPRIVATE void ImplDrawWaveTextLine( long nBaseX, long nBaseY, long nX, long nY, long nWidth, FontUnderline eTextLine, Color aColor, BOOL bIsAbove );
+ SAL_DLLPRIVATE void ImplDrawStraightTextLine( long nBaseX, long nBaseY, long nX, long nY, long nWidth, FontUnderline eTextLine, Color aColor, BOOL bIsAbove );
+ SAL_DLLPRIVATE void ImplDrawStrikeoutLine( long nBaseX, long nBaseY, long nX, long nY, long nWidth, FontStrikeout eStrikeout, Color aColor );
+ SAL_DLLPRIVATE void ImplDrawStrikeoutChar( long nBaseX, long nBaseY, long nX, long nY, long nWidth, FontStrikeout eStrikeout, Color aColor );
+ SAL_DLLPRIVATE void ImplDrawTextLine( long nBaseX, long nX, long nY, long nWidth, FontStrikeout eStrikeout, FontUnderline eUnderline, FontUnderline eOverline, BOOL bUnderlineAbove );
+ SAL_DLLPRIVATE void ImplDrawMnemonicLine( long nX, long nY, long nWidth );
+ SAL_DLLPRIVATE void ImplGetEmphasisMark( PolyPolygon& rPolyPoly, BOOL& rPolyLine, Rectangle& rRect1, Rectangle& rRect2, long& rYOff, long& rWidth, FontEmphasisMark eEmphasis, long nHeight, short nOrient );
+ SAL_DLLPRIVATE void ImplDrawEmphasisMark( long nBaseX, long nX, long nY, const PolyPolygon& rPolyPoly, BOOL bPolyLine, const Rectangle& rRect1, const Rectangle& rRect2 );
+ static
+ SAL_DLLPRIVATE long ImplGetTextLines( ImplMultiTextLineInfo& rLineInfo, long nWidth, const XubString& rStr, USHORT nStyle, const ::vcl::ITextLayout& _rLayout );
+ SAL_DLLPRIVATE void ImplInitFontList() const;
+ SAL_DLLPRIVATE void ImplUpdateFontData( bool bNewFontLists );
+ SAL_DLLPRIVATE static void ImplUpdateAllFontData( bool bNewFontLists );
+
+ SAL_DLLPRIVATE long ImplLogicXToDevicePixel( long nX ) const;
+ SAL_DLLPRIVATE long ImplLogicYToDevicePixel( long nY ) const;
+ SAL_DLLPRIVATE long ImplLogicWidthToDevicePixel( long nWidth ) const;
+ SAL_DLLPRIVATE long ImplLogicHeightToDevicePixel( long nHeight ) const;
+ SAL_DLLPRIVATE long ImplDevicePixelToLogicWidth( long nWidth ) const;
+ SAL_DLLPRIVATE long ImplDevicePixelToLogicHeight( long nHeight ) const;
+ SAL_DLLPRIVATE float ImplFloatLogicWidthToDevicePixel( float ) const;
+ SAL_DLLPRIVATE float ImplFloatLogicHeightToDevicePixel( float ) const;
+ SAL_DLLPRIVATE float ImplFloatDevicePixelToLogicWidth( float ) const;
+ SAL_DLLPRIVATE float ImplFloatDevicePixelToLogicHeight( float ) const;
+ SAL_DLLPRIVATE Point ImplLogicToDevicePixel( const Point& rLogicPt ) const;
+ SAL_DLLPRIVATE Size ImplLogicToDevicePixel( const Size& rLogicSize ) const;
+ SAL_DLLPRIVATE Rectangle ImplLogicToDevicePixel( const Rectangle& rLogicRect ) const;
+ SAL_DLLPRIVATE ::basegfx::B2DPolygon ImplLogicToDevicePixel( const ::basegfx::B2DPolygon& ) const;
+ SAL_DLLPRIVATE ::basegfx::B2DPolyPolygon ImplLogicToDevicePixel( const ::basegfx::B2DPolyPolygon& ) const;
+ SAL_DLLPRIVATE Polygon ImplLogicToDevicePixel( const Polygon& rLogicPoly ) const;
+ SAL_DLLPRIVATE PolyPolygon ImplLogicToDevicePixel( const PolyPolygon& rLogicPolyPoly ) const;
+ SAL_DLLPRIVATE LineInfo ImplLogicToDevicePixel( const LineInfo& rLineInfo ) const;
+ SAL_DLLPRIVATE Rectangle ImplDevicePixelToLogic( const Rectangle& rLogicRect ) const;
+ SAL_DLLPRIVATE Region ImplPixelToDevicePixel( const Region& rRegion ) const;
+ SAL_DLLPRIVATE void ImplInvalidateViewTransform();
+ SAL_DLLPRIVATE basegfx::B2DHomMatrix ImplGetDeviceTransformation() const;
+
+ SAL_DLLPRIVATE void ImplDrawPolygon( const Polygon& rPoly, const PolyPolygon* pClipPolyPoly = NULL );
+ SAL_DLLPRIVATE void ImplDrawPolyPolygon( const PolyPolygon& rPolyPoly, const PolyPolygon* pClipPolyPoly = NULL );
+ SAL_DLLPRIVATE void ImplDrawPolyPolygon( USHORT nPoly, const PolyPolygon& rPolyPoly );
+ SAL_DLLPRIVATE void ImplDrawLinearGradient( const Rectangle& rRect, const Gradient& rGradient, BOOL bMtf, const PolyPolygon* pClipPolyPoly );
+ SAL_DLLPRIVATE void ImplDrawComplexGradient( const Rectangle& rRect, const Gradient& rGradient, BOOL bMtf, const PolyPolygon* pClipPolyPoly );
+
+ SAL_DLLPRIVATE void ImplDrawHatch( const PolyPolygon& rPolyPoly, const Hatch& rHatch, BOOL bMtf );
+ SAL_DLLPRIVATE void ImplCalcHatchValues( const Rectangle& rRect, long nDist, USHORT nAngle10, Point& rPt1, Point& rPt2, Size& rInc, Point& rEndPt1 );
+ SAL_DLLPRIVATE void ImplDrawHatchLine( const Line& rLine, const PolyPolygon& rPolyPoly, Point* pPtBuffer, BOOL bMtf );
+
+ SAL_DLLPRIVATE void ImplDrawWallpaper( long nX, long nY, long nWidth, long nHeight, const Wallpaper& rWallpaper );
+ SAL_DLLPRIVATE void ImplDrawColorWallpaper( long nX, long nY, long nWidth, long nHeight, const Wallpaper& rWallpaper );
+ SAL_DLLPRIVATE void ImplDrawBitmapWallpaper( long nX, long nY, long nWidth, long nHeight, const Wallpaper& rWallpaper );
+ SAL_DLLPRIVATE void ImplDrawGradientWallpaper( long nX, long nY, long nWidth, long nHeight, const Wallpaper& rWallpaper );
+ SAL_DLLPRIVATE void ImplDraw2ColorFrame( const Rectangle& rRect, const Color& rLeftTopColor, const Color& rRightBottomColor );
+
+ SAL_DLLPRIVATE void ImplDrawOutDevDirect( const OutputDevice* pSrcDev, void* pPosAry );
+ SAL_DLLPRIVATE void ImplDrawBitmap( const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPtPixel, const Size& rSrcSizePixel,
+ const Bitmap& rBitmap, const ULONG nAction );
+ SAL_DLLPRIVATE void ImplDrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPtPixel, const Size& rSrcSizePixel,
+ const BitmapEx& rBitmapEx, const ULONG nAction );
+ SAL_DLLPRIVATE void ImplDrawMask( const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPtPixel, const Size& rSrcSizePixel,
+ const Bitmap& rBitmap, const Color& rMaskColor,
+ const ULONG nAction );
+ SAL_DLLPRIVATE void ImplDrawAlpha( const Bitmap& rBmp, const AlphaMask& rAlpha,
+ const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPtPixel, const Size& rSrcSizePixel );
+ SAL_DLLPRIVATE Bitmap 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 );
+ SAL_DLLPRIVATE Bitmap 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 );
+ SAL_DLLPRIVATE void ImplPrintTransparent( const Bitmap& rBmp, const Bitmap& rMask,
+ const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPtPixel, const Size& rSrcSizePixel );
+ SAL_DLLPRIVATE void ImplPrintMask( const Bitmap& rMask, const Color& rMaskColor,
+ const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPtPixel, const Size& rSrcSizePixel );
+ SAL_DLLPRIVATE void ImplDrawFrameDev( const Point& rPt, const Point& rDevPt, const Size& rDevSize,
+ const OutputDevice& rOutDev, const Region& rRegion );
+ SAL_DLLPRIVATE void ImplGetFrameDev( const Point& rPt, const Point& rDevPt, const Size& rDevSize,
+ OutputDevice& rOutDev );
+ SAL_DLLPRIVATE void ImplGetFrameBitmap( const Point& rPt, const Size& rSize,
+ Bitmap& rBitmap ) const;
+
+ SAL_DLLPRIVATE BOOL ImplIsRecordLayout() const;
+
+ void ImplAddDevFontSubstitute( const XubString& rFontName,
+ const XubString& rReplaceFontName,
+ USHORT nFlags = 0 );
+
+ SAL_DLLPRIVATE static FontEmphasisMark ImplGetEmphasisMarkStyle( const Font& rFont );
+ SAL_DLLPRIVATE static BOOL ImplIsUnderlineAbove( const Font& );
+
+ // tells whether this output device is RTL in an LTR UI or LTR in a RTL UI
+ SAL_DLLPRIVATE bool ImplIsAntiparallel() const ;
+
+ // #i101491#
+ // Helper which holds the old line geometry creation and is extended to use AA when
+ // switched on. Advantage is that line geometry is only temporarily used for paint
+ SAL_DLLPRIVATE void ImpDrawPolyLineWithLineInfo(const Polygon& rPoly, const LineInfo& rLineInfo);
+
+ // #i101491#
+ // Helper who implements the DrawPolyPolygon functionality for basegfx::B2DPolyPolygon
+ // without MetaFile processing
+ SAL_DLLPRIVATE void ImpDrawPolyPolygonWithB2DPolyPolygon(const basegfx::B2DPolyPolygon& rB2DPolyPoly);
+
+ // #i101491#
+ // Helper who tries to use SalGDI's DrawPolyLine direct and returns it's bool. Contains no AA check.
+ SAL_DLLPRIVATE bool ImpTryDrawPolyLineDirect(const basegfx::B2DPolygon& rB2DPolygon, double fLineWidth, basegfx::B2DLineJoin eLineJoin);
+
+ // Helper for line geometry paint with support for graphic expansion (pattern and fat_to_area)
+ void impPaintLineGeometryWithEvtlExpand(const LineInfo& rInfo, basegfx::B2DPolyPolygon aLinePolyPolygon);
+
+protected:
+ OutputDevice();
+
+private:
+ SAL_DLLPRIVATE OutputDevice( const OutputDevice& rOutDev );
+ SAL_DLLPRIVATE OutputDevice& operator =( const OutputDevice& rOutDev );
+
+public:
+ virtual ~OutputDevice();
+
+ OutDevType GetOutDevType() const { return meOutDevType; }
+
+ /** query an <code>OutputDevice</code> whether it spports a specific operation
+
+ @return
+ true if operation supported, else false
+ */
+ bool supportsOperation( OutDevSupportType ) const;
+
+ vcl::PDFWriterImpl* GetPDFWriter() const { return mpPDFWriter; }
+
+ void SetExtOutDevData( vcl::ExtOutDevData* pExtOutDevData ) { mpExtOutDevData = pExtOutDevData; }
+ vcl::ExtOutDevData* GetExtOutDevData() const { return mpExtOutDevData; }
+
+ void DrawTextLine( const Point& rPos, long nWidth,
+ FontStrikeout eStrikeout,
+ FontUnderline eUnderline,
+ FontUnderline eOverline,
+ BOOL bUnderlineAbove = FALSE );
+ static BOOL IsTextUnderlineAbove( const Font& rFont );
+
+ void DrawText( const Point& rStartPt, const XubString& rStr,
+ xub_StrLen nIndex = 0, xub_StrLen nLen = STRING_LEN,
+ MetricVector* pVector = NULL, String* pDisplayText = NULL );
+ long GetTextWidth( const XubString& rStr, xub_StrLen nIndex = 0,
+ xub_StrLen nLen = STRING_LEN ) const;
+ long GetTextHeight() const;
+ void DrawTextArray( const Point& rStartPt, const XubString& rStr,
+ const sal_Int32* pDXAry = NULL,
+ xub_StrLen nIndex = 0,
+ xub_StrLen nLen = STRING_LEN );
+ long GetTextArray( const XubString& rStr, sal_Int32* pDXAry = NULL,
+ xub_StrLen nIndex = 0,
+ xub_StrLen nLen = STRING_LEN ) const;
+ bool GetCaretPositions( const XubString&, sal_Int32* pCaretXArray,
+ xub_StrLen nIndex, xub_StrLen nLen,
+ sal_Int32* pDXAry = NULL, long nWidth = 0,
+ BOOL bCellBreaking = TRUE ) const;
+ void DrawStretchText( const Point& rStartPt, ULONG nWidth,
+ const XubString& rStr,
+ xub_StrLen nIndex = 0, xub_StrLen nLen = STRING_LEN );
+ xub_StrLen GetTextBreak( const XubString& rStr, long nTextWidth,
+ xub_StrLen nIndex = 0, xub_StrLen nLen = STRING_LEN,
+ long nCharExtra = 0, BOOL bCellBreaking = TRUE ) const;
+ xub_StrLen GetTextBreak( const XubString& rStr, long nTextWidth,
+ USHORT nExtraChar, xub_StrLen& rExtraCharPos,
+ xub_StrLen nIndex, xub_StrLen nLen,
+ long nCharExtra = 0 ) const;
+ /** Generate MetaTextActions for the text rect
+
+ This method splits up the text rect into multiple
+ MetaTextActions, one for each line of text. This is comparable
+ to AddGradientActions(), which splits up a gradient into its
+ constituing polygons. Parameter semantics fully compatible to
+ DrawText().
+ */
+ void AddTextRectActions( const Rectangle& rRect,
+ const String& rOrigStr,
+ USHORT nStyle,
+ GDIMetaFile& rMtf );
+ void DrawText( const Rectangle& rRect,
+ const XubString& rStr, USHORT nStyle = 0,
+ MetricVector* pVector = NULL, String* pDisplayText = NULL,
+ ::vcl::ITextLayout* _pTextLayout = NULL );
+ Rectangle GetTextRect( const Rectangle& rRect,
+ const XubString& rStr, USHORT nStyle = TEXT_DRAW_WORDBREAK,
+ TextRectInfo* pInfo = NULL,
+ const ::vcl::ITextLayout* _pTextLayout = NULL ) const;
+ XubString GetEllipsisString( const XubString& rStr, long nMaxWidth,
+ USHORT nStyle = TEXT_DRAW_ENDELLIPSIS ) const;
+ void DrawCtrlText( const Point& rPos, const XubString& rStr,
+ xub_StrLen nIndex = 0, xub_StrLen nLen = STRING_LEN,
+ USHORT nStyle = TEXT_DRAW_MNEMONIC, MetricVector* pVector = NULL, String* pDisplayText = NULL );
+ long GetCtrlTextWidth( const XubString& rStr, xub_StrLen nIndex = 0,
+ xub_StrLen nLen = STRING_LEN,
+ USHORT nStyle = TEXT_DRAW_MNEMONIC ) const;
+ static XubString GetNonMnemonicString( const XubString& rStr, xub_StrLen& rMnemonicPos );
+ static XubString GetNonMnemonicString( const XubString& rStr )
+ { xub_StrLen nDummy; return GetNonMnemonicString( rStr, nDummy ); }
+
+ ULONG GetKerningPairCount() const;
+ void GetKerningPairs( ULONG nPairs, KerningPair* pKernPairs ) const;
+
+ BOOL GetTextBoundRect( Rectangle& rRect,
+ const String& rStr, xub_StrLen nBase = 0, xub_StrLen nIndex = 0, xub_StrLen nLen = STRING_LEN,
+ ULONG nLayoutWidth = 0, const sal_Int32* pDXArray = NULL ) const;
+ BOOL GetTextOutline( PolyPolygon&,
+ const String& rStr, xub_StrLen nBase = 0, xub_StrLen nIndex = 0,
+ xub_StrLen nLen = STRING_LEN, BOOL bOptimize = TRUE,
+ ULONG nLayoutWidth = 0, const sal_Int32* pDXArray = NULL ) const;
+ BOOL GetTextOutlines( PolyPolyVector&,
+ const String& rStr, xub_StrLen nBase = 0, xub_StrLen nIndex = 0,
+ xub_StrLen nLen = STRING_LEN, BOOL bOptimize = TRUE,
+ ULONG nLayoutWidth = 0, const sal_Int32* pDXArray = NULL ) const;
+ BOOL GetTextOutlines( ::basegfx::B2DPolyPolygonVector&,
+ const String& rStr, xub_StrLen nBase = 0, xub_StrLen nIndex = 0,
+ xub_StrLen nLen = STRING_LEN, BOOL bOptimize = TRUE,
+ ULONG nLayoutWidth = 0, const sal_Int32* pDXArray = NULL ) const;
+ BOOL GetGlyphBoundRects( const Point& rOrigin, const String& rStr, int nIndex,
+ int nLen, int nBase, MetricVector& rVector );
+
+ void DrawPixel( const Point& rPt );
+ void DrawPixel( const Point& rPt, const Color& rColor );
+ void DrawPixel( const Polygon& rPts, const Color* pColors = NULL );
+ void DrawPixel( const Polygon& rPts, const Color& rColor );
+
+ void DrawLine( const Point& rStartPt, const Point& rEndPt );
+ void DrawLine( const Point& rStartPt, const Point& rEndPt,
+ const LineInfo& rLineInfo );
+
+ /** Render the given polygon as a line stroke
+
+ The given polygon is stroked with the current LineColor, start
+ and end point are not automatically connected
+
+ @see DrawPolygon
+ @see DrawPolyPolygon
+ */
+ void DrawPolyLine( const Polygon& rPoly );
+ void DrawPolyLine( const basegfx::B2DPolygon&, double fLineWidth = 0.0, basegfx::B2DLineJoin = basegfx::B2DLINEJOIN_ROUND );
+
+ /** Render the given polygon as a line stroke
+
+ The given polygon is stroked with the current LineColor, start
+ and end point are not automatically connected. The line is
+ rendered according to the specified LineInfo, e.g. supplying a
+ dash pattern, or a line thickness.
+
+ @see DrawPolygon
+ @see DrawPolyPolygon
+ */
+ void DrawPolyLine( const Polygon& rPoly,
+ const LineInfo& rLineInfo );
+
+ /** Render the given polygon
+
+ The given polygon is stroked with the current LineColor, and
+ filled with the current FillColor. If one of these colors are
+ transparent, the corresponding stroke or fill stays
+ invisible. Start and end point of the polygon are
+ automatically connected.
+
+ @see DrawPolyLine
+ */
+ void DrawPolygon( const Polygon& rPoly );
+ void DrawPolygon( const basegfx::B2DPolygon& );
+
+ /** Render the given poly-polygon
+
+ The given poly-polygon is stroked with the current LineColor,
+ and filled with the current FillColor. If one of these colors
+ are transparent, the corresponding stroke or fill stays
+ invisible. Start and end points of the contained polygons are
+ automatically connected.
+
+ @see DrawPolyLine
+ */
+ void DrawPolyPolygon( const PolyPolygon& rPolyPoly );
+ void DrawPolyPolygon( const basegfx::B2DPolyPolygon& );
+
+ void DrawRect( const Rectangle& rRect );
+ void DrawRect( const Rectangle& rRect,
+ ULONG nHorzRount, ULONG nVertRound );
+ void DrawEllipse( const Rectangle& rRect );
+ void DrawArc( const Rectangle& rRect,
+ const Point& rStartPt, const Point& rEndPt );
+ void DrawPie( const Rectangle& rRect,
+ const Point& rStartPt, const Point& rEndPt );
+ void DrawChord( const Rectangle& rRect,
+ const Point& rStartPt, const Point& rEndPt );
+
+ void DrawOutDev( const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPt, const Size& rSrcSize );
+ void DrawOutDev( const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPt, const Size& rSrcSize,
+ const OutputDevice& rOutDev );
+ void CopyArea( const Point& rDestPt,
+ const Point& rSrcPt, const Size& rSrcSize,
+ USHORT nFlags = 0 );
+
+ void DrawBitmap( const Point& rDestPt,
+ const Bitmap& rBitmap );
+ void DrawBitmap( const Point& rDestPt, const Size& rDestSize,
+ const Bitmap& rBitmap );
+ void DrawBitmap( const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPtPixel, const Size& rSrcSizePixel,
+ const Bitmap& rBitmap );
+
+ void DrawBitmapEx( const Point& rDestPt,
+ const BitmapEx& rBitmapEx );
+ void DrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
+ const BitmapEx& rBitmapEx );
+ void DrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPtPixel, const Size& rSrcSizePixel,
+ const BitmapEx& rBitmapEx );
+
+ void DrawMask( const Point& rDestPt,
+ const Bitmap& rBitmap, const Color& rMaskColor );
+ void DrawMask( const Point& rDestPt, const Size& rDestSize,
+ const Bitmap& rBitmap, const Color& rMaskColor );
+ void DrawMask( const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPtPixel, const Size& rSrcSizePixel,
+ const Bitmap& rBitmap, const Color& rMaskColor );
+
+ void DrawImage( const Point& rPos,
+ const Image& rImage, USHORT nStyle = 0 );
+ void DrawImage( const Point& rPos, const Size& rSize,
+ const Image& rImage, USHORT nStyle = 0 );
+
+ void DrawGradient( const Rectangle& rRect, const Gradient& rGradient );
+ void DrawGradient( const PolyPolygon& rPolyPoly, const Gradient& rGradient );
+ void AddGradientActions( const Rectangle& rRect,
+ const Gradient& rGradient,
+ GDIMetaFile& rMtf );
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+ void DrawHatch( const PolyPolygon& rPolyPoly, const ::Hatch& rHatch );
+ void AddHatchActions( const PolyPolygon& rPolyPoly,
+ const ::Hatch& rHatch,
+ GDIMetaFile& rMtf );
+#else
+ void DrawHatch( const PolyPolygon& rPolyPoly, const Hatch& rHatch );
+ void AddHatchActions( const PolyPolygon& rPolyPoly,
+ const Hatch& rHatch,
+ GDIMetaFile& rMtf );
+#endif
+
+ void DrawWallpaper( const Rectangle& rRect, const Wallpaper& rWallpaper );
+ void DrawWaveLine( const Point& rStartPos, const Point& rEndPos, USHORT nStyle );
+ void DrawGrid( const Rectangle& rRect, const Size& rDist, ULONG nFlags );
+
+ void DrawTransparent( const PolyPolygon& rPolyPoly, USHORT nTransparencePercent );
+ void DrawTransparent( const basegfx::B2DPolyPolygon& rB2DPolyPoly, double fTransparency);
+ void DrawTransparent( const GDIMetaFile& rMtf, const Point& rPos, const Size& rSize, const Gradient& rTransparenceGradient );
+
+ Color GetPixel( const Point& rPt ) const;
+ Color* GetPixel( const Polygon& rPts ) const;
+
+ Bitmap GetBitmap( const Point& rSrcPt, const Size& rSize ) const;
+
+ /** Query extended bitmap (with alpha channel, if available).
+ */
+ BitmapEx GetBitmapEx( const Point& rSrcPt, const Size& rSize ) const;
+
+ void EnableMapMode( BOOL bEnable = TRUE );
+ BOOL IsMapModeEnabled() const { return mbMap; }
+
+ // Enabling/disabling RTL only makes sense for OutputDevices that use a mirroring SalGraphisLayout
+ void EnableRTL( BOOL bEnable = TRUE);
+ BOOL IsRTLEnabled() const { return mbEnableRTL; }
+
+ void SetConnectMetaFile( GDIMetaFile* pMtf );
+ GDIMetaFile* GetConnectMetaFile() const { return mpMetaFile; }
+
+ void EnableOutput( BOOL bEnable = TRUE );
+ BOOL IsOutputEnabled() const { return mbOutput; }
+ BOOL IsDeviceOutput() const { return mbDevOutput; }
+ BOOL IsDeviceOutputNecessary() const { return (mbOutput && mbDevOutput); }
+ BOOL IsOutputNecessary() const { return ((mbOutput && mbDevOutput) || (mpMetaFile != NULL)); }
+
+ void SetClipRegion();
+ void SetClipRegion( const Region& rRegion );
+ void SetTriangleClipRegion( const PolyPolygon &rRegion );
+ Region GetClipRegion() const;
+ BOOL IsClipRegion() const { return mbClipRegion; }
+ Region GetActiveClipRegion() const;
+
+ void MoveClipRegion( long nHorzMove, long nVertMove );
+ void IntersectClipRegion( const Rectangle& rRect );
+ void IntersectClipRegion( const Region& rRegion );
+
+ void SetAntialiasing( USHORT nMode = 0 );
+ USHORT GetAntialiasing() const { return mnAntialiasing; }
+
+ void SetDrawMode( ULONG nDrawMode );
+ ULONG GetDrawMode() const { return mnDrawMode; }
+
+ void SetLayoutMode( ULONG nTextLayoutMode );
+ ULONG GetLayoutMode() const { return mnTextLayoutMode; }
+
+ void SetDigitLanguage( LanguageType );
+ LanguageType GetDigitLanguage() const { return meTextLanguage; }
+
+ void SetRasterOp( RasterOp eRasterOp );
+ RasterOp GetRasterOp() const { return meRasterOp; }
+
+ /**
+ If this OutputDevice is used for displaying a Print Preview
+ the OutDevViewType should be set to 'OUTDEV_VIEWTYPE_PRINTPREVIEW'.
+
+ A View than can make painting decisions dependent on this OutDevViewType.
+ E.g. text colors need to be handled different, dependent on wether it's a PrintPreview or not. (see #106611# for more)
+ */
+ void SetOutDevViewType( OutDevViewType eOutDevViewType ) { meOutDevViewType=eOutDevViewType; }
+ OutDevViewType GetOutDevViewType() const { return meOutDevViewType; }
+
+ void SetLineColor();
+ void SetLineColor( const Color& rColor );
+ const Color& GetLineColor() const { return maLineColor; }
+ BOOL IsLineColor() const { return mbLineColor; }
+
+ void SetFillColor();
+ void SetFillColor( const Color& rColor );
+ const Color& GetFillColor() const { return maFillColor; }
+ BOOL IsFillColor() const { return mbFillColor; }
+
+ void SetBackground();
+ void SetBackground( const Wallpaper& rBackground );
+
+ const Wallpaper& GetBackground() const { return maBackground; }
+ BOOL IsBackground() const { return mbBackground; }
+
+ void SetFont( const Font& rNewFont );
+ const Font& GetFont() const { return maFont; }
+
+ SystemFontData GetSysFontData( int nFallbacklevel ) const;
+ SystemTextLayoutData GetSysTextLayoutData( const Point& rStartPt, const XubString& rStr,
+ xub_StrLen nIndex = 0, xub_StrLen nLen = STRING_LEN,
+ const sal_Int32* pDXAry = NULL ) const;
+
+ void SetTextColor( const Color& rColor );
+ const Color& GetTextColor() const { return maTextColor; }
+ void SetTextFillColor();
+ void SetTextFillColor( const Color& rColor );
+
+ Color GetTextFillColor() const;
+ BOOL IsTextFillColor() const { return !maFont.IsTransparent(); }
+ void SetTextLineColor();
+ void SetTextLineColor( const Color& rColor );
+ const Color& GetTextLineColor() const { return maTextLineColor; }
+ BOOL IsTextLineColor() const { return (maTextLineColor.GetTransparency() == 0); }
+ void SetOverlineColor();
+ void SetOverlineColor( const Color& rColor );
+ const Color& GetOverlineColor() const { return maOverlineColor; }
+ BOOL IsOverlineColor() const { return (maOverlineColor.GetTransparency() == 0); }
+ void SetTextAlign( TextAlign eAlign );
+ TextAlign GetTextAlign() const { return maFont.GetAlign(); }
+
+ virtual void SetSettings( const AllSettings& rSettings );
+ const AllSettings& GetSettings() const { return maSettings; }
+
+ SystemGraphicsData GetSystemGfxData() const;
+ ::com::sun::star::uno::Any GetSystemGfxDataAny() const;
+
+ virtual void SetMapMode();
+ virtual void SetMapMode( const MapMode& rNewMapMode );
+ virtual void SetRelativeMapMode( const MapMode& rNewMapMode );
+ const MapMode& GetMapMode() const { return maMapMode; }
+ BOOL IsMapMode() const { return mbMap; }
+
+ void SetRefPoint();
+ void SetRefPoint( const Point& rRefPoint );
+ const Point& GetRefPoint() const { return maRefPoint; }
+ BOOL IsRefPoint() const { return mbRefPoint; }
+
+ // #i75163#
+ basegfx::B2DHomMatrix GetViewTransformation() const;
+ basegfx::B2DHomMatrix GetInverseViewTransformation() const;
+
+ basegfx::B2DHomMatrix GetViewTransformation( const MapMode& rMapMode ) const;
+ basegfx::B2DHomMatrix GetInverseViewTransformation( const MapMode& rMapMode ) const;
+
+
+ /** Set an offset in pixel
+
+ This method offsets every drawing operation that converts its
+ coordinates to pixel by the given value. Normally, the effect
+ can be achieved by setting a MapMode with a different
+ origin. Unfortunately, this origin is in logical coordinates
+ and can lead to rounding errors (see #102532# for details).
+
+ @attention This offset is only applied when converting to
+ pixel, i.e. some output modes such as metafile recordings
+ might be completely unaffected by this method! Use with
+ care. Furthermore, if the OutputDevice's MapMode is the
+ default (that's MAP_PIXEL), then, too, any pixel offset set is
+ ignored. This might be unintuitive for cases, but would have
+ been far more fragile to implement. What's more, the reason
+ why the pixel offset was introduced (avoiding rounding errors)
+ does not apply for MAP_PIXEL, because one can always use the
+ MapMode origin then.
+
+ @param rOffset
+ The offset in pixel
+ */
+ void SetPixelOffset( const Size& rOffset );
+
+ /** Get the offset in pixel
+
+ @see OutputDevice::SetPixelOffset for details
+
+ @return the current offset in pixel
+ */
+ Size GetPixelOffset() const;
+
+ Point LogicToPixel( const Point& rLogicPt ) const;
+ Size LogicToPixel( const Size& rLogicSize ) const;
+ Rectangle LogicToPixel( const Rectangle& rLogicRect ) const;
+ Polygon LogicToPixel( const Polygon& rLogicPoly ) const;
+ basegfx::B2DPolygon LogicToPixel( const basegfx::B2DPolygon& rLogicPolyPoly ) const;
+ PolyPolygon LogicToPixel( const PolyPolygon& rLogicPolyPoly ) const;
+ basegfx::B2DPolyPolygon LogicToPixel( const basegfx::B2DPolyPolygon& rLogicPolyPoly ) const;
+ Region LogicToPixel( const Region& rLogicRegion )const;
+ Point LogicToPixel( const Point& rLogicPt,
+ const MapMode& rMapMode ) const;
+ Size LogicToPixel( const Size& rLogicSize,
+ const MapMode& rMapMode ) const;
+ Rectangle LogicToPixel( const Rectangle& rLogicRect,
+ const MapMode& rMapMode ) const;
+ Polygon LogicToPixel( const Polygon& rLogicPoly,
+ const MapMode& rMapMode ) const;
+ basegfx::B2DPolygon LogicToPixel( const basegfx::B2DPolygon& rLogicPoly,
+ const MapMode& rMapMode ) const;
+ PolyPolygon LogicToPixel( const PolyPolygon& rLogicPolyPoly,
+ const MapMode& rMapMode ) const;
+ basegfx::B2DPolyPolygon LogicToPixel( const basegfx::B2DPolyPolygon& rLogicPolyPoly,
+ const MapMode& rMapMode ) const;
+ Region LogicToPixel( const Region& rLogicRegion,
+ const MapMode& rMapMode ) const;
+ Point PixelToLogic( const Point& rDevicePt ) const;
+ Size PixelToLogic( const Size& rDeviceSize ) const;
+ Rectangle PixelToLogic( const Rectangle& rDeviceRect ) const;
+ Polygon PixelToLogic( const Polygon& rDevicePoly ) const;
+ basegfx::B2DPolygon PixelToLogic( const basegfx::B2DPolygon& rDevicePoly ) const;
+ PolyPolygon PixelToLogic( const PolyPolygon& rDevicePolyPoly ) const;
+ basegfx::B2DPolyPolygon PixelToLogic( const basegfx::B2DPolyPolygon& rDevicePolyPoly ) const;
+ Region PixelToLogic( const Region& rDeviceRegion ) const;
+ Point PixelToLogic( const Point& rDevicePt,
+ const MapMode& rMapMode ) const;
+ Size PixelToLogic( const Size& rDeviceSize,
+ const MapMode& rMapMode ) const;
+ Rectangle PixelToLogic( const Rectangle& rDeviceRect,
+ const MapMode& rMapMode ) const;
+ Polygon PixelToLogic( const Polygon& rDevicePoly,
+ const MapMode& rMapMode ) const;
+ basegfx::B2DPolygon PixelToLogic( const basegfx::B2DPolygon& rDevicePoly,
+ const MapMode& rMapMode ) const;
+ PolyPolygon PixelToLogic( const PolyPolygon& rDevicePolyPoly,
+ const MapMode& rMapMode ) const;
+ basegfx::B2DPolyPolygon PixelToLogic( const basegfx::B2DPolyPolygon& rDevicePolyPoly,
+ const MapMode& rMapMode ) const;
+ Region PixelToLogic( const Region& rDeviceRegion,
+ const MapMode& rMapMode ) const;
+
+ Point LogicToLogic( const Point& rPtSource,
+ const MapMode* pMapModeSource,
+ const MapMode* pMapModeDest ) const;
+ Size LogicToLogic( const Size& rSzSource,
+ const MapMode* pMapModeSource,
+ const MapMode* pMapModeDest ) const;
+ Rectangle LogicToLogic( const Rectangle& rRectSource,
+ const MapMode* pMapModeSource,
+ const MapMode* pMapModeDest ) const;
+ long* LogicToLogic( long* pX,
+ USHORT nCount,
+ const MapMode* pMapModeSource,
+ const MapMode* pMapModeDest ) const;
+ static Point LogicToLogic( const Point& rPtSource,
+ const MapMode& rMapModeSource,
+ const MapMode& rMapModeDest );
+ static Size LogicToLogic( const Size& rSzSource,
+ const MapMode& rMapModeSource,
+ const MapMode& rMapModeDest );
+ static Rectangle LogicToLogic( const Rectangle& rRectSource,
+ const MapMode& rMapModeSource,
+ const MapMode& rMapModeDest );
+ static long LogicToLogic( long nLongSource,
+ MapUnit eUnitSource,
+ MapUnit eUnitDest );
+
+ static basegfx::B2DPolygon LogicToLogic( const basegfx::B2DPolygon& rPoly,
+ const MapMode& rMapModeSource,
+ const MapMode& rMapModeDest );
+ static basegfx::B2DPolyPolygon LogicToLogic( const basegfx::B2DPolyPolygon& rPolyPoly,
+ const MapMode& rMapModeSource,
+ const MapMode& rMapModeDest );
+
+ Size GetOutputSizePixel() const
+ { return Size( mnOutWidth, mnOutHeight ); }
+ long GetOutputWidthPixel() const { return mnOutWidth; }
+ long GetOutputHeightPixel() const { return mnOutHeight; }
+ long GetOutOffXPixel() const { return mnOutOffX; }
+ long GetOutOffYPixel() const { return mnOutOffY; }
+
+ Size GetOutputSize() const
+ { return PixelToLogic( GetOutputSizePixel() ); }
+
+ void Erase();
+ void Erase( const Rectangle& rRect ) { DrawWallpaper( rRect, GetBackground() ); }
+
+ BOOL AddTempDevFont( const String& rFileURL, const String& rFontName );
+ int GetDevFontCount() const;
+ FontInfo GetDevFont( int nDevFontIndex ) const;
+ int GetDevFontSizeCount( const Font& ) const;
+ Size GetDevFontSize( const Font& rFont, int nSizeIndex ) const;
+ BOOL IsFontAvailable( const String& rFontName ) const;
+
+ FontMetric GetFontMetric() const;
+ FontMetric GetFontMetric( const Font& rFont ) const;
+ BOOL GetFontCharMap( FontCharMap& rFontCharMap ) const;
+
+ xub_StrLen HasGlyphs( const Font& rFont, const String& rStr,
+ xub_StrLen nIndex = 0, xub_StrLen nLen = STRING_LEN ) const;
+
+ long GetMinKashida() const;
+ long GetMinKashida( const Font& rFont ) const;
+
+ // i60594
+ // validate kashida positions against the current font
+ // returns count of invalid kashida positions
+ xub_StrLen ValidateKashidas ( const String& rTxt,
+ xub_StrLen nIdx, xub_StrLen nLen,
+ xub_StrLen nKashCount, // number of suggested kashida positions (in)
+ const xub_StrLen* pKashidaPos, // suggested kashida positions (in)
+ xub_StrLen* pKashidaPosDropped // invalid kashida positions (out)
+ ) const;
+
+ USHORT GetBitCount() const;
+
+ BOOL GetTextIsRTL( const String&, xub_StrLen nIndex,
+ xub_StrLen nLen ) const;
+
+ /** Query the existence and depth of the alpha channel
+
+ @return 0, if no alpha channel available, and the bit depth of
+ the alpha channel otherwise.
+ */
+ USHORT GetAlphaBitCount() const;
+ ULONG GetColorCount() const;
+
+ void Push( USHORT nFlags = PUSH_ALL );
+ void Pop();
+
+ /** Query availability of alpha channel
+
+ @return TRUE, if this device has an alpha channel.
+ */
+ BOOL HasAlpha();
+
+ /** Added return value to see if EPS could be painted directly.
+ Theoreticaly, handing over a matrix would be needed to handle
+ painting rotated EPS files (e.g. contained mín Metafiles). This
+ would then need to be supported for Mac and PS printers, but
+ that's too much for now, wrote #i107046# for this */
+ bool DrawEPS( const Point& rPt, const Size& rSz,
+ const GfxLink& rGfxLink, GDIMetaFile* pSubst = NULL );
+
+ /// request XCanvas render interface for this OutputDevice
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XCanvas > GetCanvas() const;
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::awt::XGraphics > CreateUnoGraphics();
+ List* GetUnoGraphicsList() const { return mpUnoGraphicsList; }
+ List* CreateUnoGraphicsList() { mpUnoGraphicsList = new List; return mpUnoGraphicsList; }
+
+ static void BeginFontSubstitution();
+ static void EndFontSubstitution();
+ static void AddFontSubstitute( const XubString& rFontName,
+ const XubString& rReplaceFontName,
+ USHORT nFlags = 0 );
+ static void RemoveFontSubstitute( USHORT n );
+ static USHORT GetFontSubstituteCount();
+ static void GetFontSubstitute( USHORT n,
+ XubString& rFontName,
+ XubString& rReplaceFontName,
+ USHORT& rFlags );
+
+ static Font GetDefaultFont( USHORT nType,
+ LanguageType eLang,
+ ULONG nFlags,
+ const OutputDevice* pOutDev = NULL );
+
+ /** helper method removing transparencies from a metafile (e.g. for printing)
+
+ @returns
+ true: transparencies were removed
+ false: output metafile is unchanged input metafile
+
+ @attention this is a member method, so current state can influence the result !
+ @attention the output metafile is prepared in pixel mode for the currentOutputDevice
+ state. It can not be moved or rotated reliably anymore.
+ */
+ bool RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf, GDIMetaFile& rOutMtf,
+ long nMaxBmpDPIX, long nMaxBmpDPIY,
+ bool bReduceTransparency,
+ bool bTransparencyAutoMode,
+ bool bDownsampleBitmaps,
+ const Color& rBackground = Color( COL_TRANSPARENT )
+ );
+ /** Retrieve downsampled and cropped bitmap
+
+ @attention This method ignores negative rDstSz values, thus
+ mirroring must happen outside this method (e.g. in DrawBitmap)
+ */
+ Bitmap GetDownsampledBitmap( const Size& rDstSz,
+ const Point& rSrcPt, const Size& rSrcSz,
+ const Bitmap& rBmp, long nMaxBmpDPIX, long nMaxBmpDPIY );
+ /** Retrieve downsampled and cropped bitmapEx
+
+ @attention This method ignores negative rDstSz values, thus
+ mirroring must happen outside this method (e.g. in DrawBitmapEx)
+ */
+ BitmapEx GetDownsampledBitmapEx( const Size& rDstSz,
+ const Point& rSrcPt, const Size& rSrcSz,
+ const BitmapEx& rBmpEx, long nMaxBmpDPIX, long nMaxBmpDPIY );
+
+ //-------------------------------------
+ // Native Widget Rendering functions
+ //-------------------------------------
+
+ // These all just call through to the private mpGraphics functions of the same name.
+
+ // Query the platform layer for control support
+ BOOL IsNativeControlSupported( ControlType nType, ControlPart nPart );
+
+ // Query the native control to determine if it was acted upon
+ BOOL HitTestNativeControl( ControlType nType,
+ ControlPart nPart,
+ const Region& rControlRegion,
+ const Point& aPos,
+ BOOL& rIsInside );
+
+ // Request rendering of a particular control and/or part
+ BOOL DrawNativeControl( ControlType nType,
+ ControlPart nPart,
+ const Region& rControlRegion,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ ::rtl::OUString aCaption );
+
+ // Request rendering of a caption string for a control
+ BOOL DrawNativeControlText( ControlType nType,
+ ControlPart nPart,
+ const Region& rControlRegion,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ ::rtl::OUString aCaption );
+
+ // Query the native control's actual drawing region (including adornment)
+ BOOL GetNativeControlRegion( ControlType nType,
+ ControlPart nPart,
+ const Region& rControlRegion,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ ::rtl::OUString aCaption,
+ Region &rNativeBoundingRegion,
+ Region &rNativeContentRegion );
+
+};
+
+#endif // _SV_OUTDEV_HXX
diff --git a/vcl/inc/vcl/outfont.hxx b/vcl/inc/vcl/outfont.hxx
new file mode 100644
index 000000000000..4bbf7176ddb2
--- /dev/null
+++ b/vcl/inc/vcl/outfont.hxx
@@ -0,0 +1,406 @@
+/*************************************************************************
+ *
+ * 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_OUTFONT_HXX
+#define _SV_OUTFONT_HXX
+
+#include <tools/string.hxx>
+#include <tools/list.hxx>
+#include <i18npool/lang.h>
+#include <tools/gen.hxx>
+#include <tools/solar.h>
+#include <vcl/dllapi.h>
+#include <unotools/fontdefs.hxx>
+#include <vcl/vclenum.hxx>
+
+#include <hash_map>
+
+#include <com/sun/star/linguistic2/XLinguServiceManager.hpp>
+
+class ImplDevFontListData;
+class ImplGetDevFontList;
+class ImplGetDevSizeList;
+class ImplFontEntry;
+class ImplDirectFontSubstitution;
+class ImplPreMatchFontSubstitution;
+class ImplGlyphFallbackFontSubstitution;
+class ImplFontSelectData;
+class Font;
+class ConvertChar;
+struct FontMatchStatus;
+class OutputDevice;
+
+// ----------------------
+// - ImplFontAttributes -
+// ----------------------
+// device independent font properties
+
+class ImplFontAttributes
+{
+public: // TODO: create matching interface class
+ const String& GetFamilyName() const { return maName; }
+ const String& GetStyleName() const { return maStyleName; }
+ FontWeight GetWeight() const { return meWeight; }
+ FontItalic GetSlant() const { return meItalic; }
+ FontFamily GetFamilyType() const { return meFamily; }
+ FontPitch GetPitch() const { return mePitch; }
+ FontWidth GetWidthType() const { return meWidthType; }
+ bool IsSymbolFont() const { return mbSymbolFlag; }
+
+public: // TODO: hide members behind accessor methods
+ String maName; // Font Family Name
+ String maStyleName; // Font Style Name
+ FontWeight meWeight; // Weight Type
+ FontItalic meItalic; // Slant Type
+ FontFamily meFamily; // Family Type
+ FontPitch mePitch; // Pitch Type
+ FontWidth meWidthType; // Width Type
+ bool mbSymbolFlag;
+};
+
+// -------------------------
+// - ImplDevFontAttributes -
+// -------------------------
+// device dependent font properties
+
+class ImplDevFontAttributes : public ImplFontAttributes
+{
+public: // TODO: create matching interface class
+ const String& GetAliasNames() const { return maMapNames; }
+ int GetQuality() const { return mnQuality; }
+ bool IsRotatable() const { return mbOrientation; }
+ bool IsDeviceFont() const { return mbDevice; }
+ bool IsEmbeddable() const { return mbEmbeddable; }
+ bool IsSubsettable() const { return mbSubsettable; }
+
+public: // TODO: hide members behind accessor methods
+ String maMapNames; // List of family name aliass separated with ';'
+ int mnQuality; // Quality (used when similar fonts compete)
+ bool mbOrientation; // true: physical font can be rotated
+ bool mbDevice; // true: built in font
+ bool mbSubsettable; // true: a subset of the font can be created
+ bool mbEmbeddable; // true: the font can be embedded
+};
+
+// ----------------
+// - ImplFontData -
+// ----------------
+// TODO: rename ImplFontData to PhysicalFontFace
+// TODO: no more direct access to members
+// TODO: add reference counting
+// TODO: get rid of height/width for scalable fonts
+// TODO: make cloning cheaper
+
+// abstract base class for physical font faces
+class VCL_DLLPUBLIC ImplFontData : public ImplDevFontAttributes
+{
+public:
+ // by using an ImplFontData object as a factory for its corresponding
+ // ImplFontEntry an ImplFontEntry can be extended to cache device and
+ // font instance specific data
+ virtual ImplFontEntry* CreateFontInstance( ImplFontSelectData& ) const = 0;
+
+ virtual int GetHeight() const { return mnHeight; }
+ virtual int GetWidth() const { return mnWidth; }
+ virtual sal_IntPtr GetFontId() const = 0;
+ int GetFontMagic() const { return mnMagic; }
+ bool IsScalable() const { return (mnHeight == 0); }
+ bool CheckMagic( int n ) const { return (n == mnMagic); }
+ ImplFontData* GetNextFace() const { return mpNext; }
+ ImplFontData* CreateAlias() const { return Clone(); }
+
+ bool IsBetterMatch( const ImplFontSelectData&, FontMatchStatus& ) const;
+ StringCompare CompareWithSize( const ImplFontData& ) const;
+ StringCompare CompareIgnoreSize( const ImplFontData& ) const;
+ virtual ~ImplFontData() {}
+ virtual ImplFontData* Clone() const = 0;
+
+protected:
+ ImplFontData( const ImplDevFontAttributes&, int nMagic );
+ void SetBitmapSize( int nW, int nH ) { mnWidth=nW; mnHeight=nH; }
+
+ long mnWidth; // Width (in pixels)
+ long mnHeight; // Height (in pixels)
+
+private:
+friend class ImplDevFontListData;
+ const int mnMagic; // poor man's RTTI
+ ImplFontData* mpNext;
+};
+
+// ----------------------
+// - ImplFontSelectData -
+// ----------------------
+
+class ImplFontSelectData : public ImplFontAttributes
+{
+public:
+ ImplFontSelectData( const Font&, const String& rSearchName,
+ const Size&, float fExactHeight );
+ ImplFontSelectData( const ImplFontData&, const Size&,
+ float fExactHeight, int nOrientation, bool bVertical );
+
+public: // TODO: change to private
+ String maTargetName; // name of the font name token that is chosen
+ String maSearchName; // name of the font that matches best
+ int mnWidth; // width of font in pixel units
+ int mnHeight; // height of font in pixel units
+ float mfExactHeight; // requested height (in pixels with subpixel details)
+ int mnOrientation; // text orientation in 3600 system
+ LanguageType meLanguage; // text language
+ bool mbVertical; // vertical mode of requested font
+ bool mbNonAntialiased; // true if antialiasing is disabled
+
+ const ImplFontData* mpFontData; // a matching ImplFontData object
+ ImplFontEntry* mpFontEntry; // pointer to the resulting FontCache entry
+};
+
+// -------------------
+// - ImplDevFontList -
+// -------------------
+// TODO: merge with ImplFontCache
+// TODO: rename to LogicalFontManager
+
+class VCL_DLLPUBLIC ImplDevFontList
+{
+private:
+ friend class WinGlyphFallbackSubstititution;
+ mutable bool mbMatchData; // true if matching attributes are initialized
+ bool mbMapNames; // true if MapNames are available
+
+ typedef std::hash_map<const String, ImplDevFontListData*,FontNameHash> DevFontList;
+ DevFontList maDevFontList;
+
+ ImplPreMatchFontSubstitution* mpPreMatchHook; // device specific prematch substitution
+ ImplGlyphFallbackFontSubstitution* mpFallbackHook; // device specific glyh fallback substitution
+
+public:
+ ImplDevFontList();
+ ~ImplDevFontList();
+
+ // fill the list with device fonts
+ void Add( ImplFontData* );
+ void Clear();
+ int Count() const { return maDevFontList.size(); }
+
+ // find the device font
+ ImplDevFontListData* FindFontFamily( const String& rFontName ) const;
+ ImplDevFontListData* ImplFindByFont( ImplFontSelectData&, bool bPrinter, ImplDirectFontSubstitution* ) const;
+ ImplDevFontListData* ImplFindBySearchName( const String& ) const;
+
+ // suggest fonts for glyph fallback
+ ImplDevFontListData* GetGlyphFallbackFont( ImplFontSelectData&,
+ rtl::OUString& rMissingCodes, int nFallbackLevel ) const;
+
+ // prepare platform specific font substitutions
+ void SetPreMatchHook( ImplPreMatchFontSubstitution* );
+ void SetFallbackHook( ImplGlyphFallbackFontSubstitution* );
+
+ // misc utilities
+ ImplDevFontList* Clone( bool bScalable, bool bEmbeddable ) const;
+ ImplGetDevFontList* GetDevFontList() const;
+ ImplGetDevSizeList* GetDevSizeList( const String& rFontName ) const;
+
+ //used by 2-level font fallback
+ ImplDevFontListData* ImplFindByLocale(com::sun::star::lang::Locale lc) const;
+
+protected:
+ void InitMatchData() const;
+ bool AreMapNamesAvailable() const { return mbMapNames; }
+
+ ImplDevFontListData* ImplFindByTokenNames( const String& ) const;
+ ImplDevFontListData* ImplFindByAliasName( const String& rSearchName, const String& rShortName ) const;
+ ImplDevFontListData* ImplFindBySubstFontAttr( const utl::FontNameAttr& ) const;
+ ImplDevFontListData* ImplFindByAttributes( ULONG nSearchType, FontWeight, FontWidth,
+ FontFamily, FontItalic, const String& rSearchFamily ) const;
+ ImplDevFontListData* FindDefaultFont() const;
+
+private:
+ void InitGenericGlyphFallback() const;
+ mutable ImplDevFontListData** mpFallbackList;
+ mutable int mnFallbackCount;
+};
+
+// --------------------
+// - ImplKernPairData -
+// --------------------
+// TODO: get rid of ImplKernPairData and use outdev.hxx's KerningPair struct
+// the problem is that outdev.hxx is too high level for the device layers
+// and outdev.hxx's customers depend on KerningPair being defined there
+
+struct ImplKernPairData
+{
+ USHORT mnChar1;
+ USHORT mnChar2;
+ long mnKern;
+};
+
+
+// -----------------------
+// - ImplFontMetricData -
+// -----------------------
+
+class ImplFontMetricData : public ImplFontAttributes
+{
+public:
+ ImplFontMetricData( const ImplFontSelectData& );
+ void ImplInitTextLineSize( const OutputDevice* pDev );
+ void ImplInitAboveTextLineSize();
+
+public: // TODO: hide members behind accessor methods
+ // font instance attributes from the font request
+ long mnWidth; // Reference Width
+ short mnOrientation; // Rotation in 1/10 degrees
+
+ // font metrics measured for the font instance
+ long mnAscent; // Ascent
+ long mnDescent; // Descent
+ long mnIntLeading; // Internal Leading
+ long mnExtLeading; // External Leading
+ int mnSlant; // Slant (Italic/Oblique)
+ long mnMinKashida; // Minimal width of kashida (Arabic)
+
+ // font attributes queried from the font instance
+ int meFamilyType; // Font Family Type
+ bool mbDevice; // Flag for Device Fonts
+ bool mbScalableFont;
+ bool mbKernableFont;
+
+ // font metrics that are usually derived from the measurements
+ long mnUnderlineSize; // Lineheight of Underline
+ long mnUnderlineOffset; // Offset from Underline to Baseline
+ long mnBUnderlineSize; // Hoehe von fetter Unterstreichung
+ long mnBUnderlineOffset; // Offset von fetter Unterstreichung zur Baseline
+ long mnDUnderlineSize; // Hoehe von doppelter Unterstreichung
+ long mnDUnderlineOffset1; // Offset von doppelter Unterstreichung zur Baseline
+ long mnDUnderlineOffset2; // Offset von doppelter Unterstreichung zur Baseline
+ long mnWUnderlineSize; // Hoehe von WaveLine-Unterstreichung
+ long mnWUnderlineOffset; // Offset von WaveLine-Unterstreichung zur Baseline, jedoch zentriert zur WaveLine
+ long mnAboveUnderlineSize; // Hoehe von einfacher Unterstreichung (for Vertical Right)
+ long mnAboveUnderlineOffset; // Offset von einfacher Unterstreichung zur Baseline (for Vertical Right)
+ long mnAboveBUnderlineSize; // Hoehe von fetter Unterstreichung (for Vertical Right)
+ long mnAboveBUnderlineOffset; // Offset von fetter Unterstreichung zur Baseline (for Vertical Right)
+ long mnAboveDUnderlineSize; // Hoehe von doppelter Unterstreichung (for Vertical Right)
+ long mnAboveDUnderlineOffset1; // Offset von doppelter Unterstreichung zur Baseline (for Vertical Right)
+ long mnAboveDUnderlineOffset2; // Offset von doppelter Unterstreichung zur Baseline (for Vertical Right)
+ long mnAboveWUnderlineSize; // Hoehe von WaveLine-Unterstreichung (for Vertical Right)
+ long mnAboveWUnderlineOffset; // Offset von WaveLine-Unterstreichung zur Baseline, jedoch zentriert zur WaveLine (for Vertical Right)
+ long mnStrikeoutSize; // Hoehe von einfacher Durchstreichung
+ long mnStrikeoutOffset; // Offset von einfacher Durchstreichung zur Baseline
+ long mnBStrikeoutSize; // Hoehe von fetter Durchstreichung
+ long mnBStrikeoutOffset; // Offset von fetter Durchstreichung zur Baseline
+ long mnDStrikeoutSize; // Hoehe von doppelter Durchstreichung
+ long mnDStrikeoutOffset1; // Offset von doppelter Durchstreichung zur Baseline
+ long mnDStrikeoutOffset2; // Offset von doppelter Durchstreichung zur Baseline
+};
+
+// -----------------
+// - ImplFontEntry -
+// ------------------
+// TODO: rename ImplFontEntry to LogicalFontInstance
+// TODO: allow sharing of metrics for related fonts
+
+class VCL_DLLPUBLIC ImplFontEntry
+{
+public:
+ ImplFontEntry( const ImplFontSelectData& );
+ virtual ~ImplFontEntry();
+
+public: // TODO: make data members private
+ ImplFontSelectData maFontSelData; // FontSelectionData
+ ImplFontMetricData maMetric; // Font Metric
+ const ConvertChar* mpConversion; // used e.g. for StarBats->StarSymbol
+ long mnLineHeight;
+ ULONG mnRefCount;
+ USHORT mnSetFontFlags; // Flags returned by SalGraphics::SetFont()
+ short mnOwnOrientation; // text angle if lower layers don't rotate text themselves
+ short mnOrientation; // text angle in 3600 system
+ bool mbInit; // true if maMetric member is valid
+
+ void AddFallbackForUnicode( sal_UCS4, FontWeight eWeight, const String& rFontName );
+ bool GetFallbackForUnicode( sal_UCS4, FontWeight eWeight, String* pFontName ) const;
+ void IgnoreFallbackForUnicode( sal_UCS4, FontWeight eWeight, const String& rFontName );
+
+private:
+ // cache of Unicode characters and replacement font names
+ // TODO: a fallback map can be shared with many other ImplFontEntries
+ // TODO: at least the ones which just differ in orientation, stretching or height
+ typedef ::std::pair<sal_UCS4,FontWeight> GFBCacheKey;
+ struct GFBCacheKey_Hash{ size_t operator()( const GFBCacheKey& ) const; };
+ typedef ::std::hash_map<GFBCacheKey,String,GFBCacheKey_Hash> UnicodeFallbackList;
+ UnicodeFallbackList* mpUnicodeFallbackList;
+};
+
+
+class ImplTextLineInfo
+{
+private:
+ long mnWidth;
+ xub_StrLen mnIndex;
+ xub_StrLen mnLen;
+
+public:
+ ImplTextLineInfo( long nWidth, xub_StrLen nIndex, xub_StrLen nLen )
+ {
+ mnWidth = nWidth;
+ mnIndex = nIndex;
+ mnLen = nLen;
+ }
+
+ long GetWidth() const { return mnWidth; }
+ xub_StrLen GetIndex() const { return mnIndex; }
+ xub_StrLen GetLen() const { return mnLen; }
+};
+
+#define MULTITEXTLINEINFO_RESIZE 16
+typedef ImplTextLineInfo* PImplTextLineInfo;
+
+class ImplMultiTextLineInfo
+{
+private:
+ PImplTextLineInfo* mpLines;
+ xub_StrLen mnLines;
+ xub_StrLen mnSize;
+
+public:
+ ImplMultiTextLineInfo();
+ ~ImplMultiTextLineInfo();
+
+ void AddLine( ImplTextLineInfo* pLine );
+ void Clear();
+
+ ImplTextLineInfo* GetLine( USHORT nLine ) const
+ { return mpLines[nLine]; }
+ xub_StrLen Count() const { return mnLines; }
+
+private:
+ ImplMultiTextLineInfo( const ImplMultiTextLineInfo& );
+ ImplMultiTextLineInfo& operator=( const ImplMultiTextLineInfo& );
+};
+
+#endif // _SV_OUTFONT_HXX
+
diff --git a/vcl/inc/vcl/pdfextoutdevdata.hxx b/vcl/inc/vcl/pdfextoutdevdata.hxx
new file mode 100644
index 000000000000..5dda4b0f79fa
--- /dev/null
+++ b/vcl/inc/vcl/pdfextoutdevdata.hxx
@@ -0,0 +1,518 @@
+/*************************************************************************
+ *
+ * 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_PDFEXTOUTDEVDATA_HXX
+#define _VCL_PDFEXTOUTDEVDATA_HXX
+
+#include <vcl/dllapi.h>
+
+#include <vcl/pdfwriter.hxx>
+#include <vcl/extoutdevdata.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/mapmod.hxx>
+#include <tools/rtti.hxx>
+#include <vector>
+#include <deque>
+
+class Graphic;
+
+namespace vcl { class PDFWriter; }
+
+namespace vcl
+{
+
+/*
+ A PDFExtOutDevBookmarkEntry is being created by the EditEngine if
+ a bookmark URL has been parsed. The Application is requested to take
+ care of each bookmark entry by emptying out the bookmark vector.
+*/
+struct PDFExtOutDevBookmarkEntry
+{
+ sal_Int32 nLinkId;
+ rtl::OUString aBookmark;
+};
+
+/*
+ Class that is being set at the OutputDevice allowing the
+ application to send enhanced PDF commands like CreateLink
+*/
+struct PageSyncData;
+struct GlobalSyncData;
+class VCL_DLLPUBLIC PDFExtOutDevData : public ExtOutDevData
+{
+
+ const OutputDevice& mrOutDev;
+
+ sal_Bool mbTaggedPDF;
+ sal_Bool mbExportNotes;
+ sal_Bool mbTransitionEffects;
+ sal_Bool mbUseLosslessCompression;
+ sal_Bool mbReduceImageResolution;
+ sal_Bool mbExportFormFields;
+ sal_Bool mbExportBookmarks;
+ sal_Bool mbExportNDests; //i56629
+ sal_Int32 mnFormsFormat;
+ sal_Int32 mnPage;
+ com::sun::star::lang::Locale maDocLocale;
+
+ PageSyncData* mpPageSyncData;
+ GlobalSyncData* mpGlobalSyncData;
+
+ std::vector< PDFExtOutDevBookmarkEntry > maBookmarks;
+
+public :
+
+ TYPEINFO();
+ PDFExtOutDevData( const OutputDevice& rOutDev );
+ virtual ~PDFExtOutDevData();
+
+ sal_Bool PlaySyncPageAct( PDFWriter& rWriter, sal_uInt32& rCurGDIMtfAction );
+ void ResetSyncData();
+
+ void PlayGlobalActions( PDFWriter& rWriter );
+
+
+
+ sal_Bool GetIsExportNotes() const;
+ void SetIsExportNotes( const sal_Bool bExportNotes );
+
+ sal_Bool GetIsExportTaggedPDF() const;
+ void SetIsExportTaggedPDF( const sal_Bool bTaggedPDF );
+
+ sal_Bool GetIsExportTransitionEffects() const;
+ void SetIsExportTransitionEffects( const sal_Bool bTransitionalEffects );
+
+ sal_Bool GetIsExportFormFields() const;
+ void SetIsExportFormFields( const sal_Bool bExportFormFields );
+
+ sal_Int32 GetFormsFormat() const;
+ void SetFormsFormat( const sal_Int32 nFormsFormat );
+
+ sal_Bool GetIsExportBookmarks() const;
+ void SetIsExportBookmarks( const sal_Bool bExportBookmarks );
+
+ sal_Bool GetIsExportNamedDestinations() const; //i56629
+ void SetIsExportNamedDestinations( const sal_Bool bExportNDests ); //i56629
+
+ // PageNumber, Compression is being set by the PDFExport
+ sal_Int32 GetCurrentPageNumber() const;
+ void SetCurrentPageNumber( const sal_Int32 nPage );
+
+ sal_Bool GetIsLosslessCompression() const;
+ void SetIsLosslessCompression( const sal_Bool bLosslessCompression );
+
+ sal_Bool GetIsReduceImageResolution() const;
+ void SetIsReduceImageResolution( const sal_Bool bReduceImageResolution );
+
+ const com::sun::star::lang::Locale& GetDocumentLocale() const;
+ void SetDocumentLocale( const com::sun::star::lang::Locale& rLoc );
+
+ std::vector< PDFExtOutDevBookmarkEntry >& GetBookmarks();
+
+ /** Start a new group of render output
+
+ Use this method to group render output.
+ */
+ void BeginGroup();
+
+ /** End render output
+
+ This method ends grouped render output without
+ further actions.
+ */
+ void EndGroup();
+
+ /** End render output
+
+ This method ends grouped render output, that can be
+ represented by a GfxLink. This is typically used for
+ external graphic files, such as JPEGs, EPS files etc.
+ The BeginGroup/EndGroup calls must exactly enclose the
+ relevant OutputDevice calls issued to render the
+ graphic the normal way.
+
+ @param rGraphic
+ The link to the original graphic
+
+ @param nTransparency
+ Eight bit transparency value, with 0 denoting full opacity,
+ and 255 full transparency.
+
+ @param rOutputRect
+ The output rectangle of the graphic.
+
+ @param rVisibleOutputRect
+ The visible part of the output. This might be less than
+ rOutputRect, e.g. for cropped graphics.
+ */
+ void EndGroup( const Graphic& rGraphic,
+ BYTE nTransparency,
+ const Rectangle& rOutputRect,
+ const Rectangle& rVisibleOutputRect );
+//--->i56629
+ /** Create a new named destination to be used in a link to this document from another PDF document
+ (see PDF spec 1.4, 8.2.1)
+
+ @parm sDestName
+ the name this destination will be addressed with from others PDF document
+
+ @param rRect
+ target rectangle on page to be displayed if dest is jumped to
+
+ @param nPageNr
+ number of page the dest is on (as returned by NewPage)
+ or -1 in which case the current page is used
+
+ @param eType
+ what dest type to use
+
+ @returns
+ the destination id (to be used in SetLinkDest) or
+ -1 if page id does not exist
+ */
+ sal_Int32 CreateNamedDest( const String& sDestName, const Rectangle& rRect, sal_Int32 nPageNr = -1, PDFWriter::DestAreaType eType = PDFWriter::XYZ );
+//<---i56629
+
+ /** Create a new destination to be used in a link
+
+ @param rRect
+ target rectangle on page to be displayed if dest is jumped to
+
+ @param nPageNr
+ number of page the dest is on (as returned by NewPage)
+ or -1 in which case the current page is used
+
+ @param eType
+ what dest type to use
+
+ @returns
+ the destination id (to be used in SetLinkDest) or
+ -1 if page id does not exist
+ */
+ sal_Int32 CreateDest( const Rectangle& rRect, sal_Int32 nPageNr = -1, PDFWriter::DestAreaType eType = PDFWriter::XYZ );
+ /** Create a new link on a page
+
+ @param rRect
+ active rectangle of the link (that is the area that has to be
+ hit to activate the link)
+
+ @param nPageNr
+ number of page the link is on (as returned by NewPage)
+ or -1 in which case the current page is used
+
+ @returns
+ the link id (to be used in SetLinkDest, SetLinkURL) or
+ -1 if page id does not exist
+ */
+ sal_Int32 CreateLink( const Rectangle& rRect, sal_Int32 nPageNr = -1 );
+ /** Set the destination for a link
+ <p>will change a URL type link to a dest link if necessary</p>
+
+ @param nLinkId
+ the link to be changed
+
+ @param nDestId
+ the dest the link shall point to
+ @returns
+ 0 for success
+ -1 in case the link id does not exist
+ -2 in case the dest id does not exist
+ */
+ sal_Int32 SetLinkDest( sal_Int32 nLinkId, sal_Int32 nDestId );
+ /** Set the URL for a link
+ <p>will change a dest type link to an URL type link if necessary</p>
+ @param nLinkId
+ the link to be changed
+
+ @param rURL
+ the URL the link shall point to.
+ there will be no error checking or any kind of
+ conversion done to this parameter execept this:
+ it will be output as 7bit Ascii. The URL
+ will appear literally in the PDF file produced
+
+ @returns
+ 0 for success
+ -1 in case the link id does not exist
+ */
+ sal_Int32 SetLinkURL( sal_Int32 nLinkId, const rtl::OUString& rURL );
+ /** Create a new outline item
+
+ @param nParent
+ declares the parent of the new item in the outline hierarchy.
+ An invalid value will result in a new toplevel item.
+
+ @param rText
+ sets the title text of the item
+
+ @param nDestId
+ declares which Dest (created with CreateDest) the outline item
+ will point to
+
+ @returns
+ the outline item id of the new item
+ */
+ sal_Int32 CreateOutlineItem( sal_Int32 nParent = 0, const rtl::OUString& rText = rtl::OUString(), sal_Int32 nDestID = -1 );
+
+ /** Set an outline item's parent
+
+ @param nItem
+ specififies which item should be reparented.
+
+ @param nNewParent
+ specifies which outline item will be the item's new parent.
+ Use 0 for reparenting to top level.
+
+ @returns
+ -1 if the item does not exist
+ -2 if the new parent does not exist, item will be reparented to top level.
+ */
+ sal_Int32 SetOutlineItemParent( sal_Int32 nItem, sal_Int32 nNewParent );
+
+ /** Set an outline item's title text
+
+ @param nItem
+ specififies which item should get a new text
+
+ @param rText
+ sets the title text of the item
+
+ @returns
+ 0 if the item exists and the text was changed
+ -1 if the item does not exist
+ */
+ sal_Int32 SetOutlineItemText( sal_Int32 nItem, const rtl::OUString& rText );
+
+ /** Set an outline item's destination
+
+ @param nItem
+ specififies which item should get a new dest
+
+ @param nDestID
+ specifies the item's new destination
+
+ @returns
+ -1 if the item does not exist
+ -2 if the new dest does not exist, dest will remain unchanged
+ */
+ sal_Int32 SetOutlineItemDest( sal_Int32 nItem, sal_Int32 nDestID );
+
+ /** Create a new note on a page
+
+ @param rRect
+ active rectangle of the note (that is the area that has to be
+ hit to popup the annotation)
+
+ @param rNote
+ specifies the contents of the note
+
+ @param nPageNr
+ number of page the note is on (as returned by NewPage)
+ or -1 in which case the current page is used
+ */
+ void CreateNote( const Rectangle& rRect, const PDFNote& rNote, sal_Int32 nPageNr = -1 );
+
+ /** begin a new logical structure element
+
+ BeginStructureElement/EndStructureElement calls build the logical structure
+ of the PDF - the basis for tagged PDF. Structural elements are implemented
+ using marked content tags. Each structural element can contain sub elements
+ (e.g. a section can contain a heading and a paragraph). The structure hierarchy
+ is build automatically from the Begin/EndStructureElement calls.
+
+ A structural element need not be contained on one page; e.g. paragraphs often
+ run from one page to the next. In this case the corresponding EndStructureElement
+ must be called while drawing the next page.
+
+ BeginStructureElement and EndStructureElement must be called only after
+ <member scope="vcl">PDFWriter::NewPage</member> has been called and before
+ <member scope="vcl">PDFWriter::Emit</member>gets called. The current page
+ number is an implicit context parameter for Begin/EndStructureElement.
+
+ For pagination artifacts that are not part of the logical structure
+ of the document (like header, footer or page number) the special
+ StructElement <code>NonStructElement</code> exists. To place content
+ outside of the struture tree simply call
+ <code>BeginStructureElement( NonStructElement )</code> then draw your
+ content and then call <code>EndStructureElement()</code>. Any children
+ of a <code>NonStructElement</code> will not be part of the structure as well.
+
+ @param eType
+ denotes what kind of element to begin (e.g. a heading or paragraph)
+
+ @param rAlias
+ the specified alias will be used as structure tag. Also an entry in the PDF's
+ role map will be created mapping alias to regular structure type.
+
+ @returns
+ the id of the newly created structural element
+ */
+ sal_Int32 BeginStructureElement( PDFWriter::StructElement eType, const rtl::OUString& rAlias = rtl::OUString() );
+ /** end a logical structure element
+
+ @see BeginStructureElement
+ */
+ void EndStructureElement();
+ /** set the current structure element
+
+ <p>
+ For different purposes it may be useful to paint a structure element's
+ content discontinously. In that case an already existing structure element
+ can be appended to by using <code>SetCurrentStructureElement</code>. The
+ refenrenced structure element becomes the current structure element with
+ all consequences: all following structure elements are appended as children
+ of the current element.
+ </p>
+
+ @param nElement
+ the id of the new current structure element
+
+ @returns
+ <true/> if the current structure element could be set successfully
+ <false/> if the current structure element could not be changed
+ (e.g. if the passed element id is invalid)
+ */
+ bool SetCurrentStructureElement( sal_Int32 nElement );
+ /** get the current structure element id
+
+ @returns
+ the id of the current structure element
+ */
+ sal_Int32 GetCurrentStructureElement();
+
+ /** set a structure attribute on the current structural element
+
+ SetStructureAttribute sets an attribute of the current structural element to a
+ new value. A consistency check is performed before actually setting the value;
+ if the check fails, the function returns <FALSE/> and the attribute remains
+ unchanged.
+
+ @param eAttr
+ denotes what attribute to change
+
+ @param eVal
+ the value to set the attribute to
+
+ @returns
+ <TRUE/> if the value was valid and the change has been performed,
+ <FALSE/> if the attribute or value was invalid; attribute remains unchanged
+ */
+ bool SetStructureAttribute( PDFWriter::StructAttribute eAttr, PDFWriter::StructAttributeValue eVal );
+ /** set a structure attribute on the current structural element
+
+ SetStructureAttributeNumerical sets an attribute of the current structural element
+ to a new numerical value. A consistency check is performed before actually setting
+ the value; if the check fails, the function returns <FALSE/> and the attribute
+ remains unchanged.
+
+ @param eAttr
+ denotes what attribute to change
+
+ @param nValue
+ the value to set the attribute to
+
+ @returns
+ <TRUE/> if the value was valid and the change has been performed,
+ <FALSE/> if the attribute or value was invalid; attribute remains unchanged
+ */
+ bool SetStructureAttributeNumerical( PDFWriter::StructAttribute eAttr, sal_Int32 nValue );
+ /** set the bounding box of a structural element
+
+ SetStructureBoundingBox sets the BBox attribute to a new value. Since the BBox
+ attribute can only be applied to <code>Table</code>, <code>Figure</code>,
+ <code>Form</code> and <code>Formula</code> elements, a call of this function
+ for other element types will be ignored and the BBox attribute not be set.
+
+ @param rRect
+ the new bounding box for the structural element
+ */
+ void SetStructureBoundingBox( const Rectangle& rRect );
+
+ /** set the ActualText attribute of a structural element
+
+ ActualText contains the Unicode text without layout artifacts that is shown by
+ a structural element. For example if a line is ended prematurely with a break in
+ a word and continued on the next line (e.g. "happen-<newline>stance") the
+ corresponding ActualText would contain the unbroken line (e.g. "happenstance").
+
+ @param rText
+ contains the complete logical text the structural element displays.
+ */
+ void SetActualText( const String& rText );
+
+ /** set the Alt attribute of a strutural element
+
+ Alt is s replacement text describing the contents of a structural element. This
+ is mainly used by accessibility applications; e.g. a screen reader would read
+ the Alt replacement text for an image to a visually impaired user.
+
+ @param rText
+ contains the replacement text for the structural element
+ */
+ void SetAlternateText( const String& rText );
+
+ /** Sets the time in seconds a page will appear before the next
+ page is shown automatically
+
+ @param nSeconds
+ time in seconds the current page will be shown; pass 0 for manual advancement
+
+ @param nPageNr
+ the page number to apply the autoadvance time to; -1 denotes the current page
+ */
+ void SetAutoAdvanceTime( sal_uInt32 nSeconds, sal_Int32 nPageNr = -1 );
+
+ /** Sets the transitional effect to be applied when the current page gets shown.
+
+ @param eType
+ the kind of effect to be used; use Regular to disable transitional effects
+ for this page
+
+ @param nMilliSec
+ the duration of the transitional effect in milliseconds;
+ set 0 to disable transitional effects
+
+ @param nPageNr
+ the page number to apply the effect to; -1 denotes the current page
+ */
+ void SetPageTransition( PDFWriter::PageTransition eType, sal_uInt32 nMilliSec, sal_Int32 nPageNr = -1 );
+
+ /** create a new form control
+
+ This function creates a new form control in the PDF and sets its various
+ properties. Do not pass an actual AnyWidget as <code>rControlType</code>
+ will be cast to the type described by the type member.
+
+ @param rControlType
+ a descendant of <code>AnyWidget</code> determing the control's properties
+ */
+ void CreateControl( const PDFWriter::AnyWidget& rControlType, sal_Int32 nPageNr = -1 );
+};
+
+}
+
+#endif
diff --git a/vcl/inc/vcl/pdfwriter.hxx b/vcl/inc/vcl/pdfwriter.hxx
new file mode 100644
index 000000000000..419814e5ce97
--- /dev/null
+++ b/vcl/inc/vcl/pdfwriter.hxx
@@ -0,0 +1,1298 @@
+/*************************************************************************
+ *
+ * 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_HXX
+#define _VCL_PDFWRITER_HXX
+
+#include <sal/types.h>
+
+#include <tools/gen.hxx>
+#include <tools/string.hxx>
+#include <tools/color.hxx>
+
+#include <vcl/dllapi.h>
+#include <vcl/vclenum.hxx>
+#include <vcl/font.hxx>
+#include <vcl/graphictools.hxx>
+
+#include <com/sun/star/io/XOutputStream.hpp>
+
+#include <list>
+#include <vector>
+#include <set>
+
+class Font;
+class Point;
+class OutputDevice;
+class MapMode;
+class Polygon;
+class LineInfo;
+class PolyPolygon;
+class Bitmap;
+class BitmapEx;
+class Image;
+class Gradient;
+class Hatch;
+class Wallpaper;
+
+namespace vcl
+{
+
+struct PDFDocInfo
+{
+ String Title; // document title
+ String Author; // document author
+ String Subject; // subject
+ String Keywords; // keywords
+ String Creator; // application that created the original document
+ String Producer; // OpenOffice
+};
+
+struct PDFNote
+{
+ String Title; // optional title for the popup containing the note
+ String Contents; // contents of the note
+};
+
+class VCL_DLLPUBLIC PDFOutputStream
+{
+ public:
+ virtual ~PDFOutputStream();
+ virtual void write( const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xStream ) = 0;
+};
+
+class VCL_DLLPUBLIC PDFWriter
+{
+ void* pImplementation;
+public:
+ // extended line info
+ enum CapType { capButt, capRound, capSquare };
+ enum JoinType { joinMiter, joinRound, joinBevel };
+ struct ExtLineInfo
+ {
+ double m_fLineWidth;
+ double m_fTransparency;
+ CapType m_eCap;
+ JoinType m_eJoin;
+ double m_fMiterLimit;
+ std::vector< double > m_aDashArray;
+
+ ExtLineInfo() : m_fLineWidth( 0.0 ),
+ m_fTransparency( 0.0 ),
+ m_eCap( capButt ),
+ m_eJoin( joinMiter ),
+ m_fMiterLimit( 10.0 )
+ {}
+ };
+
+ enum Orientation { Portrait, Landscape, Seascape, Inherit };
+
+ // in case the below enum is added PDF_1_6 PDF_1_7, please add them just after PDF_1_5
+ enum PDFVersion { PDF_1_2, PDF_1_3, PDF_1_4, PDF_1_5, PDF_A_1 };//i59651, PDF/A-1b & -1a, only -1b implemented for now
+ // for the meaning of DestAreaType please look at PDF Reference Manual
+ // version 1.4 section 8.2.1, page 475
+ enum DestAreaType { XYZ, Fit, FitHorizontal, FitVertical,
+ FitRectangle, FitPageBoundingBox, FitPageBoundingBoxHorizontal,
+ FitPageBoundingBoxVertical
+ };
+
+ // for a definition of structural element types please refer to
+ // PDF Reference, 3rd ed. section 9.7.4
+ enum StructElement
+ {
+ // special element to place outside the structure hierarchy
+ NonStructElement,
+ // Grouping elements
+ Document, Part, Article, Section, Division, BlockQuote,
+ Caption, TOC, TOCI, Index,
+
+ // block level elements
+ Paragraph, Heading, H1, H2, H3, H4, H5, H6,
+ List, ListItem, LILabel, LIBody,
+ Table, TableRow, TableHeader, TableData,
+
+ // inline level elements
+ Span, Quote, Note, Reference, BibEntry, Code, Link,
+
+ // illustration elements
+ Figure, Formula, Form
+ };
+
+ enum StructAttribute
+ {
+ Placement, WritingMode, SpaceBefore, SpaceAfter, StartIndent, EndIndent,
+ TextIndent, TextAlign, Width, Height, BlockAlign, InlineAlign,
+ LineHeight, BaselineShift, TextDecorationType, ListNumbering,
+ RowSpan, ColSpan,
+
+ // link destination is an artificial attribute that sets
+ // the link annotation ID of a Link element
+ // further note: since structure attributes can only be
+ // set during content creation, but links can be
+ // created after the fact, it is possible to set
+ // an arbitrary id as structure attribute here. In this
+ // case the arbitrary id has to be passed again when the
+ // actual link annotation is created via SetLinkPropertyID
+ LinkAnnotation,
+ // Language currently sets a LanguageType (see i18npool/lang.h)
+ // which will be internally changed to a corresponding locale
+ Language
+ };
+
+ enum StructAttributeValue
+ {
+ Invalid,
+ NONE,
+ // Placement
+ Block, Inline, Before, After, Start, End,
+ // WritingMode
+ LrTb, RlTb, TbRl,
+ // TextAlign
+ Center, Justify,
+ // Width, Height,
+ Auto,
+ // BlockAlign
+ Middle,
+ // LineHeight
+ Normal,
+ // TextDecorationType
+ Underline, Overline, LineThrough,
+ // ListNumbering
+ Disc, Circle, Square, Decimal, UpperRoman, LowerRoman, UpperAlpha, LowerAlpha
+ };
+
+ enum PageTransition
+ {
+ Regular,
+ SplitHorizontalInward, SplitHorizontalOutward,
+ SplitVerticalInward, SplitVerticalOutward,
+ BlindsHorizontal, BlindsVertical,
+ BoxInward, BoxOutward,
+ WipeLeftToRight, WipeBottomToTop, WipeRightToLeft, WipeTopToBottom,
+ Dissolve,
+ GlitterLeftToRight, GlitterTopToBottom, GlitterTopLeftToBottomRight
+ };
+
+ enum WidgetType
+ {
+ PushButton, RadioButton, CheckBox, Edit, ListBox, ComboBox, Hierarchy
+ };
+
+ enum WidgetState
+ {
+ // PushButton, RadioButton, CheckBox; Down means selected for
+ // RadioButton and CheckBox
+ Up, Down
+ };
+
+ enum ErrorCode
+ {
+ // transparent object occurred and was draw opaque because
+ // PDF/A does not allow transparency
+ Warning_Transparency_Omitted_PDFA,
+
+ // transparent object occured but is only supported since
+ // PDF 1.4
+ Warning_Transparency_Omitted_PDF13,
+
+ // a form action was exported that is not suitable for PDF/A
+ // the action was skipped
+ Warning_FormAction_Omitted_PDFA,
+
+ // transparent objects were converted to a bitmap in order
+ // to removetransparencies from the output
+ Warning_Transparency_Converted
+ };
+
+ struct VCL_DLLPUBLIC AnyWidget
+ {
+ protected:
+ WidgetType Type; // primitive RTTI
+ public:
+ rtl::OUString Name; // a distinct name to identify the control
+ rtl::OUString Description;// descriptive text for the contro (e.g. for tool tip)
+ rtl::OUString Text; // user text to appear on the control
+ USHORT TextStyle; // style flags
+ bool ReadOnly;
+ Rectangle Location; // describes the area filled by the control
+ bool Border; // true: widget should have a border, false: no border
+ Color BorderColor;// COL_TRANSPARENT and Border=true means get color from application settings
+ bool Background; // true: widget shall draw its background, false: no background
+ Color BackgroundColor; // COL_TRANSPARENT and Background=true means get color from application settings
+ Font TextFont; // an empty font will be replaced by the
+ // appropriate font from the user settings
+ Color TextColor; // COL_TRANSPARENT will be replaced by the appropriate color from application settings
+ sal_Int32 TabOrder; // lowest number is first in tab order
+
+ /* style flags for text are those for OutputDevice::DrawText
+ allowed values are:
+ TEXT_DRAW_LEFT, TEXT_DRAW_CENTER, TEXT_DRAW_RIGHT, TEXT_DRAW_TOP,
+ TEXT_DRAW_VCENTER, TEXT_DRAW_BOTTOM,
+ TEXT_DRAW_MULTILINE, TEXT_DRAW_WORDBREAK
+
+ if TextStyle is 0, then each control will fill in default values
+ */
+
+ // note: the Name member comprises the field name of the resulting
+ // PDF field names need to be globally unique. Therefore if any
+ // Widget with an already used name is created, the name will be
+ // made unique by adding an underscore ('_') and an ascending number
+ // to the name.
+
+ AnyWidget( WidgetType eType ) :
+ Type( eType ),
+ TextStyle( 0 ),
+ ReadOnly( false ),
+ Border( false ),
+ BorderColor( COL_TRANSPARENT ),
+ Background( false ),
+ BackgroundColor( COL_TRANSPARENT ),
+ TextColor( COL_TRANSPARENT ),
+ TabOrder( -1 )
+ {}
+ virtual ~AnyWidget();
+
+ WidgetType getType() const { return Type; }
+
+ virtual AnyWidget* Clone() const = 0;
+
+ protected:
+ // note that this equals the default compiler-generated copy-ctor, but we want to have it
+ // protected, to only allow sub classes to access it
+ AnyWidget( const AnyWidget& rSource )
+ :Type( rSource.Type )
+ ,Name( rSource.Name )
+ ,Description( rSource.Description )
+ ,Text( rSource.Text )
+ ,TextStyle( rSource.TextStyle )
+ ,ReadOnly( rSource.ReadOnly )
+ ,Location( rSource.Location )
+ ,Border( rSource.Border )
+ ,BorderColor( rSource.BorderColor )
+ ,Background( rSource.Background )
+ ,BackgroundColor( rSource.BackgroundColor )
+ ,TextFont( rSource.TextFont )
+ ,TextColor( rSource.TextColor )
+ ,TabOrder( rSource.TabOrder )
+ {
+ }
+ AnyWidget& operator=( const AnyWidget& ); // never implemented
+ };
+
+ struct PushButtonWidget : public AnyWidget
+ {
+ /* If Dest is set to a valid link destination,
+ Then pressing the button will act as a goto
+ action within the docuemnt.
+
+ Else:
+ An empty URL means this button will reset the form.
+
+ If URL is not empty and Submit is set, then the URL
+ contained will be set as the URL to submit the
+ form to. In this case the submit method will be
+ either GET if SubmitGet is true or POST if
+ SubmitGet is false.
+
+ If URL is not empty and Submit is clear, then
+ the URL contained will be interpreted as a
+ hyperlink to be executed on pushing the button.
+
+ There will be no error checking or any kind of
+ conversion done to the URL parameter execept this:
+ it will be output as 7bit Ascii. The URL
+ will appear literally in the PDF file produced
+ */
+ sal_Int32 Dest;
+ rtl::OUString URL;
+ bool Submit;
+ bool SubmitGet;
+
+ PushButtonWidget()
+ : AnyWidget( vcl::PDFWriter::PushButton ),
+ Dest( -1 ), Submit( false ), SubmitGet( false )
+ {}
+
+ virtual AnyWidget* Clone() const
+ {
+ return new PushButtonWidget( *this );
+ }
+ };
+
+ struct CheckBoxWidget : public AnyWidget
+ {
+ bool Checked;
+ bool ButtonIsLeft;
+
+ CheckBoxWidget()
+ : AnyWidget( vcl::PDFWriter::CheckBox ),
+ Checked( false ),
+ ButtonIsLeft( true )
+ {}
+
+ virtual AnyWidget* Clone() const
+ {
+ return new CheckBoxWidget( *this );
+ }
+ };
+
+ struct RadioButtonWidget : public AnyWidget
+ {
+ bool Selected;
+ sal_Int32 RadioGroup;
+ bool ButtonIsLeft;
+ rtl::OUString OnValue; // the value of the radio button if it is selected
+
+ RadioButtonWidget()
+ : AnyWidget( vcl::PDFWriter::RadioButton ),
+ Selected( false ),
+ RadioGroup( 0 ),
+ ButtonIsLeft( true )
+ {}
+
+ virtual AnyWidget* Clone() const
+ {
+ return new RadioButtonWidget( *this );
+ }
+ // radio buttons having the same RadioGroup id comprise one
+ // logical radio button group, that is at most one of the RadioButtons
+ // in a group can be checked at any time
+ //
+ // note: a PDF radio button field consists of a named field
+ // containing unnamed checkbox child fields. The name of the
+ // radio button field is taken from the first RadioButtonWidget created
+ // in the group
+ };
+
+ struct EditWidget : public AnyWidget
+ {
+ bool MultiLine; // whether multiple lines are allowed
+ bool Password; // visible echo off
+ bool FileSelect; // field is a file selector
+ sal_Int32 MaxLen; // maximum field length in characters, 0 means unlimited
+
+ EditWidget()
+ : AnyWidget( vcl::PDFWriter::Edit ),
+ MultiLine( false ),
+ Password( false ),
+ FileSelect( false ),
+ MaxLen( 0 )
+ {}
+
+ virtual AnyWidget* Clone() const
+ {
+ return new EditWidget( *this );
+ }
+ };
+
+ struct ListBoxWidget : public AnyWidget
+ {
+ bool DropDown;
+ bool Sort;
+ bool MultiSelect;
+ std::vector<rtl::OUString> Entries;
+ std::vector<sal_Int32> SelectedEntries;
+ // if MultiSelect is false only the first entry of SelectedEntries
+ // will be taken into account. the same is implicit for PDF < 1.4
+ // since multiselect is a 1.4+ feature
+
+ ListBoxWidget()
+ : AnyWidget( vcl::PDFWriter::ListBox ),
+ DropDown( false ),
+ Sort( false ),
+ MultiSelect( false )
+ {}
+
+ virtual AnyWidget* Clone() const
+ {
+ return new ListBoxWidget( *this );
+ }
+ };
+
+ // note: PDF only supports dropdown comboboxes
+ struct ComboBoxWidget : public AnyWidget
+ {
+ bool Sort;
+ std::vector<rtl::OUString> Entries;
+ // set the current value in AnyWidget::Text
+
+ ComboBoxWidget()
+ : AnyWidget( vcl::PDFWriter::ComboBox ),
+ Sort( false )
+ {}
+
+ virtual AnyWidget* Clone() const
+ {
+ return new ComboBoxWidget( *this );
+ }
+ };
+
+ enum ExportDataFormat { HTML, XML, FDF, PDF };
+// see 3.6.1 of PDF 1.4 ref for details, used for 8.1 PDF v 1.4 ref also
+// These emuns are treated as integer while reading/writing to configuration
+ enum PDFViewerPageMode
+ {
+ ModeDefault,
+ UseOutlines,
+ UseThumbs
+ };
+// These emuns are treated as integer while reading/writing to configuration
+ enum PDFViewerAction
+ {
+ ActionDefault,
+ FitInWindow,
+ FitWidth,
+ FitVisible,
+ ActionZoom
+ };
+// These emuns are treated as integer while reading/writing to configuration
+ enum PDFPageLayout
+ {
+ DefaultLayout,
+ SinglePage,
+ Continuous,
+ ContinuousFacing
+ };
+
+ // These emuns are treated as integer while reading/writing to configuration
+ //what default action to generate in a PDF hyperlink to external document/site
+ enum PDFLinkDefaultAction
+ {
+ URIAction,
+ URIActionDestination,
+ LaunchAction
+ };
+
+/*
+The following structure describes the permissions used in PDF security
+ */
+ struct PDFSecPermissions
+ {
+//for both 40 and 128 bit security, see 3.5.2 PDF v 1.4 table 3.15, v 1.5 and v 1.6 table 3.20.
+ bool CanPrintTheDocument;
+ bool CanModifyTheContent;
+ bool CanCopyOrExtract;
+ bool CanAddOrModify;
+//for revision 3 (bit 128 security) only
+ bool CanFillInteractive;
+ bool CanExtractForAccessibility;
+ bool CanAssemble;
+ bool CanPrintFull;
+//permission default set for 128 bit, accessibility only
+ PDFSecPermissions() :
+ CanPrintTheDocument ( false ),
+ CanModifyTheContent ( false ),
+ CanCopyOrExtract ( false ),
+ CanAddOrModify ( false ),
+ CanFillInteractive ( false ),
+ CanExtractForAccessibility ( true ),
+ CanAssemble ( false ),
+ CanPrintFull ( false )
+ {}
+ };
+
+ struct PDFWriterContext
+ {
+ /* must be a valid file: URL usable by osl */
+ rtl::OUString URL;
+ /* the URL of the document being exported, used for relative links*/
+ rtl::OUString BaseURL;
+ /*if relative to file system should be formed*/
+ bool RelFsys;//i56629, i49415?, i64585?
+ /*the action to set the PDF hyperlink to*/
+ PDFWriter::PDFLinkDefaultAction DefaultLinkAction;
+ //convert the .od? target file type in a link to a .pdf type
+ //this is examined before doing anything else
+ bool ConvertOOoTargetToPDFTarget;
+ //when the file type is .pdf, force the GoToR action
+ bool ForcePDFAction;
+
+ /* decides the PDF language level to be produced */
+ PDFVersion Version;
+ /* valid for PDF >= 1.4
+ causes the MarkInfo entry in the document catalog to be set
+ */
+ bool Tagged;
+ /* forces the embedding of PDF standard fonts */
+ bool EmbedStandardFonts;
+ /* determines in which format a form
+ will be submitted.
+ */
+ PDFWriter::ExportDataFormat SubmitFormat;
+ bool AllowDuplicateFieldNames;
+ bool FieldsUseSystemFonts;
+ /* the following data members are used to customize the PDF viewer
+ preferences
+ */
+ /* see 3.6.1 PDF v 1.4 ref*/
+ PDFWriter::PDFViewerPageMode PDFDocumentMode;
+ PDFWriter::PDFViewerAction PDFDocumentAction;
+ // in percent, valid only if PDFDocumentAction == ActionZoom
+ sal_Int32 Zoom;
+
+ /* see 8.6 PDF v 1.4 ref
+ specifies whether to hide the viewer tool
+ bars when the document is active.
+ */
+ bool HideViewerToolbar;
+ bool HideViewerMenubar;
+ bool HideViewerWindowControls;
+ bool FitWindow;
+ bool OpenInFullScreenMode;
+ bool CenterWindow;
+ bool DisplayPDFDocumentTitle;
+ PDFPageLayout PageLayout;
+ bool FirstPageLeft;
+ // intially visible page in viewer (starting with 0 for first page)
+ sal_Int32 InitialPage;
+ sal_Int32 OpenBookmarkLevels; // -1 means all levels
+
+ struct PDFSecPermissions AccessPermissions;
+
+ bool Encrypt; // main encryption flag, must be true to encript
+ bool Security128bit; // true to select 128 bit encryption, false for 40 bit
+ rtl::OUString OwnerPassword; // owner password for PDF, in clear text
+ rtl::OUString UserPassword; // user password for PDF, in clear text
+
+ com::sun::star::lang::Locale DocumentLocale; // defines the document default language
+
+ PDFWriterContext() :
+ RelFsys( false ), //i56629, i49415?, i64585?
+ DefaultLinkAction( PDFWriter::URIAction ),
+ ConvertOOoTargetToPDFTarget( false ),
+ ForcePDFAction( false ),
+ Version( PDFWriter::PDF_1_4 ),
+ Tagged( false ),
+ EmbedStandardFonts( false ),
+ SubmitFormat( PDFWriter::FDF ),
+ AllowDuplicateFieldNames( false ),
+ FieldsUseSystemFonts( true ),
+ PDFDocumentMode( PDFWriter::ModeDefault ),
+ PDFDocumentAction( PDFWriter::ActionDefault ),
+ Zoom( 100 ),
+ HideViewerToolbar( false ),
+ HideViewerMenubar( false ),
+ HideViewerWindowControls( false ),
+ FitWindow( false ),
+ OpenInFullScreenMode( false ),
+ CenterWindow( false ),
+ DisplayPDFDocumentTitle( true ),
+ PageLayout( PDFWriter::DefaultLayout ),
+ FirstPageLeft( false ),
+ InitialPage( 1 ),
+ OpenBookmarkLevels( -1 ),
+ AccessPermissions( ),
+ Encrypt( false ),
+ Security128bit( true )
+ {}
+ };
+
+ PDFWriter( const PDFWriterContext& rContext );
+ ~PDFWriter();
+
+ /** Returns an OutputDevice for formatting
+ <p>This Output device is guaranteed to use the same
+ font metrics as the resulting PDF file.</p>
+
+ @returns
+ the reference output device
+ */
+ OutputDevice* GetReferenceDevice();
+
+ /** Creates a new page to fill
+ <p>If width and height are not set the page size
+ is inherited from the page tree</p>
+ <p>other effects:
+ resets the graphics state: MapMode, Font
+ Colors and other state information MUST
+ be set again or are undefined.
+ </p>
+
+ @returns
+ returns the page id of the new page
+ */
+ sal_Int32 NewPage( sal_Int32 nPageWidth = 0, sal_Int32 nPageHeight = 0, Orientation eOrientation = Inherit );
+
+ /*
+ * set document info; due to the use of document information in building the PDF document ID, must be called before
+ * emitting anything.
+ */
+ void SetDocInfo( const PDFDocInfo& rInfo );
+
+ /*
+ * get currently set document info
+ */
+ const PDFDocInfo& GetDocInfo() const;
+
+ /* sets the document locale originally passed with the context to a new value
+ * only affects the output if used before calling <code>Emit/code>.
+ */
+ void SetDocumentLocale( const com::sun::star::lang::Locale& rDocLocale );
+
+ /* finishes the file */
+ bool Emit();
+
+ /*
+ * Get a list of errors that occured during processing
+ * this should enable the producer to give feedback about
+ * any anomalies that might have occured
+ */
+ std::set< ErrorCode > GetErrors();
+
+ PDFVersion GetVersion() const;
+
+ /* functions for graphics state */
+ /* flag values: see vcl/outdev.hxx */
+ void Push( USHORT nFlags = 0xffff );
+ void Pop();
+
+ void SetClipRegion();
+ void SetClipRegion( const basegfx::B2DPolyPolygon& rRegion );
+ void MoveClipRegion( long nHorzMove, long nVertMove );
+ void IntersectClipRegion( const Rectangle& rRect );
+ void IntersectClipRegion( const basegfx::B2DPolyPolygon& rRegion );
+
+ void SetAntialiasing( USHORT nMode = 0 );
+
+ void SetLayoutMode( ULONG nMode );
+ void SetDigitLanguage( LanguageType eLang );
+
+ void SetLineColor( const Color& rColor );
+ void SetLineColor() { SetLineColor( Color( COL_TRANSPARENT ) ); }
+
+ void SetFillColor( const Color& rColor );
+ void SetFillColor() { SetFillColor( Color( COL_TRANSPARENT ) ); }
+
+ void SetFont( const Font& rNewFont );
+ void SetTextColor( const Color& rColor );
+ void SetTextFillColor();
+ void SetTextFillColor( const Color& rColor );
+
+ void SetTextLineColor();
+ void SetTextLineColor( const Color& rColor );
+ void SetOverlineColor();
+ void SetOverlineColor( const Color& rColor );
+ void SetTextAlign( ::TextAlign eAlign );
+
+ void SetMapMode();
+ void SetMapMode( const MapMode& rNewMapMode );
+
+
+ /* actual drawing functions */
+ void DrawText( const Point& rPos, const String& rText );
+
+ void DrawTextLine( const Point& rPos, long nWidth,
+ FontStrikeout eStrikeout,
+ FontUnderline eUnderline,
+ FontUnderline eOverline,
+ BOOL bUnderlineAbove = FALSE );
+ void DrawTextArray( const Point& rStartPt, const XubString& rStr,
+ const sal_Int32* pDXAry = NULL,
+ xub_StrLen nIndex = 0,
+ xub_StrLen nLen = STRING_LEN );
+ void DrawStretchText( const Point& rStartPt, ULONG nWidth,
+ const XubString& rStr,
+ xub_StrLen nIndex = 0, xub_StrLen nLen = STRING_LEN );
+ void DrawText( const Rectangle& rRect,
+ const XubString& rStr, USHORT nStyle = 0 );
+
+ void DrawPixel( const Point& rPt, const Color& rColor );
+ void DrawPixel( const Point& rPt )
+ { DrawPixel( rPt, Color( COL_TRANSPARENT ) ); }
+ void DrawPixel( const Polygon& rPts, const Color* pColors = NULL );
+ void DrawPixel( const Polygon& rPts, const Color& rColor )
+ { Push(); SetLineColor( rColor ); DrawPixel( rPts ); Pop(); }
+
+ void DrawLine( const Point& rStartPt, const Point& rEndPt );
+ void DrawLine( const Point& rStartPt, const Point& rEndPt,
+ const LineInfo& rLineInfo );
+ void DrawPolyLine( const Polygon& rPoly );
+ void DrawPolyLine( const Polygon& rPoly,
+ const LineInfo& rLineInfo );
+ void DrawPolyLine( const Polygon& rPoly, const ExtLineInfo& rInfo );
+ void DrawPolygon( const Polygon& rPoly );
+ void DrawPolyPolygon( const PolyPolygon& rPolyPoly );
+ void DrawRect( const Rectangle& rRect );
+ void DrawRect( const Rectangle& rRect,
+ ULONG nHorzRount, ULONG nVertRound );
+ void DrawEllipse( const Rectangle& rRect );
+ void DrawArc( const Rectangle& rRect,
+ const Point& rStartPt, const Point& rEndPt );
+ void DrawPie( const Rectangle& rRect,
+ const Point& rStartPt, const Point& rEndPt );
+ void DrawChord( const Rectangle& rRect,
+ const Point& rStartPt, const Point& rEndPt );
+
+ void DrawBitmap( const Point& rDestPt,
+ const Bitmap& rBitmap );
+ void DrawBitmap( const Point& rDestPt, const Size& rDestSize,
+ const Bitmap& rBitmap );
+ void DrawBitmap( const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPtPixel, const Size& rSrcSizePixel,
+ const Bitmap& rBitmap );
+
+ void DrawBitmapEx( const Point& rDestPt,
+ const BitmapEx& rBitmapEx );
+ void DrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
+ const BitmapEx& rBitmapEx );
+ void DrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPtPixel, const Size& rSrcSizePixel,
+ const BitmapEx& rBitmapEx );
+
+ void DrawMask( const Point& rDestPt,
+ const Bitmap& rBitmap, const Color& rMaskColor );
+ void DrawMask( const Point& rDestPt, const Size& rDestSize,
+ const Bitmap& rBitmap, const Color& rMaskColor );
+ void DrawMask( const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPtPixel, const Size& rSrcSizePixel,
+ const Bitmap& rBitmap, const Color& rMaskColor );
+
+ 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& rWallpaper );
+ void DrawTransparent( const PolyPolygon& rPolyPoly,
+ USHORT nTransparencePercent );
+
+ /** Start a transparency group
+
+ Drawing operations can be grouped together to acquire a common transparency
+ behaviour; after calling <code>BeginTransparencyGroup</code> all drawing
+ operations will be grouped together into a transparent object.
+
+ The transparency behaviour is set with ond of the <code>EndTransparencyGroup</code>
+ calls and can be either a constant transparency factor or a transparent
+ soft mask in form of an 8 bit gray scale bitmap.
+
+ It is permissible to nest transparency group.
+
+ Transparency groups MUST NOT span multiple pages
+
+ Transparency is a feature introduced in PDF1.4, so transparency group
+ will be ignored if the produced PDF has a lower version. The drawing
+ operations will be emitted normally.
+ */
+ void BeginTransparencyGroup();
+
+ /** End a transparency group with constant transparency factor
+
+ This ends a transparency group and inserts it on the current page. The
+ coordinates of the group result out of the grouped drawing operations.
+
+ @param rBoundRect
+ The bounding rectangle of the group
+
+ @param nTransparencePercent
+ The transparency factor
+ */
+ void EndTransparencyGroup( const Rectangle& rBoundRect, USHORT nTransparencePercent );
+
+ /** End a transparency group with an alpha mask
+
+ This ends a transparency group and inserts it on the current page. The
+ coordinates of the group result out of the grouped drawing operations.
+
+ @param rBoundRect
+ The bounding rectangle of the group
+
+ @param rAlphaMask
+ The transparency mask; must be an 8 bit grayscale image
+ */
+ void EndTransparencyGroup( const Rectangle& rBoundRect, const Bitmap& rAlphaMask );
+
+ /** Insert a JPG encoded image (optionally with mask)
+
+ @param rJPGData
+ a Stream containing the encoded image
+
+ @param bIsTrueColor
+ true: jpeg is 24 bit true color, false: jpeg is 8 bit greyscale
+
+ @param rSrcSizePixel
+ size in pixel of the image
+
+ @param rTargetArea
+ where to put the image
+
+ @param rMask
+ optional mask; if not empty it must have
+ the same pixel size as the image and
+ be either 1 bit black&white or 8 bit grey
+ */
+ void DrawJPGBitmap( SvStream& rJPGData, bool bIsTrueColor, const Size& rSrcSizePixel, const Rectangle& rTargetArea, const Bitmap& rMask );
+
+ /** Create a new named destination to be used in a link from another PDF document
+
+ @parm sDestName
+ the name (label) of the bookmark, to be used to jump to
+
+ @param rRect
+ target rectangle on page to be displayed if dest is jumped to
+
+ @param nPageNr
+ number of page the dest is on (as returned by NewPage)
+ or -1 in which case the current page is used
+
+ @param eType
+ what dest type to use
+
+ @returns
+ the destination id (to be used in SetLinkDest) or
+ -1 if page id does not exist
+ */
+ sal_Int32 CreateNamedDest( const rtl::OUString& sDestName, const Rectangle& rRect, sal_Int32 nPageNr = -1, DestAreaType eType = XYZ );
+ /** Create a new destination to be used in a link
+
+ @param rRect
+ target rectangle on page to be displayed if dest is jumped to
+
+ @param nPageNr
+ number of page the dest is on (as returned by NewPage)
+ or -1 in which case the current page is used
+
+ @param eType
+ what dest type to use
+
+ @returns
+ the destination id (to be used in SetLinkDest) or
+ -1 if page id does not exist
+ */
+ sal_Int32 CreateDest( const Rectangle& rRect, sal_Int32 nPageNr = -1, DestAreaType eType = XYZ );
+ /** Create a new link on a page
+
+ @param rRect
+ active rectangle of the link (that is the area that has to be
+ hit to activate the link)
+
+ @param nPageNr
+ number of page the link is on (as returned by NewPage)
+ or -1 in which case the current page is used
+
+ @returns
+ the link id (to be used in SetLinkDest, SetLinkURL) or
+ -1 if page id does not exist
+ */
+ sal_Int32 CreateLink( const Rectangle& rRect, sal_Int32 nPageNr = -1 );
+ /** Set the destination for a link
+ <p>will change a URL type link to a dest link if necessary</p>
+
+ @param nLinkId
+ the link to be changed
+
+ @param nDestId
+ the dest the link shall point to
+ @returns
+ 0 for success
+ -1 in case the link id does not exist
+ -2 in case the dest id does not exist
+ */
+ sal_Int32 SetLinkDest( sal_Int32 nLinkId, sal_Int32 nDestId );
+ /** Set the URL for a link
+ <p>will change a dest type link to an URL type link if necessary</p>
+ @param nLinkId
+ the link to be changed
+
+ @param rURL
+ the URL the link shall point to.
+ The URL will be parsed (and corrected) by the <code>com.sun.star.util.URLTransformer</code>
+ service; the result will then appear literally in the PDF file produced
+
+ @returns
+ 0 for success
+ -1 in case the link id does not exist
+ */
+ sal_Int32 SetLinkURL( sal_Int32 nLinkId, const rtl::OUString& rURL );
+ /** Resolve link in logical structure
+ <p>
+ If a link is created after the corresponding visual appearance was drawn
+ it is not possible to set the link id as a property attribute to the
+ link structure item that should be created in tagged PDF around the
+ visual appearance of a link.
+ </p>
+ <p>
+ For this reason an arbitrary id can be given to
+ <code>SetStructureAttributeNumerical</code> at the time the text for
+ the link is drawn. To resolve this arbitrary id again when the actual
+ link annotation is created use SetLinkPropertyID. When <code>Emit</code>
+ finally gets called all <code>LinkAnnotation</code> type structure attributes
+ will be replaced with the correct link id.
+ </p>
+ <p>
+ CAUTION: this technique must be used either for all or none of the links
+ in a document since the link id space and arbitrary property id space
+ could overlap and it would be impossible to resolve whether a <code>Link</code>
+ structure attribute value was arbitrary or already a real id.
+ </p>
+
+ @param nLinkId
+ the link to be mapped
+
+ @param nPropertyID
+ the arbitrary id set in a <code>Link</code> structure element to address
+ the link with real id <code>nLinkId</code>
+ */
+ void SetLinkPropertyID( sal_Int32 nLinkId, sal_Int32 nPropertyID );
+ /** Create a new outline item
+
+ @param nParent
+ declares the parent of the new item in the outline hierarchy.
+ An invalid value will result in a new toplevel item.
+
+ @param rText
+ sets the title text of the item
+
+ @param nDestId
+ declares which Dest (created with CreateDest) the outline item
+ will point to
+
+ @returns
+ the outline item id of the new item
+ */
+ sal_Int32 CreateOutlineItem( sal_Int32 nParent = 0, const rtl::OUString& rText = rtl::OUString(), sal_Int32 nDestID = -1 );
+
+ /** Set an outline item's parent
+
+ @param nItem
+ specififies which item should be reparented.
+
+ @param nNewParent
+ specifies which outline item will be the item's new parent.
+ Use 0 for reparenting to top level.
+
+ @returns
+ -1 if the item does not exist
+ -2 if the new parent does not exist, item will be reparented to top level.
+ */
+ sal_Int32 SetOutlineItemParent( sal_Int32 nItem, sal_Int32 nNewParent );
+
+ /** Set an outline item's title text
+
+ @param nItem
+ specififies which item should get a new text
+
+ @param rText
+ sets the title text of the item
+
+ @returns
+ 0 if the item exists and the text was changed
+ -1 if the item does not exist
+ */
+ sal_Int32 SetOutlineItemText( sal_Int32 nItem, const rtl::OUString& rText );
+
+ /** Set an outline item's destination
+
+ @param nItem
+ specififies which item should get a new dest
+
+ @param nDestID
+ specifies the item's new destination
+
+ @returns
+ -1 if the item does not exist
+ -2 if the new dest does not exist, dest will remain unchanged
+ */
+ sal_Int32 SetOutlineItemDest( sal_Int32 nItem, sal_Int32 nDestID );
+
+ /** Create a new note on a page
+
+ @param rRect
+ active rectangle of the note (that is the area that has to be
+ hit to popup the annotation)
+
+ @param rNote
+ specifies the contents of the note
+
+ @param nPageNr
+ number of page the note is on (as returned by NewPage)
+ or -1 in which case the current page is used
+ */
+ void CreateNote( const Rectangle& rRect, const PDFNote& rNote, sal_Int32 nPageNr = -1 );
+
+ /** begin a new logical structure element
+
+ <p>
+ BeginStructureElement/EndStructureElement calls build the logical structure
+ of the PDF - the basis for tagged PDF. Structural elements are implemented
+ using marked content tags. Each structural element can contain sub elements
+ (e.g. a section can contain a heading and a paragraph). The structure hierarchy
+ is build automatically from the Begin/EndStructureElement calls.
+
+ A structural element need not be contained on one page; e.g. paragraphs often
+ run from one page to the next. In this case the corresponding EndStructureElement
+ must be called while drawing the next page.
+ </p>
+
+ <p>
+ BeginStructureElement and EndStructureElement must be called only after
+ <member scope="vcl">PDFWriter::NewPage</member> has been called and before
+ <member scope="vcl">PDFWriter::Emit</member>gets called. The current page
+ number is an implicit context parameter for Begin/EndStructureElement.
+ </p>
+
+ <p>
+ For pagination artifacts that are not part of the logical structure
+ of the document (like header, footer or page number) the special
+ StructElement <code>NonStructElement</code> exists. To place content
+ outside of the struture tree simply call
+ <code>BeginStructureElement( NonStructElement )</code> then draw your
+ content and then call <code>EndStructureElement()</code>. All children
+ of a <code>NonStructElement</code> will not be part of the structure.
+ Nonetheless if you add a child structural element to a
+ <code>NonStructElement</code> you will still have to call
+ <code>EndStructureElement</code> for it. Best think of the structure
+ tree as a stack.
+ </p>
+
+ <p>
+ Note: there is always one structural element in existance without having
+ called <code>BeginStructureElement</code>; this is the root of the structure
+ tree (called StructTreeRoot). The StructTreeRoot has always the id 0.
+ </p>
+
+ @param eType
+ denotes what kind of element to begin (e.g. a heading or paragraph)
+
+ @param rAlias
+ the specified alias will be used as structure tag. Also an entry in the PDF's
+ role map will be created mapping alias to regular structure type.
+
+ @returns
+ the new structure element's id for use in <code>SetCurrentStructureElement</code>
+ */
+ sal_Int32 BeginStructureElement( enum StructElement eType, const rtl::OUString& rAlias = rtl::OUString() );
+ /** end the current logical structure element
+
+ <p>
+ Close the current structure element. The current element's
+ parent becomes the current structure element again.
+ </p>
+
+ @see BeginStructureElement
+ */
+ void EndStructureElement();
+ /** set the current structure element
+
+ <p>
+ For different purposes it may be useful to paint a structure element's
+ content discontinously. In that case an already existing structure element
+ can be appended to by using <code>SetCurrentStructureElement</code>. The
+ refenrenced structure element becomes the current structure element with
+ all consequences: all following structure elements are appended as children
+ of the current element.
+ </p>
+
+ @param nElement
+ the id of the new current structure element
+
+ @returns
+ <true/> if the current structure element could be set successfully
+ <false/> if the current structure element could not be changed
+ (e.g. if the passed element id is invalid)
+ */
+ bool SetCurrentStructureElement( sal_Int32 nElement );
+ /** get the current structure element's id
+
+ @returns
+ the id of the current structure element or -1 if no structure exists
+ (e.g. if no tagged PDF is being produced)
+ */
+ sal_Int32 GetCurrentStructureElement();
+
+ /** set a structure attribute on the current structural element
+
+ SetStructureAttribute sets an attribute of the current structural element to a
+ new value. A consistency check is performed before actually setting the value;
+ if the check fails, the function returns <FALSE/> and the attribute remains
+ unchanged.
+
+ @param eAttr
+ denotes what attribute to change
+
+ @param eVal
+ the value to set the attribute to
+
+ @returns
+ <TRUE/> if the value was valid and the change has been performed,
+ <FALSE/> if the attribute or value was invalid; attribute remains unchanged
+ */
+ bool SetStructureAttribute( enum StructAttribute eAttr, enum StructAttributeValue eVal );
+ /** set a structure attribute on the current structural element
+
+ SetStructureAttributeNumerical sets an attribute of the current structural element
+ to a new numerical value. A consistency check is performed before actually setting
+ the value; if the check fails, the function returns <FALSE/> and the attribute
+ remains unchanged.
+
+ @param eAttr
+ denotes what attribute to change
+
+ @param nValue
+ the value to set the attribute to
+
+ @returns
+ <TRUE/> if the value was valid and the change has been performed,
+ <FALSE/> if the attribute or value was invalid; attribute remains unchanged
+ */
+ bool SetStructureAttributeNumerical( enum StructAttribute eAttr, sal_Int32 nValue );
+ /** set the bounding box of a structural element
+
+ SetStructureBoundingBox sets the BBox attribute to a new value. Since the BBox
+ attribute can only be applied to <code>Table</code>, <code>Figure</code>,
+ <code>Form</code> and <code>Formula</code> elements, a call of this function
+ for other element types will be ignored and the BBox attribute not be set.
+
+ @param rRect
+ the new bounding box for the structural element
+ */
+ void SetStructureBoundingBox( const Rectangle& rRect );
+
+ /** set the ActualText attribute of a structural element
+
+ ActualText contains the Unicode text without layout artifacts that is shown by
+ a structural element. For example if a line is ended prematurely with a break in
+ a word and continued on the next line (e.g. "happen-<newline>stance") the
+ corresponding ActualText would contain the unbroken line (e.g. "happenstance").
+
+ @param rText
+ contains the complete logical text the structural element displays.
+ */
+ void SetActualText( const String& rText );
+
+ /** set the Alt attribute of a strutural element
+
+ Alt is s replacement text describing the contents of a structural element. This
+ is mainly used by accessibility applications; e.g. a screen reader would read
+ the Alt replacement text for an image to a visually impaired user.
+
+ @param rText
+ contains the replacement text for the structural element
+ */
+ void SetAlternateText( const String& rText );
+
+ /** Sets the time in seconds a page will appear before the next
+ page is shown automatically
+
+ @param nSeconds
+ time in seconds the current page will be shown; pass 0 for manual advancement
+
+ @param nPageNr
+ the page number to apply the autoadvance time to; -1 denotes the current page
+ */
+ void SetAutoAdvanceTime( sal_uInt32 nSeconds, sal_Int32 nPageNr = -1 );
+
+ /** Sets the transitional effect to be applied when the current page gets shown.
+
+ @param eType
+ the kind of effect to be used; use Regular to disable transitional effects
+ for this page
+
+ @param nMilliSec
+ the duration of the transitional effect in milliseconds;
+ set 0 to disable transitional effects
+
+ @param nPageNr
+ the page number to apply the effect to; -1 denotes the current page
+ */
+ void SetPageTransition( PageTransition eType, sal_uInt32 nMilliSec, sal_Int32 nPageNr = -1 );
+
+ /** create a new form control
+
+ This function creates a new form control in the PDF and sets its various
+ properties. Do not pass an actual AnyWidget as <code>rControlType</code>
+ will be cast to the type described by the type member.
+
+ @param rControlType
+ a descendant of <code>AnyWidget</code> determing the control's properties
+
+ @returns
+ the new control's id for reference purposes
+ */
+ sal_Int32 CreateControl( const AnyWidget& rControlType, sal_Int32 nPageNr = -1 );
+
+ /** Inserts an additional stream to the PDF file
+
+ This function adds an arbitrary stream to the produced PDF file. May be called
+ any time before <code>Emit()</code>. The stream will be written during
+ <code>Emit</code> by calling the <code>PDFOutputStream</code> Object's <code>write</code>
+ method. After the call the <code>PDFOutputStream</code> will be deleted.
+
+ All additional streams and their mimetypes will be entered into an array
+ in the trailer dictionary.
+
+ @param rMimeType
+ the mimetype of the stream
+
+ @param rStream
+ the interface to the additional stream
+
+ @param bCompress
+ specifies whether the stream should be flate encoded by PDFWriter or not
+ */
+ void AddStream( const String& rMimeType, PDFOutputStream* pStream, bool bCompress );
+
+ /** create a new pattern for filling operations
+
+ This function creates a new pattern to be used for subsequent filling operations.
+ A pattern can consist of arbitrary drawing operations; all drawing operations
+ between <code>BeingPattern()</code> and <code>EndPattern()</code> calls
+ will be recorded and considered as forming up the pattern.
+
+ @param rCellBounds
+ a rectangle defining the "cell" that will be repeated to form the pattern
+ */
+ void BeginPattern( const Rectangle& );
+ /** finish a new pattern for filling operations
+
+ This functions finishes the pattern create begun with <code>BeginPattern()</code>
+ and returns a pattern id to be used in subsequent drawing operations.
+
+ @param rMatrix
+ a transformation to be imposed on the drawing operations that make up the pattern
+
+ @returns
+ the new pattern's id
+ */
+ sal_Int32 EndPattern( const SvtGraphicFill::Transform& rTransformation );
+ /** draw a polypolygon filled with a pattern
+
+ @param rPolyPoly
+ PolyPolygon to filled
+
+ @param nPatternId
+ the pattern previously obtained in the <code>EndPattern</code> call.
+
+ @param bEOFill
+ true: polypolygon gets filled with EvenOdd method,
+ false: polypolygon gets filled with nonzero winding method
+ */
+ void DrawPolyPolygon( const PolyPolygon& rPolyPoly, sal_Int32 nPatternId, bool bEOFill );
+};
+
+}
+
+#endif // _VCL_PDFWRITER_HXX
diff --git a/vcl/inc/vcl/pngread.hxx b/vcl/inc/vcl/pngread.hxx
new file mode 100644
index 000000000000..d2879f8f182a
--- /dev/null
+++ b/vcl/inc/vcl/pngread.hxx
@@ -0,0 +1,70 @@
+/*************************************************************************
+ *
+ * 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_PNGREAD_HXX
+#define _SV_PNGREAD_HXX
+
+#include <vcl/dllapi.h>
+#include <vcl/bitmapex.hxx>
+#include <vector>
+
+// -------------
+// - PNGReader -
+// -------------
+
+namespace vcl
+{
+ class PNGReaderImpl;
+
+ class VCL_DLLPUBLIC PNGReader
+ {
+ PNGReaderImpl* mpImpl;
+
+ public:
+
+ /* the PNG chunks are read within the c'tor, so the stream will
+ be positioned at the end of the PNG */
+ PNGReader( SvStream& rStm );
+ ~PNGReader();
+
+ /* an empty preview size hint (=default) will read the whole image
+ */
+ BitmapEx Read( const Size& i_rPreviewHint = Size() );
+
+ // retrieve every chunk that resides inside the PNG
+ struct ChunkData
+ {
+ sal_uInt32 nType;
+ std::vector< sal_uInt8 > aData;
+ };
+ const std::vector< ChunkData >& GetChunks() const;
+
+ void SetIgnoreGammaChunk( sal_Bool b );
+ };
+}
+
+#endif // _SV_PNGREAD_HXX
diff --git a/vcl/inc/vcl/pngwrite.hxx b/vcl/inc/vcl/pngwrite.hxx
new file mode 100644
index 000000000000..38ca97a8c931
--- /dev/null
+++ b/vcl/inc/vcl/pngwrite.hxx
@@ -0,0 +1,67 @@
+/*************************************************************************
+ *
+ * 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_PNGWRITE_HXX
+#define _SV_PNGWRITE_HXX
+
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <vcl/dllapi.h>
+#include <vcl/bitmapex.hxx>
+#include <vector>
+
+// -------------
+// - PNGWriter -
+// -------------
+
+namespace vcl
+{
+ class PNGWriterImpl;
+
+ class VCL_DLLPUBLIC PNGWriter
+ {
+ PNGWriterImpl* mpImpl;
+
+ public:
+
+ PNGWriter( const BitmapEx& BmpEx,
+ const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData = NULL );
+ ~PNGWriter();
+
+ sal_Bool Write( SvStream& rStm );
+
+ // additional method to be able to modify all chunk before they are stored
+ struct ChunkData
+ {
+ sal_uInt32 nType;
+ std::vector< sal_uInt8 > aData;
+ };
+ std::vector< vcl::PNGWriter::ChunkData >& GetChunks();
+ };
+}
+
+#endif // _SV_PNGWRITE_HXX
diff --git a/vcl/inc/vcl/pointr.hxx b/vcl/inc/vcl/pointr.hxx
new file mode 100644
index 000000000000..b90b3b04d134
--- /dev/null
+++ b/vcl/inc/vcl/pointr.hxx
@@ -0,0 +1,59 @@
+/*************************************************************************
+ *
+ * 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_POINTR_HXX
+#define _VCL_POINTR_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/ptrstyle.hxx>
+
+class Point;
+
+// -----------
+// - Pointer -
+// -----------
+
+class VCL_DLLPUBLIC Pointer
+{
+ PointerStyle meStyle;
+
+public:
+ Pointer()
+ { meStyle = POINTER_ARROW; }
+ Pointer( PointerStyle eStyle )
+ { meStyle = eStyle; }
+
+ PointerStyle GetStyle() const { return meStyle; }
+
+ BOOL operator==( const Pointer& rPointer ) const
+ { return (meStyle == rPointer.meStyle); }
+ BOOL operator!=( const Pointer& rPointer ) const
+ { return !(Pointer::operator==( rPointer )); }
+};
+
+#endif // _VCL_POINTR_HXX
diff --git a/vcl/inc/vcl/polyscan.hxx b/vcl/inc/vcl/polyscan.hxx
new file mode 100644
index 000000000000..1c699e36623d
--- /dev/null
+++ b/vcl/inc/vcl/polyscan.hxx
@@ -0,0 +1,155 @@
+/*************************************************************************
+ *
+ * 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_POLYSCAN_HXX
+#define _SV_POLYSCAN_HXX
+
+#include <tools/gen.hxx>
+
+// -----------------
+// - ScanlinePoint -
+// -----------------
+
+struct ScanlinePoint
+{
+ long mnX;
+ ScanlinePoint* mpNext;
+
+ ScanlinePoint() : mnX( 0L ), mpNext( NULL ) {};
+ ScanlinePoint( long nX, ScanlinePoint* pNext ) : mnX( nX ), mpNext( pNext ) {};
+ ~ScanlinePoint() {};
+
+ void Set( long nX, ScanlinePoint* pNext ) { mnX = nX, mpNext = pNext; }
+};
+
+// -------------------
+// - PolyScanSegment -
+// -------------------
+
+struct PolyScanSegment
+{
+ long mnStart;
+ long mnEnd;
+
+ PolyScanSegment() : mnStart( 0L ), mnEnd( 0L ) {};
+ PolyScanSegment( long nStart, long nEnd ) : mnStart( nStart ), mnEnd( nEnd ) {};
+ ~PolyScanSegment() {};
+};
+
+// ----------------
+// - PolyScanline -
+// ----------------
+
+struct ScanlinePoint;
+class Polygon;
+class PolyPolygon;
+
+class PolyScanline
+{
+private:
+
+ ScanlinePoint* mpFirst;
+ ScanlinePoint* mpLast;
+ ScanlinePoint* mpAct;
+ long mnLeft;
+ long mnRight;
+
+ void ImplDelete();
+
+public:
+
+ PolyScanline();
+ ~PolyScanline();
+
+ void Insert( long nX );
+ void Set( long nStart, long nEnd );
+ void Set( const PolyScanSegment& rSegment ) { Set( rSegment.mnStart, rSegment.mnEnd ); }
+
+ inline BOOL GetFirstX( long& rX );
+ inline BOOL GetNextX( long& rX );
+
+ BOOL GetFirstSegment( PolyScanSegment& rSegment );
+ BOOL GetNextSegment( PolyScanSegment& rSegment );
+};
+
+// ------------------------------------------------------------------------
+
+inline BOOL PolyScanline::GetFirstX( long& rX )
+{
+ mpAct = mpFirst;
+ return( mpAct ? ( rX = mpAct->mnX, mpAct = mpAct->mpNext, TRUE ) : FALSE );
+}
+
+// ------------------------------------------------------------------------
+
+inline BOOL PolyScanline::GetNextX( long& rX )
+{
+ return( mpAct ? ( rX = mpAct->mnX, mpAct = mpAct->mpNext, TRUE ) : FALSE );
+}
+
+// ---------------
+// - PolyScanner -
+// ---------------
+
+class PolyScanner
+{
+private:
+
+ PolyScanline* mpArray;
+ long mnLeft;
+ long mnTop;
+ long mnRight;
+ long mnBottom;
+
+ PolyScanner() {};
+
+protected:
+
+ void InsertLine( const Point& rStart, const Point& rEnd );
+
+public:
+
+ PolyScanner( const Rectangle& rRect );
+ PolyScanner( const Polygon& rPoly );
+ PolyScanner( const PolyPolygon& rPolyPoly );
+ ~PolyScanner();
+
+ long Left() const { return mnLeft; }
+ long Top() const { return mnTop; }
+ long Right() const { return mnRight; }
+ long Bottom() const { return mnBottom; }
+
+ long Width() const { return( mnRight - mnLeft + 1L ); }
+ long Height() const { return( mnBottom - mnTop + 1L ); }
+
+ Rectangle GetBoundRect() const { return Rectangle( mnLeft, mnTop, mnRight, mnBottom ); }
+
+ ULONG Count() const { return Height(); }
+ PolyScanline* operator[]( ULONG nPos ) const;
+};
+
+#endif // _SV_POLYSCAN_HXX
diff --git a/vcl/inc/vcl/popupmenuwindow.hxx b/vcl/inc/vcl/popupmenuwindow.hxx
new file mode 100644
index 000000000000..5ed794ff56ca
--- /dev/null
+++ b/vcl/inc/vcl/popupmenuwindow.hxx
@@ -0,0 +1,47 @@
+/*************************************************************************
+ *
+ * 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 __POPUPMENUWINDOW_HXX__
+#define __POPUPMENUWINDOW_HXX__
+
+#include "vcl/floatwin.hxx"
+
+class VCL_DLLPUBLIC PopupMenuFloatingWindow : public FloatingWindow
+{
+private:
+ struct ImplData;
+ ImplData* mpImplData;
+public:
+ PopupMenuFloatingWindow( Window* pParent, WinBits nStyle = (WB_SYSTEMFLOATWIN|WB_SYSTEMWINDOW|WB_NOBORDER) );
+ ~PopupMenuFloatingWindow();
+
+ sal_uInt16 GetMenuStackLevel() const;
+ void SetMenuStackLevel( sal_uInt16 nLevel );
+ bool IsPopupMenu() const;
+};
+
+#endif
diff --git a/vcl/inc/vcl/ppdparser.hxx b/vcl/inc/vcl/ppdparser.hxx
new file mode 100644
index 000000000000..c7a1e09b81e4
--- /dev/null
+++ b/vcl/inc/vcl/ppdparser.hxx
@@ -0,0 +1,343 @@
+/*************************************************************************
+ *
+ * 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 _PSPRINT_PPDPARSER_HXX_
+#define _PSPRINT_PPDPARSER_HXX_
+
+#include <list>
+#include <vector>
+#include <hash_map>
+
+#include "tools/string.hxx"
+#include "tools/stream.hxx"
+
+#include "com/sun/star/lang/Locale.hpp"
+
+#define PRINTER_PPDDIR "driver"
+
+namespace psp {
+
+class PPDParser;
+class PPDTranslator;
+
+enum PPDValueType { eInvocation, eQuoted, eSymbol, eString, eNo };
+
+struct PPDValue
+{
+ PPDValueType m_eType;
+ String m_aOption;
+ String m_aValue;
+};
+
+// ----------------------------------------------------------------------
+
+/*
+ * PPDKey - a container for the available options (=values) of a PPD keyword
+ */
+
+class PPDKey
+{
+ friend class PPDParser;
+
+ typedef ::std::hash_map< ::rtl::OUString, PPDValue, ::rtl::OUStringHash > hash_type;
+ typedef ::std::vector< PPDValue* > value_type;
+
+ String m_aKey;
+ hash_type m_aValues;
+ value_type m_aOrderedValues;
+ const PPDValue* m_pDefaultValue;
+ bool m_bQueryValue;
+ PPDValue m_aQueryValue;
+
+public:
+ enum UIType { PickOne, PickMany, Boolean };
+ enum SetupType { ExitServer, Prolog, DocumentSetup, PageSetup, JCLSetup, AnySetup };
+private:
+
+ bool m_bUIOption;
+ UIType m_eUIType;
+ int m_nOrderDependency;
+ SetupType m_eSetupType;
+
+ void eraseValue( const String& rOption );
+public:
+ PPDKey( const String& rKey );
+ ~PPDKey();
+
+ PPDValue* insertValue( const String& rOption );
+ int countValues() const
+ { return m_aValues.size(); }
+ // neither getValue will return the query option
+ const PPDValue* getValue( int n ) const;
+ const PPDValue* getValue( const String& rOption ) const;
+ const PPDValue* getValueCaseInsensitive( const String& rOption ) const;
+ const PPDValue* getDefaultValue() const { return m_pDefaultValue; }
+ const PPDValue* getQueryValue() const { return m_bQueryValue ? &m_aQueryValue : NULL; }
+
+ const String& getKey() const { return m_aKey; }
+ bool isUIKey() const { return m_bUIOption; }
+ UIType getUIType() const { return m_eUIType; }
+ SetupType getSetupType() const { return m_eSetupType; }
+ int getOrderDependency() const { return m_nOrderDependency; }
+};
+
+// define a hash for PPDKey
+struct PPDKeyhash
+{
+ size_t operator()( const PPDKey * pKey) const
+ { return (size_t)pKey; }
+};
+
+// ----------------------------------------------------------------------
+
+/*
+ * PPDParser - parses a PPD file and contains all available keys from it
+ */
+
+class PPDContext;
+class CUPSManager;
+
+class PPDParser
+{
+ friend class PPDContext;
+ friend class CUPSManager;
+
+ typedef ::std::hash_map< ::rtl::OUString, PPDKey*, ::rtl::OUStringHash > hash_type;
+ typedef ::std::vector< PPDKey* > value_type;
+
+ void insertKey( const String& rKey, PPDKey* pKey );
+public:
+ struct PPDConstraint
+ {
+ const PPDKey* m_pKey1;
+ const PPDValue* m_pOption1;
+ const PPDKey* m_pKey2;
+ const PPDValue* m_pOption2;
+
+ PPDConstraint() : m_pKey1( NULL ), m_pOption1( NULL ), m_pKey2( NULL ), m_pOption2( NULL ) {}
+ };
+private:
+
+ static ::std::list< PPDParser* > aAllParsers;
+ static ::std::hash_map< rtl::OUString, rtl::OUString, rtl::OUStringHash >*
+ pAllPPDFiles;
+
+ hash_type m_aKeys;
+ value_type m_aOrderedKeys;
+ ::std::list< PPDConstraint > m_aConstraints;
+
+ // some identifying fields
+ String m_aPrinterName;
+ String m_aNickName;
+ // the full path of the PPD file
+ String m_aFile;
+ // some basic attributes
+ bool m_bColorDevice;
+ bool m_bType42Capable;
+ ULONG m_nLanguageLevel;
+ rtl_TextEncoding m_aFileEncoding;
+
+
+ // shortcuts to important keys and their default values
+ // imageable area
+ const PPDValue* m_pDefaultImageableArea;
+ const PPDKey* m_pImageableAreas;
+ // paper dimensions
+ const PPDValue* m_pDefaultPaperDimension;
+ const PPDKey* m_pPaperDimensions;
+ // paper trays
+ const PPDValue* m_pDefaultInputSlot;
+ const PPDKey* m_pInputSlots;
+ // resolutions
+ const PPDValue* m_pDefaultResolution;
+ const PPDKey* m_pResolutions;
+ // duplex commands
+ const PPDValue* m_pDefaultDuplexType;
+ const PPDKey* m_pDuplexTypes;
+
+ // fonts
+ const PPDKey* m_pFontList;
+
+ // translations
+ PPDTranslator* m_pTranslator;
+
+ PPDParser( const String& rFile );
+ ~PPDParser();
+
+ void parseOrderDependency( const ByteString& rLine );
+ void parseOpenUI( const ByteString& rLine );
+ void parseConstraint( const ByteString& rLine );
+ void parse( std::list< ByteString >& rLines );
+
+ String handleTranslation( const ByteString& i_rString, bool i_bIsGlobalized );
+
+ static void scanPPDDir( const String& rDir );
+ static void initPPDFiles();
+ static String getPPDFile( const String& rFile );
+public:
+ static const PPDParser* getParser( const String& rFile );
+ static String getPPDPrinterName( const String& rFile );
+ static void freeAll();
+ static void getKnownPPDDrivers( std::list< rtl::OUString >& o_rDrivers, bool bRefresh = false );
+
+ const String& getFilename() const { return m_aFile; }
+
+ const PPDKey* getKey( int n ) const;
+ const PPDKey* getKey( const String& rKey ) const;
+ int getKeys() const { return m_aKeys.size(); }
+ bool hasKey( const PPDKey* ) const;
+
+ const ::std::list< PPDConstraint >& getConstraints() const { return m_aConstraints; }
+
+ const String& getPrinterName() const
+ { return m_aPrinterName.Len() ? m_aPrinterName : m_aNickName; }
+ const String& getNickName() const
+ { return m_aNickName.Len() ? m_aNickName : m_aPrinterName; }
+
+ bool isColorDevice() const { return m_bColorDevice; }
+ bool isType42Capable() const { return m_bType42Capable; }
+ ULONG getLanguageLevel() const { return m_nLanguageLevel; }
+
+ String getDefaultPaperDimension() const;
+ void getDefaultPaperDimension( int& rWidth, int& rHeight ) const
+ { getPaperDimension( getDefaultPaperDimension(), rWidth, rHeight ); }
+ bool getPaperDimension( const String& rPaperName,
+ int& rWidth, int& rHeight ) const;
+ // width and height in pt
+ // returns false if paper not found
+ int getPaperDimensions() const
+ { return m_pPaperDimensions ? m_pPaperDimensions->countValues() : 0; }
+ String getPaperDimension( int ) const;
+ String getPaperDimensionCommand( int ) const;
+ String getPaperDimensionCommand( const String & ) const;
+
+ // match the best paper for width and height
+ String matchPaper( int nWidth, int nHeight ) const;
+
+ bool getMargins( const String& rPaperName,
+ int &rLeft, int& rRight,
+ int &rUpper, int& rLower ) const;
+ // values in pt
+ // returns true if paper found
+
+ // values int pt
+
+ String getDefaultInputSlot() const;
+ int getInputSlots() const
+ { return m_pInputSlots ? m_pInputSlots->countValues() : 0; }
+ String getSlot( int ) const;
+ String getSlotCommand( int ) const;
+ String getSlotCommand( const String& ) const;
+
+ void getDefaultResolution( int& rXRes, int& rYRes ) const;
+ int getResolutions() const;
+ void getResolution( int, int& rXRes, int& rYRes ) const;
+ String getResolutionCommand( int nXRes, int nYRes ) const;
+ // values in dpi
+ void getResolutionFromString( const String&, int&, int& ) const;
+ // helper function
+
+ String getDefaultDuplexType() const;
+ int getDuplexTypes() const
+ { return m_pDuplexTypes ? m_pDuplexTypes->countValues() : 0; }
+ String getDuplex( int ) const;
+ String getDuplexCommand( int ) const;
+ String getDuplexCommand( const String& ) const;
+
+ int getFonts() const
+ { return m_pFontList ? m_pFontList->countValues() : 0; }
+ void getFontAttributes( int,
+ String& rEncoding,
+ String& rCharset ) const;
+ void getFontAttributes( const String&,
+ String& rEncoding,
+ String& rCharset ) const;
+ String getFont( int ) const;
+
+
+ rtl::OUString translateKey( const rtl::OUString& i_rKey,
+ const com::sun::star::lang::Locale& i_rLocale = com::sun::star::lang::Locale() ) const;
+ rtl::OUString translateOption( const rtl::OUString& i_rKey,
+ const rtl::OUString& i_rOption,
+ const com::sun::star::lang::Locale& i_rLocale = com::sun::star::lang::Locale() ) const;
+ rtl::OUString translateValue( const rtl::OUString& i_rKey,
+ const rtl::OUString& i_rOption,
+ const rtl::OUString& i_rValue,
+ const com::sun::star::lang::Locale& i_rLocale = com::sun::star::lang::Locale() ) const;
+};
+
+// ----------------------------------------------------------------------
+
+/*
+ * PPDContext - a class to manage user definable states based on the
+ * contents of a PPDParser.
+ */
+
+class PPDContext
+{
+ typedef ::std::hash_map< const PPDKey*, const PPDValue*, PPDKeyhash > hash_type;
+ hash_type m_aCurrentValues;
+ const PPDParser* m_pParser;
+
+ // returns false: check failed, new value is constrained
+ // true: check succeded, new value can be set
+ bool checkConstraints( const PPDKey*, const PPDValue*, bool bDoReset );
+ bool resetValue( const PPDKey*, bool bDefaultable = false );
+public:
+ PPDContext( const PPDParser* pParser = NULL );
+ PPDContext( const PPDContext& rContext ) { operator=( rContext ); }
+ PPDContext& operator=( const PPDContext& rContext );
+ ~PPDContext();
+
+ void setParser( const PPDParser* );
+ const PPDParser* getParser() const { return m_pParser; }
+
+ const PPDValue* getValue( const PPDKey* ) const;
+ const PPDValue* setValue( const PPDKey*, const PPDValue*, bool bDontCareForConstraints = false );
+
+ int countValuesModified() const { return m_aCurrentValues.size(); }
+ const PPDKey* getModifiedKey( int n ) const;
+
+ // public wrapper for the private method
+ bool checkConstraints( const PPDKey*, const PPDValue* );
+
+ void getUnconstrainedValues( const PPDKey*, ::std::list< const PPDValue* >& rValues );
+
+ // for printer setup
+ void* getStreamableBuffer( ULONG& rBytes ) const;
+ void rebuildFromStreamBuffer( void* pBuffer, ULONG nBytes );
+
+ // convenience
+ int getRenderResolution() const;
+
+ // width, height in points, paper will contain the name of the selected
+ // paper after the call
+ void getPageSize( String& rPaper, int& rWidth, int& rHeight ) const;
+};
+
+} // namespace
+
+#endif // _PSPRINT_PPDPARSER_HXX_
diff --git a/vcl/inc/vcl/print.h b/vcl/inc/vcl/print.h
new file mode 100644
index 000000000000..78c1bb647575
--- /dev/null
+++ b/vcl/inc/vcl/print.h
@@ -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 _SV_PRINT_H
+#define _SV_PRINT_H
+
+#include "vcl/sv.h"
+#include "vcl/dllapi.h"
+
+#include <vector>
+#include <hash_map>
+
+struct SalPrinterQueueInfo;
+class QueueInfo;
+class JobSetup;
+
+namespace vcl
+{ class PrinterListener; }
+
+// --------------------
+// - ImplPrnQueueData -
+// --------------------
+
+struct ImplPrnQueueData
+{
+ QueueInfo* mpQueueInfo;
+ SalPrinterQueueInfo* mpSalQueueInfo;
+};
+
+// --------------------
+// - ImplPrnQueueList -
+// --------------------
+
+class VCL_DLLPUBLIC ImplPrnQueueList
+{
+public:
+ std::hash_map< rtl::OUString, sal_Int32, rtl::OUStringHash >
+ m_aNameToIndex;
+ std::vector< ImplPrnQueueData > m_aQueueInfos;
+ std::vector< rtl::OUString > m_aPrinterList;
+
+ ImplPrnQueueList() {}
+ ~ImplPrnQueueList();
+
+ void Add( SalPrinterQueueInfo* pData );
+ ImplPrnQueueData* Get( const rtl::OUString& rPrinter );
+};
+
+// --------------
+// - Prototypes -
+// --------------
+
+void ImplDeletePrnQueueList();
+void SAL_DLLPRIVATE ImplUpdateJobSetupPaper( JobSetup& rJobSetup );
+
+
+#endif // _SV_PRINT_H
diff --git a/vcl/inc/vcl/print.hxx b/vcl/inc/vcl/print.hxx
new file mode 100644
index 000000000000..96822d9bc756
--- /dev/null
+++ b/vcl/inc/vcl/print.hxx
@@ -0,0 +1,679 @@
+/*************************************************************************
+ *
+ * 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_PRINT_HXX
+#define _SV_PRINT_HXX
+
+#include "tools/errcode.hxx"
+#include "vcl/sv.h"
+#include "vcl/dllapi.h"
+#include "vcl/outdev.hxx"
+#include "vcl/prntypes.hxx"
+#include "vcl/jobset.hxx"
+#include "vcl/gdimtf.hxx"
+#include "tools/stream.hxx"
+#include "tools/multisel.hxx"
+
+#include "com/sun/star/beans/PropertyValue.hpp"
+#include "com/sun/star/view/PrintableState.hpp"
+
+#include <boost/shared_ptr.hpp>
+#include <hash_map>
+#include <set>
+
+struct SalPrinterInfoQueue;
+class SalInfoPrinter;
+struct SalPrinterQueueInfo;
+class SalPrinter;
+class VirtualDevice;
+class Window;
+
+namespace vcl {
+ class PrinterController;
+ class PrintDialog;
+}
+
+// -----------------
+// - Printer-Types -
+// -----------------
+
+#define PAGEQUEUE_ALLPAGES 0xFFFF
+
+enum PrinterSupport { SUPPORT_SET_ORIENTATION, SUPPORT_SET_PAPERBIN,
+ SUPPORT_SET_PAPERSIZE, SUPPORT_SET_PAPER,
+ SUPPORT_COPY, SUPPORT_COLLATECOPY,
+ SUPPORT_SETUPDIALOG, SUPPORT_FAX, SUPPORT_PDF };
+
+// ---------------
+// - PrinterPage -
+// ---------------
+
+class VCL_DLLPUBLIC PrinterPage
+{
+ GDIMetaFile* mpMtf;
+ JobSetup maJobSetup;
+ UINT16 mbNewJobSetup;
+
+public:
+
+ PrinterPage() : mpMtf( new GDIMetaFile() ) {}
+ PrinterPage( GDIMetaFile* pMtf, BOOL bNewJobSetup, const JobSetup& rSetup ) :
+ mpMtf( pMtf ), maJobSetup( rSetup ), mbNewJobSetup( bNewJobSetup ) {}
+ ~PrinterPage() { delete mpMtf; }
+
+ GDIMetaFile* GetGDIMetaFile() const { return mpMtf; }
+ const JobSetup& GetJobSetup() const { return maJobSetup; }
+ BOOL IsNewJobSetup() const { return (mbNewJobSetup != 0); }
+
+ friend VCL_DLLPUBLIC SvStream& operator<<( SvStream& rOStm, const PrinterPage& rPage )
+ { rOStm << rPage.mbNewJobSetup; rOStm << rPage.maJobSetup; rPage.mpMtf->Write( rOStm ); return rOStm; }
+ friend VCL_DLLPUBLIC SvStream& operator>>( SvStream& rIStm, PrinterPage& rPage )
+ { return rIStm >> rPage.mbNewJobSetup >> rPage.maJobSetup >> *rPage.mpMtf; }
+};
+
+
+// -------------
+// - QueueInfo -
+// -------------
+
+class VCL_DLLPUBLIC QueueInfo
+{
+ friend class Printer;
+
+private:
+ XubString maPrinterName;
+ XubString maDriver;
+ XubString maLocation;
+ XubString maComment;
+ sal_uInt32 mnStatus;
+ sal_uInt32 mnJobs;
+
+public:
+ QueueInfo();
+ QueueInfo( const QueueInfo& rInfo );
+ ~QueueInfo();
+
+ const XubString& GetPrinterName() const { return maPrinterName; }
+ const XubString& GetDriver() const { return maDriver; }
+ const XubString& GetLocation() const { return maLocation; }
+ const XubString& GetComment() const { return maComment; }
+ sal_uInt32 GetStatus() const { return mnStatus; }
+ sal_uInt32 GetJobs() const { return mnJobs; }
+
+ bool operator==( const QueueInfo& rInfo ) const;
+
+ friend VCL_DLLPUBLIC SvStream& operator>>( SvStream& rIStream, QueueInfo& rInfo );
+ friend VCL_DLLPUBLIC SvStream& operator<<( SvStream& rOStream, const QueueInfo& rInfo );
+};
+
+// ------------------
+// - PrinterOptions -
+// ------------------
+
+enum PrinterTransparencyMode
+{
+ PRINTER_TRANSPARENCY_AUTO = 0,
+ PRINTER_TRANSPARENCY_NONE = 1
+};
+
+// -----------------------------------------------------------------------------
+
+enum PrinterGradientMode
+{
+ PRINTER_GRADIENT_STRIPES = 0,
+ PRINTER_GRADIENT_COLOR = 1
+};
+
+// -----------------------------------------------------------------------------
+
+enum PrinterBitmapMode
+{
+ PRINTER_BITMAP_OPTIMAL = 0,
+ PRINTER_BITMAP_NORMAL = 1,
+ PRINTER_BITMAP_RESOLUTION = 2
+};
+
+// -----------------------------------------------------------------------------
+
+class VCL_DLLPUBLIC PrinterOptions
+{
+private:
+
+ BOOL mbReduceTransparency;
+ PrinterTransparencyMode meReducedTransparencyMode;
+ BOOL mbReduceGradients;
+ PrinterGradientMode meReducedGradientsMode;
+ USHORT mnReducedGradientStepCount;
+ BOOL mbReduceBitmaps;
+ PrinterBitmapMode meReducedBitmapMode;
+ USHORT mnReducedBitmapResolution;
+ BOOL mbReducedBitmapsIncludeTransparency;
+ BOOL mbConvertToGreyscales;
+
+public:
+
+ PrinterOptions();
+ ~PrinterOptions();
+
+ BOOL IsReduceTransparency() const { return mbReduceTransparency; }
+ void SetReduceTransparency( BOOL bSet ) { mbReduceTransparency = bSet; }
+
+ PrinterTransparencyMode GetReducedTransparencyMode() const { return meReducedTransparencyMode; }
+ void SetReducedTransparencyMode( PrinterTransparencyMode eMode ) { meReducedTransparencyMode = eMode; }
+
+ BOOL IsReduceGradients() const { return mbReduceGradients; }
+ void SetReduceGradients( BOOL bSet ) { mbReduceGradients = bSet; }
+
+ PrinterGradientMode GetReducedGradientMode() const { return meReducedGradientsMode; }
+ void SetReducedGradientMode( PrinterGradientMode eMode ) { meReducedGradientsMode = eMode; }
+
+ USHORT GetReducedGradientStepCount() const { return mnReducedGradientStepCount; }
+ void SetReducedGradientStepCount( USHORT nStepCount ) { mnReducedGradientStepCount = nStepCount; }
+
+ BOOL IsReduceBitmaps() const { return mbReduceBitmaps; }
+ void SetReduceBitmaps( BOOL bSet ) { mbReduceBitmaps = bSet; }
+
+ PrinterBitmapMode GetReducedBitmapMode() const { return meReducedBitmapMode; }
+ void SetReducedBitmapMode( PrinterBitmapMode eMode ) { meReducedBitmapMode = eMode; }
+
+ USHORT GetReducedBitmapResolution() const { return mnReducedBitmapResolution; }
+ void SetReducedBitmapResolution( USHORT nResolution ) { mnReducedBitmapResolution = nResolution; }
+
+ BOOL IsReducedBitmapIncludesTransparency() const { return mbReducedBitmapsIncludeTransparency; }
+ void SetReducedBitmapIncludesTransparency( BOOL bSet ) { mbReducedBitmapsIncludeTransparency = bSet; }
+
+ BOOL IsConvertToGreyscales() const { return mbConvertToGreyscales; }
+ void SetConvertToGreyscales( BOOL bSet ) { mbConvertToGreyscales = bSet; }
+};
+
+// -----------
+// - Printer -
+// -----------
+
+class VCL_DLLPUBLIC Printer : public OutputDevice
+{
+ friend class OutputDevice;
+ friend class ImplQPrinter;
+
+private:
+ SalInfoPrinter* mpInfoPrinter;
+ SalPrinter* mpPrinter;
+ SalGraphics* mpJobGraphics;
+ Printer* mpPrev;
+ Printer* mpNext;
+ VirtualDevice* mpDisplayDev;
+ PrinterOptions* mpPrinterOptions;
+ XubString maPrinterName;
+ XubString maDriver;
+ XubString maPrintFile;
+ XubString maJobName;
+ JobSetup maJobSetup;
+ Point maPageOffset;
+ Size maPaperSize;
+ ULONG mnError;
+ USHORT mnCurPage;
+ USHORT mnCurPrintPage;
+ USHORT mnPageQueueSize;
+ USHORT mnCopyCount;
+ BOOL mbDefPrinter;
+ BOOL mbPrinting;
+ BOOL mbJobActive;
+ BOOL mbCollateCopy;
+ BOOL mbPrintFile;
+ BOOL mbInPrintPage;
+ BOOL mbNewJobSetup;
+ BOOL mbIsQueuePrinter;
+ BOOL mbUserSetupCompleted;
+ BOOL mbUserSetupResult;
+ Link maErrorHdl;
+
+ SAL_DLLPRIVATE void ImplInitData();
+ SAL_DLLPRIVATE void ImplInit( SalPrinterQueueInfo* pInfo );
+ SAL_DLLPRIVATE void ImplInitDisplay( const Window* pWindow );
+ SAL_DLLPRIVATE static SalPrinterQueueInfo* ImplGetQueueInfo( const XubString& rPrinterName,
+ const XubString* pDriver );
+ SAL_DLLPRIVATE void ImplUpdatePageData();
+ SAL_DLLPRIVATE void ImplUpdateFontList();
+ SAL_DLLPRIVATE void ImplFindPaperFormatForUserSize( JobSetup&, bool bMatchNearest );
+ DECL_DLLPRIVATE_LINK( ImplDestroyPrinterAsync, void* );
+
+ SAL_DLLPRIVATE bool StartJob( const rtl::OUString& rJobName, boost::shared_ptr<vcl::PrinterController>& );
+
+ static SAL_DLLPRIVATE ULONG ImplSalPrinterErrorCodeToVCL( ULONG nError );
+
+private:
+ SAL_DLLPRIVATE void ImplEndPrint();
+ SAL_DLLPRIVATE BOOL EndJob();
+ SAL_DLLPRIVATE Printer( const Printer& rPrinter );
+ SAL_DLLPRIVATE Printer& operator =( const Printer& rPrinter );
+public:
+ SAL_DLLPRIVATE void ImplStartPage();
+ SAL_DLLPRIVATE void ImplEndPage();
+public:
+ void DrawGradientEx( OutputDevice* pOut, const Rectangle& rRect, const Gradient& rGradient );
+ void DrawGradientEx( OutputDevice* pOut, const PolyPolygon& rPolyPoly, const Gradient& rGradient );
+
+protected:
+
+ void SetSelfAsQueuePrinter( BOOL bQueuePrinter ) { mbIsQueuePrinter = bQueuePrinter; }
+ BOOL IsQueuePrinter() const { return mbIsQueuePrinter; }
+
+public:
+ Printer();
+ Printer( const Window* pWindow );
+ Printer( const JobSetup& rJobSetup );
+ Printer( const QueueInfo& rQueueInfo );
+ Printer( const XubString& rPrinterName );
+ virtual ~Printer();
+
+ static const std::vector< rtl::OUString >& GetPrinterQueues();
+ static const QueueInfo* GetQueueInfo( const String& rPrinterName, bool bStatusUpdate );
+ static XubString GetDefaultPrinterName();
+
+ virtual void Error();
+
+ const XubString& GetName() const { return maPrinterName; }
+ const XubString& GetDriverName() const { return maDriver; }
+ BOOL IsDefPrinter() const { return mbDefPrinter; }
+ BOOL IsDisplayPrinter() const { return mpDisplayDev != NULL; }
+ BOOL IsValid() const { return !IsDisplayPrinter(); }
+
+ ULONG GetCapabilities( USHORT nType ) const;
+ BOOL HasSupport( PrinterSupport eFeature ) const;
+
+ BOOL SetJobSetup( const JobSetup& rSetup );
+ const JobSetup& GetJobSetup() const { return maJobSetup; }
+ String GetJobValue( const String& rKey ) const { return maJobSetup.GetValue( rKey ); }
+ void SetJobValue( const String& rKey, const String& rValue ) { maJobSetup.SetValue( rKey, rValue ); }
+
+ BOOL Setup( Window* pWindow = NULL );
+ BOOL SetPrinterProps( const Printer* pPrinter );
+
+ void SetPrinterOptions( const PrinterOptions& rOptions ) { *mpPrinterOptions = rOptions; }
+ const PrinterOptions& GetPrinterOptions() const { return( *mpPrinterOptions ); }
+
+ BOOL SetOrientation( Orientation eOrient );
+ Orientation GetOrientation() const;
+ DuplexMode GetDuplexMode() const;
+ BOOL SetDuplexMode( DuplexMode );
+ // returns the angle that a landscape page will be turned counterclockwise
+ // wrt to portrait. The return value may be only valid for
+ // the current paper
+ int GetLandscapeAngle() const;
+ BOOL SetPaperBin( USHORT nPaperBin );
+ USHORT GetPaperBin() const;
+ BOOL SetPaper( Paper ePaper );
+ BOOL SetPaperSizeUser( const Size& rSize );
+ BOOL SetPaperSizeUser( const Size& rSize, bool bMatchNearest );
+ Paper GetPaper() const;
+
+ // returns number of available paper formats
+ int GetPaperInfoCount() const;
+ // returns info about paper format nPaper
+ const PaperInfo& GetPaperInfo( int nPaper ) const;
+ USHORT GetPaperBinCount() const;
+ XubString GetPaperBinName( USHORT nPaperBin ) const;
+
+ const Size& GetPaperSizePixel() const { return maPaperSize; }
+ Size GetPaperSize() const { return PixelToLogic( maPaperSize ); }
+ const Point& GetPageOffsetPixel() const { return maPageOffset; }
+ Point GetPageOffset() const { return PixelToLogic( maPageOffset ); }
+
+ BOOL SetCopyCount( USHORT nCopy, BOOL bCollate = FALSE );
+ USHORT GetCopyCount() const { return mnCopyCount; }
+ BOOL IsCollateCopy() const { return mbCollateCopy; }
+
+ BOOL IsPrinting() const { return mbPrinting; }
+
+ void SetPrintFile( const XubString& rFileName ) { maPrintFile = rFileName; }
+ const XubString& GetPrintFile() const { return maPrintFile; }
+ void EnablePrintFile( BOOL bEnable ) { mbPrintFile = bEnable; }
+ BOOL IsPrintFileEnabled() const { return mbPrintFile; }
+ BOOL AbortJob();
+ const XubString& GetCurJobName() const { return maJobName; }
+ USHORT GetCurPage() const { return mnCurPage; }
+ BOOL IsJobActive() const { return mbJobActive; }
+
+ ULONG GetError() const { return ERRCODE_TOERROR(mnError); }
+ ULONG GetErrorCode() const { return mnError; }
+
+ void SetErrorHdl( const Link& rLink ) { maErrorHdl = rLink; }
+ const Link& GetErrorHdl() const { return maErrorHdl; }
+
+ void Compat_OldPrinterMetrics( bool bSet );
+
+ /** checks the printer list and updates it necessary
+ *
+ * sends a DataChanged event of type DATACHANGED_PRINTER
+ * if the printer list changed
+ */
+ static void updatePrinters();
+
+ /** execute a print job
+
+ starts a print job asynchronously (that is will return
+
+ */
+ static void PrintJob( const boost::shared_ptr<vcl::PrinterController>& i_pController,
+ const JobSetup& i_rInitSetup
+ );
+
+ // implementation detail of PrintJob being asynchronous
+ // not exported, not usable outside vcl
+ static void SAL_DLLPRIVATE ImplPrintJob( const boost::shared_ptr<vcl::PrinterController>& i_pController,
+ const JobSetup& i_rInitSetup
+ );
+};
+
+namespace vcl
+{
+class ImplPrinterControllerData;
+
+class VCL_DLLPUBLIC PrinterController
+{
+ ImplPrinterControllerData* mpImplData;
+protected:
+ PrinterController( const boost::shared_ptr<Printer>& );
+public:
+ enum NupOrderType
+ { LRTB, TBLR };
+ struct MultiPageSetup
+ {
+ // all metrics in 100th mm
+ int nRows;
+ int nColumns;
+ int nRepeat;
+ Size aPaperSize;
+ long nLeftMargin;
+ long nTopMargin;
+ long nRightMargin;
+ long nBottomMargin;
+ long nHorizontalSpacing;
+ long nVerticalSpacing;
+ bool bDrawBorder;
+ PrinterController::NupOrderType nOrder;
+
+ MultiPageSetup()
+ : nRows( 1 ), nColumns( 1 ), nRepeat( 1 ), aPaperSize( 21000, 29700 )
+ , nLeftMargin( 0 ), nTopMargin( 0 )
+ , nRightMargin( 0 ), nBottomMargin( 0 )
+ , nHorizontalSpacing( 0 ), nVerticalSpacing( 0 )
+ , bDrawBorder( false )
+ , nOrder( LRTB )
+ {
+ }
+ };
+
+ struct PageSize
+ {
+ Size aSize; // in 100th mm
+ bool bFullPaper; // full paper, not only imageable area is printed
+
+ PageSize( const Size& i_rSize = Size( 21000, 29700 ),
+ bool i_bFullPaper = false
+ ) : aSize( i_rSize ), bFullPaper( i_bFullPaper ) {}
+ };
+
+ PrinterController();
+ virtual ~PrinterController();
+
+ const boost::shared_ptr<Printer>& getPrinter() const;
+ /* for implementations: get current job properties as changed by e.g. print dialog
+ this gets the current set of properties initially told to Printer::PrintJob
+
+ For convenience a second sequence will be merged in to get a combined sequence.
+ In case of duplicate property names, the value of i_MergeList wins.
+ */
+ com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >
+ getJobProperties( const com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >& i_rMergeList ) const;
+
+ /* get the PropertyValue of a Property
+ */
+ com::sun::star::beans::PropertyValue* getValue( const rtl::OUString& i_rPropertyName );
+ const com::sun::star::beans::PropertyValue* getValue( const rtl::OUString& i_rPropertyName ) const;
+ // get a sequence of properties
+ com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue > getValues( const com::sun::star::uno::Sequence< rtl::OUString >& ) const;
+ /* get a bool property
+ in case the property is unknown or not convertible to bool, i_bFallback is returned
+ */
+ sal_Bool getBoolProperty( const rtl::OUString& i_rPropertyName, sal_Bool i_bFallback ) const;
+
+ /* set a property value - can also be used to add another UI property
+ */
+ void setValue( const rtl::OUString& i_rPropertyName, const com::sun::star::uno::Any& i_rValue );
+ void setValue( const com::sun::star::beans::PropertyValue& i_rValue );
+
+ /* return the currently active UI options. These are the same that were passed to setUIOptions.
+ */
+ const com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >& getUIOptions() const;
+ /* set possible UI options. should only be done once before passing the PrinterListener
+ to Printer::PrintJob
+ */
+ void setUIOptions( const com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >& );
+ /* enable/disable an option; this can be used to implement dialog logic.
+ */
+ void enableUIOption( const rtl::OUString& rPropName, bool bEnable );
+ bool isUIOptionEnabled( const rtl::OUString& rPropName ) const;
+ /* returns the property name rPropName depends on or an empty string
+ if no dependency exists.
+ */
+ rtl::OUString getDependency( const rtl::OUString& rPropName ) const;
+ /* makeEnabled will chage the property rPropName depends on to the value
+ that makes rPropName enabled. If the dependency itself is also disabled,
+ no action will be performed.
+
+ returns the property name rPropName depends on or an empty string
+ if no change was made.
+ */
+ rtl::OUString makeEnabled( const rtl::OUString& rPropName );
+
+ virtual int getPageCount() const = 0; // must be overloaded by the app
+ /* get the page parameters, namely the jobsetup that should be active for the page
+ (describing among others the physical page size) and the "page size". In writer
+ case this would probably be the same as the JobSetup since writer sets the page size
+ draw/impress for example print their page on the paper set on the printer,
+ possibly adjusting the page size to fit. That means the page size can be different from
+ the paper size.
+ */
+ // must be overloaded by the app, return page size in 1/100th mm
+ virtual com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue > getPageParameters( int i_nPage ) const = 0;
+ virtual void printPage( int i_nPage ) const = 0; // must be overloaded by the app
+ virtual void jobStarted(); // will be called after a possible dialog has been shown and the real printjob starts
+ virtual void jobFinished( com::sun::star::view::PrintableState );
+
+ com::sun::star::view::PrintableState getJobState() const;
+
+ void abortJob();
+
+ bool isShowDialogs() const;
+ bool isDirectPrint() const;
+
+ // implementation details, not usable outside vcl
+ SAL_DLLPRIVATE int getFilteredPageCount();
+ SAL_DLLPRIVATE PageSize getPageFile( int i_inUnfilteredPage, GDIMetaFile& rMtf, bool i_bMayUseCache = false );
+ SAL_DLLPRIVATE PageSize getFilteredPageFile( int i_nFilteredPage, GDIMetaFile& o_rMtf, bool i_bMayUseCache = false );
+ SAL_DLLPRIVATE void printFilteredPage( int i_nPage );
+ SAL_DLLPRIVATE void setPrinter( const boost::shared_ptr<Printer>& );
+ SAL_DLLPRIVATE void setOptionChangeHdl( const Link& );
+ SAL_DLLPRIVATE void createProgressDialog();
+ SAL_DLLPRIVATE void setMultipage( const MultiPageSetup& );
+ SAL_DLLPRIVATE const MultiPageSetup& getMultipage() const;
+ SAL_DLLPRIVATE void setLastPage( sal_Bool i_bLastPage );
+ SAL_DLLPRIVATE void setReversePrint( sal_Bool i_bReverse );
+ SAL_DLLPRIVATE bool getReversePrint() const;
+ SAL_DLLPRIVATE void pushPropertiesToPrinter();
+ SAL_DLLPRIVATE void setJobState( com::sun::star::view::PrintableState );
+ SAL_DLLPRIVATE bool setupPrinter( Window* i_pDlgParent );
+
+ SAL_DLLPRIVATE int getPageCountProtected() const;
+ SAL_DLLPRIVATE com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue > getPageParametersProtected( int i_nPage ) const;
+
+ SAL_DLLPRIVATE ULONG removeTransparencies( GDIMetaFile& i_rIn, GDIMetaFile& o_rOut );
+};
+
+class VCL_DLLPUBLIC PrinterOptionsHelper
+{
+ protected:
+ std::hash_map< rtl::OUString, com::sun::star::uno::Any, rtl::OUStringHash > m_aPropertyMap;
+ com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue > m_aUIProperties;
+
+ public:
+ PrinterOptionsHelper() {} // create without ui properties
+ PrinterOptionsHelper( const com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >& i_rUIProperties )
+ : m_aUIProperties( i_rUIProperties )
+ {}
+ ~PrinterOptionsHelper()
+ {}
+
+ /* process a new set of properties
+ * merges changed properties and returns "true" if any occured
+ * if the optional output set is not NULL then the names of the changed properties are returned
+ **/
+ bool processProperties( const com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >& i_rNewProp,
+ std::set< rtl::OUString >* o_pChangeProp = NULL );
+ /* append to a sequence of property values the ui property sequence passed at creation
+ * as the "ExtraPrintUIOptions" property. if that sequence was empty, no "ExtraPrintUIOptions" property
+ * will be appended.
+ **/
+ void appendPrintUIOptions( com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >& io_rProps ) const;
+
+ // check if a property exists
+ bool hasProperty( const rtl::OUString& i_rPropertyName ) const;
+ bool hasProperty( const char* i_pPropertyName ) const
+ { return hasProperty( rtl::OUString::createFromAscii( i_pPropertyName ) ); }
+
+ // returns an empty Any for not existing properties
+ com::sun::star::uno::Any getValue( const rtl::OUString& i_rPropertyName ) const;
+ // change a value in the property set; this will not have an effect to an eventual PrinterController
+ // the user of setValue must decide whether it is necessary to set the value there also
+ void setValue( const rtl::OUString& i_rPropertyName, const com::sun::star::uno::Any& i_rValue );
+ void setValue( const char* i_pPropertyName, const com::sun::star::uno::Any& i_rValue )
+ { setValue( rtl::OUString::createFromAscii( i_pPropertyName ), i_rValue ); }
+
+ sal_Bool getBoolValue( const rtl::OUString& i_rPropertyName, sal_Bool i_bDefault = sal_False ) const;
+ // convenience for fixed strings
+ sal_Bool getBoolValue( const char* i_pPropName, sal_Bool i_bDefault = sal_False ) const
+ { return getBoolValue( rtl::OUString::createFromAscii( i_pPropName ), i_bDefault ); }
+
+ sal_Int64 getIntValue( const rtl::OUString& i_rPropertyName, sal_Int64 i_nDefault = 0 ) const;
+ // convenience for fixed strings
+ sal_Int64 getIntValue( const char* i_pPropName, sal_Int64 i_nDefault = 0 ) const
+ { return getIntValue( rtl::OUString::createFromAscii( i_pPropName ), i_nDefault ); }
+
+ rtl::OUString getStringValue( const rtl::OUString& i_rPropertyName, const rtl::OUString& i_rDefault = rtl::OUString() ) const;
+ // convenience for fixed strings
+ rtl::OUString getStringValue( const char* i_pPropName, const rtl::OUString& i_rDefault = rtl::OUString() ) const
+ { return getStringValue( rtl::OUString::createFromAscii( i_pPropName ), i_rDefault ); }
+
+ // helper functions for user to create a single control
+ struct UIControlOptions
+ {
+ rtl::OUString maDependsOnName;
+ sal_Int32 mnDependsOnEntry;
+ sal_Bool mbAttachToDependency;
+ rtl::OUString maGroupHint;
+ sal_Bool mbInternalOnly;
+ sal_Bool mbEnabled;
+ com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue > maAddProps;
+
+ UIControlOptions( const rtl::OUString& i_rDependsOnName = rtl::OUString(),
+ sal_Int32 i_nDependsOnEntry = -1,
+ sal_Bool i_bAttachToDependency = sal_False,
+ const rtl::OUString& i_rGroupHint = rtl::OUString(),
+ sal_Bool i_bInternalOnly = sal_False,
+ sal_Bool i_bEnabled = sal_True
+ )
+ : maDependsOnName( i_rDependsOnName )
+ , mnDependsOnEntry( i_nDependsOnEntry )
+ , mbAttachToDependency( i_bAttachToDependency )
+ , maGroupHint( i_rGroupHint )
+ , mbInternalOnly( i_bInternalOnly )
+ , mbEnabled( i_bEnabled ) {}
+ };
+
+ // general control
+ static com::sun::star::uno::Any getUIControlOpt( const rtl::OUString& i_rTitle,
+ const com::sun::star::uno::Sequence< rtl::OUString >& i_rHelpText,
+ const rtl::OUString& i_rType,
+ const com::sun::star::beans::PropertyValue* i_pValue = NULL,
+ const UIControlOptions& i_rControlOptions = UIControlOptions()
+ );
+ // create a group (e.g. a TabPage); following controls will be grouped in it until the next
+ // group begins
+ static com::sun::star::uno::Any getGroupControlOpt( const rtl::OUString& i_rTitle, const rtl::OUString& i_rHelpText );
+
+ // create a subgroup (e.g. a FixedLine); following controls will be grouped in it until the next
+ // subgroup or group begins
+ // setting bJobPage = true will make the subgroup appear on the first page of the print dialog
+ static com::sun::star::uno::Any getSubgroupControlOpt( const rtl::OUString& i_rTitle,
+ const rtl::OUString& i_rHelpText,
+ const UIControlOptions& i_rControlOptions = UIControlOptions()
+ );
+
+ // create a bool option (usually a checkbox)
+ static com::sun::star::uno::Any getBoolControlOpt( const rtl::OUString& i_rTitle,
+ const rtl::OUString& i_rHelpText,
+ const rtl::OUString& i_rProperty,
+ sal_Bool i_bValue,
+ const UIControlOptions& i_rControlOptions = UIControlOptions()
+ );
+
+ // create a set of choices (either a radio button group or a list box)
+ static com::sun::star::uno::Any getChoiceControlOpt( const rtl::OUString& i_rTitle,
+ const com::sun::star::uno::Sequence< rtl::OUString >& i_rHelpText,
+ const rtl::OUString& i_rProperty,
+ const com::sun::star::uno::Sequence< rtl::OUString >& i_rChoices,
+ sal_Int32 i_nValue,
+ const rtl::OUString& i_rType = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Radio" ) ),
+ const UIControlOptions& i_rControlOptions = UIControlOptions()
+ );
+
+ // create an integer range (e.g. a spin field)
+ // note: max value < min value means do not apply min/max values
+ static com::sun::star::uno::Any getRangeControlOpt( const rtl::OUString& i_rTitle,
+ const rtl::OUString& i_rHelpText,
+ const rtl::OUString& i_rProperty,
+ sal_Int32 i_nValue,
+ sal_Int32 i_nMinValue = -1,
+ sal_Int32 i_nMaxValue = -2,
+ const UIControlOptions& i_rControlOptions = UIControlOptions()
+ );
+
+ // create a string field
+ // note: max value < min value means do not apply min/max values
+ static com::sun::star::uno::Any getEditControlOpt( const rtl::OUString& i_rTitle,
+ const rtl::OUString& i_rHelpText,
+ const rtl::OUString& i_rProperty,
+ const rtl::OUString& i_rValue,
+ const UIControlOptions& i_rControlOptions = UIControlOptions()
+ );
+};
+
+}
+
+
+#endif // _SV_PRINT_HXX
diff --git a/vcl/inc/vcl/printergfx.hxx b/vcl/inc/vcl/printergfx.hxx
new file mode 100644
index 000000000000..790021ae3adc
--- /dev/null
+++ b/vcl/inc/vcl/printergfx.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _PSPRINT_PRINTERGFX_HXX_
+#define _PSPRINT_PRINTERGFX_HXX_
+
+#include "vcl/helper.hxx"
+#include "vcl/sallayout.hxx"
+#include "osl/file.hxx"
+#include "tools/gen.hxx"
+
+#include <list>
+#include <hash_map>
+
+namespace psp {
+
+// forwards
+class JobData;
+
+/*
+ * lightweight container to handle RGB values
+ */
+
+class PrinterColor
+{
+public:
+
+ enum ColorSpace { eInvalid, eRGB };
+
+private:
+
+ sal_uInt8 mnRed;
+ sal_uInt8 mnGreen;
+ sal_uInt8 mnBlue;
+ ColorSpace meColorspace;
+
+public:
+
+ PrinterColor () :
+ meColorspace(eInvalid)
+ {}
+ PrinterColor (sal_uInt16 nRed, sal_uInt16 nGreen,
+ sal_uInt16 nBlue) :
+ mnRed (nRed),
+ mnGreen (nGreen),
+ mnBlue (nBlue),
+ meColorspace (eRGB)
+ {}
+ PrinterColor (sal_uInt32 nRGB) :
+ mnRed ((nRGB & 0x00ff0000) >> 16),
+ mnGreen ((nRGB & 0x0000ff00) >> 8),
+ mnBlue ((nRGB & 0x000000ff) ),
+ meColorspace (eRGB)
+ {}
+ ~PrinterColor ()
+ {}
+
+ sal_Bool Is () const
+ { return meColorspace != eInvalid; }
+
+ ColorSpace GetColorSpace () const
+ { return meColorspace; }
+ sal_uInt16 GetRed () const
+ { return mnRed; }
+ sal_uInt16 GetGreen () const
+ { return mnGreen; }
+ sal_uInt16 GetBlue () const
+ { return mnBlue; }
+ sal_Bool operator== (const PrinterColor& aColor) const
+ {
+ return aColor.Is() && this->Is()
+ && mnRed == aColor.mnRed
+ && mnGreen == aColor.mnGreen
+ && mnBlue == aColor.mnBlue;
+ }
+ sal_Bool operator!= (const PrinterColor& aColor) const
+ { return ! (aColor==*this); }
+ PrinterColor& operator= (const PrinterColor& aColor)
+ {
+ meColorspace = aColor.meColorspace;
+ mnRed = aColor.mnRed;
+ mnGreen = aColor.mnGreen;
+ mnBlue = aColor.mnBlue;
+
+ return *this;
+ }
+
+ PrinterColor& operator= (sal_uInt32 nRGB)
+ {
+ meColorspace = eRGB;
+ mnBlue = (nRGB & 0x000000ff);
+ mnGreen = (nRGB & 0x0000ff00) >> 8;
+ mnRed = (nRGB & 0x00ff0000) >> 16;
+
+ return *this;
+ }
+};
+
+/*
+ * forward declarations
+ */
+
+class Font3;
+class GlyphSet;
+class PrinterJob;
+class PrintFontManager;
+class KernPair;
+struct CharacterMetric;
+
+/*
+ * Bitmap Interface, this has to be filled with your actual bitmap implementation
+ * sample implementations can be found in:
+ * psprint/workben/cui/pspdem.cxx
+ * vcl/unx/source/gdi/salgdi2.cxx
+ */
+
+class PrinterBmp
+{
+public:
+
+ virtual ~PrinterBmp () = 0;
+ virtual sal_uInt32 GetPaletteColor (sal_uInt32 nIdx) const = 0;
+ virtual sal_uInt32 GetPaletteEntryCount () const = 0;
+ virtual sal_uInt32 GetPixelRGB (sal_uInt32 nRow, sal_uInt32 nColumn) const = 0;
+ virtual sal_uInt8 GetPixelGray (sal_uInt32 nRow, sal_uInt32 nColumn) const = 0;
+ virtual sal_uInt8 GetPixelIdx (sal_uInt32 nRow, sal_uInt32 nColumn) const = 0;
+ virtual sal_uInt32 GetWidth () const = 0;
+ virtual sal_uInt32 GetHeight () const = 0;
+ virtual sal_uInt32 GetDepth () const = 0;
+};
+
+typedef enum {
+ InvalidType = 0,
+ TrueColorImage,
+ MonochromeImage,
+ PaletteImage,
+ GrayScaleImage
+} ImageType;
+
+/*
+ * printer raster operations
+ */
+
+struct GraphicsStatus
+{
+ rtl::OString maFont;
+ rtl_TextEncoding maEncoding;
+ bool mbArtItalic;
+ bool mbArtBold;
+ sal_Int32 mnTextHeight;
+ sal_Int32 mnTextWidth;
+ PrinterColor maColor;
+ double mfLineWidth;
+
+ GraphicsStatus();
+};
+
+class Font3;
+
+class PrinterGfx
+{
+private:
+
+ /* common settings */
+
+ double mfScaleX;
+ double mfScaleY;
+
+ sal_uInt32 mnDpi;
+ sal_uInt16 mnDepth;
+
+ sal_uInt16 mnPSLevel;
+ sal_Bool mbColor;
+ sal_Bool mbUploadPS42Fonts;
+
+ osl::File* mpPageHeader;
+ osl::File* mpPageBody;
+
+ void TranslateCoordinates (sal_Int32 &rXOut, sal_Int32 &rYOut,
+ sal_Int32 nXIn, sal_Int32 nYIn )
+ { rXOut = nXIn; rYOut = nYIn; }
+ void TranslateCoordinates (Point& rOut, const Point& rIn)
+ { rOut = rIn; }
+
+ /* text/font related data, for a type1 font it has to be checked
+ whether this font has already been downloaded. A TrueType font
+ will be converted into one or more Type3 fonts, containing glyphs
+ in no particular order. In addition to the existence of the
+ glyph in one of the subfonts, the mapping from unicode to the
+ glyph has to be remembered */
+
+ std::list< sal_Int32 > maPS1Font;
+ std::list< GlyphSet > maPS3Font;
+
+ sal_Int32 mnFontID;
+ sal_Int32 mnFallbackID;
+ sal_Int32 mnTextAngle;
+ bool mbTextVertical;
+ PrintFontManager& mrFontMgr;
+
+ /* bitmap drawing implementation */
+
+ sal_Bool mbCompressBmp;
+
+ void DrawPS1GrayImage (const PrinterBmp& rBitmap, const Rectangle& rArea);
+ void writePS2ImageHeader (const Rectangle& rArea, psp::ImageType nType);
+ void writePS2Colorspace (const PrinterBmp& rBitmap, psp::ImageType nType);
+ void DrawPS2GrayImage (const PrinterBmp& rBitmap, const Rectangle& rArea);
+ void DrawPS2PaletteImage (const PrinterBmp& rBitmap, const Rectangle& rArea);
+ void DrawPS2TrueColorImage (const PrinterBmp& rBitmap, const Rectangle& rArea);
+ void DrawPS2MonoImage (const PrinterBmp& rBitmap, const Rectangle& rArea);
+
+ /* clip region */
+
+ std::list< Rectangle > maClipRegion;
+ sal_Bool JoinVerticalClipRectangles( std::list< Rectangle >::iterator& it,
+ Point& aOldPoint, sal_Int32& nColumn );
+
+ /* color settings */
+ PrinterColor maFillColor;
+ PrinterColor maTextColor;
+ PrinterColor maLineColor;
+
+ /* graphics state */
+ GraphicsStatus maVirtualStatus;
+ std::list< GraphicsStatus > maGraphicsStack;
+ GraphicsStatus& currentState() { return maGraphicsStack.front(); }
+
+ /* font / font substitution */
+ friend class Font3;
+ const ::std::hash_map< fontID, fontID >* mpFontSubstitutes;
+ int getCharWidth (sal_Bool b_vert, sal_Unicode n_char,
+ CharacterMetric *p_bbox);
+ fontID getCharMetric (const Font3 &rFont, sal_Unicode n_char,
+ CharacterMetric *p_bbox);
+ fontID getFontSubstitute () const;
+ fontID getFallbackID () const { return mnFallbackID; }
+
+ bool mbStrictSO52Compatibility;
+public:
+ /* grahics status update */
+ void PSSetColor ();
+ void PSSetLineWidth ();
+ void PSSetFont ();
+
+ /* graphics status functions */
+ void PSSetColor (const PrinterColor& rColor)
+ { maVirtualStatus.maColor = rColor; }
+
+ void PSUploadPS1Font (sal_Int32 nFontID);
+ void PSSetFont (const rtl::OString& rName,
+ rtl_TextEncoding nEncoding = RTL_TEXTENCODING_DONTKNOW)
+ { maVirtualStatus.maFont = rName; maVirtualStatus.maEncoding = nEncoding; }
+
+ /* graphics status stack */
+ void PSGSave ();
+ void PSGRestore ();
+
+
+ /* PS helpers */
+ enum pspath_t { moveto = 0, lineto = 1 };
+ void PSBinLineTo (const Point& rCurrent, Point& rOld,
+ sal_Int32& nColumn);
+ void PSBinMoveTo (const Point& rCurrent, Point& rOld,
+ sal_Int32& nColumn);
+ void PSBinStartPath ();
+ void PSBinEndPath ();
+ void PSBinCurrentPath (sal_uInt32 nPoints, const Point* pPath);
+ void PSBinPath (const Point& rCurrent, Point& rOld,
+ pspath_t eType, sal_Int32& nColumn);
+
+ void PSRotate (sal_Int32 nAngle);
+ void PSTranslate (const Point& rPoint);
+ void PSMoveTo (const Point& rPoint);
+ void PSRMoveTo (sal_Int32 nDx, sal_Int32 nDy = 0);
+ void PSScale (double fScaleX, double fScaleY);
+ void PSLineTo(const Point& rPoint );
+ void PSPointOp (const Point& rPoint, const sal_Char* pOperator);
+ void PSHexString (const sal_uChar* pString, sal_Int16 nLen);
+ void PSDeltaArray (const sal_Int32 *pArray, sal_Int16 nEntries);
+ void PSShowText (const sal_uChar* pString,
+ sal_Int16 nGlyphs, sal_Int16 nBytes,
+ const sal_Int32* pDeltaArray = NULL);
+ void PSComment (const sal_Char* pComment );
+ void LicenseWarning (const Point& rPoint, const sal_Unicode* pStr,
+ sal_Int16 nLen, const sal_Int32* pDeltaArray);
+
+ void OnEndPage ();
+ void OnEndJob ();
+ void writeResources( osl::File* pFile, std::list< rtl::OString >& rSuppliedFonts, std::list< rtl::OString >& rNeededFonts );
+ PrintFontManager& GetFontMgr () { return mrFontMgr; }
+
+ void drawVerticalizedText (const Point& rPoint,
+ const sal_Unicode* pStr,
+ sal_Int16 nLen,
+ const sal_Int32* pDeltaArray );
+ void drawText (const Point& rPoint,
+ const sal_Unicode* pStr, sal_Int16 nLen,
+ const sal_Int32* pDeltaArray = NULL);
+
+ void drawGlyphs( const Point& rPoint,
+ sal_GlyphId* pGlyphIds,
+ sal_Unicode* pUnicodes,
+ sal_Int16 nLen,
+ sal_Int32* pDeltaArray );
+public:
+ PrinterGfx();
+ ~PrinterGfx();
+ sal_Bool Init (PrinterJob &rPrinterSpec);
+ sal_Bool Init (const JobData& rData);
+ void Clear();
+
+ // query depth and size
+ void GetResolution (sal_Int32 &rDpiX, sal_Int32 &rDpiY) const;
+ sal_uInt16 GetBitCount ();
+
+ // clip region
+ void ResetClipRegion ();
+ void BeginSetClipRegion (sal_uInt32);
+ sal_Bool UnionClipRegion (sal_Int32 nX, sal_Int32 nY,
+ sal_Int32 nDX, sal_Int32 nDY);
+ void EndSetClipRegion ();
+
+ // set xy color
+ void SetLineColor (const PrinterColor& rLineColor = PrinterColor())
+ { maLineColor = rLineColor; }
+ void SetFillColor (const PrinterColor& rFillColor = PrinterColor())
+ { maFillColor = rFillColor; }
+
+ // drawing primitives
+ void DrawPixel (const Point& rPoint, const PrinterColor& rPixelColor);
+ void DrawPixel (const Point& rPoint)
+ { DrawPixel (rPoint, maLineColor); }
+ void DrawLine (const Point& rFrom, const Point& rTo);
+ void DrawRect (const Rectangle& rRectangle);
+ void DrawPolyLine (sal_uInt32 nPoints, const Point* pPath );
+ void DrawPolygon (sal_uInt32 nPoints, const Point* pPath);
+ void DrawPolyPolygon (sal_uInt32 nPoly,
+ const sal_uInt32 *pPolygonSize,
+ const Point** pPolygonList);
+ void DrawPolyLineBezier (sal_uInt32 nPoints,
+ const Point* pPath,
+ const BYTE* pFlgAry );
+ void DrawPolygonBezier (sal_uInt32 nPoints,
+ const Point* pPath,
+ const BYTE* pFlgAry);
+ void DrawPolyPolygonBezier (sal_uInt32 nPoly,
+ const sal_uInt32* pPoints,
+ const Point* const* pPtAry,
+ const BYTE* const* pFlgAry);
+
+ // eps
+ sal_Bool DrawEPS ( const Rectangle& rBoundingBox, void* pPtr, sal_uInt32 nSize);
+
+ // image drawing
+ void DrawBitmap (const Rectangle& rDest, const Rectangle& rSrc,
+ const PrinterBmp& rBitmap);
+ void DrawBitmap (const Rectangle& rDest, const Rectangle& rSrc,
+ const PrinterBmp& rBitmap,
+ const PrinterBmp& rTransBitmap);
+ void DrawMask (const Rectangle& rDest, const Rectangle& rSrc,
+ const PrinterBmp &rBitmap, PrinterColor& rMaskColor);
+
+ // font and text handling
+ sal_uInt16 SetFont (
+ sal_Int32 nFontID,
+ sal_Int32 nPointHeight,
+ sal_Int32 nPointWidth,
+ sal_Int32 nAngle,
+ bool bVertical,
+ bool bArtItalic,
+ bool bArtBold
+ );
+ sal_uInt16 SetFallbackFont ( sal_Int32 nFontID );
+ sal_Int32 GetFontAngle () const
+ { return mnTextAngle; }
+ sal_Int32 GetFontID () const
+ { return mnFontID; }
+ bool GetFontVertical() const
+ { return mbTextVertical; }
+ sal_Int32 GetFontHeight () const
+ { return maVirtualStatus.mnTextHeight; }
+ sal_Int32 GetFontWidth () const
+ { return maVirtualStatus.mnTextWidth; }
+ bool GetArtificialItalic() const
+ { return maVirtualStatus.mbArtItalic; }
+ bool GetArtificialBold() const
+ { return maVirtualStatus.mbArtBold; }
+ void DrawText (const Point& rPoint,
+ const sal_Unicode* pStr, sal_Int16 nLen,
+ const sal_Int32* pDeltaArray = NULL);
+ void SetTextColor (PrinterColor& rTextColor)
+ { maTextColor = rTextColor; }
+ sal_Int32 GetCharWidth (sal_uInt16 nFrom, sal_uInt16 nTo,
+ long *pWidthArray);
+ const ::std::list< KernPair >& getKernPairs( bool bVertical = false ) const;
+ // advanced font handling
+ sal_Bool GetGlyphBoundRect (sal_Unicode c, Rectangle& rOutRect);
+ sal_uInt32 GetGlyphOutline (sal_Unicode c,
+ sal_uInt16 **ppPolySizes, Point **ppPoints,
+ sal_uInt8 **ppFlags);
+
+ // for CTL
+ void DrawGlyphs( const Point& rPoint,
+ sal_GlyphId* pGlyphIds,
+ sal_Unicode* pUnicodes,
+ sal_Int16 nLen,
+ sal_Int32* pDeltaArray );
+
+ bool getStrictSO52Compatibility() const;
+ void setStrictSO52Compatibility( bool );
+};
+
+} /* namespace psp */
+
+
+#endif /* _PSPRINT_PRINTERGFX_HXX_ */
+
diff --git a/vcl/inc/vcl/printerinfomanager.hxx b/vcl/inc/vcl/printerinfomanager.hxx
new file mode 100644
index 000000000000..f2e0aad538c8
--- /dev/null
+++ b/vcl/inc/vcl/printerinfomanager.hxx
@@ -0,0 +1,241 @@
+/*************************************************************************
+ *
+ * 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 _PSPRINT_PRINTERINFOMANAGER_HXX_
+#define _PSPRINT_PRINTERINFOMANAGER_HXX_
+
+#include <hash_map>
+#include <list>
+
+#include "vcl/dllapi.h"
+#include "vcl/helper.hxx"
+#include "vcl/jobdata.hxx"
+#include "vcl/helper.hxx"
+#include "osl/file.hxx"
+
+#include <cstdio>
+
+namespace psp
+{
+
+class SystemQueueInfo;
+
+struct PrinterInfo : JobData
+{
+ // basename of PPD
+ rtl::OUString m_aDriverName;
+ // can be the queue
+ rtl::OUString m_aLocation;
+ // a user defined comment
+ rtl::OUString m_aComment;
+ // a command line to pipe a PS-file to
+ rtl::OUString m_aCommand;
+ // a command line to pipe a PS-file to in case of direct print
+ rtl::OUString m_aQuickCommand;
+ // a list of special features separated by ',' not used by psprint
+ // but assigned from the outside (currently for "fax","pdf=","autoqueue","external_dialog")
+ rtl::OUString m_aFeatures;
+ // a mapping of fonts to other fonts.
+ // this provides a method for the user
+ // to replace arbitrary fonts by printer builtin fonts
+ // currently this is only a mapping between font names
+ // assuming that only adbobe standard encoding fonts are
+ // built into the printer. in future it may be necessary
+ // to map to a font name and UCS2 vector which should be mapped
+ // this vector is currently implicitly given by the adobe
+ // standard encoding
+ bool m_bPerformFontSubstitution;
+ std::hash_map< rtl::OUString, rtl::OUString, rtl::OUStringHash >
+ m_aFontSubstitutes;
+ std::hash_map< fontID, fontID >
+ m_aFontSubstitutions;
+
+ PrinterInfo() :
+ JobData(),
+ m_bPerformFontSubstitution( false )
+ {}
+};
+
+class VCL_DLLPUBLIC PrinterInfoManager
+{
+public:
+ enum Type { Default = 0, CUPS = 1 };
+
+ struct SystemPrintQueue
+ {
+ rtl::OUString m_aQueue;
+ rtl::OUString m_aLocation;
+ rtl::OUString m_aComment;
+ };
+protected:
+ // needed for checkPrintersChanged: files (not necessarily existant)
+ // and their last known modification time
+ struct WatchFile
+ {
+ // the file in question
+ rtl::OUString m_aFilePath;
+ // the last know modification time or 0, if file did not exist
+ TimeValue m_aModified;
+ };
+
+ // internal data to describe a printer
+ struct Printer
+ {
+ // configuration file containing this printer
+ // empty means a freshly added printer that has to be saved yet
+ rtl::OUString m_aFile;
+ // details other config files that have this printer
+ // in case of removal all have to be removed
+ std::list< rtl::OUString > m_aAlternateFiles;
+ // group in m_aFile containing the printer
+ // this must be unique over all configuration files
+ // it usually should be the printer name
+ rtl::OString m_aGroup;
+ // whether changes need to be saved
+ bool m_bModified;
+ // the corresponding info and job data
+ PrinterInfo m_aInfo;
+ };
+
+ std::hash_map< rtl::OUString, Printer, rtl::OUStringHash > m_aPrinters;
+ PrinterInfo m_aGlobalDefaults;
+ std::list< WatchFile > m_aWatchFiles;
+ rtl::OUString m_aDefaultPrinter;
+ rtl::OUString m_aSystemPrintCommand;
+
+ std::list< SystemPrintQueue > m_aSystemPrintQueues;
+
+ SystemQueueInfo* m_pQueueInfo;
+
+ Type m_eType;
+ bool m_bUseIncludeFeature;
+ bool m_bUseJobPatch;
+ rtl::OUString m_aSystemDefaultPaper;
+
+ bool m_bDisableCUPS;
+
+ PrinterInfoManager( Type eType = Default );
+ virtual ~PrinterInfoManager();
+
+ virtual void initialize();
+
+ // fill in font substitutions
+ // the resulting hash_map maps from source to target font ids
+ void fillFontSubstitutions( PrinterInfo& rInfo ) const;
+
+ // fill default paper if not configured in config file
+ // default paper is e.g. locale dependent
+ // if a paper is already set it will not be overwritten
+ void setDefaultPaper( PPDContext& rInfo ) const;
+
+ void initSystemDefaultPaper();
+public:
+
+ // there can only be one
+ static PrinterInfoManager& get();
+
+ // get PrinterInfoManager type
+ Type getType() const { return m_eType; }
+
+ // lists the names of all known printers
+ void listPrinters( std::list< rtl::OUString >& rList ) const;
+
+ // gets the number of known printers
+ int countPrinters() const { return m_aPrinters.size(); }
+
+ // gets info about a named printer
+ const PrinterInfo& getPrinterInfo( const rtl::OUString& rPrinter ) const;
+
+ // gets the name of the default printer
+ const rtl::OUString& getDefaultPrinter() const { return m_aDefaultPrinter; }
+
+ virtual void setupJobContextData( JobData& rData );
+
+ // changes the info about a named printer
+ virtual void changePrinterInfo( const rtl::OUString& rPrinter, const PrinterInfo& rNewInfo );
+
+ // check if the printer configuration has changed
+ // if bwait is true, then this method waits for eventual asynchronous
+ // printer discovery to finish
+ virtual bool checkPrintersChanged( bool bWait );
+
+ // members for administration (->padmin)
+
+ // add a named printer
+ // addPrinter fails if a printer with the same name already exists
+ // or the driver does not exist
+ virtual bool addPrinter( const rtl::OUString& rPrinterName, const rtl::OUString& rDriverName );
+
+ // remove a named printer
+ // this fails if the config file belonging to this printer
+ // is not writeable
+ // if bCheckOnly is true, the printer is not really removed;
+ // this is for checking if the removal would fail
+ virtual bool removePrinter( const rtl::OUString& rPrinterName, bool bCheckOnly = false );
+
+ // save the changes to all printers. this fails if there
+ // is no writable config file at all
+ virtual bool writePrinterConfig();
+
+ // set a new default printer
+ // fails if the specified printer does not exist
+ virtual bool setDefaultPrinter( const rtl::OUString& rPrinterName );
+
+ // primarily used internally but also by padmin
+ // returns the printer queue names
+ virtual const std::list< SystemPrintQueue >& getSystemPrintQueues();
+
+ // similar but returnse whole commandlines
+ virtual void getSystemPrintCommands( std::list< rtl::OUString >& rCommands );
+
+ // abstract print command
+ // returns a stdio FILE* that a postscript file may be written to
+ // this may either be a regular file or the result of popen()
+ virtual FILE* startSpool( const rtl::OUString& rPrinterName, bool bQuickCommand );
+ // close the FILE* returned by startSpool and does the actual spooling
+ // returns a numerical job id
+ virtual int endSpool( const rtl::OUString& rPrinterName, const rtl::OUString& rJobTitle, FILE* pFile, const JobData& rDocumentJobData );
+
+ // for spadmin: whether adding or removing a printer is possible
+ virtual bool addOrRemovePossible() const;
+
+ bool getUseIncludeFeature() const { return m_bUseIncludeFeature; }
+ bool getUseJobPatch() const { return m_bUseJobPatch; }
+
+ // check whether a printer's feature string contains a subfeature
+ bool checkFeatureToken( const rtl::OUString& rPrinterName, const char* pToken ) const;
+
+ // set m_bDisableCUPS and update printer config
+ void setCUPSDisabled( bool );
+
+ // gets m_bDisableCUPS, initialized from printer config
+ bool isCUPSDisabled() const;
+};
+
+} // namespace
+
+#endif // _PSPRINT_PRINTERINFOMANAGER_HXX_
diff --git a/vcl/inc/vcl/printerjob.hxx b/vcl/inc/vcl/printerjob.hxx
new file mode 100644
index 000000000000..cdf8745febcc
--- /dev/null
+++ b/vcl/inc/vcl/printerjob.hxx
@@ -0,0 +1,149 @@
+/*************************************************************************
+ *
+ * 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 _PSPRINT_PRINTERJOB_HXX_
+#define _PSPRINT_PRINTERJOB_HXX_
+
+#include "vcl/jobdata.hxx"
+#include "osl/file.hxx"
+#include "rtl/string.hxx"
+
+#include <list>
+
+namespace psp {
+
+// forward declarations
+class PrinterGfx;
+
+
+class PrinterJob
+{
+private: // private data
+
+ rtl::OUString maSpoolDirName;
+ rtl::OUString maFileName; // empty: spool to command, else spool to named file
+ rtl::OUString maJobTitle;
+ int mnFileMode;
+
+ osl::File* mpJobHeader;
+ osl::File* mpJobTrailer;
+
+ std::list< osl::File* > maPageList;
+ std::list< osl::File* > maHeaderList;
+
+ JobData m_aDocumentJobData;
+ JobData m_aLastJobData;
+ PrinterGfx* m_pGraphics;
+
+ sal_uInt32 mnResolution;
+
+ sal_uInt32 mnWidthPt;
+ sal_uInt32 mnHeightPt;
+ sal_uInt32 mnMaxWidthPt;
+ sal_uInt32 mnMaxHeightPt;
+
+ int mnLandscapes;
+ int mnPortraits;
+
+ sal_uInt32 mnLMarginPt;
+ sal_uInt32 mnRMarginPt;
+ sal_uInt32 mnTMarginPt;
+ sal_uInt32 mnBMarginPt;
+
+ double mfXScale;
+ double mfYScale;
+
+ sal_Int32 mnErrorCode;
+ bool m_bQuickJob;
+
+private: // private methods
+
+ osl::File* CreateSpoolFile (const rtl::OUString& rName,
+ const rtl::OUString& rExtension);
+ void InitPaperSize (const JobData& rJobSetup);
+
+ bool writeFeatureList( osl::File* pFile, const JobData&, bool bDocumentSetup );
+ bool writeSetup( osl::File* pFile, const JobData& );
+ bool writePageSetup( osl::File* pFile, const JobData&, bool bWriteFeatures = true );
+ void writeJobPatch( osl::File* File, const JobData& );
+ bool writeProlog (osl::File* pFile, const JobData& );
+
+public: // for usage in PrinterGfx
+
+ sal_uInt32 GetResolution () const { return mnResolution; }
+ void GetScale (double &rXScale, double &rYScale) const;
+ sal_uInt16 GetDepth () const;
+ sal_uInt16 GetPostscriptLevel (const JobData *pJobData = NULL) const;
+ sal_Bool IsColorPrinter () const;
+
+ osl::File* GetDocumentHeader ();
+ osl::File* GetDocumentTrailer ();
+ osl::File* GetCurrentPageHeader ();
+ osl::File* GetCurrentPageBody ();
+
+ const ::rtl::OUString& GetPrinterName() const { return m_aLastJobData.m_aPrinterName; }
+
+public:
+ PrinterJob ();
+ ~PrinterJob ();
+
+ /* rFileName: if length is greater than 0 save resulting PostScript
+ * to named file.
+ * nMode: only meaningful when saving to file: if nonzero, try
+ * to impose the mode on the resulting file's inode; for nonexistant
+ * files use open, for existant files try a chmod
+ * rJobName: text to appear in the %%Title comment
+ * rAppName: text to appear in the %%Creator comment
+ * rSetupData: JobData that apply to this job
+ * pGraphics: the graphics used to print this job;
+ * this graphics must live until End/AbortJob has returned
+ * bIsQuickJob: the job was started as "direct print" meaning
+ * the quick command for spooling should be used instead
+ * of the normal command
+ */
+ sal_Bool StartJob (const rtl::OUString& rFileName,
+ int nMode,
+ const rtl::OUString& rJobName,
+ const rtl::OUString& rAppName,
+ const JobData& rSetupData,
+ PrinterGfx* pGraphics,
+ bool bIsQuickJob
+ );
+ sal_Bool EndJob ();
+
+ sal_Bool AbortJob ();
+
+ sal_Bool StartPage (const JobData& rJobSetup);
+ sal_Bool EndPage ();
+
+ sal_uInt32 GetErrorCode ();
+};
+
+} /* namespace psp */
+
+#endif /* _PSPRINT_PRINTERJOB_HXX_ */
+
diff --git a/vcl/inc/vcl/prndlg.hxx b/vcl/inc/vcl/prndlg.hxx
new file mode 100644
index 000000000000..fdaf06c9854e
--- /dev/null
+++ b/vcl/inc/vcl/prndlg.hxx
@@ -0,0 +1,335 @@
+/*************************************************************************
+ *
+ * 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_PRNDLG_HXX
+#define _SV_PRNDLG_HXX
+
+#include <vcl/dllapi.h>
+
+#include "vcl/print.hxx"
+#include "vcl/print.h"
+
+#include "vcl/dialog.hxx"
+#include "vcl/fixed.hxx"
+#include "vcl/button.hxx"
+#include "vcl/gdimtf.hxx"
+#include "vcl/lstbox.hxx"
+#include "vcl/field.hxx"
+#include "vcl/tabctrl.hxx"
+#include "vcl/tabpage.hxx"
+#include "vcl/arrange.hxx"
+#include "vcl/virdev.hxx"
+
+#include <boost/shared_ptr.hpp>
+#include <map>
+
+namespace vcl
+{
+ class PrintDialog : public ModalDialog
+ {
+ class PrintPreviewWindow : public Window
+ {
+ GDIMetaFile maMtf;
+ Size maOrigSize;
+ Size maPreviewSize;
+ VirtualDevice maPageVDev;
+ rtl::OUString maReplacementString;
+ rtl::OUString maToolTipString;
+
+ bool useHCColorReplacement() const;
+ public:
+ PrintPreviewWindow( Window* pParent, const ResId& );
+ virtual ~PrintPreviewWindow();
+
+ virtual void Paint( const Rectangle& rRect );
+ virtual void Command( const CommandEvent& );
+ virtual void Resize();
+ virtual void DataChanged( const DataChangedEvent& );
+
+ void setPreview( const GDIMetaFile&, const Size&, const rtl::OUString&,
+ sal_Int32 i_nDPIX, sal_Int32 i_nDPIY
+ );
+ };
+
+ class ShowNupOrderWindow : public Window
+ {
+ int mnOrderMode;
+ int mnRows;
+ int mnColumns;
+ void ImplInitSettings();
+ public:
+ ShowNupOrderWindow( Window* pParent );
+ virtual ~ShowNupOrderWindow();
+
+ virtual void Paint( const Rectangle& );
+
+ void setValues( int i_nOrderMode, int i_nColumns, int i_nRows )
+ {
+ mnOrderMode = i_nOrderMode;
+ mnRows = i_nRows;
+ mnColumns = i_nColumns;
+ Invalidate();
+ }
+ };
+
+ class NUpTabPage : public TabPage
+ {
+ public:
+ FixedLine maNupLine;
+ RadioButton maPagesBtn;
+ RadioButton maBrochureBtn;
+ FixedText maPagesBoxTitleTxt;
+ ListBox maNupPagesBox;
+
+ // controls for "Custom" page mode
+ FixedText maNupNumPagesTxt;
+ NumericField maNupColEdt;
+ FixedText maNupTimesTxt;
+ NumericField maNupRowsEdt;
+ FixedText maPageMarginTxt1;
+ MetricField maPageMarginEdt;
+ FixedText maPageMarginTxt2;
+ FixedText maSheetMarginTxt1;
+ MetricField maSheetMarginEdt;
+ FixedText maSheetMarginTxt2;
+ FixedText maNupOrientationTxt;
+ ListBox maNupOrientationBox;
+
+ // page order ("left to right, then down")
+ FixedText maNupOrderTxt;
+ ListBox maNupOrderBox;
+ ShowNupOrderWindow maNupOrderWin;
+ // border around each page
+ CheckBox maBorderCB;
+
+ vcl::RowOrColumn maLayout;
+ boost::shared_ptr< vcl::RowOrColumn > mxBrochureDep;
+ boost::shared_ptr< vcl::LabeledElement >mxPagesBtnLabel;
+
+ void setupLayout();
+
+ NUpTabPage( Window*, const ResId& );
+ virtual ~NUpTabPage();
+
+ void readFromSettings();
+ void storeToSettings();
+ void initFromMultiPageSetup( const vcl::PrinterController::MultiPageSetup& );
+ void enableNupControls( bool bEnable );
+
+ void showAdvancedControls( bool );
+
+ virtual void Resize();
+ };
+
+ class JobTabPage : public TabPage
+ {
+ public:
+ FixedLine maPrinterFL;
+ ListBox maPrinters;
+ DisclosureButton maDetailsBtn;
+ FixedText maStatusLabel;
+ FixedText maStatusTxt;
+ FixedText maLocationLabel;
+ FixedText maLocationTxt;
+ FixedText maCommentLabel;
+ FixedText maCommentTxt;
+
+ PushButton maSetupButton;
+
+ FixedLine maCopies;
+ FixedLine maCopySpacer;
+ FixedText maCopyCount;
+ NumericField maCopyCountField;
+ CheckBox maCollateBox;
+ FixedImage maCollateImage;
+
+ Image maCollateImg;
+ Image maCollateHCImg;
+ Image maNoCollateImg;
+ Image maNoCollateHCImg;
+
+ long mnCollateUIMode;
+
+ vcl::RowOrColumn maLayout;
+ boost::shared_ptr<vcl::RowOrColumn> mxPrintRange;
+ boost::shared_ptr<vcl::WindowArranger> mxDetails;
+
+ JobTabPage( Window*, const ResId& );
+ virtual ~JobTabPage();
+
+ void readFromSettings();
+ void storeToSettings();
+
+ virtual void Resize();
+
+ void setupLayout();
+ };
+
+ class OutputOptPage : public TabPage
+ {
+ public:
+ FixedLine maOptionsLine;
+ CheckBox maToFileBox;
+ CheckBox maCollateSingleJobsBox;
+ CheckBox maReverseOrderBox;
+
+ vcl::RowOrColumn maLayout;
+ boost::shared_ptr<vcl::RowOrColumn> mxOptGroup;
+
+ OutputOptPage( Window*, const ResId& );
+ virtual ~OutputOptPage();
+
+ void readFromSettings();
+ void storeToSettings();
+
+ virtual void Resize();
+
+ void setupLayout();
+ };
+
+ OKButton maOKButton;
+ CancelButton maCancelButton;
+ HelpButton maHelpButton;
+ PrintPreviewWindow maPreviewWindow;
+ NumericField maPageEdit;
+ FixedText maNumPagesText;
+ PushButton maBackwardBtn;
+ PushButton maForwardBtn;
+
+ TabControl maTabCtrl;
+ NUpTabPage maNUpPage;
+ JobTabPage maJobPage;
+ OutputOptPage maOptionsPage;
+
+ FixedLine maButtonLine;
+
+ boost::shared_ptr< PrinterController > maPController;
+
+ rtl::OUString maPageStr;
+ rtl::OUString maNoPageStr;
+ sal_Int32 mnCurPage;
+ sal_Int32 mnCachedPages;
+
+ std::list< Window* > maControls;
+ std::map< Window*, rtl::OUString > maControlToPropertyMap;
+ std::map< rtl::OUString, std::vector< Window* > >
+ maPropertyToWindowMap;
+ std::map< Window*, sal_Int32 > maControlToNumValMap;
+ std::set< rtl::OUString > maReverseDependencySet;
+
+ Size maNupPortraitSize;
+ Size maNupLandscapeSize;
+
+ // internal, used for automatic Nup-Portrait/landscape
+ Size maFirstPageSize;
+
+ rtl::OUString maPrintToFileText;
+ rtl::OUString maPrintText;
+ rtl::OUString maDefPrtText;
+
+ vcl::RowOrColumn maLayout;
+ boost::shared_ptr<vcl::RowOrColumn> mxPreviewCtrls;
+
+ Size maDetailsCollapsedSize;
+ Size maDetailsExpandedSize;
+
+ sal_Bool mbShowLayoutPage;
+
+ Size getJobPageSize();
+ void updateNup();
+ void updateNupFromPages();
+ void preparePreview( bool i_bPrintChanged = true, bool i_bMayUseCache = false );
+ void setPreviewText( sal_Int32 );
+ void updatePrinterText();
+ void checkControlDependencies();
+ void checkOptionalControlDependencies();
+ void makeEnabled( Window* );
+ void updateWindowFromProperty( const rtl::OUString& );
+ void setupOptionalUI();
+ void readFromSettings();
+ void storeToSettings();
+ com::sun::star::beans::PropertyValue* getValueForWindow( Window* ) const;
+
+ virtual void Resize();
+ virtual void Command( const CommandEvent& );
+ virtual void DataChanged( const DataChangedEvent& );
+
+ DECL_LINK( SelectHdl, ListBox* );
+ DECL_LINK( ClickHdl, Button* );
+ DECL_LINK( ModifyHdl, Edit* );
+ DECL_LINK( UIOptionsChanged, void* );
+
+ DECL_LINK( UIOption_CheckHdl, CheckBox* );
+ DECL_LINK( UIOption_RadioHdl, RadioButton* );
+ DECL_LINK( UIOption_SelectHdl, ListBox* );
+ DECL_LINK( UIOption_ModifyHdl, Edit* );
+
+ void setupLayout();
+ public:
+ PrintDialog( Window*, const boost::shared_ptr< PrinterController >& );
+ virtual ~PrintDialog();
+
+ bool isPrintToFile();
+ int getCopyCount();
+ bool isCollate();
+ bool isSingleJobs();
+
+ void previewForward();
+ void previewBackward();
+ };
+
+ class PrintProgressDialog : public ModelessDialog
+ {
+ String maStr;
+ FixedText maText;
+ CancelButton maButton;
+
+ bool mbCanceled;
+ sal_Int32 mnCur;
+ sal_Int32 mnMax;
+ long mnProgressHeight;
+ Rectangle maProgressRect;
+ bool mbNativeProgress;
+
+ DECL_LINK( ClickHdl, Button* );
+
+ void implCalcProgressRect();
+ public:
+ PrintProgressDialog( Window* i_pParent, int i_nMax );
+ ~PrintProgressDialog();
+
+ bool isCanceled() const { return mbCanceled; }
+ void setProgress( int i_nCurrent, int i_nMax = -1 );
+ void tick();
+ void reset();
+
+ virtual void Paint( const Rectangle& );
+ };
+}
+
+
+#endif // _SV_PRNDLG_HXX
diff --git a/vcl/inc/vcl/prntypes.hxx b/vcl/inc/vcl/prntypes.hxx
new file mode 100644
index 000000000000..6b2af991f2dd
--- /dev/null
+++ b/vcl/inc/vcl/prntypes.hxx
@@ -0,0 +1,95 @@
+/*************************************************************************
+ *
+ * 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_PRNTYPES_HXX
+#define _SV_PRNTYPES_HXX
+
+#include <tools/string.hxx>
+#include <vcl/sv.h>
+#include <i18npool/paper.hxx>
+
+// ---------------
+// - Duplex Mode -
+// ---------------
+
+enum DuplexMode { DUPLEX_UNKNOWN, DUPLEX_OFF, DUPLEX_LONGEDGE, DUPLEX_SHORTEDGE };
+
+// ---------------
+// - Orientation -
+// ---------------
+
+enum Orientation { ORIENTATION_PORTRAIT, ORIENTATION_LANDSCAPE };
+
+// -------------------
+// - QueueInfo-Types -
+// -------------------
+
+#define QUEUE_STATUS_READY ((ULONG)0x00000001)
+#define QUEUE_STATUS_PAUSED ((ULONG)0x00000002)
+#define QUEUE_STATUS_PENDING_DELETION ((ULONG)0x00000004)
+#define QUEUE_STATUS_BUSY ((ULONG)0x00000008)
+#define QUEUE_STATUS_INITIALIZING ((ULONG)0x00000010)
+#define QUEUE_STATUS_WAITING ((ULONG)0x00000020)
+#define QUEUE_STATUS_WARMING_UP ((ULONG)0x00000040)
+#define QUEUE_STATUS_PROCESSING ((ULONG)0x00000080)
+#define QUEUE_STATUS_PRINTING ((ULONG)0x00000100)
+#define QUEUE_STATUS_OFFLINE ((ULONG)0x00000200)
+#define QUEUE_STATUS_ERROR ((ULONG)0x00000400)
+#define QUEUE_STATUS_SERVER_UNKNOWN ((ULONG)0x00000800)
+#define QUEUE_STATUS_PAPER_JAM ((ULONG)0x00001000)
+#define QUEUE_STATUS_PAPER_OUT ((ULONG)0x00002000)
+#define QUEUE_STATUS_MANUAL_FEED ((ULONG)0x00004000)
+#define QUEUE_STATUS_PAPER_PROBLEM ((ULONG)0x00008000)
+#define QUEUE_STATUS_IO_ACTIVE ((ULONG)0x00010000)
+#define QUEUE_STATUS_OUTPUT_BIN_FULL ((ULONG)0x00020000)
+#define QUEUE_STATUS_TONER_LOW ((ULONG)0x00040000)
+#define QUEUE_STATUS_NO_TONER ((ULONG)0x00080000)
+#define QUEUE_STATUS_PAGE_PUNT ((ULONG)0x00100000)
+#define QUEUE_STATUS_USER_INTERVENTION ((ULONG)0x00200000)
+#define QUEUE_STATUS_OUT_OF_MEMORY ((ULONG)0x00400000)
+#define QUEUE_STATUS_DOOR_OPEN ((ULONG)0x00800000)
+#define QUEUE_STATUS_POWER_SAVE ((ULONG)0x01000000)
+
+#define QUEUE_JOBS_DONTKNOW ((ULONG)0xFFFFFFFF)
+
+// -----------------
+// - Printer-Types -
+// -----------------
+
+#define PRINTER_CAPABILITIES_SUPPORTDIALOG ((USHORT)1)
+#define PRINTER_CAPABILITIES_COPIES ((USHORT)2)
+#define PRINTER_CAPABILITIES_COLLATECOPIES ((USHORT)3)
+#define PRINTER_CAPABILITIES_SETORIENTATION ((USHORT)4)
+#define PRINTER_CAPABILITIES_SETPAPERBIN ((USHORT)5)
+#define PRINTER_CAPABILITIES_SETPAPERSIZE ((USHORT)6)
+#define PRINTER_CAPABILITIES_SETPAPER ((USHORT)7)
+#define PRINTER_CAPABILITIES_FAX ((USHORT)8)
+#define PRINTER_CAPABILITIES_PDF ((USHORT)9)
+#define PRINTER_CAPABILITIES_EXTERNALDIALOG ((USHORT)10)
+#define PRINTER_CAPABILITIES_SETDUPLEX ((USHORT)11)
+
+#endif // _SV_PRNTYPES_HXX
diff --git a/vcl/inc/vcl/ptrstyle.hxx b/vcl/inc/vcl/ptrstyle.hxx
new file mode 100644
index 000000000000..796613bd5726
--- /dev/null
+++ b/vcl/inc/vcl/ptrstyle.hxx
@@ -0,0 +1,142 @@
+/*************************************************************************
+ *
+ * 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_PTRSTYLE_HXX
+#define _VCL_PTRSTYLE_HXX
+
+#include <vcl/sv.h>
+
+// -----------------
+// - Pointer-Types -
+// -----------------
+
+typedef USHORT PointerStyle;
+
+#define POINTER_ARROW ((PointerStyle)0)
+#define POINTER_NULL ((PointerStyle)1)
+#define POINTER_WAIT ((PointerStyle)2)
+#define POINTER_TEXT ((PointerStyle)3)
+#define POINTER_HELP ((PointerStyle)4)
+#define POINTER_CROSS ((PointerStyle)5)
+#define POINTER_MOVE ((PointerStyle)6)
+#define POINTER_NSIZE ((PointerStyle)7)
+#define POINTER_SSIZE ((PointerStyle)8)
+#define POINTER_WSIZE ((PointerStyle)9)
+#define POINTER_ESIZE ((PointerStyle)10)
+#define POINTER_NWSIZE ((PointerStyle)11)
+#define POINTER_NESIZE ((PointerStyle)12)
+#define POINTER_SWSIZE ((PointerStyle)13)
+#define POINTER_SESIZE ((PointerStyle)14)
+#define POINTER_WINDOW_NSIZE ((PointerStyle)15)
+#define POINTER_WINDOW_SSIZE ((PointerStyle)16)
+#define POINTER_WINDOW_WSIZE ((PointerStyle)17)
+#define POINTER_WINDOW_ESIZE ((PointerStyle)18)
+#define POINTER_WINDOW_NWSIZE ((PointerStyle)19)
+#define POINTER_WINDOW_NESIZE ((PointerStyle)20)
+#define POINTER_WINDOW_SWSIZE ((PointerStyle)21)
+#define POINTER_WINDOW_SESIZE ((PointerStyle)22)
+#define POINTER_HSPLIT ((PointerStyle)23)
+#define POINTER_VSPLIT ((PointerStyle)24)
+#define POINTER_HSIZEBAR ((PointerStyle)25)
+#define POINTER_VSIZEBAR ((PointerStyle)26)
+#define POINTER_HAND ((PointerStyle)27)
+#define POINTER_REFHAND ((PointerStyle)28)
+#define POINTER_PEN ((PointerStyle)29)
+#define POINTER_MAGNIFY ((PointerStyle)30)
+#define POINTER_FILL ((PointerStyle)31)
+#define POINTER_ROTATE ((PointerStyle)32)
+#define POINTER_HSHEAR ((PointerStyle)33)
+#define POINTER_VSHEAR ((PointerStyle)34)
+#define POINTER_MIRROR ((PointerStyle)35)
+#define POINTER_CROOK ((PointerStyle)36)
+#define POINTER_CROP ((PointerStyle)37)
+#define POINTER_MOVEPOINT ((PointerStyle)38)
+#define POINTER_MOVEBEZIERWEIGHT ((PointerStyle)39)
+#define POINTER_MOVEDATA ((PointerStyle)40)
+#define POINTER_COPYDATA ((PointerStyle)41)
+#define POINTER_LINKDATA ((PointerStyle)42)
+#define POINTER_MOVEDATALINK ((PointerStyle)43)
+#define POINTER_COPYDATALINK ((PointerStyle)44)
+#define POINTER_MOVEFILE ((PointerStyle)45)
+#define POINTER_COPYFILE ((PointerStyle)46)
+#define POINTER_LINKFILE ((PointerStyle)47)
+#define POINTER_MOVEFILELINK ((PointerStyle)48)
+#define POINTER_COPYFILELINK ((PointerStyle)49)
+#define POINTER_MOVEFILES ((PointerStyle)50)
+#define POINTER_COPYFILES ((PointerStyle)51)
+#define POINTER_NOTALLOWED ((PointerStyle)52)
+#define POINTER_DRAW_LINE ((PointerStyle)53)
+#define POINTER_DRAW_RECT ((PointerStyle)54)
+#define POINTER_DRAW_POLYGON ((PointerStyle)55)
+#define POINTER_DRAW_BEZIER ((PointerStyle)56)
+#define POINTER_DRAW_ARC ((PointerStyle)57)
+#define POINTER_DRAW_PIE ((PointerStyle)58)
+#define POINTER_DRAW_CIRCLECUT ((PointerStyle)59)
+#define POINTER_DRAW_ELLIPSE ((PointerStyle)60)
+#define POINTER_DRAW_FREEHAND ((PointerStyle)61)
+#define POINTER_DRAW_CONNECT ((PointerStyle)62)
+#define POINTER_DRAW_TEXT ((PointerStyle)63)
+#define POINTER_DRAW_CAPTION ((PointerStyle)64)
+#define POINTER_CHART ((PointerStyle)65)
+#define POINTER_DETECTIVE ((PointerStyle)66)
+#define POINTER_PIVOT_COL ((PointerStyle)67)
+#define POINTER_PIVOT_ROW ((PointerStyle)68)
+#define POINTER_PIVOT_FIELD ((PointerStyle)69)
+#define POINTER_CHAIN ((PointerStyle)70)
+#define POINTER_CHAIN_NOTALLOWED ((PointerStyle)71)
+#define POINTER_TIMEEVENT_MOVE ((PointerStyle)72)
+#define POINTER_TIMEEVENT_SIZE ((PointerStyle)73)
+#define POINTER_AUTOSCROLL_N ((PointerStyle)74)
+#define POINTER_AUTOSCROLL_S ((PointerStyle)75)
+#define POINTER_AUTOSCROLL_W ((PointerStyle)76)
+#define POINTER_AUTOSCROLL_E ((PointerStyle)77)
+#define POINTER_AUTOSCROLL_NW ((PointerStyle)78)
+#define POINTER_AUTOSCROLL_NE ((PointerStyle)79)
+#define POINTER_AUTOSCROLL_SW ((PointerStyle)80)
+#define POINTER_AUTOSCROLL_SE ((PointerStyle)81)
+#define POINTER_AUTOSCROLL_NS ((PointerStyle)82)
+#define POINTER_AUTOSCROLL_WE ((PointerStyle)83)
+#define POINTER_AUTOSCROLL_NSWE ((PointerStyle)84)
+#define POINTER_AIRBRUSH ((PointerStyle)85)
+#define POINTER_TEXT_VERTICAL ((PointerStyle)86)
+#define POINTER_PIVOT_DELETE ((PointerStyle)87)
+
+// --> FME 2004-07-30 #i32329# Enhanced table selection
+#define POINTER_TAB_SELECT_S ((PointerStyle)88)
+#define POINTER_TAB_SELECT_E ((PointerStyle)89)
+#define POINTER_TAB_SELECT_SE ((PointerStyle)90)
+#define POINTER_TAB_SELECT_W ((PointerStyle)91)
+#define POINTER_TAB_SELECT_SW ((PointerStyle)92)
+// <--
+
+// --> FME 2004-08-16 #i20119# Paintbrush tool
+#define POINTER_PAINTBRUSH ((PointerStyle)93)
+// <--
+
+#define POINTER_COUNT 94
+
+#endif // _VCL_PTRSTYLE_HXX
diff --git a/vcl/inc/vcl/regband.hxx b/vcl/inc/vcl/regband.hxx
new file mode 100644
index 000000000000..2e34fdcd5677
--- /dev/null
+++ b/vcl/inc/vcl/regband.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_REGBAND_HXX
+#define _SV_REGBAND_HXX
+
+#include <vcl/sv.h>
+#include <tools/poly.hxx>
+
+/* =======================================================================
+
+class ImplRegionBand
+
+This class handles one y-band of the region. In this band may contain one
+or more seprarations in x-direction. The y-Band do not contain any
+separation after creation.
+
+The separations are modified with basic clipping functions like Union and
+Intersection - the Class will process the clipping for the actual band.
+
+The actual separations may be checked by functions like IsInside or
+IsOver.
+
+======================================================================= */
+
+// ------------------------
+// - ImplRegionBand-Types -
+// ------------------------
+
+// element for the list with x-separations
+struct ImplRegionBandSep
+{
+ ImplRegionBandSep* mpNextSep;
+ long mnXLeft;
+ long mnXRight;
+ BOOL mbRemoved;
+};
+
+enum LineType { LINE_ASCENDING, LINE_DESCENDING, LINE_HORIZONTAL };
+
+// element for the list with x-separations
+struct ImplRegionBandPoint
+{
+ ImplRegionBandPoint* mpNextBandPoint;
+ long mnX;
+ long mnLineId;
+ BOOL mbEndPoint;
+ LineType meLineType;
+};
+
+// ------------------
+// - ImplRegionBand -
+// ------------------
+
+class ImplRegionBand
+{
+public:
+ ImplRegionBand* mpNextBand; // pointer to the next element of the list
+ ImplRegionBand* mpPrevBand; // pointer to the previous element of the list (only used temporaery)
+ ImplRegionBandSep* mpFirstSep; // root of the list with x-separations
+ ImplRegionBandPoint* mpFirstBandPoint; // root of the list with lines
+ long mnYTop; // actual boundary of the band
+ long mnYBottom;
+ BOOL mbTouched;
+
+ // create y-band with boundaries
+ ImplRegionBand( long nYTop, long nYBottom );
+ /** copy y-band with with all data
+ @param theSourceBand
+ The new ImplRegionBand object will
+ be a copy of this band.
+ @param bIgnorePoints
+ When <TRUE/> (the default) the
+ band points pointed to by
+ mpFirstBandPoint are not copied.
+ When <FALSE/> they are copied.
+ You need the points when you are
+ planning to call ProcessPoints()
+ later on.
+ */
+ ImplRegionBand( const ImplRegionBand & theSourceBand,
+ const bool bIgnorePoints = true);
+ ~ImplRegionBand();
+
+ long GetXLeftBoundary() const;
+ long GetXRightBoundary() const;
+
+ // combine overlapping bands
+ BOOL OptimizeBand();
+
+ // generate separations from lines and process
+ // union with existing separations
+ void ProcessPoints();
+ // insert point in the list for later processing
+ BOOL InsertPoint( long nX, long nLineID,
+ BOOL bEndPoint, LineType eLineType );
+
+ void Union( long nXLeft, long nXRight );
+ void Intersect( long nXLeft, long nXRight );
+ void Exclude( long nXLeft, long nXRight );
+ void XOr( long nXLeft, long nXRight );
+
+ void MoveX( long nHorzMove );
+ void ScaleX( double fHorzScale );
+
+ BOOL IsInside( long nX );
+ BOOL IsInside( long nLeft, long nRight );
+ BOOL IsOver( long nLeft, long nRight );
+
+ BOOL IsEmpty() const { return ((!mpFirstSep) && (!mpFirstBandPoint)); }
+
+ BOOL operator==( const ImplRegionBand& rRegionBand ) const;
+
+ /** Split the called band at the given vertical coordinate. After the
+ split the called band will cover the upper part not including nY.
+ The new band will cover the lower part including nY.
+ @param nY
+ The band is split at this y coordinate. The new, lower band
+ will include this very value.
+ @return
+ Returns the new, lower band.
+ */
+ ImplRegionBand* SplitBand (const sal_Int32 nY);
+};
+
+#endif // _SV_REGBAND_HXX
diff --git a/vcl/inc/vcl/region.h b/vcl/inc/vcl/region.h
new file mode 100644
index 000000000000..b10f0eaf0f0f
--- /dev/null
+++ b/vcl/inc/vcl/region.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_REGION_H
+#define _SV_REGION_H
+
+#include <vcl/regband.hxx>
+#include <tools/poly.hxx>
+#include <vcl/region.hxx>
+
+// -----------------
+// - Hilfsmethoden -
+// -----------------
+
+#ifdef DBG_UTIL
+const char* ImplDbgTestRegion( const void* pObj );
+#endif
+
+// --------------------
+// - ImplRegionHandle -
+// --------------------
+
+struct ImplRegionHandle
+{
+ Region* mpRegion;
+ ImplRegionBand* mpCurrRectBand;
+ ImplRegionBandSep* mpCurrRectBandSep;
+ BOOL mbFirst;
+};
+
+// ------------------
+// - ImplRegionInfo -
+// ------------------
+
+struct ImplRegionInfo
+{
+ void* mpVoidCurrRectBand;
+ void* mpVoidCurrRectBandSep;
+};
+
+// --------------
+// - ImplRegion -
+// --------------
+
+struct ImplRegionBase
+{
+public:
+ ImplRegionBase( int nCount = 1 ); // TODO: replace manual refcounting
+ virtual ~ImplRegionBase();
+public:
+ ULONG mnRefCount;
+ ULONG mnRectCount;
+ PolyPolygon* mpPolyPoly;
+ basegfx::B2DPolyPolygon* mpB2DPolyPoly;
+};
+
+class ImplRegion : public ImplRegionBase
+{
+ friend class Region;
+
+private:
+ ImplRegionBand* mpFirstBand; // root of the list with y-bands
+ ImplRegionBand* mpLastCheckedBand;
+
+public:
+ ImplRegion();
+ ImplRegion( const PolyPolygon& rPolyPoly );
+ ImplRegion( const basegfx::B2DPolyPolygon& );
+ ImplRegion( const ImplRegion& rImplRegion );
+ ~ImplRegion();
+
+ ImplRegionBand* ImplGetFirstRegionBand() const { return mpFirstBand; }
+ PolyPolygon* ImplGetPolyPoly() const { return mpPolyPoly; }
+
+ void CreateBandRange( long nYTop, long nYBottom );
+ void InsertBands( long nYTop, long nYBottom );
+ BOOL InsertSingleBand( ImplRegionBand* mpImplRegionBand,
+ long nYBandPosition );
+ BOOL InsertLine( const Point & rFirstPoint,
+ const Point & rSecondPoint,
+ long nLineID );
+ BOOL InsertPoint( const Point &rPoint,
+ long nLineID,
+ BOOL bEndPoint, LineType eLineType );
+
+ /** Insert one band either after another band or as the first or only
+ band. Both the forward as well as the backward links are updated.
+ @param pPreviousBand
+ When <NULL/> then pBandToInsert is inserted as first band or as
+ only band when there are no other bands.
+ When not <NULL/> then pBandToInsert is inserted directly after
+ pPreviousBand.
+ @param pBandToInsert
+ The band to insert.
+ */
+ void InsertBand (ImplRegionBand* pPreviousBand,
+ ImplRegionBand* pBandToInsert);
+
+ void Union( long nLeft, long nTop, long nRight, long nBottom );
+ void Exclude( long nLeft, long nTop, long nRight, long nBottom );
+ void XOr( long nLeft, long nTop, long nRight, long nBottom );
+
+ // remove emtpy rects
+ BOOL OptimizeBandList();
+
+ friend SvStream& operator>>( SvStream& rIStm, Region& rRegion );
+ friend SvStream& operator<<( SvStream& rOStm, const Region& rRegion );
+};
+
+#endif // _SV_REGION_H
diff --git a/vcl/inc/vcl/region.hxx b/vcl/inc/vcl/region.hxx
new file mode 100644
index 000000000000..ddfba57ffdcf
--- /dev/null
+++ b/vcl/inc/vcl/region.hxx
@@ -0,0 +1,155 @@
+/*************************************************************************
+ *
+ * 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_REGION_HXX
+#define _SV_REGION_HXX
+
+#include <tools/gen.hxx>
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+
+class ImplRegion;
+class ImplRegionBand;
+class Polygon;
+class PolyPolygon;
+struct ImplRegionInfo;
+
+// --------------
+// - RegionType -
+// --------------
+
+enum RegionType { REGION_NULL, REGION_EMPTY, REGION_RECTANGLE, REGION_COMPLEX };
+enum RegionOverlapType { REGION_INSIDE, REGION_OVER, REGION_OUTSIDE };
+
+typedef long RegionHandle;
+
+// ----------
+// - Region -
+// ----------
+
+class VCL_DLLPUBLIC Region
+{
+ friend class OutputDevice;
+ friend class Window;
+ friend class Bitmap;
+
+private:
+ ImplRegion* mpImplRegion;
+
+ SAL_DLLPRIVATE void ImplCopyData();
+ SAL_DLLPRIVATE void ImplCreateRectRegion( const Rectangle& rRect );
+ SAL_DLLPRIVATE void ImplCreatePolyPolyRegion( const PolyPolygon& rPolyPoly );
+ SAL_DLLPRIVATE void ImplPolyPolyRegionToBandRegionFunc();
+ SAL_DLLPRIVATE inline void ImplPolyPolyRegionToBandRegion();
+ SAL_DLLPRIVATE const ImplRegion* ImplGetImplRegion() const { return mpImplRegion; }
+ SAL_DLLPRIVATE ImplRegion* ImplGetImplRegion() { return mpImplRegion; }
+ SAL_DLLPRIVATE BOOL ImplGetFirstRect( ImplRegionInfo& rImplRegionInfo,
+ long& nX, long& nY, long& nWidth, long& nHeight ) const;
+ SAL_DLLPRIVATE BOOL ImplGetNextRect( ImplRegionInfo& rImplRegionInfo,
+ long& nX, long& nY, long& nWidth, long& nHeight ) const;
+ SAL_DLLPRIVATE void ImplBeginAddRect( );
+ SAL_DLLPRIVATE BOOL ImplAddRect( const Rectangle& rRect );
+ SAL_DLLPRIVATE void ImplEndAddRect( );
+
+#ifdef DBG_UTIL
+ friend const char* ImplDbgTestRegion( const void* pObj );
+#endif
+
+public:
+ Region();
+ Region( RegionType eType );
+ Region( const Rectangle& rRect );
+ Region( const Polygon& rPolygon );
+ Region( const PolyPolygon& rPolyPoly );
+ Region( const basegfx::B2DPolyPolygon& );
+ Region( const Region& rRegion );
+ ~Region();
+
+ void Move( long nHorzMove, long nVertMove );
+ void Scale( double fScaleX, double fScaleY );
+ BOOL Union( const Rectangle& rRegion );
+ BOOL Intersect( const Rectangle& rRegion );
+ BOOL Exclude( const Rectangle& rRegion );
+ BOOL XOr( const Rectangle& rRegion );
+ BOOL Union( const Region& rRegion );
+ BOOL Intersect( const Region& rRegion );
+ BOOL Exclude( const Region& rRegion );
+ BOOL XOr( const Region& rRegion );
+
+ RegionType GetType() const;
+ BOOL IsEmpty() const { return GetType() == REGION_EMPTY; };
+ BOOL IsNull() const { return GetType() == REGION_NULL; };
+
+ void SetEmpty();
+ void SetNull();
+
+ Rectangle GetBoundRect() const;
+
+ BOOL HasPolyPolygon() const;
+ PolyPolygon GetPolyPolygon() const;
+ // returns an empty polypolygon in case HasPolyPolygon is FALSE
+ const basegfx::B2DPolyPolygon GetB2DPolyPolygon() const;
+ // returns a PolyPolygon either copied from the set PolyPolygon region
+ // or created from the constituent rectangles
+ basegfx::B2DPolyPolygon ConvertToB2DPolyPolygon();
+
+ ULONG GetRectCount() const;
+ RegionHandle BeginEnumRects();
+ BOOL GetEnumRects( RegionHandle hRegionHandle, Rectangle& rRect );
+ BOOL GetNextEnumRect( RegionHandle hRegionHandle, Rectangle& rRect )
+ { return GetEnumRects( hRegionHandle, rRect ); }
+ void EndEnumRects( RegionHandle hRegionHandle );
+
+ BOOL IsInside( const Point& rPoint ) const;
+ BOOL IsInside( const Rectangle& rRect ) const;
+ BOOL IsOver( const Rectangle& rRect ) const;
+
+ Region& operator=( const Region& rRegion );
+ Region& operator=( const Rectangle& rRect );
+
+ BOOL operator==( const Region& rRegion ) const;
+ BOOL operator!=( const Region& rRegion ) const
+ { return !(Region::operator==( rRegion )); }
+
+ friend VCL_DLLPUBLIC SvStream& operator>>( SvStream& rIStm, Region& rRegion );
+ friend VCL_DLLPUBLIC SvStream& operator<<( SvStream& rOStm, const Region& rRegion );
+
+ /* workaround: faster conversion for PolyPolygons
+ * if half of the Polygons contained in rPolyPoly are actually
+ * rectangles, then the returned Region will be constructed by
+ * XOr'ing the contained Polygons together; in the case of
+ * only Rectangles this can be up to eight times faster than
+ * Region( const PolyPolygon& ).
+ * Caution: this is only useful if the Region is known to be
+ * changed to rectangles; e.g. if being set as clip region
+ */
+ static Region GetRegionFromPolyPolygon( const PolyPolygon& rPolyPoly );
+};
+
+#endif // _SV_REGION_HXX
diff --git a/vcl/inc/vcl/salatype.hxx b/vcl/inc/vcl/salatype.hxx
new file mode 100644
index 000000000000..d9e25c0cada9
--- /dev/null
+++ b/vcl/inc/vcl/salatype.hxx
@@ -0,0 +1,47 @@
+/*************************************************************************
+ *
+ * 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_SALATYPE_HXX
+#define _SV_SALATYPE_HXX
+
+#include <vcl/sv.h>
+
+// ---------------------
+// - Application-Types -
+// ---------------------
+
+// Derzeit doppelt und in apptypes.hxx auch vorhanden
+
+#define INPUT_MOUSE 0x0001
+#define INPUT_KEYBOARD 0x0002
+#define INPUT_PAINT 0x0004
+#define INPUT_TIMER 0x0008
+#define INPUT_OTHER 0x0010
+#define INPUT_MOUSEANDKEYBOARD (INPUT_MOUSE | INPUT_KEYBOARD)
+#define INPUT_ANY (INPUT_MOUSEANDKEYBOARD | INPUT_PAINT | INPUT_TIMER | INPUT_OTHER)
+
+#endif // _SV_SALATYPE_HXX
diff --git a/vcl/inc/vcl/salbmp.hxx b/vcl/inc/vcl/salbmp.hxx
new file mode 100644
index 000000000000..4aca4a9277e9
--- /dev/null
+++ b/vcl/inc/vcl/salbmp.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALBMP_HXX
+#define _SV_SALBMP_HXX
+
+#ifndef _TL_GEN_HXX
+#include <tools/gen.hxx>
+#endif
+#include <vcl/dllapi.h>
+
+struct BitmapBuffer;
+class SalGraphics;
+class BitmapPalette;
+struct BitmapSystemData;
+
+class VCL_DLLPUBLIC SalBitmap
+{
+public:
+ SalBitmap() {}
+ virtual ~SalBitmap();
+
+ virtual bool Create( const Size& rSize,
+ USHORT nBitCount,
+ const BitmapPalette& rPal ) = 0;
+ virtual bool Create( const SalBitmap& rSalBmp ) = 0;
+ virtual bool Create( const SalBitmap& rSalBmp,
+ SalGraphics* pGraphics ) = 0;
+ virtual bool Create( const SalBitmap& rSalBmp,
+ USHORT nNewBitCount ) = 0;
+ virtual void Destroy() = 0;
+ virtual Size GetSize() const = 0;
+ virtual USHORT GetBitCount() const = 0;
+
+ virtual BitmapBuffer* AcquireBuffer( bool bReadOnly ) = 0;
+ virtual void ReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly ) = 0;
+ virtual bool GetSystemData( BitmapSystemData& rData ) = 0;
+
+};
+
+#endif
diff --git a/vcl/inc/vcl/salbtype.hxx b/vcl/inc/vcl/salbtype.hxx
new file mode 100644
index 000000000000..bbb70efcdf22
--- /dev/null
+++ b/vcl/inc/vcl/salbtype.hxx
@@ -0,0 +1,900 @@
+/*************************************************************************
+ *
+ * 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_SALBTYPE_HXX
+#define _SV_SALBTYPE_HXX
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <osl/endian.h>
+#include <tools/debug.hxx>
+#include <vcl/salgtype.hxx>
+#include <tools/color.hxx>
+#include <tools/gen.hxx>
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+
+// ----------
+// - Memory -
+// ----------
+
+typedef BYTE* HPBYTE;
+typedef HPBYTE Scanline;
+typedef const BYTE* ConstHPBYTE;
+typedef ConstHPBYTE ConstScanline;
+
+// ------------------
+// - Bitmap formats -
+// ------------------
+
+#define BMP_FORMAT_BOTTOM_UP 0x00000000UL
+#define BMP_FORMAT_TOP_DOWN 0x80000000UL
+
+#define BMP_FORMAT_1BIT_MSB_PAL 0x00000001UL
+#define BMP_FORMAT_1BIT_LSB_PAL 0x00000002UL
+
+#define BMP_FORMAT_4BIT_MSN_PAL 0x00000004UL
+#define BMP_FORMAT_4BIT_LSN_PAL 0x00000008UL
+
+#define BMP_FORMAT_8BIT_PAL 0x00000010UL
+#define BMP_FORMAT_8BIT_TC_MASK 0x00000020UL
+
+// #define BMP_FORMAT_16BIT_TC_MASK 0x00000040UL
+
+#define BMP_FORMAT_24BIT_TC_BGR 0x00000080UL
+#define BMP_FORMAT_24BIT_TC_RGB 0x00000100UL
+#define BMP_FORMAT_24BIT_TC_MASK 0x00000200UL
+
+#define BMP_FORMAT_32BIT_TC_ABGR 0x00000400UL
+#define BMP_FORMAT_32BIT_TC_ARGB 0x00000800UL
+#define BMP_FORMAT_32BIT_TC_BGRA 0x00001000UL
+#define BMP_FORMAT_32BIT_TC_RGBA 0x00002000UL
+#define BMP_FORMAT_32BIT_TC_MASK 0x00004000UL
+
+#define BMP_FORMAT_16BIT_TC_MSB_MASK 0x00008000UL
+#define BMP_FORMAT_16BIT_TC_LSB_MASK 0x00010000UL
+
+#define BMP_SCANLINE_ADJUSTMENT( Mac_nBmpFormat ) ( (Mac_nBmpFormat) & 0x80000000UL )
+#define BMP_SCANLINE_FORMAT( Mac_nBmpFormat ) ( (Mac_nBmpFormat) & 0x7FFFFFFFUL )
+
+// ------------------------------------------------------------------
+
+#define MASK_TO_COLOR( d_nVal, d_RM, d_GM, d_BM, d_RS, d_GS, d_BS, d_Col ) \
+ULONG _def_cR = (BYTE) ( d_RS < 0L ? ( (d_nVal) & d_RM ) << -d_RS : ( (d_nVal) & d_RM ) >> d_RS ); \
+ULONG _def_cG = (BYTE) ( d_GS < 0L ? ( (d_nVal) & d_GM ) << -d_GS : ( (d_nVal) & d_GM ) >> d_GS ); \
+ULONG _def_cB = (BYTE) ( d_BS < 0L ? ( (d_nVal) & d_BM ) << -d_BS : ( (d_nVal) & d_BM ) >> d_BS ); \
+d_Col = BitmapColor( (BYTE) ( _def_cR | ( ( _def_cR & mnROr ) >> mnROrShift ) ), \
+ (BYTE) ( _def_cG | ( ( _def_cG & mnGOr ) >> mnGOrShift ) ), \
+ (BYTE) ( _def_cB | ( ( _def_cB & mnBOr ) >> mnBOrShift ) ) );
+
+// ------------------------------------------------------------------
+
+#define COLOR_TO_MASK( d_rCol, d_RM, d_GM, d_BM, d_RS, d_GS, d_BS ) \
+( ( ( ( d_RS < 0L ) ? ( (UINT32) (d_rCol).GetRed() >> -d_RS ) : \
+ ( (UINT32) (d_rCol).GetRed() << d_RS ) ) & d_RM ) | \
+ ( ( ( d_GS < 0L ) ? ( (UINT32) (d_rCol).GetGreen() >> -d_GS ) : \
+ ( (UINT32) (d_rCol).GetGreen() << d_GS ) ) & d_GM ) | \
+ ( ( ( d_BS < 0L ) ? ( (UINT32) (d_rCol).GetBlue() >> -d_BS ) : \
+ ( (UINT32) (d_rCol).GetBlue() << d_BS ) ) & d_BM ) )
+
+// ---------------
+// - BitmapColor -
+// ---------------
+
+class Color;
+
+class VCL_DLLPUBLIC BitmapColor
+{
+private:
+
+// !!! Achtung:
+// !!! da auf die Member dieser Klasse via memcpy
+// !!! zugegriffen wird, darf diese Klasse weder
+// !!! in der Groesse noch der Reihenfolge der
+// !!! Member veraendert werden (KA 02.09.97)
+ BYTE mcBlueOrIndex;
+ BYTE mcGreen;
+ BYTE mcRed;
+ BYTE mbIndex;
+
+public:
+
+ inline BitmapColor();
+ inline BitmapColor( const BitmapColor& rBitmapColor );
+ inline BitmapColor( BYTE cRed, BYTE cGreen, BYTE cBlue );
+ inline BitmapColor( const Color& rColor );
+ inline BitmapColor( BYTE cIndex );
+ inline ~BitmapColor() {};
+
+ inline BOOL operator==( const BitmapColor& rBitmapColor ) const;
+ inline BOOL operator!=( const BitmapColor& rBitmapColor ) const;
+ inline BitmapColor& operator=( const BitmapColor& rBitmapColor );
+
+ inline BOOL IsIndex() const;
+
+ inline BYTE GetRed() const;
+ inline void SetRed( BYTE cRed );
+
+ inline BYTE GetGreen() const;
+ inline void SetGreen( BYTE cGreen );
+
+ inline BYTE GetBlue() const;
+ inline void SetBlue( BYTE cBlue );
+
+ inline BYTE GetIndex() const;
+ inline void SetIndex( BYTE cIndex );
+
+ operator Color() const;
+ inline operator BYTE() const;
+
+ inline BYTE GetBlueOrIndex() const;
+
+ inline BitmapColor& Invert();
+
+ inline BYTE GetLuminance() const;
+ inline BitmapColor& IncreaseLuminance( BYTE cGreyInc );
+ inline BitmapColor& DecreaseLuminance( BYTE cGreyDec );
+
+ inline BitmapColor& Merge( const BitmapColor& rColor, BYTE cTransparency );
+ inline BitmapColor& Merge( BYTE cR, BYTE cG, BYTE cB, BYTE cTransparency );
+
+ inline ULONG GetColorError( const BitmapColor& rBitmapColor ) const;
+};
+
+// ---------------
+// - BitmapPalette -
+// ---------------
+
+class Palette;
+
+class VCL_DLLPUBLIC BitmapPalette
+{
+ friend class SalBitmap;
+ friend class BitmapAccess;
+
+private:
+
+ BitmapColor* mpBitmapColor;
+ USHORT mnCount;
+
+//#if 0 // _SOLAR__PRIVATE
+
+public:
+
+ SAL_DLLPRIVATE inline BitmapColor* ImplGetColorBuffer() const;
+
+//#endif // __PRIVATE
+
+public:
+
+ inline BitmapPalette();
+ inline BitmapPalette( const BitmapPalette& rBitmapPalette );
+ inline BitmapPalette( USHORT nCount );
+ inline ~BitmapPalette();
+
+ inline BitmapPalette& operator=( const BitmapPalette& rBitmapPalette );
+ inline BOOL operator==( const BitmapPalette& rBitmapPalette ) const;
+ inline BOOL operator!=( const BitmapPalette& rBitmapPalette ) const;
+ inline BOOL operator!();
+
+ inline USHORT GetEntryCount() const;
+ inline void SetEntryCount( USHORT nCount );
+
+ inline const BitmapColor& operator[]( USHORT nIndex ) const;
+ inline BitmapColor& operator[]( USHORT nIndex );
+
+ inline USHORT GetBestIndex( const BitmapColor& rCol ) const;
+ bool IsGreyPalette() const;
+};
+
+// ---------------
+// - ColorMask -
+// ---------------
+
+class VCL_DLLPUBLIC ColorMask
+{
+ ULONG mnRMask;
+ ULONG mnGMask;
+ ULONG mnBMask;
+ long mnRShift;
+ long mnGShift;
+ long mnBShift;
+ ULONG mnROrShift;
+ ULONG mnGOrShift;
+ ULONG mnBOrShift;
+ ULONG mnROr;
+ ULONG mnGOr;
+ ULONG mnBOr;
+
+ SAL_DLLPRIVATE inline long ImplCalcMaskShift( ULONG nMask, ULONG& rOr, ULONG& rOrShift ) const;
+
+public:
+
+ inline ColorMask( ULONG nRedMask = 0UL, ULONG nGreenMask = 0UL, ULONG nBlueMask = 0UL );
+ inline ~ColorMask() {}
+
+ inline ULONG GetRedMask() const;
+ inline ULONG GetGreenMask() const;
+ inline ULONG GetBlueMask() const;
+
+ inline void GetColorFor8Bit( BitmapColor& rColor, ConstHPBYTE pPixel ) const;
+ inline void SetColorFor8Bit( const BitmapColor& rColor, HPBYTE pPixel ) const;
+
+ inline void GetColorFor16BitMSB( BitmapColor& rColor, ConstHPBYTE pPixel ) const;
+ inline void SetColorFor16BitMSB( const BitmapColor& rColor, HPBYTE pPixel ) const;
+ inline void GetColorFor16BitLSB( BitmapColor& rColor, ConstHPBYTE pPixel ) const;
+ inline void SetColorFor16BitLSB( const BitmapColor& rColor, HPBYTE pPixel ) const;
+
+ inline void GetColorFor24Bit( BitmapColor& rColor, ConstHPBYTE pPixel ) const;
+ inline void SetColorFor24Bit( const BitmapColor& rColor, HPBYTE pPixel ) const;
+
+ inline void GetColorFor32Bit( BitmapColor& rColor, ConstHPBYTE pPixel ) const;
+ inline void SetColorFor32Bit( const BitmapColor& rColor, HPBYTE pPixel ) const;
+};
+
+// ---------------
+// - BitmapBuffer -
+// ---------------
+
+struct VCL_DLLPUBLIC BitmapBuffer
+{
+ ULONG mnFormat;
+ long mnWidth;
+ long mnHeight;
+ long mnScanlineSize;
+ USHORT mnBitCount;
+ ColorMask maColorMask;
+ BitmapPalette maPalette;
+ BYTE* mpBits;
+
+ BitmapBuffer(){}
+ ~BitmapBuffer() {}
+};
+
+// ---------------------
+// - StretchAndConvert -
+// ---------------------
+
+VCL_DLLPUBLIC BitmapBuffer* StretchAndConvert( const BitmapBuffer& rSrcBuffer, const SalTwoRect& rTwoRect,
+ ULONG nDstBitmapFormat, BitmapPalette* pDstPal = NULL, ColorMask* pDstMask = NULL );
+
+// ------------------------------------------------------------------
+
+inline BitmapColor::BitmapColor() :
+ mcBlueOrIndex ( 0 ),
+ mcGreen ( 0 ),
+ mcRed ( 0 ),
+ mbIndex ( FALSE )
+{
+}
+
+// ------------------------------------------------------------------
+
+inline BitmapColor::BitmapColor( BYTE cRed, BYTE cGreen, BYTE cBlue ) :
+ mcBlueOrIndex ( cBlue ),
+ mcGreen ( cGreen ),
+ mcRed ( cRed ),
+ mbIndex ( FALSE )
+{
+}
+
+// ------------------------------------------------------------------
+
+inline BitmapColor::BitmapColor( const BitmapColor& rBitmapColor ) :
+ mcBlueOrIndex ( rBitmapColor.mcBlueOrIndex ),
+ mcGreen ( rBitmapColor.mcGreen ),
+ mcRed ( rBitmapColor.mcRed ),
+ mbIndex ( rBitmapColor.mbIndex )
+{
+}
+
+// ------------------------------------------------------------------
+
+inline BitmapColor::BitmapColor( const Color& rColor ) :
+ mcBlueOrIndex ( rColor.GetBlue() ),
+ mcGreen ( rColor.GetGreen() ),
+ mcRed ( rColor.GetRed() ),
+ mbIndex ( 0 )
+{
+}
+
+// ------------------------------------------------------------------
+
+inline BitmapColor::BitmapColor( BYTE cIndex ) :
+ mcBlueOrIndex ( cIndex ),
+ mcGreen ( 0 ),
+ mcRed ( 0 ),
+ mbIndex ( TRUE )
+{
+}
+
+// ------------------------------------------------------------------
+
+inline BOOL BitmapColor::operator==( const BitmapColor& rBitmapColor ) const
+{
+ return( ( mcBlueOrIndex == rBitmapColor.mcBlueOrIndex ) &&
+ ( mbIndex ? rBitmapColor.mbIndex :
+ ( mcGreen == rBitmapColor.mcGreen && mcRed == rBitmapColor.mcRed ) ) );
+}
+
+// ------------------------------------------------------------------
+
+inline BOOL BitmapColor::operator!=( const BitmapColor& rBitmapColor ) const
+{
+ return !( *this == rBitmapColor );
+}
+
+// ------------------------------------------------------------------
+
+inline BitmapColor& BitmapColor::operator=( const BitmapColor& rBitmapColor )
+{
+ mcBlueOrIndex = rBitmapColor.mcBlueOrIndex;
+ mcGreen = rBitmapColor.mcGreen;
+ mcRed = rBitmapColor.mcRed;
+ mbIndex = rBitmapColor.mbIndex;
+
+ return *this;
+}
+
+// ------------------------------------------------------------------
+
+inline BOOL BitmapColor::IsIndex() const
+{
+ return mbIndex;
+}
+
+// ------------------------------------------------------------------
+
+inline BYTE BitmapColor::GetRed() const
+{
+ DBG_ASSERT( !mbIndex, "Pixel represents index into colortable!" );
+ return mcRed;
+}
+
+// ------------------------------------------------------------------
+
+inline void BitmapColor::SetRed( BYTE cRed )
+{
+ DBG_ASSERT( !mbIndex, "Pixel represents index into colortable!" );
+ mcRed = cRed;
+}
+
+// ------------------------------------------------------------------
+
+inline BYTE BitmapColor::GetGreen() const
+{
+ DBG_ASSERT( !mbIndex, "Pixel represents index into colortable!" );
+ return mcGreen;
+}
+
+// ------------------------------------------------------------------
+
+inline void BitmapColor::SetGreen( BYTE cGreen )
+{
+ DBG_ASSERT( !mbIndex, "Pixel represents index into colortable!" );
+ mcGreen = cGreen;
+}
+
+// ------------------------------------------------------------------
+
+inline BYTE BitmapColor::GetBlue() const
+{
+ DBG_ASSERT( !mbIndex, "Pixel represents index into colortable!" );
+ return mcBlueOrIndex;
+}
+
+// ------------------------------------------------------------------
+
+inline void BitmapColor::SetBlue( BYTE cBlue )
+{
+ DBG_ASSERT( !mbIndex, "Pixel represents index into colortable!" );
+ mcBlueOrIndex = cBlue;
+}
+
+// ------------------------------------------------------------------
+
+inline BYTE BitmapColor::GetIndex() const
+{
+ DBG_ASSERT( mbIndex, "Pixel represents color values!" );
+ return mcBlueOrIndex;
+}
+
+// ------------------------------------------------------------------
+
+inline void BitmapColor::SetIndex( BYTE cIndex )
+{
+ DBG_ASSERT( mbIndex, "Pixel represents color values!" );
+ mcBlueOrIndex = cIndex;
+}
+
+// ------------------------------------------------------------------
+
+inline BitmapColor::operator Color() const
+{
+ DBG_ASSERT( !mbIndex, "Pixel represents index into colortable!" );
+ return Color( mcRed, mcGreen, mcBlueOrIndex );
+}
+
+// ------------------------------------------------------------------
+
+inline BitmapColor::operator BYTE() const
+{
+ DBG_ASSERT( mbIndex, "Pixel represents color values!" );
+ return mcBlueOrIndex;
+}
+
+// ------------------------------------------------------------------
+
+inline BYTE BitmapColor::GetBlueOrIndex() const
+{
+ // #i47518# Yield a value regardless of mbIndex
+ return mcBlueOrIndex;
+}
+
+// ------------------------------------------------------------------
+
+inline BitmapColor& BitmapColor::Invert()
+{
+ DBG_ASSERT( !mbIndex, "Pixel represents index into colortable!" );
+ mcBlueOrIndex = ~mcBlueOrIndex, mcGreen = ~mcGreen, mcRed = ~mcRed;
+
+ return *this;
+}
+
+// ------------------------------------------------------------------
+
+inline BYTE BitmapColor::GetLuminance() const
+{
+ DBG_ASSERT( !mbIndex, "Pixel represents index into colortable!" );
+ return( (BYTE) ( ( mcBlueOrIndex * 28UL + mcGreen * 151UL + mcRed * 77UL ) >> 8UL ) );
+}
+
+// ------------------------------------------------------------------
+
+inline BitmapColor& BitmapColor::IncreaseLuminance( BYTE cGreyInc )
+{
+ DBG_ASSERT( !mbIndex, "Pixel represents index into colortable!" );
+ mcBlueOrIndex = (BYTE) MinMax( (long) mcBlueOrIndex + cGreyInc, 0L, 255L );
+ mcGreen = (BYTE) MinMax( (long) mcGreen + cGreyInc, 0L, 255L );
+ mcRed = (BYTE) MinMax( (long) mcRed + cGreyInc, 0L, 255L );
+
+ return *this;
+}
+
+// ------------------------------------------------------------------
+
+inline BitmapColor& BitmapColor::DecreaseLuminance( BYTE cGreyDec )
+{
+ DBG_ASSERT( !mbIndex, "Pixel represents index into colortable!" );
+ mcBlueOrIndex = (BYTE) MinMax( (long) mcBlueOrIndex - cGreyDec, 0L, 255L );
+ mcGreen = (BYTE) MinMax( (long) mcGreen - cGreyDec, 0L, 255L );
+ mcRed = (BYTE) MinMax( (long) mcRed - cGreyDec, 0L, 255L );
+
+ return *this;
+}
+
+// ------------------------------------------------------------------
+
+inline BitmapColor& BitmapColor::Merge( const BitmapColor& rBitmapColor, BYTE cTransparency )
+{
+ DBG_ASSERT( !mbIndex, "Pixel represents index into colortable!" );
+ DBG_ASSERT( !rBitmapColor.mbIndex, "Pixel represents index into colortable!" );
+ mcBlueOrIndex = COLOR_CHANNEL_MERGE( mcBlueOrIndex, rBitmapColor.mcBlueOrIndex, cTransparency );
+ mcGreen = COLOR_CHANNEL_MERGE( mcGreen, rBitmapColor.mcGreen, cTransparency );
+ mcRed = COLOR_CHANNEL_MERGE( mcRed, rBitmapColor.mcRed, cTransparency );
+
+ return *this;
+}
+
+// ------------------------------------------------------------------
+
+inline BitmapColor& BitmapColor::Merge( BYTE cR, BYTE cG, BYTE cB, BYTE cTransparency )
+{
+ DBG_ASSERT( !mbIndex, "Pixel represents index into colortable!" );
+ mcBlueOrIndex = COLOR_CHANNEL_MERGE( mcBlueOrIndex, cB, cTransparency );
+ mcGreen = COLOR_CHANNEL_MERGE( mcGreen, cG, cTransparency );
+ mcRed = COLOR_CHANNEL_MERGE( mcRed, cR, cTransparency );
+
+ return *this;
+}
+
+// ------------------------------------------------------------------
+
+inline ULONG BitmapColor::GetColorError( const BitmapColor& rBitmapColor ) const
+{
+ DBG_ASSERT( !mbIndex, "Pixel represents index into colortable!" );
+ DBG_ASSERT( !rBitmapColor.mbIndex, "Pixel represents index into colortable!" );
+ return( (ULONG) ( labs( mcBlueOrIndex - rBitmapColor.mcBlueOrIndex ) +
+ labs( mcGreen - rBitmapColor.mcGreen ) +
+ labs( mcRed - rBitmapColor.mcRed ) ) );
+}
+
+// ------------------------------------------------------------------
+
+inline BitmapPalette::BitmapPalette() :
+ mpBitmapColor ( NULL ),
+ mnCount ( 0 )
+{
+}
+
+// ------------------------------------------------------------------
+
+inline BitmapPalette::BitmapPalette( const BitmapPalette& rBitmapPalette ) :
+ mnCount( rBitmapPalette.mnCount )
+{
+ if( mnCount )
+ {
+ const ULONG nSize = mnCount * sizeof( BitmapColor );
+ mpBitmapColor = (BitmapColor*) new BYTE[ nSize ];
+ memcpy( mpBitmapColor, rBitmapPalette.mpBitmapColor, nSize );
+ }
+ else
+ mpBitmapColor = NULL;
+}
+
+// ------------------------------------------------------------------
+
+inline BitmapPalette::BitmapPalette( USHORT nCount ) :
+ mnCount( nCount )
+{
+ if( mnCount )
+ {
+ const ULONG nSize = mnCount * sizeof( BitmapColor );
+ mpBitmapColor = (BitmapColor*) new BYTE[ nSize ];
+ memset( mpBitmapColor, 0, nSize );
+ }
+ else
+ mpBitmapColor = NULL;
+}
+
+// ------------------------------------------------------------------
+
+inline BitmapPalette::~BitmapPalette()
+{
+ delete[] (BYTE*) mpBitmapColor;
+}
+
+// ------------------------------------------------------------------
+
+inline BitmapPalette& BitmapPalette::operator=( const BitmapPalette& rBitmapPalette )
+{
+ delete[] (BYTE*) mpBitmapColor;
+ mnCount = rBitmapPalette.mnCount;
+
+ if( mnCount )
+ {
+ const ULONG nSize = mnCount * sizeof( BitmapColor );
+ mpBitmapColor = (BitmapColor*) new BYTE[ nSize ];
+ memcpy( mpBitmapColor, rBitmapPalette.mpBitmapColor, nSize );
+ }
+ else
+ mpBitmapColor = NULL;
+
+ return *this;
+}
+
+// ------------------------------------------------------------------
+
+inline BOOL BitmapPalette::operator==( const BitmapPalette& rBitmapPalette ) const
+{
+ BOOL bRet = FALSE;
+
+ if( rBitmapPalette.mnCount == mnCount )
+ {
+ bRet = TRUE;
+
+ for( USHORT i = 0; i < mnCount; i++ )
+ {
+ if( mpBitmapColor[ i ] != rBitmapPalette.mpBitmapColor[ i ] )
+ {
+ bRet = FALSE;
+ break;
+ }
+ }
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+inline BOOL BitmapPalette::operator!=( const BitmapPalette& rBitmapPalette ) const
+{
+ return !( *this == rBitmapPalette );
+}
+
+// ------------------------------------------------------------------
+
+inline BOOL BitmapPalette::operator!()
+{
+ return( !mnCount || !mpBitmapColor );
+}
+
+// ------------------------------------------------------------------
+
+inline USHORT BitmapPalette::GetEntryCount() const
+{
+ return mnCount;
+}
+
+// ------------------------------------------------------------------
+
+inline void BitmapPalette::SetEntryCount( USHORT nCount )
+{
+ if( !nCount )
+ {
+ delete[] (BYTE*) mpBitmapColor;
+ mpBitmapColor = NULL;
+ mnCount = 0;
+ }
+ else if( nCount != mnCount )
+ {
+ const ULONG nNewSize = nCount * sizeof( BitmapColor );
+ const ULONG nMinSize = Min( mnCount, nCount ) * sizeof( BitmapColor );
+ BYTE* pNewColor = new BYTE[ nNewSize ];
+
+ if ( nMinSize && mpBitmapColor )
+ memcpy( pNewColor, mpBitmapColor, nMinSize );
+ delete[] (BYTE*) mpBitmapColor;
+ memset( pNewColor + nMinSize, 0, nNewSize - nMinSize );
+ mpBitmapColor = (BitmapColor*) pNewColor;
+ mnCount = nCount;
+ }
+}
+
+// ------------------------------------------------------------------
+
+inline const BitmapColor& BitmapPalette::operator[]( USHORT nIndex ) const
+{
+ DBG_ASSERT( nIndex < mnCount, "Palette index is out of range!" );
+ return mpBitmapColor[ nIndex ];
+}
+
+// ------------------------------------------------------------------
+
+inline BitmapColor& BitmapPalette::operator[]( USHORT nIndex )
+{
+ DBG_ASSERT( nIndex < mnCount, "Palette index is out of range!" );
+ return mpBitmapColor[ nIndex ];
+}
+
+// ------------------------------------------------------------------
+
+//#if 0 // _SOLAR__PRIVATE
+inline BitmapColor* BitmapPalette::ImplGetColorBuffer() const
+{
+ DBG_ASSERT( mpBitmapColor, "No color buffer available!" );
+ return mpBitmapColor;
+}
+//#endif
+// ------------------------------------------------------------------
+
+inline USHORT BitmapPalette::GetBestIndex( const BitmapColor& rCol ) const
+{
+ USHORT nRetIndex = 0;
+
+ if( mpBitmapColor && mnCount )
+ {
+ BOOL bFound = FALSE;
+
+ for( long j = 0L; ( j < mnCount ) && !bFound; j++ )
+ if( rCol == mpBitmapColor[ j ] )
+ nRetIndex = ( (USHORT) j ), bFound = TRUE;
+
+ if( !bFound )
+ {
+ long nActErr, nLastErr = rCol.GetColorError( mpBitmapColor[ nRetIndex = mnCount - 1 ] );
+
+ for( long i = nRetIndex - 1; i >= 0L; i-- )
+ if ( ( nActErr = rCol.GetColorError( mpBitmapColor[ i ] ) ) < nLastErr )
+ nLastErr = nActErr, nRetIndex = (USHORT) i;
+ }
+ }
+
+ return nRetIndex;
+}
+
+// ------------------------------------------------------------------
+
+inline ColorMask::ColorMask( ULONG nRedMask, ULONG nGreenMask, ULONG nBlueMask ) :
+ mnRMask( nRedMask ),
+ mnGMask( nGreenMask ),
+ mnBMask( nBlueMask ),
+ mnROrShift( 0L ),
+ mnGOrShift( 0L ),
+ mnBOrShift( 0L ),
+ mnROr( 0L ),
+ mnGOr( 0L ),
+ mnBOr( 0L )
+{
+ mnRShift = ( mnRMask ? ImplCalcMaskShift( mnRMask, mnROr, mnROrShift ) : 0L );
+ mnGShift = ( mnGMask ? ImplCalcMaskShift( mnGMask, mnGOr, mnGOrShift ) : 0L );
+ mnBShift = ( mnBMask ? ImplCalcMaskShift( mnBMask, mnBOr, mnBOrShift ) : 0L );
+}
+
+// ------------------------------------------------------------------
+
+inline long ColorMask::ImplCalcMaskShift( ULONG nMask, ULONG& rOr, ULONG& rOrShift ) const
+{
+ long nShift;
+ long nRet;
+ ULONG nLen = 0UL;
+
+ // bei welchen Bits faengt die Maske an
+ for( nShift = 31L; ( nShift >= 0L ) && !( nMask & ( 1 << (ULONG) nShift ) ); nShift-- )
+ {}
+
+ nRet = nShift;
+
+ // XXX Anzahl der gesetzten Bits ermitteln => nach rechts bis Null laufen
+ while( ( nShift >= 0L ) && ( nMask & ( 1 << (ULONG) nShift ) ) )
+ {
+ nShift--;
+ nLen++;
+ }
+
+ rOrShift = 8L - nLen;
+ rOr = (BYTE) ( ( 0xffUL >> nLen ) << rOrShift );
+
+ return( nRet -= 7 );
+}
+
+// ------------------------------------------------------------------
+
+inline ULONG ColorMask::GetRedMask() const
+{
+ return mnRMask;
+}
+
+// ------------------------------------------------------------------
+
+inline ULONG ColorMask::GetGreenMask() const
+{
+ return mnGMask;
+}
+
+// ------------------------------------------------------------------
+
+inline ULONG ColorMask::GetBlueMask() const
+{
+ return mnBMask;
+}
+
+// ------------------------------------------------------------------
+
+inline void ColorMask::GetColorFor8Bit( BitmapColor& rColor, ConstHPBYTE pPixel ) const
+{
+ const UINT32 nVal = *pPixel;
+ MASK_TO_COLOR( nVal, mnRMask, mnGMask, mnBMask, mnRShift, mnGShift, mnBShift, rColor );
+}
+
+// ------------------------------------------------------------------
+
+inline void ColorMask::SetColorFor8Bit( const BitmapColor& rColor, HPBYTE pPixel ) const
+{
+ *pPixel = (BYTE) COLOR_TO_MASK( rColor, mnRMask, mnGMask, mnBMask, mnRShift, mnGShift, mnBShift );
+}
+
+// ------------------------------------------------------------------
+
+inline void ColorMask::GetColorFor16BitMSB( BitmapColor& rColor, ConstHPBYTE pPixel ) const
+{
+#ifdef OSL_BIGENDIAN
+ const UINT32 nVal = *(UINT16*) pPixel;
+#else
+ const UINT32 nVal = pPixel[ 1 ] | ( (UINT32) pPixel[ 0 ] << 8UL );
+#endif
+
+ MASK_TO_COLOR( nVal, mnRMask, mnGMask, mnBMask, mnRShift, mnGShift, mnBShift, rColor );
+}
+
+// ------------------------------------------------------------------
+
+inline void ColorMask::SetColorFor16BitMSB( const BitmapColor& rColor, HPBYTE pPixel ) const
+{
+ const UINT16 nVal = (UINT16)COLOR_TO_MASK( rColor, mnRMask, mnGMask, mnBMask, mnRShift, mnGShift, mnBShift );
+
+#ifdef OSL_BIGENDIAN
+ *(UINT16*) pPixel = nVal;
+#else
+ pPixel[ 0 ] = (BYTE)(nVal >> 8U);
+ pPixel[ 1 ] = (BYTE) nVal;
+#endif
+}
+
+// ------------------------------------------------------------------
+
+inline void ColorMask::GetColorFor16BitLSB( BitmapColor& rColor, ConstHPBYTE pPixel ) const
+{
+#ifdef OSL_BIGENDIAN
+ const UINT32 nVal = pPixel[ 0 ] | ( (UINT32) pPixel[ 1 ] << 8UL );
+#else
+ const UINT32 nVal = *(UINT16*) pPixel;
+#endif
+
+ MASK_TO_COLOR( nVal, mnRMask, mnGMask, mnBMask, mnRShift, mnGShift, mnBShift, rColor );
+}
+
+// ------------------------------------------------------------------
+
+inline void ColorMask::SetColorFor16BitLSB( const BitmapColor& rColor, HPBYTE pPixel ) const
+{
+ const UINT16 nVal = (UINT16)COLOR_TO_MASK( rColor, mnRMask, mnGMask, mnBMask, mnRShift, mnGShift, mnBShift );
+
+#ifdef OSL_BIGENDIAN
+ pPixel[ 0 ] = (BYTE) nVal;
+ pPixel[ 1 ] = (BYTE)(nVal >> 8U);
+#else
+ *(UINT16*) pPixel = nVal;
+#endif
+}
+
+
+// ------------------------------------------------------------------
+
+inline void ColorMask::GetColorFor24Bit( BitmapColor& rColor, ConstHPBYTE pPixel ) const
+{
+ const UINT32 nVal = pPixel[ 0 ] | ( (UINT32) pPixel[ 1 ] << 8UL ) | ( (UINT32) pPixel[ 2 ] << 16UL );
+ MASK_TO_COLOR( nVal, mnRMask, mnGMask, mnBMask, mnRShift, mnGShift, mnBShift, rColor );
+}
+
+// ------------------------------------------------------------------
+
+inline void ColorMask::SetColorFor24Bit( const BitmapColor& rColor, HPBYTE pPixel ) const
+{
+ const UINT32 nVal = COLOR_TO_MASK( rColor, mnRMask, mnGMask, mnBMask, mnRShift, mnGShift, mnBShift );
+ pPixel[ 0 ] = (BYTE) nVal; pPixel[ 1 ] = (BYTE) ( nVal >> 8UL ); pPixel[ 2 ] = (BYTE) ( nVal >> 16UL );
+}
+
+// ------------------------------------------------------------------
+
+inline void ColorMask::GetColorFor32Bit( BitmapColor& rColor, ConstHPBYTE pPixel ) const
+{
+#ifdef OSL_BIGENDIAN
+ const UINT32 nVal = (UINT32) pPixel[ 0 ] | ( (UINT32) pPixel[ 1 ] << 8UL ) |
+ ( (UINT32) pPixel[ 2 ] << 16UL ) | ( (UINT32) pPixel[ 3 ] << 24UL );
+#else
+ const UINT32 nVal = *(UINT32*) pPixel;
+#endif
+
+ MASK_TO_COLOR( nVal, mnRMask, mnGMask, mnBMask, mnRShift, mnGShift, mnBShift, rColor );
+}
+
+// ------------------------------------------------------------------
+
+inline void ColorMask::SetColorFor32Bit( const BitmapColor& rColor, HPBYTE pPixel ) const
+{
+#ifdef OSL_BIGENDIAN
+ const UINT32 nVal = COLOR_TO_MASK( rColor, mnRMask, mnGMask, mnBMask, mnRShift, mnGShift, mnBShift );
+ pPixel[ 0 ] = (BYTE) nVal; pPixel[ 1 ] = (BYTE) ( nVal >> 8UL );
+ pPixel[ 2 ] = (BYTE) ( nVal >> 16UL ); pPixel[ 3 ] = (BYTE) ( nVal >> 24UL );
+#else
+ *(UINT32*) pPixel = COLOR_TO_MASK( rColor, mnRMask, mnGMask, mnBMask, mnRShift, mnGShift, mnBShift );
+#endif
+}
+
+#endif // _SV_SALBTYPE_HXX
diff --git a/vcl/inc/vcl/salctrlhandle.hxx b/vcl/inc/vcl/salctrlhandle.hxx
new file mode 100644
index 000000000000..4a0a3a0f5b0a
--- /dev/null
+++ b/vcl/inc/vcl/salctrlhandle.hxx
@@ -0,0 +1,48 @@
+/*************************************************************************
+ *
+ * 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_SALCTRLHANDLE_HXX
+#define _SV_SALCTRLHANDLE_HXX
+
+/* SalControlHandle:
+ *
+ * Container for platform-specific handles and data
+ * about controls. Lives as long as the VCL control
+ * lives.
+ */
+
+class SalControlHandle
+{
+ public:
+ SalControlHandle() {}
+ virtual ~SalControlHandle();
+
+ // TODO: derive Sal implementation
+ //SalControlHandleData maData;
+};
+
+#endif
diff --git a/vcl/inc/vcl/salctype.hxx b/vcl/inc/vcl/salctype.hxx
new file mode 100644
index 000000000000..1566f02a1299
--- /dev/null
+++ b/vcl/inc/vcl/salctype.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALCTYPE_HXX
+#define _SV_SALCTYPE_HXX
+
+#include <vcl/graph.hxx>
+
+// -----------
+// - Defines -
+// -----------
+
+#define CVT_UNKNOWN (0x00000000UL)
+#define CVT_BMP (0x00000001UL)
+#define CVT_GIF (0x00000002UL)
+#define CVT_JPG (0x00000003UL)
+#define CVT_MET (0x00000004UL)
+#define CVT_PCT (0x00000005UL)
+#define CVT_PNG (0x00000006UL)
+#define CVT_SVM (0x00000007UL)
+#define CVT_TIF (0x00000008UL)
+#define CVT_WMF (0x00000009UL)
+#define CVT_EMF (0x0000000aUL)
+
+// ---------------
+// - ConvertData -
+// ---------------
+
+class SvStream;
+
+struct ConvertData
+{
+private:
+
+ ConvertData();
+
+public:
+
+ Graphic maGraphic;
+ SvStream& mrStm;
+ ULONG mnFormat;
+
+ ConvertData( const Graphic& rGraphic, SvStream& rStm, ULONG nFormat ) :
+ maGraphic( rGraphic ), mrStm( rStm ), mnFormat( nFormat ) {}
+ ~ConvertData() {}
+};
+
+// ------------
+// - Callback -
+// ------------
+
+typedef ULONG (*SALGRFCVTPROC)( void* pInst,
+ ULONG nInFormat, void* pInBuffer, ULONG nInBufSize,
+ ULONG nOutFormat, void** ppOutBuffer );
+
+#endif // _SV_SALCTYPE_HXX
diff --git a/vcl/inc/vcl/saldatabasic.hxx b/vcl/inc/vcl/saldatabasic.hxx
new file mode 100644
index 000000000000..1df2a701fd1a
--- /dev/null
+++ b/vcl/inc/vcl/saldatabasic.hxx
@@ -0,0 +1,53 @@
+/*************************************************************************
+ *
+ * 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_SALDATABASIC_HXX
+#define _SV_SALDATABASIC_HXX
+
+#include <vcl/svdata.hxx>
+#include <vcl/salinst.hxx>
+#include <osl/module.h>
+
+class VCL_DLLPUBLIC SalData
+{
+public:
+ SalInstance* m_pInstance; // pointer to instance
+ oslModule m_pPlugin; // plugin library handle
+
+ SalData();
+ virtual ~SalData();
+
+};
+
+// -=-= inlines =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+inline void SetSalData( SalData* pData )
+{ ImplGetSVData()->mpSalData = (void*)pData; }
+
+inline SalData* GetSalData()
+{ return (SalData*)ImplGetSVData()->mpSalData; }
+
+#endif
diff --git a/vcl/inc/vcl/salframe.hxx b/vcl/inc/vcl/salframe.hxx
new file mode 100644
index 000000000000..08548d7dda40
--- /dev/null
+++ b/vcl/inc/vcl/salframe.hxx
@@ -0,0 +1,293 @@
+/*************************************************************************
+ *
+ * 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_SALFRAME_HXX
+#define _SV_SALFRAME_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+
+#ifdef __cplusplus
+
+#ifndef _SV_PTRSTYLE_HXX
+#include <vcl/ptrstyle.hxx>
+#endif
+#include <vcl/sndstyle.hxx>
+
+#endif // __cplusplus
+#include <vcl/salwtype.hxx>
+#include <vcl/salgeom.hxx>
+#include <tools/gen.hxx>
+#include <vcl/region.hxx>
+
+#ifndef _VCL_IMPDEL_HXX
+#include <vcl/impdel.hxx>
+#endif
+#include <rtl/ustring.hxx>
+#include <vcl/keycod.hxx>
+
+class AllSettings;
+class SalGraphics;
+class SalBitmap;
+class SalMenu;
+class Window;
+
+
+struct SalFrameState;
+struct SalInputContext;
+struct SystemEnvData;
+
+// -----------------
+// - SalFrameTypes -
+// -----------------
+
+#define SAL_FRAME_TOTOP_RESTOREWHENMIN ((USHORT)0x0001)
+#define SAL_FRAME_TOTOP_FOREGROUNDTASK ((USHORT)0x0002)
+#define SAL_FRAME_TOTOP_GRABFOCUS ((USHORT)0x0004)
+#define SAL_FRAME_TOTOP_GRABFOCUS_ONLY ((USHORT)0x0008)
+
+#define SAL_FRAME_ENDEXTTEXTINPUT_COMPLETE ((USHORT)0x0001)
+#define SAL_FRAME_ENDEXTTEXTINPUT_CANCEL ((USHORT)0x0002)
+
+
+// -----------------
+// - SalFrameStyle -
+// -----------------
+
+#define SAL_FRAME_STYLE_DEFAULT ((ULONG)0x00000001)
+#define SAL_FRAME_STYLE_MOVEABLE ((ULONG)0x00000002)
+#define SAL_FRAME_STYLE_SIZEABLE ((ULONG)0x00000004)
+#define SAL_FRAME_STYLE_CLOSEABLE ((ULONG)0x00000008)
+
+// no shadow effect on WindowsXP
+#define SAL_FRAME_STYLE_NOSHADOW ((ULONG)0x00000010)
+// indicate tooltip windows, so they can always be topmost
+#define SAL_FRAME_STYLE_TOOLTIP ((ULONG)0x00000020)
+// windows without windowmanager decoration, this typically only applies to floating windows
+#define SAL_FRAME_STYLE_OWNERDRAWDECORATION ((ULONG)0x00000040)
+// dialogs
+#define SAL_FRAME_STYLE_DIALOG ((ULONG)0x00000080)
+// partial fullscreen: fullscreen on one monitor of a multimonitor display
+#define SAL_FRAME_STYLE_PARTIAL_FULLSCREEN ((ULONG)0x00800000)
+// plugged system child window
+#define SAL_FRAME_STYLE_PLUG ((ULONG)0x10000000)
+// system child window inside another SalFrame
+#define SAL_FRAME_STYLE_SYSTEMCHILD ((ULONG)0x08000000)
+// floating window
+#define SAL_FRAME_STYLE_FLOAT ((ULONG)0x20000000)
+// floating window that needs to be focusable
+#define SAL_FRAME_STYLE_FLOAT_FOCUSABLE ((ULONG)0x04000000)
+// toolwindows should be painted with a smaller decoration
+#define SAL_FRAME_STYLE_TOOLWINDOW ((ULONG)0x40000000)
+// the window containing the intro bitmap, aka splashscreen
+#define SAL_FRAME_STYLE_INTRO ((ULONG)0x80000000)
+
+/*
+#define SAL_FRAME_STYLE_MINABLE ((ULONG)0x00000008)
+#define SAL_FRAME_STYLE_MAXABLE ((ULONG)0x00000010)
+#define SAL_FRAME_STYLE_BORDER ((ULONG)0x00000040)
+#define SAL_FRAME_STYLE_DOC ((ULONG)0x00004000)
+#define SAL_FRAME_STYLE_DIALOG ((ULONG)0x00008000)
+#define SAL_FRAME_STYLE_TOOL ((ULONG)0x00010000)
+#define SAL_FRAME_STYLE_FULLSIZE ((ULONG)0x00020000)
+*/
+
+// ----------------------------------------
+// - extended frame style -
+// - (sal equivalent to extended WinBits) -
+// ----------------------------------------
+typedef sal_uInt64 SalExtStyle;
+#define SAL_FRAME_EXT_STYLE_DOCUMENT SalExtStyle(0x00000001)
+#define SAL_FRAME_EXT_STYLE_DOCMODIFIED SalExtStyle(0x00000002)
+
+// ------------------------
+// - Flags for SetPosSize -
+// ------------------------
+
+#define SAL_FRAME_POSSIZE_X ((USHORT)0x0001)
+#define SAL_FRAME_POSSIZE_Y ((USHORT)0x0002)
+#define SAL_FRAME_POSSIZE_WIDTH ((USHORT)0x0004)
+#define SAL_FRAME_POSSIZE_HEIGHT ((USHORT)0x0008)
+
+#ifdef __cplusplus
+
+using namespace rtl;
+
+// ------------
+// - SalFrame -
+// ------------
+
+struct SystemParentData;
+
+class VCL_DLLPUBLIC SalFrame : public vcl::DeletionNotifier
+{
+ // the VCL window corresponding to this frame
+ Window* m_pWindow;
+ SALFRAMEPROC m_pProc;
+public: // public for Sal Implementation
+ SalFrame() : m_pWindow( NULL ), m_pProc( NULL ) {}
+ virtual ~SalFrame();
+
+public: // public for Sal Implementation
+ SalFrameGeometry maGeometry;
+
+public:
+ // SalGraphics or NULL, but two Graphics for all SalFrames
+ // must be returned
+ virtual SalGraphics* GetGraphics() = 0;
+ virtual void ReleaseGraphics( SalGraphics* pGraphics ) = 0;
+
+ // Event must be destroyed, when Frame is destroyed
+ // When Event is called, SalInstance::Yield() must be returned
+ virtual BOOL PostEvent( void* pData ) = 0;
+
+ virtual void SetTitle( const XubString& rTitle ) = 0;
+ virtual void SetIcon( USHORT nIcon ) = 0;
+ virtual void SetRepresentedURL( const rtl::OUString& );
+ virtual void SetMenu( SalMenu *pSalMenu ) = 0;
+ virtual void DrawMenuBar() = 0;
+
+ virtual void SetExtendedFrameStyle( SalExtStyle nExtStyle ) = 0;
+
+ // Before the window is visible, a resize event
+ // must be sent with the correct size
+ virtual void Show( BOOL bVisible, BOOL bNoActivate = FALSE ) = 0;
+ virtual void Enable( BOOL bEnable ) = 0;
+ // Set ClientSize and Center the Window to the desktop
+ // and send/post a resize message
+ virtual void SetMinClientSize( long nWidth, long nHeight ) = 0;
+ virtual void SetMaxClientSize( long nWidth, long nHeight ) = 0;
+ virtual void SetPosSize( long nX, long nY, long nWidth, long nHeight, USHORT nFlags ) = 0;
+ virtual void GetClientSize( long& rWidth, long& rHeight ) = 0;
+ virtual void GetWorkArea( Rectangle& rRect ) = 0;
+ virtual SalFrame* GetParent() const = 0;
+ // Note: x will be mirrored at parent if UI mirroring is active
+ SalFrameGeometry GetGeometry();
+ const SalFrameGeometry& GetUnmirroredGeometry() const { return maGeometry; }
+ virtual void SetWindowState( const SalFrameState* pState ) = 0;
+ virtual BOOL GetWindowState( SalFrameState* pState ) = 0;
+ virtual void ShowFullScreen( BOOL bFullScreen, sal_Int32 nDisplay ) = 0;
+ // Enable/Disable ScreenSaver, SystemAgents, ...
+ virtual void StartPresentation( BOOL bStart ) = 0;
+ // Show Window over all other Windows
+ virtual void SetAlwaysOnTop( BOOL bOnTop ) = 0;
+
+ // Window to top and grab focus
+ virtual void ToTop( USHORT nFlags ) = 0;
+
+ // this function can call with the same
+ // pointer style
+ virtual void SetPointer( PointerStyle ePointerStyle ) = 0;
+ virtual void CaptureMouse( BOOL bMouse ) = 0;
+ virtual void SetPointerPos( long nX, long nY ) = 0;
+
+ // flush output buffer
+ virtual void Flush( void) = 0;
+ virtual void Flush( const Rectangle& );
+ // flush output buffer, wait till outstanding operations are done
+ virtual void Sync() = 0;
+
+ virtual void SetInputContext( SalInputContext* pContext ) = 0;
+ virtual void EndExtTextInput( USHORT nFlags ) = 0;
+
+ virtual String GetKeyName( USHORT nKeyCode ) = 0;
+ virtual String GetSymbolKeyName( const XubString& rFontName, USHORT nKeyCode ) = 0;
+
+ // returns in 'rKeyCode' the single keycode that translates to the given unicode when using a keyboard layout of language 'aLangType'
+ // returns FALSE if no mapping exists or function not supported
+ // this is required for advanced menu support
+ virtual BOOL MapUnicodeToKeyCode( sal_Unicode aUnicode, LanguageType aLangType, KeyCode& rKeyCode ) = 0;
+
+ // returns the input language used for the last key stroke
+ // may be LANGUAGE_DONTKNOW if not supported by the OS
+ virtual LanguageType GetInputLanguage() = 0;
+
+ virtual SalBitmap* SnapShot() = 0;
+
+ virtual void UpdateSettings( AllSettings& rSettings ) = 0;
+
+ virtual void Beep( SoundType eSoundType ) = 0;
+
+ // returns system data (most prominent: window handle)
+ virtual const SystemEnvData* GetSystemData() const = 0;
+
+ // sets a background bitmap on the frame; the implementation
+ // must not make assumptions about the lifetime of the passed SalBitmap
+ // but should copy its contents to an own buffer
+ virtual void SetBackgroundBitmap( SalBitmap* ) = 0;
+
+
+ // get current modifier, button mask and mouse position
+ struct SalPointerState
+ {
+ ULONG mnState;
+ Point maPos; // in frame coordinates
+ };
+
+ virtual SalPointerState GetPointerState() = 0;
+
+ // set new parent window
+ virtual void SetParent( SalFrame* pNewParent ) = 0;
+ // reparent window to act as a plugin; implementation
+ // may choose to use a new system window inetrnally
+ // return false to indicate failure
+ virtual bool SetPluginParent( SystemParentData* pNewParent ) = 0;
+
+ // move the frame to a new screen
+ virtual void SetScreenNumber( unsigned int nScreen ) = 0;
+
+ // shaped system windows
+ // set clip region to none (-> rectangular windows, normal state)
+ virtual void ResetClipRegion() = 0;
+ // start setting the clipregion consisting of nRects rectangles
+ virtual void BeginSetClipRegion( ULONG nRects ) = 0;
+ // add a rectangle to the clip region
+ virtual void UnionClipRegion( long nX, long nY, long nWidth, long nHeight ) = 0;
+ // done setting up the clipregion
+ virtual void EndSetClipRegion() = 0;
+
+
+ // Callbacks (indepent part in vcl/source/window/winproc.cxx)
+ // for default message handling return 0
+ void SetCallback( Window* pWindow, SALFRAMEPROC pProc )
+ { m_pWindow = pWindow; m_pProc = pProc; }
+
+ // returns the instance set
+ Window* GetWindow() const { return m_pWindow; }
+
+ // Call the callback set; this sometimes necessary for implementation classes
+ // that should not now more than necessary about the SalFrame implementation
+ // (e.g. input methods, printer update handlers).
+ long CallCallback( USHORT nEvent, const void* pEvent ) const
+ { return m_pProc ? m_pProc( m_pWindow, const_cast<SalFrame*>(this), nEvent, pEvent ) : 0; }
+};
+
+
+
+#endif // __cplusplus
+
+#endif // _SV_SALFRAME_HXX
diff --git a/vcl/inc/vcl/salgdi.hxx b/vcl/inc/vcl/salgdi.hxx
new file mode 100644
index 000000000000..08c489f7d466
--- /dev/null
+++ b/vcl/inc/vcl/salgdi.hxx
@@ -0,0 +1,494 @@
+/*************************************************************************
+ *
+ * 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_SALGDI_HXX
+#define _SV_SALGDI_HXX
+
+#include "tools/string.hxx"
+#include "rtl/ustring.hxx"
+#include "vcl/sv.h"
+#include "vcl/dllapi.h"
+#include "vcl/salgtype.hxx"
+#include "vos/thread.hxx"
+#include "vcl/outdev.hxx"
+#include "vcl/salnativewidgets.hxx"
+#include "vcl/salctrlhandle.hxx"
+
+#include <map>
+
+class ImplDevFontList;
+class SalBitmap;
+class ImplFontSelectData;
+class ImplFontMetricData;
+struct ImplKernPairData;
+class ImplFontData;
+class ImplFontCharMap;
+class SalLayout;
+class ImplLayoutArgs;
+class Rectangle;
+class FontSubsetInfo;
+class OutputDevice;
+class ServerFontLayout;
+struct SystemGraphicsData;
+struct SystemFontData;
+
+namespace basegfx {
+ class B2DVector;
+ class B2DPolygon;
+ class B2DPolyPolygon;
+}
+
+// ---------------------
+// - SalGraphics-Codes -
+// ---------------------
+
+#define SAL_SETFONT_REMOVEANDMATCHNEW ((USHORT)0x0001)
+#define SAL_SETFONT_USEDRAWTEXT ((USHORT)0x0002)
+#define SAL_SETFONT_USEDRAWTEXTARRAY ((USHORT)0x0004)
+#define SAL_SETFONT_UNICODE ((USHORT)0x0008)
+#define SAL_SETFONT_BADFONT ((USHORT)0x1000)
+
+#define SAL_COPYAREA_WINDOWINVALIDATE ((USHORT)0x0001)
+
+// -------------------
+// - common typedefs -
+// -------------------
+
+typedef sal_Unicode sal_Ucs; // TODO: use sal_UCS4 instead of sal_Unicode
+typedef std::map< sal_Ucs, sal_Int32 > Ucs2SIntMap;
+typedef std::map< sal_Ucs, sal_uInt32 > Ucs2UIntMap;
+typedef std::map< sal_Ucs, rtl::OString > Ucs2OStrMap;
+typedef std::vector< sal_Int32 > Int32Vector;
+
+// ---------------
+// - SalGraphics -
+// ---------------
+
+// note: if you add any new methods to class SalGraphics using coordinates
+// make sure they have a corresponding protected pure virtual method
+// which has to be implemented by the platform dependent part.
+// Add a method that performs coordinate mirroring if required, (see
+// existing methods as sample) and then calls the equivalent pure method.
+
+// note: all positions are in pixel and relative to
+// the top/left-position of the virtual output area
+
+class VCL_DLLPUBLIC SalGraphics
+{
+ int m_nLayout; // 0: mirroring off, 1: mirror x-axis
+
+protected:
+ // flags which hold the SetAntialiasing() value from OutputDevice
+ bool m_bAntiAliasB2DDraw;
+
+public:
+ // get/set AA
+ void setAntiAliasB2DDraw(bool bNew) { m_bAntiAliasB2DDraw = bNew; }
+ bool getAntiAliasB2DDraw() const { return m_bAntiAliasB2DDraw; }
+
+ SalGraphics();
+ virtual ~SalGraphics();
+
+protected:
+ virtual BOOL unionClipRegion( long nX, long nY, long nWidth, long nHeight ) = 0;
+ virtual bool unionClipRegion( const ::basegfx::B2DPolyPolygon& ) = 0;
+ // draw --> LineColor and FillColor and RasterOp and ClipRegion
+ virtual void drawPixel( long nX, long nY ) = 0;
+ virtual void drawPixel( long nX, long nY, SalColor nSalColor ) = 0;
+ virtual void drawLine( long nX1, long nY1, long nX2, long nY2 ) = 0;
+ virtual void drawRect( long nX, long nY, long nWidth, long nHeight ) = 0;
+ virtual void drawPolyLine( ULONG nPoints, const SalPoint* pPtAry ) = 0;
+ virtual void drawPolygon( ULONG nPoints, const SalPoint* pPtAry ) = 0;
+ virtual void drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ) = 0;
+ virtual bool drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double fTransparency ) = 0;
+ virtual bool drawPolyLine( const ::basegfx::B2DPolygon&, double fTransparency, const ::basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin ) = 0;
+ virtual sal_Bool drawPolyLineBezier( ULONG nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry ) = 0;
+ virtual sal_Bool drawPolygonBezier( ULONG nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry ) = 0;
+ virtual sal_Bool drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* pPoints, const SalPoint* const* pPtAry, const BYTE* const* pFlgAry ) = 0;
+
+ // CopyArea --> No RasterOp, but ClipRegion
+ virtual void copyArea( long nDestX, long nDestY, long nSrcX, long nSrcY, long nSrcWidth,
+ long nSrcHeight, USHORT nFlags ) = 0;
+
+ // CopyBits and DrawBitmap --> RasterOp and ClipRegion
+ // CopyBits() --> pSrcGraphics == NULL, then CopyBits on same Graphics
+ virtual void copyBits( const SalTwoRect* pPosAry, SalGraphics* pSrcGraphics ) = 0;
+ virtual void drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap ) = 0;
+ virtual void drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ SalColor nTransparentColor ) = 0;
+ virtual void drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ const SalBitmap& rMaskBitmap ) = 0;
+ virtual void drawMask( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ SalColor nMaskColor ) = 0;
+
+ virtual SalBitmap* getBitmap( long nX, long nY, long nWidth, long nHeight ) = 0;
+ virtual SalColor getPixel( long nX, long nY ) = 0;
+
+ // invert --> ClipRegion (only Windows or VirDevs)
+ virtual void invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags) = 0;
+ virtual void invert( ULONG nPoints, const SalPoint* pPtAry, SalInvert nFlags ) = 0;
+
+ virtual BOOL drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, ULONG nSize ) = 0;
+
+ // native widget rendering methods that require mirroring
+ virtual BOOL hitTestNativeControl( ControlType nType, ControlPart nPart, const Region& rControlRegion,
+ const Point& aPos, BOOL& rIsInside );
+ virtual BOOL drawNativeControl( ControlType nType, ControlPart nPart, const Region& rControlRegion,
+ ControlState nState, const ImplControlValue& aValue,
+ const rtl::OUString& aCaption );
+ virtual BOOL drawNativeControlText( ControlType nType, ControlPart nPart, const Region& rControlRegion,
+ ControlState nState, const ImplControlValue& aValue,
+ const rtl::OUString& aCaption );
+ virtual BOOL getNativeControlRegion( ControlType nType, ControlPart nPart, const Region& rControlRegion, ControlState nState,
+ const ImplControlValue& aValue, const rtl::OUString& aCaption,
+ Region &rNativeBoundingRegion, Region &rNativeContentRegion );
+
+ /** Render bitmap with alpha channel
+
+ @param rSourceBitmap
+ Source bitmap to blit
+
+ @param rAlphaBitmap
+ Alpha channel to use for blitting
+
+ @return true, if the operation succeeded, and false
+ otherwise. In this case, clients should try to emulate alpha
+ compositing themselves
+ */
+ virtual bool drawAlphaBitmap( const SalTwoRect&,
+ const SalBitmap& rSourceBitmap,
+ const SalBitmap& rAlphaBitmap ) = 0;
+ /** Render solid rectangle with given transparency
+
+ @param nTransparency
+ Transparency value (0-255) to use. 0 blits and opaque, 255 a
+ fully transparent rectangle
+ */
+ virtual bool drawAlphaRect( long nX, long nY, long nWidth, long nHeight, sal_uInt8 nTransparency ) = 0;
+
+public:
+ // public SalGraphics methods, the interface to the independent vcl part
+
+ // get device resolution
+ virtual void GetResolution( sal_Int32& rDPIX, sal_Int32& rDPIY ) = 0;
+ // get the depth of the device
+ virtual USHORT GetBitCount() = 0;
+ // get the width of the device
+ virtual long GetGraphicsWidth() const = 0;
+
+ // set the clip region to empty
+ virtual void ResetClipRegion() = 0;
+ // begin setting the clip region, add rectangles to the
+ // region with the UnionClipRegion call
+ virtual void BeginSetClipRegion( ULONG nCount ) = 0;
+ // all rectangles were added and the clip region should be set now
+ virtual void EndSetClipRegion() = 0;
+
+ // set the line color to transparent (= don't draw lines)
+ virtual void SetLineColor() = 0;
+ // set the line color to a specific color
+ virtual void SetLineColor( SalColor nSalColor ) = 0;
+ // set the fill color to transparent (= don't fill)
+ virtual void SetFillColor() = 0;
+ // set the fill color to a specific color, shapes will be
+ // filled accordingly
+ virtual void SetFillColor( SalColor nSalColor ) = 0;
+ // enable/disable XOR drawing
+ virtual void SetXORMode( bool bSet, bool bInvertOnly ) = 0;
+ // set line color for raster operations
+ virtual void SetROPLineColor( SalROPColor nROPColor ) = 0;
+ // set fill color for raster operations
+ virtual void SetROPFillColor( SalROPColor nROPColor ) = 0;
+ // set the text color to a specific color
+ virtual void SetTextColor( SalColor nSalColor ) = 0;
+ // set the font
+ virtual USHORT SetFont( ImplFontSelectData*, int nFallbackLevel ) = 0;
+ // release the fonts
+ void ReleaseFonts() { SetFont( NULL, 0 ); }
+ // get the current font's metrics
+ virtual void GetFontMetric( ImplFontMetricData* ) = 0;
+
+ // get kernign pairs of the current font
+ // return only PairCount if (pKernPairs == NULL)
+ virtual ULONG GetKernPairs( ULONG nMaxPairCount, ImplKernPairData* ) = 0;
+ // get the repertoire of the current font
+ virtual ImplFontCharMap* GetImplFontCharMap() const = 0;
+ // graphics must fill supplied font list
+ virtual void GetDevFontList( ImplDevFontList* ) = 0;
+ // graphics should call ImplAddDevFontSubstitute on supplied
+ // OutputDevice for all its device specific preferred font substitutions
+ virtual void GetDevFontSubstList( OutputDevice* ) = 0;
+ virtual bool AddTempDevFont( ImplDevFontList*, const String& rFileURL, const String& rFontName ) = 0;
+ // CreateFontSubset: a method to get a subset of glyhps of a font
+ // inside a new valid font file
+ // returns TRUE if creation of subset was successfull
+ // parameters: rToFile: contains a osl file URL to write the subset to
+ // pFont: describes from which font to create a subset
+ // pGlyphIDs: the glyph ids to be extracted
+ // pEncoding: the character code corresponding to each glyph
+ // pWidths: the advance widths of the correspoding glyphs (in PS font units)
+ // nGlyphs: the number of glyphs
+ // rInfo: additional outgoing information
+ // implementation note: encoding 0 with glyph id 0 should be added implicitly
+ // as "undefined character"
+ virtual BOOL CreateFontSubset( const rtl::OUString& rToFile,
+ const ImplFontData* pFont,
+ sal_Int32* pGlyphIDs,
+ sal_uInt8* pEncoding,
+ sal_Int32* pWidths,
+ int nGlyphs,
+ FontSubsetInfo& rInfo // out parameter
+ ) = 0;
+
+ // GetFontEncodingVector: a method to get the encoding map Unicode
+ // to font encoded character; this is only used for type1 fonts and
+ // may return NULL in case of unknown encoding vector
+ // if ppNonEncoded is set and non encoded characters (that is type1
+ // glyphs with only a name) exist it is set to the corresponding
+ // map for non encoded glyphs; the encoding vector contains -1
+ // as encoding for these cases
+ virtual const Ucs2SIntMap* GetFontEncodingVector( const ImplFontData*, const Ucs2OStrMap** ppNonEncoded ) = 0;
+
+ // GetEmbedFontData: gets the font data for a font marked
+ // embeddable by GetDevFontList or NULL in case of error
+ // parameters: pFont: describes the font in question
+ // pUnicodes: contains the Unicodes assigned to
+ // code points 0 to 255; must contain at least 256 members
+ // pWidths: the widths of all glyphs from char code 0 to 255
+ // pWidths MUST support at least 256 members;
+ // rInfo: additional outgoing information
+ // pDataLen: out parameter, contains the byte length of the returned buffer
+ virtual const void* GetEmbedFontData( const ImplFontData* pFont,
+ const sal_Ucs* pUnicodes,
+ sal_Int32* pWidths,
+ FontSubsetInfo& rInfo,
+ long* pDataLen ) = 0;
+ // frees the font data again
+ virtual void FreeEmbedFontData( const void* pData, long nDataLen ) = 0;
+
+ // get the same widths as in CreateFontSubset and GetEmbedFontData
+ // in case of an embeddable font also fill the mapping
+ // between unicode and glyph id
+ // leave widths vector and mapping untouched in case of failure
+ virtual void GetGlyphWidths( const ImplFontData* pFont,
+ bool bVertical,
+ Int32Vector& rWidths,
+ Ucs2UIntMap& rUnicodeEnc ) = 0;
+
+ virtual BOOL GetGlyphBoundRect( long nIndex, Rectangle& ) = 0;
+ virtual BOOL GetGlyphOutline( long nIndex, basegfx::B2DPolyPolygon& ) = 0;
+
+ virtual SalLayout* GetTextLayout( ImplLayoutArgs&, int nFallbackLevel ) = 0;
+ virtual void DrawServerFontLayout( const ServerFontLayout& ) = 0;
+ /** Filter text from DrawText commands in a device specific manner
+ <p>
+ This function allows a device (or rather the corresponding SalGraphics
+ implementation) to prevent text portions from being drawn. This currently
+ is used only for filtering out the fax number in a document that is printed
+ to one of psprint's specialized "fax" printers.
+ </p>
+
+ @param rOrigText
+ The original text
+
+ @param rNewText
+ A String that will be filled with the adjusted version
+
+ @param nIndex
+ The index inside <code>rOrigText</code> that marks the first draw character
+
+ @param rLen
+ in: length of text beginning at <code>nIndex</code> to be drawn
+ out: length of <code>rNewText</code> containing the substituted text
+
+ @param rCutStart
+ out: index at which the cutout portion of <code>rOrigText</code> begins
+
+ @param rCutStop
+ out: index at which the cutout portion of <code>rOrigText</code> ends
+
+ @returns
+ true: a substitution has taken place and rNewText rLen, rCutStart and rCutStop have been filled accordingly
+ false: no substitution has taken place, rNewText, rLen, rCutStart, rCutStop remain unchanged
+ */
+ virtual bool filterText( const String& rOrigText, String& rNewText, xub_StrLen nIndex, xub_StrLen& rLen, xub_StrLen& rCutStart, xub_StrLen& rCutStop );
+
+ virtual bool supportsOperation( OutDevSupportType ) const = 0;
+
+ // mirroring specifica
+ int GetLayout() { return m_nLayout; }
+ void SetLayout( int aLayout ) { m_nLayout = aLayout;}
+
+ void mirror( long& nX, const OutputDevice *pOutDev, bool bBack = false ) const;
+ void mirror( long& nX, long& nWidth, const OutputDevice *pOutDev, bool bBack = false ) const;
+ BOOL mirror( sal_uInt32 nPoints, const SalPoint *pPtAry, SalPoint *pPtAry2, const OutputDevice *pOutDev, bool bBack = false ) const;
+ void mirror( Rectangle& rRect, const OutputDevice*, bool bBack = false ) const;
+ void mirror( Region& rRgn, const OutputDevice *pOutDev, bool bBack = false ) const;
+ void mirror( ControlType,const ImplControlValue&,const OutputDevice*,bool bBack = false) const;
+ basegfx::B2DPoint mirror( const basegfx::B2DPoint& i_rPoint, const OutputDevice *pOutDev, bool bBack = false ) const;
+ basegfx::B2DPolygon mirror( const basegfx::B2DPolygon& i_rPoly, const OutputDevice *pOutDev, bool bBack = false ) const;
+ basegfx::B2DPolyPolygon mirror( const basegfx::B2DPolyPolygon& i_rPoly, const OutputDevice *pOutDev, bool bBack = false ) const;
+
+ // non virtual methods; these do eventual coordinate mirroring and
+ // then delegate to protected virtual methods
+ BOOL UnionClipRegion( long nX, long nY, long nWidth, long nHeight, const OutputDevice *pOutDev );
+ BOOL UnionClipRegion( const ::basegfx::B2DPolyPolygon&, const OutputDevice* );
+
+ // draw --> LineColor and FillColor and RasterOp and ClipRegion
+ void DrawPixel( long nX, long nY, const OutputDevice *pOutDev );
+ void DrawPixel( long nX, long nY, SalColor nSalColor, const OutputDevice *pOutDev );
+ void DrawLine( long nX1, long nY1, long nX2, long nY2, const OutputDevice *pOutDev );
+ void DrawRect( long nX, long nY, long nWidth, long nHeight, const OutputDevice *pOutDev );
+ void DrawPolyLine( ULONG nPoints, const SalPoint* pPtAry, const OutputDevice *pOutDev );
+ void DrawPolygon( ULONG nPoints, const SalPoint* pPtAry, const OutputDevice *pOutDev );
+ void DrawPolyPolygon( sal_uInt32 nPoly,
+ const sal_uInt32* pPoints,
+ PCONSTSALPOINT* pPtAry,
+ const OutputDevice *pOutDev );
+ bool DrawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double fTransparency, const OutputDevice* );
+ bool DrawPolyLine( const basegfx::B2DPolygon&, double fTransparency, const basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin, const OutputDevice* );
+ sal_Bool DrawPolyLineBezier( ULONG nPoints,
+ const SalPoint* pPtAry,
+ const BYTE* pFlgAry,
+ const OutputDevice *pOutDev );
+ sal_Bool DrawPolygonBezier( ULONG nPoints,
+ const SalPoint* pPtAry,
+ const BYTE* pFlgAry,
+ const OutputDevice *pOutDev );
+ sal_Bool DrawPolyPolygonBezier( sal_uInt32 nPoly,
+ const sal_uInt32* pPoints,
+ const SalPoint* const* pPtAry,
+ const BYTE* const* pFlgAry,
+ const OutputDevice *pOutDev );
+
+ // CopyArea --> No RasterOp, but ClipRegion
+ void CopyArea( long nDestX,
+ long nDestY,
+ long nSrcX,
+ long nSrcY,
+ long nSrcWidth,
+ long nSrcHeight,
+ USHORT nFlags,
+ const OutputDevice *pOutDev );
+
+ // CopyBits and DrawBitmap --> RasterOp and ClipRegion
+ // CopyBits() --> pSrcGraphics == NULL, then CopyBits on same Graphics
+ void CopyBits( const SalTwoRect* pPosAry,
+ SalGraphics* pSrcGraphics,
+ const OutputDevice *pOutDev,
+ const OutputDevice *pSrcOutDev );
+ void DrawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ const OutputDevice *pOutDev );
+ void DrawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ SalColor nTransparentColor,
+ const OutputDevice *pOutDev );
+ void DrawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ const SalBitmap& rTransparentBitmap,
+ const OutputDevice *pOutDev );
+
+ void DrawMask( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ SalColor nMaskColor,
+ const OutputDevice *pOutDev );
+
+ SalBitmap* GetBitmap( long nX, long nY, long nWidth, long nHeight, const OutputDevice *pOutDev );
+ SalColor GetPixel( long nX, long nY, const OutputDevice *pOutDev );
+
+ // invert --> ClipRegion (only Windows)
+ void Invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags, const OutputDevice *pOutDev );
+ void Invert( ULONG nPoints, const SalPoint* pPtAry, SalInvert nFlags, const OutputDevice *pOutDev );
+
+ BOOL DrawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, ULONG nSize, const OutputDevice *pOutDev );
+
+ //-------------------------------------
+ // Native Widget Rendering functions
+ //-------------------------------------
+
+ // Query the platform layer for control support
+ virtual BOOL IsNativeControlSupported( ControlType nType, ControlPart nPart );
+
+ // Query the native control to determine if it was acted upon
+ BOOL HitTestNativeControl( ControlType nType,
+ ControlPart nPart,
+ const Region& rControlRegion,
+ const Point& aPos,
+ BOOL& rIsInside,
+ const OutputDevice *pOutDev );
+
+ // Request rendering of a particular control and/or part
+ BOOL DrawNativeControl( ControlType nType,
+ ControlPart nPart,
+ const Region& rControlRegion,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const rtl::OUString& aCaption,
+ const OutputDevice *pOutDev );
+
+ // Request rendering of a caption string for a control
+ BOOL DrawNativeControlText( ControlType nType,
+ ControlPart nPart,
+ const Region& rControlRegion,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const rtl::OUString& aCaption,
+ const OutputDevice *pOutDev );
+
+ // Query the native control's actual drawing region (including adornment)
+ BOOL GetNativeControlRegion( ControlType nType,
+ ControlPart nPart,
+ const Region& rControlRegion,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const rtl::OUString& aCaption,
+ Region &rNativeBoundingRegion,
+ Region &rNativeContentRegion,
+ const OutputDevice *pOutDev );
+
+ static void AddDevFontSubstitute( OutputDevice* pOutDev,
+ const String& rFontName,
+ const String& rReplaceFontName,
+ USHORT nFlags = 0 );
+
+ bool DrawAlphaBitmap( const SalTwoRect&,
+ const SalBitmap& rSourceBitmap,
+ const SalBitmap& rAlphaBitmap,
+ const OutputDevice *pOutDev );
+
+ bool DrawAlphaRect( long nX, long nY, long nWidth, long nHeight,
+ sal_uInt8 nTransparency, const OutputDevice *pOutDev );
+
+ virtual SystemGraphicsData GetGraphicsData() const = 0;
+ virtual SystemFontData GetSysFontData( int nFallbacklevel ) const = 0;
+};
+
+#endif // _SV_SALGDI_HXX
diff --git a/vcl/inc/vcl/salgeom.hxx b/vcl/inc/vcl/salgeom.hxx
new file mode 100644
index 000000000000..3d59e6199fa7
--- /dev/null
+++ b/vcl/inc/vcl/salgeom.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALGEOM_HXX
+#define _SV_SALGEOM_HXX
+
+typedef struct _SalFrameGeometry {
+ // screen position of upper left corner of drawable area in pixel
+ long nX, nY;
+ // dimensions of the drawable area in pixel
+ unsigned long nWidth, nHeight;
+ // thickness of the decoration in pixel
+ unsigned long nLeftDecoration,
+ nTopDecoration,
+ nRightDecoration,
+ nBottomDecoration;
+ unsigned int nScreenNumber;
+
+ _SalFrameGeometry() :
+ nX( 0 ), nY( 0 ), nWidth( 1 ), nHeight( 1 ),
+ nLeftDecoration( 0 ), nTopDecoration( 0 ),
+ nRightDecoration( 0 ), nBottomDecoration( 0 ),
+ nScreenNumber( 0 )
+ {}
+} SalFrameGeometry;
+
+#endif // _SV_SALGEOM_HXX
diff --git a/vcl/inc/vcl/salgtype.hxx b/vcl/inc/vcl/salgtype.hxx
new file mode 100644
index 000000000000..f70a5c532f73
--- /dev/null
+++ b/vcl/inc/vcl/salgtype.hxx
@@ -0,0 +1,90 @@
+/*************************************************************************
+ *
+ * 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_SALGTYPE_HXX
+#define _SV_SALGTYPE_HXX
+
+#include <vcl/sv.h>
+
+// ------------
+// - SalColor -
+// ------------
+
+typedef UINT32 SalColor;
+#define MAKE_SALCOLOR( r, g, b ) ((SalColor)(((UINT32)((UINT8)(b))))|(((UINT32)((UINT8)(g)))<<8)|(((UINT32)((UINT8)(r)))<<16))
+#define SALCOLOR_RED( n ) ((UINT8)((n)>>16))
+#define SALCOLOR_GREEN( n ) ((UINT8)(((UINT16)(n)) >> 8))
+#define SALCOLOR_BLUE( n ) ((UINT8)(n))
+#define SALCOLOR_NONE (~(SalColor)0)
+// ------------
+// - SalPoint -
+// ------------
+
+// must equal to class Point
+struct SalPoint
+{
+ long mnX;
+ long mnY;
+};
+
+typedef const SalPoint* PCONSTSALPOINT;
+
+// --------------
+// - SalTwoRect -
+// --------------
+
+struct SalTwoRect
+{
+ long mnSrcX;
+ long mnSrcY;
+ long mnSrcWidth;
+ long mnSrcHeight;
+ long mnDestX;
+ long mnDestY;
+ long mnDestWidth;
+ long mnDestHeight;
+};
+
+// ---------------
+// - SalROPColor -
+// ---------------
+
+typedef USHORT SalROPColor;
+#define SAL_ROP_0 ((SalROPColor)0)
+#define SAL_ROP_1 ((SalROPColor)1)
+#define SAL_ROP_INVERT ((SalROPColor)2)
+
+// -------------
+// - SalInvert -
+// -------------
+
+typedef USHORT SalInvert;
+#define SAL_INVERT_HIGHLIGHT ((SalInvert)0x0001)
+#define SAL_INVERT_50 ((SalInvert)0x0002)
+#define SAL_INVERT_TRACKFRAME ((SalInvert)0x0004)
+
+#endif // _SV_SALGTYPE_HXX
diff --git a/vcl/inc/vcl/salimestatus.hxx b/vcl/inc/vcl/salimestatus.hxx
new file mode 100644
index 000000000000..779a75c9afaa
--- /dev/null
+++ b/vcl/inc/vcl/salimestatus.hxx
@@ -0,0 +1,45 @@
+/*************************************************************************
+ *
+ * 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_SALIMESTATUS_HXX
+#define _SV_SALIMESTATUS_HXX
+
+#include <vcl/dllapi.h>
+
+class VCL_DLLPUBLIC SalI18NImeStatus
+{
+public:
+ SalI18NImeStatus() {}
+ virtual ~SalI18NImeStatus();
+
+ // asks whether there is a status window available
+ // to toggle into menubar
+ virtual bool canToggle() = 0;
+ virtual void toggle() = 0;
+};
+
+#endif
diff --git a/vcl/inc/vcl/salinst.hxx b/vcl/inc/vcl/salinst.hxx
new file mode 100644
index 000000000000..9b92bf95e3fe
--- /dev/null
+++ b/vcl/inc/vcl/salinst.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALINST_HXX
+#define _SV_SALINST_HXX
+
+#include "com/sun/star/uno/Reference.hxx"
+
+#include "vcl/sv.h"
+#include "vcl/dllapi.h"
+
+#include "tools/string.hxx"
+
+#include "rtl/string.hxx"
+
+#include <list>
+
+struct SystemParentData;
+struct SalPrinterQueueInfo;
+struct SalStatus;
+struct ImplJobSetup;
+class SalGraphics;
+class SalFrame;
+class SalObject;
+class SalMenu;
+class SalMenuItem;
+class SalVirtualDevice;
+class SalInfoPrinter;
+class SalPrinter;
+class SalTimer;
+class ImplPrnQueueList;
+class SalI18NImeStatus;
+class SalSystem;
+class SalBitmap;
+struct SalItemParams;
+class SalSession;
+struct SystemGraphicsData;
+struct SystemWindowData;
+
+namespace vos { class IMutex; }
+
+// ---------------
+// - SalInstance -
+// ---------------
+
+class VCL_DLLPUBLIC SalInstance
+{
+public:
+ typedef bool(*Callback)(void*,void*,int);
+private:
+ void* m_pEventInst;
+ void* m_pErrorInst;
+ Callback m_pEventCallback;
+ Callback m_pErrorCallback;
+
+public:
+ SalInstance() :
+ m_pEventInst( NULL ),
+ m_pErrorInst( NULL ),
+ m_pEventCallback( NULL ),
+ m_pErrorCallback( NULL )
+ {}
+ virtual ~SalInstance();
+
+ // Frame
+ // DisplayName for Unix ???
+ virtual SalFrame* CreateChildFrame( SystemParentData* pParent, ULONG nStyle ) = 0;
+ virtual SalFrame* CreateFrame( SalFrame* pParent, ULONG nStyle ) = 0;
+ virtual void DestroyFrame( SalFrame* pFrame ) = 0;
+
+ // Object (System Child Window)
+ virtual SalObject* CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, BOOL bShow = TRUE ) = 0;
+ virtual void DestroyObject( SalObject* pObject ) = 0;
+
+ // VirtualDevice
+ // nDX and nDY in Pixel
+ // nBitCount: 0 == Default(=as window) / 1 == Mono
+ // pData allows for using a system dependent graphics or device context
+ virtual SalVirtualDevice* CreateVirtualDevice( SalGraphics* pGraphics,
+ long nDX, long nDY,
+ USHORT nBitCount, const SystemGraphicsData *pData = NULL ) = 0;
+ virtual void DestroyVirtualDevice( SalVirtualDevice* pDevice ) = 0;
+
+ // Printer
+ // pSetupData->mpDriverData can be 0
+ // pSetupData must be updatet with the current
+ // JobSetup
+ virtual SalInfoPrinter* CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
+ ImplJobSetup* pSetupData ) = 0;
+ virtual void DestroyInfoPrinter( SalInfoPrinter* pPrinter ) = 0;
+ virtual SalPrinter* CreatePrinter( SalInfoPrinter* pInfoPrinter ) = 0;
+ virtual void DestroyPrinter( SalPrinter* pPrinter ) = 0;
+
+ virtual void GetPrinterQueueInfo( ImplPrnQueueList* pList ) = 0;
+ virtual void GetPrinterQueueState( SalPrinterQueueInfo* pInfo ) = 0;
+ virtual void DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo ) = 0;
+ virtual String GetDefaultPrinter() = 0;
+
+ // SalTimer
+ virtual SalTimer* CreateSalTimer() = 0;
+ // SalI18NImeStatus
+ virtual SalI18NImeStatus* CreateI18NImeStatus() = 0;
+ // SalSystem
+ virtual SalSystem* CreateSalSystem() = 0;
+ // SalBitmap
+ virtual SalBitmap* CreateSalBitmap() = 0;
+
+ // YieldMutex
+ virtual vos::IMutex* GetYieldMutex() = 0;
+ virtual ULONG ReleaseYieldMutex() = 0;
+ virtual void AcquireYieldMutex( ULONG nCount ) = 0;
+
+ // wait next event and dispatch
+ // must returned by UserEvent (SalFrame::PostEvent)
+ // and timer
+ virtual void Yield( bool bWait, bool bHandleAllCurrentEvents ) = 0;
+ virtual bool AnyInput( USHORT nType ) = 0;
+
+ // Menues
+ virtual SalMenu* CreateMenu( BOOL bMenuBar ) = 0;
+ virtual void DestroyMenu( SalMenu* pMenu) = 0;
+ virtual SalMenuItem* CreateMenuItem( const SalItemParams* pItemData ) = 0;
+ virtual void DestroyMenuItem( SalMenuItem* pItem ) = 0;
+
+ // may return NULL to disable session management
+ virtual SalSession* CreateSalSession() = 0;
+
+ // methods for XDisplayConnection
+
+ // the parameters for the callbacks are:
+ // void* pInst: pInstance form the SetCallback call
+ // void* pEvent: address of the system specific event structure
+ // int nBytes: length of the system specific event structure
+ void SetEventCallback( void* pInstance, Callback pCallback )
+ { m_pEventInst = pInstance; m_pEventCallback = pCallback; }
+ Callback GetEventCallback() const
+ { return m_pEventCallback; }
+ bool CallEventCallback( void* pEvent, int nBytes )
+ { return m_pEventCallback ? m_pEventCallback( m_pEventInst, pEvent, nBytes ) : false; }
+ void SetErrorEventCallback( void* pInstance, Callback pCallback )
+ { m_pErrorInst = pInstance; m_pErrorCallback = pCallback; }
+ Callback GetErrorEventCallback() const
+ { return m_pErrorCallback; }
+ bool CallErrorCallback( void* pEvent, int nBytes )
+ { return m_pErrorCallback ? m_pErrorCallback( m_pErrorInst, pEvent, nBytes ) : false; }
+
+ enum ConnectionIdentifierType { AsciiCString, Blob };
+ virtual void* GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes ) = 0;
+
+ // this is a vehicle for PrintFontManager to bridge the gap between vcl and libvclplug_*
+ // this is only necessary because PrintFontManager is an exported vcl API and therefore
+ // needs to be in libvcl while libvclplug_* do not contain exported C++ API
+ virtual void FillFontPathList( std::list< rtl::OString >& o_rFontPaths );
+
+ // dtrans implementation
+ virtual com::sun::star::uno::Reference< com::sun::star::uno::XInterface >
+ CreateClipboard( const com::sun::star::uno::Sequence< com::sun::star::uno::Any >& i_rArguments );
+ virtual com::sun::star::uno::Reference< com::sun::star::uno::XInterface > CreateDragSource();
+ virtual com::sun::star::uno::Reference< com::sun::star::uno::XInterface > CreateDropTarget();
+ virtual void AddToRecentDocumentList(const rtl::OUString& rFileUrl, const rtl::OUString& rMimeType) = 0;
+};
+
+// called from SVMain
+SalInstance* CreateSalInstance();
+void DestroySalInstance( SalInstance* pInst );
+
+// -------------------------
+// - SalInstance-Functions -
+// -------------------------
+
+void SalAbort( const XubString& rErrorText );
+
+VCL_DLLPUBLIC const ::rtl::OUString& SalGetDesktopEnvironment();
+
+// -----------
+// - SalData -
+// -----------
+
+void InitSalData(); // called from Application-Ctor
+void DeInitSalData(); // called from Application-Dtor
+
+void InitSalMain();
+void DeInitSalMain();
+
+// ----------
+// - SVMain -
+// ----------
+
+// Callbacks (indepen in \sv\source\app\svmain.cxx)
+VCL_DLLPUBLIC BOOL SVMain();
+
+#endif // _SV_SALINST_HXX
diff --git a/vcl/inc/vcl/sallayout.hxx b/vcl/inc/vcl/sallayout.hxx
new file mode 100755
index 000000000000..e23090c42392
--- /dev/null
+++ b/vcl/inc/vcl/sallayout.hxx
@@ -0,0 +1,390 @@
+/*************************************************************************
+ *
+ * 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_SALLAYOUT_HXX
+#define _SV_SALLAYOUT_HXX
+
+#include <tools/gen.hxx>
+
+#include <vector>
+namespace basegfx {
+ class B2DPolyPolygon;
+ typedef std::vector<B2DPolyPolygon> B2DPolyPolygonVector;
+}
+
+#ifndef _TOOLS_LANG_HXX
+typedef unsigned short LanguageType;
+#endif
+
+#include <vector>
+#include <list>
+#include <vcl/dllapi.h>
+
+// for typedef sal_UCS4
+#include <vcl/vclenum.hxx>
+
+class SalGraphics;
+class ImplFontData;
+
+#define MAX_FALLBACK 16
+
+// ----------------
+// - LayoutOption -
+// ----------------
+
+#define SAL_LAYOUT_BIDI_RTL 0x0001
+#define SAL_LAYOUT_BIDI_STRONG 0x0002
+#define SAL_LAYOUT_RIGHT_ALIGN 0x0004
+#define SAL_LAYOUT_KERNING_PAIRS 0x0010
+#define SAL_LAYOUT_KERNING_ASIAN 0x0020
+#define SAL_LAYOUT_VERTICAL 0x0040
+#define SAL_LAYOUT_COMPLEX_DISABLED 0x0100
+#define SAL_LAYOUT_ENABLE_LIGATURES 0x0200
+#define SAL_LAYOUT_SUBSTITUTE_DIGITS 0x0400
+#define SAL_LAYOUT_KASHIDA_JUSTIFICATON 0x0800
+#define SAL_LAYOUT_DISABLE_GLYPH_PROCESSING 0x1000
+#define SAL_LAYOUT_FOR_FALLBACK 0x2000
+
+// -----------------
+
+// used for managing runs e.g. for BiDi, glyph and script fallback
+class VCL_DLLPUBLIC ImplLayoutRuns
+{
+private:
+ int mnRunIndex;
+ std::vector<int> maRuns;
+
+public:
+ ImplLayoutRuns() { mnRunIndex = 0; maRuns.reserve(8); }
+
+ void Clear() { maRuns.clear(); }
+ bool AddPos( int nCharPos, bool bRTL );
+ bool AddRun( int nMinRunPos, int nEndRunPos, bool bRTL );
+
+ bool IsEmpty() const { return maRuns.empty(); }
+ void ResetPos() { mnRunIndex = 0; }
+ void NextRun() { mnRunIndex += 2; }
+ bool GetRun( int* nMinRunPos, int* nEndRunPos, bool* bRTL ) const;
+ bool GetNextPos( int* nCharPos, bool* bRTL );
+ bool PosIsInRun( int nCharPos ) const;
+ bool PosIsInAnyRun( int nCharPos ) const;
+};
+
+// -----------------
+
+class ImplLayoutArgs
+{
+public:
+ // string related inputs
+ int mnFlags;
+ int mnLength;
+ int mnMinCharPos;
+ int mnEndCharPos;
+ const xub_Unicode* mpStr;
+
+ // positioning related inputs
+ const sal_Int32* mpDXArray; // in pixel units
+ long mnLayoutWidth; // in pixel units
+ int mnOrientation; // in 0-3600 system
+
+ // data for bidi and glyph+script fallback
+ ImplLayoutRuns maRuns;
+ ImplLayoutRuns maReruns;
+
+public:
+ ImplLayoutArgs( const xub_Unicode* pStr, int nLength,
+ int nMinCharPos, int nEndCharPos, int nFlags );
+
+ void SetLayoutWidth( long nWidth ) { mnLayoutWidth = nWidth; }
+ void SetDXArray( const sal_Int32* pDXArray ) { mpDXArray = pDXArray; }
+ void SetOrientation( int nOrientation ) { mnOrientation = nOrientation; }
+
+ void ResetPos()
+ { maRuns.ResetPos(); }
+ bool GetNextPos( int* nCharPos, bool* bRTL )
+ { return maRuns.GetNextPos( nCharPos, bRTL ); }
+ bool GetNextRun( int* nMinRunPos, int* nEndRunPos, bool* bRTL );
+ bool NeedFallback( int nCharPos, bool bRTL )
+ { return maReruns.AddPos( nCharPos, bRTL ); }
+ bool NeedFallback( int nMinRunPos, int nEndRunPos, bool bRTL )
+ { return maReruns.AddRun( nMinRunPos, nEndRunPos, bRTL ); }
+ // methods used by BiDi and glyph fallback
+ bool NeedFallback() const
+ { return !maReruns.IsEmpty(); }
+ bool PrepareFallback();
+
+protected:
+ void AddRun( int nMinCharPos, int nEndCharPos, bool bRTL );
+};
+
+// helper functions often used with ImplLayoutArgs
+bool IsDiacritic( sal_UCS4 );
+int GetVerticalFlags( sal_UCS4 );
+sal_UCS4 GetVerticalChar( sal_UCS4 );
+// #i80090# GetMirroredChar also needed outside vcl, moved to svapp.hxx
+// VCL_DLLPUBLIC sal_UCS4 GetMirroredChar( sal_UCS4 );
+sal_UCS4 GetLocalizedChar( sal_UCS4, LanguageType );
+VCL_DLLPUBLIC const char* GetAutofallback( sal_UCS4 ) ;
+
+// -------------
+// - SalLayout -
+// -------------
+
+typedef sal_uInt32 sal_GlyphId;
+
+// Glyph Flags
+#define GF_NONE 0x00000000
+#define GF_FLAGMASK 0xFF800000
+#define GF_IDXMASK ~GF_FLAGMASK
+#define GF_ISCHAR 0x00800000
+#define GF_ROTL 0x01000000
+// caution !!!
+#define GF_VERT 0x02000000
+// GF_VERT is only for windows implementation
+// (win/source/gdi/salgdi3.cxx, win/source/gdi/winlayout.cxx)
+// don't use this elsewhere !!!
+#define GF_ROTR 0x03000000
+#define GF_ROTMASK 0x03000000
+#define GF_UNHINTED 0x04000000
+#define GF_GSUB 0x08000000
+#define GF_FONTMASK 0xF0000000
+#define GF_FONTSHIFT 28
+
+#define GF_DROPPED 0xFFFFFFFF
+
+// all positions/widths are in font units
+// one exception: drawposition is in pixel units
+
+class VCL_DLLPUBLIC SalLayout
+{
+public:
+ // used by upper layers
+ Point& DrawBase() { return maDrawBase; }
+ const Point& DrawBase() const { return maDrawBase; }
+ Point& DrawOffset() { return maDrawOffset; }
+ const Point& DrawOffset() const { return maDrawOffset; }
+ Point GetDrawPosition( const Point& rRelative = Point(0,0) ) const;
+
+ virtual bool LayoutText( ImplLayoutArgs& ) = 0; // first step of layouting
+ virtual void AdjustLayout( ImplLayoutArgs& ); // adjusting after fallback etc.
+ virtual void InitFont() const {}
+ virtual void DrawText( SalGraphics& ) const = 0;
+
+ int GetUnitsPerPixel() const { return mnUnitsPerPixel; }
+ int GetOrientation() const { return mnOrientation; }
+
+ virtual const ImplFontData* GetFallbackFontData( sal_GlyphId ) const;
+
+ // methods using string indexing
+ virtual int GetTextBreak( long nMaxWidth, long nCharExtra=0, int nFactor=1 ) const = 0;
+ virtual long FillDXArray( sal_Int32* pDXArray ) const = 0;
+ virtual long GetTextWidth() const { return FillDXArray( NULL ); }
+ virtual void GetCaretPositions( int nArraySize, sal_Int32* pCaretXArray ) const = 0;
+ virtual bool IsKashidaPosValid ( int /*nCharPos*/ ) const { return true; } // i60594
+
+ // methods using glyph indexing
+ virtual int GetNextGlyphs( int nLen, sal_GlyphId* pGlyphIdAry, Point& rPos, int&,
+ sal_Int32* pGlyphAdvAry = NULL, int* pCharPosAry = NULL ) const = 0;
+ virtual bool GetOutline( SalGraphics&, ::basegfx::B2DPolyPolygonVector& ) const;
+ virtual bool GetBoundRect( SalGraphics&, Rectangle& ) const;
+
+ virtual bool IsSpacingGlyph( sal_GlyphId ) const;
+
+ // reference counting
+ void Reference() const;
+ void Release() const;
+
+ // used by glyph+font+script fallback
+ virtual void MoveGlyph( int nStart, long nNewXPos ) = 0;
+ virtual void DropGlyph( int nStart ) = 0;
+ virtual void Simplify( bool bIsBase ) = 0;
+ virtual void DisableGlyphInjection( bool /*bDisable*/ ) {}
+
+protected:
+ // used by layout engines
+ SalLayout();
+ virtual ~SalLayout();
+
+ // used by layout layers
+ void SetUnitsPerPixel( int n ) { mnUnitsPerPixel = n; }
+ void SetOrientation( int nOrientation ) // in 0-3600 system
+ { mnOrientation = nOrientation; }
+
+ static int CalcAsianKerning( sal_UCS4, bool bLeft, bool bVertical );
+
+private:
+ // enforce proper copy semantic
+ SAL_DLLPRIVATE SalLayout( const SalLayout& );
+ SAL_DLLPRIVATE SalLayout& operator=( const SalLayout& );
+
+protected:
+ int mnMinCharPos;
+ int mnEndCharPos;
+ int mnLayoutFlags;
+
+ int mnUnitsPerPixel;
+ int mnOrientation;
+
+ mutable int mnRefCount;
+ mutable Point maDrawOffset;
+ Point maDrawBase;
+};
+
+// ------------------
+// - MultiSalLayout -
+// ------------------
+
+class VCL_DLLPUBLIC MultiSalLayout : public SalLayout
+{
+public:
+ virtual void DrawText( SalGraphics& ) const;
+ virtual int GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const;
+ virtual long FillDXArray( sal_Int32* pDXArray ) const;
+ virtual void GetCaretPositions( int nArraySize, sal_Int32* pCaretXArray ) const;
+ virtual int GetNextGlyphs( int nLen, sal_GlyphId* pGlyphIdxAry, Point& rPos,
+ int&, sal_Int32* pGlyphAdvAry, int* pCharPosAry ) const;
+ virtual bool GetOutline( SalGraphics&, ::basegfx::B2DPolyPolygonVector& ) const;
+ virtual bool GetBoundRect( SalGraphics&, Rectangle& ) const;
+
+ // used only by OutputDevice::ImplLayout, TODO: make friend
+ MultiSalLayout( SalLayout& rBaseLayout,
+ const ImplFontData* pBaseFont = NULL );
+ virtual bool AddFallback( SalLayout& rFallbackLayout,
+ ImplLayoutRuns&, const ImplFontData* pFallbackFont );
+ virtual bool LayoutText( ImplLayoutArgs& );
+ virtual void AdjustLayout( ImplLayoutArgs& );
+ virtual void InitFont() const;
+
+ virtual const ImplFontData* GetFallbackFontData( sal_GlyphId ) const;
+
+ void SetInComplete(bool bInComplete = true);
+
+protected:
+ virtual ~MultiSalLayout();
+
+private:
+ // dummy implementations
+ virtual void MoveGlyph( int, long ) {}
+ virtual void DropGlyph( int ) {}
+ virtual void Simplify( bool ) {}
+
+ // enforce proper copy semantic
+ SAL_DLLPRIVATE MultiSalLayout( const MultiSalLayout& );
+ SAL_DLLPRIVATE MultiSalLayout& operator=( const MultiSalLayout& );
+
+private:
+ SalLayout* mpLayouts[ MAX_FALLBACK ];
+ const ImplFontData* mpFallbackFonts[ MAX_FALLBACK ];
+ ImplLayoutRuns maFallbackRuns[ MAX_FALLBACK ];
+ int mnLevel;
+ bool mbInComplete;
+};
+
+// --------------------
+// - GenericSalLayout -
+// --------------------
+
+struct GlyphItem
+{
+ int mnFlags;
+ int mnCharPos; // index in string
+ int mnOrigWidth; // original glyph width
+ int mnNewWidth; // width after adjustments
+ sal_GlyphId mnGlyphIndex;
+ Point maLinearPos; // absolute position of non rotated string
+
+public:
+ GlyphItem() {}
+
+ GlyphItem( int nCharPos, sal_GlyphId nGlyphIndex, const Point& rLinearPos,
+ long nFlags, int nOrigWidth )
+ : mnFlags(nFlags), mnCharPos(nCharPos),
+ mnOrigWidth(nOrigWidth), mnNewWidth(nOrigWidth),
+ mnGlyphIndex(nGlyphIndex), maLinearPos(rLinearPos)
+ {}
+
+ enum{ FALLBACK_MASK=0xFF, IS_IN_CLUSTER=0x100, IS_RTL_GLYPH=0x200, IS_DIACRITIC=0x400 };
+
+ bool IsClusterStart() const { return ((mnFlags & IS_IN_CLUSTER) == 0); }
+ bool IsRTLGlyph() const { return ((mnFlags & IS_RTL_GLYPH) != 0); }
+ bool IsDiacritic() const { return ((mnFlags & IS_DIACRITIC) != 0); }
+};
+
+// ---------------
+
+typedef std::list<GlyphItem> GlyphList;
+typedef std::vector<GlyphItem> GlyphVector;
+
+// ---------------
+
+class VCL_DLLPUBLIC GenericSalLayout : public SalLayout
+{
+public:
+ // used by layout engines
+ void AppendGlyph( const GlyphItem& );
+ virtual void AdjustLayout( ImplLayoutArgs& );
+ virtual void ApplyDXArray( ImplLayoutArgs& );
+ virtual void Justify( long nNewWidth );
+ void KashidaJustify( long nIndex, int nWidth );
+ void ApplyAsianKerning( const sal_Unicode*, int nLength );
+ void SortGlyphItems();
+
+ // used by upper layers
+ virtual long GetTextWidth() const;
+ virtual long FillDXArray( sal_Int32* pDXArray ) const;
+ virtual int GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const;
+ virtual void GetCaretPositions( int nArraySize, sal_Int32* pCaretXArray ) const;
+
+ // used by display layers
+ virtual int GetNextGlyphs( int nLen, sal_GlyphId* pGlyphIdxAry, Point& rPos, int&,
+ sal_Int32* pGlyphAdvAry = NULL, int* pCharPosAry = NULL ) const;
+
+protected:
+ GenericSalLayout();
+ virtual ~GenericSalLayout();
+
+ // for glyph+font+script fallback
+ virtual void MoveGlyph( int nStart, long nNewXPos );
+ virtual void DropGlyph( int nStart );
+ virtual void Simplify( bool bIsBase );
+
+ bool GetCharWidths( sal_Int32* pCharWidths ) const;
+
+private:
+ GlyphItem* mpGlyphItems; // TODO: change to GlyphList
+ int mnGlyphCount;
+ int mnGlyphCapacity;
+ mutable Point maBasePoint;
+
+ // enforce proper copy semantic
+ SAL_DLLPRIVATE GenericSalLayout( const GenericSalLayout& );
+ SAL_DLLPRIVATE GenericSalLayout& operator=( const GenericSalLayout& );
+};
+
+#undef SalGraphics
+
+#endif // _SV_SALLAYOUT_HXX
diff --git a/vcl/inc/vcl/salmenu.hxx b/vcl/inc/vcl/salmenu.hxx
new file mode 100644
index 000000000000..cc0438c4e177
--- /dev/null
+++ b/vcl/inc/vcl/salmenu.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALMENU_HXX
+#define _SV_SALMENU_HXX
+
+#include <vcl/sv.h>
+#include "vcl/dllapi.h"
+#include <vcl/menu.hxx>
+#include <vcl/keycod.hxx>
+#include <vcl/image.hxx>
+
+struct SystemMenuData;
+class FloatingWindow;
+class SalFrame;
+
+struct SalItemParams
+{
+ USHORT nId; // item Id
+ MenuItemType eType; // MenuItem-Type
+ MenuItemBits nBits; // MenuItem-Bits
+ Menu* pMenu; // Pointer to Menu
+ XubString aText; // Menu-Text
+ Image aImage; // Image
+};
+
+
+struct SalMenuButtonItem
+{
+ USHORT mnId;
+ Image maImage;
+ rtl::OUString maToolTipText;
+
+ SalMenuButtonItem() : mnId( 0 ) {}
+ SalMenuButtonItem( USHORT i_nId, const Image& rImg, const rtl::OUString& i_rTTText = rtl::OUString() )
+ : mnId( i_nId ), maImage( rImg ), maToolTipText( i_rTTText ) {}
+};
+
+class VCL_DLLPUBLIC SalMenuItem
+{
+public:
+ SalMenuItem() {}
+ virtual ~SalMenuItem();
+};
+
+class VCL_DLLPUBLIC SalMenu
+{
+public:
+ SalMenu() {}
+ virtual ~SalMenu();
+
+ virtual BOOL VisibleMenuBar() = 0; // must return TRUE to actually DISPLAY native menu bars
+ // otherwise only menu messages are processed (eg, OLE on Windows)
+
+ virtual void InsertItem( SalMenuItem* pSalMenuItem, unsigned nPos ) = 0;
+ virtual void RemoveItem( unsigned nPos ) = 0;
+ virtual void SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos ) = 0;
+ virtual void SetFrame( const SalFrame* pFrame ) = 0;
+ virtual void CheckItem( unsigned nPos, BOOL bCheck ) = 0;
+ virtual void EnableItem( unsigned nPos, BOOL bEnable ) = 0;
+ virtual void SetItemText( unsigned nPos, SalMenuItem* pSalMenuItem, const XubString& rText )= 0;
+ virtual void SetItemImage( unsigned nPos, SalMenuItem* pSalMenuItem, const Image& rImage ) = 0;
+ virtual void SetAccelerator( unsigned nPos, SalMenuItem* pSalMenuItem, const KeyCode& rKeyCode, const XubString& rKeyName ) = 0;
+ virtual void GetSystemMenuData( SystemMenuData* pData ) = 0;
+ virtual bool ShowNativePopupMenu(FloatingWindow * pWin, const Rectangle& rRect, ULONG nFlags);
+ virtual bool AddMenuBarButton( const SalMenuButtonItem& ); // return false if not implemented or failure
+ virtual void RemoveMenuBarButton( USHORT nId );
+
+ // return an empty rectangle if not implemented
+ // return Rectangle( Point( -1, -1 ), Size( 1, 1 ) ) if menu bar buttons implemented
+ // but rectangle cannot be determined
+ virtual Rectangle GetMenuBarButtonRectPixel( USHORT i_nItemId, SalFrame* i_pReferenceFrame );
+};
+
+
+#endif // _SV_SALMENU_HXX
+
diff --git a/vcl/inc/vcl/salnativewidgets.hxx b/vcl/inc/vcl/salnativewidgets.hxx
new file mode 100644
index 000000000000..8e98791d9f78
--- /dev/null
+++ b/vcl/inc/vcl/salnativewidgets.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_NATIVEWIDGETS_HXX
+#define _SV_NATIVEWIDGETS_HXX
+
+#include <rtl/ustring.hxx>
+#include <vcl/dllapi.h>
+#include <tools/gen.hxx>
+
+/* Control Types:
+ *
+ * Specify the overall, whole control
+ * type (as opposed to parts of the
+ * control if it were composite).
+ */
+
+typedef sal_uInt32 ControlType;
+
+// Normal PushButton/Command Button
+#define CTRL_PUSHBUTTON 1
+
+// Normal single radio button
+#define CTRL_RADIOBUTTON 2
+
+// Normal single checkbox
+#define CTRL_CHECKBOX 10
+
+// Combobox, i.e. a ListBox
+// that allows data entry by user
+#define CTRL_COMBOBOX 20
+
+// Control that allows text entry
+#define CTRL_EDITBOX 30
+
+// Control that allows text entry, but without the usual border
+// Has to be handled separately, because this one cannot handle
+// HAS_BACKGROUND_TEXTURE, which is drawn in the edit box'es
+// border window.
+#define CTRL_EDITBOX_NOBORDER 31
+
+// Control that allows text entry
+// ( some systems distingish between single and multi line edit boxes )
+#define CTRL_MULTILINE_EDITBOX 32
+
+// Control that pops up a menu,
+// but does NOT allow data entry
+#define CTRL_LISTBOX 35
+
+// An edit field together with two little
+// buttons on the side (aka spin field)
+#define CTRL_SPINBOX 40
+
+// Two standalone spin buttons
+// without an edit field
+#define CTRL_SPINBUTTONS 45
+
+// A single tab
+#define CTRL_TAB_ITEM 50
+
+// The border around a tab area,
+// but without the tabs themselves.
+// May have a gap at the top for
+// the active tab
+#define CTRL_TAB_PANE 55
+
+// Background of a Tab Pane
+#define CTRL_TAB_BODY 56
+
+// Normal scrollbar, including
+// all parts like slider, buttons
+#define CTRL_SCROLLBAR 60
+
+#define CTRL_SLIDER 65
+
+// Border around a group of related
+// items, perhaps also displaying
+// a label of identification
+#define CTRL_GROUPBOX 70
+
+// A separator line
+#define CTRL_FIXEDLINE 80
+
+// A rectangular border, like a
+// Tab Pane, but without the
+// possible gap for a tab
+#define CTRL_FIXEDBORDER 90
+
+// A toolbar control with buttons and a grip
+#define CTRL_TOOLBAR 100
+
+// The menubar
+#define CTRL_MENUBAR 120
+// popup menu
+#define CTRL_MENU_POPUP 121
+
+// The statusbar
+#define CTRL_STATUSBAR 130
+#define CTRL_PROGRESS 131
+// Progress bar for the intro window
+// (aka splash screen), in case some
+// wants native progress bar in the
+// application but not for the splash
+// screen (used in desktop/)
+#define CTRL_INTROPROGRESS 132
+
+// tool tips
+#define CTRL_TOOLTIP 140
+
+// to draw the implemented theme
+#define CTRL_WINDOW_BACKGROUND 150
+
+//to draw border of frames natively
+#define CTRL_FRAME 160
+
+// for nodes in listviews
+// used in svtools/source/contnr/svtreebx.cxx
+#define CTRL_LISTNODE 170
+// nets between elements of listviews
+// with nodes
+#define CTRL_LISTNET 171
+
+
+/* Control Parts:
+ *
+ * Uniquely identify a part of a control,
+ * for example the slider of a scroll bar.
+ */
+
+typedef sal_uInt32 ControlPart;
+
+#define PART_ENTIRE_CONTROL 1
+#define PART_WINDOW 5 // the static listbox window containing the list
+#define PART_BUTTON 100
+#define PART_BUTTON_UP 101
+#define PART_BUTTON_DOWN 102 // Also for ComboBoxes/ListBoxes
+#define PART_BUTTON_LEFT 103
+#define PART_BUTTON_RIGHT 104
+#define PART_ALL_BUTTONS 105
+#define PART_TRACK_HORZ_LEFT 200
+#define PART_TRACK_VERT_UPPER 201
+#define PART_TRACK_HORZ_RIGHT 202
+#define PART_TRACK_VERT_LOWER 203
+#define PART_TRACK_HORZ_AREA 204
+#define PART_TRACK_VERT_AREA 205
+#define PART_THUMB_HORZ 210 // Also used as toolbar grip
+#define PART_THUMB_VERT 211 // Also used as toolbar grip
+#define PART_MENU_ITEM 250
+#define PART_MENU_ITEM_CHECK_MARK 251
+#define PART_MENU_ITEM_RADIO_MARK 252
+
+/* #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.
+*/
+
+/** The edit field part of a control, e.g. of the combo box.
+
+ Currently used just for combo boxes and just for GetNativeControlRegion().
+ It is valid only if GetNativeControlRegion() supports PART_BUTTON_DOWN as
+ well.
+*/
+#define PART_SUB_EDIT 300
+
+// For controls that require the entire background
+// to be drawn first, and then other pieces over top.
+// (GTK+ scrollbars for example). Control region passed
+// in to draw this part is expected to be the entire
+// area of the control.
+// A control may respond to one or both.
+#define PART_DRAW_BACKGROUND_HORZ 1000
+#define PART_DRAW_BACKGROUND_VERT 1001
+
+// GTK+ also draws tabs right->left since there is a
+// hardcoded 2 pixel overlap between adjacent tabs
+#define PART_TABS_DRAW_RTL 3000
+
+// For themes that do not want to have the focus
+// rectangle part drawn by VCL but take care of the
+// whole inner control part by themselves
+// eg, listboxes or comboboxes or spinbuttons
+#define HAS_BACKGROUND_TEXTURE 4000
+
+// For scrollbars that have 3 buttons (most KDE themes)
+#define HAS_THREE_BUTTONS 5000
+
+#define PART_BACKGROUND_WINDOW 6000
+#define PART_BACKGROUND_DIALOG 6001
+
+//to draw natively the border of frames
+#define PART_BORDER 7000
+
+/* Control State:
+ *
+ * Specify how a particular part of the control
+ * is to be drawn. Constants are bitwise OR-ed
+ * together to compose a final drawing state.
+ * A _disabled_ state is assumed by the drawing
+ * functions until an ENABLED or HIDDEN is passed
+ * in the ControlState.
+ */
+
+typedef sal_uInt32 ControlState;
+
+#define CTRL_STATE_ENABLED 0x0001
+#define CTRL_STATE_FOCUSED 0x0002
+#define CTRL_STATE_PRESSED 0x0004
+#define CTRL_STATE_ROLLOVER 0x0008
+#define CTRL_STATE_HIDDEN 0x0010
+#define CTRL_STATE_DEFAULT 0x0020
+#define CTRL_STATE_SELECTED 0x0040
+#define CTRL_CACHING_ALLOWED 0x8000 // set when the control is completely visible (i.e. not clipped)
+
+/* ButtonValue:
+ *
+ * Identifies the tri-state value options
+ * that buttons allow
+ */
+
+enum ButtonValue {
+ BUTTONVALUE_DONTKNOW,
+ BUTTONVALUE_ON,
+ BUTTONVALUE_OFF,
+ BUTTONVALUE_MIXED
+};
+
+#ifdef __cplusplus
+
+/* ScrollbarValue:
+ *
+ * Value container for scrollbars.
+ */
+class VCL_DLLPUBLIC ScrollbarValue
+{
+ public:
+ long mnMin;
+ long mnMax;
+ long mnCur;
+ long mnVisibleSize;
+ Rectangle maThumbRect;
+ Rectangle maButton1Rect;
+ Rectangle maButton2Rect;
+ ControlState mnButton1State;
+ ControlState mnButton2State;
+ ControlState mnThumbState;
+ ControlState mnPage1State;
+ ControlState mnPage2State;
+
+ inline ScrollbarValue()
+ {
+ mnMin = 0; mnMax = 0; mnCur = 0; mnVisibleSize = 0;
+ mnButton1State = 0; mnButton2State = 0;
+ mnThumbState = 0; mnPage1State = 0; mnPage2State = 0;
+ };
+ inline ~ScrollbarValue() {};
+};
+
+class VCL_DLLPUBLIC SliderValue
+{
+ public:
+ long mnMin;
+ long mnMax;
+ long mnCur;
+ Rectangle maThumbRect;
+ ControlState mnThumbState;
+
+ SliderValue() : mnMin( 0 ), mnMax( 0 ), mnCur( 0 ), mnThumbState( 0 )
+ {}
+ ~SliderValue() {}
+};
+
+/* TabitemValue:
+ *
+ * Value container for tabitems.
+ */
+
+/* TABITEM constants are OR-ed together */
+#define TABITEM_NOTALIGNED 0x000 // the tabitem is an inner item
+#define TABITEM_LEFTALIGNED 0x001 // the tabitem is aligned with the left border of the TabControl
+#define TABITEM_RIGHTALIGNED 0x002 // the tabitem is aligned with the right border of the TabControl
+#define TABITEM_FIRST_IN_GROUP 0x004 // the tabitem is the first in group of tabitems
+#define TABITEM_LAST_IN_GROUP 0x008 // the tabitem is the last in group of tabitems
+
+class VCL_DLLPUBLIC TabitemValue
+{
+ public:
+ unsigned int mnAlignment;
+
+ inline TabitemValue()
+ {
+ mnAlignment = 0;
+ };
+ inline ~TabitemValue() {};
+
+ BOOL isLeftAligned() { return (mnAlignment & TABITEM_LEFTALIGNED) != 0; }
+ BOOL isRightAligned() { return (mnAlignment & TABITEM_RIGHTALIGNED) != 0; }
+ BOOL isBothAligned() { return isLeftAligned() && isRightAligned(); }
+ BOOL isNotAligned() { return (mnAlignment & (TABITEM_LEFTALIGNED | TABITEM_RIGHTALIGNED)) == 0; }
+ BOOL isFirst() { return (mnAlignment & TABITEM_FIRST_IN_GROUP) != 0; }
+ BOOL isLast() { return (mnAlignment & TABITEM_LAST_IN_GROUP) != 0; }
+};
+
+/* SpinbuttonValue:
+ *
+ * Value container for spinbuttons to paint both buttons at once.
+ * Note: the other parameters of DrawNativeControl will have no meaning
+ * all parameters for spinbuttons are carried here
+ */
+class VCL_DLLPUBLIC SpinbuttonValue
+{
+ public:
+ Rectangle maUpperRect;
+ Rectangle maLowerRect;
+ ControlState mnUpperState;
+ ControlState mnLowerState;
+ int mnUpperPart;
+ int mnLowerPart;
+
+ inline SpinbuttonValue()
+ {
+ mnUpperState = mnLowerState = 0;
+ };
+ inline ~SpinbuttonValue() {};
+};
+
+/* Toolbarvalue:
+ *
+ * Value container for toolbars detailing the grip position
+ */
+class ToolbarValue
+{
+public:
+ ToolbarValue() { mbIsTopDockingArea = FALSE; }
+ Rectangle maGripRect;
+ BOOL mbIsTopDockingArea; // indicates that this is the top aligned dockingarea
+ // adjacent to the menubar
+};
+
+/* MenubarValue:
+ *
+ * Value container for menubars specifying height of adjacent docking area
+ */
+class MenubarValue
+{
+public:
+ MenubarValue() { maTopDockingAreaHeight=0; }
+ int maTopDockingAreaHeight;
+};
+
+/* PushButtonValue:
+ *
+ * Value container for pushbuttons specifying additional drawing hints
+ */
+class PushButtonValue
+{
+public:
+PushButtonValue() : mbBevelButton( false ), mbSingleLine( true ) {}
+ bool mbBevelButton:1;
+ bool mbSingleLine:1;
+};
+
+/* ImplControlValue:
+ *
+ * Generic value container for all control parts.
+ */
+
+class ImplControlValue
+{
+ friend class SalFrame;
+
+ private:
+ ButtonValue mTristate; // Tristate value: on, off, mixed
+ rtl::OUString mString; // string value
+ long mNumber; // numeric value
+ void * mOptionalVal; // optional control-specific value
+
+ public:
+ inline ImplControlValue( ButtonValue nTristate, rtl::OUString sString, long nNumeric, void * aOptVal ) \
+ { mTristate = nTristate; mString = sString; mNumber = nNumeric; mOptionalVal = aOptVal; };
+ inline ImplControlValue( ButtonValue nTristate, rtl::OUString sString, long nNumeric ) \
+ { mTristate = nTristate; mString = sString; mNumber = nNumeric; mOptionalVal = NULL; };
+ explicit ImplControlValue( ButtonValue nTristate )
+ : mTristate(nTristate), mNumber(0), mOptionalVal(NULL) {}
+ explicit ImplControlValue( rtl::OUString& rString )
+ : mTristate(BUTTONVALUE_DONTKNOW), mString(rString), mNumber(0), mOptionalVal(NULL) {}
+ explicit ImplControlValue( long nNumeric )
+ : mTristate(BUTTONVALUE_DONTKNOW), mNumber( nNumeric), mOptionalVal(NULL) {}
+ explicit ImplControlValue( void* aOptVal )
+ : mTristate(BUTTONVALUE_DONTKNOW), mNumber(0), mOptionalVal(aOptVal) {}
+ inline ImplControlValue()
+ : mTristate(BUTTONVALUE_DONTKNOW), mNumber(0), mOptionalVal(NULL) {}
+
+ inline ~ImplControlValue() { mOptionalVal = NULL; };
+
+ inline ButtonValue getTristateVal( void ) const { return mTristate; }
+ inline void setTristateVal( ButtonValue nTristate ) { mTristate = nTristate; }
+
+ inline const rtl::OUString& getStringVal( void ) const { return mString; }
+ inline void setStringVal( rtl::OUString sString ) { mString = sString; }
+
+ inline long getNumericVal( void ) const { return mNumber; }
+ inline void setNumericVal( long nNumeric ) { mNumber = nNumeric; }
+
+ inline void * getOptionalVal( void ) const { return mOptionalVal; }
+ inline void setOptionalVal( void * aOptVal ) { mOptionalVal = aOptVal; }
+};
+
+#endif /* __cplusplus */
+
+#endif
+
diff --git a/vcl/inc/vcl/salobj.hxx b/vcl/inc/vcl/salobj.hxx
new file mode 100644
index 000000000000..e453bf5c6f87
--- /dev/null
+++ b/vcl/inc/vcl/salobj.hxx
@@ -0,0 +1,90 @@
+/*************************************************************************
+ *
+ * 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_SALOBJ_HXX
+#define _SV_SALOBJ_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/salgtype.hxx>
+#include <vcl/salwtype.hxx>
+
+struct SystemEnvData;
+
+// -------------------
+// - SalObject-Types -
+// -------------------
+
+#define SAL_OBJECT_CLIP_INCLUDERECTS ((USHORT)0x0001)
+#define SAL_OBJECT_CLIP_EXCLUDERECTS ((USHORT)0x0002)
+#define SAL_OBJECT_CLIP_ABSOLUTE ((USHORT)0x0004)
+
+// -------------
+// - SalObject -
+// -------------
+
+class VCL_DLLPUBLIC SalObject
+{
+ void* m_pInst;
+ SALOBJECTPROC m_pCallback;
+ BOOL m_bMouseTransparent:1,
+ m_bEraseBackground:1;
+public:
+ SalObject() : m_pInst( NULL ), m_pCallback( NULL ), m_bMouseTransparent( FALSE ), m_bEraseBackground( TRUE ) {}
+ virtual ~SalObject();
+
+ virtual void ResetClipRegion() = 0;
+ virtual USHORT GetClipRegionType() = 0;
+ virtual void BeginSetClipRegion( ULONG nRects ) = 0;
+ virtual void UnionClipRegion( long nX, long nY, long nWidth, long nHeight ) = 0;
+ virtual void EndSetClipRegion() = 0;
+
+ virtual void SetPosSize( long nX, long nY, long nWidth, long nHeight ) = 0;
+ virtual void Show( BOOL bVisible ) = 0;
+ virtual void Enable( BOOL nEnable ) = 0;
+ virtual void GrabFocus() = 0;
+
+ virtual void SetBackground() = 0;
+ virtual void SetBackground( SalColor nSalColor ) = 0;
+
+ virtual const SystemEnvData* GetSystemData() const = 0;
+
+ void SetCallback( void* pInst, SALOBJECTPROC pProc )
+ { m_pInst = pInst; m_pCallback = pProc; }
+ long CallCallback( USHORT nEvent, const void* pEvent )
+ { return m_pCallback ? m_pCallback( m_pInst, this, nEvent, pEvent ) : 0; }
+ void SetMouseTransparent( BOOL bMouseTransparent )
+ { m_bMouseTransparent = bMouseTransparent; }
+ BOOL IsMouseTransparent()
+ { return m_bMouseTransparent; }
+ void EnableEraseBackground( BOOL bEnable )
+ { m_bEraseBackground = bEnable; }
+ BOOL IsEraseBackgroundEnabled()
+ { return m_bEraseBackground; }
+};
+
+#endif // _SV_SALOBJ_HXX
diff --git a/vcl/inc/vcl/salprn.hxx b/vcl/inc/vcl/salprn.hxx
new file mode 100644
index 000000000000..19f023108349
--- /dev/null
+++ b/vcl/inc/vcl/salprn.hxx
@@ -0,0 +1,137 @@
+/*************************************************************************
+ *
+ * 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_SALPRN_HXX
+#define _SV_SALPRN_HXX
+
+#include <tools/string.hxx>
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/prntypes.hxx>
+
+#include <vector>
+
+class SalGraphics;
+class SalFrame;
+struct ImplJobSetup;
+namespace vcl { class PrinterController; }
+
+// -----------------------
+// - SalPrinterQueueInfo -
+// -----------------------
+
+struct VCL_DLLPUBLIC SalPrinterQueueInfo
+{
+ XubString maPrinterName;
+ XubString maDriver;
+ XubString maLocation;
+ XubString maComment;
+ ULONG mnStatus;
+ ULONG mnJobs;
+ void* mpSysData;
+
+ SalPrinterQueueInfo();
+ ~SalPrinterQueueInfo();
+};
+
+// ------------------
+// - SalInfoPrinter -
+// ------------------
+
+class VCL_DLLPUBLIC SalInfoPrinter
+{
+public:
+ std::vector< PaperInfo > m_aPaperFormats; // all printer supported formats
+ bool m_bPapersInit; // set to true after InitPaperFormats
+ bool m_bCompatMetrics;
+
+ SalInfoPrinter() : m_bPapersInit( false ), m_bCompatMetrics( false ) {}
+ virtual ~SalInfoPrinter();
+
+ // SalGraphics or NULL, but two Graphics for all SalFrames
+ // must be returned
+ virtual SalGraphics* GetGraphics() = 0;
+ virtual void ReleaseGraphics( SalGraphics* pGraphics ) = 0;
+
+ virtual BOOL Setup( SalFrame* pFrame, ImplJobSetup* pSetupData ) = 0;
+ // This function set the driver data and
+ // set the new indepen data in pSetupData
+ virtual BOOL SetPrinterData( ImplJobSetup* pSetupData ) = 0;
+ // This function merged the indepen driver data
+ // and set the new indepen data in pSetupData
+ // Only the data must changed, where the bit
+ // in nFlags is set
+ virtual BOOL SetData( ULONG nFlags, ImplJobSetup* pSetupData ) = 0;
+
+ virtual void GetPageInfo( const ImplJobSetup* pSetupData,
+ long& rOutWidth, long& rOutHeight,
+ long& rPageOffX, long& rPageOffY,
+ long& rPageWidth, long& rPageHeight ) = 0;
+ virtual ULONG GetCapabilities( const ImplJobSetup* pSetupData, USHORT nType ) = 0;
+ virtual ULONG GetPaperBinCount( const ImplJobSetup* pSetupData ) = 0;
+ virtual String GetPaperBinName( const ImplJobSetup* pSetupData, ULONG nPaperBin ) = 0;
+ // fills m_aPaperFormats and sets m_bPapersInit to true
+ virtual void InitPaperFormats( const ImplJobSetup* pSetupData ) = 0;
+ // returns angle that a landscape page will be turned counterclockwise wrt to portrait
+ virtual int GetLandscapeAngle( const ImplJobSetup* pSetupData ) = 0;
+};
+
+// --------------
+// - SalPrinter -
+// --------------
+
+class VCL_DLLPUBLIC SalPrinter
+{
+public: // public for Sal Implementation
+ SalPrinter() {}
+ virtual ~SalPrinter();
+
+ virtual BOOL StartJob( const String* pFileName,
+ const String& rJobName,
+ const String& rAppName,
+ ULONG nCopies,
+ bool bCollate,
+ bool bDirect,
+ ImplJobSetup* pSetupData ) = 0;
+
+ // implement for pull model print systems only,
+ // default implementations (see salvtables.cxx) just returns FALSE
+ virtual BOOL StartJob( const String* pFileName,
+ const String& rJobName,
+ const String& rAppName,
+ ImplJobSetup* pSetupData,
+ vcl::PrinterController& rController );
+
+ virtual BOOL EndJob() = 0;
+ virtual BOOL AbortJob() = 0;
+ virtual SalGraphics* StartPage( ImplJobSetup* pSetupData, BOOL bNewJobData ) = 0;
+ virtual BOOL EndPage() = 0;
+ virtual ULONG GetErrorCode() = 0;
+
+};
+
+#endif // _SV_SALPRN_HXX
diff --git a/vcl/inc/vcl/salptype.hxx b/vcl/inc/vcl/salptype.hxx
new file mode 100644
index 000000000000..8613ead5301a
--- /dev/null
+++ b/vcl/inc/vcl/salptype.hxx
@@ -0,0 +1,60 @@
+/*************************************************************************
+ *
+ * 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_SALPTYPE_HXX
+#define _SV_SALPTYPE_HXX
+
+#include <vcl/sv.h>
+
+// --------------------
+// - SalJobSetupFlags -
+// --------------------
+
+#define SAL_JOBSET_ORIENTATION ((ULONG)0x00000001)
+#define SAL_JOBSET_PAPERBIN ((ULONG)0x00000002)
+#define SAL_JOBSET_PAPERSIZE ((ULONG)0x00000004)
+#define SAL_JOBSET_DUPLEXMODE ((ULONG)0x00000008)
+#define SAL_JOBSET_ALL (SAL_JOBSET_ORIENTATION |\
+ SAL_JOBSET_PAPERBIN |\
+ SAL_JOBSET_PAPERSIZE |\
+ SAL_JOBSET_DUPLEXMODE)
+
+// -------------------
+// - SalPrinterError -
+// -------------------
+
+#define SAL_PRINTER_ERROR_GENERALERROR 1
+#define SAL_PRINTER_ERROR_ABORT 2
+
+// -------------------
+// - SalPrinterProcs -
+// -------------------
+
+class SalPrinter;
+typedef long (*SALPRNABORTPROC)( void* pInst, SalPrinter* pPrinter );
+
+#endif // _SV_SALPTYPE_HXX
diff --git a/vcl/inc/vcl/salsession.hxx b/vcl/inc/vcl/salsession.hxx
new file mode 100644
index 000000000000..2da1ae551074
--- /dev/null
+++ b/vcl/inc/vcl/salsession.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _VCL_SALSESSION_HXX
+#define _VCL_SALSESSION_HXX
+
+#include "vcl/dllapi.h"
+
+enum SalSessionEventType
+{
+ Interaction,
+ SaveRequest,
+ ShutdownCancel,
+ Quit
+};
+
+struct SalSessionEvent
+{
+ SalSessionEventType m_eType;
+
+ SalSessionEvent( SalSessionEventType eType )
+ : m_eType( eType )
+ {}
+};
+
+struct SalSessionInteractionEvent : public SalSessionEvent
+{
+ bool m_bInteractionGranted;
+
+ SalSessionInteractionEvent( bool bGranted )
+ : SalSessionEvent( Interaction ),
+ m_bInteractionGranted( bGranted )
+ {}
+};
+
+struct SalSessionSaveRequestEvent : public SalSessionEvent
+{
+ bool m_bShutdown;
+ bool m_bCancelable;
+
+ SalSessionSaveRequestEvent( bool bShutdown, bool bCancelable )
+ : SalSessionEvent( SaveRequest ),
+ m_bShutdown( bShutdown ),
+ m_bCancelable( bCancelable )
+ {}
+};
+
+struct SalSessionShutdownCancelEvent : public SalSessionEvent
+{
+ SalSessionShutdownCancelEvent()
+ : SalSessionEvent( ShutdownCancel )
+ {}
+};
+
+struct SalSessionQuitEvent : public SalSessionEvent
+{
+ SalSessionQuitEvent()
+ : SalSessionEvent( Quit )
+ {}
+};
+
+typedef void(*SessionProc)( SalSessionEvent *pEvent);
+
+class VCL_DLLPUBLIC SalSession
+{
+ SessionProc m_aProc;
+public:
+ SalSession()
+ : m_aProc( 0 )
+ {}
+ virtual ~SalSession();
+
+ void SetCallback( SessionProc aCallback )
+ {
+ m_aProc = aCallback;
+ }
+ void CallCallback( SalSessionEvent* pEvent )
+ {
+ if( m_aProc )
+ m_aProc( pEvent );
+ }
+
+ // query the session manager for a user interaction slot
+ virtual void queryInteraction() = 0;
+ // signal the session manager that we're done with user interaction
+ virtual void interactionDone() = 0;
+ // signal that we're done saving
+ virtual void saveDone() = 0;
+ // try to cancel the sutdown in progress
+ virtual bool cancelShutdown() = 0;
+};
+
+#endif
diff --git a/vcl/inc/vcl/salsys.hxx b/vcl/inc/vcl/salsys.hxx
new file mode 100644
index 000000000000..310b0a27e30f
--- /dev/null
+++ b/vcl/inc/vcl/salsys.hxx
@@ -0,0 +1,146 @@
+/*************************************************************************
+ *
+ * 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_SALSYS_HXX
+#define _SV_SALSYS_HXX
+
+#include <tools/string.hxx>
+#include <tools/gen.hxx>
+#include <vcl/dllapi.h>
+
+
+/* Button combinations for ShowNativeMessageBox
+*/
+const int SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_OK = 0;
+const int SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_OK_CANCEL = 1;
+const int SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_ABORT_RETRY_IGNORE = 2;
+const int SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_YES_NO_CANCEL = 3;
+const int SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_YES_NO = 4;
+const int SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_RETRY_CANCEL = 5;
+
+/* Button identifier for ShowNativeMessageBox
+*/
+const int SALSYSTEM_SHOWNATIVEMSGBOX_BTN_OK = 1;
+const int SALSYSTEM_SHOWNATIVEMSGBOX_BTN_CANCEL = 2;
+const int SALSYSTEM_SHOWNATIVEMSGBOX_BTN_ABORT = 3;
+const int SALSYSTEM_SHOWNATIVEMSGBOX_BTN_RETRY = 4;
+const int SALSYSTEM_SHOWNATIVEMSGBOX_BTN_IGNORE = 5;
+const int SALSYSTEM_SHOWNATIVEMSGBOX_BTN_YES = 6;
+const int SALSYSTEM_SHOWNATIVEMSGBOX_BTN_NO = 7;
+
+
+
+// -------------
+// - SalSystem -
+// -------------
+
+class VCL_DLLPUBLIC SalSystem
+{
+public:
+ SalSystem() {}
+ virtual ~SalSystem();
+
+ // get info about the display
+
+ /* Gets the number of active screens attached to the display
+
+ @returns the number of active screens
+ */
+ virtual unsigned int GetDisplayScreenCount() = 0;
+ /* Queries whether multiple screens are truly separate
+
+ @returns true if screens are distinct and windows cannot
+ be moved between them or span multiple of them
+ false if screens form up one big display
+ */
+ virtual bool IsMultiDisplay() = 0;
+ /* Queries the default screen number. The default screen is the
+ screen on which windows will appear if no special positioning
+ is made.
+
+ @returns the default screen number
+ */
+ virtual unsigned int GetDefaultDisplayNumber() = 0;
+ /* Gets relative position and size of the screens attached to the display
+
+ @param nScreen
+ The screen number to be queried
+
+ @returns position: (0,0) in case of IsMultiscreen() == true
+ else position relative to whole display
+ size: size of the screen
+ */
+ virtual Rectangle GetDisplayScreenPosSizePixel( unsigned int nScreen ) = 0;
+ /* Gets position and size of the work area of a screen attached to the display
+
+ @param nScreen
+ The screen number to be queried
+
+ @returns position and size relative to the scree
+ */
+ virtual Rectangle GetDisplayWorkAreaPosSizePixel( unsigned int nScreen ) = 0;
+ /* Gets the name of a screen
+
+ @param nScreen
+ The screen number to be queried
+
+ @returns the name of the screen
+ */
+ virtual rtl::OUString GetScreenName( unsigned int nScreen ) = 0;
+
+ /* Shows a native message box with the specified title, message and button
+ combination.
+
+ @param rTitle
+ The title to be shown by the dialog box.
+
+ @param rMessage
+ The message to be shown by the dialog box.
+
+ @param nButtonCombination
+ Specify which button combination the message box should display.
+ See button combinations above.
+
+ @param nDefaultButton
+ Specifies which button has the focus initially.
+ See button identifiers above.
+ The effect of specifying a button that doesn't belong
+ to the specified button combination is undefined.
+
+ @returns the identifier of the button that was pressed by the user.
+ See button identifier above. If the function fails the
+ return value is 0.
+ */
+ virtual int ShowNativeMessageBox( const String& rTitle,
+ const String& rMessage,
+ int nButtonCombination,
+ int nDefaultButton) = 0;
+};
+
+SalSystem* ImplGetSalSystem();
+
+#endif // _SV_SALSYS_HXX
diff --git a/vcl/inc/vcl/saltimer.hxx b/vcl/inc/vcl/saltimer.hxx
new file mode 100644
index 000000000000..d693070138d2
--- /dev/null
+++ b/vcl/inc/vcl/saltimer.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALTIMER_HXX
+#define _SV_SALTIMER_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/salwtype.hxx>
+
+// ------------
+// - SalTimer -
+// ------------
+
+/*
+ * note: there will be only a single instance of SalTimer
+ * SalTimer originally had only static methods, but
+ * this needed to be virtualized for the sal plugin migration
+ */
+
+class VCL_DLLPUBLIC SalTimer
+{
+ SALTIMERPROC m_pProc;
+public:
+ SalTimer() : m_pProc( NULL ) {}
+ virtual ~SalTimer();
+
+ // AutoRepeat and Restart
+ virtual void Start( ULONG nMS ) = 0;
+ virtual void Stop() = 0;
+
+ // Callbacks (indepen in \sv\source\app\timer.cxx)
+ void SetCallback( SALTIMERPROC pProc )
+ {
+ m_pProc = pProc;
+ }
+
+ void CallCallback()
+ {
+ if( m_pProc )
+ m_pProc();
+ }
+};
+
+#endif // _SV_SALTIMER_HXX
diff --git a/vcl/inc/vcl/salvd.hxx b/vcl/inc/vcl/salvd.hxx
new file mode 100644
index 000000000000..fcbe1fb35383
--- /dev/null
+++ b/vcl/inc/vcl/salvd.hxx
@@ -0,0 +1,58 @@
+/*************************************************************************
+ *
+ * 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_SALVD_HXX
+#define _SV_SALVD_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+
+class SalGraphics;
+
+// --------------------
+// - SalVirtualDevice -
+// --------------------
+
+class VCL_DLLPUBLIC SalVirtualDevice
+{
+public: // public for Sal Implementation
+ SalVirtualDevice() {}
+ virtual ~SalVirtualDevice();
+
+ // SalGraphics or NULL, but two Graphics for all SalVirtualDevices
+ // must be returned
+ virtual SalGraphics* GetGraphics() = 0;
+ virtual void ReleaseGraphics( SalGraphics* pGraphics ) = 0;
+
+ // Set new size, without saving the old contents
+ virtual BOOL SetSize( long nNewDX, long nNewDY ) = 0;
+
+ /// Get actual VDev size in pixel
+ virtual void GetSize( long& rWidth, long& rHeight ) = 0;
+};
+
+#endif // _SV_SALVD_HXX
diff --git a/vcl/inc/vcl/salwtype.hxx b/vcl/inc/vcl/salwtype.hxx
new file mode 100644
index 000000000000..95b3806d648b
--- /dev/null
+++ b/vcl/inc/vcl/salwtype.hxx
@@ -0,0 +1,346 @@
+/*************************************************************************
+ *
+ * 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_SALWTYPE_HXX
+#define _SV_SALWTYPE_HXX
+
+#include <i18npool/lang.h>
+#include <tools/string.hxx>
+#include <vcl/sv.h>
+
+class SalGraphics;
+class SalFrame;
+class SalObject;
+class Window;
+
+class ImplFontSelectData;
+
+// ---------------
+// - SalExtInput -
+// ---------------
+
+// Muessen mit den Defines in cmdevt.hxx uebereinstimmen, da diese
+// nicht konvertiert werden
+#define SAL_EXTTEXTINPUT_ATTR_GRAYWAVELINE ((USHORT)0x0100)
+#define SAL_EXTTEXTINPUT_ATTR_UNDERLINE ((USHORT)0x0200)
+#define SAL_EXTTEXTINPUT_ATTR_BOLDUNDERLINE ((USHORT)0x0400)
+#define SAL_EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE ((USHORT)0x0800)
+#define SAL_EXTTEXTINPUT_ATTR_DASHDOTUNDERLINE ((USHORT)0x1000)
+#define SAL_EXTTEXTINPUT_ATTR_HIGHLIGHT ((USHORT)0x2000)
+#define SAL_EXTTEXTINPUT_ATTR_REDTEXT ((USHORT)0x4000)
+#define SAL_EXTTEXTINPUT_ATTR_HALFTONETEXT ((USHORT)0x8000)
+
+#define SAL_EXTTEXTINPUT_CURSOR_INVISIBLE ((USHORT)0x0001)
+#define SAL_EXTTEXTINPUT_CURSOR_OVERWRITE ((USHORT)0x0002)
+
+// ------------
+// - SalEvent -
+// ------------
+
+#define SALEVENT_MOUSEMOVE ((USHORT)1)
+#define SALEVENT_MOUSELEAVE ((USHORT)2)
+#define SALEVENT_MOUSEBUTTONDOWN ((USHORT)3)
+#define SALEVENT_MOUSEBUTTONUP ((USHORT)4)
+#define SALEVENT_KEYINPUT ((USHORT)5)
+#define SALEVENT_KEYUP ((USHORT)6)
+#define SALEVENT_KEYMODCHANGE ((USHORT)7)
+#define SALEVENT_PAINT ((USHORT)8)
+#define SALEVENT_RESIZE ((USHORT)9)
+#define SALEVENT_GETFOCUS ((USHORT)10)
+#define SALEVENT_LOSEFOCUS ((USHORT)11)
+#define SALEVENT_CLOSE ((USHORT)12)
+#define SALEVENT_SHUTDOWN ((USHORT)13)
+#define SALEVENT_SETTINGSCHANGED ((USHORT)14)
+#define SALEVENT_VOLUMECHANGED ((USHORT)15)
+#define SALEVENT_PRINTERCHANGED ((USHORT)16)
+#define SALEVENT_DISPLAYCHANGED ((USHORT)17)
+#define SALEVENT_FONTCHANGED ((USHORT)18)
+#define SALEVENT_DATETIMECHANGED ((USHORT)19)
+#define SALEVENT_KEYBOARDCHANGED ((USHORT)20)
+#define SALEVENT_WHEELMOUSE ((USHORT)21)
+#define SALEVENT_USEREVENT ((USHORT)22)
+#define SALEVENT_MOUSEACTIVATE ((USHORT)23)
+#define SALEVENT_EXTTEXTINPUT ((USHORT)24)
+#define SALEVENT_ENDEXTTEXTINPUT ((USHORT)25)
+#define SALEVENT_EXTTEXTINPUTPOS ((USHORT)26)
+#define SALEVENT_INPUTCONTEXTCHANGE ((USHORT)27)
+#define SALEVENT_MOVE ((USHORT)28)
+#define SALEVENT_MOVERESIZE ((USHORT)29)
+#define SALEVENT_CLOSEPOPUPS ((USHORT)30)
+#define SALEVENT_EXTERNALKEYINPUT ((USHORT)31)
+#define SALEVENT_EXTERNALKEYUP ((USHORT)32)
+#define SALEVENT_MENUCOMMAND ((USHORT)33)
+#define SALEVENT_MENUHIGHLIGHT ((USHORT)34)
+#define SALEVENT_MENUACTIVATE ((USHORT)35)
+#define SALEVENT_MENUDEACTIVATE ((USHORT)36)
+#define SALEVENT_EXTERNALMOUSEMOVE ((USHORT)37)
+#define SALEVENT_EXTERNALMOUSEBUTTONDOWN ((USHORT)38)
+#define SALEVENT_EXTERNALMOUSEBUTTONUP ((USHORT)39)
+#define SALEVENT_INPUTLANGUAGECHANGE ((USHORT)40)
+#define SALEVENT_SHOWDIALOG ((USHORT)41)
+#define SALEVENT_MENUBUTTONCOMMAND ((USHORT)42)
+#define SALEVENT_SURROUNDINGTEXTREQUEST ((USHORT)43)
+#define SALEVENT_SURROUNDINGTEXTSELECTIONCHANGE ((USHORT)44)
+#define SALEVENT_STARTRECONVERSION ((USHORT)45)
+#define SALEVENT_COUNT ((USHORT)45)
+
+// MOUSELEAVE must send, when the pointer leave the client area and
+// the mouse is not captured
+// MOUSEMOVE, MOUSELEAVE, MOUSEBUTTONDOWN and MOUSEBUTTONUP
+// MAC: Ctrl+Button is MOUSE_RIGHT
+struct SalMouseEvent
+{
+ ULONG mnTime; // Time in ms, when event is created
+ long mnX; // X-Position (Pixel, TopLeft-Output)
+ long mnY; // Y-Position (Pixel, TopLeft-Output)
+ USHORT mnButton; // 0-MouseMove/MouseLeave, MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE
+ USHORT mnCode; // SV-ModifierCode (KEY_SHIFT | KEY_MOD1 | KEY_MOD2 | MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT)
+};
+
+// KEYINPUT and KEYUP
+struct SalKeyEvent
+{
+ ULONG mnTime; // Time in ms, when event is created
+ USHORT mnCode; // SV-KeyCode (KEY_xxx | KEY_SHIFT | KEY_MOD1 | KEY_MOD2)
+ USHORT mnCharCode; // SV-CharCode
+ USHORT mnRepeat; // Repeat-Count (KeyInputs-1)
+};
+
+// MENUEVENT
+struct SalMenuEvent
+{
+ USHORT mnId; // Menu item ID
+ void* mpMenu; // pointer to VCL menu (class Menu)
+
+ SalMenuEvent() : mnId( 0 ), mpMenu( NULL ) {}
+ SalMenuEvent( USHORT i_nId, void* i_pMenu )
+ : mnId( i_nId ), mpMenu( i_pMenu ) {}
+};
+
+// KEYMODCHANGE
+struct SalKeyModEvent
+{
+ ULONG mnTime; // Time in ms, when event is created
+ USHORT mnCode; // SV-ModifierCode (KEY_SHIFT | KEY_MOD1 | KEY_MOD2)
+ USHORT mnModKeyCode; // extended Modifier (MODKEY_LEFT, MODKEY_RIGHT, MODKEY_PRESS, MODKEY_RELEASE)
+};
+
+// PAINT
+struct SalPaintEvent
+{
+ long mnBoundX; // BoundRect - X
+ long mnBoundY; // BoundRect - Y
+ long mnBoundWidth; // BoundRect - Width
+ long mnBoundHeight; // BoundRect - Height
+ bool mbImmediateUpdate; // set to true to force an immediate update
+
+ SalPaintEvent( long x, long y, long w, long h, bool bImmediate = false ) :
+ mnBoundX( x ), mnBoundY( y ),
+ mnBoundWidth( w ), mnBoundHeight( h ),
+ mbImmediateUpdate( bImmediate )
+ {}
+};
+
+// USEREVENT
+// pEvent == pData
+
+// WHEELMOUSE
+#define SAL_WHEELMOUSE_EVENT_PAGESCROLL ((ULONG)0xFFFFFFFF)
+struct SalWheelMouseEvent
+{
+ ULONG mnTime; // Time in ms, when event is created
+ long mnX; // X-Position (Pixel, TopLeft-Output)
+ long mnY; // Y-Position (Pixel, TopLeft-Output)
+ long mnDelta; // Anzahl Drehungen
+ long mnNotchDelta; // Anzahl feste Drehungen
+ ULONG mnScrollLines; // Aktuelle Anzahl zu scrollende Zeilen
+ USHORT mnCode; // SV-ModifierCode (KEY_SHIFT | KEY_MOD1 | KEY_MOD2 | MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT)
+ BOOL mbHorz; // Horizontal
+ BOOL mbDeltaIsPixel; // delta value is a pixel value (on mac)
+
+ SalWheelMouseEvent()
+ : mnTime( 0 ), mnX( 0 ), mnY( 0 ), mnDelta( 0 ), mnNotchDelta( 0 ), mnScrollLines( 0 ), mnCode( 0 ), mbHorz( FALSE ), mbDeltaIsPixel( FALSE )
+ {}
+};
+
+// MOUSEACTIVATE
+struct SalMouseActivateEvent
+{
+ long mnX; // X-Position (Pixel, TopLeft-Output)
+ long mnY; // Y-Position (Pixel, TopLeft-Output)
+};
+
+#ifdef __cplusplus
+
+// EXTTEXTINPUT
+struct SalExtTextInputEvent
+{
+ ULONG mnTime; // Time in ms, when event is created
+ UniString maText; // Text
+ const USHORT* mpTextAttr; // Text-Attribute
+ ULONG mnCursorPos; // Cursor-Position
+ ULONG mnDeltaStart; // Start-Position der letzten Aenderung
+ BYTE mnCursorFlags; // SAL_EXTTEXTINPUT_CURSOR_xxx
+ BOOL mbOnlyCursor; // TRUE: Nur Cursor-Position wurde geaendert
+};
+
+#endif // __cplusplus
+
+// EXTTEXTINPUTPOS
+struct SalExtTextInputPosEvent
+{
+ long mnX; // Cursor-X-Position to upper left corner of frame
+ long mnY; // Cursor-Y-Position to upper left corner of frame
+ long mnWidth; // Cursor-Width in Pixel
+ long mnHeight; // Cursor-Height in Pixel
+ long mnExtWidth; // Width of the PreEdit area
+ bool mbVertical; // true if in vertical mode
+};
+
+#ifdef __cplusplus
+
+// INPUTCONTEXTCHANGE
+struct SalInputContextChangeEvent
+{
+ LanguageType meLanguage; // Neue Sprache
+};
+
+#endif // __cplusplus
+
+#ifdef __cplusplus
+
+// SURROUNDINGTEXTREQUEST
+struct SalSurroundingTextRequestEvent
+{
+ UniString maText; // Text
+ ULONG mnStart; // The beggining index of selected range
+ ULONG mnEnd; // The end index of selected range
+};
+
+#endif // __cplusplus
+
+#ifdef __cplusplus
+
+// SURROUNDINGTEXTSELECTIONCHANGE
+struct SalSurroundingTextSelectionChangeEvent
+{
+ ULONG mnStart; // The beggining index of selected range
+ ULONG mnEnd; // The end index of selected range
+};
+
+#endif // __cplusplus
+
+// ------------------
+// - SalFrame-Types -
+// ------------------
+
+typedef long (*SALFRAMEPROC)( Window* pInst, SalFrame* pFrame,
+ USHORT nEvent, const void* pEvent );
+
+// --------------------
+// - SalObject-Events -
+// --------------------
+
+#define SALOBJ_EVENT_GETFOCUS ((USHORT)1)
+#define SALOBJ_EVENT_LOSEFOCUS ((USHORT)2)
+#define SALOBJ_EVENT_TOTOP ((USHORT)3)
+#define SALOBJ_EVENT_COUNT ((USHORT)4)
+
+// ------------------
+// - SalObject-Types -
+// ------------------
+
+typedef long (*SALOBJECTPROC)( void* pInst, SalObject* pObject,
+ USHORT nEvent, const void* pEvent );
+
+// -----------------
+// - SalFrameState -
+// -----------------
+
+// Must be the same as in syswin.hxx
+#define SAL_FRAMESTATE_MASK_X ((ULONG)0x00000001)
+#define SAL_FRAMESTATE_MASK_Y ((ULONG)0x00000002)
+#define SAL_FRAMESTATE_MASK_WIDTH ((ULONG)0x00000004)
+#define SAL_FRAMESTATE_MASK_HEIGHT ((ULONG)0x00000008)
+#define SAL_FRAMESTATE_MASK_MAXIMIZED_X ((ULONG)0x00000100)
+#define SAL_FRAMESTATE_MASK_MAXIMIZED_Y ((ULONG)0x00000200)
+#define SAL_FRAMESTATE_MASK_MAXIMIZED_WIDTH ((ULONG)0x00000400)
+#define SAL_FRAMESTATE_MASK_MAXIMIZED_HEIGHT ((ULONG)0x00000800)
+#define SAL_FRAMESTATE_MASK_STATE ((ULONG)0x00000010)
+
+#define SAL_FRAMESTATE_NORMAL ((ULONG)0x00000001)
+#define SAL_FRAMESTATE_MINIMIZED ((ULONG)0x00000002)
+#define SAL_FRAMESTATE_MAXIMIZED ((ULONG)0x00000004)
+#define SAL_FRAMESTATE_ROLLUP ((ULONG)0x00000008)
+#define SAL_FRAMESTATE_MAXIMIZED_HORZ ((ULONG)0x00000010)
+#define SAL_FRAMESTATE_MAXIMIZED_VERT ((ULONG)0x00000020)
+#define SAL_FRAMESTATE_SYSTEMMASK ((ULONG)0x0000FFFF)
+
+struct SalFrameState
+{
+ ULONG mnMask;
+ long mnX;
+ long mnY;
+ long mnWidth;
+ long mnHeight;
+ long mnMaximizedX;
+ long mnMaximizedY;
+ long mnMaximizedWidth;
+ long mnMaximizedHeight;
+ ULONG mnState;
+};
+
+// -------------------
+// - SalInputContext -
+// -------------------
+
+// Muessen mit den Defines in inputctx.hxx uebereinstimmen, da diese
+// nicht konvertiert werden
+#define SAL_INPUTCONTEXT_TEXT ((ULONG)0x00000001)
+#define SAL_INPUTCONTEXT_EXTTEXTINPUT ((ULONG)0x00000002)
+#define SAL_INPUTCONTEXT_EXTTEXTINPUT_ON ((ULONG)0x00000004)
+#define SAL_INPUTCONTEXT_EXTTEXTINPUT_OFF ((ULONG)0x00000008)
+#define SAL_INPUTCONTEXT_CHANGELANGUAGE ((ULONG)0x00000010)
+
+#ifdef __cplusplus
+
+struct SalInputContext
+{
+ ImplFontSelectData* mpFont;
+ LanguageType meLanguage;
+ ULONG mnOptions;
+};
+
+#endif // __cplusplus
+
+// ------------------
+// - SalTimer-Types -
+// ------------------
+
+typedef void (*SALTIMERPROC)();
+
+#endif // _SV_SALWTYPE_HXX
diff --git a/vcl/inc/vcl/scrbar.hxx b/vcl/inc/vcl/scrbar.hxx
new file mode 100644
index 000000000000..f993cb7304e4
--- /dev/null
+++ b/vcl/inc/vcl/scrbar.hxx
@@ -0,0 +1,170 @@
+/*************************************************************************
+ *
+ * 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_SCRBAR_HXX
+#define _SV_SCRBAR_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/ctrl.hxx>
+
+class AutoTimer;
+
+// -------------------
+// - ScrollBar-Types -
+// -------------------
+
+enum ScrollType { SCROLL_DONTKNOW, SCROLL_LINEUP, SCROLL_LINEDOWN,
+ SCROLL_PAGEUP, SCROLL_PAGEDOWN, SCROLL_DRAG, SCROLL_SET };
+
+// -------------
+// - ScrollBar -
+// -------------
+struct ImplScrollBarData;
+
+class VCL_DLLPUBLIC ScrollBar : public Control
+{
+private:
+ Rectangle maBtn1Rect;
+ Rectangle maBtn2Rect;
+ Rectangle maPage1Rect;
+ Rectangle maPage2Rect;
+ Rectangle maThumbRect;
+ ImplScrollBarData* mpData;
+ long mnStartPos;
+ long mnMouseOff;
+ long mnThumbPixRange;
+ long mnThumbPixPos;
+ long mnThumbPixSize;
+ long mnMinRange;
+ long mnMaxRange;
+ long mnThumbPos;
+ long mnVisibleSize;
+ long mnLineSize;
+ long mnPageSize;
+ long mnDelta;
+ USHORT mnDragDraw;
+ USHORT mnStateFlags;
+ ScrollType meScrollType;
+ ScrollType meDDScrollType;
+ BOOL mbCalcSize;
+ BOOL mbFullDrag;
+ Link maScrollHdl;
+ Link maEndScrollHdl;
+
+ SAL_DLLPRIVATE Rectangle* ImplFindPartRect( const Point& rPt );
+ using Window::ImplInit;
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle );
+ SAL_DLLPRIVATE void ImplInitStyle( WinBits nStyle );
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+ SAL_DLLPRIVATE void ImplUpdateRects( BOOL bUpdate = TRUE );
+ SAL_DLLPRIVATE long ImplCalcThumbPos( long nPixPos );
+ SAL_DLLPRIVATE long ImplCalcThumbPosPix( long nPos );
+ SAL_DLLPRIVATE void ImplCalc( BOOL bUpdate = TRUE );
+ SAL_DLLPRIVATE void ImplDraw( USHORT nDrawFlags, OutputDevice* pOutDev );
+ using Window::ImplScroll;
+ SAL_DLLPRIVATE long ImplScroll( long nNewPos, BOOL bCallEndScroll );
+ SAL_DLLPRIVATE long ImplDoAction( BOOL bCallEndScroll );
+ SAL_DLLPRIVATE void ImplDoMouseAction( const Point& rPos, BOOL bCallAction = TRUE );
+ SAL_DLLPRIVATE void ImplInvert();
+ SAL_DLLPRIVATE BOOL ImplDrawNative( USHORT nDrawFlags );
+ SAL_DLLPRIVATE void ImplDragThumb( const Point& rMousePos );
+ DECL_DLLPRIVATE_LINK( ImplTimerHdl, Timer* );
+ DECL_DLLPRIVATE_LINK( ImplAutoTimerHdl, AutoTimer* );
+
+public:
+ ScrollBar( Window* pParent, WinBits nStyle = WB_VERT );
+ ScrollBar( Window* pParent, const ResId& rResId );
+ ~ScrollBar();
+
+ virtual void MouseButtonDown( const MouseEvent& rMEvt );
+ virtual void Tracking( const TrackingEvent& rTEvt );
+ virtual void KeyInput( const KeyEvent& rKEvt );
+ virtual void Paint( const Rectangle& rRect );
+ virtual void Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG nFlags );
+ virtual void Resize();
+ virtual void StateChanged( StateChangedType nType );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+ virtual long PreNotify( NotifyEvent& rNEvt );
+ virtual void GetFocus();
+ virtual void LoseFocus();
+
+ using Window::Scroll;
+ virtual void Scroll();
+ virtual void EndScroll();
+
+ long DoScroll( long nNewPos );
+ long DoScrollAction( ScrollType eScrollType );
+
+ void EnableDrag( BOOL bEnable = TRUE )
+ { mbFullDrag = bEnable; }
+ BOOL IsDragEnabled() const { return mbFullDrag; }
+
+ void SetRangeMin( long nNewRange );
+ long GetRangeMin() const { return mnMinRange; }
+ void SetRangeMax( long nNewRange );
+ long GetRangeMax() const { return mnMaxRange; }
+ void SetRange( const Range& rRange );
+ Range GetRange() const { return Range( GetRangeMin(), GetRangeMax() ); }
+ void SetThumbPos( long nThumbPos );
+ long GetThumbPos() const { return mnThumbPos; }
+ void SetLineSize( long nNewSize ) { mnLineSize = nNewSize; }
+ long GetLineSize() const { return mnLineSize; }
+ void SetPageSize( long nNewSize ) { mnPageSize = nNewSize; }
+ long GetPageSize() const { return mnPageSize; }
+ void SetVisibleSize( long nNewSize );
+ long GetVisibleSize() const { return mnVisibleSize; }
+
+ long GetDelta() const { return mnDelta; }
+ ScrollType GetType() const { return meScrollType; }
+
+ void SetScrollHdl( const Link& rLink ) { maScrollHdl = rLink; }
+ const Link& GetScrollHdl() const { return maScrollHdl; }
+ void SetEndScrollHdl( const Link& rLink ) { maEndScrollHdl = rLink; }
+ const Link& GetEndScrollHdl() const { return maEndScrollHdl; }
+};
+
+// ----------------
+// - ScrollBarBox -
+// ----------------
+
+class VCL_DLLPUBLIC ScrollBarBox : public Window
+{
+private:
+ using Window::ImplInit;
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle );
+ SAL_DLLPRIVATE void ImplInitSettings();
+
+public:
+ ScrollBarBox( Window* pParent, WinBits nStyle = 0 );
+ ScrollBarBox( Window* pParent, const ResId& rResId );
+
+ virtual void StateChanged( StateChangedType nType );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+};
+
+#endif // _SV_SCRBAR_HXX
diff --git a/vcl/inc/vcl/seleng.hxx b/vcl/inc/vcl/seleng.hxx
new file mode 100644
index 000000000000..65539c947778
--- /dev/null
+++ b/vcl/inc/vcl/seleng.hxx
@@ -0,0 +1,253 @@
+/*************************************************************************
+ *
+ * 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_SELENG_HXX
+#define _SV_SELENG_HXX
+
+#include <vcl/dllapi.h>
+#include <vcl/timer.hxx>
+#include <vcl/event.hxx>
+
+class Window;
+class CommandEvent;
+
+// Timerticks
+#define SELENG_DRAGDROP_TIMEOUT 400
+#define SELENG_AUTOREPEAT_INTERVAL 50
+
+enum SelectionMode { NO_SELECTION, SINGLE_SELECTION, RANGE_SELECTION, MULTIPLE_SELECTION };
+
+// ---------------
+// - FunctionSet -
+// ---------------
+
+class VCL_DLLPUBLIC FunctionSet
+{
+public:
+ virtual void BeginDrag() = 0;
+
+ virtual void CreateAnchor() = 0; // Anker-Pos := Cursor-Pos
+ virtual void DestroyAnchor() = 0;
+
+ // Cursor neu setzen, dabei die beim Anker beginnende
+ // Selektion der neuen Cursor-Position anpassen. TRUE == Ok
+ virtual BOOL SetCursorAtPoint( const Point& rPointPixel,
+ BOOL bDontSelectAtCursor = FALSE ) = 0;
+
+ virtual BOOL IsSelectionAtPoint( const Point& rPointPixel ) = 0;
+ virtual void DeselectAtPoint( const Point& rPointPixel ) = 0;
+ // Anker loeschen & alles deselektieren
+ virtual void DeselectAll() = 0;
+};
+
+// -------------------
+// - SelectionEngine -
+// -------------------
+
+#define SELENG_DRG_ENAB 0x0001
+#define SELENG_IN_SEL 0x0002
+#define SELENG_IN_ADD 0x0004
+#define SELENG_ADD_ALW 0x0008
+#define SELENG_IN_DRG 0x0010
+#define SELENG_HAS_ANCH 0x0020
+#define SELENG_CMDEVT 0x0040
+#define SELENG_WAIT_UPEVT 0x0080
+#define SELENG_EXPANDONMOVE 0x0100
+
+class VCL_DLLPUBLIC SelectionEngine
+{
+private:
+ FunctionSet* pFunctionSet;
+ Window* pWin;
+ Rectangle aArea;
+ Timer aWTimer; // erzeugt kuenstliche Mouse-Moves
+ MouseEvent aLastMove;
+ SelectionMode eSelMode;
+ // Stufigkeit fuer Mausbewegungen waehrend einer Selektion
+ USHORT nMouseSensitivity;
+ USHORT nLockedMods;
+ USHORT nFlags;
+//#if 0 // _SOLAR__PRIVATE
+ DECL_DLLPRIVATE_LINK( ImpWatchDog, Timer * );
+//#endif
+
+ inline BOOL ShouldDeselect( BOOL bModifierKey1 ) const;
+ // determines to deselect or not when Ctrl-key is pressed on CursorPosChanging
+public:
+
+ SelectionEngine( Window* pWindow,
+ FunctionSet* pFunctions = NULL );
+ ~SelectionEngine();
+
+ // TRUE: Event wurde von Selection-Engine verarbeitet.
+ BOOL SelMouseButtonDown( const MouseEvent& rMEvt );
+ BOOL SelMouseButtonUp( const MouseEvent& rMEvt );
+ BOOL SelMouseMove( const MouseEvent& rMEvt );
+
+ // Tastatur
+ void CursorPosChanging( BOOL bShift, BOOL bMod1 );
+
+ // wird benoetigt, um bei ausserhalb des Bereichs stehender
+ // Maus ueber einen Timer Move-Events zu erzeugen
+ void SetVisibleArea( const Rectangle rNewArea )
+ { aArea = rNewArea; }
+ const Rectangle& GetVisibleArea() const { return aArea; }
+
+ void SetAddMode( BOOL);
+ BOOL IsAddMode() const;
+
+ void AddAlways( BOOL bOn );
+ BOOL IsAlwaysAdding() const;
+
+ void EnableDrag( BOOL bOn );
+ BOOL IsDragEnabled() const;
+ void ActivateDragMode();
+ BOOL IsInDragMode() const;
+
+ void SetSelectionMode( SelectionMode eMode );
+ SelectionMode GetSelectionMode() const { return eSelMode; }
+
+ void SetFunctionSet( FunctionSet* pFuncs )
+ { pFunctionSet = pFuncs; }
+ const FunctionSet* GetFunctionSet() const { return pFunctionSet; }
+
+ void SetMouseSensitivity( USHORT nSensitivity )
+ { nMouseSensitivity = nSensitivity; }
+ USHORT GetMouseSensitivity() const
+ { return nMouseSensitivity; }
+
+ const Point& GetMousePosPixel() const
+ { return aLastMove.GetPosPixel(); }
+ const MouseEvent& GetMouseEvent() const { return aLastMove; }
+
+ void SetWindow( Window*);
+ Window* GetWindow() const { return pWin; }
+
+ void LockModifiers( USHORT nModifiers )
+ { nLockedMods = nModifiers; }
+ USHORT GetLockedModifiers() const { return nLockedMods; }
+
+ BOOL IsInSelection() const;
+ void Reset();
+
+ void Command( const CommandEvent& rCEvt );
+
+ BOOL HasAnchor() const;
+ void SetAnchor( BOOL bAnchor );
+
+ // wird im Ctor eingeschaltet
+ void ExpandSelectionOnMouseMove( BOOL bExpand = TRUE )
+ {
+ if( bExpand )
+ nFlags |= SELENG_EXPANDONMOVE;
+ else
+ nFlags &= ~SELENG_EXPANDONMOVE;
+ }
+};
+
+inline BOOL SelectionEngine::IsDragEnabled() const
+{
+ if ( nFlags & SELENG_DRG_ENAB )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+inline BOOL SelectionEngine::IsAddMode() const
+{
+ if ( nFlags & (SELENG_IN_ADD | SELENG_ADD_ALW) )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+inline void SelectionEngine::SetAddMode( BOOL bNewMode )
+{
+ if ( bNewMode )
+ nFlags |= SELENG_IN_ADD;
+ else
+ nFlags &= (~SELENG_IN_ADD);
+}
+
+inline void SelectionEngine::EnableDrag( BOOL bOn )
+{
+ if ( bOn )
+ nFlags |= SELENG_DRG_ENAB;
+ else
+ nFlags &= (~SELENG_DRG_ENAB);
+}
+
+inline void SelectionEngine::AddAlways( BOOL bOn )
+{
+ if( bOn )
+ nFlags |= SELENG_ADD_ALW;
+ else
+ nFlags &= (~SELENG_ADD_ALW);
+}
+
+inline BOOL SelectionEngine::IsAlwaysAdding() const
+{
+ if ( nFlags & SELENG_ADD_ALW )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+inline BOOL SelectionEngine::IsInDragMode() const
+{
+ if ( nFlags & SELENG_IN_DRG )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+inline BOOL SelectionEngine::IsInSelection() const
+{
+ if ( nFlags & SELENG_IN_SEL )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+inline BOOL SelectionEngine::HasAnchor() const
+{
+ if ( nFlags & SELENG_HAS_ANCH )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+inline void SelectionEngine::SetAnchor( BOOL bAnchor )
+{
+ if ( bAnchor )
+ nFlags |= SELENG_HAS_ANCH;
+ else
+ nFlags &= (~SELENG_HAS_ANCH);
+}
+
+#endif // _SV_SELENG_HXX
+
diff --git a/vcl/inc/vcl/settings.hxx b/vcl/inc/vcl/settings.hxx
new file mode 100644
index 000000000000..24fd30750501
--- /dev/null
+++ b/vcl/inc/vcl/settings.hxx
@@ -0,0 +1,1298 @@
+/*************************************************************************
+ *
+ * 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_SETTINGS_HXX
+#define _SV_SETTINGS_HXX
+
+#include "vcl/sv.h"
+#include "vcl/dllapi.h"
+#include "tools/color.hxx"
+#include "vcl/font.hxx"
+#include "vcl/accel.hxx"
+#include "vcl/wall.hxx"
+#include "com/sun/star/lang/Locale.hpp"
+#include <unotools/syslocale.hxx>
+
+class CollatorWrapper;
+class LocaleDataWrapper;
+
+namespace vcl {
+ class I18nHelper;
+}
+
+// -------------------
+// - ImplMachineData -
+// -------------------
+
+class ImplMachineData
+{
+ friend class MachineSettings;
+
+ ImplMachineData();
+ ImplMachineData( const ImplMachineData& rData );
+
+private:
+ ULONG mnRefCount;
+ ULONG mnOptions;
+ ULONG mnScreenOptions;
+ ULONG mnPrintOptions;
+ long mnScreenRasterFontDeviation;
+};
+
+// -------------------
+// - MachineSettings -
+// -------------------
+
+class VCL_DLLPUBLIC MachineSettings
+{
+ void CopyData();
+
+private:
+ ImplMachineData* mpData;
+
+public:
+ MachineSettings();
+ MachineSettings( const MachineSettings& rSet );
+ ~MachineSettings();
+
+ void SetOptions( ULONG nOptions )
+ { CopyData(); mpData->mnOptions = nOptions; }
+ ULONG GetOptions() const
+ { return mpData->mnOptions; }
+ void SetScreenOptions( ULONG nOptions )
+ { CopyData(); mpData->mnScreenOptions = nOptions; }
+ ULONG GetScreenOptions() const
+ { return mpData->mnScreenOptions; }
+ void SetPrintOptions( ULONG nOptions )
+ { CopyData(); mpData->mnPrintOptions = nOptions; }
+ ULONG GetPrintOptions() const
+ { return mpData->mnPrintOptions; }
+
+ void SetScreenRasterFontDeviation( long nDeviation )
+ { CopyData(); mpData->mnScreenRasterFontDeviation = nDeviation; }
+ long GetScreenRasterFontDeviation() const
+ { return mpData->mnScreenRasterFontDeviation; }
+
+ const MachineSettings& operator =( const MachineSettings& rSet );
+
+ BOOL operator ==( const MachineSettings& rSet ) const;
+ BOOL operator !=( const MachineSettings& rSet ) const
+ { return !(*this == rSet); }
+};
+
+// -----------------
+// - ImplMouseData -
+// -----------------
+
+class ImplMouseData
+{
+ friend class MouseSettings;
+
+ ImplMouseData();
+ ImplMouseData( const ImplMouseData& rData );
+
+private:
+ ULONG mnRefCount;
+ ULONG mnOptions;
+ ULONG mnDoubleClkTime;
+ long mnDoubleClkWidth;
+ long mnDoubleClkHeight;
+ long mnStartDragWidth;
+ long mnStartDragHeight;
+ USHORT mnStartDragCode;
+ USHORT mnDragMoveCode;
+ USHORT mnDragCopyCode;
+ USHORT mnDragLinkCode;
+ USHORT mnContextMenuCode;
+ USHORT mnContextMenuClicks;
+ BOOL mbContextMenuDown;
+ ULONG mnScrollRepeat;
+ ULONG mnButtonStartRepeat;
+ ULONG mnButtonRepeat;
+ ULONG mnActionDelay;
+ ULONG mnMenuDelay;
+ ULONG mnFollow;
+ USHORT mnMiddleButtonAction;
+ USHORT mnWheelBehavior;
+ BOOL mbAlign1;
+};
+
+// -----------------
+// - MouseSettings -
+// -----------------
+
+#define MOUSE_OPTION_AUTOFOCUS ((ULONG)0x00000001)
+#define MOUSE_OPTION_AUTOCENTERPOS ((ULONG)0x00000002)
+#define MOUSE_OPTION_AUTODEFBTNPOS ((ULONG)0x00000004)
+
+#define MOUSE_FOLLOW_MENU ((ULONG)0x00000001)
+#define MOUSE_FOLLOW_DDLIST ((ULONG)0x00000002)
+
+#define MOUSE_MIDDLE_NOTHING ((USHORT)0)
+#define MOUSE_MIDDLE_AUTOSCROLL ((USHORT)1)
+#define MOUSE_MIDDLE_PASTESELECTION ((USHORT)2)
+
+#define MOUSE_WHEEL_DISABLE ((USHORT)0)
+#define MOUSE_WHEEL_FOCUS_ONLY ((USHORT)1)
+#define MOUSE_WHEEL_ALWAYS ((USHORT)2)
+
+class VCL_DLLPUBLIC MouseSettings
+{
+ void CopyData();
+
+private:
+ ImplMouseData* mpData;
+
+public:
+ MouseSettings();
+ MouseSettings( const MouseSettings& rSet );
+ ~MouseSettings();
+
+ void SetOptions( ULONG nOptions )
+ { CopyData(); mpData->mnOptions = nOptions; }
+ ULONG GetOptions() const
+ { return mpData->mnOptions; }
+
+ void SetDoubleClickTime( ULONG nDoubleClkTime )
+ { CopyData(); mpData->mnDoubleClkTime = nDoubleClkTime; }
+ ULONG GetDoubleClickTime() const
+ { return mpData->mnDoubleClkTime; }
+ void SetDoubleClickWidth( long nDoubleClkWidth )
+ { CopyData(); mpData->mnDoubleClkWidth = nDoubleClkWidth; }
+ long GetDoubleClickWidth() const
+ { return mpData->mnDoubleClkWidth; }
+ void SetDoubleClickHeight( long nDoubleClkHeight )
+ { CopyData(); mpData->mnDoubleClkHeight = nDoubleClkHeight; }
+ long GetDoubleClickHeight() const
+ { return mpData->mnDoubleClkHeight; }
+
+ void SetStartDragWidth( long nDragWidth )
+ { CopyData(); mpData->mnStartDragWidth = nDragWidth; }
+ long GetStartDragWidth() const
+ { return mpData->mnStartDragWidth; }
+ void SetStartDragHeight( long nDragHeight )
+ { CopyData(); mpData->mnStartDragHeight = nDragHeight; }
+ long GetStartDragHeight() const
+ { return mpData->mnStartDragHeight; }
+ void SetStartDragCode( USHORT nCode )
+ { CopyData(); mpData->mnStartDragCode = nCode; }
+ USHORT GetStartDragCode() const
+ { return mpData->mnStartDragCode; }
+ void SetDragMoveCode( USHORT nCode )
+ { CopyData(); mpData->mnDragMoveCode = nCode; }
+ USHORT GetDragMoveCode() const
+ { return mpData->mnDragMoveCode; }
+ void SetDragCopyCode( USHORT nCode )
+ { CopyData(); mpData->mnDragCopyCode = nCode; }
+ USHORT GetDragCopyCode() const
+ { return mpData->mnDragCopyCode; }
+ void SetDragLinkCode( USHORT nCode )
+ { CopyData(); mpData->mnDragLinkCode = nCode; }
+ USHORT GetDragLinkCode() const
+ { return mpData->mnDragLinkCode; }
+
+ void SetContextMenuCode( USHORT nCode )
+ { CopyData(); mpData->mnContextMenuCode = nCode; }
+ USHORT GetContextMenuCode() const
+ { return mpData->mnContextMenuCode; }
+ void SetContextMenuClicks( USHORT nClicks )
+ { CopyData(); mpData->mnContextMenuClicks = nClicks; }
+ USHORT GetContextMenuClicks() const
+ { return mpData->mnContextMenuClicks; }
+ void SetContextMenuDown( BOOL bDown )
+ { CopyData(); mpData->mbContextMenuDown = bDown; }
+ BOOL GetContextMenuDown() const
+ { return mpData->mbContextMenuDown; }
+
+ void SetScrollRepeat( ULONG nRepeat )
+ { CopyData(); mpData->mnScrollRepeat = nRepeat; }
+ ULONG GetScrollRepeat() const
+ { return mpData->mnScrollRepeat; }
+ void SetButtonStartRepeat( ULONG nRepeat )
+ { CopyData(); mpData->mnButtonStartRepeat = nRepeat; }
+ ULONG GetButtonStartRepeat() const
+ { return mpData->mnButtonStartRepeat; }
+ void SetButtonRepeat( ULONG nRepeat )
+ { CopyData(); mpData->mnButtonRepeat = nRepeat; }
+ ULONG GetButtonRepeat() const
+ { return mpData->mnButtonRepeat; }
+ void SetActionDelay( ULONG nDelay )
+ { CopyData(); mpData->mnActionDelay = nDelay; }
+ ULONG GetActionDelay() const
+ { return mpData->mnActionDelay; }
+ void SetMenuDelay( ULONG nDelay )
+ { CopyData(); mpData->mnMenuDelay = nDelay; }
+ ULONG GetMenuDelay() const
+ { return mpData->mnMenuDelay; }
+
+ void SetFollow( ULONG nFollow )
+ { CopyData(); mpData->mnFollow = nFollow; }
+ ULONG GetFollow() const
+ { return mpData->mnFollow; }
+
+ void SetMiddleButtonAction( USHORT nAction )
+ { CopyData(); mpData->mnMiddleButtonAction = nAction; }
+ USHORT GetMiddleButtonAction() const
+ { return mpData->mnMiddleButtonAction; }
+
+ void SetWheelBehavior( USHORT nBehavior )
+ { CopyData(); mpData->mnWheelBehavior = nBehavior; }
+ USHORT GetWheelBehavior() const
+ { return mpData->mnWheelBehavior; }
+
+ const MouseSettings& operator =( const MouseSettings& rSet );
+
+ BOOL operator ==( const MouseSettings& rSet ) const;
+ BOOL operator !=( const MouseSettings& rSet ) const
+ { return !(*this == rSet); }
+};
+
+// --------------------
+// - ImplKeyboardData -
+// --------------------
+
+class ImplKeyboardData
+{
+ friend class KeyboardSettings;
+
+ ImplKeyboardData();
+ ImplKeyboardData( const ImplKeyboardData& rData );
+
+private:
+ ULONG mnRefCount;
+ Accelerator maStandardAccel;
+ ULONG mnOptions;
+};
+
+// --------------------
+// - KeyboardSettings -
+// --------------------
+
+#define KEYBOARD_OPTION_QUICKCURSOR ((ULONG)0x00000001)
+
+class VCL_DLLPUBLIC KeyboardSettings
+{
+ void CopyData();
+
+private:
+ ImplKeyboardData* mpData;
+
+public:
+ KeyboardSettings();
+ KeyboardSettings( const KeyboardSettings& rSet );
+ ~KeyboardSettings();
+
+ void SetStandardAccel( const Accelerator& rAccelerator )
+ { CopyData(); mpData->maStandardAccel = rAccelerator; }
+ const Accelerator& GetStandardAccel() const
+ { return mpData->maStandardAccel; }
+
+ void SetOptions( ULONG nOptions )
+ { CopyData(); mpData->mnOptions = nOptions; }
+ ULONG GetOptions() const
+ { return mpData->mnOptions; }
+
+ const KeyboardSettings& operator =( const KeyboardSettings& rSet );
+
+ BOOL operator ==( const KeyboardSettings& rSet ) const;
+ BOOL operator !=( const KeyboardSettings& rSet ) const
+ { return !(*this == rSet); }
+};
+
+// -----------------
+// - ImplStyleData -
+// -----------------
+
+class ImplStyleData
+{
+ friend class StyleSettings;
+
+ ImplStyleData();
+ ImplStyleData( const ImplStyleData& rData );
+ void SetStandardStyles();
+
+private:
+ ULONG mnRefCount;
+
+ void* mpStyleData_NotUsedYet;
+
+ Color maActiveBorderColor;
+ Color maActiveColor;
+ Color maActiveColor2;
+ Color maActiveTextColor;
+ Color maButtonTextColor;
+ Color maButtonRolloverTextColor;
+ Color maCheckedColor;
+ Color maDarkShadowColor;
+ Color maDeactiveBorderColor;
+ Color maDeactiveColor;
+ Color maDeactiveColor2;
+ Color maDeactiveTextColor;
+ Color maDialogColor;
+ Color maDialogTextColor;
+ Color maDisableColor;
+ Color maFaceColor;
+ Color maFieldColor;
+ Color maFieldTextColor;
+ Color maFieldRolloverTextColor;
+ Color maFontColor;
+ Color maGroupTextColor;
+ Color maHelpColor;
+ Color maHelpTextColor;
+ Color maHighlightColor;
+ Color maHighlightLinkColor;
+ Color maHighlightTextColor;
+ Color maInfoTextColor;
+ Color maLabelTextColor;
+ Color maLightBorderColor;
+ Color maLightColor;
+ Color maLinkColor;
+ Color maMenuBarColor;
+ Color maMenuBorderColor;
+ Color maMenuColor;
+ Color maMenuHighlightColor;
+ Color maMenuHighlightTextColor;
+ Color maMenuTextColor;
+ Color maMenuBarTextColor;
+ Color maMonoColor;
+ Color maRadioCheckTextColor;
+ Color maShadowColor;
+ Color maVisitedLinkColor;
+ Color maWindowColor;
+ Color maWindowTextColor;
+ Color maWorkspaceColor;
+ Color maActiveTabColor;
+ Color maInactiveTabColor;
+ Font maAppFont;
+ Font maHelpFont;
+ Font maTitleFont;
+ Font maFloatTitleFont;
+ Font maMenuFont;
+ Font maToolFont;
+ Font maLabelFont;
+ Font maInfoFont;
+ Font maRadioCheckFont;
+ Font maPushButtonFont;
+ Font maFieldFont;
+ Font maIconFont;
+ Font maGroupFont;
+ long mnBorderSize;
+ long mnTitleHeight;
+ long mnFloatTitleHeight;
+ long mnTearOffTitleHeight;
+ long mnScrollBarSize;
+ long mnSplitSize;
+ long mnSpinSize;
+ long mnCursorSize;
+ long mnMenuBarHeight;
+ long mnIconHorzSpace;
+ long mnIconVertSpace;
+ long mnAntialiasedMin;
+ ULONG mnCursorBlinkTime;
+ ULONG mnDragFullOptions;
+ ULONG mnAnimationOptions;
+ ULONG mnSelectionOptions;
+ ULONG mnLogoDisplayTime;
+ ULONG mnDisplayOptions;
+ ULONG mnToolbarIconSize;
+ ULONG mnUseFlatMenues;
+ ULONG mnOptions;
+ USHORT mnScreenZoom;
+ USHORT mnScreenFontZoom;
+ USHORT mnRadioButtonStyle;
+ USHORT mnCheckBoxStyle;
+ USHORT mnPushButtonStyle;
+ USHORT mnTabControlStyle;
+ USHORT mnHighContrast;
+ USHORT mnUseSystemUIFonts;
+ USHORT mnAutoMnemonic;
+ USHORT mnUseImagesInMenus;
+ ULONG mnUseFlatBorders;
+ long mnMinThumbSize;
+ ULONG mnSymbolsStyle;
+ ULONG mnPreferredSymbolsStyle;
+ USHORT mnSkipDisabledInMenus;
+ Wallpaper maWorkspaceGradient;
+ const void* mpFontOptions;
+};
+
+#define DEFAULT_WORKSPACE_GRADIENT_START_COLOR Color( 0xa3, 0xae, 0xb8 )
+#define DEFAULT_WORKSPACE_GRADIENT_END_COLOR Color( 0x73, 0x7e, 0x88 )
+
+// -----------------
+// - StyleSettings -
+// -----------------
+
+#define STYLE_OPTION_MONO ((ULONG)0x00000001)
+#define STYLE_OPTION_COLOR ((ULONG)0x00000002)
+#define STYLE_OPTION_FLAT ((ULONG)0x00000004)
+#define STYLE_OPTION_GREAT ((ULONG)0x00000008)
+#define STYLE_OPTION_HIGHLIGHT ((ULONG)0x00000010)
+#define STYLE_OPTION_ADVANCEDUSER ((ULONG)0x00000020)
+#define STYLE_OPTION_SCROLLARROW ((ULONG)0x00000040)
+#define STYLE_OPTION_SPINARROW ((ULONG)0x00000080)
+#define STYLE_OPTION_SPINUPDOWN ((ULONG)0x00000100)
+#define STYLE_OPTION_NOMNEMONICS ((ULONG)0x00000200)
+#define STYLE_OPTION_WINSTYLE ((ULONG)0x00010000)
+#define STYLE_OPTION_OS2STYLE ((ULONG)0x00020000)
+#define STYLE_OPTION_MACSTYLE ((ULONG)0x00040000)
+#define STYLE_OPTION_UNIXSTYLE ((ULONG)0x00080000)
+#define STYLE_OPTION_SYSTEMSTYLE ((ULONG)0x000F0000)
+#define STYLE_OPTION_HIDEDISABLED ((ULONG)0x00100000)
+
+#define DRAGFULL_OPTION_WINDOWMOVE ((ULONG)0x00000001)
+#define DRAGFULL_OPTION_WINDOWSIZE ((ULONG)0x00000002)
+#define DRAGFULL_OPTION_OBJECTMOVE ((ULONG)0x00000004)
+#define DRAGFULL_OPTION_OBJECTSIZE ((ULONG)0x00000008)
+#define DRAGFULL_OPTION_DOCKING ((ULONG)0x00000010)
+#define DRAGFULL_OPTION_SPLIT ((ULONG)0x00000020)
+#define DRAGFULL_OPTION_SCROLL ((ULONG)0x00000040)
+
+#define LOGO_DISPLAYTIME_NOLOGO ((ULONG)0)
+#define LOGO_DISPLAYTIME_STARTTIME ((ULONG)0xFFFFFFFF)
+
+#define ANIMATION_OPTION_MINIMIZE ((ULONG)0x00000001)
+#define ANIMATION_OPTION_POPUP ((ULONG)0x00000002)
+#define ANIMATION_OPTION_DIALOG ((ULONG)0x00000004)
+#define ANIMATION_OPTION_TREE ((ULONG)0x00000008)
+#define ANIMATION_OPTION_SCROLL ((ULONG)0x00000010)
+
+#define SELECTION_OPTION_WORD ((ULONG)0x00000001)
+#define SELECTION_OPTION_FOCUS ((ULONG)0x00000002)
+#define SELECTION_OPTION_INVERT ((ULONG)0x00000004)
+#define SELECTION_OPTION_SHOWFIRST ((ULONG)0x00000008)
+
+#define DISPLAY_OPTION_AA_DISABLE ((ULONG)0x00000001)
+
+#define STYLE_RADIOBUTTON_WIN ((USHORT)0x0001)
+#define STYLE_RADIOBUTTON_OS2 ((USHORT)0x0002)
+#define STYLE_RADIOBUTTON_MAC ((USHORT)0x0003)
+#define STYLE_RADIOBUTTON_UNIX ((USHORT)0x0004)
+#define STYLE_RADIOBUTTON_MONO ((USHORT)0x0005)
+#define STYLE_RADIOBUTTON_STYLE ((USHORT)0x000F)
+
+#define STYLE_CHECKBOX_WIN ((USHORT)0x0001)
+#define STYLE_CHECKBOX_OS2 ((USHORT)0x0002)
+#define STYLE_CHECKBOX_MAC ((USHORT)0x0003)
+#define STYLE_CHECKBOX_UNIX ((USHORT)0x0004)
+#define STYLE_CHECKBOX_MONO ((USHORT)0x0005)
+#define STYLE_CHECKBOX_STYLE ((USHORT)0x000F)
+
+#define STYLE_PUSHBUTTON_WIN ((USHORT)0x0001)
+#define STYLE_PUSHBUTTON_OS2 ((USHORT)0x0002)
+#define STYLE_PUSHBUTTON_MAC ((USHORT)0x0003)
+#define STYLE_PUSHBUTTON_UNIX ((USHORT)0x0004)
+#define STYLE_PUSHBUTTON_STYLE ((USHORT)0x000F)
+
+#define STYLE_TABCONTROL_SINGLELINE ((USHORT)0x0001)
+#define STYLE_TABCONTROL_COLOR ((USHORT)0x0002)
+
+#define STYLE_TOOLBAR_ICONSIZE_UNKNOWN ((ULONG)0)
+#define STYLE_TOOLBAR_ICONSIZE_SMALL ((ULONG)1)
+#define STYLE_TOOLBAR_ICONSIZE_LARGE ((ULONG)2)
+
+#define STYLE_SYMBOLS_AUTO ((ULONG)0)
+#define STYLE_SYMBOLS_DEFAULT ((ULONG)1)
+#define STYLE_SYMBOLS_HICONTRAST ((ULONG)2)
+#define STYLE_SYMBOLS_INDUSTRIAL ((ULONG)3)
+#define STYLE_SYMBOLS_CRYSTAL ((ULONG)4)
+#define STYLE_SYMBOLS_TANGO ((ULONG)5)
+#define STYLE_SYMBOLS_OXYGEN ((ULONG)6)
+#define STYLE_SYMBOLS_CLASSIC ((ULONG)7)
+#define STYLE_SYMBOLS_THEMES_MAX ((ULONG)8)
+
+#define STYLE_CURSOR_NOBLINKTIME ((ULONG)0xFFFFFFFF)
+
+class VCL_DLLPUBLIC StyleSettings
+{
+ void CopyData();
+
+private:
+ ImplStyleData* mpData;
+
+public:
+ StyleSettings();
+ StyleSettings( const StyleSettings& rSet );
+ ~StyleSettings();
+
+ void Set3DColors( const Color& rColor );
+ void SetFaceColor( const Color& rColor )
+ { CopyData(); mpData->maFaceColor = rColor; }
+ const Color& GetFaceColor() const
+ { return mpData->maFaceColor; }
+ Color GetFaceGradientColor() const;
+ Color GetSeparatorColor() const;
+ void SetCheckedColor( const Color& rColor )
+ { CopyData(); mpData->maCheckedColor = rColor; }
+ const Color& GetCheckedColor() const
+ { return mpData->maCheckedColor; }
+ void SetLightColor( const Color& rColor )
+ { CopyData(); mpData->maLightColor = rColor; }
+ const Color& GetLightColor() const
+ { return mpData->maLightColor; }
+ void SetLightBorderColor( const Color& rColor )
+ { CopyData(); mpData->maLightBorderColor = rColor; }
+ const Color& GetLightBorderColor() const
+ { return mpData->maLightBorderColor; }
+ void SetShadowColor( const Color& rColor )
+ { CopyData(); mpData->maShadowColor = rColor; }
+ const Color& GetShadowColor() const
+ { return mpData->maShadowColor; }
+ void SetDarkShadowColor( const Color& rColor )
+ { CopyData(); mpData->maDarkShadowColor = rColor; }
+ const Color& GetDarkShadowColor() const
+ { return mpData->maDarkShadowColor; }
+ void SetButtonTextColor( const Color& rColor )
+ { CopyData(); mpData->maButtonTextColor = rColor; }
+ const Color& GetButtonTextColor() const
+ { return mpData->maButtonTextColor; }
+ void SetButtonRolloverTextColor( const Color& rColor )
+ { CopyData(); mpData->maButtonRolloverTextColor = rColor; }
+ const Color& GetButtonRolloverTextColor() const
+ { return mpData->maButtonRolloverTextColor; }
+ void SetRadioCheckTextColor( const Color& rColor )
+ { CopyData(); mpData->maRadioCheckTextColor = rColor; }
+ const Color& GetRadioCheckTextColor() const
+ { return mpData->maRadioCheckTextColor; }
+ void SetGroupTextColor( const Color& rColor )
+ { CopyData(); mpData->maGroupTextColor = rColor; }
+ const Color& GetGroupTextColor() const
+ { return mpData->maGroupTextColor; }
+ void SetLabelTextColor( const Color& rColor )
+ { CopyData(); mpData->maLabelTextColor = rColor; }
+ const Color& GetLabelTextColor() const
+ { return mpData->maLabelTextColor; }
+ void SetInfoTextColor( const Color& rColor )
+ { CopyData(); mpData->maInfoTextColor = rColor; }
+ const Color& GetInfoTextColor() const
+ { return mpData->maInfoTextColor; }
+ void SetWindowColor( const Color& rColor )
+ { CopyData(); mpData->maWindowColor = rColor; }
+ const Color& GetWindowColor() const
+ { return mpData->maWindowColor; }
+ void SetWindowTextColor( const Color& rColor )
+ { CopyData(); mpData->maWindowTextColor = rColor; }
+ const Color& GetWindowTextColor() const
+ { return mpData->maWindowTextColor; }
+ void SetDialogColor( const Color& rColor )
+ { CopyData(); mpData->maDialogColor = rColor; }
+ const Color& GetDialogColor() const
+ { return mpData->maDialogColor; }
+ void SetDialogTextColor( const Color& rColor )
+ { CopyData(); mpData->maDialogTextColor = rColor; }
+ const Color& GetDialogTextColor() const
+ { return mpData->maDialogTextColor; }
+ void SetWorkspaceColor( const Color& rColor )
+ { CopyData(); mpData->maWorkspaceColor = rColor; }
+ const Color& GetWorkspaceColor() const
+ { return mpData->maWorkspaceColor; }
+ void SetFieldColor( const Color& rColor )
+ { CopyData(); mpData->maFieldColor = rColor; }
+ const Color& GetFieldColor() const
+ { return mpData->maFieldColor; }
+ void SetFieldTextColor( const Color& rColor )
+ { CopyData(); mpData->maFieldTextColor = rColor; }
+ const Color& GetFieldTextColor() const
+ { return mpData->maFieldTextColor; }
+ void SetFieldRolloverTextColor( const Color& rColor )
+ { CopyData(); mpData->maFieldRolloverTextColor = rColor; }
+ const Color& GetFieldRolloverTextColor() const
+ { return mpData->maFieldRolloverTextColor; }
+ void SetActiveColor( const Color& rColor )
+ { CopyData(); mpData->maActiveColor = rColor; }
+ const Color& GetActiveColor() const
+ { return mpData->maActiveColor; }
+ void SetActiveColor2( const Color& rColor )
+ { CopyData(); mpData->maActiveColor2 = rColor; }
+ const Color& GetActiveColor2() const
+ { return mpData->maActiveColor2; }
+ void SetActiveTextColor( const Color& rColor )
+ { CopyData(); mpData->maActiveTextColor = rColor; }
+ const Color& GetActiveTextColor() const
+ { return mpData->maActiveTextColor; }
+ void SetActiveBorderColor( const Color& rColor )
+ { CopyData(); mpData->maActiveBorderColor = rColor; }
+ const Color& GetActiveBorderColor() const
+ { return mpData->maActiveBorderColor; }
+ void SetDeactiveColor( const Color& rColor )
+ { CopyData(); mpData->maDeactiveColor = rColor; }
+ const Color& GetDeactiveColor() const
+ { return mpData->maDeactiveColor; }
+ void SetDeactiveColor2( const Color& rColor )
+ { CopyData(); mpData->maDeactiveColor2 = rColor; }
+ const Color& GetDeactiveColor2() const
+ { return mpData->maDeactiveColor2; }
+ void SetDeactiveTextColor( const Color& rColor )
+ { CopyData(); mpData->maDeactiveTextColor = rColor; }
+ const Color& GetDeactiveTextColor() const
+ { return mpData->maDeactiveTextColor; }
+ void SetDeactiveBorderColor( const Color& rColor )
+ { CopyData(); mpData->maDeactiveBorderColor = rColor; }
+ const Color& GetDeactiveBorderColor() const
+ { return mpData->maDeactiveBorderColor; }
+ void SetHighlightColor( const Color& rColor )
+ { CopyData(); mpData->maHighlightColor = rColor; }
+ const Color& GetHighlightColor() const
+ { return mpData->maHighlightColor; }
+ void SetHighlightTextColor( const Color& rColor )
+ { CopyData(); mpData->maHighlightTextColor = rColor; }
+ const Color& GetHighlightTextColor() const
+ { return mpData->maHighlightTextColor; }
+ void SetDisableColor( const Color& rColor )
+ { CopyData(); mpData->maDisableColor = rColor; }
+ const Color& GetDisableColor() const
+ { return mpData->maDisableColor; }
+ void SetHelpColor( const Color& rColor )
+ { CopyData(); mpData->maHelpColor = rColor; }
+ const Color& GetHelpColor() const
+ { return mpData->maHelpColor; }
+ void SetHelpTextColor( const Color& rColor )
+ { CopyData(); mpData->maHelpTextColor = rColor; }
+ const Color& GetHelpTextColor() const
+ { return mpData->maHelpTextColor; }
+ void SetMenuColor( const Color& rColor )
+ { CopyData(); mpData->maMenuColor = rColor; }
+ const Color& GetMenuColor() const
+ { return mpData->maMenuColor; }
+ void SetMenuBarColor( const Color& rColor )
+ { CopyData(); mpData->maMenuBarColor = rColor; }
+ const Color& GetMenuBarColor() const
+ { return mpData->maMenuBarColor; }
+ void SetMenuBorderColor( const Color& rColor )
+ { CopyData(); mpData->maMenuBorderColor = rColor; }
+ const Color& GetMenuBorderColor() const
+ { return mpData->maMenuBorderColor; }
+ void SetMenuTextColor( const Color& rColor )
+ { CopyData(); mpData->maMenuTextColor = rColor; }
+ const Color& GetMenuTextColor() const
+ { return mpData->maMenuTextColor; }
+ void SetMenuBarTextColor( const Color& rColor )
+ { CopyData(); mpData->maMenuBarTextColor = rColor; }
+ const Color& GetMenuBarTextColor() const
+ { return mpData->maMenuBarTextColor; }
+ void SetMenuHighlightColor( const Color& rColor )
+ { CopyData(); mpData->maMenuHighlightColor = rColor; }
+ const Color& GetMenuHighlightColor() const
+ { return mpData->maMenuHighlightColor; }
+ void SetMenuHighlightTextColor( const Color& rColor )
+ { CopyData(); mpData->maMenuHighlightTextColor = rColor; }
+ const Color& GetMenuHighlightTextColor() const
+ { return mpData->maMenuHighlightTextColor; }
+ void SetLinkColor( const Color& rColor )
+ { CopyData(); mpData->maLinkColor = rColor; }
+ const Color& GetLinkColor() const
+ { return mpData->maLinkColor; }
+ void SetVisitedLinkColor( const Color& rColor )
+ { CopyData(); mpData->maVisitedLinkColor = rColor; }
+ const Color& GetVisitedLinkColor() const
+ { return mpData->maVisitedLinkColor; }
+ void SetHighlightLinkColor( const Color& rColor )
+ { CopyData(); mpData->maHighlightLinkColor = rColor; }
+ const Color& GetHighlightLinkColor() const
+ { return mpData->maHighlightLinkColor; }
+
+ void SetMonoColor( const Color& rColor )
+ { CopyData(); mpData->maMonoColor = rColor; }
+ const Color& GetMonoColor() const
+ { return mpData->maMonoColor; }
+
+ void SetActiveTabColor( const Color& rColor )
+ { CopyData(); mpData->maActiveTabColor = rColor; }
+ const Color& GetActiveTabColor() const
+ { return mpData->maActiveTabColor; }
+ void SetInactiveTabColor( const Color& rColor )
+ { CopyData(); mpData->maInactiveTabColor = rColor; }
+ const Color& GetInactiveTabColor() const
+ { return mpData->maInactiveTabColor; }
+
+ void SetHighContrastMode( BOOL bHighContrast )
+ { CopyData(); mpData->mnHighContrast = bHighContrast; }
+ BOOL GetHighContrastMode() const
+ { return (BOOL) mpData->mnHighContrast; }
+ BOOL IsHighContrastBlackAndWhite() const;
+ void SetUseSystemUIFonts( BOOL bUseSystemUIFonts )
+ { CopyData(); mpData->mnUseSystemUIFonts = bUseSystemUIFonts; }
+ BOOL GetUseSystemUIFonts() const
+ { return (BOOL) mpData->mnUseSystemUIFonts; }
+ void SetUseFlatBorders( BOOL bUseFlatBorders )
+ { CopyData(); mpData->mnUseFlatBorders = bUseFlatBorders; }
+ BOOL GetUseFlatBorders() const
+ { return (BOOL) mpData->mnUseFlatBorders; }
+ void SetUseFlatMenues( BOOL bUseFlatMenues )
+ { CopyData(); mpData->mnUseFlatMenues = bUseFlatMenues; }
+ BOOL GetUseFlatMenues() const
+ { return (BOOL) mpData->mnUseFlatMenues; }
+ void SetUseImagesInMenus( BOOL bUseImagesInMenus )
+ { CopyData(); mpData->mnUseImagesInMenus = bUseImagesInMenus; }
+ BOOL GetUseImagesInMenus() const
+ { return (BOOL) mpData->mnUseImagesInMenus; }
+ void SetSkipDisabledInMenus( BOOL bSkipDisabledInMenus )
+ { CopyData(); mpData->mnSkipDisabledInMenus = bSkipDisabledInMenus; }
+ BOOL GetSkipDisabledInMenus() const
+ { return (BOOL) mpData->mnSkipDisabledInMenus; }
+
+ void SetCairoFontOptions( const void *pOptions )
+ { CopyData(); mpData->mpFontOptions = pOptions; }
+ const void* GetCairoFontOptions() const
+ { return mpData->mpFontOptions; }
+
+ void SetAppFont( const Font& rFont )
+ { CopyData(); mpData->maAppFont = rFont; }
+ const Font& GetAppFont() const
+ { return mpData->maAppFont; }
+ void SetHelpFont( const Font& rFont )
+ { CopyData(); mpData->maHelpFont = rFont; }
+ const Font& GetHelpFont() const
+ { return mpData->maHelpFont; }
+ void SetTitleFont( const Font& rFont )
+ { CopyData(); mpData->maTitleFont = rFont; }
+ const Font& GetTitleFont() const
+ { return mpData->maTitleFont; }
+ void SetFloatTitleFont( const Font& rFont )
+ { CopyData(); mpData->maFloatTitleFont = rFont; }
+ const Font& GetFloatTitleFont() const
+ { return mpData->maFloatTitleFont; }
+ void SetMenuFont( const Font& rFont )
+ { CopyData(); mpData->maMenuFont = rFont; }
+ const Font& GetMenuFont() const
+ { return mpData->maMenuFont; }
+ void SetToolFont( const Font& rFont )
+ { CopyData(); mpData->maToolFont = rFont; }
+ const Font& GetToolFont() const
+ { return mpData->maToolFont; }
+ void SetGroupFont( const Font& rFont )
+ { CopyData(); mpData->maGroupFont = rFont; }
+ const Font& GetGroupFont() const
+ { return mpData->maGroupFont; }
+ void SetLabelFont( const Font& rFont )
+ { CopyData(); mpData->maLabelFont = rFont; }
+ const Font& GetLabelFont() const
+ { return mpData->maLabelFont; }
+ void SetInfoFont( const Font& rFont )
+ { CopyData(); mpData->maInfoFont = rFont; }
+ const Font& GetInfoFont() const
+ { return mpData->maInfoFont; }
+ void SetRadioCheckFont( const Font& rFont )
+ { CopyData(); mpData->maRadioCheckFont = rFont; }
+ const Font& GetRadioCheckFont() const
+ { return mpData->maRadioCheckFont; }
+ void SetPushButtonFont( const Font& rFont )
+ { CopyData(); mpData->maPushButtonFont = rFont; }
+ const Font& GetPushButtonFont() const
+ { return mpData->maPushButtonFont; }
+ void SetFieldFont( const Font& rFont )
+ { CopyData(); mpData->maFieldFont = rFont; }
+ const Font& GetFieldFont() const
+ { return mpData->maFieldFont; }
+ void SetIconFont( const Font& rFont )
+ { CopyData(); mpData->maIconFont = rFont; }
+ const Font& GetIconFont() const
+ { return mpData->maIconFont; }
+
+ void SetRadioButtonStyle( USHORT nStyle )
+ { CopyData(); mpData->mnRadioButtonStyle = nStyle; }
+ USHORT GetRadioButtonStyle() const
+ { return mpData->mnRadioButtonStyle; }
+ void SetCheckBoxStyle( USHORT nStyle )
+ { CopyData(); mpData->mnCheckBoxStyle = nStyle; }
+ USHORT GetCheckBoxStyle() const
+ { return mpData->mnCheckBoxStyle; }
+ void SetPushButtonStyle( USHORT nStyle )
+ { CopyData(); mpData->mnPushButtonStyle = nStyle; }
+ USHORT GetPushButtonStyle() const
+ { return mpData->mnPushButtonStyle; }
+ void SetTabControlStyle( USHORT nStyle )
+ { CopyData(); mpData->mnTabControlStyle = nStyle; }
+ USHORT GetTabControlStyle() const
+ { return mpData->mnTabControlStyle; }
+
+ void SetBorderSize( long nSize )
+ { CopyData(); mpData->mnBorderSize = nSize; }
+ long GetBorderSize() const
+ { return mpData->mnBorderSize; }
+ void SetTitleHeight( long nSize )
+ { CopyData(); mpData->mnTitleHeight = nSize; }
+ long GetTitleHeight() const
+ { return mpData->mnTitleHeight; }
+ void SetFloatTitleHeight( long nSize )
+ { CopyData(); mpData->mnFloatTitleHeight = nSize; }
+ long GetFloatTitleHeight() const
+ { return mpData->mnFloatTitleHeight; }
+ void SetTearOffTitleHeight( long nSize )
+ { CopyData(); mpData->mnTearOffTitleHeight = nSize; }
+ long GetTearOffTitleHeight() const
+ { return mpData->mnTearOffTitleHeight; }
+ void SetMenuBarHeight( long nSize )
+ { CopyData(); mpData->mnMenuBarHeight = nSize; }
+ long GetMenuBarHeight() const
+ { return mpData->mnMenuBarHeight; }
+ void SetScrollBarSize( long nSize )
+ { CopyData(); mpData->mnScrollBarSize = nSize; }
+ long GetScrollBarSize() const
+ { return mpData->mnScrollBarSize; }
+ void SetMinThumbSize( long nSize )
+ { CopyData(); mpData->mnMinThumbSize = nSize; }
+ long GetMinThumbSize() const
+ { return mpData->mnMinThumbSize; }
+ void SetSpinSize( long nSize )
+ { CopyData(); mpData->mnSpinSize = nSize; }
+ long GetSpinSize() const
+ { return mpData->mnSpinSize; }
+ void SetSplitSize( long nSize )
+ { CopyData(); mpData->mnSplitSize = nSize; }
+ long GetSplitSize() const
+ { return mpData->mnSplitSize; }
+
+ void SetIconHorzSpace( long nSpace )
+ { CopyData(); mpData->mnIconHorzSpace = nSpace; }
+ long GetIconHorzSpace() const
+ { return mpData->mnIconHorzSpace; }
+ void SetIconVertSpace( long nSpace )
+ { CopyData(); mpData->mnIconVertSpace = nSpace; }
+ long GetIconVertSpace() const
+ { return mpData->mnIconVertSpace; }
+
+ void SetCursorSize( long nSize )
+ { CopyData(); mpData->mnCursorSize = nSize; }
+ long GetCursorSize() const
+ { return mpData->mnCursorSize; }
+ void SetCursorBlinkTime( long nBlinkTime )
+ { CopyData(); mpData->mnCursorBlinkTime = nBlinkTime; }
+ long GetCursorBlinkTime() const
+ { return mpData->mnCursorBlinkTime; }
+
+ void SetScreenZoom( USHORT nPercent )
+ { CopyData(); mpData->mnScreenZoom = nPercent; }
+ USHORT GetScreenZoom() const
+ { return mpData->mnScreenZoom; }
+ void SetScreenFontZoom( USHORT nPercent )
+ { CopyData(); mpData->mnScreenFontZoom = nPercent; }
+ USHORT GetScreenFontZoom() const
+ { return mpData->mnScreenFontZoom; }
+
+ void SetLogoDisplayTime( ULONG nDisplayTime )
+ { CopyData(); mpData->mnLogoDisplayTime = nDisplayTime; }
+ ULONG GetLogoDisplayTime() const
+ { return mpData->mnLogoDisplayTime; }
+
+ void SetDragFullOptions( ULONG nOptions )
+ { CopyData(); mpData->mnDragFullOptions = nOptions; }
+ ULONG GetDragFullOptions() const
+ { return mpData->mnDragFullOptions; }
+
+ void SetAnimationOptions( ULONG nOptions )
+ { CopyData(); mpData->mnAnimationOptions = nOptions; }
+ ULONG GetAnimationOptions() const
+ { return mpData->mnAnimationOptions; }
+
+ void SetSelectionOptions( ULONG nOptions )
+ { CopyData(); mpData->mnSelectionOptions = nOptions; }
+ ULONG GetSelectionOptions() const
+ { return mpData->mnSelectionOptions; }
+
+ void SetDisplayOptions( ULONG nOptions )
+ { CopyData(); mpData->mnDisplayOptions = nOptions; }
+ ULONG GetDisplayOptions() const
+ { return mpData->mnDisplayOptions; }
+ void SetAntialiasingMinPixelHeight( long nMinPixel )
+ { CopyData(); mpData->mnAntialiasedMin = nMinPixel; }
+ ULONG GetAntialiasingMinPixelHeight() const
+ { return mpData->mnAntialiasedMin; }
+
+ void SetOptions( ULONG nOptions )
+ { CopyData(); mpData->mnOptions = nOptions; }
+ ULONG GetOptions() const
+ { return mpData->mnOptions; }
+ void SetAutoMnemonic( BOOL bAutoMnemonic )
+ { CopyData(); mpData->mnAutoMnemonic = (USHORT)bAutoMnemonic; }
+ BOOL GetAutoMnemonic() const
+ { return mpData->mnAutoMnemonic ? TRUE : FALSE; }
+
+ void SetFontColor( const Color& rColor )
+ { CopyData(); mpData->maFontColor = rColor; }
+ const Color& GetFontColor() const
+ { return mpData->maFontColor; }
+
+ void SetToolbarIconSize( ULONG nSize )
+ { CopyData(); mpData->mnToolbarIconSize = nSize; }
+ ULONG GetToolbarIconSize() const
+ { return mpData->mnToolbarIconSize; }
+
+ void SetSymbolsStyle( ULONG nStyle )
+ { CopyData(); mpData->mnSymbolsStyle = nStyle; }
+ ULONG GetSymbolsStyle() const
+ { return mpData->mnSymbolsStyle; }
+
+ void SetPreferredSymbolsStyle( ULONG nStyle )
+ { CopyData(); mpData->mnPreferredSymbolsStyle = nStyle; }
+ void SetPreferredSymbolsStyleName( const ::rtl::OUString &rName );
+ ULONG GetPreferredSymbolsStyle() const
+ { return mpData->mnPreferredSymbolsStyle; }
+ // check whether the symbols style is supported (icons are installed)
+ bool CheckSymbolStyle( ULONG nStyle ) const;
+ ULONG GetAutoSymbolsStyle() const;
+
+ ULONG GetCurrentSymbolsStyle() const;
+
+ void SetSymbolsStyleName( const ::rtl::OUString &rName )
+ { return SetSymbolsStyle( ImplNameToSymbolsStyle( rName ) ); }
+ ::rtl::OUString GetSymbolsStyleName() const
+ { return ImplSymbolsStyleToName( GetSymbolsStyle() ); }
+ ::rtl::OUString GetCurrentSymbolsStyleName() const
+ { return ImplSymbolsStyleToName( GetCurrentSymbolsStyle() ); }
+
+ const Wallpaper& GetWorkspaceGradient() const
+ { return mpData->maWorkspaceGradient; }
+ void SetWorkspaceGradient( const Wallpaper& rWall )
+ { CopyData(); mpData->maWorkspaceGradient = rWall; }
+
+ void SetStandardStyles();
+ void SetStandardWinStyles();
+ void SetStandardOS2Styles();
+ void SetStandardMacStyles();
+ void SetStandardUnixStyles();
+
+ const StyleSettings& operator =( const StyleSettings& rSet );
+
+ BOOL operator ==( const StyleSettings& rSet ) const;
+ BOOL operator !=( const StyleSettings& rSet ) const
+ { return !(*this == rSet); }
+
+protected:
+ ::rtl::OUString ImplSymbolsStyleToName( ULONG nStyle ) const;
+ ULONG ImplNameToSymbolsStyle( const ::rtl::OUString &rName ) const;
+};
+
+// ----------------
+// - ImplMiscData -
+// ----------------
+
+class ImplMiscData
+{
+ friend class MiscSettings;
+
+ ImplMiscData();
+ ImplMiscData( const ImplMiscData& rData );
+
+private:
+ ULONG mnRefCount;
+ USHORT mnEnableATT;
+ BOOL mbEnableLocalizedDecimalSep;
+ USHORT mnDisablePrinting;
+};
+
+// ----------------
+// - MiscSettings -
+// ----------------
+
+class VCL_DLLPUBLIC MiscSettings
+{
+ void CopyData();
+
+private:
+ ImplMiscData* mpData;
+
+public:
+ MiscSettings();
+ MiscSettings( const MiscSettings& rSet );
+ ~MiscSettings();
+
+ void SetEnableATToolSupport( BOOL bEnable );
+ BOOL GetEnableATToolSupport() const;
+ void SetDisablePrinting( BOOL bEnable );
+ BOOL GetDisablePrinting() const;
+ void SetEnableLocalizedDecimalSep( BOOL bEnable );
+ BOOL GetEnableLocalizedDecimalSep() const;
+ const MiscSettings& operator =( const MiscSettings& rSet );
+
+ BOOL operator ==( const MiscSettings& rSet ) const;
+ BOOL operator !=( const MiscSettings& rSet ) const
+ { return !(*this == rSet); }
+};
+
+// ------------------------
+// - ImplNotificationData -
+// ------------------------
+
+class ImplNotificationData
+{
+ friend class NotificationSettings;
+
+ ImplNotificationData();
+ ImplNotificationData( const ImplNotificationData& rData );
+
+private:
+ ULONG mnRefCount;
+ ULONG mnOptions;
+};
+
+// ------------------------
+// - NotificationSettings -
+// ------------------------
+
+class VCL_DLLPUBLIC NotificationSettings
+{
+ void CopyData();
+
+private:
+ ImplNotificationData* mpData;
+
+public:
+ NotificationSettings();
+ NotificationSettings( const NotificationSettings& rSet );
+ ~NotificationSettings();
+
+ void SetOptions( ULONG nOptions )
+ { CopyData(); mpData->mnOptions = nOptions; }
+ ULONG GetOptions() const
+ { return mpData->mnOptions; }
+
+ const NotificationSettings& operator =( const NotificationSettings& rSet );
+
+ BOOL operator ==( const NotificationSettings& rSet ) const;
+ BOOL operator !=( const NotificationSettings& rSet ) const
+ { return !(*this == rSet); }
+};
+
+// ----------------
+// - ImplHelpData -
+// ----------------
+
+class ImplHelpData
+{
+ friend class HelpSettings;
+
+ ImplHelpData();
+ ImplHelpData( const ImplHelpData& rData );
+
+private:
+ ULONG mnRefCount;
+ ULONG mnOptions;
+ ULONG mnTipDelay;
+ ULONG mnTipTimeout;
+ ULONG mnBalloonDelay;
+};
+
+// ----------------
+// - HelpSettings -
+// ----------------
+
+#define HELP_OPTION_QUICK ((ULONG)0x00000001)
+#define HELP_OPTION_ACTIVE ((ULONG)0x00000002)
+
+class VCL_DLLPUBLIC HelpSettings
+{
+ void CopyData();
+
+private:
+ ImplHelpData* mpData;
+
+public:
+ HelpSettings();
+ HelpSettings( const HelpSettings& rSet );
+ ~HelpSettings();
+
+ void SetOptions( ULONG nOptions )
+ { CopyData(); mpData->mnOptions = nOptions; }
+ ULONG GetOptions() const
+ { return mpData->mnOptions; }
+ void SetTipDelay( ULONG nTipDelay )
+ { CopyData(); mpData->mnTipDelay = nTipDelay; }
+ ULONG GetTipDelay() const
+ { return mpData->mnTipDelay; }
+ void SetTipTimeout( ULONG nTipTimeout )
+ { CopyData(); mpData->mnTipTimeout = nTipTimeout; }
+ ULONG GetTipTimeout() const
+ { return mpData->mnTipTimeout; }
+ void SetBalloonDelay( ULONG nBalloonDelay )
+ { CopyData(); mpData->mnBalloonDelay = nBalloonDelay; }
+ ULONG GetBalloonDelay() const
+ { return mpData->mnBalloonDelay; }
+
+ const HelpSettings& operator =( const HelpSettings& rSet );
+
+ BOOL operator ==( const HelpSettings& rSet ) const;
+ BOOL operator !=( const HelpSettings& rSet ) const
+ { return !(*this == rSet); }
+};
+
+// -----------------------
+// - ImplAllSettingsData -
+// -----------------------
+class LocaleConfigurationListener;
+class ImplAllSettingsData
+{
+ friend class AllSettings;
+
+ ImplAllSettingsData();
+ ImplAllSettingsData( const ImplAllSettingsData& rData );
+ ~ImplAllSettingsData();
+
+private:
+ ULONG mnRefCount;
+ MachineSettings maMachineSettings;
+ MouseSettings maMouseSettings;
+ KeyboardSettings maKeyboardSettings;
+ StyleSettings maStyleSettings;
+ MiscSettings maMiscSettings;
+ NotificationSettings maNotificationSettings;
+ HelpSettings maHelpSettings;
+ ::com::sun::star::lang::Locale maLocale;
+ ULONG mnSystemUpdate;
+ ULONG mnWindowUpdate;
+ ::com::sun::star::lang::Locale maUILocale;
+ LanguageType meLanguage;
+ LanguageType meUILanguage;
+ LocaleDataWrapper* mpLocaleDataWrapper;
+ LocaleDataWrapper* mpUILocaleDataWrapper;
+ CollatorWrapper* mpCollatorWrapper;
+ CollatorWrapper* mpUICollatorWrapper;
+ vcl::I18nHelper* mpI18nHelper;
+ vcl::I18nHelper* mpUII18nHelper;
+ LocaleConfigurationListener* mpLocaleCfgListener;
+ SvtSysLocale maSysLocale;
+};
+
+// ---------------
+// - AllSettings -
+// ---------------
+
+#define SETTINGS_MACHINE ((ULONG)0x00000001)
+#define SETTINGS_MOUSE ((ULONG)0x00000002)
+#define SETTINGS_KEYBOARD ((ULONG)0x00000004)
+#define SETTINGS_STYLE ((ULONG)0x00000008)
+#define SETTINGS_MISC ((ULONG)0x00000010)
+#define SETTINGS_SOUND ((ULONG)0x00000020)
+#define SETTINGS_NOTIFICATION ((ULONG)0x00000040)
+#define SETTINGS_HELP ((ULONG)0x00000080)
+#define SETTINGS_INTERNATIONAL ((ULONG)0x00000100) /* was for class International, has no effect anymore */
+#define SETTINGS_LOCALE ((ULONG)0x00000200)
+#define SETTINGS_UILOCALE ((ULONG)0x00000400)
+#define SETTINGS_ALLSETTINGS (SETTINGS_MACHINE |\
+ SETTINGS_MOUSE | SETTINGS_KEYBOARD |\
+ SETTINGS_STYLE | SETTINGS_MISC |\
+ SETTINGS_SOUND | SETTINGS_NOTIFICATION |\
+ SETTINGS_HELP |\
+ SETTINGS_LOCALE | SETTINGS_UILOCALE )
+#define SETTINGS_IN_UPDATE_SETTINGS ((ULONG)0x00000800) // this flag indicates that the data changed event was created
+ // in Windows::UpdateSettings probably because of a global
+ // settings changed
+
+class VCL_DLLPUBLIC AllSettings
+{
+ void CopyData();
+
+private:
+ ImplAllSettingsData* mpData;
+
+public:
+ AllSettings();
+ AllSettings( const AllSettings& rSet );
+ ~AllSettings();
+
+ void SetMachineSettings( const MachineSettings& rSet )
+ { CopyData(); mpData->maMachineSettings = rSet; }
+ const MachineSettings& GetMachineSettings() const
+ { return mpData->maMachineSettings; }
+
+ void SetMouseSettings( const MouseSettings& rSet )
+ { CopyData(); mpData->maMouseSettings = rSet; }
+ const MouseSettings& GetMouseSettings() const
+ { return mpData->maMouseSettings; }
+
+ void SetKeyboardSettings( const KeyboardSettings& rSet )
+ { CopyData(); mpData->maKeyboardSettings = rSet; }
+ const KeyboardSettings& GetKeyboardSettings() const
+ { return mpData->maKeyboardSettings; }
+
+ void SetStyleSettings( const StyleSettings& rSet )
+ { CopyData(); mpData->maStyleSettings = rSet; }
+ const StyleSettings& GetStyleSettings() const
+ { return mpData->maStyleSettings; }
+
+ void SetMiscSettings( const MiscSettings& rSet )
+ { CopyData(); mpData->maMiscSettings = rSet; }
+ const MiscSettings& GetMiscSettings() const
+ { return mpData->maMiscSettings; }
+
+ void SetNotificationSettings( const NotificationSettings& rSet )
+ { CopyData(); mpData->maNotificationSettings = rSet; }
+ const NotificationSettings& GetNotificationSettings() const
+ { return mpData->maNotificationSettings; }
+
+ void SetHelpSettings( const HelpSettings& rSet )
+ { CopyData(); mpData->maHelpSettings = rSet; }
+ const HelpSettings& GetHelpSettings() const
+ { return mpData->maHelpSettings; }
+
+ void SetLocale( const ::com::sun::star::lang::Locale& rLocale );
+ const ::com::sun::star::lang::Locale& GetLocale() const;
+ void SetUILocale( const ::com::sun::star::lang::Locale& rLocale );
+ const ::com::sun::star::lang::Locale& GetUILocale() const;
+ void SetLanguage( LanguageType eLang );
+ LanguageType GetLanguage() const;
+ void SetUILanguage( LanguageType eLang );
+ LanguageType GetUILanguage() const;
+ BOOL GetLayoutRTL() const; // returns TRUE if UI language requires right-to-left UI
+ const LocaleDataWrapper& GetLocaleDataWrapper() const;
+ const LocaleDataWrapper& GetUILocaleDataWrapper() const;
+ const vcl::I18nHelper& GetLocaleI18nHelper() const;
+ const vcl::I18nHelper& GetUILocaleI18nHelper() const;
+/*
+ const CollatorWrapper& GetCollatorWrapper() const;
+ const CollatorWrapper& GetUICollatorWrapper() const;
+ sal_Unicode GetMnemonicMatchChar( sal_Unicode c ) const;
+ String GetMatchString( const String& rStr ) const;
+ String GetUIMatchString( const String& rStr ) const;
+ int MatchString( const String& rStr1, xub_StrLen nPos1, xub_StrLen nCount1,
+ const String& rStr2, xub_StrLen nPos2, xub_StrLen nCount2 ) const;
+ int MatchUIString( const String& rStr1, xub_StrLen nPos1, xub_StrLen nCount1,
+ const String& rStr2, xub_StrLen nPos2, xub_StrLen nCount2 ) const;
+*/
+
+ void SetSystemUpdate( ULONG nUpdate )
+ { CopyData(); mpData->mnSystemUpdate = nUpdate; }
+ ULONG GetSystemUpdate() const
+ { return mpData->mnSystemUpdate; }
+ void SetWindowUpdate( ULONG nUpdate )
+ { CopyData(); mpData->mnWindowUpdate = nUpdate; }
+ ULONG GetWindowUpdate() const
+ { return mpData->mnWindowUpdate; }
+
+ ULONG Update( ULONG nFlags, const AllSettings& rSettings );
+ ULONG GetChangeFlags( const AllSettings& rSettings ) const;
+
+ const AllSettings& operator =( const AllSettings& rSet );
+
+ BOOL operator ==( const AllSettings& rSet ) const;
+ BOOL operator !=( const AllSettings& rSet ) const
+ { return !(*this == rSet); }
+ static void LocaleSettingsChanged( sal_uInt32 nHint );
+ SvtSysLocale& GetSysLocale() { return mpData->maSysLocale; }
+};
+
+#endif // _SV_SETTINGS_HXX
diff --git a/vcl/inc/vcl/slider.hxx b/vcl/inc/vcl/slider.hxx
new file mode 100644
index 000000000000..52af7a8bf343
--- /dev/null
+++ b/vcl/inc/vcl/slider.hxx
@@ -0,0 +1,132 @@
+/*************************************************************************
+ *
+ * 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_SLIDER_HXX
+#define _SV_SLIDER_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/ctrl.hxx>
+// for enum ScrollType
+#include <vcl/scrbar.hxx>
+
+// ----------
+// - Slider -
+// ----------
+
+class VCL_DLLPUBLIC Slider : public Control
+{
+private:
+ Rectangle maChannel1Rect;
+ Rectangle maChannel2Rect;
+ Rectangle maThumbRect;
+ long mnStartPos;
+ long mnMouseOff;
+ long mnThumbPixOffset;
+ long mnThumbPixRange;
+ long mnThumbPixPos;
+ long mnChannelPixOffset;
+ long mnChannelPixRange;
+ long mnChannelPixTop;
+ long mnChannelPixBottom;
+ long mnMinRange;
+ long mnMaxRange;
+ long mnThumbPos;
+ long mnLineSize;
+ long mnPageSize;
+ long mnDelta;
+ USHORT mnDragDraw;
+ USHORT mnStateFlags;
+ ScrollType meScrollType;
+ BOOL mbCalcSize;
+ BOOL mbFullDrag;
+ Link maSlideHdl;
+ Link maEndSlideHdl;
+
+ using Control::ImplInitSettings;
+ using Window::ImplInit;
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle );
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+ SAL_DLLPRIVATE void ImplInitSettings();
+ SAL_DLLPRIVATE void ImplUpdateRects( BOOL bUpdate = TRUE );
+ SAL_DLLPRIVATE long ImplCalcThumbPos( long nPixPos );
+ SAL_DLLPRIVATE long ImplCalcThumbPosPix( long nPos );
+ SAL_DLLPRIVATE void ImplCalc( BOOL bUpdate = TRUE );
+ SAL_DLLPRIVATE void ImplDraw( USHORT nDrawFlags );
+ SAL_DLLPRIVATE BOOL ImplIsPageUp( const Point& rPos );
+ SAL_DLLPRIVATE BOOL ImplIsPageDown( const Point& rPos );
+ SAL_DLLPRIVATE long ImplSlide( long nNewPos, BOOL bCallEndSlide );
+ SAL_DLLPRIVATE long ImplDoAction( BOOL bCallEndSlide );
+ SAL_DLLPRIVATE void ImplDoMouseAction( const Point& rPos, BOOL bCallAction = TRUE );
+ SAL_DLLPRIVATE long ImplDoSlide( long nNewPos );
+ SAL_DLLPRIVATE long ImplDoSlideAction( ScrollType eScrollType );
+
+public:
+ Slider( Window* pParent, WinBits nStyle = WB_HORZ );
+ Slider( Window* pParent, const ResId& rResId );
+
+ virtual void MouseButtonDown( const MouseEvent& rMEvt );
+ virtual void MouseButtonUp( const MouseEvent& rMEvt );
+ virtual void Tracking( const TrackingEvent& rTEvt );
+ virtual void KeyInput( const KeyEvent& rKEvt );
+ virtual void Paint( const Rectangle& rRect );
+ virtual void Resize();
+ virtual void RequestHelp( const HelpEvent& rHEvt );
+ virtual void StateChanged( StateChangedType nType );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+
+ virtual void Slide();
+ virtual void EndSlide();
+
+ void EnableDrag( BOOL bEnable = TRUE )
+ { mbFullDrag = bEnable; }
+ BOOL IsDragEnabled() const { return mbFullDrag; }
+
+ void SetRangeMin( long nNewRange );
+ long GetRangeMin() const { return mnMinRange; }
+ void SetRangeMax( long nNewRange );
+ long GetRangeMax() const { return mnMaxRange; }
+ void SetRange( const Range& rRange );
+ Range GetRange() const { return Range( GetRangeMin(), GetRangeMax() ); }
+ void SetThumbPos( long nThumbPos );
+ long GetThumbPos() const { return mnThumbPos; }
+ void SetLineSize( long nNewSize ) { mnLineSize = nNewSize; }
+ long GetLineSize() const { return mnLineSize; }
+ void SetPageSize( long nNewSize ) { mnPageSize = nNewSize; }
+ long GetPageSize() const { return mnPageSize; }
+
+ long GetDelta() const { return mnDelta; }
+
+ Size CalcWindowSizePixel();
+
+ void SetSlideHdl( const Link& rLink ) { maSlideHdl = rLink; }
+ const Link& GetSlideHdl() const { return maSlideHdl; }
+ void SetEndSlideHdl( const Link& rLink ) { maEndSlideHdl = rLink; }
+ const Link& GetEndSlideHdl() const { return maEndSlideHdl; }
+};
+
+#endif // _SV_SLIDER_HXX
diff --git a/vcl/inc/vcl/smartid.hxx b/vcl/inc/vcl/smartid.hxx
new file mode 100755
index 000000000000..2cc5f347b2cb
--- /dev/null
+++ b/vcl/inc/vcl/smartid.hxx
@@ -0,0 +1,87 @@
+/*************************************************************************
+ *
+ * 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 _SMARTID_HXX_
+#define _SMARTID_HXX_
+
+#include <tools/string.hxx>
+#include <vcl/dllapi.h>
+
+/// SMART_SET_SMART only sets the Ids that are defined in the SmartId
+/// the other types set whatever is given. This can also be used to reset an Id
+enum SmartIdUpdateMode { SMART_SET_SMART, SMART_SET_NUM, SMART_SET_STR, SMART_SET_ALL };
+
+struct ImplSmartIdData;
+
+/*
+
+SmartId is a substitute for Numeric HelpIds. They can handle Numeric and String HelpIds and offer commonly needed operators.
+
+Matching Ids:
+if part of an Id is not set (HasNumeric HasString is False) then this part will never match to anything. Not even unset values
+
+*/
+class VCL_DLLPUBLIC SmartId
+{
+private:
+ ImplSmartIdData* mpData;
+ SAL_DLLPRIVATE ImplSmartIdData* GetSmartIdData();
+
+public:
+ explicit SmartId( const String& rId );
+ explicit SmartId( ULONG nId );
+ SmartId( const String& rId, ULONG nId );
+
+ SmartId();
+
+ SmartId( const SmartId& rId );
+ SmartId& operator = ( const SmartId& rId );
+
+ ~SmartId();
+
+ void UpdateId( const SmartId& rId, SmartIdUpdateMode aMode = SMART_SET_SMART );
+
+ BOOL HasNumeric() const;
+ BOOL HasString() const;
+ BOOL HasAny() const;
+ ULONG GetNum() const;
+ String GetStr() const;
+
+ String GetText() const; /// return String for UI usage
+
+ BOOL Matches( const String &rId )const;
+ BOOL Matches( const ULONG nId ) const;
+/// In case both Ids have both values set only the StringId is used for Matching
+ BOOL Matches( const SmartId &rId ) const;
+
+ BOOL Equals( const SmartId &rId ) const;
+
+ BOOL operator == ( const SmartId& rRight ) const;
+ BOOL operator < ( const SmartId& rRight ) const;
+};
+
+#endif
diff --git a/vcl/inc/vcl/sndstyle.hxx b/vcl/inc/vcl/sndstyle.hxx
new file mode 100644
index 000000000000..6e1401986b36
--- /dev/null
+++ b/vcl/inc/vcl/sndstyle.hxx
@@ -0,0 +1,46 @@
+/*************************************************************************
+ *
+ * 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_SNDSTYLE_HXX
+#define _SV_SNDSTYLE_HXX
+
+#include <vcl/sv.h>
+
+// ---------------
+// - Sound-Types -
+// ---------------
+
+typedef USHORT SoundType;
+#define SOUND_DEFAULT ((SoundType)0)
+#define SOUND_INFO ((SoundType)1)
+#define SOUND_WARNING ((SoundType)2)
+#define SOUND_ERROR ((SoundType)3)
+#define SOUND_QUERY ((SoundType)4)
+
+#define SOUND_DISABLE ((SoundType)5)
+
+#endif // _SV_SNDSTYLE_HXX
diff --git a/vcl/inc/vcl/sound.hxx b/vcl/inc/vcl/sound.hxx
new file mode 100644
index 000000000000..edab9d7d8655
--- /dev/null
+++ b/vcl/inc/vcl/sound.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SOUND_HXX
+#define _SV_SOUND_HXX
+
+#include <vcl/dllapi.h>
+#include <vcl/sndstyle.hxx>
+#include <tools/string.hxx>
+#include <tools/link.hxx>
+#include <tools/time.hxx>
+
+class Window;
+class Timer;
+
+// ---------
+// - Sound -
+// ---------
+
+class VCL_DLLPUBLIC Sound
+{
+public:
+ static void Beep( SoundType eType = SOUND_DEFAULT, Window* pWindow = NULL );
+};
+
+#endif // _SV_SOUND_HXX
+
diff --git a/vcl/inc/vcl/spin.h b/vcl/inc/vcl/spin.h
new file mode 100644
index 000000000000..b600c18f0f9f
--- /dev/null
+++ b/vcl/inc/vcl/spin.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SPIN_H
+#define _SV_SPIN_H
+
+#include <vcl/sv.h>
+
+class Rectangle;
+class OutputDevice;
+
+// -----------------------------------------------------------------------
+
+#define SPIN_DELAY 280
+#define SPIN_SPEED 60
+
+// -----------------------------------------------------------------------
+
+void ImplDrawSpinButton( OutputDevice* pOutDev,
+ const Rectangle& rUpperRect,
+ const Rectangle& rLowerRect,
+ BOOL bUpperIn, BOOL bLowerIn,
+ BOOL bUpperEnabled = TRUE,
+ BOOL bLowerEnabled = TRUE,
+ BOOL bHorz = FALSE, BOOL bMirrorHorz = FALSE );
+
+#endif // _SV_SPIN_H
diff --git a/vcl/inc/vcl/spin.hxx b/vcl/inc/vcl/spin.hxx
new file mode 100644
index 000000000000..2ca4709de4c5
--- /dev/null
+++ b/vcl/inc/vcl/spin.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SPIN_HXX
+#define _SV_SPIN_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/ctrl.hxx>
+#include <vcl/timer.hxx>
+
+// --------------
+// - SpinButton -
+// --------------
+
+class VCL_DLLPUBLIC SpinButton : public Control
+{
+private:
+ AutoTimer maRepeatTimer;
+ Rectangle maUpperRect;
+ Rectangle maLowerRect;
+ Rectangle maFocusRect;
+ BOOL mbRepeat : 1;
+ BOOL mbUpperIn : 1;
+ BOOL mbLowerIn : 1;
+ BOOL mbInitialUp : 1;
+ BOOL mbInitialDown : 1;
+ BOOL mbHorz : 1;
+ BOOL mbUpperIsFocused : 1;
+ Link maUpHdlLink;
+ Link maDownHdlLink;
+ long mnMinRange;
+ long mnMaxRange;
+ long mnValue;
+ long mnValueStep;
+
+ SAL_DLLPRIVATE Rectangle* ImplFindPartRect( const Point& rPt );
+ using Window::ImplInit;
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle );
+ DECL_DLLPRIVATE_LINK( ImplTimeout, Timer* );
+
+public:
+ SpinButton( Window* pParent, WinBits nStyle = 0 );
+ SpinButton( Window* pParent, const ResId& rResId );
+ ~SpinButton();
+
+ virtual void Up();
+ virtual void Down();
+
+ virtual void Resize();
+ virtual void Paint( const Rectangle& rRect );
+ virtual void Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG nFlags );
+ virtual void MouseButtonDown( const MouseEvent& rMEvt );
+ virtual void MouseButtonUp( const MouseEvent& rMEvt );
+ virtual void MouseMove( const MouseEvent& rMEvt );
+ virtual void KeyInput( const KeyEvent& rKEvt );
+ virtual void StateChanged( StateChangedType nStateChange );
+ virtual void GetFocus();
+ virtual void LoseFocus();
+
+ void SetRangeMin( long nNewRange );
+ long GetRangeMin() const { return mnMinRange; }
+ void SetRangeMax( long nNewRange );
+ long GetRangeMax() const { return mnMaxRange; }
+ void SetRange( const Range& rRange );
+ Range GetRange() const { return Range( GetRangeMin(), GetRangeMax() ); }
+ void SetValue( long nValue );
+ long GetValue() const { return mnValue; }
+ void SetValueStep( long nNewStep ) { mnValueStep = nNewStep; }
+ long GetValueStep() const { return mnValueStep; }
+ virtual long PreNotify( NotifyEvent& rNEvt );
+
+ void SetUpHdl( const Link& rLink ) { maUpHdlLink = rLink; }
+ const Link& GetUpHdl() const { return maUpHdlLink; }
+ void SetDownHdl( const Link& rLink ) { maDownHdlLink = rLink; }
+ const Link& GetDownHdl() const { return maDownHdlLink; }
+
+private:
+ // moves the focus to the upper or lower rect. Return TRUE if the focus rect actually changed.
+ SAL_DLLPRIVATE BOOL ImplMoveFocus( BOOL _bUpper );
+ SAL_DLLPRIVATE void ImplCalcFocusRect( BOOL _bUpper );
+
+ SAL_DLLPRIVATE inline BOOL ImplIsUpperEnabled( ) const
+ {
+ return mnValue + mnValueStep <= mnMaxRange;
+ }
+ SAL_DLLPRIVATE inline BOOL ImplIsLowerEnabled( ) const
+ {
+ return mnValue >= mnMinRange + mnValueStep;
+ }
+};
+
+#endif // _SV_SPIN_HXX
diff --git a/vcl/inc/vcl/spinfld.hxx b/vcl/inc/vcl/spinfld.hxx
new file mode 100644
index 000000000000..7df0b6d95bfc
--- /dev/null
+++ b/vcl/inc/vcl/spinfld.hxx
@@ -0,0 +1,115 @@
+/*************************************************************************
+ *
+ * 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_SPINFLD_HXX
+#define _SV_SPINFLD_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/edit.hxx>
+#include <vcl/timer.hxx>
+
+// -------------
+// - SpinField -
+// -------------
+
+class VCL_DLLPUBLIC SpinField : public Edit
+{
+protected:
+ Edit* mpEdit;
+ AutoTimer maRepeatTimer;
+ Rectangle maUpperRect;
+ Rectangle maLowerRect;
+ Rectangle maDropDownRect; // noch nicht angebunden...
+ Link maUpHdlLink;
+ Link maDownHdlLink;
+ Link maFirstHdlLink;
+ Link maLastHdlLink;
+ BOOL mbRepeat:1,
+ mbSpin:1,
+ mbInitialUp:1,
+ mbInitialDown:1,
+ mbNoSelect:1,
+ mbUpperIn:1,
+ mbLowerIn:1,
+ mbInDropDown:1;
+
+ using Window::ImplInit;
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle );
+
+private:
+ DECL_DLLPRIVATE_LINK( ImplTimeout, Timer* );
+ SAL_DLLPRIVATE void ImplInitSpinFieldData();
+ SAL_DLLPRIVATE void ImplCalcButtonAreas( OutputDevice* pDev, const Size& rOutSz, Rectangle& rDDArea, Rectangle& rSpinUpArea, Rectangle& rSpinDownArea );
+
+protected:
+ SpinField( WindowType nTyp );
+
+ virtual long Notify( NotifyEvent& rNEvt );
+ virtual void Command( const CommandEvent& rCEvt );
+
+ void EndDropDown();
+
+ virtual void FillLayoutData() const;
+ Rectangle * ImplFindPartRect( const Point& rPt );
+public:
+ SpinField( Window* pParent, WinBits nWinStyle = 0 );
+ SpinField( Window* pParent, const ResId& rResId );
+ ~SpinField();
+
+ virtual BOOL ShowDropDown( BOOL bShow );
+
+ virtual void Up();
+ virtual void Down();
+ virtual void First();
+ virtual void Last();
+
+ virtual void MouseButtonDown( const MouseEvent& rMEvt );
+ virtual void MouseButtonUp( const MouseEvent& rMEvt );
+ virtual void MouseMove( const MouseEvent& rMEvt );
+ virtual void Paint( const Rectangle& rRect );
+ virtual void Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG nFlags );
+ virtual void Resize();
+ virtual void StateChanged( StateChangedType nType );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+ virtual long PreNotify( NotifyEvent& rNEvt );
+
+ void SetUpHdl( const Link& rLink ) { maUpHdlLink = rLink; }
+ const Link& GetUpHdl() const { return maUpHdlLink; }
+ void SetDownHdl( const Link& rLink ) { maDownHdlLink = rLink; }
+ const Link& GetDownHdl() const { return maDownHdlLink; }
+ void SetFirstHdl( const Link& rLink ) { maFirstHdlLink = rLink; }
+ const Link& GetFirstHdl() const { return maFirstHdlLink; }
+ void SetLastHdl( const Link& rLink ) { maLastHdlLink = rLink; }
+ const Link& GetLastHdl() const { return maLastHdlLink; }
+
+ virtual Size CalcMinimumSize() const;
+ virtual Size GetOptimalSize(WindowSizeType eType) const;
+ virtual Size CalcSize( USHORT nChars ) const;
+};
+
+#endif // _SV_SPINFLD_HXX
diff --git a/vcl/inc/vcl/split.hxx b/vcl/inc/vcl/split.hxx
new file mode 100644
index 000000000000..890ef5365fbc
--- /dev/null
+++ b/vcl/inc/vcl/split.hxx
@@ -0,0 +1,126 @@
+/*************************************************************************
+ *
+ * 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_SPLIT_HXX
+#define _SV_SPLIT_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/window.hxx>
+
+#define SPLITTER_DEFAULTSTEPSIZE 0xFFFF
+
+// ------------
+// - Splitter -
+// ------------
+
+class VCL_DLLPUBLIC Splitter : public Window
+{
+private:
+ Window* mpRefWin;
+ long mnSplitPos;
+ long mnLastSplitPos;
+ long mnStartSplitPos;
+ Point maDragPos;
+ Rectangle maDragRect;
+ BOOL mbHorzSplit;
+ BOOL mbDragFull;
+ BOOL mbKbdSplitting;
+ long mbInKeyEvent;
+ long mnKeyboardStepSize;
+ Link maStartSplitHdl;
+ Link maSplitHdl;
+ Link maEndSplitHdl;
+
+ SAL_DLLPRIVATE void ImplInitSplitterData();
+ SAL_DLLPRIVATE void ImplDrawSplitter();
+ SAL_DLLPRIVATE void ImplSplitMousePos( Point& rPos );
+ SAL_DLLPRIVATE void ImplStartKbdSplitting();
+ SAL_DLLPRIVATE void ImplKbdTracking( KeyCode aKeyCode );
+ SAL_DLLPRIVATE BOOL ImplSplitterActive();
+ SAL_DLLPRIVATE Splitter* ImplFindSibling();
+ SAL_DLLPRIVATE void ImplRestoreSplitter();
+
+ // Copy assignment is forbidden and not implemented.
+ SAL_DLLPRIVATE Splitter (const Splitter &);
+ SAL_DLLPRIVATE Splitter& operator= (const Splitter &);
+
+protected:
+ using Window::ImplInit;
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nWinStyle );
+
+public:
+ Splitter( Window* pParent, WinBits nStyle = WB_VSCROLL );
+ Splitter( Window* pParent, const ResId& rResId );
+ ~Splitter();
+
+ virtual void StartSplit();
+ virtual void EndSplit();
+ virtual void Split();
+ virtual void Splitting( Point& rSplitPos );
+
+ virtual void MouseButtonDown( const MouseEvent& rMEvt );
+ virtual void Tracking( const TrackingEvent& rTEvt );
+
+ virtual long Notify( NotifyEvent& rNEvt );
+
+ virtual void GetFocus();
+ virtual void LoseFocus();
+ virtual void KeyInput( const KeyEvent& rKEvt );
+ virtual void Paint( const Rectangle& rPaintRect );
+
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+
+ void StartDrag();
+
+ void SetDragRectPixel( const Rectangle& rDragRect,
+ Window* pRefWin = NULL );
+ const Rectangle& GetDragRectPixel() const { return maDragRect; }
+ Window* GetDragWindow() const { return mpRefWin; }
+
+ virtual void SetSplitPosPixel( long nPos );
+ long GetSplitPosPixel() const { return mnSplitPos; }
+
+ void SetLastSplitPosPixel( long nNewPos );
+ long GetLastSplitPosPixel() const { return mnLastSplitPos; }
+
+ BOOL IsHorizontal() const { return mbHorzSplit; }
+
+ // set the stepsize of the splitter for cursor movement
+ // the default is 10% of the reference window's width/height
+ void SetKeyboardStepSize( long nStepSize );
+ long GetKeyboardStepSize() const;
+
+ void SetStartSplitHdl( const Link& rLink ) { maStartSplitHdl = rLink; }
+ const Link& GetStartSplitHdl() const { return maStartSplitHdl; }
+ void SetSplitHdl( const Link& rLink ) { maSplitHdl = rLink; }
+ void SetEndSplitHdl( const Link& rLink ) { maEndSplitHdl = rLink; }
+ const Link& GetEndSplitHdl() const { return maEndSplitHdl; }
+ const Link& GetSplitHdl() const { return maSplitHdl; }
+};
+
+#endif // _SV_SPLIT_HXX
diff --git a/vcl/inc/vcl/splitwin.hxx b/vcl/inc/vcl/splitwin.hxx
new file mode 100644
index 000000000000..4aa1ca16785c
--- /dev/null
+++ b/vcl/inc/vcl/splitwin.hxx
@@ -0,0 +1,268 @@
+/*************************************************************************
+ *
+ * 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_SPLITWIN_HXX
+#define _SV_SPLITWIN_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/dockwin.hxx>
+
+class Wallpaper;
+struct ImplSplitSet;
+
+// -----------------------
+// - SplitWindowItemBits -
+// -----------------------
+
+typedef USHORT SplitWindowItemBits;
+
+// -------------------------------
+// - Bits fuer SplitWindow-Items -
+// -------------------------------
+
+#define SWIB_FIXED ((SplitWindowItemBits)0x0001)
+#define SWIB_RELATIVESIZE ((SplitWindowItemBits)0x0002)
+#define SWIB_PERCENTSIZE ((SplitWindowItemBits)0x0004)
+#define SWIB_COLSET ((SplitWindowItemBits)0x0008)
+#define SWIB_INVISIBLE ((SplitWindowItemBits)0x0010)
+
+// ---------------------
+// - SplitWindow-Types -
+// ---------------------
+
+#define SPLITWINDOW_APPEND ((USHORT)0xFFFF)
+#define SPLITWINDOW_ITEM_NOTFOUND ((USHORT)0xFFFF)
+
+// ---------------
+// - SplitWindow -
+// ---------------
+
+class VCL_DLLPUBLIC SplitWindow : public DockingWindow
+{
+private:
+ ImplSplitSet* mpMainSet;
+ ImplSplitSet* mpBaseSet;
+ ImplSplitSet* mpSplitSet;
+ long* mpLastSizes;
+ Rectangle maDragRect;
+ long mnDX;
+ long mnDY;
+ long mnLeftBorder;
+ long mnTopBorder;
+ long mnRightBorder;
+ long mnBottomBorder;
+ long mnMaxSize;
+ long mnMouseOff;
+ long mnMStartPos;
+ long mnMSplitPos;
+ WinBits mnWinStyle;
+ WindowAlign meAlign;
+ USHORT mnSplitTest;
+ USHORT mnSplitPos;
+ USHORT mnMouseModifier;
+ BOOL mbDragFull:1,
+ mbHorz:1,
+ mbBottomRight:1,
+ mbCalc:1,
+ mbRecalc:1,
+ mbInvalidate:1,
+ mbSizeable:1,
+ mbBorder:1,
+ mbAutoHide:1,
+ mbFadeIn:1,
+ mbFadeOut:1,
+ mbAutoHideIn:1,
+ mbAutoHideDown:1,
+ mbFadeInDown:1,
+ mbFadeOutDown:1,
+ mbAutoHidePressed:1,
+ mbFadeInPressed:1,
+ mbFadeOutPressed:1,
+ mbFadeNoButtonMode:1,
+ mbNoAlign:1;
+ Link maStartSplitHdl;
+ Link maSplitHdl;
+ Link maSplitResizeHdl;
+ Link maAutoHideHdl;
+ Link maFadeInHdl;
+ Link maFadeOutHdl;
+
+ using Window::ImplInit;
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle );
+ SAL_DLLPRIVATE void ImplInitSettings();
+ SAL_DLLPRIVATE void ImplCalcLayout();
+ SAL_DLLPRIVATE void ImplUpdate();
+ SAL_DLLPRIVATE void ImplUpdateSet( ImplSplitSet* pSet );
+ SAL_DLLPRIVATE void ImplSetWindowSize( long nDelta );
+ SAL_DLLPRIVATE void ImplSplitMousePos( Point& rMousePos );
+ SAL_DLLPRIVATE void ImplGetButtonRect( Rectangle& rRect, long nEx, BOOL bTest ) const;
+ SAL_DLLPRIVATE void ImplGetAutoHideRect( Rectangle& rRect, BOOL bTest = FALSE ) const;
+ SAL_DLLPRIVATE void ImplGetFadeInRect( Rectangle& rRect, BOOL bTest = FALSE ) const;
+ SAL_DLLPRIVATE void ImplGetFadeOutRect( Rectangle& rRect, BOOL bTest = FALSE ) const;
+ SAL_DLLPRIVATE void ImplDrawButtonRect( const Rectangle& rRect, long nSize );
+ SAL_DLLPRIVATE void ImplDrawAutoHide( BOOL bInPaint );
+ SAL_DLLPRIVATE void ImplDrawFadeIn( BOOL bInPaint );
+ SAL_DLLPRIVATE void ImplDrawFadeOut( BOOL bInPaint );
+ SAL_DLLPRIVATE void ImplNewAlign();
+ SAL_DLLPRIVATE void ImplDrawGrip( const Rectangle& rRect, BOOL bHorz, BOOL bLeft );
+ SAL_DLLPRIVATE void ImplDrawFadeArrow( const Point& rPt, BOOL bHorz, BOOL bLeft );
+ SAL_DLLPRIVATE void ImplStartSplit( const MouseEvent& rMEvt );
+
+ static SAL_DLLPRIVATE void ImplDrawBorder( SplitWindow* pWin );
+ static SAL_DLLPRIVATE void ImplDrawBorderLine( SplitWindow* pWin );
+ static SAL_DLLPRIVATE void ImplCalcSet2( SplitWindow* pWindow, ImplSplitSet* pSet, BOOL bHide,
+ BOOL bRows, BOOL bDown = TRUE );
+ static SAL_DLLPRIVATE void ImplDrawBack( SplitWindow* pWindow, ImplSplitSet* pSet );
+ static SAL_DLLPRIVATE void ImplDrawBack( SplitWindow* pWindow, const Rectangle& rRect,
+ const Wallpaper* pWall, const Bitmap* pBitmap );
+ static SAL_DLLPRIVATE USHORT ImplTestSplit( ImplSplitSet* pSet, const Point& rPos,
+ long& rMouseOff, ImplSplitSet** ppFoundSet, USHORT& rFoundPos,
+ BOOL bRows, BOOL bDown = TRUE );
+ static SAL_DLLPRIVATE USHORT ImplTestSplit( SplitWindow* pWindow, const Point& rPos,
+ long& rMouseOff, ImplSplitSet** ppFoundSet, USHORT& rFoundPos );
+ static SAL_DLLPRIVATE void ImplDrawSplitTracking( SplitWindow* pThis, const Point& rPos );
+
+ // Copy assignment is forbidden and not implemented.
+ SAL_DLLPRIVATE SplitWindow (const SplitWindow &);
+ SAL_DLLPRIVATE SplitWindow & operator= (const SplitWindow &);
+public:
+ SplitWindow( Window* pParent, WinBits nStyle = 0 );
+ SplitWindow( Window* pParent, const ResId& rResId );
+ ~SplitWindow();
+
+ virtual void StartSplit();
+ virtual void Split();
+ virtual void SplitResize();
+ virtual void AutoHide();
+ virtual void FadeIn();
+ virtual void FadeOut();
+
+ virtual void MouseButtonDown( const MouseEvent& rMEvt );
+ virtual void MouseMove( const MouseEvent& rMEvt );
+ virtual void Tracking( const TrackingEvent& rTEvt );
+ virtual void Paint( const Rectangle& rRect );
+ virtual void Move();
+ virtual void Resize();
+ virtual void RequestHelp( const HelpEvent& rHEvt );
+ virtual void StateChanged( StateChangedType nType );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+ virtual long PreNotify( NotifyEvent& rNEvt );
+
+ void InsertItem( USHORT nId, Window* pWindow, long nSize,
+ USHORT nPos = SPLITWINDOW_APPEND, USHORT nSetId = 0,
+ SplitWindowItemBits nBits = 0 );
+ void InsertItem( USHORT nId, long nSize,
+ USHORT nPos = SPLITWINDOW_APPEND, USHORT nSetId = 0,
+ SplitWindowItemBits nBits = 0 );
+ void MoveItem( USHORT nId, USHORT nNewPos, USHORT nNewSetId = 0 );
+ void RemoveItem( USHORT nId, BOOL bHide = TRUE );
+ void Clear();
+
+ void SetBaseSet( USHORT nSetId = 0 );
+ USHORT GetBaseSet() const;
+
+ void SetSplitSize( USHORT nSetId, long nSplitSize,
+ BOOL bWithChilds = FALSE );
+ long GetSplitSize( USHORT nSetId ) const;
+ void SetItemBackground( USHORT nSetId );
+ void SetItemBackground( USHORT nSetId, const Wallpaper& rWallpaper );
+ Wallpaper GetItemBackground( USHORT nSetId ) const;
+ BOOL IsItemBackground( USHORT nSetId ) const;
+ void SetItemBitmap( USHORT nSetId, const Bitmap& rBitmap );
+ Bitmap GetItemBitmap( USHORT nSetId ) const;
+
+ void SplitItem( USHORT nId, long nNewSize,
+ BOOL bPropSmall = FALSE,
+ BOOL bPropGreat = FALSE );
+ void SetItemSize( USHORT nId, long nNewSize );
+ long GetItemSize( USHORT nId ) const;
+ long GetItemSize( USHORT nId, SplitWindowItemBits nBits ) const;
+ void SetItemBits( USHORT nId, SplitWindowItemBits nNewBits );
+ SplitWindowItemBits GetItemBits( USHORT nId ) const;
+ Window* GetItemWindow( USHORT nId ) const;
+ USHORT GetSet( USHORT nId ) const;
+ BOOL GetSet( USHORT nId, USHORT& rSetId, USHORT& rPos ) const;
+ USHORT GetItemId( Window* pWindow ) const;
+ USHORT GetItemId( const Point& rPos ) const;
+ USHORT GetItemPos( USHORT nId, USHORT nSetId = 0 ) const;
+ USHORT GetItemId( USHORT nPos, USHORT nSetId = 0 ) const;
+ USHORT GetItemCount( USHORT nSetId = 0 ) const;
+ BOOL IsItemValid( USHORT nId ) const;
+
+ void SetNoAlign( BOOL bNoAlign );
+ BOOL IsNoAlign() const { return mbNoAlign; }
+ void SetAlign( WindowAlign eNewAlign = WINDOWALIGN_TOP );
+ WindowAlign GetAlign() const { return meAlign; }
+ BOOL IsHorizontal() const { return mbHorz; }
+
+ BOOL IsSplitting() const { return IsTracking(); }
+
+ void SetMaxSizePixel( long nNewMaxSize ) { mnMaxSize = nNewMaxSize; }
+ long GetMaxSizePixel() const { return mnMaxSize; }
+
+ static Size CalcWindowSizePixel( const Size& rSize,
+ WindowAlign eAlign,
+ WinBits nWinStyle,
+ BOOL bExtra = FALSE );
+ Size CalcWindowSizePixel( const Size& rSize )
+ { return CalcWindowSizePixel( rSize, meAlign, mnWinStyle, (mbAutoHide || mbFadeOut) ); }
+
+ Size CalcLayoutSizePixel( const Size& aNewSize );
+
+ void ShowAutoHideButton( BOOL bShow = TRUE );
+ BOOL IsAutoHideButtonVisible() const { return mbAutoHide; }
+ void ShowFadeInHideButton( BOOL bShow = TRUE );
+ void ShowFadeInButton( BOOL bShow = TRUE ) { ShowFadeInHideButton( bShow ); }
+ BOOL IsFadeInButtonVisible() const { return mbFadeIn; }
+ void ShowFadeOutButton( BOOL bShow = TRUE );
+ BOOL IsFadeOutButtonVisible() const { return mbFadeOut; }
+ long GetFadeInSize() const;
+ BOOL IsFadeNoButtonMode() const { return mbFadeNoButtonMode; }
+
+ void SetAutoHideState( BOOL bAutoHide );
+ BOOL GetAutoHideState() const { return mbAutoHideIn; }
+
+ Rectangle GetAutoHideRect() const;
+ Rectangle GetFadeInRect() const;
+ Rectangle GetFadeOutRect() const;
+
+ void SetStartSplitHdl( const Link& rLink ) { maStartSplitHdl = rLink; }
+ const Link& GetStartSplitHdl() const { return maStartSplitHdl; }
+ void SetSplitHdl( const Link& rLink ) { maSplitHdl = rLink; }
+ const Link& GetSplitHdl() const { return maSplitHdl; }
+ void SetSplitResizeHdl( const Link& rLink ) { maSplitResizeHdl = rLink; }
+ const Link& GetSplitResizeHdl() const { return maSplitResizeHdl; }
+ void SetAutoHideHdl( const Link& rLink ) { maAutoHideHdl = rLink; }
+ const Link& GetAutoHideHdl() const { return maAutoHideHdl; }
+ void SetFadeInHdl( const Link& rLink ) { maFadeInHdl = rLink; }
+ const Link& GetFadeInHdl() const { return maFadeInHdl; }
+ void SetFadeOutHdl( const Link& rLink ) { maFadeOutHdl = rLink; }
+ const Link& GetFadeOutHdl() const { return maFadeOutHdl; }
+};
+
+#endif // _SV_SPLITWIN_HXX
diff --git a/vcl/inc/vcl/status.hxx b/vcl/inc/vcl/status.hxx
new file mode 100644
index 000000000000..810ecf230960
--- /dev/null
+++ b/vcl/inc/vcl/status.hxx
@@ -0,0 +1,226 @@
+/*************************************************************************
+ *
+ * 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_STATUS_HXX
+#define _SV_STATUS_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/window.hxx>
+
+class ImplStatusItemList;
+
+// --------------------
+// - Progress-Ausgabe -
+// --------------------
+
+void VCL_DLLPUBLIC DrawProgress( Window* pWindow, const Point& rPos,
+ long nOffset, long nPrgsWidth, long nPrgsHeight,
+ USHORT nPercent1, USHORT nPercent2, USHORT nPercentCount,
+ const Rectangle& rFramePosSize
+ );
+
+// ---------------------
+// - StatusBarItemBits -
+// ---------------------
+
+typedef USHORT StatusBarItemBits;
+
+// ----------------------------
+// - Bits fuer StatusBarItems -
+// ----------------------------
+
+#define SIB_LEFT ((StatusBarItemBits)0x0001)
+#define SIB_CENTER ((StatusBarItemBits)0x0002)
+#define SIB_RIGHT ((StatusBarItemBits)0x0004)
+#define SIB_IN ((StatusBarItemBits)0x0008)
+#define SIB_OUT ((StatusBarItemBits)0x0010)
+#define SIB_FLAT ((StatusBarItemBits)0x0020)
+#define SIB_AUTOSIZE ((StatusBarItemBits)0x0040)
+#define SIB_USERDRAW ((StatusBarItemBits)0x0080)
+
+// -------------------
+// - StatusBar-Types -
+// -------------------
+
+#define STATUSBAR_APPEND ((USHORT)0xFFFF)
+#define STATUSBAR_ITEM_NOTFOUND ((USHORT)0xFFFF)
+#define STATUSBAR_OFFSET ((long)5)
+
+// -------------
+// - StatusBar -
+// -------------
+
+class VCL_DLLPUBLIC StatusBar : public Window
+{
+ class ImplData;
+private:
+ ImplStatusItemList* mpItemList;
+ ImplData* mpImplData;
+ XubString maPrgsTxt;
+ Point maPrgsTxtPos;
+ Rectangle maPrgsFrameRect;
+ long mnPrgsSize;
+ long mnItemsWidth;
+ long mnDX;
+ long mnDY;
+ long mnCalcHeight;
+ long mnTextY;
+ long mnItemY;
+ USHORT mnCurItemId;
+ USHORT mnPercent;
+ USHORT mnPercentCount;
+ BOOL mbVisibleItems;
+ BOOL mbFormat;
+ BOOL mbProgressMode;
+ BOOL mbInUserDraw;
+ BOOL mbBottomBorder;
+ Link maClickHdl;
+ Link maDoubleClickHdl;
+
+ using Window::ImplInit;
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle );
+ SAL_DLLPRIVATE void ImplInitSettings( BOOL bFont, BOOL bForeground, BOOL bBackground );
+ SAL_DLLPRIVATE void ImplFormat();
+ SAL_DLLPRIVATE BOOL ImplIsItemUpdate();
+// #if 0 // _SOLAR__PRIVATE
+ using OutputDevice::ImplDrawText;
+// #endif
+ SAL_DLLPRIVATE void ImplDrawText( BOOL bOffScreen, long nOldTextWidth );
+ SAL_DLLPRIVATE void ImplDrawItem( BOOL bOffScreen, USHORT nPos, BOOL bDrawText, BOOL bDrawFrame );
+ SAL_DLLPRIVATE void ImplDrawProgress( BOOL bPaint,
+ USHORT nOldPerc, USHORT nNewPerc );
+ SAL_DLLPRIVATE void ImplCalcProgressRect();
+ SAL_DLLPRIVATE Rectangle ImplGetItemRectPos( USHORT nPos ) const;
+ SAL_DLLPRIVATE USHORT ImplGetFirstVisiblePos() const;
+ SAL_DLLPRIVATE void ImplCalcBorder();
+
+public:
+ StatusBar( Window* pParent,
+ WinBits nWinStyle = WB_BORDER | WB_RIGHT );
+ StatusBar( Window* pParent, const ResId& rResId );
+ ~StatusBar();
+
+ virtual void MouseButtonDown( const MouseEvent& rMEvt );
+ virtual void Paint( const Rectangle& rRect );
+ virtual void Move();
+ virtual void Resize();
+ virtual void RequestHelp( const HelpEvent& rHEvt );
+ virtual void StateChanged( StateChangedType nType );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+
+ virtual void Click();
+ virtual void DoubleClick();
+ virtual void UserDraw( const UserDrawEvent& rUDEvt );
+
+ void InsertItem( USHORT nItemId, ULONG nWidth,
+ StatusBarItemBits nBits = SIB_CENTER | SIB_IN,
+ long nOffset = STATUSBAR_OFFSET,
+ USHORT nPos = STATUSBAR_APPEND );
+ void RemoveItem( USHORT nItemId );
+
+ void ShowItem( USHORT nItemId );
+ void HideItem( USHORT nItemId );
+ BOOL IsItemVisible( USHORT nItemId ) const;
+
+ void ShowItems();
+ void HideItems();
+ BOOL AreItemsVisible() const { return mbVisibleItems; }
+
+ void CopyItems( const StatusBar& rStatusBar );
+ void Clear();
+
+ USHORT GetItemCount() const;
+ USHORT GetItemId( USHORT nPos ) const;
+ USHORT GetItemId( const Point& rPos ) const;
+ USHORT GetItemPos( USHORT nItemId ) const;
+ Rectangle GetItemRect( USHORT nItemId ) const;
+ Point GetItemTextPos( USHORT nItemId ) const;
+ USHORT GetCurItemId() const { return mnCurItemId; }
+
+ ULONG GetItemWidth( USHORT nItemId ) const;
+ StatusBarItemBits GetItemBits( USHORT nItemId ) const;
+ long GetItemOffset( USHORT nItemId ) const;
+
+ void SetItemText( USHORT nItemId, const XubString& rText );
+ const XubString& GetItemText( USHORT nItemId ) const;
+
+ void SetItemData( USHORT nItemId, void* pNewData );
+ void* GetItemData( USHORT nItemId ) const;
+
+ void SetItemCommand( USHORT nItemId, const XubString& rCommand );
+ const XubString& GetItemCommand( USHORT nItemId );
+
+ void SetHelpText( USHORT nItemId, const XubString& rText );
+ const XubString& GetHelpText( USHORT nItemId ) const;
+
+ using Window::SetQuickHelpText;
+ void SetQuickHelpText( USHORT nItemId, const XubString& rText );
+ using Window::GetQuickHelpText;
+ const XubString& GetQuickHelpText( USHORT nItemId ) const;
+
+ void SetHelpId( USHORT nItemId, ULONG nHelpId );
+ ULONG GetHelpId( USHORT nItemId ) const;
+
+ void SetBottomBorder( BOOL bBottomBorder = TRUE );
+ BOOL IsBottomBorder() const { return mbBottomBorder; }
+
+ void SetTopBorder( BOOL bTopBorder = TRUE );
+ BOOL IsTopBorder() const;
+
+ void StartProgressMode( const XubString& rText );
+ void SetProgressValue( USHORT nPercent );
+ void EndProgressMode();
+ BOOL IsProgressMode() const { return mbProgressMode; }
+ void ResetProgressMode();
+
+ void SetText( const XubString& rText );
+
+ void SetHelpText( const XubString& rText )
+ { Window::SetHelpText( rText ); }
+ const XubString& GetHelpText() const
+ { return Window::GetHelpText(); }
+
+ void SetHelpId( ULONG nId )
+ { Window::SetHelpId( nId ); }
+ ULONG GetHelpId() const
+ { return Window::GetHelpId(); }
+
+ Size CalcWindowSizePixel() const;
+
+ void SetClickHdl( const Link& rLink ) { maClickHdl = rLink; }
+ const Link& GetClickHdl() const { return maClickHdl; }
+ void SetDoubleClickHdl( const Link& rLink ) { maDoubleClickHdl = rLink; }
+ const Link& GetDoubleClickHdl() const { return maDoubleClickHdl; }
+
+ using Window::SetAccessibleName;
+ void SetAccessibleName( USHORT nItemId, const XubString& rName );
+ using Window::GetAccessibleName;
+ const XubString& GetAccessibleName( USHORT nItemId ) const;
+};
+
+#endif // _SV_STATUS_HXX
diff --git a/vcl/inc/vcl/stdtext.hxx b/vcl/inc/vcl/stdtext.hxx
new file mode 100644
index 000000000000..111e58aca5bf
--- /dev/null
+++ b/vcl/inc/vcl/stdtext.hxx
@@ -0,0 +1,53 @@
+/*************************************************************************
+ *
+ * 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_STDTEXT_HXX
+#define _VCL_STDTEXT_HXX
+
+#include <tools/string.hxx>
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+
+class Window;
+
+// ------------------
+// - Standard-Texte -
+// ------------------
+
+#define STANDARD_TEXT_FIRST STANDARD_TEXT_SERVICE_NOT_AVAILABLE
+#define STANDARD_TEXT_SERVICE_NOT_AVAILABLE ((USHORT)0)
+#define STANDARD_TEXT_LAST STANDARD_TEXT_SERVICE_NOT_AVAILABLE
+
+XubString VCL_DLLPUBLIC GetStandardText( USHORT nStdText );
+
+// -------------------------------------
+// - Hilfsmethoden fuer Standard-Texte -
+// -------------------------------------
+
+void VCL_DLLPUBLIC ShowServiceNotAvailableError( Window* pParent, const XubString& rServiceName, BOOL bError );
+
+#endif // _VCL_STDTEXT_HXX
diff --git a/vcl/inc/vcl/strhelper.hxx b/vcl/inc/vcl/strhelper.hxx
new file mode 100644
index 000000000000..8df83d6f33f4
--- /dev/null
+++ b/vcl/inc/vcl/strhelper.hxx
@@ -0,0 +1,83 @@
+/*************************************************************************
+ *
+ * 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 _PSPRINT_STRHELPER_HXX_
+#define _PSPRINT_STRHELPER_HXX_
+
+#include "vcl/dllapi.h"
+
+#include <tools/string.hxx>
+#include <rtl/math.hxx>
+
+#include <cstring>
+
+namespace psp {
+
+String VCL_DLLPUBLIC GetCommandLineToken( int, const String& );
+ByteString VCL_DLLPUBLIC GetCommandLineToken( int, const ByteString& );
+// gets one token of a unix command line style string
+// doublequote, singlequote and singleleftquote protect their respective
+// contents
+
+int VCL_DLLPUBLIC GetCommandLineTokenCount( const String& );
+int VCL_DLLPUBLIC GetCommandLineTokenCount( const ByteString& );
+// returns number of tokens (zero if empty or whitespace only)
+
+String VCL_DLLPUBLIC WhitespaceToSpace( const String&, BOOL bProtect = TRUE );
+ByteString VCL_DLLPUBLIC WhitespaceToSpace( const ByteString&, BOOL bProtect = TRUE );
+// returns a string with multiple adjacent occurences of whitespace
+// converted to a single space. if bProtect is TRUE (nonzero), then
+// doublequote, singlequote and singleleftquote protect their respective
+// contents
+
+
+// parses the first double in the string; decimal is '.' only
+inline double VCL_DLLPUBLIC StringToDouble( const String& rStr )
+{
+ rtl_math_ConversionStatus eStatus;
+ return rtl::math::stringToDouble( rStr, sal_Unicode('.'), sal_Unicode(0), &eStatus, NULL);
+}
+
+inline double VCL_DLLPUBLIC StringToDouble( const ByteString& rStr )
+{
+ rtl_math_ConversionStatus eStatus;
+ return rtl::math::stringToDouble( rtl::OStringToOUString( rStr, osl_getThreadTextEncoding() ), sal_Unicode('.'), sal_Unicode(0), &eStatus, NULL);
+}
+
+// fills a character buffer with the string representation of a double
+// the buffer has to be long enough (e.g. 128 bytes)
+// returns the string len
+inline int VCL_DLLPUBLIC getValueOfDouble( char* pBuffer, double f, int nPrecision = 0)
+{
+ rtl::OString aStr( rtl::math::doubleToString( f, rtl_math_StringFormat_G, nPrecision, '.', true ) );
+ int nLen = aStr.getLength();
+ std::strncpy( pBuffer, aStr.getStr(), nLen+1 ); // copy string including terminating zero
+ return nLen;
+}
+
+} // namespace
+
+#endif // _PSPRINT_STRHELPER_HXX_
diff --git a/vcl/inc/vcl/subedit.hxx b/vcl/inc/vcl/subedit.hxx
new file mode 100644
index 000000000000..3ea1eaffa864
--- /dev/null
+++ b/vcl/inc/vcl/subedit.hxx
@@ -0,0 +1,48 @@
+/*************************************************************************
+ *
+ * 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_SUBEDIT_HXX
+#define _SV_SUBEDIT_HXX
+
+#include <vcl/sv.h>
+#include <vcl/edit.hxx>
+
+// ---------------
+// - ImplSubEdit -
+// ---------------
+
+class ImplSubEdit : public Edit
+{
+public:
+ ImplSubEdit( Edit* pParent, WinBits nStyle );
+
+ Edit* GetParent() const { return (Edit*)Edit::GetParent(); }
+
+ virtual void Modify();
+};
+
+#endif // _SV_SUBEDIT_HXX
diff --git a/vcl/inc/vcl/sv.h b/vcl/inc/vcl/sv.h
new file mode 100644
index 000000000000..9296570a71bb
--- /dev/null
+++ b/vcl/inc/vcl/sv.h
@@ -0,0 +1,33 @@
+/*************************************************************************
+ *
+ * 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_SV_H
+#define _SV_SV_H
+
+#include <tools/solar.h>
+
+#endif // _SV_SV_H
diff --git a/vcl/inc/vcl/svapp.hxx b/vcl/inc/vcl/svapp.hxx
new file mode 100644
index 000000000000..f90326ce50eb
--- /dev/null
+++ b/vcl/inc/vcl/svapp.hxx
@@ -0,0 +1,517 @@
+/*************************************************************************
+ *
+ * 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_SVAPP_HXX
+#define _SV_SVAPP_HXX
+
+#ifndef _VOS_THREAD_HXX
+#include <vos/thread.hxx>
+#endif
+#include <tools/string.hxx>
+#include <tools/link.hxx>
+#include <tools/unqid.hxx>
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/apptypes.hxx>
+#ifndef _VCL_SETTINGS_HXX
+#include <vcl/settings.hxx>
+#endif
+#include <vcl/vclevent.hxx>
+class Link;
+class AllSettings;
+class DataChangedEvent;
+class Accelerator;
+class Help;
+class OutputDevice;
+class Window;
+class WorkWindow;
+class MenuBar;
+class UnoWrapperBase;
+class Reflection;
+class KeyCode;
+class NotifyEvent;
+class KeyEvent;
+class MouseEvent;
+
+namespace vos { class IMutex; }
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/connection/XConnection.hpp>
+
+namespace com {
+namespace sun {
+namespace star {
+namespace lang {
+ class XMultiServiceFactory;
+}
+namespace awt {
+ class XToolkit;
+ class XDisplayConnection;
+}
+} } }
+
+// helper needed by SalLayout implementations as well as svx/source/dialog/svxbmpnumbalueset.cxx
+VCL_DLLPUBLIC sal_UCS4 GetMirroredChar( sal_UCS4 );
+
+// --------------------
+// - SystemWindowMode -
+// --------------------
+
+#define SYSTEMWINDOW_MODE_NOAUTOMODE ((USHORT)0x0001)
+#define SYSTEMWINDOW_MODE_DIALOG ((USHORT)0x0002)
+
+// -------------
+// - EventHook -
+// -------------
+
+typedef long (*VCLEventHookProc)( NotifyEvent& rEvt, void* pData );
+
+// --------------------
+// - ApplicationEvent -
+// --------------------
+
+// Erstmal wieder eingebaut, damit AppEvents auf dem MAC funktionieren
+#ifdef UNX
+// enum Doppelt in daemon.cxx unter unix Achtung !!!
+enum Service { SERVICE_OLE, SERVICE_APPEVENT, SERVICE_IPC };
+#endif
+
+class VCL_DLLPUBLIC ApplicationAddress
+{
+friend class Application;
+protected:
+ UniString aHostName;
+ UniString aDisplayName;
+ UniString aDomainName;
+ int nPID;
+
+public:
+ ApplicationAddress();
+ ApplicationAddress( const UniString& rDomain );
+ ApplicationAddress( const UniString& rHost,
+ const UniString& rDisp,
+ const UniString& rDomain );
+ ApplicationAddress( const UniString& rHost, int nPID );
+
+ const UniString& GetHost() const { return aHostName; }
+ const UniString& GetDisplay() const { return aDisplayName; }
+ const UniString& GetDomain() const { return aDomainName; }
+ int GetPID() const { return nPID; }
+
+ BOOL IsConnectToSame( const ApplicationAddress& rAdr ) const;
+};
+
+inline ApplicationAddress::ApplicationAddress()
+{
+ nPID = 0;
+}
+
+inline ApplicationAddress::ApplicationAddress( const UniString& rDomain )
+{
+ aDomainName = rDomain;
+ nPID = 0;
+}
+
+inline ApplicationAddress::ApplicationAddress( const UniString& rHost,
+ const UniString& rDisp,
+ const UniString& rDomain )
+{
+ aHostName = rHost;
+ aDisplayName = rDisp;
+ aDomainName = rDomain;
+ nPID = 0;
+}
+
+inline ApplicationAddress::ApplicationAddress( const UniString& rHost, int nPIDPar )
+{
+ aHostName = rHost;
+ nPID = nPIDPar;
+}
+
+inline BOOL ApplicationAddress::IsConnectToSame( const ApplicationAddress& rAdr ) const
+{
+ if ( nPID && ((nPID == rAdr.nPID) && (aHostName.Equals( rAdr.aHostName))) )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+#define APPEVENT_PARAM_DELIMITER '\n'
+
+#define APPEVENT_OPEN_STRING "Open"
+#define APPEVENT_PRINT_STRING "Print"
+#define APPEVENT_DISKINSERT_STRING "DiskInsert"
+#define APPEVENT_SAVEDOCUMENTS_STRING "SaveDocuments"
+
+class VCL_DLLPUBLIC ApplicationEvent
+{
+private:
+ UniString aSenderAppName; // Absender Applikationsname
+ ByteString aEvent; // Event
+ UniString aData; // Uebertragene Daten
+ ApplicationAddress aAppAddr; // Absender Addresse
+
+public:
+ ApplicationEvent() {}
+ ApplicationEvent( const UniString& rSenderAppName,
+ const ApplicationAddress& rAppAddr,
+ const ByteString& rEvent,
+ const UniString& rData );
+
+ const UniString& GetSenderAppName() const { return aSenderAppName; }
+ const ByteString& GetEvent() const { return aEvent; }
+ const UniString& GetData() const { return aData; }
+ const ApplicationAddress& GetAppAddress() const { return aAppAddr; }
+
+ BOOL IsOpenEvent() const;
+ BOOL IsPrintEvent() const;
+ BOOL IsDiskInsertEvent() const;
+
+ USHORT GetParamCount() const { return aData.GetTokenCount( APPEVENT_PARAM_DELIMITER ); }
+ UniString GetParam( USHORT nParam ) const { return aData.GetToken( nParam, APPEVENT_PARAM_DELIMITER ); }
+};
+
+inline ApplicationEvent::ApplicationEvent( const UniString& rSenderAppName,
+ const ApplicationAddress& rAppAddr,
+ const ByteString& rEvent,
+ const UniString& rData ) :
+ aSenderAppName( rSenderAppName ),
+ aEvent( rEvent ),
+ aData( rData ),
+ aAppAddr( rAppAddr )
+{
+}
+
+inline BOOL ApplicationEvent::IsOpenEvent() const
+{
+ if ( aEvent.Equals( APPEVENT_OPEN_STRING ))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+inline BOOL ApplicationEvent::IsPrintEvent() const
+{
+ if ( aEvent.Equals( APPEVENT_PRINT_STRING ))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+inline BOOL ApplicationEvent::IsDiskInsertEvent() const
+{
+ if ( aEvent.Equals( APPEVENT_DISKINSERT_STRING ))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+class VCL_DLLPUBLIC PropertyHandler
+{
+public:
+ virtual void Property( ApplicationProperty& ) = 0;
+};
+
+// ---------------
+// - Application -
+// ---------------
+
+class VCL_DLLPUBLIC Application
+{
+public:
+ Application();
+ virtual ~Application();
+
+ virtual void Main() = 0;
+
+ virtual BOOL QueryExit();
+
+ virtual void UserEvent( ULONG nEvent, void* pEventData );
+
+ virtual void ActivateExtHelp();
+ virtual void DeactivateExtHelp();
+
+ virtual void ShowStatusText( const XubString& rText );
+ virtual void HideStatusText();
+
+ virtual void ShowHelpStatusText( const XubString& rText );
+ virtual void HideHelpStatusText();
+
+ virtual void FocusChanged();
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+
+ virtual void Init();
+ virtual void DeInit();
+
+ static void InitAppRes( const ResId& rResId );
+
+ static USHORT GetCommandLineParamCount();
+ static XubString GetCommandLineParam( USHORT nParam );
+ static const XubString& GetAppFileName();
+
+ virtual USHORT Exception( USHORT nError );
+ static void Abort( const XubString& rErrorText );
+
+ static void Execute();
+ static void Quit();
+ static void Reschedule( bool bAllEvents = false );
+ static void Yield( bool bAllEvents = false );
+ static void EndYield();
+ static vos::IMutex& GetSolarMutex();
+ static vos::OThread::TThreadIdentifier GetMainThreadIdentifier();
+ static ULONG ReleaseSolarMutex();
+ static void AcquireSolarMutex( ULONG nCount );
+ static void EnableNoYieldMode( bool i_bNoYield );
+ static void AddPostYieldListener( const Link& i_rListener );
+ static void RemovePostYieldListener( const Link& i_rListener );
+
+ static BOOL IsInMain();
+ static BOOL IsInExecute();
+ static BOOL IsShutDown();
+ static BOOL IsInModalMode();
+ static USHORT GetModalModeCount();
+
+ static USHORT GetDispatchLevel();
+ static BOOL AnyInput( USHORT nType = INPUT_ANY );
+ static ULONG GetLastInputInterval();
+ static BOOL IsUICaptured();
+ static BOOL IsUserActive( USHORT nTest = USERACTIVE_ALL );
+
+ virtual void SystemSettingsChanging( AllSettings& rSettings,
+ Window* pFrame );
+ static void MergeSystemSettings( AllSettings& rSettings );
+ /** validate that the currently selected system UI font is suitable
+ to display the application's UI.
+
+ A localized test string will be checked if it can be displayed
+ in the currently selected system UI font. If no glyphs are
+ missing it can be assumed that the font is proper for display
+ of the application's UI.
+
+ @returns
+ <TRUE/> if the system font is suitable for our UI
+ <FALSE/> if the test string could not be displayed with the system font
+ */
+ static bool ValidateSystemFont();
+
+ static void SetSettings( const AllSettings& rSettings );
+ static const AllSettings& GetSettings();
+ static void NotifyAllWindows( DataChangedEvent& rDCEvt );
+
+ static void AddEventListener( const Link& rEventListener );
+ static void RemoveEventListener( const Link& rEventListener );
+ static void AddKeyListener( const Link& rKeyListener );
+ static void RemoveKeyListener( const Link& rKeyListener );
+ static void ImplCallEventListeners( ULONG nEvent, Window* pWin, void* pData );
+ static void ImplCallEventListeners( VclSimpleEvent* pEvent );
+ static BOOL HandleKey( ULONG nEvent, Window *pWin, KeyEvent* pKeyEvent );
+
+ static ULONG PostKeyEvent( ULONG nEvent, Window *pWin, KeyEvent* pKeyEvent );
+ static ULONG PostMouseEvent( ULONG nEvent, Window *pWin, MouseEvent* pMouseEvent );
+ static void RemoveMouseAndKeyEvents( Window *pWin );
+ static BOOL IsProcessedMouseOrKeyEvent( ULONG nEventId );
+
+ static ULONG PostUserEvent( ULONG nEvent, void* pEventData = NULL );
+ static ULONG PostUserEvent( const Link& rLink, void* pCaller = NULL );
+ static BOOL PostUserEvent( ULONG& rEventId, ULONG nEvent, void* pEventData = NULL );
+ static BOOL PostUserEvent( ULONG& rEventId, const Link& rLink, void* pCaller = NULL );
+ static void RemoveUserEvent( ULONG nUserEvent );
+
+ static BOOL InsertIdleHdl( const Link& rLink, USHORT nPriority );
+ static void RemoveIdleHdl( const Link& rLink );
+
+ virtual void AppEvent( const ApplicationEvent& rAppEvent );
+
+ virtual void Property( ApplicationProperty& );
+ void SetPropertyHandler( PropertyHandler* pHandler );
+
+#ifndef NO_GETAPPWINDOW
+ static WorkWindow* GetAppWindow();
+#endif
+
+ static Window* GetFocusWindow();
+ static OutputDevice* GetDefaultDevice();
+
+ static Window* GetFirstTopLevelWindow();
+ static Window* GetNextTopLevelWindow( Window* pWindow );
+
+ static long GetTopWindowCount();
+ static Window* GetTopWindow( long nIndex );
+ static Window* GetActiveTopWindow();
+
+ static void SetAppName( const String& rUniqueName );
+ static String GetAppName();
+
+ static void SetDisplayName( const UniString& rDisplayName );
+ static UniString GetDisplayName();
+
+ static unsigned int GetScreenCount();
+ // IsMultiDisplay returns:
+ // true: different screens are separate and windows cannot be moved
+ // between them (e.g. Xserver with multiple screens)
+ // false: screens form up one large display area
+ // windows can be moved between single screens
+ // (e.g. Xserver with Xinerama, Windows)
+ static bool IsMultiDisplay();
+ static Rectangle GetScreenPosSizePixel( unsigned int nScreen );
+ static Rectangle GetWorkAreaPosSizePixel( unsigned int nScreen );
+ static rtl::OUString GetScreenName( unsigned int nScreen );
+ static unsigned int GetDefaultDisplayNumber();
+ // if IsMultiDisplay() == false the return value will be
+ // nearest screen of the target rectangle
+ // in case of IsMultiDisplay() == true the return value
+ // will always be GetDefaultDisplayNumber()
+ static unsigned int GetBestScreen( const Rectangle& );
+
+ static const LocaleDataWrapper& GetAppLocaleDataWrapper();
+
+ static BOOL InsertAccel( Accelerator* pAccel );
+ static void RemoveAccel( Accelerator* pAccel );
+ static void FlushAccel();
+ static BOOL CallAccel( const KeyCode& rKeyCode, USHORT nRepeat = 0 );
+
+ static ULONG AddHotKey( const KeyCode& rKeyCode, const Link& rLink, void* pData = NULL );
+ static void RemoveHotKey( ULONG nId );
+ static ULONG AddEventHook( VCLEventHookProc pProc, void* pData = NULL );
+ static void RemoveEventHook( ULONG nId );
+ static long CallEventHooks( NotifyEvent& rEvt );
+ static long CallPreNotify( NotifyEvent& rEvt );
+ static long CallEvent( NotifyEvent& rEvt );
+
+ static void SetHelp( Help* pHelp = NULL );
+ static Help* GetHelp();
+
+ static void EnableAutoHelpId( BOOL bEnabled = TRUE );
+ static BOOL IsAutoHelpIdEnabled();
+
+ static void EnableAutoMnemonic( BOOL bEnabled = TRUE );
+ static BOOL IsAutoMnemonicEnabled();
+
+ static ULONG GetReservedKeyCodeCount();
+ static const KeyCode* GetReservedKeyCode( ULONG i );
+ static String GetReservedKeyCodeDescription( ULONG i );
+
+ static void SetDefDialogParent( Window* pWindow );
+ static Window* GetDefDialogParent();
+
+ static void EnableDialogCancel( BOOL bDialogCancel = TRUE );
+ static BOOL IsDialogCancelEnabled();
+
+ static void SetSystemWindowMode( USHORT nMode );
+ static USHORT GetSystemWindowMode();
+
+ static void SetDialogScaleX( short nScale );
+ static short GetDialogScaleX();
+
+ static void SetFontPath( const String& rPath );
+ static const String& GetFontPath();
+
+ static UniqueItemId CreateUniqueId();
+
+ static ::com::sun::star::uno::Reference< ::com::sun::star::awt::XDisplayConnection > GetDisplayConnection();
+
+ // The global service manager has to be created before!
+ static ::com::sun::star::uno::Reference< ::com::sun::star::awt::XToolkit > GetVCLToolkit();
+ static UnoWrapperBase* GetUnoWrapper( BOOL bCreateIfNotExists = TRUE );
+ static void SetUnoWrapper( UnoWrapperBase* pWrapper );
+
+ static void SetFilterHdl( const Link& rLink );
+ static const Link& GetFilterHdl();
+
+ static BOOL IsAccessibilityEnabled();
+
+ static void EnableHeadlessMode( BOOL bEnable = TRUE );
+ static BOOL IsHeadlessModeEnabled();
+
+ static void ShowNativeErrorBox(const String& sTitle ,
+ const String& sMessage);
+
+ // IME Status Window Control:
+
+ /** Return true if any IME status window can be toggled on and off
+ externally.
+
+ Must only be called with the Solar mutex locked.
+ */
+ static bool CanToggleImeStatusWindow();
+
+ /** Toggle any IME status window on and off.
+
+ This only works if CanToggleImeStatusWinodw returns true (otherwise,
+ any calls of this method are ignored).
+
+ Must only be called with the Solar mutex locked.
+ */
+ static void ShowImeStatusWindow(bool bShow);
+
+ /** Return true if any IME status window should be turned on by default
+ (this decision can be locale dependent, for example).
+
+ Can be called without the Solar mutex locked.
+ */
+ static bool GetShowImeStatusWindowDefault();
+
+ /** Returns a string representing the desktop environment
+ the process is currently running in.
+ */
+ static const ::rtl::OUString& GetDesktopEnvironment();
+
+ /** Add a file to the system shells recent document list if there is any.
+ This function may have no effect under Unix because there is no
+ standard API among the different desktop managers.
+
+ @param rFileUrl
+ The file url of the document.
+
+ @param rMimeType
+ The mime content type of the document specified by aFileUrl.
+ If an empty string will be provided "application/octet-stream"
+ will be used.
+ */
+ static void AddToRecentDocumentList(const rtl::OUString& rFileUrl, const rtl::OUString& rMimeType);
+
+private:
+
+ DECL_STATIC_LINK( Application, PostEventHandler, void* );
+};
+
+VCL_DLLPUBLIC Application* GetpApp();
+
+VCL_DLLPUBLIC BOOL InitVCL( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > & );
+VCL_DLLPUBLIC void DeInitVCL();
+
+VCL_DLLPUBLIC BOOL InitAccessBridge( BOOL bAllowCancel, BOOL &rCancelled );
+
+// only allowed to call, if no thread is running. You must call JoinMainLoopThread to free all memory.
+VCL_DLLPUBLIC void CreateMainLoopThread( oslWorkerFunction pWorker, void * pThreadData );
+VCL_DLLPUBLIC void JoinMainLoopThread();
+
+inline void Application::EndYield()
+{
+ PostUserEvent( Link() );
+}
+
+#endif // _APP_HXX
diff --git a/vcl/inc/vcl/svcompat.hxx b/vcl/inc/vcl/svcompat.hxx
new file mode 100644
index 000000000000..9e461da4e54b
--- /dev/null
+++ b/vcl/inc/vcl/svcompat.hxx
@@ -0,0 +1,70 @@
+/*************************************************************************
+ *
+ * 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_SVCOMPAT_HXX
+#define _SV_SVCOMPAT_HXX
+
+#include <sv.h>
+
+// -----------
+// - Defines -
+// -----------
+
+#define COMPAT_FORMAT( char1, char2, char3, char4 ) \
+ ((ULONG)((((ULONG)(char)(char1)))| \
+ (((ULONG)(char)(char2))<<8UL)| \
+ (((ULONG)(char)(char3))<<16UL)| \
+ ((ULONG)(char)(char4))<<24UL))
+
+
+class SvStream;
+
+// --------------
+// - ImplCompat -
+// --------------
+
+class ImplCompat
+{
+ SvStream* mpRWStm;
+ UINT32 mnCompatPos;
+ UINT32 mnTotalSize;
+ UINT16 mnStmMode;
+ UINT16 mnVersion;
+
+ ImplCompat() {}
+ ImplCompat( const ImplCompat& rCompat ) {}
+ ImplCompat& operator=( const ImplCompat& rCompat ) { return *this; }
+ BOOL operator==( const ImplCompat& rCompat ) { return FALSE; }
+
+public:
+ ImplCompat( SvStream& rStm, USHORT nStreamMode, UINT16 nVersion = 1 );
+ ~ImplCompat();
+
+ UINT16 GetVersion() const { return mnVersion; }
+};
+
+#endif // _SV_SVCOMPAT_HXX
diff --git a/vcl/inc/vcl/svdata.hxx b/vcl/inc/vcl/svdata.hxx
new file mode 100644
index 000000000000..5cc8f32d7ac9
--- /dev/null
+++ b/vcl/inc/vcl/svdata.hxx
@@ -0,0 +1,453 @@
+/*************************************************************************
+ *
+ * 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_SVDATA_HXX
+#define _SV_SVDATA_HXX
+
+#ifndef _VOS_THREAD_HXX
+#include <vos/thread.hxx>
+#endif
+#include <tools/string.hxx>
+#include <tools/gen.hxx>
+#include <tools/shl.hxx>
+#include <tools/link.hxx>
+#include <vcl/vclevent.hxx>
+#include <vcl/sv.h>
+#include <tools/color.hxx>
+#include <tools/debug.hxx>
+#include <vcl/dllapi.h>
+#include <com/sun/star/uno/Reference.hxx>
+#include <unotools/options.hxx>
+
+namespace com {
+namespace sun {
+namespace star {
+namespace lang {
+ class XMultiServiceFactory;
+}
+namespace frame {
+ class XSessionManagerClient;
+}
+namespace awt {
+ class XDisplayConnection;
+}
+}}}
+
+struct ImplTimerData;
+struct ImplFileImageCacheData;
+struct ImplConfigData;
+class ImplDirectFontSubstitution;
+struct ImplHotKey;
+struct ImplEventHook;
+class Point;
+class Rectangle;
+class ImpResMgr;
+class ResMgr;
+class UniqueIndex;
+class ImplAccelManager;
+class ImplDevFontList;
+class ImplFontCache;
+class HelpTextWindow;
+class ImplTBDragMgr;
+class ImplButtonList;
+class ImplIdleMgr;
+class DbgWindow;
+class FloatingWindow;
+class AllSettings;
+class KeyCode;
+class NotifyEvent;
+class Timer;
+class AutoTimer;
+class Help;
+class ImageList;
+class Image;
+class PopupMenu;
+class Application;
+class OutputDevice;
+class Window;
+class SystemWindow;
+class WorkWindow;
+class Dialog;
+class VirtualDevice;
+class Printer;
+class SalFrame;
+class SalInstance;
+class SalSystem;
+class SalProcessWindowList;
+class SalTrayList;
+class UniqueIdContainer;
+class List;
+class ImplPrnQueueList;
+class ImplVDevCache;
+class UnoWrapperBase;
+class GraphicConverter;
+class ImplWheelWindow;
+class SalTimer;
+class SalI18NImeStatus;
+class DockingManager;
+class VclEventListeners2;
+
+namespace vos { class OMutex; }
+namespace vos { class OCondition; }
+namespace vcl { class DisplayConnection; class SettingsConfigItem; class DeleteOnDeinitBase; }
+namespace utl { class DefaultFontConfiguration; class FontSubstConfiguration; }
+
+// -----------------
+// - ImplSVAppData -
+// -----------------
+class LocaleConfigurationListener : public utl::ConfigurationListener
+{
+public:
+ virtual void ConfigurationChanged( utl::ConfigurationBroadcaster*, sal_uInt32 );
+};
+
+struct ImplSVAppData
+{
+ enum ImeStatusWindowMode
+ {
+ ImeStatusWindowMode_UNKNOWN,
+ ImeStatusWindowMode_HIDE,
+ ImeStatusWindowMode_SHOW
+ };
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > mxMSF;
+ String* mpMSFTempFileName;
+ AllSettings* mpSettings; // Application settings
+ LocaleConfigurationListener* mpCfgListener;
+ VclEventListeners* mpEventListeners; // listeners for vcl events (eg, extended toolkit)
+ VclEventListeners* mpKeyListeners; // listeners for key events only (eg, extended toolkit)
+ ImplAccelManager* mpAccelMgr; // Accelerator Manager
+ XubString* mpAppName; // Application name
+ XubString* mpAppFileName; // Abs. Application FileName
+ XubString* mpDisplayName; // Application Display Name
+ String* mpFontPath; // Additional Fontpath
+ Help* mpHelp; // Application help
+ PopupMenu* mpActivePopupMenu; // Actives Popup-Menu (in Execute)
+ UniqueIdContainer* mpUniqueIdCont; // Fuer Eindeutige Id's
+ ImplIdleMgr* mpIdleMgr; // Idle-Manager
+ ImplWheelWindow* mpWheelWindow; // WheelWindow
+ ImplHotKey* mpFirstHotKey; // HotKey-Verwaltung
+ ImplEventHook* mpFirstEventHook; // Event-Hooks
+ VclEventListeners2* mpPostYieldListeners; // post yield listeners
+ ULONG mnLastInputTime; // GetLastInputTime()
+ USHORT mnDispatchLevel; // DispatchLevel
+ USHORT mnModalMode; // ModalMode Count
+ USHORT mnModalDialog; // ModalDialog Count
+ USHORT mnAccessCount; // AccessHdl Count
+ USHORT mnSysWinMode; // Modus, wann SystemWindows erzeugt werden sollen
+ USHORT mnLayout; // --- RTL-Flags --- currently not used, only for testing
+ short mnDialogScaleX; // Scale X-Positions and sizes in Dialogs
+ BOOL mbInAppMain; // is Application::Main() on stack
+ BOOL mbInAppExecute; // is Application::Execute() on stack
+ BOOL mbAppQuit; // is Application::Quit() called
+ BOOL mbSettingsInit; // TRUE: Settings are initialized
+ BOOL mbDialogCancel; // TRUE: Alle Dialog::Execute()-Aufrufe werden mit return FALSE sofort beendet
+ BOOL mbNoYield; // Application::Yield will not wait for events if the queue is empty
+ // essentially that makes it the same as Application::Reschedule
+
+ /** Controls whether showing any IME status window is toggled on or off.
+
+ Only meaningful if showing IME status windows can be toggled on and off
+ externally (see Application::CanToggleImeStatusWindow).
+ */
+ ImeStatusWindowMode meShowImeStatusWindow;
+
+ DECL_STATIC_LINK( ImplSVAppData, ImplQuitMsg, void* );
+
+};
+
+
+// -----------------
+// - ImplSVGDIData -
+// -----------------
+
+struct ImplSVGDIData
+{
+ OutputDevice* mpFirstWinGraphics; // First OutputDevice with a Frame Graphics
+ OutputDevice* mpLastWinGraphics; // Last OutputDevice with a Frame Graphics
+ OutputDevice* mpFirstVirGraphics; // First OutputDevice with a VirtualDevice Graphics
+ OutputDevice* mpLastVirGraphics; // Last OutputDevice with a VirtualDevice Graphics
+ OutputDevice* mpFirstPrnGraphics; // First OutputDevice with a InfoPrinter Graphics
+ OutputDevice* mpLastPrnGraphics; // Last OutputDevice with a InfoPrinter Graphics
+ VirtualDevice* mpFirstVirDev; // First VirtualDevice
+ VirtualDevice* mpLastVirDev; // Last VirtualDevice
+ Printer* mpFirstPrinter; // First Printer
+ Printer* mpLastPrinter; // Last Printer
+ ImplPrnQueueList* mpPrinterQueueList; // List of all printer queue
+ ImplDevFontList* mpScreenFontList; // Screen-Font-List
+ ImplFontCache* mpScreenFontCache; // Screen-Font-Cache
+ ImplDirectFontSubstitution* mpDirectFontSubst;// Font-Substitutons defined in Tools->Options->Fonts
+ GraphicConverter* mpGrfConverter; // Converter for graphics
+ long mnRealAppFontX; // AppFont X-Numenator for 40/tel Width
+ long mnAppFontX; // AppFont X-Numenator for 40/tel Width + DialogScaleX
+ long mnAppFontY; // AppFont Y-Numenator for 80/tel Height
+ BOOL mbFontSubChanged; // TRUE: FontSubstitution wurde zwischen Begin/End geaendert
+ utl::DefaultFontConfiguration* mpDefaultFontConfiguration;
+ utl::FontSubstConfiguration* mpFontSubstConfiguration;
+ bool mbPrinterPullModel; // true: use pull model instead of normal push model when printing
+ bool mbNativeFontConfig; // true: do not override UI font
+ bool mbNoXORClipping; // true: do not use XOR to achieve clipping effects
+};
+
+
+// -----------------
+// - ImplSVWinData -
+// -----------------
+
+struct ImplSVWinData
+{
+ Window* mpFirstFrame; // First FrameWindow
+ Window* mpDefDialogParent; // Default Dialog Parent
+ WorkWindow* mpAppWin; // Application-Window
+ Window* mpFocusWin; // window, that has the focus
+ Window* mpActiveApplicationFrame; // the last active application frame, can be used as DefModalDialogParent if no focuswin set
+ Window* mpCaptureWin; // window, that has the mouse capture
+ Window* mpLastDeacWin; // Window, that need a deactivate (FloatingWindow-Handling)
+ DbgWindow* mpDbgWin; // debug window
+ FloatingWindow* mpFirstFloat; // First FloatingWindow in PopupMode
+ Dialog* mpLastExecuteDlg; // Erster Dialog, der sich in Execute befindet
+ Window* mpExtTextInputWin; // Window, which is in ExtTextInput
+ Window* mpTrackWin; // window, that is in tracking mode
+ AutoTimer* mpTrackTimer; // tracking timer
+ ImageList* mpMsgBoxImgList; // ImageList for MessageBox
+ ImageList* mpMsgBoxHCImgList; // ImageList for MessageBox (high contrast mode)
+ Window* mpAutoScrollWin; // window, that is in AutoScrollMode mode
+ USHORT mnTrackFlags; // tracking flags
+ USHORT mnAutoScrollFlags; // auto scroll flags
+ BOOL mbNoDeactivate; // TRUE: keine Deactivate durchfuehren
+ BOOL mbNoSaveFocus; // TRUE: menues must not save/restore focus
+ BOOL mbNoSaveBackground; // TRUE: save background is unnecessary or even less performant
+};
+
+
+// ------------------
+// - ImplSVCtrlData -
+// ------------------
+
+struct ImplSVCtrlData
+{
+ ImageList* mpCheckImgList; // ImageList for CheckBoxes
+ ImageList* mpRadioImgList; // ImageList for RadioButtons
+ ImageList* mpPinImgList; // ImageList for PIN
+ ImageList* mpSplitHPinImgList; // ImageList for Horizontale SplitWindows
+ ImageList* mpSplitVPinImgList; // ImageList for Vertikale SplitWindows (PIN's)
+ ImageList* mpSplitHArwImgList; // ImageList for Horizontale SplitWindows (Arrows)
+ ImageList* mpSplitVArwImgList; // ImageList for Vertikale SplitWindows (Arrows)
+ Image* mpDisclosurePlus;
+ Image* mpDisclosurePlusHC;
+ Image* mpDisclosureMinus;
+ Image* mpDisclosureMinusHC;
+ ImplTBDragMgr* mpTBDragMgr; // DragMgr for ToolBox
+ USHORT mnCheckStyle; // CheckBox-Style for ImageList-Update
+ USHORT mnRadioStyle; // Radio-Style for ImageList-Update
+ ULONG mnLastCheckFColor; // Letzte FaceColor fuer CheckImage
+ ULONG mnLastCheckWColor; // Letzte WindowColor fuer CheckImage
+ ULONG mnLastCheckWTextColor; // Letzte WindowTextColor fuer CheckImage
+ ULONG mnLastCheckLColor; // Letzte LightColor fuer CheckImage
+ ULONG mnLastRadioFColor; // Letzte FaceColor fuer RadioImage
+ ULONG mnLastRadioWColor; // Letzte WindowColor fuer RadioImage
+ ULONG mnLastRadioLColor; // Letzte LightColor fuer RadioImage
+};
+
+
+// ------------------
+// - ImplSVHelpData -
+// ------------------
+
+struct ImplSVHelpData
+{
+ BOOL mbContextHelp : 1; // is ContextHelp enabled
+ BOOL mbExtHelp : 1; // is ExtendedHelp enabled
+ BOOL mbExtHelpMode : 1; // is in ExtendedHelp Mode
+ BOOL mbOldBalloonMode : 1; // BallonMode, befor ExtHelpMode started
+ BOOL mbBalloonHelp : 1; // is BalloonHelp enabled
+ BOOL mbQuickHelp : 1; // is QuickHelp enabled
+ BOOL mbSetKeyboardHelp : 1; // tiphelp was activated by keyboard
+ BOOL mbKeyboardHelp : 1; // tiphelp was activated by keyboard
+ BOOL mbAutoHelpId : 1; // generate HelpIds
+ BOOL mbRequestingHelp : 1; // In Window::RequestHelp
+ HelpTextWindow* mpHelpWin; // HelpWindow
+ ULONG mnLastHelpHideTime; // ticks of last show
+};
+
+struct ImplSVNWFData
+{
+ bool mbMenuBarDockingAreaCommonBG; // e.g. WinXP default theme
+ bool mbDockingAreaSeparateTB; // individual toolbar backgrounds
+ // instead of one for docking area
+ bool mbToolboxDropDownSeparate; // two adjacent buttons for
+ // toolbox dropdown buttons
+ int mnMenuFormatExtraBorder; // inner popup menu border
+ bool mbFlatMenu; // no popup 3D border
+ Color maMenuBarHighlightTextColor; // override higlight text color
+ // in menubar if not transparent
+ bool mbOpenMenuOnF10; // on gnome the first menu opens on F10
+ bool mbNoFocusRects; // on Aqua focus rects are not used
+ bool mbNoBoldTabFocus; // on Aqua and Gnome the focused tab has not bold text
+ bool mbCenteredTabs; // on Aqua, tabs are centered
+ bool mbNoActiveTabTextRaise; // on Aqua the text for the selected tab
+ // should not "jump up" a pixel
+ bool mbProgressNeedsErase; // set true for platforms that should draw the
+ // window background before drawing the native
+ // progress bar
+ bool mbCheckBoxNeedsErase; // set true for platforms that should draw the
+ // window background before drawing the native
+ // checkbox
+ bool mbScrollbarJumpPage; // true for "jump to here" behavior
+};
+
+
+// --------------
+// - ImplSVData -
+// --------------
+
+struct ImplSVData
+{
+ void* mpSalData; // SalData
+ SalInstance* mpDefInst; // Default SalInstance
+ Application* mpApp; // pApp
+ WorkWindow* mpDefaultWin; // Default-Window
+ BOOL mbDeInit; // Is VCL deinitializing
+ ULONG mnThreadCount; // is VCL MultiThread enabled
+ ImplConfigData* mpFirstConfigData; // Zeiger auf ersten Config-Block
+ ImplTimerData* mpFirstTimerData; // list of all running timers
+ SalTimer* mpSalTimer; // interface to sal event loop/timers
+ SalI18NImeStatus* mpImeStatus; // interface to ime status window
+ SalSystem* mpSalSystem; // SalSystem interface
+ ResMgr* mpResMgr; // SV-Resource-Manager
+ ULONG mnTimerPeriod; // current timer period
+ ULONG mnTimerUpdate; // TimerCallbackProcs on stack
+ BOOL mbNotAllTimerCalled;// TRUE: Es muessen noch Timer abgearbeitet werden
+ BOOL mbNoCallTimer; // TRUE: No Timeout calls
+ ImplSVAppData maAppData; // indepen data for class Application
+ ImplSVGDIData maGDIData; // indepen data for Output classes
+ ImplSVWinData maWinData; // indepen data for Windows classes
+ ImplSVCtrlData maCtrlData; // indepen data for Control classes
+ ImplSVHelpData maHelpData; // indepen data for Help classes
+ ImplSVNWFData maNWFData;
+ UnoWrapperBase* mpUnoWrapper;
+ Window* mpIntroWindow; // the splash screen
+ DockingManager* mpDockingManager;
+ BOOL mbIsTestTool;
+
+ vos::OThread::TThreadIdentifier mnMainThreadId;
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::awt::XDisplayConnection > mxDisplayConnection;
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > mxAccessBridge;
+ com::sun::star::uno::Reference< com::sun::star::frame::XSessionManagerClient > xSMClient;
+ ::vcl::SettingsConfigItem* mpSettingsConfigItem;
+ std::list< vcl::DeleteOnDeinitBase* >* mpDeinitDeleteList;
+};
+
+void ImplInitSVData();
+void ImplDeInitSVData();
+void ImplDestroySVData();
+Window* ImplGetDefaultWindow();
+VCL_DLLPUBLIC ResMgr* ImplGetResMgr();
+VCL_DLLPUBLIC ResId VclResId( sal_Int32 nId ); // throws std::bad_alloc if no res mgr
+DockingManager* ImplGetDockingManager();
+void ImplWindowAutoMnemonic( Window* pWindow );
+
+void ImplUpdateSystemProcessWindow();
+Window* ImplFindWindow( const SalFrame* pFrame, Point& rSalFramePos );
+
+// SVAPP.CXX
+BOOL ImplCallHotKey( const KeyCode& rKeyCode );
+void ImplFreeHotKeyData();
+void ImplFreeEventHookData();
+
+// WINPROC.CXX
+long ImplCallPreNotify( NotifyEvent& rEvt );
+long ImplCallEvent( NotifyEvent& rEvt );
+
+extern VCL_DLLPUBLIC ImplSVData* pImplSVData;
+inline VCL_DLLPUBLIC ImplSVData* ImplGetSVData() { return pImplSVData; }
+inline ImplSVData* ImplGetAppSVData() { return ImplGetSVData(); }
+
+bool ImplInitAccessBridge( BOOL bAllowCancel, BOOL &rCancelled );
+
+// -----------------------------------------------------------------------
+
+// -----------------
+// - ImplSVEmpyStr -
+// -----------------
+
+// Empty-SV-String
+
+inline const String& ImplGetSVEmptyStr()
+ { return String::EmptyString(); }
+inline const ByteString& ImplGetSVEmptyByteStr()
+ { return ByteString::EmptyString(); }
+
+// -----------------------------------------------------------------------
+
+// ----------------------
+// - struct ImplDelData -
+// ----------------------
+// ImplDelData is used as a "dog tag" by a window when it
+// does something that could indirectly destroy the window
+// TODO: wild destruction of a window should not be possible
+
+struct ImplDelData
+{
+ ImplDelData* mpNext;
+ const Window* mpWindow;
+ BOOL mbDel;
+
+ ImplDelData( const Window* pWindow = NULL )
+ : mpNext( NULL ), mpWindow( NULL ), mbDel( FALSE )
+ { if( pWindow ) AttachToWindow( pWindow ); }
+
+ virtual ~ImplDelData();
+
+ bool IsDead() const
+ {
+ DBG_ASSERT( mbDel == FALSE, "object deleted while in use !" );
+ return (mbDel!=FALSE);
+ }
+ BOOL /*deprecated */IsDelete() const { return (BOOL)IsDead(); }
+
+private:
+ void AttachToWindow( const Window* );
+};
+
+// ---------------
+// - ImplSVEvent -
+// ---------------
+
+struct ImplSVEvent
+{
+ ULONG mnEvent;
+ void* mpData;
+ Link* mpLink;
+ Window* mpWindow;
+ ImplDelData maDelData;
+ BOOL mbCall;
+};
+
+#endif // _SV_SVDATA_HXX
diff --git a/vcl/inc/vcl/svids.hrc b/vcl/inc/vcl/svids.hrc
new file mode 100644
index 000000000000..059ed1524b7c
--- /dev/null
+++ b/vcl/inc/vcl/svids.hrc
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SVIDS_HRC
+#define _SV_SVIDS_HRC
+
+#include "svl/solar.hrc"
+
+#define SV_RESID_STDOFFSET 0
+#define SV_RESID_WINOFFSET 1
+#define SV_RESID_OS2OFFSET 2
+#define SV_RESID_MACOFFSET 3
+#define SV_RESID_UNIXOFFSET 4
+#define SV_RESID_MONOOFFSET 5
+
+// Achtung: Diese Id's muessen min. 10 Werte auseinanderliegen, da
+// je nach Style noch ein Offset aufgerechnet wird
+#define SV_RESID_BITMAP_CHECK 1000
+#define SV_RESID_BITMAP_RADIO 1010
+
+#define SV_RESID_BITMAP_MSGBOX 1020
+#define SV_RESID_BITMAP_MSGBOX_HC 1021
+
+#define SV_RESID_BITMAP_PIN 1030
+
+#define SV_RESID_BITMAP_SPLITHPIN 1040
+#define SV_RESID_BITMAP_SPLITVPIN 1041
+#define SV_RESID_BITMAP_SPLITHARW 1042
+#define SV_RESID_BITMAP_SPLITVARW 1043
+
+#define SV_RESID_BITMAP_SCROLLMSK 1050
+#define SV_RESID_BITMAP_SCROLLBMP 1051
+#define SV_RESID_BITMAP_CLOSEDOC 1052
+#define SV_RESID_BITMAP_CLOSEDOCHC 1053
+
+#define SV_DISCLOSURE_PLUS 1060
+#define SV_DISCLOSURE_MINUS 1061
+#define SV_DISCLOSURE_PLUS_HC 1062
+#define SV_DISCLOSURE_MINUS_HC 1063
+
+#define SV_RESID_MENU_EDIT 2000
+#define SV_MENU_EDIT_UNDO 1
+#define SV_MENU_EDIT_CUT 2
+#define SV_MENU_EDIT_COPY 3
+#define SV_MENU_EDIT_PASTE 4
+#define SV_MENU_EDIT_DELETE 5
+#define SV_MENU_EDIT_SELECTALL 6
+#define SV_MENU_EDIT_INSERTSYMBOL 7
+#define SV_RESID_STRING_NOSELECTIONPOSSIBLE 2001
+
+#define SV_MENU_MAC_SERVICES 2002
+#define SV_MENU_MAC_HIDEAPP 2003
+#define SV_MENU_MAC_HIDEALL 2004
+#define SV_MENU_MAC_SHOWALL 2005
+#define SV_MENU_MAC_QUITAPP 2006
+
+#define SV_DLG_PRINT 2048
+#define SV_PRINT_OK 1
+#define SV_PRINT_CANCEL 2
+#define SV_PRINT_HELP 3
+#define SV_PRINT_PAGE_PREVIEW 4
+#define SV_PRINT_PAGE_TXT 5
+#define SV_PRINT_PAGE_FORWARD 6
+#define SV_PRINT_PAGE_BACKWARD 7
+#define SV_PRINT_PAGE_EDIT 8
+#define SV_PRINT_TABCTRL 9
+#define SV_PRINT_PRT_TYPE 10
+#define SV_PRINT_PRT_STATUS 11
+#define SV_PRINT_PRT_LOCATION 12
+#define SV_PRINT_PRT_COMMENT 13
+#define SV_PRINT_TOFILE_TXT 14
+#define SV_PRINT_DEFPRT_TXT 15
+#define SV_PRINT_PRINTPREVIEW_TXT 16
+
+#define SV_PRINT_TAB_NUP 1
+#define SV_PRINT_PRT_NUP_LAYOUT_FL 1
+#define SV_PRINT_PRT_NUP_DEFAULT_BTN 2
+#define SV_PRINT_PRT_NUP_BROCHURE_BTN 3
+#define SV_PRINT_PRT_NUP_PAGES_BTN 4
+#define SV_PRINT_PRT_NUP_PAGES_BOX 5
+#define SV_PRINT_PRT_NUP_NUM_PAGES_TXT 6
+#define SV_PRINT_PRT_NUP_COLS_EDT 7
+#define SV_PRINT_PRT_NUP_TIMES_TXT 8
+#define SV_PRINT_PRT_NUP_ROWS_EDT 9
+#define SV_PRINT_PRT_NUP_MARGINS_PAGES_1_TXT 10
+#define SV_PRINT_PRT_NUP_MARGINS_PAGES_EDT 11
+#define SV_PRINT_PRT_NUP_MARGINS_PAGES_2_TXT 12
+#define SV_PRINT_PRT_NUP_MARGINS_SHEET_1_TXT 13
+#define SV_PRINT_PRT_NUP_MARGINS_SHEET_EDT 14
+#define SV_PRINT_PRT_NUP_MARGINS_SHEET_2_TXT 15
+#define SV_PRINT_PRT_NUP_ORIENTATION_TXT 16
+#define SV_PRINT_PRT_NUP_ORIENTATION_BOX 17
+#define SV_PRINT_PRT_NUP_ORDER_TXT 18
+#define SV_PRINT_PRT_NUP_ORDER_BOX 19
+#define SV_PRINT_PRT_NUP_BORDER_CB 20
+
+#define SV_PRINT_PRT_NUP_ORIENTATION_AUTOMATIC 0
+#define SV_PRINT_PRT_NUP_ORIENTATION_PORTRAIT 1
+#define SV_PRINT_PRT_NUP_ORIENTATION_LANDSCAPE 2
+
+#define SV_PRINT_PRT_NUP_ORDER_LRTD 0
+#define SV_PRINT_PRT_NUP_ORDER_TDLR 1
+
+#define SV_PRINT_TAB_JOB 2
+#define SV_PRINT_PRINTERS_FL 1
+#define SV_PRINT_PRINTERS 2
+#define SV_PRINT_PRT_SETUP 3
+#define SV_PRINT_RANGE 4
+#define SV_PRINT_ALL 5
+#define SV_PRINT_PAGERANGE 6
+#define SV_PRINT_SELECTION 7
+#define SV_PRINT_PAGERANGE_EDIT 8
+#define SV_PRINT_COPIES 9
+#define SV_PRINT_COPYCOUNT 10
+#define SV_PRINT_COPYCOUNT_FIELD 11
+#define SV_PRINT_COLLATE 12
+#define SV_PRINT_COLLATE_IMAGE 13
+#define SV_PRINT_BUTTONLINE 14
+#define SV_PRINT_COLLATE_IMG 15
+#define SV_PRINT_NOCOLLATE_IMG 16
+#define SV_PRINT_COLLATE_HC_IMG 17
+#define SV_PRINT_NOCOLLATE_HC_IMG 18
+#define SV_PRINT_NOPAGES 19
+#define SV_PRINT_STATUS_TXT 20
+#define SV_PRINT_LOCATION_TXT 21
+#define SV_PRINT_COMMENT_TXT 22
+#define SV_PRINT_DETAILS_BTN 23
+
+#define SV_PRINT_TAB_OPT 3
+#define SV_PRINT_OPT_PRINT_FL 1
+#define SV_PRINT_OPT_TOFILE 2
+#define SV_PRINT_OPT_SINGLEJOBS 3
+#define SV_PRINT_OPT_REVERSE 4
+
+#define SV_DLG_PRINT_PROGRESS 2049
+#define SV_PRINT_PROGRESS_CANCEL 1
+#define SV_PRINT_PROGRESS_TEXT 2
+
+#define SV_PRINT_NATIVE_STRINGS 2050
+#define SV_PRINT_NOPRINTERWARNING 2051
+#define SV_PRINT_NOCONTENT 2052
+
+#define SV_HELPTEXT_CLOSE 10000
+#define SV_HELPTEXT_MINIMIZE 10001
+#define SV_HELPTEXT_MAXIMIZE 10002
+#define SV_HELPTEXT_RESTORE 10003
+#define SV_HELPTEXT_ROLLDOWN 10004
+#define SV_HELPTEXT_ROLLUP 10005
+#define SV_HELPTEXT_HELP 10006
+#define SV_HELPTEXT_ALWAYSVISIBLE 10007
+#define SV_HELPTEXT_FADEIN 10008
+#define SV_HELPTEXT_FADEOUT 10009
+#define SV_HELPTEXT_SPLITFLOATING 10010
+#define SV_HELPTEXT_SPLITFIXED 10011
+#define SV_HELPTEXT_CLOSEDOCUMENT 10012
+
+#define SV_BUTTONTEXT_OK 10100
+#define SV_BUTTONTEXT_CANCEL 10101
+#define SV_BUTTONTEXT_YES 10102
+#define SV_BUTTONTEXT_NO 10103
+#define SV_BUTTONTEXT_RETRY 10104
+#define SV_BUTTONTEXT_HELP 10105
+#define SV_BUTTONTEXT_CLOSE SV_HELPTEXT_CLOSE
+#define SV_BUTTONTEXT_MORE 10107
+#define SV_BUTTONTEXT_IGNORE 10108
+#define SV_BUTTONTEXT_ABORT 10109
+#define SV_BUTTONTEXT_LESS 10110
+
+#define SV_STDTEXT_FIRST SV_STDTEXT_SERVICENOTAVAILABLE
+#define SV_STDTEXT_SERVICENOTAVAILABLE 10200
+#define SV_STDTEXT_DONTHINTAGAIN 10201
+#define SV_STDTEXT_DONTASKAGAIN 10202
+#define SV_STDTEXT_DONTWARNAGAIN 10203
+#define SV_STDTEXT_ABOUT 10204
+#define SV_STDTEXT_PREFERENCES 10205
+#define SV_MAC_SCREENNNAME 10206
+#define SV_STDTEXT_ALLFILETYPES 10207
+#define SV_STDTEXT_LAST SV_STDTEXT_ALLFILETYPES
+
+#define SV_ACCESSERROR_FIRST SV_ACCESSERROR_WRONG_VERSION
+#define SV_ACCESSERROR_WRONG_VERSION 10500
+#define SV_ACCESSERROR_BRIDGE_MSG 10501
+#define SV_ACCESSERROR_OK_CANCEL_MSG 10502
+#define SV_ACCESSERROR_MISSING_BRIDGE 10503
+#define SV_ACCESSERROR_FAULTY_JAVA 10504
+#define SV_ACCESSERROR_JAVA_MSG 10505
+#define SV_ACCESSERROR_MISSING_JAVA 10506
+#define SV_ACCESSERROR_JAVA_NOT_CONFIGURED 10507
+#define SV_ACCESSERROR_JAVA_DISABLED 10508
+#define SV_ACCESSERROR_TURNAROUND_MSG 10509
+#define SV_ACCESSERROR_LAST SV_ACCESSERROR_TURNAROUND_MSG
+
+#define SV_SHORTCUT_HELP 10600
+#define SV_SHORTCUT_CONTEXTHELP 10601
+#define SV_SHORTCUT_ACTIVEHELP 10602
+#define SV_SHORTCUT_DOCKUNDOCK 10603
+#define SV_SHORTCUT_NEXTSUBWINDOW 10604
+#define SV_SHORTCUT_PREVSUBWINDOW 10605
+#define SV_SHORTCUT_TODOCUMENT 10606
+#define SV_SHORTCUT_MENUBAR 10607
+#define SV_SHORTCUT_SPLITTER 10608
+
+#define SV_EDIT_WARNING_BOX 10650
+
+#define SV_FUNIT_STRINGS 10700
+
+#define SV_ICON_SIZE48_START 20000
+#define SV_ICON_SIZE32_START 21000
+#define SV_ICON_SIZE16_START 23000
+
+#define SV_ICON_LARGE_START 24000
+#define SV_ICON_SMALL_START 25000
+#define SV_ICON_LARGE_HC_START 26000
+#define SV_ICON_SMALL_HC_START 27000
+
+#define SV_ICON_ID_OFFICE 1
+#define SV_ICON_ID_TEXT 2
+#define SV_ICON_ID_TEXT_TEMPLATE 3
+#define SV_ICON_ID_SPREADSHEET 4
+#define SV_ICON_ID_SPREADSHEET_TEMPLATE 5
+#define SV_ICON_ID_DRAWING 6
+#define SV_ICON_ID_DRAWING_TEMPLATE 7
+#define SV_ICON_ID_PRESENTATION 8
+#define SV_ICON_ID_PRESENTATION_TEMPLATE 9
+#define SV_ICON_ID_PRESENTATION_COMPRESSED 10
+#define SV_ICON_ID_MASTER_DOCUMENT 11
+#define SV_ICON_ID_HTML_DOCUMENT 12
+#define SV_ICON_ID_CHART 13
+#define SV_ICON_ID_DATABASE 14
+#define SV_ICON_ID_FORMULA 15
+#define SV_ICON_ID_TEMPLATE 16
+#define SV_ICON_ID_MACRO 17
+#define SV_ICON_ID_PRINTERADMIN 501
+
+#define HID_PRINTDLG HID_VCL_START
+
+#endif // _SV_SVIDS_HRC
diff --git a/vcl/inc/vcl/symbol.hxx b/vcl/inc/vcl/symbol.hxx
new file mode 100644
index 000000000000..c7a745516856
--- /dev/null
+++ b/vcl/inc/vcl/symbol.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 _SV_SYMBOL_HXX
+#define _SV_SYMBOL_HXX
+
+#include <vcl/sv.h>
+
+// ----------------
+// - Symbol-Types -
+// ----------------
+
+// By changes you must also change: rsc/vclrsc.hxx
+typedef USHORT SymbolType;
+#define SYMBOL_DONTKNOW ((SymbolType)0)
+#define SYMBOL_IMAGE ((SymbolType)1)
+#define SYMBOL_ARROW_UP ((SymbolType)2)
+#define SYMBOL_ARROW_DOWN ((SymbolType)3)
+#define SYMBOL_ARROW_LEFT ((SymbolType)4)
+#define SYMBOL_ARROW_RIGHT ((SymbolType)5)
+#define SYMBOL_SPIN_UP ((SymbolType)6)
+#define SYMBOL_SPIN_DOWN ((SymbolType)7)
+#define SYMBOL_SPIN_LEFT ((SymbolType)8)
+#define SYMBOL_SPIN_RIGHT ((SymbolType)9)
+#define SYMBOL_FIRST ((SymbolType)10)
+#define SYMBOL_LAST ((SymbolType)11)
+#define SYMBOL_PREV ((SymbolType)12)
+#define SYMBOL_NEXT ((SymbolType)13)
+#define SYMBOL_PAGEUP ((SymbolType)14)
+#define SYMBOL_PAGEDOWN ((SymbolType)15)
+#define SYMBOL_PLAY ((SymbolType)16)
+#define SYMBOL_REVERSEPLAY ((SymbolType)17)
+#define SYMBOL_RECORD ((SymbolType)18)
+#define SYMBOL_STOP ((SymbolType)19)
+#define SYMBOL_PAUSE ((SymbolType)20)
+#define SYMBOL_WINDSTART ((SymbolType)21)
+#define SYMBOL_WINDEND ((SymbolType)22)
+#define SYMBOL_WINDBACKWARD ((SymbolType)23)
+#define SYMBOL_WINDFORWARD ((SymbolType)24)
+#define SYMBOL_CLOSE ((SymbolType)25)
+#define SYMBOL_ROLLUP ((SymbolType)26)
+#define SYMBOL_ROLLDOWN ((SymbolType)27)
+#define SYMBOL_CHECKMARK ((SymbolType)28)
+#define SYMBOL_RADIOCHECKMARK ((SymbolType)29)
+#define SYMBOL_SPIN_UPDOWN ((SymbolType)30)
+#define SYMBOL_FLOAT ((SymbolType)31)
+#define SYMBOL_DOCK ((SymbolType)32)
+#define SYMBOL_HIDE ((SymbolType)33)
+#define SYMBOL_HELP ((SymbolType)34)
+#define SYMBOL_OS2CLOSE ((SymbolType)35)
+#define SYMBOL_OS2FLOAT ((SymbolType)36)
+#define SYMBOL_OS2HIDE ((SymbolType)37)
+#define SYMBOL_MENU SYMBOL_SPIN_DOWN
+
+#define SYMBOL_NOSYMBOL (SYMBOL_DONTKNOW)
+
+#endif // _SV_SYMBOL_HXX
diff --git a/vcl/inc/vcl/syschild.hxx b/vcl/inc/vcl/syschild.hxx
new file mode 100644
index 000000000000..da4ffcd51a22
--- /dev/null
+++ b/vcl/inc/vcl/syschild.hxx
@@ -0,0 +1,67 @@
+/*************************************************************************
+ *
+ * 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_SYSCHILD_HXX
+#define _SV_SYSCHILD_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/window.hxx>
+
+struct SystemEnvData;
+struct SystemWindowData;
+
+// ---------------------
+// - SystemChildWindow -
+// ---------------------
+
+class VCL_DLLPUBLIC SystemChildWindow : public Window
+{
+private:
+ using Window::ImplInit;
+ SAL_DLLPRIVATE void ImplInitSysChild( Window* pParent, WinBits nStyle, SystemWindowData *pData, BOOL bShow = FALSE );
+
+ // Copy assignment is forbidden and not implemented.
+ SAL_DLLPRIVATE SystemChildWindow (const SystemChildWindow &);
+ SAL_DLLPRIVATE SystemChildWindow & operator= (const SystemChildWindow &);
+
+public:
+ SystemChildWindow( Window* pParent, WinBits nStyle = 0 );
+ // create a SystemChildWindow using the given SystemWindowData
+ SystemChildWindow( Window* pParent, WinBits nStyle, SystemWindowData *pData, BOOL bShow = TRUE );
+ SystemChildWindow( Window* pParent, const ResId& rResId );
+ ~SystemChildWindow();
+
+ const SystemEnvData* GetSystemData() const;
+
+ // per default systemchildwindows erase their background for better plugin support
+ // however, this might not always be required
+ void EnableEraseBackground( BOOL bEnable = TRUE );
+ BOOL IsEraseBackgroundEnabled();
+};
+
+#endif // _SV_SYSCHILD_HXX
diff --git a/vcl/inc/vcl/sysdata.hxx b/vcl/inc/vcl/sysdata.hxx
new file mode 100644
index 000000000000..1146f1b3b842
--- /dev/null
+++ b/vcl/inc/vcl/sysdata.hxx
@@ -0,0 +1,189 @@
+/*************************************************************************
+ *
+ * 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_SYSDATA_HXX
+#define _SV_SYSDATA_HXX
+
+#include <vector>
+
+#ifdef QUARTZ
+// predeclare the native classes to avoid header/include problems
+typedef struct CGContext *CGContextRef;
+typedef struct CGLayer *CGLayerRef;
+#ifdef __OBJC__
+@class NSView;
+#else
+class NSView;
+#endif
+#endif
+
+// -----------------
+// - SystemEnvData -
+// -----------------
+
+struct SystemEnvData
+{
+ unsigned long nSize; // size in bytes of this structure
+#if defined( WNT ) || defined( OS2 )
+ HWND hWnd; // the window hwnd
+#elif defined( QUARTZ )
+ NSView* pView; // the cocoa (NSView *) implementing this object
+#elif defined( UNX )
+ void* pDisplay; // the relevant display connection
+ long aWindow; // the window of the object
+ void* pSalFrame; // contains a salframe, if object has one
+ void* pWidget; // the corresponding widget
+ void* pVisual; // the visual in use
+ int nScreen; // the current screen of the window
+ int nDepth; // depth of said visual
+ long aColormap; // the colormap being used
+ void* pAppContext; // the application context in use
+ long aShellWindow; // the window of the frame's shell
+ void* pShellWidget; // the frame's shell widget
+#endif
+};
+
+#define SystemChildData SystemEnvData
+
+// --------------------
+// - SystemParentData -
+// --------------------
+
+struct SystemParentData
+{
+ unsigned long nSize; // size in bytes of this structure
+#if defined( WNT ) || defined( OS2 )
+ HWND hWnd; // the window hwnd
+#elif defined( QUARTZ )
+ NSView* pView; // the cocoa (NSView *) implementing this object
+#elif defined( UNX )
+ long aWindow; // the window of the object
+ bool bXEmbedSupport:1; // decides whether the object in question
+ // should support the XEmbed protocol
+#endif
+};
+
+// --------------------
+// - SystemMenuData -
+// --------------------
+
+struct SystemMenuData
+{
+ unsigned long nSize; // size in bytes of this structure
+#if defined( WNT )
+ HMENU hMenu; // the menu handle of the menu bar
+#elif defined( QUARTZ )
+ //not defined
+#elif defined( UNX )
+ long aMenu; // ???
+#endif
+};
+
+// --------------------
+// - SystemGraphicsData -
+// --------------------
+
+struct SystemGraphicsData
+{
+ unsigned long nSize; // size in bytes of this structure
+#if defined( WNT )
+ HDC hDC; // handle to a device context
+#elif defined( QUARTZ )
+ CGContextRef rCGContext; // QUARTZ graphic context
+#elif defined( UNX )
+ void* pDisplay; // the relevant display connection
+ long hDrawable; // a drawable
+ void* pVisual; // the visual in use
+ int nScreen; // the current screen of the drawable
+ int nDepth; // depth of said visual
+ long aColormap; // the colormap being used
+ void* pRenderFormat; // render format for drawable
+#endif
+};
+
+
+// --------------------
+// - SystemWindowData -
+// --------------------
+
+struct SystemWindowData
+{
+ unsigned long nSize; // size in bytes of this structure
+#if defined( WNT ) // meaningless on Windows
+#elif defined( QUARTZ ) // meaningless on Mac OS X / Quartz
+#elif defined( UNX )
+ void* pVisual; // the visual to be used
+#endif
+};
+
+
+// --------------------
+// - SystemGlyphData -
+// --------------------
+
+struct SystemGlyphData
+{
+ unsigned long index;
+ double x;
+ double y;
+};
+
+
+// --------------------
+// - SystemFontData -
+// --------------------
+
+struct SystemFontData
+{
+ unsigned long nSize; // size in bytes of this structure
+#if defined( WNT )
+ HFONT hFont; // native font object
+#elif defined( QUARTZ )
+ void* aATSUFontID; // native font object
+#elif defined( UNX )
+ void* nFontId; // native font id
+ int nFontFlags; // native font flags
+#endif
+ bool bFakeBold; // Does this font need faking the bold style
+ bool bFakeItalic; // Does this font need faking the italic style
+ bool bAntialias; // Should this font be antialiased
+ bool bVerticalCharacterType; // Is the font using vertical character type
+};
+
+// --------------------
+// - SystemTextLayoutData -
+// --------------------
+
+struct SystemTextLayoutData
+{
+ unsigned long nSize; // size in bytes of this structure
+ std::vector<SystemGlyphData> rGlyphData; // glyph data
+ int orientation; // Text orientation
+ SystemFontData aSysFontData; // Font data for the text layout
+};
+
+#endif // _SV_SYSDATA_HXX
diff --git a/vcl/inc/vcl/syswin.hxx b/vcl/inc/vcl/syswin.hxx
new file mode 100644
index 000000000000..b3a7d9b8775e
--- /dev/null
+++ b/vcl/inc/vcl/syswin.hxx
@@ -0,0 +1,281 @@
+/*************************************************************************
+ *
+ * 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_SYSWIN_HXX
+#define _SV_SYSWIN_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/window.hxx>
+
+class ModalDialog;
+class MenuBar;
+class TaskPaneList;
+
+// --------------
+// - Icon-Types -
+// --------------
+
+#define ICON_DEFAULT 0
+#define ICON_SO_DEFAULT 1
+#define ICON_TEXT_DOCUMENT 2
+#define ICON_TEXT_TEMPLATE 3
+#define ICON_SPREADSHEET_DOCUMENT 4
+#define ICON_SPREADSHEET_TEMPLATE 5
+#define ICON_DRAWING_DOCUMENT 6
+#define ICON_DRAWING_TEMPLATE 7
+#define ICON_PRESENTATION_DOCUMENT 8
+#define ICON_PRESENTATION_TEMPLATE 9
+#define ICON_PRESENTATION_COMPRESSED 10
+#define ICON_GLOBAL_DOCUMENT 11
+#define ICON_HTML_DOCUMENT 12
+#define ICON_CHART_DOCUMENT 13
+#define ICON_DATABASE_DOCUMENT 14
+#define ICON_MATH_DOCUMENT 15
+#define ICON_TEMPLATE 16
+#define ICON_MACROLIBRARY 17
+#define ICON_PLAYER 100
+#define ICON_SETUP 500
+
+// -------------------
+// - WindowStateData -
+// -------------------
+
+#define WINDOWSTATE_MASK_X ((ULONG)0x00000001)
+#define WINDOWSTATE_MASK_Y ((ULONG)0x00000002)
+#define WINDOWSTATE_MASK_WIDTH ((ULONG)0x00000004)
+#define WINDOWSTATE_MASK_HEIGHT ((ULONG)0x00000008)
+#define WINDOWSTATE_MASK_STATE ((ULONG)0x00000010)
+#define WINDOWSTATE_MASK_MINIMIZED ((ULONG)0x00000020)
+#define WINDOWSTATE_MASK_MAXIMIZED_X ((ULONG)0x00000100)
+#define WINDOWSTATE_MASK_MAXIMIZED_Y ((ULONG)0x00000200)
+#define WINDOWSTATE_MASK_MAXIMIZED_WIDTH ((ULONG)0x00000400)
+#define WINDOWSTATE_MASK_MAXIMIZED_HEIGHT ((ULONG)0x00000800)
+#define WINDOWSTATE_MASK_POS (WINDOWSTATE_MASK_X | WINDOWSTATE_MASK_Y)
+#define WINDOWSTATE_MASK_ALL (WINDOWSTATE_MASK_X | WINDOWSTATE_MASK_Y | WINDOWSTATE_MASK_WIDTH | WINDOWSTATE_MASK_HEIGHT | WINDOWSTATE_MASK_MAXIMIZED_X | WINDOWSTATE_MASK_MAXIMIZED_Y | WINDOWSTATE_MASK_MAXIMIZED_WIDTH | WINDOWSTATE_MASK_MAXIMIZED_HEIGHT | WINDOWSTATE_MASK_STATE | WINDOWSTATE_MASK_MINIMIZED)
+
+#define WINDOWSTATE_STATE_NORMAL ((ULONG)0x00000001)
+#define WINDOWSTATE_STATE_MINIMIZED ((ULONG)0x00000002)
+#define WINDOWSTATE_STATE_MAXIMIZED ((ULONG)0x00000004)
+#define WINDOWSTATE_STATE_ROLLUP ((ULONG)0x00000008)
+#define WINDOWSTATE_STATE_MAXIMIZED_HORZ ((ULONG)0x00000010)
+#define WINDOWSTATE_STATE_MAXIMIZED_VERT ((ULONG)0x00000020)
+
+class VCL_DLLPUBLIC WindowStateData
+{
+private:
+ sal_uInt32 mnValidMask;
+ int mnX;
+ int mnY;
+ unsigned int mnWidth;
+ unsigned int mnHeight;
+ int mnMaximizedX;
+ int mnMaximizedY;
+ unsigned int mnMaximizedWidth;
+ unsigned int mnMaximizedHeight;
+ sal_uInt32 mnState;
+
+public:
+ WindowStateData()
+ {
+ mnValidMask = mnX = mnY = mnWidth = mnHeight = mnState = 0;
+ mnMaximizedX = mnMaximizedY = mnMaximizedWidth = mnMaximizedHeight = 0;
+ }
+
+ void SetMask( ULONG nValidMask ) { mnValidMask = nValidMask; }
+ sal_uInt32 GetMask() const { return mnValidMask; }
+
+ void SetX( int nX ) { mnX = nX; }
+ int GetX() const { return mnX; }
+ void SetY( int nY ) { mnY = nY; }
+ int GetY() const { return mnY; }
+ void SetWidth( unsigned int nWidth ) { mnWidth = nWidth; }
+ unsigned int GetWidth() const { return mnWidth; }
+ void SetHeight( unsigned int nHeight ) { mnHeight = nHeight; }
+ unsigned int GetHeight() const { return mnHeight; }
+ void SetState( sal_uInt32 nState ) { mnState = nState; }
+ sal_uInt32 GetState() const { return mnState; }
+ void SetMaximizedX( int nRX ) { mnMaximizedX = nRX; }
+ int GetMaximizedX() const { return mnMaximizedX; }
+ void SetMaximizedY( int nRY ) { mnMaximizedY = nRY; }
+ int GetMaximizedY() const { return mnMaximizedY; }
+ void SetMaximizedWidth( unsigned int nRWidth ) { mnMaximizedWidth = nRWidth; }
+ unsigned int GetMaximizedWidth() const { return mnMaximizedWidth; }
+ void SetMaximizedHeight( unsigned int nRHeight ) { mnMaximizedHeight = nRHeight; }
+ unsigned int GetMaximizedHeight() const { return mnMaximizedHeight; }
+};
+
+// ----------------------
+// - SystemWindow-Types -
+// ----------------------
+
+#define MENUBAR_MODE_NORMAL ((USHORT)0)
+#define MENUBAR_MODE_HIDE ((USHORT)1)
+
+#define TITLE_BUTTON_DOCKING ((USHORT)1)
+#define TITLE_BUTTON_HIDE ((USHORT)2)
+#define TITLE_BUTTON_MENU ((USHORT)4)
+
+// ----------------
+// - SystemWindow -
+// ----------------
+
+
+class VCL_DLLPUBLIC SystemWindow : public Window
+{
+ friend class WorkWindow;
+ class ImplData;
+
+private:
+ MenuBar* mpMenuBar;
+ Size maOrgSize;
+ Size maRollUpOutSize;
+ Size maMinOutSize;
+ BOOL mbPined;
+ BOOL mbRollUp;
+ BOOL mbRollFunc;
+ BOOL mbDockBtn;
+ BOOL mbHideBtn;
+ BOOL mbSysChild;
+ USHORT mnMenuBarMode;
+ USHORT mnIcon;
+ ImplData* mpImplData;
+
+#if _SOLAR__PRIVATE
+public:
+ using Window::ImplIsInTaskPaneList;
+ SAL_DLLPRIVATE BOOL ImplIsInTaskPaneList( Window* pWin );
+#endif
+
+private:
+ // Default construction is forbidden and not implemented.
+ SystemWindow();
+
+ // Copy assignment is forbidden and not implemented.
+ SystemWindow (const SystemWindow &);
+ SystemWindow & operator= (const SystemWindow &);
+
+ SAL_DLLPRIVATE void ImplMoveToScreen( long& io_rX, long& io_rY, long i_nWidth, long i_nHeight, Window* i_pConfigureWin );
+
+protected:
+ // Single argument ctors shall be explicit.
+ explicit SystemWindow( WindowType nType );
+
+ void SetWindowStateData( const WindowStateData& rData );
+
+public:
+ ~SystemWindow();
+ virtual long Notify( NotifyEvent& rNEvt );
+ virtual long PreNotify( NotifyEvent& rNEvt );
+
+ virtual BOOL Close();
+ virtual void TitleButtonClick( USHORT nButton );
+ virtual void Pin();
+ virtual void Roll();
+ virtual void Resizing( Size& rSize );
+
+ void SetIcon( USHORT nIcon );
+ USHORT GetIcon() const { return mnIcon; }
+ // for systems like MacOSX which can display the URL a document is loaded from
+ // separately from the window title
+ void SetRepresentedURL( const rtl::OUString& );
+ const rtl::OUString& GetRepresentedURL() const;
+
+ void SetZLevel( BYTE nLevel );
+ BYTE GetZLevel() const;
+
+ void EnableSaveBackground( BOOL bSave = TRUE );
+ BOOL IsSaveBackgroundEnabled() const;
+
+ void ShowTitleButton( USHORT nButton, BOOL bVisible = TRUE );
+ BOOL IsTitleButtonVisible( USHORT nButton ) const;
+
+ void SetPin( BOOL bPin );
+ BOOL IsPined() const { return mbPined; }
+
+ void RollUp();
+ void RollDown();
+ BOOL IsRollUp() const { return mbRollUp; }
+
+ void SetRollUpOutputSizePixel( const Size& rSize ) { maRollUpOutSize = rSize; }
+ Size GetRollUpOutputSizePixel() const { return maRollUpOutSize; }
+
+ void SetMinOutputSizePixel( const Size& rSize );
+ const Size& GetMinOutputSizePixel() const { return maMinOutSize; }
+ void SetMaxOutputSizePixel( const Size& rSize );
+ const Size& GetMaxOutputSizePixel() const;
+ Size GetResizeOutputSizePixel() const;
+
+ void SetWindowState( const ByteString& rStr );
+ ByteString GetWindowState( ULONG nMask = WINDOWSTATE_MASK_ALL ) const;
+
+ void SetMenuBar( MenuBar* pMenuBar );
+ MenuBar* GetMenuBar() const { return mpMenuBar; }
+ void SetMenuBarMode( USHORT nMode );
+ USHORT GetMenuBarMode() const { return mnMenuBarMode; }
+
+ TaskPaneList* GetTaskPaneList();
+ void GetWindowStateData( WindowStateData& rData ) const;
+
+ /**
+ Returns the screen number the window is on
+
+ The screen number is counted the same way that
+ <code>Application::GetScreenPosSizePixel</code>,
+ <code>Application::GetWorkAreaPosSizePixel</code>,
+ <code>Application::GetScreenName</code>
+ and of course <code>SystemWindow::SetScreenNumber</code>
+ are counted in.
+
+ In case the window is positioned on multiple screens the
+ screen number returned will be of the screen containing the
+ upper left pixel of the frame area (that is of the client
+ area on system decorated windows, or the frame area of
+ undecorated resp. owner decorated windows.
+
+ @returns the screen number
+
+ @see SystemWindow::SetScreenNumber
+ */
+ unsigned int GetScreenNumber() const;
+ /**
+ Move the Window to a new screen. The same rules for
+ positioning apply as in <code>SystemWindow::GetScreenNumber</code>
+
+ The screen number is counted the same way that
+ <code>Application::GetScreenPosSizePixel</code>,
+ <code>Application::GetWorkAreaPosSizePixel</code>,
+ <code>Application::GetScreenName</code>
+ and of course <code>SystemWindow::GetScreenNumber</code>
+ are counted in.
+
+ @see GetScreenNumber
+ */
+ void SetScreenNumber( unsigned int nNewScreen );
+};
+
+#endif // _SV_SYSWIN_HXX
diff --git a/vcl/inc/vcl/tabctrl.hxx b/vcl/inc/vcl/tabctrl.hxx
new file mode 100644
index 000000000000..4c63b12f15fe
--- /dev/null
+++ b/vcl/inc/vcl/tabctrl.hxx
@@ -0,0 +1,219 @@
+/*************************************************************************
+ *
+ * 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_TABCTRL_HXX
+#define _SV_TABCTRL_HXX
+
+#include "vcl/sv.h"
+#include "vcl/dllapi.h"
+#include "vcl/ctrl.hxx"
+
+struct ImplTabItem;
+struct ImplTabCtrlData;
+class ImplTabItemList;
+class TabPage;
+class PushButton;
+class ListBox;
+
+// --------------------
+// - TabControl-Types -
+// --------------------
+
+#ifndef TAB_APPEND
+#define TAB_APPEND ((USHORT)0xFFFF)
+#define TAB_PAGE_NOTFOUND ((USHORT)0xFFFF)
+#endif /* !TAB_APPEND */
+
+// --------------
+// - TabControl -
+// --------------
+
+class VCL_DLLPUBLIC TabControl : public Control
+{
+private:
+ void* mpDummyPtr; // FIXME: remove before integration
+ ImplTabCtrlData* mpTabCtrlData;
+ long mnLastWidth;
+ long mnLastHeight;
+ long mnBtnSize;
+ long mnMaxPageWidth;
+ USHORT mnActPageId;
+ USHORT mnCurPageId;
+ USHORT mnFirstPagePos;
+ USHORT mnLastFirstPagePos;
+ BOOL mbFormat;
+ BOOL mbRestoreHelpId;
+ BOOL mbRestoreUnqId;
+ BOOL mbSingleLine;
+ BOOL mbScroll;
+ BOOL mbRestoreSmartId;
+ BOOL mbSmallInvalidate;
+ BOOL mbExtraSpace;
+ Link maActivateHdl;
+ Link maDeactivateHdl;
+
+ using Control::ImplInitSettings;
+ SAL_DLLPRIVATE void ImplInitSettings( BOOL bFont, BOOL bForeground, BOOL bBackground );
+ SAL_DLLPRIVATE ImplTabItem* ImplGetItem( USHORT nId ) const;
+ SAL_DLLPRIVATE void ImplScrollBtnsColor();
+ SAL_DLLPRIVATE void ImplSetScrollBtnsState();
+ SAL_DLLPRIVATE void ImplPosScrollBtns();
+ SAL_DLLPRIVATE Size ImplGetItemSize( ImplTabItem* pItem, long nMaxWidth );
+ SAL_DLLPRIVATE Rectangle ImplGetTabRect( USHORT nPos, long nWidth = -1, long nHeight = -1 );
+ SAL_DLLPRIVATE void ImplChangeTabPage( USHORT nId, USHORT nOldId );
+ SAL_DLLPRIVATE BOOL ImplPosCurTabPage();
+ SAL_DLLPRIVATE void ImplActivateTabPage( BOOL bNext );
+ SAL_DLLPRIVATE void ImplSetFirstPagePos( USHORT nPagePos );
+ SAL_DLLPRIVATE void ImplShowFocus();
+ SAL_DLLPRIVATE void ImplDrawItem( ImplTabItem* pItem, const Rectangle& rCurRect, bool bLayout = false, bool bFirstInGroup = false, bool bLastInGroup = false, bool bIsCurrentItem = false );
+ SAL_DLLPRIVATE void ImplPaint( const Rectangle& rRect, bool bLayout = false );
+ SAL_DLLPRIVATE void ImplFreeLayoutData();
+ SAL_DLLPRIVATE long ImplHandleKeyEvent( const KeyEvent& rKeyEvent );
+
+ DECL_DLLPRIVATE_LINK( ImplScrollBtnHdl, PushButton* pBtn );
+ DECL_DLLPRIVATE_LINK( ImplListBoxSelectHdl, ListBox* );
+ DECL_DLLPRIVATE_LINK( ImplWindowEventListener, VclSimpleEvent* );
+
+
+protected:
+ using Window::ImplInit;
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle );
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+
+ virtual void FillLayoutData() const;
+ virtual const Font& GetCanonicalFont( const StyleSettings& _rStyle ) const;
+ virtual const Color& GetCanonicalTextColor( const StyleSettings& _rStyle ) const;
+ SAL_DLLPRIVATE Rectangle* ImplFindPartRect( const Point& rPt );
+
+public:
+ TabControl( Window* pParent,
+ WinBits nStyle = WB_STDTABCONTROL );
+ TabControl( Window* pParent, const ResId& rResId );
+ ~TabControl();
+
+ virtual void MouseButtonDown( const MouseEvent& rMEvt );
+ virtual void KeyInput( const KeyEvent& rKEvt );
+ virtual void Paint( const Rectangle& rRect );
+ virtual void Resize();
+ virtual void GetFocus();
+ virtual void LoseFocus();
+ virtual void RequestHelp( const HelpEvent& rHEvt );
+ virtual void Command( const CommandEvent& rCEvt );
+ virtual long Notify( NotifyEvent& rNEvt );
+ virtual void StateChanged( StateChangedType nType );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+ virtual long PreNotify( NotifyEvent& rNEvt );
+
+ virtual void ActivatePage();
+ virtual long DeactivatePage();
+
+ virtual Size GetOptimalSize(WindowSizeType eType) const;
+ void SetMinimumSizePixel( const Size& );
+
+ void SetTabPageSizePixel( const Size& rSize );
+ Size GetTabPageSizePixel() const;
+
+ // pixel offset for the tab items, default is (0,0)
+ void SetItemsOffset( const Point& rOffs );
+ Point GetItemsOffset() const;
+
+ void InsertPage( const ResId& rResId,
+ USHORT nPos = TAB_APPEND );
+ void InsertPage( USHORT nPageId, const XubString& rText,
+ USHORT nPos = TAB_APPEND );
+ void RemovePage( USHORT nPageId );
+ void Clear();
+ void EnablePage( USHORT nPageId, bool bEnable = true );
+
+ USHORT GetPageCount() const;
+ USHORT GetPageId( USHORT nPos ) const;
+ USHORT GetPagePos( USHORT nPageId ) const;
+ USHORT GetPageId( const Point& rPos ) const;
+
+ void SetCurPageId( USHORT nPageId );
+ USHORT GetCurPageId() const;
+
+ void SetFirstPageId( USHORT nPageId );
+ USHORT GetFirstPageId() const { return GetPageId( mnFirstPagePos ); }
+
+ void SelectTabPage( USHORT nPageId );
+
+ void SetMaxPageWidth( long nMaxWidth ) { mnMaxPageWidth = nMaxWidth; }
+ long GetMaxPageWidth() const { return mnMaxPageWidth; }
+ void ResetMaxPageWidth() { SetMaxPageWidth( 0 ); }
+ BOOL IsMaxPageWidth() const { return mnMaxPageWidth != 0; }
+
+ void SetTabPage( USHORT nPageId, TabPage* pPage );
+ TabPage* GetTabPage( USHORT nPageId ) const;
+ USHORT GetTabPageResId( USHORT nPageId ) const;
+
+ void SetPageText( USHORT nPageId, const XubString& rText );
+ XubString GetPageText( USHORT nPageId ) const;
+
+ void SetHelpText( USHORT nPageId, const XubString& rText );
+ const XubString& GetHelpText( USHORT nPageId ) const;
+
+ void SetHelpId( USHORT nPageId, ULONG nHelpId );
+ ULONG GetHelpId( USHORT nPageId ) const;
+
+ void SetPageImage( USHORT nPageId, const Image& rImage );
+ const Image* GetPageImage( USHORT nPageId ) const;
+
+ void SetHelpText( const XubString& rText )
+ { Control::SetHelpText( rText ); }
+ const XubString& GetHelpText() const
+ { return Control::GetHelpText(); }
+
+ void SetHelpId( ULONG nId )
+ { Control::SetHelpId( nId ); }
+ ULONG GetHelpId() const
+ { return Control::GetHelpId(); }
+
+ void SetActivatePageHdl( const Link& rLink ) { maActivateHdl = rLink; }
+ const Link& GetActivatePageHdl() const { return maActivateHdl; }
+ void SetDeactivatePageHdl( const Link& rLink ) { maDeactivateHdl = rLink; }
+ const Link& GetDeactivatePageHdl() const { return maDeactivateHdl; }
+
+ // returns (control relative) bounding rectangle for the
+ // character at index nIndex relative to the text of page nPageId
+ using Control::GetCharacterBounds;
+ Rectangle GetCharacterBounds( USHORT nPageId, long nIndex ) const;
+
+ // returns the index relative to the text of page nPageId (also returned)
+ // at position rPoint (control relative)
+ using Control::GetIndexForPoint;
+ long GetIndexForPoint( const Point& rPoint, USHORT& rPageId ) const;
+
+ // returns the bounding rectangle of the union of tab page area and the
+ // corresponding tab
+ Rectangle GetTabPageBounds( USHORT nPageId ) const;
+
+ // returns the rectangle of the tab for page nPageId
+ Rectangle GetTabBounds( USHORT nPageId ) const;
+};
+
+#endif // _SV_TABCTRL_HXX
diff --git a/vcl/inc/vcl/tabdlg.hxx b/vcl/inc/vcl/tabdlg.hxx
new file mode 100644
index 000000000000..35543bb6aac0
--- /dev/null
+++ b/vcl/inc/vcl/tabdlg.hxx
@@ -0,0 +1,70 @@
+/*************************************************************************
+ *
+ * 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_TABDLG_HXX
+#define _SV_TABDLG_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/dialog.hxx>
+
+class FixedLine;
+class TabControl;
+
+// ----------------------
+// - TabDialog -
+// ----------------------
+
+class VCL_DLLPUBLIC TabDialog : public Dialog
+{
+private:
+ FixedLine* mpFixedLine;
+ Window* mpViewWindow;
+ WindowAlign meViewAlign;
+ BOOL mbPosControls;
+
+ SAL_DLLPRIVATE void ImplInitTabDialogData();
+ SAL_DLLPRIVATE void ImplPosControls();
+
+public:
+ TabDialog( Window* pParent,
+ WinBits nStyle = WB_STDTABDIALOG );
+ TabDialog( Window* pParent, const ResId& rResId );
+ ~TabDialog();
+
+ virtual void Resize();
+ virtual void StateChanged( StateChangedType nStateChange );
+
+ void AdjustLayout();
+
+ void SetViewWindow( Window* pWindow ) { mpViewWindow = pWindow; }
+ Window* GetViewWindow() const { return mpViewWindow; }
+ void SetViewAlign( WindowAlign eAlign ) { meViewAlign = eAlign; }
+ WindowAlign GetViewAlign() const { return meViewAlign; }
+};
+
+#endif // _SV_TABDLG_HXX
diff --git a/vcl/inc/vcl/tabpage.hxx b/vcl/inc/vcl/tabpage.hxx
new file mode 100644
index 000000000000..c653ccca5a30
--- /dev/null
+++ b/vcl/inc/vcl/tabpage.hxx
@@ -0,0 +1,62 @@
+/*************************************************************************
+ *
+ * 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_TABPAGE_HXX
+#define _SV_TABPAGE_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/window.hxx>
+
+// -----------
+// - TabPage -
+// -----------
+
+class VCL_DLLPUBLIC TabPage : public Window
+{
+private:
+ using Window::ImplInit;
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle );
+ SAL_DLLPRIVATE void ImplInitSettings();
+
+public:
+ TabPage( Window* pParent, WinBits nStyle = 0 );
+ TabPage( Window* pParent, const ResId& rResId );
+
+ virtual void Paint( const Rectangle& rRect );
+ virtual void Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG nFlags );
+
+ virtual void StateChanged( StateChangedType nStateChange );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+
+ virtual void ActivatePage();
+ virtual void DeactivatePage();
+
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > CreateAccessible();
+};
+
+#endif // _SV_TABPAGE_HXX
diff --git a/vcl/inc/vcl/taskpanelist.hxx b/vcl/inc/vcl/taskpanelist.hxx
new file mode 100644
index 000000000000..33d75d7e31bd
--- /dev/null
+++ b/vcl/inc/vcl/taskpanelist.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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_TASKPANELIST_HXX
+#define _SV_TASKPANELIST_HXX
+
+#include <vcl/dllapi.h>
+
+#include <vector>
+#include <vcl/window.hxx>
+
+class VCL_DLLPUBLIC TaskPaneList
+{
+ ::std::vector<Window *> mTaskPanes;
+ Window *FindNextPane( Window *pWindow, BOOL bForward = TRUE );
+ Window *FindNextFloat( Window *pWindow, BOOL bForward = TRUE );
+ Window *FindNextSplitter( Window *pWindow, BOOL bForward = TRUE );
+
+//#if 0 // _SOLAR__PRIVATE
+public:
+ BOOL IsInList( Window *pWindow );
+//#endif
+
+public:
+ TaskPaneList();
+ ~TaskPaneList();
+
+ void AddWindow( Window *pWindow );
+ void RemoveWindow( Window *pWindow );
+ BOOL HandleKeyEvent( KeyEvent aKeyEvent );
+};
+
+#endif
diff --git a/vcl/inc/vcl/textlayout.hxx b/vcl/inc/vcl/textlayout.hxx
new file mode 100644
index 000000000000..418e1aa8bf64
--- /dev/null
+++ b/vcl/inc/vcl/textlayout.hxx
@@ -0,0 +1,136 @@
+/*************************************************************************
+ *
+ * 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_TEXTLAYOUT_HXX
+#define VCL_TEXTLAYOUT_HXX
+
+#include "vcl/outdev.hxx"
+
+#include <tools/solar.h>
+#include <tools/string.hxx>
+
+#include <memory>
+
+class Control;
+
+//........................................................................
+namespace vcl
+{
+//........................................................................
+
+ //====================================================================
+ //= ITextLayout
+ //====================================================================
+ class SAL_NO_VTABLE ITextLayout
+ {
+ public:
+ virtual long GetTextWidth( const XubString& _rText, xub_StrLen _nStartIndex, xub_StrLen _nLength ) const = 0;
+ virtual void DrawText( const Point& _rStartPoint, const XubString& _rText, xub_StrLen _nStartIndex, xub_StrLen _nLength,
+ MetricVector* _pVector, String* _pDisplayText ) = 0;
+ virtual bool GetCaretPositions( const XubString& _rText, sal_Int32* _pCaretXArray, xub_StrLen _nStartIndex, xub_StrLen _nLength ) const = 0;
+ virtual xub_StrLen GetTextBreak( const XubString& _rText, long _nMaxTextWidth, xub_StrLen _nStartIndex, xub_StrLen _nLength ) const = 0;
+ virtual bool DecomposeTextRectAction() const = 0;
+ };
+
+ //====================================================================
+ //= DefaultTextLayout
+ //====================================================================
+ /** is an implementation of the ITextLayout interface which simply delegates its calls to the respective
+ methods of an OutputDevice instance, without any inbetween magic.
+ */
+ class DefaultTextLayout : public ITextLayout
+ {
+ public:
+ DefaultTextLayout( OutputDevice& _rTargetDevice )
+ :m_rTargetDevice( _rTargetDevice )
+ {
+ }
+ virtual ~DefaultTextLayout();
+
+ // ITextLayout overridables
+ virtual long GetTextWidth(
+ const XubString& _rText,
+ xub_StrLen _nStartIndex,
+ xub_StrLen _nLength
+ ) 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;
+
+ private:
+ OutputDevice& m_rTargetDevice;
+ };
+
+ //====================================================================
+ //= ControlTextRenderer
+ //====================================================================
+ class ReferenceDeviceTextLayout;
+ /** a class which allows rendering text of a Control onto a device, by taking into account the metrics of
+ a reference device.
+ */
+ class ControlTextRenderer
+ {
+ public:
+ ControlTextRenderer( const Control& _rControl, OutputDevice& _rTargetDevice, OutputDevice& _rReferenceDevice );
+ virtual ~ControlTextRenderer();
+
+ Rectangle DrawText( const Rectangle& _rRect,
+ const XubString& _rText, USHORT _nStyle = 0,
+ MetricVector* _pVector = NULL, String* _pDisplayText = NULL );
+
+ private:
+ ControlTextRenderer(); // never implemented
+ ControlTextRenderer( const ControlTextRenderer& ); // never implemented
+ ControlTextRenderer& operator=( const ControlTextRenderer& ); // never implemented
+
+ private:
+ ::std::auto_ptr< ReferenceDeviceTextLayout > m_pImpl;
+ };
+
+//........................................................................
+} // namespace vcl
+//........................................................................
+
+#endif // VCL_TEXTLAYOUT_HXX
diff --git a/vcl/inc/vcl/threadex.hxx b/vcl/inc/vcl/threadex.hxx
new file mode 100644
index 000000000000..1b48b5d63c9c
--- /dev/null
+++ b/vcl/inc/vcl/threadex.hxx
@@ -0,0 +1,288 @@
+/*************************************************************************
+ *
+ * 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 <osl/conditn.h>
+#include <osl/thread.h>
+#include <tools/link.hxx>
+#include <vcl/dllapi.h>
+
+#if ! defined(_CPPUHELPER_EXC_HLP_HXX_)
+#include "cppuhelper/exc_hlp.hxx"
+#endif
+#include "boost/optional.hpp"
+#include <memory>
+
+namespace vcl
+{
+ class VCL_DLLPUBLIC ThreadExecutor
+ {
+ oslThread m_aThread;
+ oslCondition m_aFinish;
+ long m_nReturn;
+
+ #ifdef THREADEX_IMPLEMENTATION
+ public:
+ SAL_DLLPRIVATE static void SAL_CALL worker( void* );
+ #endif
+ public:
+ ThreadExecutor();
+ virtual ~ThreadExecutor();
+
+ virtual long doIt() = 0;
+ long execute();
+ };
+
+ class VCL_DLLPUBLIC SolarThreadExecutor
+ {
+ oslCondition m_aStart;
+ oslCondition m_aFinish;
+ long m_nReturn;
+ bool m_bTimeout;
+
+ DECL_DLLPRIVATE_LINK( worker, void* );
+
+ public:
+ SolarThreadExecutor();
+ virtual ~SolarThreadExecutor();
+
+ virtual long doIt() = 0;
+ long execute() { return impl_execute( NULL ); }
+ // caution: timeout for getting the solar mutex, not for ending
+ // the operation of doIt(). If doIt actually gets called within
+ // the specified timeout, execute will only return after
+ // doIt() completed
+ long execute( const TimeValue& _rTimeout ) { return impl_execute( &_rTimeout ); }
+
+ public:
+ bool didTimeout() const { return m_bTimeout; }
+
+ private:
+ long impl_execute( const TimeValue* _pTimeout );
+ };
+
+namespace solarthread {
+
+/// @internal
+namespace detail {
+
+template <typename FuncT, typename ResultT>
+class GenericSolarThreadExecutor : public SolarThreadExecutor
+{
+public:
+ static ResultT exec( FuncT const& func )
+ {
+ typedef GenericSolarThreadExecutor<FuncT, ResultT> ExecutorT;
+ ::std::auto_ptr<ExecutorT> const pExecutor( new ExecutorT(func) );
+ pExecutor->execute();
+#if ! defined(EXCEPTIONS_OFF)
+ if (pExecutor->m_exc.hasValue())
+ ::cppu::throwException( pExecutor->m_exc );
+#endif
+ return *pExecutor->m_result;
+ }
+
+private:
+ explicit GenericSolarThreadExecutor( FuncT const& func )
+ : m_exc(), m_func(func), m_result() {}
+
+ virtual long doIt()
+ {
+#if defined(EXCEPTIONS_OFF)
+ m_result.reset( m_func() );
+#else
+ try {
+ m_result.reset( m_func() );
+ }
+ catch (::com::sun::star::uno::Exception &) {
+ // only UNO exceptions can be dispatched:
+ m_exc = ::cppu::getCaughtException();
+ }
+#endif
+ return 0;
+ }
+
+ ::com::sun::star::uno::Any m_exc;
+ FuncT const m_func;
+ // using boost::optional here omits the need that ResultT is default
+ // constructable:
+ ::boost::optional<ResultT> m_result;
+};
+
+template <typename FuncT>
+class GenericSolarThreadExecutor<FuncT, void> : public SolarThreadExecutor
+{
+public:
+ static void exec( FuncT const& func )
+ {
+ typedef GenericSolarThreadExecutor<FuncT, void> ExecutorT;
+ ::std::auto_ptr<ExecutorT> const pExecutor( new ExecutorT(func) );
+ pExecutor->execute();
+#if ! defined(EXCEPTIONS_OFF)
+ if (pExecutor->m_exc.hasValue())
+ ::cppu::throwException( pExecutor->m_exc );
+#endif
+ }
+
+private:
+ explicit GenericSolarThreadExecutor( FuncT const& func )
+ : m_exc(), m_func(func) {}
+
+ virtual long doIt()
+ {
+#if defined(EXCEPTIONS_OFF)
+ m_func();
+#else
+ try {
+ m_func();
+ }
+ catch (::com::sun::star::uno::Exception &) {
+ // only UNO exceptions can be dispatched:
+ m_exc = ::cppu::getCaughtException();
+ }
+#endif
+ return 0;
+ }
+
+ ::com::sun::star::uno::Any m_exc;
+ FuncT const m_func;
+};
+
+template <typename T>
+class copy_back_wrapper
+{
+public:
+ operator T *() const { return &m_holder->m_value; }
+ operator T &() const { return m_holder->m_value; }
+
+ explicit copy_back_wrapper( T * p ) : m_holder( new data_holder(p) ) {}
+
+ // no thread-safe counting needed here, because calling thread blocks
+ // until solar thread has executed the functor.
+ copy_back_wrapper( copy_back_wrapper<T> const& r )
+ : m_holder(r.m_holder) { ++m_holder->m_refCount; }
+ ~copy_back_wrapper() {
+ --m_holder->m_refCount;
+ if (m_holder->m_refCount == 0) {
+ delete m_holder;
+ }
+ }
+private:
+ struct data_holder {
+ T m_value;
+ T * const m_ptr;
+ sal_Int32 m_refCount;
+ data_holder( T * p ) : m_value(*p), m_ptr(p), m_refCount(1) {}
+ ~data_holder() { *m_ptr = m_value; }
+ };
+ data_holder * const m_holder;
+};
+
+} // namespace detail
+
+/** Makes a copy back reference wrapper to be used for inout parameters.
+ Only use for syncExecute(), the returned wrapper relies on its
+ implemenation, i.e. the function object is stored in free store.
+ Type T needs to be copy constructable assignable.
+
+ @see syncExecute()
+ @param r reference to a stack variable
+ @return reference wrapper
+*/
+template <typename T>
+inline detail::copy_back_wrapper<T> inout_by_ref( T & r )
+{
+ return detail::copy_back_wrapper<T>(&r);
+}
+
+/** Makes a copy back ptr wrapper to be used for inout parameters.
+ Only use for syncExecute(), the returned wrapper relies on its
+ implemenation, i.e. the function object is stored in free store.
+ Type T needs to be copy constructable assignable.
+
+ @see syncExecute()
+ @param p pointer to a stack variable
+ @return ptr wrapper
+*/
+template <typename T>
+inline detail::copy_back_wrapper<T> inout_by_ptr( T * p )
+{
+ return detail::copy_back_wrapper<T>(p);
+}
+
+/** This function will execute the passed functor synchronously in the
+ solar thread, thus the calling thread will (eventually) be blocked until
+ the functor has been called.
+ Any UNO exception that came up calling the functor in the solar thread
+ will be caught and rethrown in the calling thread. Any non-UNO
+ exception needs to be handled by the called functor.
+ The result type of this function needs to be default constructable.
+ Please keep in mind not to pass addresses to stack variables
+ (e.g. for out parameters) to foreign threads, use inout_by_ref()
+ for this purpose. For in parameters, this may not affect you, because
+ the functor object is copy constructed into free store. This way
+ you must not use boost::cref()/boost::ref() or similar for objects on
+ your thread's stack.
+ Use inout_by_ref() or inout_by_ptr() for this purpose, e.g.
+
+ <pre>
+ using namespace vcl::solarthread;
+
+ long n = 3;
+ // calling foo( long & r ):
+ syncExecute( boost::bind( &foo, inout_by_ref(n) ) );
+ // calling foo( long * p ):
+ syncExecute( boost::bind( &foo, inout_by_ptr(&n) ) );
+
+ char const* pc = "default";
+ // calling foo( char const** ppc ):
+ syncExecute( boost::bind( &foo, inout_by_ptr(&pc) ) );
+ // calling foo( char const*& rpc ):
+ syncExecute( boost::bind( &foo, inout_by_ref(pc) ) );
+ </pre>
+
+ @tpl ResultT result type, defaults to FuncT::result_type to seamlessly
+ support mem_fn and bind
+ @tpl FuncT functor type, let your compiler deduce this type
+ @param func functor object to be executed in solar thread
+ @return return value of functor
+*/
+template <typename ResultT, typename FuncT>
+inline ResultT syncExecute( FuncT const& func )
+{
+ return detail::GenericSolarThreadExecutor<FuncT, ResultT>::exec(func);
+}
+
+template <typename FuncT>
+inline typename FuncT::result_type syncExecute( FuncT const& func )
+{
+ return detail::GenericSolarThreadExecutor<
+ FuncT, typename FuncT::result_type>::exec(func);
+}
+
+} // namespace solarthread
+} // namespace vcl
+
diff --git a/vcl/inc/vcl/timer.hxx b/vcl/inc/vcl/timer.hxx
new file mode 100644
index 000000000000..bb325c118844
--- /dev/null
+++ b/vcl/inc/vcl/timer.hxx
@@ -0,0 +1,89 @@
+/*************************************************************************
+ *
+ * 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_TIMER_HXX
+#define _SV_TIMER_HXX
+
+#include <tools/link.hxx>
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+
+struct ImplTimerData;
+struct ImplSVData;
+
+// ---------
+// - Timer -
+// ---------
+
+class VCL_DLLPUBLIC Timer
+{
+protected:
+ ImplTimerData* mpTimerData;
+ ULONG mnTimeout;
+ BOOL mbActive;
+ BOOL mbAuto;
+ Link maTimeoutHdl;
+
+public:
+ Timer();
+ Timer( const Timer& rTimer );
+ virtual ~Timer();
+
+ virtual void Timeout();
+
+ void Start();
+ void Stop();
+
+ void SetTimeout( ULONG nTimeout );
+ ULONG GetTimeout() const { return mnTimeout; }
+ BOOL IsActive() const { return mbActive; }
+
+ void SetTimeoutHdl( const Link& rLink ) { maTimeoutHdl = rLink; }
+ const Link& GetTimeoutHdl() const { return maTimeoutHdl; }
+
+ Timer& operator=( const Timer& rTimer );
+
+// #ifdef _SOLAR__PRIVATE
+ static void ImplDeInitTimer();
+ static void ImplTimerCallbackProc();
+// #endif
+};
+
+// -------------
+// - AutoTimer -
+// -------------
+
+class VCL_DLLPUBLIC AutoTimer : public Timer
+{
+public:
+ AutoTimer();
+ AutoTimer( const AutoTimer& rTimer );
+
+ AutoTimer& operator=( const AutoTimer& rTimer );
+};
+
+#endif // _SV_TIMER_HXX
diff --git a/vcl/inc/vcl/toolbox.h b/vcl/inc/vcl/toolbox.h
new file mode 100644
index 000000000000..33e4e8d2e013
--- /dev/null
+++ b/vcl/inc/vcl/toolbox.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_TOOLBOX_H
+#define _SV_TOOLBOX_H
+
+#include <tools/gen.hxx>
+#include <tools/string.hxx>
+#include <vcl/sv.h>
+#include <vcl/image.hxx>
+#include <vcl/toolbox.hxx>
+#include <vcl/controllayout.hxx>
+#include <vcl/ImageListProvider.hxx>
+
+#include <vector>
+
+#define TB_DROPDOWNARROWWIDTH 11
+
+#define TB_MENUBUTTON_SIZE 12
+#define TB_MENUBUTTON_OFFSET 2
+
+#define TB_SMALLIMAGESIZE 16
+
+#define TB_LARGEIMAGESIZE 26
+#define TB_LARGEIMAGESIZE_INDUSTRIAL 24
+#define TB_LARGEIMAGESIZE_CRYSTAL 22
+#define TB_LARGEIMAGESIZE_OXYGEN 22
+
+class Window;
+
+// ----------------
+// - ImplToolItem -
+// ----------------
+
+struct ImplToolItem
+{
+ Window* mpWindow;
+ void* mpUserData;
+ Image maImage;
+ Image maHighImage;
+ long mnImageAngle;
+ bool mbMirrorMode;
+ XubString maText;
+ XubString maQuickHelpText;
+ XubString maHelpText;
+ String maCommandStr;
+ ULONG mnHelpId;
+ Rectangle maRect;
+ Rectangle maCalcRect;
+ // the overall horizontal item size, including one or more of [image size + textlength + dropdown arrow]
+ Size maItemSize;
+ long mnSepSize;
+ long mnDropDownArrowWidth;
+ ToolBoxItemType meType;
+ ToolBoxItemBits mnBits;
+ TriState meState;
+ USHORT mnId;
+ BOOL mbEnabled:1,
+ mbVisible:1,
+ mbEmptyBtn:1,
+ mbShowWindow:1,
+ mbBreak:1,
+ mbVisibleText:1; // indicates if text will definitely be drawn, influences dropdown pos
+
+ ImplToolItem();
+ ImplToolItem( USHORT nItemId, const Image& rImage,
+ ToolBoxItemBits nItemBits );
+ ImplToolItem( USHORT nItemId, const XubString& rTxt,
+ ToolBoxItemBits nItemBits );
+ ImplToolItem( USHORT nItemId, const Image& rImage,
+ const XubString& rTxt,
+ ToolBoxItemBits nItemBits );
+ ~ImplToolItem();
+
+ ImplToolItem( const ImplToolItem& );
+ ImplToolItem& operator=(const ImplToolItem&);
+
+ // returns the size of a item, taking toolbox orientation into account
+ // the default size is the precomputed size for standard items
+ // ie those that are just ordinary buttons (no windows or text etc.)
+ // bCheckMaxWidth indicates that item windows must not exceed maxWidth in which case they will be painted as buttons
+ Size GetSize( BOOL bHorz, BOOL bCheckMaxWidth, long maxWidth, const Size& rDefaultSize );
+
+ // only useful for buttons: returns if the text or image part or both can be drawn according to current button drawing style
+ void DetermineButtonDrawStyle( ButtonType eButtonType, BOOL& rbImage, BOOL& rbText ) const;
+
+ // returns the rectangle which contains the drop down arrow
+ // or an empty rect if there is none
+ // bHorz denotes the toolbox alignment
+ Rectangle GetDropDownRect( BOOL bHorz ) const;
+
+ // returns TRUE if the toolbar item is currently clipped, which can happen for docked toolbars
+ BOOL IsClipped() const;
+};
+
+namespace vcl
+{
+
+struct ToolBoxLayoutData : public ControlLayoutData
+{
+ std::vector< USHORT > m_aLineItemIds;
+ std::vector< USHORT > m_aLineItemPositions;
+};
+
+
+} /* namespace vcl */
+
+
+struct ImplToolBoxPrivateData
+{
+ vcl::ToolBoxLayoutData* m_pLayoutData;
+ std::vector< ImplToolItem > m_aItems;
+
+ ImplToolBoxPrivateData();
+ ~ImplToolBoxPrivateData();
+
+ void ImplClearLayoutData() { delete m_pLayoutData; m_pLayoutData = NULL; }
+
+ // called when dropdown items are clicked
+ Link maDropdownClickHdl;
+ Timer maDropdownTimer; // for opening dropdown items on "long click"
+
+ // large or small buttons ?
+ ToolBoxButtonSize meButtonSize;
+
+ // the optional custom menu
+ PopupMenu* mpMenu;
+ USHORT maMenuType;
+ ULONG mnEventId;
+
+ // called when menu button is clicked and before the popup menu is executed
+ Link maMenuButtonHdl;
+
+ // a dummy item representing the custom menu button
+ ImplToolItem maMenubuttonItem;
+ long mnMenuButtonWidth;
+
+ Wallpaper maDisplayBackground;
+
+ // support for highcontrast
+ vcl::IImageListProvider* mpImageListProvider;
+ vcl::ImageListType meImageListType;
+
+ BOOL mbIsLocked:1, // keeps last lock state from ImplDockingWindowWrapper
+ mbAssumeDocked:1, // only used during calculations to override current floating/popup mode
+ mbAssumeFloating:1,
+ mbAssumePopupMode:1,
+ mbKeyInputDisabled:1, // no KEY input if all items disabled, closing/docking will be allowed though
+ mbIsPaintLocked:1, // don't allow paints
+ mbMenubuttonSelected:1, // menu button is highlighted
+ mbPageScroll:1, // determines if we scroll a page at a time
+ mbNativeButtons:1, // system supports native toolbar buttons
+ mbWillUsePopupMode:1, // this toolbox will be opened in popup mode
+ mbDropDownByKeyboard:1; // tells whether a dropdown was started by key input
+};
+
+
+#endif // _SV_TOOLBOX_H
diff --git a/vcl/inc/vcl/toolbox.hxx b/vcl/inc/vcl/toolbox.hxx
new file mode 100644
index 000000000000..5cc102842dc3
--- /dev/null
+++ b/vcl/inc/vcl/toolbox.hxx
@@ -0,0 +1,682 @@
+/*************************************************************************
+ *
+ * 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_TOOLBOX_HXX
+#define _SV_TOOLBOX_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/dockwin.hxx>
+#include <vcl/image.hxx>
+#include <vcl/timer.hxx>
+#include <vcl/virdev.hxx>
+
+class UserDrawEvent;
+
+struct ImplToolItem;
+struct ImplToolSizeArray;
+struct ImplToolSize;
+struct ImplToolBoxPrivateData;
+class ImplTrackRect;
+class PopupMenu;
+
+namespace vcl
+{
+ class IImageListProvider;
+}
+
+// -------------------------
+// - ToolBoxCustomizeEvent -
+// -------------------------
+
+#define TOOLBOX_CUSTOMIZE_RESIZE ((USHORT)0xFFFE)
+
+class VCL_DLLPUBLIC ToolBoxCustomizeEvent
+{
+private:
+ ToolBox* mpTargetBox;
+ void* mpData;
+ USHORT mnIdFrom;
+ USHORT mnPosTo;
+
+public:
+ ToolBoxCustomizeEvent();
+ ToolBoxCustomizeEvent( ToolBox* pDropBox,
+ USHORT nId, USHORT nPos = 0,
+ void* pUserData = NULL );
+
+ ToolBox* GetTargetBox() const { return mpTargetBox; }
+ USHORT GetTargetPos() const { return mnPosTo; }
+ USHORT GetSourceId() const { return mnIdFrom; }
+ void* GetData() const { return mpData; }
+ BOOL IsResized() const;
+};
+
+inline ToolBoxCustomizeEvent::ToolBoxCustomizeEvent()
+{
+ mpTargetBox = NULL;
+ mnIdFrom = 0;
+ mnPosTo = 0;
+ mpData = NULL;
+}
+
+inline ToolBoxCustomizeEvent::ToolBoxCustomizeEvent( ToolBox* pDropBox,
+ USHORT nId, USHORT nPos,
+ void* pUserData )
+{
+ mpTargetBox = pDropBox;
+ mnIdFrom = nId;
+ mnPosTo = nPos;
+ mpData = pUserData;
+}
+
+inline BOOL ToolBoxCustomizeEvent::IsResized() const
+{
+ if ( mnPosTo == TOOLBOX_CUSTOMIZE_RESIZE )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+// -------------------
+// - ToolBoxItemBits -
+// -------------------
+
+typedef USHORT ToolBoxItemBits;
+
+// --------------------------
+// - Bits fuer ToolBoxItems -
+// --------------------------
+
+// By changes you must also change: rsc/vclrsc.hxx
+#define TIB_CHECKABLE ((ToolBoxItemBits)0x0001)
+#define TIB_RADIOCHECK ((ToolBoxItemBits)0x0002)
+#define TIB_AUTOCHECK ((ToolBoxItemBits)0x0004)
+#define TIB_LEFT ((ToolBoxItemBits)0x0008)
+#define TIB_AUTOSIZE ((ToolBoxItemBits)0x0010)
+#define TIB_DROPDOWN ((ToolBoxItemBits)0x0020)
+#define TIB_REPEAT ((ToolBoxItemBits)0x0040)
+#define TIB_DROPDOWNONLY ((ToolBoxItemBits)0x0080 | TIB_DROPDOWN) // this button has only drop down functionality
+#define TIB_TEXT_ONLY ((ToolBoxItemBits)0x0100)
+#define TIB_ICON_ONLY ((ToolBoxItemBits)0x0200)
+#define TIB_TEXTICON ((ToolBoxItemBits) TIB_TEXT_ONLY | TIB_ICON_ONLY )
+
+// -----------------
+// - ToolBox-Types -
+// -----------------
+
+#define TOOLBOX_STYLE_OUTBUTTON ((USHORT)0x0001)
+#define TOOLBOX_STYLE_HANDPOINTER ((USHORT)0x0002)
+#define TOOLBOX_STYLE_FLAT ((USHORT)0x0004)
+
+#define TOOLBOX_APPEND ((USHORT)0xFFFF)
+#define TOOLBOX_ITEM_NOTFOUND ((USHORT)0xFFFF)
+
+// item ids in the custom menu may not exceed this constant
+#define TOOLBOX_MENUITEM_START ((USHORT)0xE000)
+
+// defines for the menubutton
+#define TOOLBOX_MENUTYPE_NONE ((USHORT)0x0000) // no menu at all, scrolling by spin buttons
+#define TOOLBOX_MENUTYPE_CLIPPEDITEMS ((USHORT)0x0001) // menu will contain "more" indicator
+#define TOOLBOX_MENUTYPE_CUSTOMIZE ((USHORT)0x0002) // menu will contain "customization" and "more" indicator
+
+// By changes you must also change: rsc/vclrsc.hxx
+enum ButtonType { BUTTON_SYMBOL, BUTTON_TEXT, BUTTON_SYMBOLTEXT };
+
+// By changes you must also change: rsc/vclrsc.hxx
+enum ToolBoxItemType { TOOLBOXITEM_DONTKNOW, TOOLBOXITEM_BUTTON,
+ TOOLBOXITEM_SPACE, TOOLBOXITEM_SEPARATOR,
+ TOOLBOXITEM_BREAK };
+
+// small or large force an exact toolbox size for proper alignemnt
+// dontcare will let the toolbox decide about its size
+enum ToolBoxButtonSize { TOOLBOX_BUTTONSIZE_DONTCARE, TOOLBOX_BUTTONSIZE_SMALL, TOOLBOX_BUTTONSIZE_LARGE };
+
+// used for internal sizing calculations
+enum FloatingSizeMode { FSMODE_AUTO, FSMODE_FAVOURWIDTH, FSMODE_FAVOURHEIGHT };
+
+// -----------
+// - ToolBox -
+// -----------
+
+class VCL_DLLPUBLIC ToolBox : public DockingWindow
+{
+ friend class FloatingWindow;
+ friend class ImplTBDragMgr;
+
+private:
+ ImplToolBoxPrivateData* mpData;
+ VirtualDevice* mpBtnDev; // TODO: remove unused member
+ ImplToolSizeArray* mpFloatSizeAry;
+ XubString maCvtStr;
+ XubString maNextToolBoxStr;
+ ImageList maImageList;
+ Timer maTimer;
+ Rectangle maUpperRect;
+ Rectangle maLowerRect;
+ Rectangle maNextToolRect;
+ Rectangle maOutDockRect;
+ Rectangle maInDockRect;
+ Rectangle maPaintRect;
+ FloatingWindow* mpFloatWin;
+ USHORT mnKeyModifier;
+ long mnDX;
+ long mnDY;
+ long mnMaxItemWidth; // max item width
+ long mnMaxItemHeight; // max item height (for standard items)
+ long mnWinHeight; // max window height (for window items)
+ long mnBorderX; // custom border
+ long mnBorderY;
+ long mnLeftBorder; // inner border
+ long mnTopBorder;
+ long mnRightBorder;
+ long mnBottomBorder;
+ long mnLastResizeDY;
+ long mnActivateCount;
+ USHORT mnLastFocusItemId;
+ USHORT mnFocusPos;
+ USHORT mnOutStyle;
+ USHORT mnHighItemId;
+ USHORT mnCurItemId;
+ USHORT mnDownItemId;
+ USHORT mnCurPos;
+ USHORT mnLines; // total number of toolbox lines
+ USHORT mnCurLine; // the currently visible line
+ USHORT mnCurLines; // number of lines due to line breaking
+ USHORT mnVisLines; // number of visible lines (for scrolling)
+ USHORT mnFloatLines; // number of lines during floating mode
+ USHORT mnDockLines;
+ USHORT mnConfigItem;
+ USHORT mnMouseClicks;
+ USHORT mnMouseModifier;
+ unsigned int mbDrag:1,
+ mbSelection:1,
+ mbCommandDrag:1,
+ mbUpper:1,
+ mbLower:1,
+ mbNextTool:1,
+ mbIn:1,
+ mbCalc:1,
+ mbFormat:1,
+ mbFullPaint:1,
+ mbHorz:1,
+ mbScroll:1,
+ mbLastFloatMode:1,
+ mbCustomize:1,
+ mbCustomizeMode:1,
+ mbDragging:1,
+ mbHideStatusText:1,
+ mbMenuStrings:1,
+ mbIsShift:1,
+ mbIsKeyEvent:1,
+ mbChangingHighlight:1;
+ WindowAlign meAlign;
+ WindowAlign meDockAlign;
+ ButtonType meButtonType;
+ PointerStyle meLastStyle;
+ WinBits mnWinStyle;
+ Link maClickHdl;
+ Link maDoubleClickHdl;
+ Link maActivateHdl;
+ Link maDeactivateHdl;
+ Link maHighlightHdl;
+ Link maSelectHdl;
+ Link maNextToolBoxHdl;
+
+ public:
+ using Window::ImplInit;
+ private:
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle );
+// #if 0 // _SOLAR__PRIVATE
+ using DockingWindow::ImplInitSettings;
+// #endif
+ SAL_DLLPRIVATE void ImplInitSettings( BOOL bFont, BOOL bForeground, BOOL bBackground );
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+ SAL_DLLPRIVATE ImplToolItem* ImplGetItem( USHORT nId ) const;
+ SAL_DLLPRIVATE BOOL ImplCalcItem();
+ SAL_DLLPRIVATE USHORT ImplCalcBreaks( long nWidth, long* pMaxLineWidth, BOOL bCalcHorz );
+ SAL_DLLPRIVATE void ImplFormat( BOOL bResize = FALSE );
+ SAL_DLLPRIVATE void ImplDrawSpin( BOOL bUpperIn, BOOL bLowerIn );
+ SAL_DLLPRIVATE void ImplDrawNext( BOOL bIn );
+ SAL_DLLPRIVATE void ImplDrawItem( USHORT nPos, BOOL bHighlight = FALSE, BOOL bPaint = FALSE, BOOL bLayout = FALSE );
+ using Window::ImplInvalidate;
+ SAL_DLLPRIVATE void ImplInvalidate( BOOL bNewCalc = FALSE, BOOL bFullPaint = FALSE );
+ SAL_DLLPRIVATE void ImplUpdateItem( USHORT nIndex = 0xFFFF );
+ SAL_DLLPRIVATE void ImplStartCustomizeMode();
+ SAL_DLLPRIVATE void ImplEndCustomizeMode();
+ SAL_DLLPRIVATE const XubString& ImplConvertMenuString( const XubString& rStr );
+ SAL_DLLPRIVATE BOOL ImplHandleMouseMove( const MouseEvent& rMEvt, BOOL bRepeat = FALSE );
+ SAL_DLLPRIVATE BOOL ImplHandleMouseButtonUp( const MouseEvent& rMEvt, BOOL bCancel = FALSE );
+ SAL_DLLPRIVATE void ImplChangeHighlight( ImplToolItem* pItem, BOOL bNoGrabFocus = FALSE );
+ SAL_DLLPRIVATE BOOL ImplChangeHighlightUpDn( BOOL bUp, BOOL bNoCycle = FALSE );
+ SAL_DLLPRIVATE USHORT ImplGetItemLine( ImplToolItem* pCurrentItem );
+ SAL_DLLPRIVATE ImplToolItem* ImplGetFirstValidItem( USHORT nLine );
+ SAL_DLLPRIVATE ImplToolItem* ImplGetLastValidItem( USHORT nLine );
+ SAL_DLLPRIVATE BOOL ImplOpenItem( KeyCode aKeyCode );
+ SAL_DLLPRIVATE BOOL ImplActivateItem( KeyCode aKeyCode );
+ SAL_DLLPRIVATE void ImplShowFocus();
+ SAL_DLLPRIVATE void ImplHideFocus();
+ SAL_DLLPRIVATE void ImplUpdateInputEnable();
+ SAL_DLLPRIVATE void ImplFillLayoutData() const;
+ SAL_DLLPRIVATE void ImplUpdateCustomMenu();
+ SAL_DLLPRIVATE BOOL ImplHasClippedItems();
+ SAL_DLLPRIVATE Point ImplGetPopupPosition( const Rectangle& rRect, const Size& rSize ) const;
+ SAL_DLLPRIVATE void ImplExecuteCustomMenu();
+ SAL_DLLPRIVATE BOOL ImplIsFloatingMode() const;
+ SAL_DLLPRIVATE BOOL ImplIsInPopupMode() const;
+ SAL_DLLPRIVATE const XubString& ImplGetHelpText( USHORT nItemId ) const;
+ SAL_DLLPRIVATE Size ImplGetOptimalFloatingSize( FloatingSizeMode eMode );
+ SAL_DLLPRIVATE BOOL ImplHasExternalMenubutton();
+ SAL_DLLPRIVATE void ImplDrawFloatwinBorder( ImplToolItem* pItem );
+
+ DECL_DLLPRIVATE_LINK( ImplCallExecuteCustomMenu, void* );
+ DECL_DLLPRIVATE_LINK( ImplUpdateHdl, void* );
+ DECL_DLLPRIVATE_LINK( ImplResetAutoSizeTriesHdl, void* );
+ DECL_DLLPRIVATE_LINK( ImplCustomMenuListener, VclMenuEvent* );
+ DECL_DLLPRIVATE_LINK( ImplDropdownLongClickHdl, ToolBox* );
+
+//#if 0 // _SOLAR__PRIVATE
+ // Copy assignment is forbidden and not implemented.
+ SAL_DLLPRIVATE ToolBox (const ToolBox &);
+ SAL_DLLPRIVATE ToolBox& operator= (const ToolBox &);
+
+ SAL_DLLPRIVATE void ImplUpdateImageList(); // called if StateChanged
+public:
+ SAL_DLLPRIVATE void ImplFloatControl( BOOL bStart, FloatingWindow* pWindow = NULL );
+ SAL_DLLPRIVATE void ImplDisableFlatButtons();
+
+ static SAL_DLLPRIVATE int ImplGetDragWidth( ToolBox* pThis );
+ static SAL_DLLPRIVATE void ImplUpdateDragArea( ToolBox *pThis );
+ static SAL_DLLPRIVATE void ImplCalcBorder( WindowAlign eAlign, long& rLeft, long& rTop,
+ long& rRight, long& rBottom, const ToolBox *pThis );
+ static SAL_DLLPRIVATE void ImplDrawGrip( ToolBox* pThis );
+ static SAL_DLLPRIVATE void ImplDrawGradientBackground( ToolBox* pThis, ImplDockingWindowWrapper *pWrapper );
+ static SAL_DLLPRIVATE BOOL ImplDrawNativeBackground( ToolBox* pThis, const Region &rRegion );
+ static SAL_DLLPRIVATE void ImplDrawTransparentBackground( ToolBox* pThis, const Region &rRegion );
+ static SAL_DLLPRIVATE void ImplDrawConstantBackground( ToolBox* pThis, const Region &rRegion, BOOL bIsInPopupMode );
+ static SAL_DLLPRIVATE void ImplDrawBackground( ToolBox* pThis, const Rectangle &rRect );
+ static SAL_DLLPRIVATE void ImplErase( ToolBox* pThis, const Rectangle &rRect, BOOL bHighlight = FALSE, BOOL bHasOpenPopup = FALSE );
+ static SAL_DLLPRIVATE void ImplDrawBorder( ToolBox* pWin );
+ static SAL_DLLPRIVATE const ImplToolItem *ImplGetFirstClippedItem( const ToolBox* pThis );
+ static SAL_DLLPRIVATE Size ImplCalcSize( const ToolBox* pThis, USHORT nCalcLines, USHORT nCalcMode = 0 );
+ static SAL_DLLPRIVATE void ImplCalcFloatSizes( ToolBox* pThis );
+ static SAL_DLLPRIVATE Size ImplCalcFloatSize( ToolBox* pThis, USHORT& rLines );
+ static SAL_DLLPRIVATE void ImplCalcMinMaxFloatSize( ToolBox* pThis, Size& rMinSize, Size& rMaxSize );
+ static SAL_DLLPRIVATE void ImplSetMinMaxFloatSize( ToolBox *pThis );
+ static SAL_DLLPRIVATE USHORT ImplCalcLines( ToolBox* pThis, long nToolSize );
+ static SAL_DLLPRIVATE USHORT ImplTestLineSize( ToolBox* pThis, const Point& rPos );
+ static SAL_DLLPRIVATE void ImplLineSizing( ToolBox* pThis, const Point& rPos, Rectangle& rRect, USHORT nLineMode );
+ static SAL_DLLPRIVATE USHORT ImplFindItemPos( ToolBox* pBox, const Point& rPos );
+ static SAL_DLLPRIVATE USHORT ImplFindItemPos( const ImplToolItem* pItem, const std::vector< ImplToolItem >& rList );
+ static SAL_DLLPRIVATE void ImplDrawToolArrow( ToolBox* pBox, long nX, long nY, BOOL bBlack, BOOL bColTransform,
+ BOOL bLeft = FALSE, BOOL bTop = FALSE,
+ long nSize = 6 );
+ static SAL_DLLPRIVATE void SetToolArrowClipregion( ToolBox* pBox, long nX, long nY,
+ BOOL bLeft = FALSE, BOOL bTop = FALSE,
+ long nSize = 6 );
+ static SAL_DLLPRIVATE void ImplDrawMenubutton( ToolBox *pThis, BOOL bHighlight );
+ static SAL_DLLPRIVATE USHORT ImplCountLineBreaks( const ToolBox *pThis );
+ SAL_DLLPRIVATE ImplToolBoxPrivateData* ImplGetToolBoxPrivateData() const { return mpData; }
+//#endif
+
+protected:
+ void SetCurItemId(USHORT nSet) { mnCurItemId = nSet; }
+
+public:
+ ToolBox( Window* pParent, WinBits nStyle = 0 );
+ ToolBox( Window* pParent, const ResId& rResId );
+ ~ToolBox();
+
+ virtual void Click();
+ virtual void DoubleClick();
+ virtual void Activate();
+ virtual void Deactivate();
+ virtual void Highlight();
+ virtual void Select();
+ virtual void NextToolBox();
+ virtual void Customize( const ToolBoxCustomizeEvent& rCEvt );
+ virtual void UserDraw( const UserDrawEvent& rUDEvt );
+
+ virtual void MouseButtonDown( const MouseEvent& rMEvt );
+ virtual void MouseButtonUp( const MouseEvent& rMEvt );
+ virtual void MouseMove( const MouseEvent& rMEvt );
+ virtual void Tracking( const TrackingEvent& rTEvt );
+ virtual void Paint( const Rectangle& rRect );
+ virtual void Move();
+ virtual void Resize();
+ virtual void RequestHelp( const HelpEvent& rHEvt );
+ virtual long Notify( NotifyEvent& rNEvt );
+ virtual void Command( const CommandEvent& rCEvt );
+ virtual void StateChanged( StateChangedType nType );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+
+ virtual void GetFocus();
+ virtual void LoseFocus();
+ virtual void KeyInput( const KeyEvent& rKEvt );
+
+ virtual BOOL PrepareToggleFloatingMode();
+ virtual void ToggleFloatingMode();
+ virtual void StartDocking();
+ virtual BOOL Docking( const Point& rPos, Rectangle& rRect );
+ virtual void EndDocking( const Rectangle& rRect, BOOL bFloatMode );
+ virtual void Resizing( Size& rSize );
+
+ void InsertItem( const ResId& rResId,
+ USHORT nPos = TOOLBOX_APPEND );
+ void InsertItem( USHORT nItemId, const Image& rImage,
+ ToolBoxItemBits nBits = 0,
+ USHORT nPos = TOOLBOX_APPEND );
+ void InsertItem( USHORT nItemId, const Image& rImage,
+ const XubString& rText,
+ ToolBoxItemBits nBits = 0,
+ USHORT nPos = TOOLBOX_APPEND );
+ void InsertItem( USHORT nItemId, const XubString& rText,
+ ToolBoxItemBits nBits = 0,
+ USHORT nPos = TOOLBOX_APPEND );
+ void InsertWindow( USHORT nItemId, Window* pWindow,
+ ToolBoxItemBits nBits = 0,
+ USHORT nPos = TOOLBOX_APPEND );
+ void InsertSpace( USHORT nPos = TOOLBOX_APPEND );
+ void InsertSeparator( USHORT nPos = TOOLBOX_APPEND,
+ USHORT nPixSize = 0 );
+ void InsertBreak( USHORT nPos = TOOLBOX_APPEND );
+ void RemoveItem( USHORT nPos );
+ void MoveItem( USHORT nItemId, USHORT nNewPos = TOOLBOX_APPEND );
+ void CopyItem( const ToolBox& rToolBox, USHORT nItemId,
+ USHORT nNewPos = TOOLBOX_APPEND );
+ void CopyItems( const ToolBox& rToolBox );
+ void Clear();
+ void RecalcItems();
+
+ const ImageList& GetImageList() const { return maImageList; }
+ void SetImageList( const ImageList& rImageList );
+
+ void SetButtonType( ButtonType eNewType = BUTTON_SYMBOL );
+ ButtonType GetButtonType() const { return meButtonType; }
+
+ // sets a fixed button size (small, large or dontcare (==autosize))
+ void SetToolboxButtonSize( ToolBoxButtonSize eSize );
+ ToolBoxButtonSize GetToolboxButtonSize() const;
+
+ void SetAlign( WindowAlign eNewAlign = WINDOWALIGN_TOP );
+ WindowAlign GetAlign() const { return meAlign; }
+ BOOL IsHorizontal() const { return mbHorz; }
+
+ void SetLineCount( USHORT nNewLines );
+ USHORT GetLineCount() const { return mnLines; }
+ USHORT GetCurLine() const { return mnCurLine; }
+ void ShowLine( BOOL bNext );
+
+ // Used to enable/disable scrolling one page at a time for toolbar
+ void SetPageScroll( BOOL b );
+ BOOL GetPageScroll();
+
+ void SetNextToolBox( const XubString& rStr );
+ const XubString& GetNextToolBox() const { return maNextToolBoxStr; }
+
+ USHORT GetItemCount() const;
+ ToolBoxItemType GetItemType( USHORT nPos ) const;
+ USHORT GetItemPos( USHORT nItemId ) const;
+ USHORT GetItemPos( const Point& rPos ) const;
+ USHORT GetItemId( USHORT nPos ) const;
+ USHORT GetItemId( const Point& rPos ) const;
+ Rectangle GetItemRect( USHORT nItemId ) const;
+ Rectangle GetItemPosRect( USHORT nPos ) const;
+ Rectangle GetItemDropDownRect( USHORT nItemId ) const;
+ Rectangle GetItemPosDropDownRect( USHORT nPos ) const;
+
+ // retrieves the optimal position to place a popup window for this item (subtoolbar or dropdown)
+ Point GetItemPopupPosition( USHORT nItemId, const Size& rSize ) const;
+
+ Rectangle GetScrollRect() const;
+ Rectangle GetMenubuttonRect() const;
+ USHORT GetCurItemId() const { return mnCurItemId; }
+ USHORT GetDownItemId() const { return mnDownItemId; }
+ USHORT GetClicks() const { return mnMouseClicks; }
+ USHORT GetModifier() const { return mnMouseModifier; }
+ USHORT GetKeyModifier() const { return mnKeyModifier; }
+
+ void SetItemBits( USHORT nItemId, ToolBoxItemBits nBits );
+ ToolBoxItemBits GetItemBits( USHORT nItemId ) const;
+
+ void SetItemData( USHORT nItemId, void* pNewData );
+ void* GetItemData( USHORT nItemId ) const;
+ void SetItemImage( USHORT nItemId, const Image& rImage );
+ Image GetItemImage( USHORT nItemId ) const;
+ void SetItemImageAngle( USHORT nItemId, long nAngle10 );
+ long GetItemImageAngle( USHORT nItemId ) const;
+ void SetItemImageMirrorMode( USHORT nItemId, BOOL bMirror );
+ BOOL GetItemImageMirrorMode( USHORT ) const;
+ void SetItemHighImage( USHORT nItemId, const Image& rImage );
+ Image GetItemHighImage( USHORT nItemId ) const;
+ void SetItemText( USHORT nItemId, const XubString& rText );
+ const XubString& GetItemText( USHORT nItemId ) const;
+ void SetItemWindow( USHORT nItemId, Window* pNewWindow );
+ Window* GetItemWindow( USHORT nItemId ) const;
+ USHORT GetHighlightItemId() const { return mnHighItemId; }
+
+ void StartSelection();
+ void EndSelection();
+
+ void SetItemDown( USHORT nItemId, BOOL bDown, BOOL bRelease = TRUE );
+ BOOL IsItemDown( USHORT nItemId ) const;
+
+ void SetItemState( USHORT nItemId, TriState eState );
+ TriState GetItemState( USHORT nItemId ) const;
+
+ void CheckItem( USHORT nItemId, BOOL bCheck = TRUE );
+ BOOL IsItemChecked( USHORT nItemId ) const;
+
+ void EnableItem( USHORT nItemId, BOOL bEnable = TRUE );
+ BOOL IsItemEnabled( USHORT nItemId ) const;
+
+ void TriggerItem( USHORT nItemId, BOOL bShift = FALSE, BOOL bCtrl = FALSE );
+ void ShowItem( USHORT nItemId, BOOL bVisible = TRUE );
+ void HideItem( USHORT nItemId ) { ShowItem( nItemId, FALSE ); }
+ BOOL IsItemVisible( USHORT nItemId ) const;
+ BOOL IsItemReallyVisible( USHORT nItemId ) const;
+
+ void SetItemCommand( USHORT nItemId, const XubString& rCommand );
+ const XubString& GetItemCommand( USHORT nItemId ) const;
+
+ using Window::SetQuickHelpText;
+ void SetQuickHelpText( USHORT nItemId, const XubString& rText );
+ using Window::GetQuickHelpText;
+ const XubString& GetQuickHelpText( USHORT nItemId ) const;
+
+ void SetHelpText( USHORT nItemId, const XubString& rText );
+ const XubString& GetHelpText( USHORT nItemId ) const;
+
+ void SetHelpId( USHORT nItemId, ULONG nHelpId );
+ ULONG GetHelpId( USHORT nItemId ) const;
+
+ // window size according to current alignment, floating state and number of lines
+ Size CalcWindowSizePixel() const;
+ // window size according to current alignment, floating state and a given number of lines
+ Size CalcWindowSizePixel( USHORT nCalcLines ) const;
+ // window size according to current floating state and a given number of lines and a given alignment
+ Size CalcWindowSizePixel( USHORT nCalcLines, WindowAlign eAlign ) const;
+ // floating window size according to number of lines (uses the number of line breaks)
+ Size CalcFloatingWindowSizePixel() const;
+ // floating window size with a given number of lines
+ Size CalcFloatingWindowSizePixel( USHORT nCalcLines ) const;
+ // automatic window size for popoup mode
+ Size CalcPopupWindowSizePixel() const;
+
+ // computes the smallest useful size when docked, ie with the first item visible only (+drag area and menu button)
+ Size CalcMinimumWindowSizePixel() const;
+
+ void SetDockingRects( const Rectangle& rOutRect,
+ const Rectangle& rInRect );
+ void SetFloatingLines( USHORT nFloatLines );
+ USHORT GetFloatingLines() const;
+
+ void SetBorder( long nX, long nY );
+ long GetBorderX() const { return mnBorderX; }
+ long GetBorderY() const { return mnBorderY; }
+
+ void SetStyle( WinBits nNewStyle ) { mnWinStyle = nNewStyle; }
+ WinBits GetStyle() const { return mnWinStyle; }
+
+ // enable/disable undocking
+ void Lock( BOOL bLock = TRUE );
+
+ // read configuration to determine locking behaviour
+ static BOOL AlwaysLocked();
+
+ void EnableMenuStrings( BOOL bEnable = TRUE ) { mbMenuStrings = (bEnable != 0); }
+ BOOL IsMenuStringsEnabled() const { return mbMenuStrings; }
+
+ void SetOutStyle( USHORT nNewStyle );
+ USHORT GetOutStyle() const { return mnOutStyle; }
+
+ void EnableCustomize( BOOL bEnable = TRUE );
+ BOOL IsCustomize() { return mbCustomize; }
+ void StartCustomize( const Rectangle& rRect, void* pData = NULL );
+ void SetCustomizeMode( BOOL );
+ BOOL IsInCustomizeMode() const { return mbCustomizeMode; }
+
+ static void StartCustomizeMode();
+ static void EndCustomizeMode();
+ static BOOL IsCustomizeMode();
+
+ void SetHelpText( const XubString& rText )
+ { DockingWindow::SetHelpText( rText ); }
+ const XubString& GetHelpText() const
+ { return DockingWindow::GetHelpText(); }
+
+ void SetHelpId( ULONG nId )
+ { DockingWindow::SetHelpId( nId ); }
+ ULONG GetHelpId() const
+ { return DockingWindow::GetHelpId(); }
+
+ void SetClickHdl( const Link& rLink ) { maClickHdl = rLink; }
+ const Link& GetClickHdl() const { return maClickHdl; }
+ void SetDoubleClickHdl( const Link& rLink ) { maDoubleClickHdl = rLink; }
+ const Link& GetDoubleClickHdl() const { return maDoubleClickHdl; }
+ void SetDropdownClickHdl( const Link& rLink );
+ const Link& GetDropdownClickHdl() const;
+ void SetActivateHdl( const Link& rLink ) { maActivateHdl = rLink; }
+ const Link& GetActivateHdl() const { return maActivateHdl; }
+ void SetDeactivateHdl( const Link& rLink ) { maDeactivateHdl = rLink; }
+ const Link& GetDeactivateHdl() const { return maDeactivateHdl; }
+ void SetHighlightHdl( const Link& rLink ) { maHighlightHdl = rLink; }
+ const Link& GetHighlightHdl() const { return maHighlightHdl; }
+ void SetSelectHdl( const Link& rLink ) { maSelectHdl = rLink; }
+ const Link& GetSelectHdl() const { return maSelectHdl; }
+ void SetNextToolBoxHdl( const Link& rLink ) { maNextToolBoxHdl = rLink; }
+ const Link& GetNextToolBoxHdl() const { return maNextToolBoxHdl; }
+
+ // support for custom menu (eg for configuration)
+ // note: this menu will also be used to display currently
+ // clipped toolbox items, so you should only touch
+ // items that you added by yourself
+ // the private toolbox items will only use item ids starting from TOOLBOX_MENUITEM_START
+ // to allow for customization of the menu the coresponding handler is called
+ // when the menu button was clicked and before the menu is executed
+ void SetMenuType( USHORT aType = TOOLBOX_MENUTYPE_CUSTOMIZE );
+ USHORT GetMenuType() const;
+ BOOL IsMenuEnabled() const;
+ PopupMenu* GetMenu() const;
+ void SetMenuButtonHdl( const Link& rLink );
+ const Link& GetMenuButtonHdl() const;
+
+ // open custommenu
+ void ExecuteCustomMenu();
+
+ // allow Click Handler to detect special key
+ BOOL IsShift() const { return mbIsShift; }
+ // allow Click Handler to distinguish between mouse and key input
+ BOOL IsKeyEvent() const { return mbIsKeyEvent; }
+
+ // allows framework to set/query the planned popupmode
+ BOOL WillUsePopupMode() const;
+ void WillUsePopupMode( BOOL b);
+
+ // accessibility helpers
+
+ // gets the displayed text
+ String GetDisplayText() const;
+ // returns the bounding box for the character at index nIndex
+ // where nIndex is relative to the starting index of the item
+ // with id nItemId (in coordinates of the displaying window)
+ Rectangle GetCharacterBounds( USHORT nItemId, long nIndex ) const;
+ // -1 is returned if no character is at that point
+ // if an index is found the corresponding item id is filled in (else 0)
+ long GetIndexForPoint( const Point& rPoint, USHORT& rItemID ) const;
+ // returns the number of portions in the result of GetDisplayText()
+ long GetTextCount() const;
+ // returns the interval [start,end] of text portion nText
+ // returns [-1,-1] for an invalid text number
+ Pair GetTextStartEnd( long nText ) const;
+ // returns the item id for text portion nText or 0 if nText is invalid
+ USHORT GetDisplayItemId( long nText ) const;
+
+ const Size& GetDefaultImageSize() const;
+ void ChangeHighlight( USHORT nPos );
+
+ void SetImageListProvider(vcl::IImageListProvider* _pProvider);
+};
+
+inline void ToolBox::CheckItem( USHORT nItemId, BOOL bCheck )
+{
+ SetItemState( nItemId, (bCheck) ? STATE_CHECK : STATE_NOCHECK );
+}
+
+inline BOOL ToolBox::IsItemChecked( USHORT nItemId ) const
+{
+ return (GetItemState( nItemId ) == STATE_CHECK);
+}
+
+inline Size ToolBox::CalcWindowSizePixel() const
+{
+ return CalcWindowSizePixel( mnLines );
+}
+
+inline Rectangle ToolBox::GetScrollRect() const
+{
+ return maUpperRect.GetUnion( maLowerRect );
+}
+
+inline void ToolBox::SetDockingRects( const Rectangle& rOutRect,
+ const Rectangle& rInRect )
+{
+ maOutDockRect = rOutRect;
+ maInDockRect = rInRect;
+}
+
+inline void ToolBox::SetFloatingLines( USHORT nNewLines )
+{
+ mnFloatLines = nNewLines;
+}
+
+inline USHORT ToolBox::GetFloatingLines() const
+{
+ return mnFloatLines;
+}
+
+#endif // _SV_TOOLBOX_HXX
diff --git a/vcl/inc/vcl/unobrok.hxx b/vcl/inc/vcl/unobrok.hxx
new file mode 100644
index 000000000000..af616e80351a
--- /dev/null
+++ b/vcl/inc/vcl/unobrok.hxx
@@ -0,0 +1,39 @@
+/*************************************************************************
+ *
+ * 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 _UNOBROK_HXX
+#define _UNOBROK_HXX
+
+#include <vcl/svdata.hxx>
+#include <vos/thread.hxx>
+
+namespace vcl_accept
+{
+ sal_Bool accept(const ::rtl::OUString & accDcp, const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory> & rSMgr);
+}
+
+#endif // _UNOBROK_HXX
diff --git a/vcl/inc/vcl/unohelp.hxx b/vcl/inc/vcl/unohelp.hxx
new file mode 100644
index 000000000000..5d98b6872a26
--- /dev/null
+++ b/vcl/inc/vcl/unohelp.hxx
@@ -0,0 +1,70 @@
+/*************************************************************************
+ *
+ * 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_UNOHELP_HXX
+#define _VCL_UNOHELP_HXX
+
+#include <com/sun/star/uno/Reference.h>
+#include <rtl/ustring.hxx>
+#include <vcl/dllapi.h>
+
+namespace com {
+namespace sun {
+namespace star {
+namespace i18n {
+ class XBreakIterator;
+ class XCharacterClassification;
+ class XCollator;
+}
+namespace lang {
+ class XMultiServiceFactory;
+}
+}}}
+
+namespace com {
+namespace sun {
+namespace star {
+namespace accessibility {
+ struct AccessibleEventObject;
+}
+}}}
+
+namespace vcl
+{
+namespace unohelper
+{
+
+::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > VCL_DLLPUBLIC GetMultiServiceFactory();
+::com::sun::star::uno::Reference < ::com::sun::star::i18n::XBreakIterator > VCL_DLLPUBLIC CreateBreakIterator();
+::com::sun::star::uno::Reference < ::com::sun::star::i18n::XCharacterClassification> VCL_DLLPUBLIC CreateCharacterClassification();
+::com::sun::star::uno::Reference < ::com::sun::star::i18n::XCollator > VCL_DLLPUBLIC CreateCollator();
+::rtl::OUString VCL_DLLPUBLIC CreateLibraryName( const sal_Char* pModName, sal_Bool bSUPD );
+void VCL_DLLPUBLIC NotifyAccessibleStateEventGlobally( const ::com::sun::star::accessibility::AccessibleEventObject& rEventObject );
+}} // namespace vcl::unohelper
+
+#endif // _VCL_UNOHELP_HXX
+
diff --git a/vcl/inc/vcl/unohelp2.hxx b/vcl/inc/vcl/unohelp2.hxx
new file mode 100644
index 000000000000..e7d8d34e0595
--- /dev/null
+++ b/vcl/inc/vcl/unohelp2.hxx
@@ -0,0 +1,84 @@
+/*************************************************************************
+ *
+ * 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_UNOHELP2_HXX
+#define _VCL_UNOHELP2_HXX
+
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <cppuhelper/weak.hxx>
+#include <tools/string.hxx>
+#include <osl/mutex.hxx>
+
+namespace com { namespace sun { namespace star { namespace datatransfer { namespace clipboard {
+ class XClipboard;
+} } } } }
+#include <vcl/dllapi.h>
+
+namespace vcl { namespace unohelper {
+
+ class VCL_DLLPUBLIC TextDataObject :
+ public ::com::sun::star::datatransfer::XTransferable,
+ public ::cppu::OWeakObject
+ {
+ private:
+ String maText;
+
+ public:
+ TextDataObject( const String& rText );
+ ~TextDataObject();
+
+ String& GetString() { return maText; }
+
+ // ::com::sun::star::uno::XInterface
+ ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type & rType ) throw(::com::sun::star::uno::RuntimeException);
+ void SAL_CALL acquire() throw() { OWeakObject::acquire(); }
+ void SAL_CALL release() throw() { OWeakObject::release(); }
+
+ // ::com::sun::star::datatransfer::XTransferable
+ ::com::sun::star::uno::Any SAL_CALL getTransferData( const ::com::sun::star::datatransfer::DataFlavor& aFlavor ) throw(::com::sun::star::datatransfer::UnsupportedFlavorException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
+ ::com::sun::star::uno::Sequence< ::com::sun::star::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors( ) throw(::com::sun::star::uno::RuntimeException);
+ sal_Bool SAL_CALL isDataFlavorSupported( const ::com::sun::star::datatransfer::DataFlavor& aFlavor ) throw(::com::sun::star::uno::RuntimeException);
+
+ /// copies a given string to a given clipboard
+ static void CopyStringTo(
+ const String& rContent,
+ const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboard >& rxClipboard
+ );
+ };
+
+ struct MutexHelper
+ {
+ private:
+ ::osl::Mutex maMutex;
+ public:
+ ::osl::Mutex& GetMutex() { return maMutex; }
+ };
+
+}} // namespace vcl::unohelper
+
+#endif // _VCL_UNOHELP2_HXX
+
diff --git a/vcl/inc/vcl/unowrap.hxx b/vcl/inc/vcl/unowrap.hxx
new file mode 100644
index 000000000000..b11842aa0c6b
--- /dev/null
+++ b/vcl/inc/vcl/unowrap.hxx
@@ -0,0 +1,91 @@
+/*************************************************************************
+ *
+ * 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_UNOWRAP_HXX
+#define _VCL_UNOWRAP_HXX
+
+#include <tools/solar.h>
+#include <vcl/dllapi.h>
+#include <com/sun/star/uno/Reference.h>
+
+class XWindowPeer;
+class XToolkit;
+class XVclToolkit;
+class EventList;
+class Window;
+class OutputDevice;
+class MouseEvent;
+class CommandEvent;
+class KeyEvent;
+class Rectangle;
+class XVclComponentPeer;
+class Menu;
+
+namespace com {
+namespace sun {
+namespace star {
+namespace awt {
+ class XGraphics;
+ class XToolkit;
+ class XWindowPeer;
+}
+namespace lang {
+ class XMultiServiceFactory;
+}
+} } }
+
+namespace com {
+namespace sun {
+namespace star {
+namespace accessibility {
+ class XAccessible;
+}}}}
+
+class VCL_DLLPUBLIC UnoWrapperBase
+{
+public:
+ virtual void Destroy() = 0;
+
+ // Toolkit
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::awt::XToolkit > GetVCLToolkit() = 0;
+
+ // Graphics
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::awt::XGraphics > CreateGraphics( OutputDevice* pOutDev ) = 0;
+ virtual void ReleaseAllGraphics( OutputDevice* pOutDev ) = 0;
+
+ // Window
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindowPeer> GetWindowInterface( Window* pWindow, sal_Bool bCreate ) = 0;
+ virtual void SetWindowInterface( Window* pWindow, ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindowPeer > xIFace ) = 0;
+
+ virtual void WindowDestroyed( Window* pWindow ) = 0;
+
+ // Accessibility
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >
+ CreateAccessible( Menu* pMenu, sal_Bool bIsMenuBar ) = 0;
+};
+
+#endif // _VCL_UNOWRAP_HXX
diff --git a/vcl/inc/vcl/vclenum.hxx b/vcl/inc/vcl/vclenum.hxx
new file mode 100644
index 000000000000..a34c633479e7
--- /dev/null
+++ b/vcl/inc/vcl/vclenum.hxx
@@ -0,0 +1,328 @@
+/*************************************************************************
+ *
+ * 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_VCLENUM_HXX
+#define _VCL_VCLENUM_HXX
+
+#include <sal/types.h>
+#include <tools/solar.h>
+
+#ifndef ENUM_TIMEFIELDFORMAT_DECLARED
+#define ENUM_TIMEFIELDFORMAT_DECLARED
+
+// By changes you must also change: rsc/vclrsc.hxx
+enum TimeFieldFormat {TIMEF_NONE, TIMEF_SEC, TIMEF_100TH_SEC, TIMEF_SEC_CS, TimeFieldFormat_FORCE_EQUAL_SIZE=SAL_MAX_ENUM };
+
+#endif
+
+// ------------------------------------------------------------
+
+#ifndef ENUM_EXTTIMEFIELDFORMAT_DECLARED
+#define ENUM_EXTTIMEFIELDFORMAT_DECLARED
+
+enum ExtTimeFieldFormat { EXTTIMEF_24H_SHORT, EXTTIMEF_24H_LONG,
+ EXTTIMEF_12H_SHORT, EXTTIMEF_12H_LONG,
+ EXTTIMEF_DURATION_SHORT, EXTTIMEF_DURATION_LONG };
+
+#endif
+
+// ------------------------------------------------------------
+
+#ifndef ENUM_EXTDATEFIELDFORMAT_DECLARED
+#define ENUM_EXTDATEFIELDFORMAT_DECLARED
+
+enum ExtDateFieldFormat { XTDATEF_SYSTEM_SHORT, XTDATEF_SYSTEM_SHORT_YY, XTDATEF_SYSTEM_SHORT_YYYY,
+ XTDATEF_SYSTEM_LONG,
+ XTDATEF_SHORT_DDMMYY, XTDATEF_SHORT_MMDDYY, XTDATEF_SHORT_YYMMDD,
+ XTDATEF_SHORT_DDMMYYYY, XTDATEF_SHORT_MMDDYYYY, XTDATEF_SHORT_YYYYMMDD,
+ XTDATEF_SHORT_YYMMDD_DIN5008, XTDATEF_SHORT_YYYYMMDD_DIN5008, ExtDateFieldFormat_FORCE_EQUAL_SIZE=SAL_MAX_ENUM };
+
+#endif
+
+// ------------------------------------------------------------
+
+// to avoid conflicts with enum's declared otherwise
+#define GRADIENT_LINEAR GradientStyle_LINEAR
+#define GRADIENT_AXIAL GradientStyle_AXIAL
+#define GRADIENT_RADIAL GradientStyle_RADIAL
+#define GRADIENT_ELLIPTICAL GradientStyle_ELLIPTICAL
+#define GRADIENT_SQUARE GradientStyle_SQUARE
+#define GRADIENT_RECT GradientStyle_RECT
+#define GRADIENT_FORCE_EQUAL_SIZE GradientStyle_FORCE_EQUAL_SIZE
+
+#ifndef ENUM_GRADIENTSTYLE_DECLARED
+#define ENUM_GRADIENTSTYLE_DECLARED
+
+enum GradientStyle
+{
+ GRADIENT_LINEAR = 0,
+ GRADIENT_AXIAL = 1,
+ GRADIENT_RADIAL = 2,
+ GRADIENT_ELLIPTICAL = 3,
+ GRADIENT_SQUARE = 4,
+ GRADIENT_RECT = 5,
+ GradientStyle_FORCE_EQUAL_SIZE = SAL_MAX_ENUM
+};
+
+#endif
+
+// ------------------------------------------------------------
+
+// to avoid conflicts with enum's declared otherwise
+#define HATCH_SINGLE HatchStyle_SINGLE
+#define HATCH_DOUBLE HatchStyle_DOUBLE
+#define HATCH_TRIPLE HatchStyle_TRIPLE
+#define HATCH_FORCE_EQUAL_SIZE HatchStyle_FORCE_EQUAL_SIZE
+
+#ifndef ENUM_HATCHSTYLE_DECLARED
+#define ENUM_HATCHSTYLE_DECLARED
+
+enum HatchStyle
+{
+ HATCH_SINGLE = 0,
+ HATCH_DOUBLE = 1,
+ HATCH_TRIPLE = 2,
+ HatchStyle_FORCE_EQUAL_SIZE = SAL_MAX_ENUM
+};
+
+#endif
+
+// ------------------------------------------------------------
+
+// to avoid conflicts with enum's declared otherwise
+#define LINE_NONE LineStyle_NONE
+#define LINE_SOLID LineStyle_SOLID
+#define LINE_DASH LineStyle_DASH
+#define LINE_FORCE_EQUAL_SIZE LineStyle_FORCE_EQUAL_SIZE
+
+#ifndef ENUM_LINESTYLE_DECLARED
+#define ENUM_LINESTYLE_DECLARED
+
+enum LineStyle
+{
+ LINE_NONE = 0,
+ LINE_SOLID = 1,
+ LINE_DASH = 2,
+ LineStyle_FORCE_EQUAL_SIZE = SAL_MAX_ENUM
+};
+
+#endif
+
+// ------------------------------------------------------------
+
+#ifndef ENUM_RASTEROP_DECLARED
+#define ENUM_RASTEROP_DECLARED
+
+enum RasterOp { ROP_OVERPAINT, ROP_XOR, ROP_0, ROP_1, ROP_INVERT };
+
+#endif
+
+// ------------------------------------------------------------
+
+#ifndef ENUM_FONTFAMILY_DECLARED
+#define ENUM_FONTFAMILY_DECLARED
+
+enum FontFamily { FAMILY_DONTKNOW, FAMILY_DECORATIVE, FAMILY_MODERN,
+ FAMILY_ROMAN, FAMILY_SCRIPT, FAMILY_SWISS, FAMILY_SYSTEM, FontFamily_FORCE_EQUAL_SIZE=SAL_MAX_ENUM };
+
+#endif
+
+// ------------------------------------------------------------
+
+#ifndef ENUM_FONTPITCH_DECLARED
+#define ENUM_FONTPITCH_DECLARED
+
+enum FontPitch { PITCH_DONTKNOW, PITCH_FIXED, PITCH_VARIABLE, FontPitch_FORCE_EQUAL_SIZE=SAL_MAX_ENUM };
+
+#endif
+
+// ------------------------------------------------------------
+
+#ifndef ENUM_TEXTALIGN_DECLARED
+#define ENUM_TEXTALIGN_DECLARED
+
+enum TextAlign { ALIGN_TOP, ALIGN_BASELINE, ALIGN_BOTTOM, TextAlign_FORCE_EQUAL_SIZE=SAL_MAX_ENUM };
+
+#endif
+
+// ------------------------------------------------------------
+
+#ifndef ENUM_FONTWEIGHT_DECLARED
+#define ENUM_FONTWEIGHT_DECLARED
+
+enum FontWeight { WEIGHT_DONTKNOW, WEIGHT_THIN, WEIGHT_ULTRALIGHT,
+ WEIGHT_LIGHT, WEIGHT_SEMILIGHT, WEIGHT_NORMAL,
+ WEIGHT_MEDIUM, WEIGHT_SEMIBOLD, WEIGHT_BOLD,
+ WEIGHT_ULTRABOLD, WEIGHT_BLACK, FontWeight_FORCE_EQUAL_SIZE=SAL_MAX_ENUM };
+
+#endif
+
+// ------------------------------------------------------------
+
+#ifndef ENUM_FONTWIDTH_DECLARED
+#define ENUM_FONTWIDTH_DECLARED
+
+enum FontWidth { WIDTH_DONTKNOW, WIDTH_ULTRA_CONDENSED, WIDTH_EXTRA_CONDENSED,
+ WIDTH_CONDENSED, WIDTH_SEMI_CONDENSED, WIDTH_NORMAL,
+ WIDTH_SEMI_EXPANDED, WIDTH_EXPANDED, WIDTH_EXTRA_EXPANDED,
+ WIDTH_ULTRA_EXPANDED,
+ FontWidth_FORCE_EQUAL_SIZE=SAL_MAX_ENUM };
+
+#endif
+
+// ------------------------------------------------------------
+
+#ifndef ENUM_FONTITALIC_DECLARED
+#define ENUM_FONTITALIC_DECLARED
+
+enum FontItalic { ITALIC_NONE, ITALIC_OBLIQUE, ITALIC_NORMAL, ITALIC_DONTKNOW, FontItalic_FORCE_EQUAL_SIZE=SAL_MAX_ENUM };
+
+#endif
+
+// ------------------------------------------------------------
+
+#ifndef ENUM_FONTUNDERLINE_DECLARED
+#define ENUM_FONTUNDERLINE_DECLARED
+
+enum FontUnderline { UNDERLINE_NONE, UNDERLINE_SINGLE, UNDERLINE_DOUBLE,
+ UNDERLINE_DOTTED, UNDERLINE_DONTKNOW,
+ UNDERLINE_DASH, UNDERLINE_LONGDASH,
+ UNDERLINE_DASHDOT, UNDERLINE_DASHDOTDOT,
+ UNDERLINE_SMALLWAVE,
+ UNDERLINE_WAVE, UNDERLINE_DOUBLEWAVE,
+ UNDERLINE_BOLD, UNDERLINE_BOLDDOTTED,
+ UNDERLINE_BOLDDASH, UNDERLINE_BOLDLONGDASH,
+ UNDERLINE_BOLDDASHDOT, UNDERLINE_BOLDDASHDOTDOT,
+ UNDERLINE_BOLDWAVE,
+ FontUnderline_FORCE_EQUAL_SIZE=SAL_MAX_ENUM };
+
+#endif
+
+// ------------------------------------------------------------
+
+#ifndef ENUM_FONTSTRIKEOUT_DECLARED
+#define ENUM_FONTSTRIKEOUT_DECLARED
+
+enum FontStrikeout { STRIKEOUT_NONE, STRIKEOUT_SINGLE, STRIKEOUT_DOUBLE,
+ STRIKEOUT_DONTKNOW, STRIKEOUT_BOLD,
+ STRIKEOUT_SLASH, STRIKEOUT_X,
+ FontStrikeout_FORCE_EQUAL_SIZE=SAL_MAX_ENUM };
+
+#endif
+
+// ------------------------------------------------------------
+
+#ifndef ENUM_FONTEMPHASISMARK_DECLARED
+#define ENUM_FONTEMPHASISMARK_DECLARED
+
+typedef USHORT FontEmphasisMark;
+#define EMPHASISMARK_NONE ((FontEmphasisMark)0x0000)
+#define EMPHASISMARK_DOT ((FontEmphasisMark)0x0001)
+#define EMPHASISMARK_CIRCLE ((FontEmphasisMark)0x0002)
+#define EMPHASISMARK_DISC ((FontEmphasisMark)0x0003)
+#define EMPHASISMARK_ACCENT ((FontEmphasisMark)0x0004)
+#define EMPHASISMARK_STYLE ((FontEmphasisMark)0x00FF)
+#define EMPHASISMARK_POS_ABOVE ((FontEmphasisMark)0x1000)
+#define EMPHASISMARK_POS_BELOW ((FontEmphasisMark)0x2000)
+
+// Only for kompability
+#define EMPHASISMARK_DOTS_ABOVE (EMPHASISMARK_DOT | EMPHASISMARK_POS_ABOVE)
+#define EMPHASISMARK_DOTS_BELOW (EMPHASISMARK_DOT | EMPHASISMARK_POS_BELOW)
+#define EMPHASISMARK_SIDE_DOTS (EMPHASISMARK_ACCENT | EMPHASISMARK_POS_ABOVE)
+#define EMPHASISMARK_CIRCLE_ABOVE (EMPHASISMARK_CIRCLE | EMPHASISMARK_POS_ABOVE)
+
+#endif
+
+// ------------------------------------------------------------
+
+#ifndef ENUM_FONTTYPE_DECLARED
+#define ENUM_FONTTYPE_DECLARED
+
+enum FontType { TYPE_DONTKNOW, TYPE_RASTER, TYPE_VECTOR, TYPE_SCALABLE,
+ FontType_FORCE_EQUAL_SIZE=SAL_MAX_ENUM };
+
+#endif
+
+#ifndef ENUM_FONTEMBEDDEDBITMAP_DECLARED
+#define ENUM_FONTEMBEDDEDBITMAP_DECLARED
+
+enum FontEmbeddedBitmap { EMBEDDEDBITMAP_DONTKNOW, EMBEDDEDBITMAP_FALSE, EMBEDDEDBITMAP_TRUE };
+
+#endif
+
+#ifndef ENUM_FONTANTIALIAS_DECLARED
+#define ENUM_FONTANTIALIAS_DECLARED
+
+enum FontAntiAlias { ANTIALIAS_DONTKNOW, ANTIALIAS_FALSE, ANTIALIAS_TRUE };
+
+#endif
+
+#ifndef ENUM_FONTAUTOHINT_DECLARED
+#define ENUM_FONTAUTOHINT_DECLARED
+
+enum FontAutoHint { AUTOHINT_DONTKNOW, AUTOHINT_FALSE, AUTOHINT_TRUE };
+
+#endif
+
+#ifndef ENUM_FONTHINTING_DECLARED
+#define ENUM_FONTHINTING_DECLARED
+
+enum FontHinting { HINTING_DONTKNOW, HINTING_FALSE, HINTING_TRUE };
+
+#endif
+
+#ifndef ENUM_FONTHINTSTYLE_DECLARED
+#define ENUM_FONTHINTSTYLE_DECLARED
+
+enum FontHintStyle { HINT_NONE, HINT_SLIGHT, HINT_MEDIUM, HINT_FULL };
+
+#endif
+
+// ------------------------------------------------------------
+
+#ifndef ENUM_KEYFUNCTYPE_DECLARED
+#define ENUM_KEYFUNCTYPE_DECLARED
+
+enum KeyFuncType { KEYFUNC_DONTKNOW, KEYFUNC_NEW, KEYFUNC_OPEN, KEYFUNC_SAVE,
+ KEYFUNC_SAVEAS, KEYFUNC_PRINT, KEYFUNC_CLOSE, KEYFUNC_QUIT,
+ KEYFUNC_CUT, KEYFUNC_COPY, KEYFUNC_PASTE, KEYFUNC_UNDO,
+ KEYFUNC_REDO, KEYFUNC_DELETE, KEYFUNC_REPEAT, KEYFUNC_FIND,
+ KEYFUNC_FINDBACKWARD, KEYFUNC_PROPERTIES, KEYFUNC_FRONT,
+ KeyFuncType_FORCE_EQUAL_SIZE=SAL_MAX_ENUM };
+
+#endif
+
+typedef sal_uInt32 sal_UCS4; // TODO: this should be moved to rtl
+
+#ifndef ENUM_OUTDEVSUPPORT_DECLARED
+#define ENUM_OUTDEVSUPPORT_DECLARED
+
+enum OutDevSupportType { OutDevSupport_TransparentRect, OutDevSupport_B2DClip, OutDevSupport_B2DDraw };
+
+#endif
+
+#endif // _VCL_VCLENUM_HXX
diff --git a/vcl/inc/vcl/vclevent.hxx b/vcl/inc/vcl/vclevent.hxx
new file mode 100644
index 000000000000..8ccb880fce34
--- /dev/null
+++ b/vcl/inc/vcl/vclevent.hxx
@@ -0,0 +1,301 @@
+/*************************************************************************
+ *
+ * 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_VCLEVENT_HXX
+#define _VCL_VCLEVENT_HXX
+
+#include "tools/link.hxx"
+#include "tools/rtti.hxx"
+#include "vcl/dllapi.h"
+#include "vcl/impdel.hxx"
+
+#include <com/sun/star/uno/Reference.hxx>
+
+#include <list>
+#include <vector>
+
+class Window;
+class Menu;
+
+namespace com { namespace sun { namespace star {
+ namespace accessibility {
+ class XAccessible;
+ }
+}}}
+
+#define VCLEVENT_OBJECT_DYING 1
+
+// VclWindowEvent:
+#define VCLEVENT_WINDOW_CHILDCREATED 500 // pData = Window*
+#define VCLEVENT_WINDOW_CHILDDESTROYED 501 // pData = Window*
+#define VCLEVENT_WINDOW_PAINT 1000 // pData = Rectangle*
+#define VCLEVENT_WINDOW_MOVE 1001
+#define VCLEVENT_WINDOW_RESIZE 1002
+#define VCLEVENT_WINDOW_SHOW 1003
+#define VCLEVENT_WINDOW_HIDE 1004
+#define VCLEVENT_WINDOW_ACTIVATE 1005
+#define VCLEVENT_WINDOW_DEACTIVATE 1006 // pData = Window* = pPrevActiveWindow
+#define VCLEVENT_WINDOW_CLOSE 1007
+#define VCLEVENT_WINDOW_GETFOCUS 1008
+#define VCLEVENT_WINDOW_LOSEFOCUS 1009
+#define VCLEVENT_WINDOW_MINIMIZE 1010
+#define VCLEVENT_WINDOW_NORMALIZE 1011
+#define VCLEVENT_WINDOW_KEYINPUT 1012 // pData = KeyEvent*
+#define VCLEVENT_WINDOW_KEYUP 1013 // pData = KeyEvent*
+#define VCLEVENT_WINDOW_COMMAND 1014 // pData = CommandEvent*
+#define VCLEVENT_WINDOW_MOUSEMOVE 1015 // pData = MouseEvent*
+#define VCLEVENT_WINDOW_MOUSEBUTTONDOWN 1016 // pData = MouseEvent*
+#define VCLEVENT_WINDOW_MOUSEBUTTONUP 1017 // pData = MouseEvent*
+#define VCLEVENT_WINDOW_FRAMETITLECHANGED 1018 // pData = XubString* = oldTitle
+#define VCLEVENT_APPLICATION_DATACHANGED 1019 // pData = DataChangedEvent*
+#define VCLEVENT_WINDOW_ENABLED 1020
+#define VCLEVENT_WINDOW_DISABLED 1021
+#define VCLEVENT_WINDOW_DATACHANGED 1022 // pData = DataChangedEvent*
+
+// VclWindowEvent
+#define VCLEVENT_CONTROL_GETFOCUS 1100
+#define VCLEVENT_CONTROL_LOSEFOCUS 1101
+#define VCLEVENT_BUTTON_CLICK 1102
+#define VCLEVENT_PUSHBUTTON_TOGGLE 1103
+#define VCLEVENT_RADIOBUTTON_TOGGLE 1104
+#define VCLEVENT_CHECKBOX_TOGGLE 1105
+#define VCLEVENT_COMBOBOX_SELECT 1106
+#define VCLEVENT_COMBOBOX_DOUBLECLICK 1107
+#define VCLEVENT_LISTBOX_SELECT 1108
+#define VCLEVENT_LISTBOX_DOUBLECLICK 1109
+#define VCLEVENT_EDIT_MODIFY 1110
+#define VCLEVENT_SCROLLBAR_SCROLL 1111
+#define VCLEVENT_SCROLLBAR_ENDSCROLL 1112
+#define VCLEVENT_SPINBUTTON_UP 1113
+#define VCLEVENT_SPINBUTTON_DOWN 1114
+#define VCLEVENT_SPINFIELD_UP 1115
+#define VCLEVENT_SPINFIELD_DOWN 1116
+#define VCLEVENT_SPINFIELD_FIRST 1117
+#define VCLEVENT_SPINFIELD_LAST 1118
+#define VCLEVENT_STATUSBAR_CLICK 1119
+#define VCLEVENT_STATUSBAR_DOUBLECLICK 1120
+#define VCLEVENT_TOOLBOX_CLICK 1121
+#define VCLEVENT_TOOLBOX_DOUBLECLICK 1122
+#define VCLEVENT_TOOLBOX_ACTIVATE 1123
+#define VCLEVENT_TOOLBOX_DEACTIVATE 1124
+#define VCLEVENT_TOOLBOX_HIGHLIGHT 1125
+#define VCLEVENT_TOOLBOX_SELECT 1126
+// Resort later...
+#define VCLEVENT_LISTBOX_SCROLLED 1127
+#define VCLEVENT_COMBOBOX_SCROLLED 1128
+#define VCLEVENT_EDIT_SELECTIONCHANGED 1129
+#define VCLEVENT_DROPDOWN_OPEN 1130
+#define VCLEVENT_DROPDOWN_CLOSE 1131
+
+#define VCLEVENT_TOOLBOX_ITEMADDED 1132 // pData = itempos
+#define VCLEVENT_TOOLBOX_ITEMREMOVED 1133 // pData = itempos
+#define VCLEVENT_TOOLBOX_ALLITEMSCHANGED 1134
+#define VCLEVENT_TOOLBOX_HIGHLIGHTOFF 1135 // pData = itempos
+#define VCLEVENT_WINDOW_MENUBARADDED 1136 // pData = pMenuBar
+#define VCLEVENT_TABPAGE_ACTIVATE 1137 // pData = pageid
+#define VCLEVENT_TABPAGE_DEACTIVATE 1138 // pData = pageid
+#define VCLEVENT_TABBAR_PAGEENABLED 1139 // pData = pageid
+#define VCLEVENT_TABBAR_PAGEDISABLED 1140 // pData = pageid
+#define VCLEVENT_TABBAR_PAGESELECTED 1141 // pData = pageid
+#define VCLEVENT_TABBAR_PAGEACTIVATED 1142 // pData = pageid
+#define VCLEVENT_TABBAR_PAGEDEACTIVATED 1143 // pData = pageid
+#define VCLEVENT_TABBAR_PAGEINSERTED 1144 // pData = pageid
+#define VCLEVENT_TABBAR_PAGEREMOVED 1145 // pData = pageid
+#define VCLEVENT_TABBAR_PAGEMOVED 1146 // pData = Pair( pagepos_old, pagepos_new )
+#define VCLEVENT_TABBAR_PAGETEXTCHANGED 1147 // pData = pageid
+#define VCLEVENT_COMBOBOX_DESELECT 1148
+#define VCLEVENT_TOOLBOX_ITEMTEXTCHANGED 1149 // pData = itempos
+#define VCLEVENT_TABPAGE_INSERTED 1150 // pData = pageid
+#define VCLEVENT_TABPAGE_REMOVED 1151 // pData = pageid
+#define VCLEVENT_TABPAGE_REMOVEDALL 1152
+#define VCLEVENT_LISTBOX_ITEMADDED 1153 // pData = itempos
+#define VCLEVENT_LISTBOX_ITEMREMOVED 1154 // pData = itempos, -1=ALL
+#define VCLEVENT_COMBOBOX_ITEMADDED 1155 // pData = itempos
+#define VCLEVENT_COMBOBOX_ITEMREMOVED 1156 // pData = itempos, -1=ALL
+// free 1157
+#define VCLEVENT_WINDOW_MENUBARREMOVED 1158 // pData = pMenuBar
+#define VCLEVENT_STATUSBAR_ITEMADDED 1159 // pData = itemid
+#define VCLEVENT_STATUSBAR_ITEMREMOVED 1160 // pData = itemid
+#define VCLEVENT_STATUSBAR_ALLITEMSREMOVED 1161
+#define VCLEVENT_STATUSBAR_SHOWITEM 1162 // pData = itemid
+#define VCLEVENT_STATUSBAR_HIDEITEM 1163 // pData = itemid
+#define VCLEVENT_STATUSBAR_SHOWALLITEMS 1164
+#define VCLEVENT_STATUSBAR_HIDEALLITEMS 1165
+#define VCLEVENT_STATUSBAR_DRAWITEM 1166 // pData = itemid
+#define VCLEVENT_STATUSBAR_NAMECHANGED 1167 // pData = itemid
+#define VCLEVENT_TOOLBOX_ITEMENABLED 1168 // pData = itempos
+#define VCLEVENT_TOOLBOX_ITEMDISABLED 1169 // pData = itempos
+#define VCLEVENT_TABPAGE_PAGETEXTCHANGED 1170 // pData = pageid
+#define VCLEVENT_ROADMAP_ITEMSELECTED 1171
+#define VCLEVENT_TOOLBOX_FORMATCHANGED 1172 // request new layout
+#define VCLEVENT_COMBOBOX_SETTEXT 1173
+// --> OD 2009-04-01 #i92103#
+#define VCLEVENT_ITEM_EXPANDED 1174
+#define VCLEVENT_ITEM_COLLAPSED 1175
+// <--
+#define VCLEVENT_DROPDOWN_PRE_OPEN 1176
+
+// VclMenuEvent
+#define VCLEVENT_MENU_ACTIVATE 1200
+#define VCLEVENT_MENU_DEACTIVATE 1201
+#define VCLEVENT_MENU_HIGHLIGHT 1202
+#define VCLEVENT_MENU_SELECT 1203
+#define VCLEVENT_MENU_ENABLE 1204
+#define VCLEVENT_MENU_INSERTITEM 1205
+#define VCLEVENT_MENU_REMOVEITEM 1206
+#define VCLEVENT_MENU_SUBMENUACTIVATE 1207
+#define VCLEVENT_MENU_SUBMENUDEACTIVATE 1208
+#define VCLEVENT_MENU_SUBMENUCHANGED 1209
+#define VCLEVENT_MENU_DEHIGHLIGHT 1210
+#define VCLEVENT_MENU_DISABLE 1211
+#define VCLEVENT_MENU_ITEMTEXTCHANGED 1212
+#define VCLEVENT_MENU_ITEMCHECKED 1213
+#define VCLEVENT_MENU_ITEMUNCHECKED 1214
+#define VCLEVENT_MENU_ACCESSIBLENAMECHANGED 1215
+
+#define VCLEVENT_MENU_SHOW 1250
+#define VCLEVENT_MENU_HIDE 1251
+
+#define VCLEVENT_TOOLBOX_ITEMWINDOWCHANGED 1216
+
+// DockingWindow
+#define VCLEVENT_WINDOW_STARTDOCKING 1217 // pData = DockingData
+#define VCLEVENT_WINDOW_DOCKING 1218
+#define VCLEVENT_WINDOW_ENDDOCKING 1219 // pData = EndDockingData
+#define VCLEVENT_WINDOW_PREPARETOGGLEFLOATING 1220 // pData = BOOL
+#define VCLEVENT_WINDOW_TOGGLEFLOATING 1221
+#define VCLEVENT_WINDOW_ENDPOPUPMODE 1222 // pData = EndPopupModeData
+
+#define VCLEVENT_TOOLBOX_BUTTONSTATECHANGED 1223 // pData = itempos
+#define VCLEVENT_TABLECELL_NAMECHANGED 1224 // pData = struct(Entry, Column, oldText)
+#define VCLEVENT_TABLEROW_SELECT 1225
+
+class VCL_DLLPUBLIC VclSimpleEvent
+{
+private:
+ ULONG nId;
+
+public:
+ VclSimpleEvent( ULONG n ) { nId = n; }
+ TYPEINFO();
+
+ ULONG GetId() const { return nId; }
+};
+
+class VCL_DLLPUBLIC VclWindowEvent : public VclSimpleEvent
+{
+private:
+ Window* pWindow;
+ void* pData;
+
+public:
+ VclWindowEvent( Window* pWin, ULONG n, void* pDat = NULL ) : VclSimpleEvent(n) { pWindow = pWin; pData = pDat; }
+ TYPEINFO();
+
+ Window* GetWindow() const { return pWindow; }
+ void* GetData() const { return pData; }
+};
+
+/*
+class VclMouseEvent : public VclWindowEvent
+{
+private:
+ MouseEvent aEvent;
+
+public:
+ VclMouseEvent( Window* pWin, ULONG n, const MouseEvent& rEvent ) : VclWindowEvent( pWin, n ), aEvent(rEvent) { ; }
+ TYPEINFO();
+
+ const MouseEvent& GetEvent() const { return aEvent; }
+};
+*/
+
+class VCL_DLLPUBLIC VclMenuEvent : public VclSimpleEvent
+{
+private:
+ Menu* pMenu;
+ USHORT mnPos;
+
+public:
+ VclMenuEvent( Menu* pM, ULONG n, USHORT nPos ) : VclSimpleEvent(n) { pMenu = pM; mnPos = nPos; }
+ TYPEINFO();
+
+ Menu* GetMenu() const { return pMenu; }
+ USHORT GetItemPos() const { return mnPos; }
+};
+
+class VCL_DLLPUBLIC VclAccessibleEvent: public VclSimpleEvent
+{
+public:
+ VclAccessibleEvent( ULONG n, const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& rxAccessible );
+ virtual ~VclAccessibleEvent();
+ ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > GetAccessible() const;
+
+private:
+ ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > mxAccessible;
+};
+
+class VCL_DLLPUBLIC VclEventListeners : public std::list<Link>
+{
+public:
+ void Call( VclSimpleEvent* pEvent ) const;
+
+ // stops notifying when any handler has processed the event
+ // and returns TRUE in that case
+ // a handler must return TRUE to signal that it has processed the event
+ BOOL Process( VclSimpleEvent* pEvent ) const;
+};
+
+class VCL_DLLPUBLIC VclEventListeners2 : public vcl::DeletionNotifier
+{
+ std::list< Link > m_aListeners;
+
+ struct ListenerIt
+ {
+ std::list< Link >::iterator m_aIt;
+ bool m_bWasInvalidated;
+
+ ListenerIt(const std::list<Link>::iterator& rIt)
+ : m_aIt(rIt)
+ , m_bWasInvalidated( false )
+ {}
+ };
+
+ std::vector< ListenerIt > m_aIterators;
+
+
+public:
+ VclEventListeners2();
+ ~VclEventListeners2();
+
+ void addListener( const Link& );
+ void removeListener( const Link& );
+
+ void callListeners( VclSimpleEvent* );
+};
+
+#endif // _VCL_VCLEVENT_HXX
diff --git a/vcl/inc/vcl/virdev.hxx b/vcl/inc/vcl/virdev.hxx
new file mode 100644
index 000000000000..26270ec7703f
--- /dev/null
+++ b/vcl/inc/vcl/virdev.hxx
@@ -0,0 +1,129 @@
+/*************************************************************************
+ *
+ * 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_VIRDEV_HXX
+#define _SV_VIRDEV_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/outdev.hxx>
+
+// -----------------
+// - VirtualDevice -
+// -----------------
+
+class SalVirtualDevice;
+class RmVirtualDevice;
+struct SystemGraphicsData;
+
+class VCL_DLLPUBLIC VirtualDevice : public OutputDevice
+{
+ friend class Application;
+ friend class OutputDevice;
+
+private:
+ SalVirtualDevice* mpVirDev;
+ VirtualDevice* mpPrev;
+ VirtualDevice* mpNext;
+ USHORT mnBitCount;
+ BOOL mbScreenComp;
+ sal_Int8 mnAlphaDepth;
+ BYTE meRefDevMode;
+
+ SAL_DLLPRIVATE void ImplInitVirDev( const OutputDevice* pOutDev, long nDX, long nDY, USHORT nBitCount, const SystemGraphicsData *pData = NULL );
+ SAL_DLLPRIVATE BOOL ImplSetOutputSizePixel( const Size& rNewSize, BOOL bErase );
+
+ // Copy assignment is forbidden and not implemented.
+ VirtualDevice (const VirtualDevice &);
+ VirtualDevice & operator= (const VirtualDevice &);
+
+ /** Used for alpha VDev, to set areas to opaque
+
+ @since #i32109#
+ */
+ SAL_DLLPRIVATE void ImplFillOpaqueRectangle( const Rectangle& rRect );
+
+ // TODO: add extra member for refdev backward compatibility options
+ #define REFDEV_FORCE_ZERO_EXTLEAD 0x80
+ SAL_DLLPRIVATE bool ForceZeroExtleadBug() const
+ { return ((meRefDevMode & REFDEV_FORCE_ZERO_EXTLEAD) != 0); }
+public:
+ VirtualDevice( USHORT nBitCount = 0 );
+ VirtualDevice( const OutputDevice& rCompDev,
+ USHORT nBitCount = 0 );
+ /** Create a virtual device with alpha channel
+
+ @param rCompDev
+ The generated vdev will be compatible to this device. By
+ default, Application::GetDefaultDevice() is used here.
+
+ @param nBitCount
+ Bit depth of the generated virtual device. Use 0 here, to
+ indicate: take default screen depth. Currently, only 0 and 1
+ are allowed here, with 1 denoting binary mask.
+
+ @param nAlphaBitCount
+ Bit depth of the generated virtual device. Use 0 here, to
+ indicate: take default screen depth. Currently, only 0 and 1
+ are allowed here, with 1 denoting binary mask.
+ */
+ VirtualDevice( const OutputDevice& rCompDev,
+ USHORT nBitCount, USHORT nAlphaBitCount );
+
+ /** Create a virtual device using an existing system dependent device or graphics context
+ Any rendering will happen directly on the context and not on any intermediate bitmap.
+ Note: This might not be suported on all platforms !
+ */
+ VirtualDevice( const SystemGraphicsData *pData, USHORT nBitCount );
+
+ virtual ~VirtualDevice();
+
+ BOOL SetOutputSizePixel( const Size& rNewSize, BOOL bErase = TRUE );
+ BOOL SetOutputSize( const Size& rNewSize, BOOL bErase = TRUE )
+ { return SetOutputSizePixel( LogicToPixel( rNewSize ), bErase ); }
+
+ // reference device modes for different compatibility levels
+ enum RefDevMode { REFDEV_NONE = 0,
+ REFDEV_MODE06 = 1, // 600 dpi
+ REFDEV_MODE48 = 2, // 4800 dpi
+ REFDEV_MODE_MSO1 = 3,
+ REFDEV_MODE_PDF1 = 4,
+ REFDEV_CUSTOM = 5
+ };
+
+ void SetReferenceDevice( RefDevMode );
+
+ void Compat_ZeroExtleadBug(); // enable workaround for #i60495#
+
+ void SetReferenceDevice( sal_Int32 i_nDPIX, sal_Int32 i_nDPIY );
+
+private:
+ SAL_DLLPRIVATE void ImplSetReferenceDevice( RefDevMode, sal_Int32 i_nDPIX, sal_Int32 i_nDPIY );
+
+};
+
+#endif // _SV_VIRDEV_HXX
diff --git a/vcl/inc/vcl/waitobj.hxx b/vcl/inc/vcl/waitobj.hxx
new file mode 100644
index 000000000000..1dcd42d8bcf9
--- /dev/null
+++ b/vcl/inc/vcl/waitobj.hxx
@@ -0,0 +1,53 @@
+/*************************************************************************
+ *
+ * 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_WAITOBJ_HXX
+#define _SV_WAITOBJ_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/window.hxx>
+
+// --------------
+// - WaitObject -
+// --------------
+
+class VCL_DLLPUBLIC WaitObject
+{
+private:
+ Window* mpWindow;
+public:
+ WaitObject( Window* pWindow )
+ {
+ mpWindow = pWindow;
+ if ( mpWindow )
+ mpWindow->EnterWait();
+ }
+ ~WaitObject();
+};
+
+#endif // _SV_WAITOBJ_HXX
diff --git a/vcl/inc/vcl/wall.hxx b/vcl/inc/vcl/wall.hxx
new file mode 100644
index 000000000000..07611aaf5edc
--- /dev/null
+++ b/vcl/inc/vcl/wall.hxx
@@ -0,0 +1,143 @@
+/*************************************************************************
+ *
+ * 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_WALL_HXX
+#define _SV_WALL_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <tools/color.hxx>
+
+class Rectangle;
+class Gradient;
+class BitmapEx;
+class ImplWallpaper;
+
+// -------------------
+// - Wallpaper-Types -
+// -------------------
+
+#define WALLPAPER_NULL WallpaperStyle_NULL
+#define WALLPAPER_TILE WallpaperStyle_TILE
+#define WALLPAPER_CENTER WallpaperStyle_CENTER
+#define WALLPAPER_SCALE WallpaperStyle_SCALE
+#define WALLPAPER_TOPLEFT WallpaperStyle_TOPLEFT
+#define WALLPAPER_TOP WallpaperStyle_TOP
+#define WALLPAPER_TOPRIGHT WallpaperStyle_TOPRIGHT
+#define WALLPAPER_LEFT WallpaperStyle_LEFT
+#define WALLPAPER_RIGHT WallpaperStyle_RIGHT
+#define WALLPAPER_BOTTOMLEFT WallpaperStyle_BOTTOMLEFT
+#define WALLPAPER_BOTTOM WallpaperStyle_BOTTOM
+#define WALLPAPER_BOTTOMRIGHT WallpaperStyle_BOTTOMRIGHT
+#define WALLPAPER_APPLICATIONGRADIENT WallpaperStyle_APPLICATIONGRADIENT
+#define WALLPAPER_FORCE_EQUAL_SIZE WallpaperStyle_FORCE_EQUAL_SIZE
+
+#ifndef ENUM_WALLPAPERSTYLE_DECLARED
+#define ENUM_WALLPAPERSTYLE_DECLARED
+
+enum WallpaperStyle
+{
+ WALLPAPER_NULL,
+ WALLPAPER_TILE,
+ WALLPAPER_CENTER,
+ WALLPAPER_SCALE,
+ WALLPAPER_TOPLEFT,
+ WALLPAPER_TOP,
+ WALLPAPER_TOPRIGHT,
+ WALLPAPER_LEFT,
+ WALLPAPER_RIGHT,
+ WALLPAPER_BOTTOMLEFT,
+ WALLPAPER_BOTTOM,
+ WALLPAPER_BOTTOMRIGHT,
+ WALLPAPER_APPLICATIONGRADIENT, // defines a gradient that internally covers the whole application
+ // and uses a color derived from the face color
+ WALLPAPER_FORCE_EQUAL_SIZE = 0x7fffffff
+};
+
+#endif
+
+// -------------
+// - Wallpaper -
+// -------------
+
+class VCL_DLLPUBLIC Wallpaper
+{
+private:
+ ImplWallpaper* mpImplWallpaper;
+
+ SAL_DLLPRIVATE void ImplMakeUnique( BOOL bReleaseCache = TRUE );
+ SAL_DLLPRIVATE Gradient ImplGetApplicationGradient() const;
+
+//#if 0 // _SOLAR__PRIVATE
+public:
+ SAL_DLLPRIVATE ImplWallpaper* ImplGetImpWallpaper() const { return mpImplWallpaper; }
+//#endif
+
+public:
+ Wallpaper();
+ Wallpaper( const Wallpaper& rWallpaper );
+ Wallpaper( const Color& rColor );
+ Wallpaper( const BitmapEx& rBmpEx );
+ Wallpaper( const Gradient& rGradient );
+ ~Wallpaper();
+
+ void SetColor( const Color& rColor );
+ const Color& GetColor() const;
+
+ void SetStyle( WallpaperStyle eStyle );
+ WallpaperStyle GetStyle() const;
+
+ void SetBitmap( const BitmapEx& rBitmap );
+ void SetBitmap();
+ BitmapEx GetBitmap() const;
+ BOOL IsBitmap() const;
+
+ void SetGradient( const Gradient& rGradient );
+ void SetGradient();
+ Gradient GetGradient() const;
+ BOOL IsGradient() const;
+
+ void SetRect( const Rectangle& rRect );
+ void SetRect();
+ Rectangle GetRect() const;
+ BOOL IsRect() const;
+
+ BOOL IsFixed() const;
+ BOOL IsScrollable() const;
+
+ Wallpaper& operator=( const Wallpaper& rWallpaper );
+ BOOL operator==( const Wallpaper& rWallpaper ) const;
+ BOOL operator!=( const Wallpaper& rWallpaper ) const
+ { return !(Wallpaper::operator==( rWallpaper )); }
+ BOOL IsSameInstance( const Wallpaper& rWallpaper ) const
+ { return (mpImplWallpaper == rWallpaper.mpImplWallpaper); }
+
+ friend VCL_DLLPUBLIC SvStream& operator>>( SvStream& rIStm, Wallpaper& rWallpaper );
+ friend VCL_DLLPUBLIC SvStream& operator<<( SvStream& rOStm, const Wallpaper& rWallpaper );
+};
+
+#endif // _SV_WALL_HXX
diff --git a/vcl/inc/vcl/wall2.hxx b/vcl/inc/vcl/wall2.hxx
new file mode 100644
index 000000000000..e93a8370ee7d
--- /dev/null
+++ b/vcl/inc/vcl/wall2.hxx
@@ -0,0 +1,60 @@
+/*************************************************************************
+ *
+ * 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_WALL2_HXX
+#define _SV_WALL2_HXX
+
+#include <vcl/wall.hxx>
+
+class ImplWallpaper
+{
+ friend class Wallpaper;
+
+private:
+ Color maColor;
+ BitmapEx* mpBitmap;
+ Gradient* mpGradient;
+ Rectangle* mpRect;
+ WallpaperStyle meStyle;
+ ULONG mnRefCount;
+ BitmapEx* mpCache;
+
+ friend SvStream& operator>>( SvStream& rIStm, ImplWallpaper& rImplWallpaper );
+ friend SvStream& operator<<( SvStream& rOStm, const ImplWallpaper& rImplWallpaper );
+
+public:
+ ImplWallpaper();
+ ImplWallpaper( const ImplWallpaper& rImplWallpaper );
+ ~ImplWallpaper();
+
+ void ImplSetCachedBitmap( BitmapEx& rBmp );
+ const BitmapEx* ImplGetCachedBitmap() { return mpCache; }
+ void ImplReleaseCachedBitmap();
+};
+
+
+#endif // _SV_WALL2_HXX
diff --git a/vcl/inc/vcl/windata.hxx b/vcl/inc/vcl/windata.hxx
new file mode 100644
index 000000000000..9436352e4927
--- /dev/null
+++ b/vcl/inc/vcl/windata.hxx
@@ -0,0 +1,49 @@
+/*************************************************************************
+ *
+ * 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_WINDATA_HXX
+#define _SV_WINDATA_HXX
+
+#include <vcl/sv.h>
+
+class SalFrame;
+class Window;
+
+// --------------
+// - Prototypes -
+// --------------
+
+long ImplWindowFrameProc( Window* pInst, SalFrame* pFrame, USHORT nEvent, const void* pEvent );
+
+// -----------
+// - HitTest -
+// -----------
+
+#define WINDOW_HITTEST_INSIDE ((USHORT)0x0001)
+#define WINDOW_HITTEST_TRANSPARENT ((USHORT)0x0002)
+
+#endif // _SV_WINDATA_HXX
diff --git a/vcl/inc/vcl/window.h b/vcl/inc/vcl/window.h
new file mode 100644
index 000000000000..691c3ed18421
--- /dev/null
+++ b/vcl/inc/vcl/window.h
@@ -0,0 +1,372 @@
+/*************************************************************************
+ *
+ * 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_WINDOW_H
+#define _SV_WINDOW_H
+
+#include <vector>
+#include <vcl/sv.h>
+#include <vcl/outdev.hxx>
+#include <vcl/timer.hxx>
+#ifndef _SV_INPUTCTX_HXX
+#include <vcl/inputctx.hxx>
+#endif
+#ifndef _SV_POINTR_HXX
+#include <vcl/pointr.hxx>
+#endif
+#include <vcl/wintypes.hxx>
+#include <vcl/vclevent.hxx>
+#include <com/sun/star/uno/Reference.hxx>
+#include <cppuhelper/weakref.hxx>
+
+#include <vcl/salnativewidgets.hxx>
+
+#include <list>
+
+struct SalPaintEvent;
+struct ImplDelData;
+struct ImplAccessibleInfos;
+
+class Window;
+class VirtualDevice;
+class Cursor;
+class ImplDevFontList;
+class ImplFontCache;
+class SmartId;
+class VCLXWindow;
+class SalFrame;
+class SalObject;
+
+
+namespace com {
+namespace sun {
+namespace star {
+namespace accessibility {
+ class XAccessible;
+}}}}
+
+namespace com {
+namespace sun {
+namespace star {
+namespace rendering {
+ class XCanvas;
+}}}}
+
+namespace com {
+namespace sun {
+namespace star {
+namespace awt {
+ class XWindowPeer;
+ class XWindow;
+}
+namespace uno {
+ class Any;
+ class XInterface;
+}
+namespace datatransfer {
+namespace clipboard {
+ class XClipboard;
+}
+
+namespace dnd {
+ class XDropTargetListener;
+ class XDragGestureRecognizer;
+ class XDragSource;
+ class XDropTarget;
+} } } } }
+
+namespace vcl { struct ControlLayoutData; }
+
+
+
+
+// ---------------
+// - ImplWinData -
+// ---------------
+
+struct ImplWinData
+{
+ UniString* mpExtOldText;
+ USHORT* mpExtOldAttrAry;
+ Rectangle* mpCursorRect;
+ long mnCursorExtWidth;
+ Rectangle* mpFocusRect;
+ Rectangle* mpTrackRect;
+ USHORT mnTrackFlags;
+ USHORT mnIsTopWindow;
+ BOOL mbMouseOver; // tracks mouse over for native widget paint effect
+ BOOL mbEnableNativeWidget; // toggle native widget rendering
+ SmartId* mpSmartHelpId;
+ SmartId* mpSmartUniqueId;
+ ::std::list< Window* >
+ maTopWindowChildren;
+};
+
+// -------------------
+// - ImplOverlapData -
+// -------------------
+
+struct ImplOverlapData
+{
+ VirtualDevice* mpSaveBackDev; // Gesicherte Hintergrund-Bitmap
+ Region* mpSaveBackRgn; // Gesicherte Region, was invalidiert werden muss
+ Window* mpNextBackWin; // Naechstes Fenster mit Hintergrund-Sicherung
+ ULONG mnSaveBackSize; // Groesse Bitmap fuer Hintergrund-Sicherung
+ BOOL mbSaveBack; // TRUE: Background sichern
+ BYTE mnTopLevel; // Level for Overlap-Window
+};
+
+// -----------------
+// - ImplFrameData -
+// -----------------
+
+struct ImplFrameData
+{
+ Timer maPaintTimer; // paint timer
+ Timer maResizeTimer; // resize timer
+ InputContext maOldInputContext; // Last set Input Context
+ Window* mpNextFrame; // next frame window
+ Window* mpFirstOverlap; // first overlap window
+ Window* mpFocusWin; // focus window (is also set, when frame doesn't have the focous)
+ Window* mpMouseMoveWin; // last window, where MouseMove() called
+ Window* mpMouseDownWin; // last window, where MouseButtonDown() called
+ Window* mpFirstBackWin; // Erstes Overlap-Window mit Hintergrund-Sicherung
+ ::std::vector<Window *> maOwnerDrawList; // List of system windows with owner draw decoration
+ ImplDevFontList* mpFontList; // Font-List for this frame
+ ImplFontCache* mpFontCache; // Font-Cache for this frame
+ sal_Int32 mnDPIX; // Original Screen Resolution
+ sal_Int32 mnDPIY; // Original Screen Resolution
+ ImplMapRes maMapUnitRes; // for LogicUnitToPixel
+ ULONG mnAllSaveBackSize; // Groesse aller Bitmaps fuer Hintergrund-Sicherung
+ ULONG mnFocusId; // FocusId for PostUserLink
+ ULONG mnMouseMoveId; // MoveId for PostUserLink
+ long mnLastMouseX; // last x mouse position
+ long mnLastMouseY; // last y mouse position
+ long mnBeforeLastMouseX; // last but one x mouse position
+ long mnBeforeLastMouseY; // last but one y mouse position
+ long mnFirstMouseX; // first x mouse position by mousebuttondown
+ long mnFirstMouseY; // first y mouse position by mousebuttondown
+ long mnLastMouseWinX; // last x mouse position, rel. to pMouseMoveWin
+ long mnLastMouseWinY; // last y mouse position, rel. to pMouseMoveWin
+ USHORT mnModalMode; // frame based modal count (app based makes no sense anymore)
+ ULONG mnMouseDownTime; // mouse button down time for double click
+ USHORT mnClickCount; // mouse click count
+ USHORT mnFirstMouseCode; // mouse code by mousebuttondown
+ USHORT mnMouseCode; // mouse code
+ USHORT mnMouseMode; // mouse mode
+ MapUnit meMapUnit; // last MapUnit for LogicUnitToPixel
+ BOOL mbHasFocus; // focus
+ BOOL mbInMouseMove; // is MouseMove on stack
+ BOOL mbMouseIn; // is Mouse inside the frame
+ BOOL mbStartDragCalled; // is command startdrag called
+ BOOL mbNeedSysWindow; // set, when FrameSize <= IMPL_MIN_NEEDSYSWIN
+ BOOL mbMinimized; // set, when FrameSize <= 0
+ BOOL mbStartFocusState; // FocusState, beim abschicken des Events
+ BOOL mbInSysObjFocusHdl; // Innerhalb vom GetFocus-Handler eines SysChilds
+ BOOL mbInSysObjToTopHdl; // Innerhalb vom ToTop-Handler eines SysChilds
+ BOOL mbSysObjFocus; // Hat ein SysChild den Focus
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSource > mxDragSource;
+ ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDropTarget > mxDropTarget;
+ ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDropTargetListener > mxDropTargetListener;
+ ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboard > mxClipboard;
+ ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboard > mxSelection;
+
+ BOOL mbInternalDragGestureRecognizer;
+};
+
+// ---------------
+// - WindowImpl -
+// ---------------
+
+enum AlwaysInputMode { AlwaysInputNone = 0, AlwaysInputEnabled = 1, AlwaysInputDisabled =2 };
+
+class WindowImpl
+{
+public:
+ WindowImpl();
+ ~WindowImpl();
+
+ ImplWinData* mpWinData;
+ ImplOverlapData* mpOverlapData;
+ ImplFrameData* mpFrameData;
+ SalFrame* mpFrame;
+ SalObject* mpSysObj;
+ Window* mpFrameWindow;
+ Window* mpOverlapWindow;
+ Window* mpBorderWindow;
+ Window* mpClientWindow;
+ Window* mpParent;
+ Window* mpRealParent;
+ Window* mpFirstChild;
+ Window* mpLastChild;
+ Window* mpFirstOverlap;
+ Window* mpLastOverlap;
+ Window* mpPrev;
+ Window* mpNext;
+ Window* mpNextOverlap;
+ Window* mpLastFocusWindow;
+ Window* mpDlgCtrlDownWindow;
+ VclEventListeners maEventListeners;
+ VclEventListeners maChildEventListeners;
+
+ // The canvas interface for this VCL window. Is persistent after the first GetCanvas() call
+ ::com::sun::star::uno::WeakReference< ::com::sun::star::rendering::XCanvas > mxCanvas;
+
+ ImplDelData* mpFirstDel;
+ void* mpUserData;
+ Cursor* mpCursor;
+ Pointer maPointer;
+ Fraction maZoom;
+ XubString maText;
+ Font* mpControlFont;
+ Color maControlForeground;
+ Color maControlBackground;
+ sal_Int32 mnLeftBorder;
+ sal_Int32 mnTopBorder;
+ sal_Int32 mnRightBorder;
+ sal_Int32 mnBottomBorder;
+ long mnX;
+ long mnY;
+ long mnAbsScreenX;
+ Point maPos;
+ ULONG mnHelpId;
+ ULONG mnUniqId;
+ XubString maHelpText;
+ XubString maQuickHelpText;
+ InputContext maInputContext;
+ ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindowPeer > mxWindowPeer;
+ ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > mxAccessible;
+ ImplAccessibleInfos* mpAccessibleInfos;
+ VCLXWindow* mpVCLXWindow;
+ Region maWinRegion; // region to 'shape' the VCL window (frame coordinates)
+ Region maWinClipRegion; // the (clipping) region that finally corresponds to the VCL window (frame coordinates)
+ Region maInvalidateRegion; // region that has to be redrawn (frame coordinates)
+ Region* mpChildClipRegion; // child clip region if CLIPCHILDREN is set (frame coordinates)
+ Region* mpPaintRegion; // only set during Paint() method call (window coordinates)
+ WinBits mnStyle;
+ WinBits mnPrevStyle;
+ WinBits mnExtendedStyle;
+ WinBits mnPrevExtendedStyle;
+ WindowType mnType;
+ ControlPart mnNativeBackground;
+ USHORT mnWaitCount;
+ USHORT mnPaintFlags;
+ USHORT mnGetFocusFlags;
+ USHORT mnParentClipMode;
+ USHORT mnActivateMode;
+ USHORT mnDlgCtrlFlags;
+ USHORT mnLockCount;
+ AlwaysInputMode meAlwaysInputMode;
+ BOOL mbFrame:1,
+ mbBorderWin:1,
+ mbOverlapWin:1,
+ mbSysWin:1,
+ mbDialog:1,
+ mbDockWin:1,
+ mbFloatWin:1,
+ mbPushButton:1,
+ mbVisible:1,
+ mbDisabled:1,
+ mbInputDisabled:1,
+ mbDropDisabled:1,
+ mbNoUpdate:1,
+ mbNoParentUpdate:1,
+ mbActive:1,
+ mbParentActive:1,
+ mbReallyVisible:1,
+ mbReallyShown:1,
+ mbInInitShow:1,
+ mbChildNotify:1,
+ mbChildPtrOverwrite:1,
+ mbNoPtrVisible:1,
+ mbPaintFrame:1,
+ mbInPaint:1,
+ mbMouseMove:1,
+ mbMouseButtonDown:1,
+ mbMouseButtonUp:1,
+ mbKeyInput:1,
+ mbKeyUp:1,
+ mbCommand:1,
+ mbDefPos:1,
+ mbDefSize:1,
+ mbCallMove:1,
+ mbCallResize:1,
+ mbWaitSystemResize:1,
+ mbInitWinClipRegion:1,
+ mbInitChildRegion:1,
+ mbWinRegion:1,
+ mbClipChildren:1,
+ mbClipSiblings:1,
+ mbChildTransparent:1,
+ mbPaintTransparent:1,
+ mbMouseTransparent:1,
+ mbDlgCtrlStart:1,
+ mbFocusVisible:1,
+ mbTrackVisible:1,
+ mbUseNativeFocus:1,
+ mbNativeFocusVisible:1,
+ mbInShowFocus:1,
+ mbInHideFocus:1,
+ mbControlForeground:1,
+ mbControlBackground:1,
+ mbAlwaysOnTop:1,
+ mbCompoundControl:1,
+ mbCompoundControlHasFocus:1,
+ mbPaintDisabled:1,
+ mbAllResize:1,
+ mbInDtor:1,
+ mbExtTextInput:1,
+ mbInFocusHdl:1,
+ mbOverlapVisible:1,
+ mbCreatedWithToolkit:1,
+ mbToolBox:1,
+ mbSplitter:1,
+ mbSuppressAccessibilityEvents:1,
+ mbMenuFloatingWindow:1,
+ mbDrawSelectionBackground:1,
+ mbIsInTaskPaneList:1,
+ mbToolbarFloatingWindow:1,
+ mbCallHandlersDuringInputDisabled:1,
+ mbDisableAccessibleLabelForRelation:1,
+ mbDisableAccessibleLabeledByRelation:1,
+ mbHelpTextDynamic:1,
+ mbFakeFocusSet:1;
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > mxDNDListenerContainer;
+};
+
+// -----------------
+// - Hilfsmethoden -
+// -----------------
+
+long ImplHandleMouseEvent( Window* pWindow, USHORT nSVEvent, BOOL bMouseLeave,
+ long nX, long nY, ULONG nMsgTime,
+ USHORT nCode, USHORT nMode );
+void ImplHandleResize( Window* pWindow, long nNewWidth, long nNewHeight );
+
+#endif // _SV_WINDOW_H
diff --git a/vcl/inc/vcl/window.hxx b/vcl/inc/vcl/window.hxx
new file mode 100644
index 000000000000..8264767e59ad
--- /dev/null
+++ b/vcl/inc/vcl/window.hxx
@@ -0,0 +1,1109 @@
+/*************************************************************************
+ *
+ * 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_WINDOW_HXX
+#define _SV_WINDOW_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/outdev.hxx>
+#include <tools/resid.hxx>
+#ifndef _SV_POINTR_HXX
+#include <vcl/pointr.hxx>
+#endif
+#include <vcl/wintypes.hxx>
+#ifndef _SV_APPTYPES_HXX
+#include <vcl/apptypes.hxx>
+#endif
+#include <vcl/inputctx.hxx>
+#include <vcl/vclevent.hxx>
+// Only for compatibility - because many people outside haven't included event.hxx
+#ifndef _VCL_EVENT_HXX
+#include <vcl/event.hxx>
+#endif
+#include <vcl/region.hxx>
+#include <vcl/salnativewidgets.hxx>
+#include <rtl/ustring.hxx>
+#include <cppuhelper/weakref.hxx>
+#include <com/sun/star/uno/Reference.hxx>
+#include <vcl/smartid.hxx>
+
+class VirtualDevice;
+struct ImplDelData;
+struct ImplWinData;
+struct ImplOverlapData;
+struct ImplFrameData;
+struct ImplCalcToTopData;
+struct SystemEnvData;
+struct SystemParentData;
+class ImplBorderWindow;
+class VirtualDevice;
+class Timer;
+class Cursor;
+class DockingManager;
+class ScrollBar;
+class Bitmap;
+class Image;
+class MouseEvent;
+class KeyEvent;
+class CommandEvent;
+class TrackingEvent;
+class HelpEvent;
+class DataChangedEvent;
+class NotifyEvent;
+class SystemWindow;
+class SalFrame;
+class SalObject;
+class MenuFloatingWindow;
+class UNOWindowData;
+// Nur fuer ExecuteDrag:
+struct IDataObject;
+class VCLXWindow;
+struct ImplAccessibleInfos;
+
+namespace com {
+namespace sun {
+namespace star {
+namespace accessibility {
+ class XAccessible;
+}}}}
+
+namespace com {
+namespace sun {
+namespace star {
+namespace rendering {
+ class XCanvas;
+ class XSpriteCanvas;
+}}}}
+
+namespace com {
+namespace sun {
+namespace star {
+namespace awt {
+ class XWindowPeer;
+ class XWindow;
+}
+namespace uno {
+ class Any;
+ class XInterface;
+}
+namespace datatransfer {
+namespace clipboard {
+ class XClipboard;
+}
+
+namespace dnd {
+ class XDragGestureRecognizer;
+ class XDragSource;
+ class XDropTarget;
+} } } } }
+
+namespace vcl { struct ControlLayoutData; }
+
+namespace svt { class PopupWindowControllerImpl; }
+
+// ---------------
+// - WindowTypes -
+// ---------------
+
+// Type fuer GetWindow()
+#define WINDOW_PARENT ((USHORT)0)
+#define WINDOW_FIRSTCHILD ((USHORT)1)
+#define WINDOW_LASTCHILD ((USHORT)2)
+#define WINDOW_PREV ((USHORT)3)
+#define WINDOW_NEXT ((USHORT)4)
+#define WINDOW_FIRSTOVERLAP ((USHORT)5)
+#define WINDOW_LASTOVERLAP ((USHORT)6)
+#define WINDOW_OVERLAP ((USHORT)7)
+#define WINDOW_PARENTOVERLAP ((USHORT)8)
+#define WINDOW_CLIENT ((USHORT)9)
+#define WINDOW_REALPARENT ((USHORT)10)
+#define WINDOW_FRAME ((USHORT)11)
+#define WINDOW_BORDER ((USHORT)12)
+#define WINDOW_FIRSTTOPWINDOWCHILD ((USHORT)13)
+#define WINDOW_LASTTOPWINDOWCHILD ((USHORT)14)
+#define WINDOW_PREVTOPWINDOWSIBLING ((USHORT)15)
+#define WINDOW_NEXTTOPWINDOWSIBLING ((USHORT)16)
+
+// Flags for SetPosSizePixel()
+#define WINDOW_POSSIZE_X ((USHORT)0x0001)
+#define WINDOW_POSSIZE_Y ((USHORT)0x0002)
+#define WINDOW_POSSIZE_WIDTH ((USHORT)0x0004)
+#define WINDOW_POSSIZE_HEIGHT ((USHORT)0x0008)
+#define WINDOW_POSSIZE_POS (WINDOW_POSSIZE_X | WINDOW_POSSIZE_Y)
+#define WINDOW_POSSIZE_SIZE (WINDOW_POSSIZE_WIDTH | WINDOW_POSSIZE_HEIGHT)
+#define WINDOW_POSSIZE_POSSIZE (WINDOW_POSSIZE_POS | WINDOW_POSSIZE_SIZE)
+#define WINDOW_POSSIZE_ALL (WINDOW_POSSIZE_POSSIZE)
+#define WINDOW_POSSIZE_DROPDOWN ((USHORT)0x0010)
+
+// Flags for Show()
+#define SHOW_NOPARENTUPDATE ((USHORT)0x0001)
+#define SHOW_NOFOCUSCHANGE ((USHORT)0x0002)
+#define SHOW_NOACTIVATE ((USHORT)0x0004)
+#define SHOW_FOREGROUNDTASK ((USHORT)0x0008)
+
+// Flags for SetZOrder()
+#define WINDOW_ZORDER_BEFOR ((USHORT)0x0001)
+#define WINDOW_ZORDER_BEHIND ((USHORT)0x0002)
+#define WINDOW_ZORDER_FIRST ((USHORT)0x0004)
+#define WINDOW_ZORDER_LAST ((USHORT)0x0008)
+
+// Activate-Flags
+#define ACTIVATE_MODE_GRABFOCUS ((USHORT)0x0001)
+
+// ToTop-Flags
+#define TOTOP_RESTOREWHENMIN ((USHORT)0x0001)
+#define TOTOP_FOREGROUNDTASK ((USHORT)0x0002)
+#define TOTOP_NOGRABFOCUS ((USHORT)0x0004)
+//#if 0 // _SOLAR__PRIVATE // vcl internal only
+#define TOTOP_GRABFOCUSONLY ((USHORT)0x0008)
+//#endif
+
+// Flags for Invalidate
+#define INVALIDATE_CHILDREN ((USHORT)0x0001)
+#define INVALIDATE_NOCHILDREN ((USHORT)0x0002)
+#define INVALIDATE_NOERASE ((USHORT)0x0004)
+#define INVALIDATE_UPDATE ((USHORT)0x0008)
+#define INVALIDATE_TRANSPARENT ((USHORT)0x0010)
+#define INVALIDATE_NOTRANSPARENT ((USHORT)0x0020)
+#define INVALIDATE_NOCLIPCHILDREN ((USHORT)0x4000)
+// Temporaer fuer Kompatibilitaet
+#define INVALIDATE_BACKGROUND INVALIDATE_TRANSPARENT
+
+// Flags for Validate
+#define VALIDATE_CHILDREN ((USHORT)0x0001)
+#define VALIDATE_NOCHILDREN ((USHORT)0x0002)
+
+// Flags for Scroll
+#define SCROLL_CLIP ((USHORT)0x0001)
+#define SCROLL_CHILDREN ((USHORT)0x0002)
+#define SCROLL_NOCHILDREN ((USHORT)0x0004)
+#define SCROLL_NOERASE ((USHORT)0x0008)
+#define SCROLL_NOINVALIDATE ((USHORT)0x0010)
+#define SCROLL_NOWINDOWINVALIDATE ((USHORT)0x0020)
+#define SCROLL_USECLIPREGION ((USHORT)0x0040)
+#define SCROLL_UPDATE ((USHORT)0x0080)
+
+// Flags for ParentClipMode
+#define PARENTCLIPMODE_CLIP ((USHORT)0x0001)
+#define PARENTCLIPMODE_NOCLIP ((USHORT)0x0002)
+
+// Flags for Invert()
+#define INVERT_HIGHLIGHT ((USHORT)0x0001)
+#define INVERT_50 ((USHORT)0x0002)
+
+// Flags for ShowTracking()
+#define SHOWTRACK_SMALL ((USHORT)0x0001)
+#define SHOWTRACK_BIG ((USHORT)0x0002)
+#define SHOWTRACK_SPLIT ((USHORT)0x0003)
+#define SHOWTRACK_OBJECT ((USHORT)0x0004)
+#define SHOWTRACK_WINDOW ((USHORT)0x1000)
+#define SHOWTRACK_CLIP ((USHORT)0x2000)
+#define SHOWTRACK_STYLE ((USHORT)0x000F)
+
+// Flags for StartTracking()
+#define STARTTRACK_KEYINPUT ((USHORT)0x0001)
+#define STARTTRACK_KEYMOD ((USHORT)0x0002)
+#define STARTTRACK_NOKEYCANCEL ((USHORT)0x0004)
+#define STARTTRACK_SCROLLREPEAT ((USHORT)0x0008)
+#define STARTTRACK_BUTTONREPEAT ((USHORT)0x0010)
+#define STARTTRACK_MOUSEBUTTONDOWN ((USHORT)0x0020)
+#define STARTTRACK_FOCUSCANCEL ((USHORT)0x0040)
+
+// Flags for StartAutoScroll()
+#define AUTOSCROLL_VERT ((USHORT)0x0001)
+#define AUTOSCROLL_HORZ ((USHORT)0x0002)
+
+// Flags for StateChanged()
+typedef USHORT StateChangedType;
+#define STATE_CHANGE_INITSHOW ((StateChangedType)1)
+#define STATE_CHANGE_VISIBLE ((StateChangedType)2)
+#define STATE_CHANGE_UPDATEMODE ((StateChangedType)3)
+#define STATE_CHANGE_ENABLE ((StateChangedType)4)
+#define STATE_CHANGE_TEXT ((StateChangedType)5)
+#define STATE_CHANGE_IMAGE ((StateChangedType)6)
+#define STATE_CHANGE_DATA ((StateChangedType)7)
+#define STATE_CHANGE_STATE ((StateChangedType)8)
+#define STATE_CHANGE_STYLE ((StateChangedType)9)
+#define STATE_CHANGE_ZOOM ((StateChangedType)10)
+#define STATE_CHANGE_BORDER ((StateChangedType)11)
+#define STATE_CHANGE_TRANSPARENT ((StateChangedType)12)
+#define STATE_CHANGE_CONTROLFONT ((StateChangedType)13)
+#define STATE_CHANGE_CONTROLFOREGROUND ((StateChangedType)14)
+#define STATE_CHANGE_CONTROLBACKGROUND ((StateChangedType)15)
+#define STATE_CHANGE_READONLY ((StateChangedType)16)
+#define STATE_CHANGE_FORMAT ((StateChangedType)17)
+#define STATE_CHANGE_EXTENDEDSTYLE ((StateChangedType)18)
+#define STATE_CHANGE_MIRRORING ((StateChangedType)19)
+#define STATE_CHANGE_USER ((StateChangedType)10000)
+
+// GetFocusFlags
+#define GETFOCUS_TAB ((USHORT)0x0001)
+#define GETFOCUS_CURSOR ((USHORT)0x0002)
+#define GETFOCUS_MNEMONIC ((USHORT)0x0004)
+#define GETFOCUS_FORWARD ((USHORT)0x0010)
+#define GETFOCUS_BACKWARD ((USHORT)0x0020)
+#define GETFOCUS_AROUND ((USHORT)0x0040)
+#define GETFOCUS_UNIQUEMNEMONIC ((USHORT)0x0100)
+#define GETFOCUS_INIT ((USHORT)0x0200)
+#define GETFOCUS_FLOATWIN_POPUPMODEEND_CANCEL ((USHORT)0x0400)
+
+// Draw-Flags fuer Draw()
+#define WINDOW_DRAW_MONO ((ULONG)0x00000001)
+#define WINDOW_DRAW_NOBORDER ((ULONG)0x00000002)
+#define WINDOW_DRAW_NOCONTROLS ((ULONG)0x00000004)
+#define WINDOW_DRAW_NODISABLE ((ULONG)0x00000008)
+#define WINDOW_DRAW_NOMNEMONIC ((ULONG)0x00000010)
+#define WINDOW_DRAW_NOSELECTION ((ULONG)0x00000020)
+#define WINDOW_DRAW_NOFOCUS ((ULONG)0x00000040)
+#define WINDOW_DRAW_NOBACKGROUND ((ULONG)0x00000080)
+#define WINDOW_DRAW_ROLLOVER ((ULONG)0x00000100)
+
+// Border-Styles fuer SetBorder()
+#define WINDOW_BORDER_NORMAL ((USHORT)0x0001)
+#define WINDOW_BORDER_MONO ((USHORT)0x0002)
+#define WINDOW_BORDER_ACTIVE ((USHORT)0x0004)
+#define WINDOW_BORDER_DOUBLEOUT ((USHORT)0x0008)
+#define WINDOW_BORDER_MENU ((USHORT)0x0010)
+#define WINDOW_BORDER_NOBORDER ((USHORT)0x1000)
+#define WINDOW_BORDER_REMOVEBORDER ((USHORT)0x2000)
+
+// DialogControl-Flags
+#define WINDOW_DLGCTRL_RETURN ((USHORT)0x0001)
+#define WINDOW_DLGCTRL_WANTFOCUS ((USHORT)0x0002)
+#define WINDOW_DLGCTRL_MOD1TAB ((USHORT)0x0004)
+#define WINDOW_DLGCTRL_FLOATWIN_POPUPMODEEND_CANCEL ((USHORT)0x0008)
+
+// GetWindowClipRegionPixel-Flags
+#define WINDOW_GETCLIPREGION_NULL ((USHORT)0x0001)
+#define WINDOW_GETCLIPREGION_NOCHILDREN ((USHORT)0x0002)
+
+// EndExtTextInput-Flags
+#define EXTTEXTINPUT_END_COMPLETE ((USHORT)0x0001)
+#define EXTTEXTINPUT_END_CANCEL ((USHORT)0x0002)
+
+//#if 0 // _SOLAR__PRIVATE
+#define IMPL_MINSIZE_BUTTON_WIDTH 70
+#define IMPL_MINSIZE_BUTTON_HEIGHT 22
+#define IMPL_EXTRA_BUTTON_WIDTH 18
+#define IMPL_EXTRA_BUTTON_HEIGHT 10
+#define IMPL_SEP_BUTTON_X 5
+#define IMPL_SEP_BUTTON_Y 5
+#define IMPL_MINSIZE_MSGBOX_WIDTH 150
+#define IMPL_MINSIZE_MSGBOX_HEIGHT 80
+#define IMPL_DIALOG_OFFSET 5
+#define IMPL_DIALOG_BAR_OFFSET 3
+#define IMPL_MSGBOX_OFFSET_EXTRA_X 0
+#define IMPL_MSGBOX_OFFSET_EXTRA_Y 2
+#define IMPL_SEP_MSGBOX_IMAGE 8
+
+#define DLGWINDOW_PREV 0
+#define DLGWINDOW_NEXT 1
+#define DLGWINDOW_FIRST 2
+//#endif
+
+enum WindowSizeType {
+ WINDOWSIZE_MINIMUM,
+ WINDOWSIZE_PREFERRED,
+ WINDOWSIZE_MAXIMUM
+};
+
+// ----------
+// - Window -
+// ----------
+
+#ifdef DBG_UTIL
+const char* ImplDbgCheckWindow( const void* pObj );
+#endif
+
+class WindowImpl;
+class VCL_DLLPUBLIC Window : public OutputDevice
+{
+ friend class Cursor;
+ friend class OutputDevice;
+ friend class Application;
+ friend class SystemWindow;
+ friend class WorkWindow;
+ friend class Dialog;
+ friend class MessBox;
+ friend class DockingWindow;
+ friend class FloatingWindow;
+ friend class GroupBox;
+ friend class PushButton;
+ friend class RadioButton;
+ friend class SystemChildWindow;
+ friend class ImplBorderWindow;
+
+ // TODO: improve missing functionality
+ // only required because of SetFloatingMode()
+ friend class ImplDockingWindowWrapper;
+ friend class ImplPopupFloatWin;
+ friend class MenuFloatingWindow;
+
+ friend class svt::PopupWindowControllerImpl;
+
+private:
+ // NOTE: to remove many dependencies of other modules
+ // to this central file, all members are now hidden
+ // in the WindowImpl class and all inline functions
+ // were removed
+ //
+ // Please do *not* add new members or inline functions to class Window,
+ // but use class WindowImpl instead
+ //
+ WindowImpl* mpWindowImpl;
+
+ SAL_DLLPRIVATE void ImplInitWindowData( WindowType nType );
+
+#ifdef DBG_UTIL
+ friend const char* ImplDbgCheckWindow( const void* pObj );
+#endif
+ friend Window* ImplFindWindow( const SalFrame* pFrame, Point& rSalFramePos );
+public:
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle, SystemParentData* pSystemParentData );
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle, const ::com::sun::star::uno::Any& aSystemWorkWindowToken );
+ SAL_DLLPRIVATE WinBits ImplInitRes( const ResId& rResId );
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+ SAL_DLLPRIVATE void ImplWindowRes( const ResId& rResId );
+ SAL_DLLPRIVATE void ImplSetFrameParent( const Window* pParent );
+ SAL_DLLPRIVATE void ImplInsertWindow( Window* pParent );
+ SAL_DLLPRIVATE void ImplRemoveWindow( BOOL bRemoveFrameData );
+ SAL_DLLPRIVATE Window* ImplGetWindow();
+ SAL_DLLPRIVATE ImplFrameData* ImplGetFrameData();
+ SAL_DLLPRIVATE SalFrame* ImplGetFrame() const;
+ SAL_DLLPRIVATE ImplWinData* ImplGetWinData() const;
+ SAL_DLLPRIVATE SalGraphics* ImplGetFrameGraphics() const;
+ SAL_DLLPRIVATE void ImplCallFocusChangeActivate( Window* pNewOverlapWindow, Window* pOldOverlapWindow );
+ SAL_DLLPRIVATE Window* ImplFindWindow( const Point& rFramePos );
+ SAL_DLLPRIVATE USHORT ImplHitTest( const Point& rFramePos );
+ SAL_DLLPRIVATE Window* ImplGetParent() const;
+ SAL_DLLPRIVATE Window* ImplGetClientWindow() const;
+ SAL_DLLPRIVATE Window* ImplGetBorderWindow() const;
+ SAL_DLLPRIVATE Window* ImplGetFirstOverlapWindow();
+ SAL_DLLPRIVATE const Window* ImplGetFirstOverlapWindow() const;
+ SAL_DLLPRIVATE Window* ImplGetFrameWindow() const;
+ SAL_DLLPRIVATE BOOL ImplIsRealParentPath( const Window* pWindow ) const;
+ SAL_DLLPRIVATE BOOL ImplIsChild( const Window* pWindow, BOOL bSystemWindow = FALSE ) const;
+ SAL_DLLPRIVATE BOOL ImplIsWindowOrChild( const Window* pWindow, BOOL bSystemWindow = FALSE ) const;
+ SAL_DLLPRIVATE Window* ImplGetSameParent( const Window* pWindow ) const;
+ SAL_DLLPRIVATE BOOL ImplIsDockingWindow() const;
+ SAL_DLLPRIVATE BOOL ImplIsFloatingWindow() const;
+ SAL_DLLPRIVATE BOOL ImplIsToolbox() const;
+ SAL_DLLPRIVATE BOOL ImplIsSplitter() const;
+ SAL_DLLPRIVATE BOOL ImplIsPushButton() const;
+ SAL_DLLPRIVATE BOOL ImplIsOverlapWindow() const;
+ SAL_DLLPRIVATE void ImplSetActive( BOOL bActive );
+ SAL_DLLPRIVATE BOOL ImplIsMouseTransparent() const;
+ SAL_DLLPRIVATE void ImplSetMouseTransparent( BOOL bTransparent );
+ SAL_DLLPRIVATE int ImplTestMousePointerSet();
+ SAL_DLLPRIVATE PointerStyle ImplGetMousePointer() const;
+ SAL_DLLPRIVATE void ImplResetReallyVisible();
+ SAL_DLLPRIVATE void ImplSetReallyVisible();
+ SAL_DLLPRIVATE void ImplCallInitShow();
+ SAL_DLLPRIVATE void ImplAddDel( ImplDelData* pDel );
+ SAL_DLLPRIVATE void ImplRemoveDel( ImplDelData* pDel );
+ SAL_DLLPRIVATE void ImplInitResolutionSettings();
+ SAL_DLLPRIVATE void ImplPointToLogic( Font& rFont ) const;
+ SAL_DLLPRIVATE void ImplLogicToPoint( Font& rFont ) const;
+ SAL_DLLPRIVATE Point ImplOutputToFrame( const Point& rPos );
+ SAL_DLLPRIVATE Point ImplFrameToOutput( const Point& rPos );
+ SAL_DLLPRIVATE void ImplOutputToFrame( Rectangle& rRect );
+ SAL_DLLPRIVATE void ImplFrameToOutput( Rectangle& rRect );
+ SAL_DLLPRIVATE BOOL ImplSysObjClip( const Region* pOldRegion );
+ SAL_DLLPRIVATE void ImplUpdateSysObjChildsClip();
+ SAL_DLLPRIVATE void ImplUpdateSysObjOverlapsClip();
+ SAL_DLLPRIVATE void ImplUpdateSysObjClip();
+ SAL_DLLPRIVATE BOOL ImplSetClipFlagChilds( BOOL bSysObjOnlySmaller = FALSE );
+ SAL_DLLPRIVATE BOOL ImplSetClipFlagOverlapWindows( BOOL bSysObjOnlySmaller = FALSE );
+ SAL_DLLPRIVATE BOOL ImplSetClipFlag( BOOL bSysObjOnlySmaller = FALSE );
+ SAL_DLLPRIVATE void ImplIntersectWindowClipRegion( Region& rRegion );
+ SAL_DLLPRIVATE void ImplIntersectWindowRegion( Region& rRegion );
+ SAL_DLLPRIVATE void ImplExcludeWindowRegion( Region& rRegion );
+ SAL_DLLPRIVATE void ImplExcludeOverlapWindows( Region& rRegion );
+ SAL_DLLPRIVATE void ImplExcludeOverlapWindows2( Region& rRegion );
+ SAL_DLLPRIVATE void ImplClipBoundaries( Region& rRegion, BOOL bThis, BOOL bOverlaps );
+ SAL_DLLPRIVATE BOOL ImplClipChilds( Region& rRegion );
+ SAL_DLLPRIVATE void ImplClipAllChilds( Region& rRegion );
+ SAL_DLLPRIVATE void ImplClipSiblings( Region& rRegion );
+ SAL_DLLPRIVATE void ImplInitWinClipRegion();
+ SAL_DLLPRIVATE void ImplInitWinChildClipRegion();
+ SAL_DLLPRIVATE Region* ImplGetWinChildClipRegion();
+ SAL_DLLPRIVATE void ImplIntersectAndUnionOverlapWindows( const Region& rInterRegion, Region& rRegion );
+ SAL_DLLPRIVATE void ImplIntersectAndUnionOverlapWindows2( const Region& rInterRegion, Region& rRegion );
+ SAL_DLLPRIVATE void ImplCalcOverlapRegionOverlaps( const Region& rInterRegion, Region& rRegion );
+ SAL_DLLPRIVATE void ImplCalcOverlapRegion( const Rectangle& rSourceRect, Region& rRegion,
+ BOOL bChilds, BOOL bParent, BOOL bSiblings );
+ SAL_DLLPRIVATE void ImplCallPaint( const Region* pRegion, USHORT nPaintFlags );
+ SAL_DLLPRIVATE void ImplCallOverlapPaint();
+ SAL_DLLPRIVATE void ImplPostPaint();
+ SAL_DLLPRIVATE void ImplInvalidateFrameRegion( const Region* pRegion, USHORT nFlags );
+ SAL_DLLPRIVATE void ImplInvalidateOverlapFrameRegion( const Region& rRegion );
+ SAL_DLLPRIVATE void ImplInvalidateParentFrameRegion( Region& rRegion );
+ SAL_DLLPRIVATE void ImplInvalidate( const Region* rRegion, USHORT nFlags );
+ SAL_DLLPRIVATE void ImplValidateFrameRegion( const Region* rRegion, USHORT nFlags );
+ SAL_DLLPRIVATE void ImplValidate( const Region* rRegion, USHORT nFlags );
+ SAL_DLLPRIVATE void ImplMoveInvalidateRegion( const Rectangle& rRect, long nHorzScroll, long nVertScroll, BOOL bChilds );
+ SAL_DLLPRIVATE void ImplMoveAllInvalidateRegions( const Rectangle& rRect, long nHorzScroll, long nVertScroll, BOOL bChilds );
+ SAL_DLLPRIVATE void ImplScroll( const Rectangle& rRect, long nHorzScroll, long nVertScroll, USHORT nFlags );
+ SAL_DLLPRIVATE void ImplUpdateAll( BOOL bOverlapWindows = TRUE );
+ SAL_DLLPRIVATE void ImplUpdateWindowPtr( Window* pWindow );
+ SAL_DLLPRIVATE void ImplUpdateWindowPtr();
+ SAL_DLLPRIVATE void ImplUpdateOverlapWindowPtr( BOOL bNewFrame );
+ SAL_DLLPRIVATE BOOL ImplUpdatePos();
+ SAL_DLLPRIVATE void ImplUpdateSysObjPos();
+ SAL_DLLPRIVATE WindowImpl* ImplGetWindowImpl() const { return mpWindowImpl; }
+ /** check whether a font is suitable for UI
+
+ The font to be tested will be checked whether it could display a
+ localized test string. If this is not the case, then the font
+ is deemed unsuitable as UI font.
+
+ @param rFont
+ the font to be tested
+
+ @returns
+ <TRUE/> if the font can be used as UI font
+ <FALSE/> if the font is unsuitable as UI font
+ */
+ SAL_DLLPRIVATE bool ImplCheckUIFont( const Font& rFont );
+ SAL_DLLPRIVATE void ImplUpdateGlobalSettings( AllSettings& rSettings, BOOL bCallHdl = TRUE );
+ SAL_DLLPRIVATE void ImplAlignChilds();
+ SAL_DLLPRIVATE void ImplPosSizeWindow( long nX, long nY, long nWidth, long nHeight, USHORT nFlags );
+ SAL_DLLPRIVATE void ImplToBottomChild();
+ SAL_DLLPRIVATE void ImplCalcToTop( ImplCalcToTopData* pPrevData );
+ SAL_DLLPRIVATE void ImplCalcChildOverlapToTop( ImplCalcToTopData* pPrevData );
+ SAL_DLLPRIVATE void ImplToTop( USHORT nFlags );
+ SAL_DLLPRIVATE void ImplStartToTop( USHORT nFlags );
+ SAL_DLLPRIVATE void ImplFocusToTop( USHORT nFlags, BOOL bReallyVisible );
+ SAL_DLLPRIVATE void ImplShowAllOverlaps();
+ SAL_DLLPRIVATE void ImplHideAllOverlaps();
+ SAL_DLLPRIVATE void ImplNotifyKeyMouseCommandEventListeners( NotifyEvent& rNEvt );
+ SAL_DLLPRIVATE void ImplCallMouseMove( USHORT nMouseCode, BOOL bModChanged = FALSE );
+ SAL_DLLPRIVATE void ImplGenerateMouseMove();
+ SAL_DLLPRIVATE void ImplGrabFocus( USHORT nFlags );
+ SAL_DLLPRIVATE void ImplInvertFocus( const Rectangle& rRect );
+ SAL_DLLPRIVATE void ImplControlFocus( USHORT nFlags = 0 );
+ SAL_DLLPRIVATE Window* ImplGetDlgWindow( USHORT n, USHORT nType, USHORT nStart = 0, USHORT nEnd = 0xFFFF, USHORT* pIndex = NULL );
+ SAL_DLLPRIVATE BOOL ImplDlgCtrl( const KeyEvent& rKEvt, BOOL bKeyInput );
+ SAL_DLLPRIVATE BOOL ImplHasDlgCtrl();
+ SAL_DLLPRIVATE void ImplDlgCtrlNextWindow();
+ SAL_DLLPRIVATE void ImplDlgCtrlFocusChanged( Window* pWindow, BOOL bGetFocus );
+ SAL_DLLPRIVATE Window* ImplFindDlgCtrlWindow( Window* pWindow );
+ SAL_DLLPRIVATE long ImplLogicUnitToPixelX( long nX, MapUnit eUnit );
+ SAL_DLLPRIVATE long ImplLogicUnitToPixelY( long nY, MapUnit eUnit );
+ SAL_DLLPRIVATE BOOL ImplIsWindowInFront( const Window* pTestWindow ) const;
+ SAL_DLLPRIVATE void ImplSaveOverlapBackground();
+ SAL_DLLPRIVATE BOOL ImplRestoreOverlapBackground( Region& rInvRegion );
+ SAL_DLLPRIVATE void ImplDeleteOverlapBackground();
+ SAL_DLLPRIVATE void ImplInvalidateAllOverlapBackgrounds();
+ SAL_DLLPRIVATE static void ImplNewInputContext();
+ SAL_DLLPRIVATE void ImplCallActivateListeners(Window*);
+ SAL_DLLPRIVATE void ImplCallDeactivateListeners(Window*);
+ DECL_DLLPRIVATE_LINK( ImplHandlePaintHdl, void* );
+ DECL_DLLPRIVATE_LINK( ImplGenerateMouseMoveHdl, void* );
+ DECL_DLLPRIVATE_LINK( ImplTrackTimerHdl, Timer* );
+ DECL_DLLPRIVATE_LINK( ImplAsyncFocusHdl, void* );
+ DECL_DLLPRIVATE_LINK( ImplAsyncStateChangedHdl, void* );
+ DECL_DLLPRIVATE_LINK( ImplHideOwnerDrawWindowsHdl, void* );
+ DECL_DLLPRIVATE_LINK( ImplHandleResizeTimerHdl, void* );
+
+ SAL_DLLPRIVATE static void ImplCalcSymbolRect( Rectangle& rRect );
+ SAL_DLLPRIVATE void ImplHandleScroll( ScrollBar* pHScrl, long nX, ScrollBar* pVScrl, long nY );
+ SAL_DLLPRIVATE BOOL ImplGetCurrentBackgroundColor( Color& rCol );
+ SAL_DLLPRIVATE BOOL ImplIsAccessibleCandidate() const;
+ SAL_DLLPRIVATE BOOL ImplIsAccessibleNativeFrame() const;
+ SAL_DLLPRIVATE USHORT ImplGetAccessibleCandidateChildWindowCount( USHORT nFirstWindowType ) const;
+ SAL_DLLPRIVATE Window* ImplGetAccessibleCandidateChild( USHORT nChild, USHORT& rChildCount, USHORT nFirstWindowType, BOOL bTopLevel = TRUE ) const;
+ SAL_DLLPRIVATE BOOL ImplRegisterAccessibleNativeFrame();
+ SAL_DLLPRIVATE void ImplRevokeAccessibleNativeFrame();
+ SAL_DLLPRIVATE void ImplCallResize();
+ SAL_DLLPRIVATE void ImplCallMove();
+ SAL_DLLPRIVATE Rectangle ImplOutputToUnmirroredAbsoluteScreenPixel( const Rectangle& rRect ) const;
+ SAL_DLLPRIVATE void ImplMirrorFramePos( Point &pt ) const;
+ SAL_DLLPRIVATE long ImplGetUnmirroredOutOffX();
+ SAL_DLLPRIVATE void ImplIncModalCount();
+ SAL_DLLPRIVATE void ImplDecModalCount();
+
+ // retrieves the list of owner draw decorated windows for this window hiearchy
+ SAL_DLLPRIVATE ::std::vector<Window *>& ImplGetOwnerDrawList();
+ SAL_DLLPRIVATE Window* ImplGetTopmostFrameWindow();
+
+ SAL_DLLPRIVATE Rectangle ImplGetWindowExtentsRelative( Window *pRelativeWindow, BOOL bClientOnly ) const;
+ SAL_DLLPRIVATE void ImplNotifyIconifiedState( BOOL bIconified );
+ SAL_DLLPRIVATE bool ImplStopDnd();
+ SAL_DLLPRIVATE void ImplStartDnd();
+
+ SAL_DLLPRIVATE static void ImplInitAppFontData( Window* pWindow );
+ SAL_DLLPRIVATE void ImplPaintToDevice( OutputDevice* pTargetOutDev, const Point& rPos );
+
+ SAL_DLLPRIVATE BOOL ImplIsInTaskPaneList();
+ SAL_DLLPRIVATE void ImplIsInTaskPaneList( BOOL mbIsInTaskList );
+ SAL_DLLPRIVATE ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCanvas >
+ ImplGetCanvas( const Size& rFullscreenSize, bool bFullscreen, bool bSpriteCanvas ) const;
+
+private:
+ // Default construction is forbidden and not implemented.
+ SAL_DLLPRIVATE Window();
+
+ // Copy assignment is forbidden and not implemented.
+ SAL_DLLPRIVATE Window (const Window &);
+ SAL_DLLPRIVATE Window & operator= (const Window &);
+
+protected:
+ // Single argument ctors shall be explicit.
+ explicit Window( WindowType nType );
+
+ void SetCompoundControl( BOOL bCompound );
+
+ void ImplCallEventListeners( ULONG nEvent, void* pData = NULL );
+ void CallEventListeners( ULONG nEvent, void* pData = NULL );
+ void FireVclEvent( VclSimpleEvent* pEvent );
+
+ // FIXME: this is a hack to workaround missing layout functionality
+ SAL_DLLPRIVATE void ImplAdjustNWFSizes();
+public:
+ // Single argument ctors shall be explicit.
+ explicit Window( Window* pParent, WinBits nStyle = 0 );
+
+ Window( Window* pParent, const ResId& rResId );
+ virtual ~Window();
+
+ virtual void MouseMove( const MouseEvent& rMEvt );
+ virtual void MouseButtonDown( const MouseEvent& rMEvt );
+ virtual void MouseButtonUp( const MouseEvent& rMEvt );
+ virtual void KeyInput( const KeyEvent& rKEvt );
+ virtual void KeyUp( const KeyEvent& rKEvt );
+ virtual void PrePaint();
+ virtual void Paint( const Rectangle& rRect );
+ virtual void Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG nFlags );
+ virtual void Move();
+ virtual void Resize();
+ virtual void Activate();
+ virtual void Deactivate();
+ virtual void GetFocus();
+ virtual void LoseFocus();
+ virtual void RequestHelp( const HelpEvent& rHEvt );
+ virtual void Command( const CommandEvent& rCEvt );
+ virtual void Tracking( const TrackingEvent& rTEvt );
+ virtual void UserEvent( ULONG nEvent, void* pEventData );
+ virtual void StateChanged( StateChangedType nStateChange );
+ virtual void DataChanged( const DataChangedEvent& rDCEvt );
+ virtual long PreNotify( NotifyEvent& rNEvt );
+ virtual long Notify( NotifyEvent& rNEvt );
+ virtual Window* GetPreferredKeyInputWindow();
+
+ /*virtual*/ void AddEventListener( const Link& rEventListener );
+ /*virtual*/ void RemoveEventListener( const Link& rEventListener );
+ /*virtual*/ void AddChildEventListener( const Link& rEventListener );
+ /*virtual*/ void RemoveChildEventListener( const Link& rEventListener );
+
+ ULONG PostUserEvent( ULONG nEvent, void* pEventData = NULL );
+ ULONG PostUserEvent( const Link& rLink, void* pCaller = NULL );
+ BOOL PostUserEvent( ULONG& rEventId, ULONG nEvent, void* pEventData = NULL );
+ BOOL PostUserEvent( ULONG& rEventId, const Link& rLink, void* pCaller = NULL );
+ void RemoveUserEvent( ULONG nUserEvent );
+ void PostStateChanged( StateChangedType nState );
+
+ void IncrementLockCount();
+ void DecrementLockCount();
+ BOOL IsLocked( BOOL bChilds = FALSE ) const;
+
+ // returns the input language used for the last key stroke
+ // may be LANGUAGE_DONTKNOW if not supported by the OS
+ LanguageType GetInputLanguage() const;
+
+ void SetStyle( WinBits nStyle );
+ WinBits GetStyle() const;
+ WinBits GetPrevStyle() const;
+ void SetExtendedStyle( WinBits nExtendedStyle );
+ WinBits GetExtendedStyle() const;
+ WinBits GetPrevExtendedStyle() const;
+ void SetType( WindowType nType );
+ WindowType GetType() const;
+ BOOL IsSystemWindow() const;
+ BOOL IsDialog() const;
+ BOOL IsMenuFloatingWindow() const;
+ BOOL IsToolbarFloatingWindow() const;
+ BOOL IsTopWindow() const;
+ SystemWindow* GetSystemWindow() const;
+
+ void EnableAllResize( BOOL bEnable = TRUE );
+ BOOL IsAllResizeEnabled() const;
+
+ void SetBorderStyle( USHORT nBorderStyle );
+ USHORT GetBorderStyle() const;
+ void GetBorder( sal_Int32& rLeftBorder, sal_Int32& rTopBorder,
+ sal_Int32& rRightBorder, sal_Int32& rBottomBorder ) const;
+ Size CalcWindowSize( const Size& rOutSz ) const;
+ Size CalcOutputSize( const Size& rWinSz ) const;
+ long CalcTitleWidth() const;
+
+ void EnableClipSiblings( BOOL bClipSiblings = TRUE );
+ BOOL IsClipSiblingsEnabled() const;
+
+ void EnableChildTransparentMode( BOOL bEnable = TRUE );
+ BOOL IsChildTransparentModeEnabled() const;
+
+ void SetMouseTransparent( BOOL bTransparent );
+ BOOL IsMouseTransparent() const;
+ void SetPaintTransparent( BOOL bTransparent );
+ BOOL IsPaintTransparent() const;
+ void SetDialogControlStart( BOOL bStart );
+ BOOL IsDialogControlStart() const;
+ void SetDialogControlFlags( USHORT nFlags );
+ USHORT GetDialogControlFlags() const;
+
+ struct PointerState
+ {
+ ULONG mnState; // the button state
+ Point maPos; // mouse position in output coordinates
+ };
+ PointerState GetPointerState();
+ BOOL IsMouseOver();
+
+ ULONG GetCurrentModButtons();
+
+ void SetInputContext( const InputContext& rInputContext );
+ const InputContext& GetInputContext() const;
+ void EndExtTextInput( USHORT nFlags );
+ BOOL IsExtTextInput() const;
+ void SetCursorRect( const Rectangle* pRect = NULL, long nExtTextInputWidth = 0 );
+ const Rectangle* GetCursorRect() const;
+ long GetCursorExtTextInputWidth() const;
+
+ void EnableChildNotify( BOOL bEnable );
+ BOOL IsChildNotify() const;
+
+ using OutputDevice::SetSettings;
+ virtual void SetSettings( const AllSettings& rSettings );
+ virtual void SetSettings( const AllSettings& rSettings, BOOL bChild );
+ void UpdateSettings( const AllSettings& rSettings, BOOL bChild = FALSE );
+ void NotifyAllChilds( DataChangedEvent& rDCEvt );
+
+ void SetPointFont( const Font& rFont );
+ Font GetPointFont() const;
+ void SetZoomedPointFont( const Font& rFont );
+ long GetDrawPixel( OutputDevice* pDev, long nPixels ) const;
+ Font GetDrawPixelFont( OutputDevice* pDev ) const;
+ void GetFontResolution( sal_Int32& nDPIX, sal_Int32& nDPIY ) const;
+
+ void SetControlFont();
+ void SetControlFont( const Font& rFont );
+ Font GetControlFont() const;
+ BOOL IsControlFont() const;
+ void SetControlForeground();
+ void SetControlForeground( const Color& rColor );
+ Color GetControlForeground() const;
+ BOOL IsControlForeground() const;
+ void SetControlBackground();
+ void SetControlBackground( const Color& rColor );
+ Color GetControlBackground() const;
+ BOOL IsControlBackground() const;
+
+ void SetParentClipMode( USHORT nMode = 0 );
+ USHORT GetParentClipMode() const;
+
+ void SetWindowRegionPixel();
+ void SetWindowRegionPixel( const Region& rRegion );
+ const Region& GetWindowRegionPixel() const;
+ BOOL IsWindowRegionPixel() const;
+ Region GetWindowClipRegionPixel( USHORT nFlags = 0 ) const;
+ Region GetPaintRegion() const;
+ BOOL IsInPaint() const;
+ // while IsInPaint returns true ExpandPaintClipRegion adds the
+ // submitted region to the paint clip region so you can
+ // paint additional parts of your window if necessary
+ void ExpandPaintClipRegion( const Region& rRegion );
+
+ void SetParent( Window* pNewParent );
+ Window* GetParent() const;
+
+ void Show( BOOL bVisible = TRUE, USHORT nFlags = 0 );
+ void Hide( USHORT nFlags = 0 ) { Show( FALSE, nFlags ); }
+ BOOL IsVisible() const;
+ BOOL IsReallyVisible() const;
+ // Do not use this function, use IsReallyVisible()
+ BOOL IsParentPathVisible() const;
+ BOOL IsReallyShown() const;
+ BOOL IsInInitShow() const;
+
+ void Enable( bool bEnable = true, bool bChild = true );
+ void Disable( bool bChild = true ) { Enable( false, bChild ); }
+ BOOL IsEnabled() const;
+
+ void EnableInput( BOOL bEnable = TRUE, BOOL bChild = TRUE );
+ void EnableInput( BOOL bEnable, BOOL bChild, BOOL bSysWin,
+ const Window* pExcludeWindow = NULL );
+ BOOL IsInputEnabled() const;
+
+ /** Override <code>EnableInput</code>. This can be necessary due to other people
+ using EnableInput for whole window hierarchies.
+
+
+ <code>AlwaysEnableInput</code> and <code>AlwaysDisableInput</code> are
+ mutually exclusive; the last setter wins.
+ @param bAlways
+ sets always enabled flag
+
+ @param bChild
+ if true children are recursively set to AlwaysEnableInput
+ */
+ void AlwaysEnableInput( BOOL bAlways, BOOL bChild = TRUE );
+ /** returns the current AlwaysEnableInput state
+ @return
+ true if window is in AlwaysEnableInput state
+ */
+ BOOL IsAlwaysEnableInput() const;
+ /** Override <code>EnableInput</code>, counterpart to AlwaysEnableInput.
+ Windows with AlwaysDisableInput will not get key events even if enabled
+ and input enabled.This can be necessary due to other people using EnableInput
+ for whole window hierarchies.
+
+ <code>AlwaysEnableInput</code> and <code>AlwaysDisableInput</code> are
+ mutually exclusive; the last setter wins.
+
+ @param bAlways
+ sets always disable flag
+
+ @param bChild
+ if true children are recursively set to AlwaysDisableInput
+ */
+ void AlwaysDisableInput( BOOL bAlways, BOOL bChild = TRUE );
+ /** returns the current AlwaysDisableInput state
+ @return
+ true if window is in AlwaysEnableInput state
+ */
+ BOOL IsAlwaysDisableInput() const;
+ /** usually event handlers (see AddEventListener and AddChildEventListener)
+ are not called on disabled, modal or input disabled windows. There are however rare cases
+ in which one wants a Window or rather one of its Control subclasses to
+ not evaluate events but still react to those events externally. In these
+ rare cases call SetCallHandlersOnInputDisabled( true ) to have your handler
+ called anyway.
+
+ Currently only mouse events get this special treatment.
+
+ Use this sparingly, chances are if you want to use it you're wroking around
+ the real problem.
+
+ @param bCall
+ Enable/Disable calling event handlers for this disabled, modal or input disabled window.
+ This call is implicity done recursively for possible child windows.
+ */
+ void SetCallHandlersOnInputDisabled( bool bCall );
+ /** get state of SetCallHandlersOnInputDisabled
+
+ @returns whether handlers are called regardless of input enabled state
+ */
+ bool IsCallHandlersOnInputDisabled() const;
+ /** A window is in modal mode if one of its children or subchildren
+ is a running modal window (a modal dialog)
+
+ @returns TRUE if a child or subchild is a running modal window
+ */
+ BOOL IsInModalMode() const;
+
+ void SetActivateMode( USHORT nMode );
+ USHORT GetActivateMode() const;
+
+ void ToTop( USHORT nFlags = 0 );
+ void SetZOrder( Window* pRefWindow, USHORT nFlags );
+ void EnableAlwaysOnTop( BOOL bEnable = TRUE );
+ BOOL IsAlwaysOnTopEnabled() const;
+
+ virtual void SetPosSizePixel( long nX, long nY,
+ long nWidth, long nHeight,
+ USHORT nFlags = WINDOW_POSSIZE_ALL );
+ virtual void SetPosPixel( const Point& rNewPos );
+ virtual Point GetPosPixel() const;
+ virtual void SetSizePixel( const Size& rNewSize );
+ virtual Size GetSizePixel() const;
+ virtual void SetPosSizePixel( const Point& rNewPos,
+ const Size& rNewSize );
+ virtual void SetOutputSizePixel( const Size& rNewSize );
+ BOOL IsDefaultPos() const;
+ BOOL IsDefaultSize() const;
+
+ // those conversion routines might deliver different results during UI mirroring
+ Point OutputToScreenPixel( const Point& rPos ) const;
+ Point ScreenToOutputPixel( const Point& rPos ) const;
+ // the normalized screen methods work independent from UI mirroring
+ Point OutputToNormalizedScreenPixel( const Point& rPos ) const;
+ Point NormalizedScreenToOutputPixel( const Point& rPos ) const;
+ Point OutputToAbsoluteScreenPixel( const Point& rPos ) const;
+ Point AbsoluteScreenToOutputPixel( const Point& rPos ) const;
+ Rectangle GetDesktopRectPixel() const;
+ // window extents including border and decoratrion
+ Rectangle GetWindowExtentsRelative( Window *pRelativeWindow ) const;
+ // window extents of the client window, coordinates to be used in SetPosPixel
+ Rectangle GetClientWindowExtentsRelative( Window *pRelativeWindow ) const;
+
+ virtual BOOL IsScrollable() const;
+ virtual void Scroll( long nHorzScroll, long nVertScroll,
+ USHORT nFlags = 0 );
+ virtual void Scroll( long nHorzScroll, long nVertScroll,
+ const Rectangle& rRect, USHORT nFlags = 0 );
+ virtual void Invalidate( USHORT nFlags = 0 );
+ virtual void Invalidate( const Rectangle& rRect, USHORT nFlags = 0 );
+ virtual void Invalidate( const Region& rRegion, USHORT nFlags = 0 );
+ void Validate( USHORT nFlags = 0 );
+ void Validate( const Rectangle& rRect, USHORT nFlags = 0 );
+ void Validate( const Region& rRegion, USHORT nFlags = 0 );
+ BOOL HasPaintEvent() const;
+ void Update();
+ void Flush();
+ void Sync();
+
+ // toggles new docking support, enabled via toolkit
+ void EnableDocking( BOOL bEnable = TRUE );
+ // retrieves the single dockingmanager instance
+ static DockingManager* GetDockingManager();
+
+ void EnablePaint( BOOL bEnable );
+ BOOL IsPaintEnabled() const;
+ void SetUpdateMode( BOOL bUpdate );
+ BOOL IsUpdateMode() const;
+ void SetParentUpdateMode( BOOL bUpdate );
+ BOOL IsParentUpdateMode() const;
+
+ void GrabFocus();
+ BOOL HasFocus() const;
+ BOOL HasChildPathFocus( BOOL bSystemWindow = FALSE ) const;
+ BOOL IsActive() const;
+ BOOL HasActiveChildFrame();
+ USHORT GetGetFocusFlags() const;
+ void GrabFocusToDocument();
+
+ /**
+ * Set this when you need to act as if the window has focus even if it
+ * doesn't. This is necessary for implementing tab stops inside floating
+ * windows, but floating windows don't get focus from the system.
+ */
+ void SetFakeFocus( bool bFocus );
+
+ BOOL IsCompoundControl() const;
+ BOOL HasCompoundControlFocus() const;
+
+ static sal_uIntPtr SaveFocus();
+ static BOOL EndSaveFocus( sal_uIntPtr nSaveId, BOOL bRestore = TRUE );
+
+ void CaptureMouse();
+ void ReleaseMouse();
+ BOOL IsMouseCaptured() const;
+
+ void SetPointer( const Pointer& rPointer );
+ const Pointer& GetPointer() const;
+ void EnableChildPointerOverwrite( BOOL bOverwrite = TRUE );
+ BOOL IsChildPointerOverwrite() const;
+ void SetPointerPosPixel( const Point& rPos );
+ Point GetPointerPosPixel();
+ Point GetLastPointerPosPixel();
+ void ShowPointer( BOOL bVisible );
+ BOOL IsPointerVisible() const;
+ void EnterWait();
+ void LeaveWait();
+ BOOL IsWait() const;
+
+ void SetCursor( Cursor* pCursor );
+ Cursor* GetCursor() const;
+
+ void SetZoom( const Fraction& rZoom );
+ const Fraction& GetZoom() const;
+ BOOL IsZoom() const;
+ long CalcZoom( long n ) const;
+
+ virtual void SetText( const XubString& rStr );
+ virtual String GetText() const;
+ // return the actual text displayed
+ // this may have e.g. accellerators removed or portions
+ // replaced by ellipsis
+ virtual String GetDisplayText() const;
+ // gets the visible background color. for transparent windows
+ // this may be the parent's background color; for controls
+ // this may be a child's background color (e.g. ListBox)
+ virtual const Wallpaper& GetDisplayBackground() const;
+
+ void SetHelpText( const XubString& rHelpText );
+ const XubString& GetHelpText() const;
+
+ void SetQuickHelpText( const XubString& rHelpText );
+ const XubString& GetQuickHelpText() const;
+
+ void SetHelpId( ULONG nHelpId ); /// deprecated
+ ULONG GetHelpId() const; /// deprecated
+ void SetSmartHelpId( const SmartId& aId, SmartIdUpdateMode aMode = SMART_SET_SMART );
+ SmartId GetSmartHelpId() const;
+
+ void SetUniqueId( ULONG nUniqueId ); /// deprecated
+ ULONG GetUniqueId() const; /// deprecated
+ void SetSmartUniqueId( const SmartId& aId, SmartIdUpdateMode aMode = SMART_SET_SMART );
+ SmartId GetSmartUniqueId() const;
+ SmartId GetSmartUniqueOrHelpId() const;
+
+ Window* FindWindow( const Point& rPos ) const;
+
+ USHORT GetChildCount() const;
+ Window* GetChild( USHORT nChild ) const;
+ Window* GetWindow( USHORT nType ) const;
+ BOOL IsChild( const Window* pWindow, BOOL bSystemWindow = FALSE ) const;
+ BOOL IsWindowOrChild( const Window* pWindow, BOOL bSystemWindow = FALSE ) const;
+
+ void SetData( void* pNewData );
+ void* GetData() const;
+
+ // Should be merged in the next top level build !!!
+ Bitmap SnapShot( BOOL bBorder ) const;
+ Bitmap SnapShot() const;
+
+ void ShowFocus( const Rectangle& rRect );
+ void HideFocus();
+
+ void Invert( const Rectangle& rRect, USHORT nFlags = 0 );
+ void Invert( const Polygon& rPoly, USHORT nFlags = 0 );
+
+ // transparent background for selected or checked items in toolboxes etc.
+ void DrawSelectionBackground( const Rectangle& rRect, USHORT highlight, BOOL bChecked, BOOL bDrawBorder, BOOL bDrawExtBorderOnly );
+ // the same, but fills a passed Color with a text color complementing the selection background
+ void DrawSelectionBackground( const Rectangle& rRect, USHORT highlight, BOOL bChecked, BOOL bDrawBorder, BOOL bDrawExtBorderOnly, Color* pSelectionTextColor );
+ // support rounded edges in the selection rect
+ void DrawSelectionBackground( const Rectangle& rRect, USHORT highlight, BOOL bChecked, BOOL bDrawBorder, BOOL bDrawExtBorderOnly, long nCornerRadius, Color* pSelectionTextColor, Color* pPaintColor );
+
+ void ShowTracking( const Rectangle& rRect,
+ USHORT nFlags = SHOWTRACK_SMALL );
+ void HideTracking();
+ void InvertTracking( const Rectangle& rRect,
+ USHORT nFlags = SHOWTRACK_SMALL );
+ void InvertTracking( const Polygon& rPoly, USHORT nFlags = 0 );
+
+ void StartTracking( USHORT nFlags = 0 );
+ void EndTracking( USHORT nFlags = 0 );
+ BOOL IsTracking() const;
+
+ void StartAutoScroll( USHORT nFlags );
+ void EndAutoScroll();
+ BOOL IsAutoScroll() const;
+
+ BOOL HandleScrollCommand( const CommandEvent& rCmd,
+ ScrollBar* pHScrl = NULL,
+ ScrollBar* pVScrl = NULL );
+
+ void SaveBackground( const Point& rPos, const Size& rSize,
+ const Point& rDestOff, VirtualDevice& rSaveDevice );
+
+ const SystemEnvData* GetSystemData() const;
+ ::com::sun::star::uno::Any GetSystemDataAny() const;
+
+ // API zum Setzen/Abfragen des Komponenteninterfaces
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindowPeer > GetComponentInterface( BOOL bCreate = TRUE );
+ virtual void SetComponentInterface( ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindowPeer > xIFace );
+
+ // Accessibility
+ ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > GetAccessible( BOOL bCreate = TRUE );
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > CreateAccessible();
+ void SetAccessible( ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > );
+
+ Window* GetAccessibleParentWindow() const;
+ USHORT GetAccessibleChildWindowCount();
+ Window* GetAccessibleChildWindow( USHORT n );
+
+ void SetAccessibleRole( USHORT nRole );
+ USHORT GetAccessibleRole() const;
+
+ void SetAccessibleName( const String& rName );
+ String GetAccessibleName() const;
+
+ void SetAccessibleDescription( const String& rDescr );
+ String GetAccessibleDescription() const;
+
+ // to avoid sending accessibility events in cases like closing dialogs
+ // by default checks complete parent path
+ BOOL IsAccessibilityEventsSuppressed( BOOL bTraverseParentPath = TRUE );
+
+ /// request XCanvas render interface for this window
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XCanvas > GetCanvas() const;
+ /// request XSpriteCanvas render interface for this window
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XSpriteCanvas > GetSpriteCanvas() const;
+ /// request fullscreen XSpriteCanvas render interface for this window
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::rendering::XSpriteCanvas > GetFullscreenSpriteCanvas( const Size& rFullscreenSize ) const;
+
+ /* records all DrawText operations within the passed rectangle;
+ * a synchronous paint is sent to achieve this
+ */
+ void RecordLayoutData( vcl::ControlLayoutData* pLayout, const Rectangle& rRect );
+
+ // Setzen und Abfragen fuer das Toolkit
+ VCLXWindow* GetWindowPeer() const;
+ void SetWindowPeer( ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindowPeer > xPeer, VCLXWindow* pVCLXWindow );
+
+ // Merken, ob vom Toolkit erzeugt
+ BOOL IsCreatedWithToolkit() const;
+ void SetCreatedWithToolkit( BOOL b );
+
+ Window* GetLabelFor() const;
+ Window* GetLabeledBy() const;
+ virtual Window* GetParentLabelFor( const Window* pLabel ) const;
+ virtual Window* GetParentLabeledBy( const Window* pLabeled ) const;
+ KeyEvent GetActivationKey() const;
+
+ // Drag and Drop interfaces
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDropTarget > GetDropTarget();
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSource > GetDragSource();
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragGestureRecognizer > GetDragGestureRecognizer();
+ // only for RVP transmission
+ void GetDragSourceDropTarget(::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSource >& xDragSource,::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDropTarget > &xDropTarget );
+
+ // Clipboard/Selection interfaces
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboard > GetClipboard();
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboard > GetPrimarySelection();
+
+ // Advisory Sizing - what is a good size for this widget ?
+ virtual Size GetOptimalSize(WindowSizeType eType) const;
+
+ //-------------------------------------
+ // Native Widget Rendering functions
+ //-------------------------------------
+
+ // form controls must never use native widgets, this can be toggled here
+ void EnableNativeWidget( BOOL bEnable = TRUE );
+ BOOL IsNativeWidgetEnabled() const;
+
+ // a helper method for a Control's Draw method
+ void PaintToDevice( OutputDevice* pDevice, const Point& rPos, const Size& rSize );
+
+ /* mark Window for deletion in top of event queue
+ */
+ void doLazyDelete();
+
+ virtual XubString GetSurroundingText() const;
+ virtual Selection GetSurroundingTextSelection() const;
+};
+
+
+#endif // _SV_WINDOW_HXX
diff --git a/vcl/inc/vcl/wintypes.hxx b/vcl/inc/vcl/wintypes.hxx
new file mode 100644
index 000000000000..6da4e4e3d988
--- /dev/null
+++ b/vcl/inc/vcl/wintypes.hxx
@@ -0,0 +1,33 @@
+/*************************************************************************
+ *
+ * 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_WINTYPES_HXX
+#define _SV_WINTYPES_HXX
+
+#include <tools/wintypes.hxx>
+
+#endif // _SV_WINTYPES_HXX
+
diff --git a/vcl/inc/vcl/wrkwin.hxx b/vcl/inc/vcl/wrkwin.hxx
new file mode 100644
index 000000000000..c710434c79a4
--- /dev/null
+++ b/vcl/inc/vcl/wrkwin.hxx
@@ -0,0 +1,108 @@
+/*************************************************************************
+ *
+ * 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_WRKWIN_HXX
+#define _SV_WRKWIN_HXX
+
+#include <vcl/sv.h>
+#include <vcl/dllapi.h>
+#include <vcl/syswin.hxx>
+
+namespace com { namespace sun { namespace star { namespace uno { class Any; }}}}
+struct SystemParentData;
+
+// ----------------------
+// - WorkWindow - Types -
+// ----------------------
+
+// Presentation Flags
+#define PRESENTATION_HIDEALLAPPS ((USHORT)0x0001)
+#define PRESENTATION_NOFULLSCREEN ((USHORT)0x0002)
+#define PRESENTATION_NOAUTOSHOW ((USHORT)0x0004)
+
+// --------------
+// - WorkWindow -
+// --------------
+
+class VCL_DLLPUBLIC WorkWindow : public SystemWindow
+{
+private:
+ USHORT mnPresentationFlags;
+ BOOL mbPresentationMode:1,
+ mbPresentationVisible:1,
+ mbPresentationFull:1,
+ mbFullScreenMode:1;
+
+ SAL_DLLPRIVATE void ImplInitWorkWindowData();
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle, const ::com::sun::star::uno::Any& aSystemWorkWindowToken );
+
+private:
+ SAL_DLLPRIVATE WorkWindow( const WorkWindow& rWin );
+ SAL_DLLPRIVATE WorkWindow& operator =( const WorkWindow& rWin );
+
+protected:
+ WorkWindow( WindowType nType );
+ SAL_DLLPRIVATE void ImplInit( Window* pParent, WinBits nStyle, SystemParentData* pSystemParentData = NULL );
+ SAL_DLLPRIVATE void ImplLoadRes( const ResId& rResId );
+ SAL_DLLPRIVATE void ImplSetFrameState( ULONG aFrameState );
+
+public:
+ WorkWindow( Window* pParent, const ResId& rResId );
+ WorkWindow( Window* pParent, WinBits nStyle = WB_STDWORK );
+ WorkWindow( Window* pParent, const ::com::sun::star::uno::Any& aSystemWorkWindowToken, WinBits nStyle = WB_STDWORK );
+ WorkWindow( SystemParentData* pParent ); // Not in the REMOTE-Version
+ ~WorkWindow();
+
+ virtual BOOL Close();
+
+ /** The default value of nDisplay = -1 means "don't care" and
+ allows to backends to use any screen [** or display? terminology!]
+ they like (most probably the current one).
+
+ NOTE: The default value cannot be 0, because 0 is a legitimate
+ screen number.
+ */
+ void ShowFullScreenMode( BOOL bFullScreenMode = TRUE, sal_Int32 nDisplay = -1 );
+ void EndFullScreenMode() { ShowFullScreenMode( FALSE ); }
+ BOOL IsFullScreenMode() const { return mbFullScreenMode; }
+
+ void StartPresentationMode( BOOL bPresentation = TRUE, USHORT nFlags = 0, sal_Int32 nDisplay = 0 );
+ void EndPresentationMode() { StartPresentationMode( FALSE ); }
+ BOOL IsPresentationMode() const { return mbPresentationMode; }
+
+ BOOL IsMinimized() const;
+
+ BOOL SetPluginParent( SystemParentData* pParent );
+
+ void Minimize();
+ void Restore();
+
+ void Maximize( BOOL bMaximize = TRUE );
+ BOOL IsMaximized() const;
+};
+
+#endif // _SV_WRKWIN_HXX
diff --git a/vcl/inc/vcl/xconnection.hxx b/vcl/inc/vcl/xconnection.hxx
new file mode 100644
index 000000000000..aa9d37430ea6
--- /dev/null
+++ b/vcl/inc/vcl/xconnection.hxx
@@ -0,0 +1,70 @@
+/*************************************************************************
+ *
+ * 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_XCONNECTION_HXX
+#define _VCL_XCONNECTION_HXX
+
+#include <com/sun/star/awt/XDisplayConnection.hpp>
+#include <cppuhelper/implbase1.hxx>
+#include <osl/mutex.hxx>
+#include <com/sun/star/uno/Reference.hxx>
+
+#ifndef _STLP_LIST
+#include <list>
+#endif
+
+namespace vcl {
+
+ class DisplayConnection :
+ public ::cppu::WeakImplHelper1< ::com::sun::star::awt::XDisplayConnection >
+ {
+ ::osl::Mutex m_aMutex;
+ ::std::list< ::com::sun::star::uno::Reference< ::com::sun::star::awt::XEventHandler > >
+ m_aHandlers;
+ ::std::list< ::com::sun::star::uno::Reference< ::com::sun::star::awt::XEventHandler > >
+ m_aErrorHandlers;
+ ::com::sun::star::uno::Any m_aAny;
+ public:
+ DisplayConnection();
+ virtual ~DisplayConnection();
+
+ static bool dispatchEvent( void* pThis, void* pData, int nBytes );
+ static bool dispatchErrorEvent( void* pThis, void* pData, int nBytes );
+ void dispatchDowningEvent();
+
+ // XDisplayConnection
+ virtual void SAL_CALL addEventHandler( const ::com::sun::star::uno::Any& window, const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XEventHandler >& handler, sal_Int32 eventMask ) throw();
+ virtual void SAL_CALL removeEventHandler( const ::com::sun::star::uno::Any& window, const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XEventHandler >& handler ) throw();
+ virtual void SAL_CALL addErrorHandler( const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XEventHandler >& handler ) throw();
+ virtual void SAL_CALL removeErrorHandler( const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XEventHandler >& handler ) throw();
+ virtual ::com::sun::star::uno::Any SAL_CALL getIdentifier() throw();
+
+ };
+
+}
+
+#endif // _VCL_XCONNECTION_HXX
diff --git a/vcl/os2/howto.txt b/vcl/os2/howto.txt
new file mode 100644
index 000000000000..8711e8ea3b09
--- /dev/null
+++ b/vcl/os2/howto.txt
@@ -0,0 +1,13 @@
+
+VCL positioning
+
+Window coordinates are parent relative, with exception of maState fields, they
+have screen coordinates.
+
+Every window has a parent window, usually the client area of an existing window,
+otherwise the desktop window.
+
+When a window is to be sized/moved, SetPosSize is called.
+Since coordinates are the position/size of client area, we need to calculate
+current window frame size/position and map to screen coordinates using the
+owner window position as offset.
diff --git a/vcl/os2/inc/salbmp.h b/vcl/os2/inc/salbmp.h
new file mode 100644
index 000000000000..14e51ffae8da
--- /dev/null
+++ b/vcl/os2/inc/salbmp.h
@@ -0,0 +1,109 @@
+/*************************************************************************
+ *
+ * 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_SALBMP_H
+#define _SV_SALBMP_H
+
+#include <tools/gen.hxx>
+#include <vcl/sv.h>
+#include <vcl/salbmp.hxx>
+
+// --------------
+// - SalBitmap -
+// --------------
+
+struct BitmapBuffer;
+class BitmapColor;
+class BitmapPalette;
+class SalGraphics;
+
+#define HANDLE ULONG
+#define HBITMAP ULONG
+
+class Os2SalBitmap : public SalBitmap
+{
+private:
+
+ Size maSize;
+ HANDLE mhDIB;
+ HANDLE mhDIB1Subst;
+ HBITMAP mhDDB;
+ USHORT mnBitCount;
+
+public:
+
+ HANDLE ImplGethDIB() const { return mhDIB; }
+ HBITMAP ImplGethDDB() const { return mhDDB; }
+ HANDLE ImplGethDIB1Subst() const { return mhDIB1Subst; }
+
+ void ImplReplacehDIB1Subst( HANDLE hDIB1Subst );
+
+ static HANDLE ImplCreateDIB( const Size& rSize, USHORT nBitCount, const BitmapPalette& rPal );
+ static HANDLE ImplCreateDIB4FromDIB1( HANDLE hDIB1 );
+ static HANDLE ImplCopyDIBOrDDB( HANDLE hHdl, BOOL bDIB );
+ static USHORT ImplGetDIBColorCount( HANDLE hDIB );
+ static void ImplDecodeRLEBuffer( const BYTE* pSrcBuf, BYTE* pDstBuf,
+ const Size& rSizePixel, BOOL bRLE4 );
+
+ //BOOL Create( HANDLE hBitmap, BOOL bDIB, BOOL bCopyHandle );
+
+public:
+
+ Os2SalBitmap();
+ ~Os2SalBitmap();
+
+public:
+
+ //BOOL Create( const Size& rSize, USHORT nBitCount, const BitmapPalette& rPal );
+ //BOOL Create( const SalBitmap& rSalBmpImpl );
+ //BOOL Create( const SalBitmap& rSalBmpImpl, SalGraphics* pGraphics );
+ //BOOL Create( const SalBitmap& rSalBmpImpl, USHORT nNewBitCount );
+
+ //void Destroy();
+
+ //Size GetSize() const { return maSize; }
+ //USHORT GetBitCount() const { return mnBitCount; }
+
+ //BitmapBuffer* AcquireBuffer( bool bReadOnly );
+ //void ReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly );
+ bool Create( HANDLE hBitmap, bool bDIB, bool bCopyHandle );
+ virtual bool Create( const Size& rSize, USHORT nBitCount, const BitmapPalette& rPal );
+ virtual bool Create( const SalBitmap& rSalBmpImpl );
+ virtual bool Create( const SalBitmap& rSalBmpImpl, SalGraphics* pGraphics );
+ virtual bool Create( const SalBitmap& rSalBmpImpl, USHORT nNewBitCount );
+
+ virtual void Destroy();
+
+ virtual Size GetSize() const { return maSize; }
+ virtual USHORT GetBitCount() const { return mnBitCount; }
+
+ virtual BitmapBuffer* AcquireBuffer( bool bReadOnly );
+ virtual void ReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly );
+ virtual bool GetSystemData( BitmapSystemData& rData );
+};
+
+#endif // _SV_SALBMP_H
diff --git a/vcl/os2/inc/saldata.hxx b/vcl/os2/inc/saldata.hxx
new file mode 100644
index 000000000000..cf536a58d8dd
--- /dev/null
+++ b/vcl/os2/inc/saldata.hxx
@@ -0,0 +1,307 @@
+/*************************************************************************
+ *
+ * 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_SALDATA_HXX
+#define _SV_SALDATA_HXX
+
+#include <vcl/sv.h>
+#include <vcl/svdata.hxx>
+#include <vcl/salwtype.hxx>
+
+class Os2SalInstance;
+class Os2SalFrame;
+class Os2SalObject;
+
+extern "C" int debug_printf(const char *f, ...);
+
+// --------------
+// - SalIMEData -
+// --------------
+
+// YD FIXME #define ENABLE_IME
+
+#ifdef ENABLE_IME
+
+struct SalIMEData;
+
+#ifdef OS2IM_INCLUDED
+
+typedef APIRET (APIENTRY ImAssociateInstanceFunc)( HWND hwnd, HIMI himi, PHIMI phimiPrev );
+typedef APIRET (APIENTRY ImGetInstanceFunc)( HWND hwnd, PHIMI phimi );
+typedef APIRET (APIENTRY ImReleaseInstanceFunc)( HWND hwnd, HIMI himi );
+typedef APIRET (APIENTRY ImSetConversionFontFunc)( HIMI himi, PFATTRS pFontAttrs );
+typedef APIRET (APIENTRY ImSetConversionFontSizeFunc)( HIMI himi, PSIZEF psizfxBox );
+typedef APIRET (APIENTRY ImGetConversionStringFunc)( HIMI himi, ULONG ulIndex, PVOID pBuf, PULONG pulBufLen );
+typedef APIRET (APIENTRY ImGetResultStringFunc)( HIMI himi, ULONG ulIndex, PVOID pBuf, PULONG pulBufLen );
+typedef APIRET (APIENTRY ImSetCandidateWindowPosFunc)( HIMI himi, PCANDIDATEPOS pCandidatePos );
+typedef APIRET (APIENTRY ImQueryIMEPropertyFunc)( HIMI himi, ULONG ulIndex, PULONG pulProp );
+typedef APIRET (APIENTRY ImRequestIMEFunc)( HIMI himi, ULONG ulAction, ULONG ulIndex, ULONG ulValue );
+typedef APIRET (APIENTRY ImSetIMModeFunc)( HIMI himi, ULONG ulInputMode, ULONG ulConversionMode );
+typedef APIRET (APIENTRY ImQueryIMModeFunc)( HIMI himi, PULONG pulInputMode, PULONG pulConversionMode );
+
+struct SalIMEData
+{
+ HMODULE mhModIME;
+ ImAssociateInstanceFunc* mpAssocIME;
+ ImGetInstanceFunc* mpGetIME;
+ ImReleaseInstanceFunc* mpReleaseIME;
+ ImSetConversionFontFunc* mpSetConversionFont;
+ ImSetConversionFontSizeFunc* mpSetConversionFontSize;
+ ImGetConversionStringFunc* mpGetConversionString;
+ ImGetResultStringFunc* mpGetResultString;
+ ImSetCandidateWindowPosFunc* mpSetCandidateWin;
+ ImQueryIMEPropertyFunc* mpQueryIMEProperty;
+ ImRequestIMEFunc* mpRequestIME;
+ ImSetIMModeFunc* mpSetIMEMode;
+ ImQueryIMModeFunc* mpQueryIMEMode;
+};
+
+#endif
+
+#endif
+
+// --------------------
+// - Icon cache -
+// --------------------
+
+struct SalIcon
+{
+ int nId;
+ HPOINTER hIcon;
+ SalIcon *pNext;
+};
+
+// -----------
+// - SalData -
+// -----------
+
+struct SalData
+{
+ HAB mhAB; // anchor block handle
+ HMQ mhMQ; // handle of os2 message queue
+ int mnArgc; // commandline param count
+ char** mpArgv; // commandline
+ ULONG mnNewTimerMS; // Neue Zeit, mit dem der Timer gestartet werden soll
+ ULONG mnTimerMS; // Current Time (in MS) of the Timer
+ ULONG mnTimerOrgMS; // Current Original Time (in MS)
+ ULONG mnNextTimerTime;
+ ULONG mnLastEventTime;
+ ULONG mnTimerId; // os2 timer id
+ BOOL mbInTimerProc; // timer event is currently being dispatched
+ //SALTIMERPROC mpTimerProc; // timer callback proc
+ HWND mhWantLeaveMsg; // window handle, that want a MOUSELEAVE message
+ AutoTimer* mpMouseLeaveTimer; // Timer for MouseLeave Test
+ Os2SalInstance* mpFirstInstance; // pointer of first instance
+ Os2SalFrame* mpFirstFrame; // pointer of first frame
+ Os2SalFrame* mpCreateFrame; // Create-Frame for WM_CREATE
+ Os2SalObject* mpFirstObject; // pointer of first object window
+ ULONG mnAppThreadId; // Id from Applikation-Thread
+ ULONG mnFontMetricCount; // number of entries in the font list
+ PFONTMETRICS mpFontMetrics; // cached font list
+ BOOL mbObjClassInit; // Ist SALOBJECTCLASS initialised
+#ifdef ENABLE_IME
+ SalIMEData* mpIMEData; // SalIME-Data
+ BOOL mbIMEInit; // SalIME-Data-Init
+#endif
+
+ SalIcon* mpFirstIcon; // icon cache, points to first icon, NULL if none
+
+};
+
+inline void SetSalData( SalData* pData ) { ImplGetSVData()->mpSalData = (void*)pData; }
+inline SalData* GetSalData() { return (SalData*)ImplGetSVData()->mpSalData; }
+inline SalData* GetAppSalData() { return (SalData*)ImplGetAppSVData()->mpSalData; }
+
+// --------------
+// - SalShlData -
+// --------------
+
+#define OS2_VER_211 211
+#define OS2_VER_WARP3 230
+#define OS2_VER_WARP4 240
+
+struct SalShlData
+{
+ HMODULE mhMod; // Module handle of SAL-DLL
+ USHORT mnVersion; // 211 = OS2 2.11; 230 = OS2 3.0; 240 = OS2 4.0
+ PFNWP mpFrameProc; // old frame proc
+};
+
+extern SalShlData aSalShlData;
+
+BOOL SalImplHandleProcessMenu( HWND hWnd, ULONG nMsg, MPARAM nMP1, MPARAM nMP2 );
+
+// --------------------------------------------
+// - SALSHL.CXX - for accessing DLL resources -
+// --------------------------------------------
+
+HPOINTER ImplLoadSalCursor( int nId );
+HBITMAP ImplLoadSalBitmap( int nId );
+BOOL ImplLoadSalIcon( int nId, HPOINTER& rIcon);
+
+// SALGDI.CXX
+void ImplInitSalGDI();
+void ImplFreeSalGDI();
+
+// --------------
+// - Prototypes -
+// --------------
+
+// \\OS2\SOURCE\APP\SALINST.CXX
+void ImplSalYieldMutexAcquireWithWait();
+ULONG ImplSalReleaseYieldMutex();
+void ImplSalAcquireYieldMutex( ULONG nCount );
+ULONG GetCurrentThreadId();
+BOOL ImplSalYieldMutexTryToAcquire();
+void ImplSalYieldMutexAcquire();
+void ImplSalYieldMutexRelease();
+
+// \\OS2\SOURCE\WINDOW\SALFRAME.CXX
+MRESULT EXPENTRY SalFrameWndProc( HWND hWnd, ULONG nMsg, MPARAM nMP1, MPARAM nMP2 );
+MRESULT EXPENTRY SalFrameFrameProc( HWND hWnd, ULONG nMsg, MPARAM nMP1, MPARAM nMP2 );
+// \SV\WIN\SOURCE\APP\SALTIMER.CXX
+#define SALTIMERPROC_RECURSIVE 0xffffffff
+void SalTimerProc( HWND hWnd, UINT nMsg, UINT nId, ULONG nTime );
+
+// \WIN\SOURCE\WINDOW\SALFRAME.CXX
+void SalTestMouseLeave();
+
+// \\OS2\SOURCE\WINDOW\SALFRAME.CXX
+// return Frame for Message-Handling
+Os2SalFrame* GetSalDefaultFrame();
+
+// \\OS2\SOURCE\WINDOW\SALFRAME.CXX
+// IME-Daten wieder freigeben
+#ifdef ENABLE_IME
+void ImplReleaseSALIMEData();
+#endif
+
+// -----------
+// - Defines -
+// -----------
+
+#define SAL_PROFILE_APPNAME ((PSZ)"StarOffice")
+#define SAL_PROFILE_USEDJP ((PSZ)"UseDJP")
+#define SAL_PROFILE_PRINTDJP ((PSZ)"PrintDJP")
+#define SAL_PROFILE_PRINTRAW ((PSZ)"PrintRAW")
+
+#define SAL_FRAME_WNDEXTRA sizeof(ULONG)
+#define SAL_FRAME_THIS 0
+#define SAL_FRAME_CLASSNAME "SALFRAME"
+#define SAL_SUBFRAME_CLASSNAME "SALSUBFRAME"
+#define SAL_OBJECT_WNDEXTRA sizeof(ULONG)
+#define SAL_OBJECT_THIS 0
+#define SAL_OBJECT_CLASSNAME "SALOBJECT"
+#define SAL_OBJECT_CHILDCLASSNAME "SALOBJECTCHILD"
+#define SAL_OBJECT_CLIPCLASSNAME "SALOBJECTCLIP"
+#define SAL_COM_CLASSNAME "SALCOMWND"
+
+#define SAL_MOUSELEAVE_TIMEOUT 300
+
+// MP1 == 0; MP2 == pData
+#define SAL_MSG_USEREVENT (WM_USER+111)
+// MP1 == 0; MP2 == MousePosition relativ to upper left of screen
+#define SAL_MSG_MOUSELEAVE (WM_USER+112)
+// MP1 == hDC; MP2 == 0
+#define SAL_MSG_PRINTABORTJOB (WM_USER+113)
+// MP1 == 0; MP2 == 0
+#define SAL_MSG_STARTTIMER (WM_USER+114)
+// MP1 == nFrameStyle; MP2 == pParent; lResult pFrame
+#define SAL_MSG_CREATEFRAME (WM_USER+115)
+// MP1 == 0; MP2 == pParent; lResult pObject
+#define SAL_MSG_CREATEOBJECT (WM_USER+116)
+// MP1 == bWait; MP2 == pMutex
+#define SAL_MSG_THREADYIELD (WM_USER+117)
+// MP1 == 0; MP2 == 0
+#define SAL_MSG_RELEASEWAITYIELD (WM_USER+118)
+// MP1 == 0; MP2 == pData
+#define SAL_MSG_SYSPROCESSMENU (WM_USER+119)
+// POSTFOCUS-Message; MP1 == nMP1; MP2 == nMP2 (SHORT1( bFocus ), 0)
+#define SAL_MSG_POSTFOCUS (WM_USER+120)
+// POSTSIZE-Message; MP1 == nMP1; MP2 == nMP2
+#define SAL_MSG_POSTSIZE (WM_USER+121)
+
+// wParam == wParam; lParam == lParam
+#define SAL_MSG_POSTMOVE (WM_USER+136)
+// wParam == pRECT; lParam == 0
+#define SAL_MSG_POSTPAINT (WM_USER+137)
+// wParam == nFlags; lParam == 0
+#define SAL_MSG_TOTOP (WM_USER+142)
+// wParam == bVisible; lParam == 0
+#define SAL_MSG_SHOW (WM_USER+143)
+
+// SysChild-ToTop; nMP1 = 0; nMP2 = 0
+#define SALOBJ_MSG_TOTOP (WM_USER+150)
+// POSTFOCUS-Message; MP1 == nMP1; MP2 == nMP2 (SHORT1( bFocus ), 0)
+#define SALOBJ_MSG_POSTFOCUS (WM_USER+151)
+
+// wParam == 0; lParam == 0
+#define SAL_MSG_DESTROYFRAME (WM_USER+160)
+// wParam == 0; lParam == pObject;
+#define SAL_MSG_DESTROYOBJECT (WM_USER+161)
+// wParam == 0; lParam == this; lResult == bRet
+#define SAL_MSG_CREATESOUND (WM_USER+162)
+// wParam == 0; lParam == this
+#define SAL_MSG_DESTROYSOUND (WM_USER+163)
+// wParam == hWnd; lParam == 0; lResult == hDC
+#define SAL_MSG_GETDC (WM_USER+164)
+// wParam == hWnd; lParam == 0
+#define SAL_MSG_RELEASEDC (WM_USER+165)
+// wParam == newParentHwnd; lParam == oldHwnd; lResult == newhWnd
+#define SAL_MSG_RECREATEHWND (WM_USER+166)
+// wParam == newParentHwnd; lParam == oldHwnd; lResult == newhWnd
+#define SAL_MSG_RECREATECHILDHWND (WM_USER+167)
+// wParam == 0; lParam == HWND;
+#define SAL_MSG_DESTROYHWND (WM_USER+168)
+// POSTTIMER-Message; wparam = 0, lParam == time
+#define SAL_MSG_POSTTIMER (WM_USER+169)
+
+// -----------------
+// - Helpfunctions -
+// -----------------
+
+inline void SetWindowPtr( HWND hWnd, SalFrame* pThis )
+{
+ WinSetWindowULong( hWnd, SAL_FRAME_THIS, (ULONG)pThis );
+}
+
+inline Os2SalFrame* GetWindowPtr( HWND hWnd )
+{
+ return (Os2SalFrame*)WinQueryWindowULong( hWnd, SAL_FRAME_THIS );
+}
+
+inline void SetSalObjWindowPtr( HWND hWnd, SalObject* pThis )
+{
+ WinSetWindowULong( hWnd, SAL_OBJECT_THIS, (ULONG)pThis );
+}
+
+inline Os2SalObject* GetSalObjWindowPtr( HWND hWnd )
+{
+ return (Os2SalObject*)WinQueryWindowULong( hWnd, SAL_OBJECT_THIS );
+}
+
+#endif // _SV_SALDATA_HXX
diff --git a/vcl/os2/inc/salframe.h b/vcl/os2/inc/salframe.h
new file mode 100644
index 000000000000..f02a39f80955
--- /dev/null
+++ b/vcl/os2/inc/salframe.h
@@ -0,0 +1,166 @@
+/*************************************************************************
+ *
+ * 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_SALFRAME_H
+#define _SV_SALFRAME_H
+
+#include <vcl/sv.h>
+#include <vcl/sysdata.hxx>
+#include <vcl/salframe.hxx>
+
+
+#ifndef PM_BIDI_INCLUDED
+#include <pmbidi.h>
+#endif
+
+#ifndef __UCONV_H__
+#include <uconv.h>
+#endif
+
+#ifndef __UNIDEF_H__
+#include <unidef.h>
+#endif
+
+#ifndef __UNIKBD_H__
+#include <unikbd.h>
+#endif
+
+//class SalFrame;
+class Os2SalGraphics;
+
+// ----------------
+// - SalFrameData -
+// ----------------
+
+//class SalFrameData
+class Os2SalFrame : public SalFrame
+{
+public:
+ HWND mhWndFrame; // HWND-Frame
+ HWND mhWndClient; // HWND-Client
+ HAB mhAB; // HAB
+ HPOINTER mhPointer; // Current MousePointer
+ void* mpInst; // VCL-Instance
+ //SALFRAMEPROC mpProc; // VCL-Proc
+ Os2SalGraphics* mpGraphics; // current frame graphics
+ Os2SalFrame* mpNextFrame; // pointer to next frame
+ SystemEnvData maSysData; // system data
+ SalFrameState maState; // frame state
+ int mnShowState; // show state
+ ULONG mnStyle; // SalFrameStyle
+ long mnWidth; // Window-Witdth
+ long mnHeight; // Window-Height
+ SWP maFullScreenRect; // WindowRect befor FullScreenMode
+ BOOL mbGraphics; // is Graphics used
+ BOOL mbAllwayOnTop; // Allways on top modus
+ BOOL mbVisible; // Visible Show/Hide-Status
+ BOOL mbMinHide; // hide called from OS2
+ BOOL mbHandleIME; // TRUE: Wir handeln die IME-Messages
+ BOOL mbConversionMode; // TRUE: Wir befinden uns im Conversion-Modus
+ BOOL mbCandidateMode; // TRUE: Wir befinden uns im Candidate-Modus
+ BOOL mbCaption; // has window a caption
+ BOOL mbBorder; // has window a border
+ BOOL mbFixBorder; // has window a fixed border
+ BOOL mbSizeBorder; // has window a sizeable border
+ BOOL mbNoIcon; // is an window without an icon
+ BOOL mbFloatWin; // is a FloatingWindow
+ BOOL mbFullScreen; // TRUE: in full screen mode
+ BOOL mbPresentation; // TRUE: Presentation Mode running
+ BOOL mbInShow; // innerhalb eines Show-Aufrufs
+ BOOL mbRestoreMaximize; // Restore-Maximize
+ BOOL mbInMoveMsg; // Move-Message wird verarbeitet
+ BOOL mbInSizeMsg; // Size-Message wird verarbeitet
+ BOOL mbFullScreenToolWin; // WS_EX_TOOLWINDOW reset in FullScreenMode
+ BOOL mbDefPos; // default-position
+ BOOL mbOverwriteState; // TRUE: WindowState darf umgesetzt werden
+
+ int mnMinWidth; // min. client width in pixeln
+ int mnMinHeight; // min. client height in pixeln
+ int mnMaxWidth; // max. client width in pixeln
+ int mnMaxHeight; // max. client height in pixeln
+ static ULONG mnInputLang; // current Input Language
+ KHAND mnKeyboardHandle; // current unicode keyboard
+ static BOOL mbInReparent; // TRUE: ignore focus lost and gain due to reparenting
+
+private:
+ Os2SalFrame* mpParentFrame; // parent frame pointer
+
+public:
+ Os2SalFrame();
+ virtual ~Os2SalFrame();
+
+ virtual SalGraphics* GetGraphics();
+ virtual void ReleaseGraphics( SalGraphics* pGraphics );
+ virtual BOOL PostEvent( void* pData );
+ virtual void SetTitle( const XubString& rTitle );
+ virtual void SetIcon( USHORT nIcon );
+ virtual void SetMenu( SalMenu* pSalMenu );
+ virtual void DrawMenuBar();
+ virtual void SetExtendedFrameStyle( SalExtStyle nExtStyle );
+ virtual void Show( BOOL bVisible, BOOL bNoActivate = FALSE );
+ virtual void Enable( BOOL bEnable );
+ virtual void SetMinClientSize( long nWidth, long nHeight );
+ virtual void SetMaxClientSize( long nWidth, long nHeight );
+ virtual void SetPosSize( long nX, long nY, long nWidth, long nHeight, USHORT nFlags );
+ virtual void GetClientSize( long& rWidth, long& rHeight );
+ virtual void GetWorkArea( RECTL& rRect );
+ virtual void GetWorkArea( Rectangle& rRect );
+ virtual SalFrame* GetParent() const;
+ virtual void SetWindowState( const SalFrameState* pState );
+ virtual BOOL GetWindowState( SalFrameState* pState );
+ virtual void ShowFullScreen( BOOL bFullScreen, sal_Int32 nDisplay );
+ virtual void StartPresentation( BOOL bStart );
+ virtual void SetAlwaysOnTop( BOOL bOnTop );
+ virtual void ToTop( USHORT nFlags );
+ virtual void SetPointer( PointerStyle ePointerStyle );
+ virtual void CaptureMouse( BOOL bMouse );
+ virtual void SetPointerPos( long nX, long nY );
+ virtual void Flush();
+ virtual void Sync();
+ virtual void SetInputContext( SalInputContext* pContext );
+ virtual void EndExtTextInput( USHORT nFlags );
+ virtual String GetKeyName( USHORT nKeyCode );
+ virtual String GetSymbolKeyName( const XubString& rFontName, USHORT nKeyCode );
+ virtual BOOL MapUnicodeToKeyCode( sal_Unicode aUnicode, LanguageType aLangType, KeyCode& rKeyCode );
+ virtual LanguageType GetInputLanguage();
+ virtual SalBitmap* SnapShot();
+ virtual void UpdateSettings( AllSettings& rSettings );
+ virtual void Beep( SoundType eSoundType );
+ virtual const SystemEnvData* GetSystemData() const;
+ virtual SalPointerState GetPointerState();
+ virtual void SetParent( SalFrame* pNewParent );
+ virtual bool SetPluginParent( SystemParentData* pNewParent );
+ virtual void SetBackgroundBitmap( SalBitmap* );
+ virtual void SetScreenNumber( unsigned int );
+ virtual void ResetClipRegion();
+ virtual void BeginSetClipRegion( ULONG nRects );
+ virtual void UnionClipRegion( long nX, long nY, long nWidth, long nHeight );
+ virtual void EndSetClipRegion();
+
+};
+
+#endif // _SV_SALFRAME_H
diff --git a/vcl/os2/inc/salgdi.h b/vcl/os2/inc/salgdi.h
new file mode 100644
index 000000000000..cf05ff15d7e2
--- /dev/null
+++ b/vcl/os2/inc/salgdi.h
@@ -0,0 +1,373 @@
+/*************************************************************************
+ *
+ * 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_SALGDI_H
+#define _SV_SALGDI_H
+
+#include <vcl/sv.h>
+#include <vcl/sallayout.hxx>
+#include <vcl/salgdi.hxx>
+#include <vcl/outfont.hxx>
+#include <vcl/impfont.hxx>
+
+#include <hash_set>
+
+class ImplOs2FontEntry;
+
+// -----------
+// - Defines -
+// -----------
+
+// win32 platform specific options. Move them to the PMK file?
+#define GCP_USEKERNING 0x0008
+#define USE_UNISCRIBE
+#define GCP_KERN_HACK
+#define GNG_VERT_HACK
+
+// os2 specific physically available font face
+class ImplOs2FontData : public ImplFontData
+{
+public:
+ ImplOs2FontData( PFONTMETRICS,
+ int nFontHeight,
+ BYTE nPitchAndFamily );
+ ~ImplOs2FontData();
+
+ virtual ImplFontData* Clone() const;
+ virtual ImplFontEntry* CreateFontInstance( ImplFontSelectData& ) const;
+ virtual sal_IntPtr GetFontId() const;
+ void SetFontId( sal_IntPtr nId ) { mnId = nId; }
+ void UpdateFromHPS( HPS ) const;
+
+ bool HasChar( sal_uInt32 cChar ) const;
+
+ PFONTMETRICS GetFontMetrics() const { return pFontMetric; }
+ USHORT GetCharSet() const { return meOs2CharSet; }
+ BYTE GetPitchAndFamily() const { return mnPitchAndFamily; }
+ bool IsGlyphApiDisabled() const { return mbDisableGlyphApi; }
+ bool SupportsKorean() const { return mbHasKoreanRange; }
+ bool SupportsCJK() const { return mbHasCJKSupport; }
+ bool AliasSymbolsHigh() const { return mbAliasSymbolsHigh; }
+ bool AliasSymbolsLow() const { return mbAliasSymbolsLow; }
+
+ ImplFontCharMap* GetImplFontCharMap() const;
+
+private:
+ sal_IntPtr mnId;
+ mutable bool mbDisableGlyphApi;
+ mutable bool mbHasKoreanRange;
+ mutable bool mbHasCJKSupport;
+
+ mutable ImplFontCharMap* mpUnicodeMap;
+
+ // TODO: get rid of the members below needed to work with the Win9x non-unicode API
+ BYTE* mpFontCharSets; // all Charsets for the current font (used on W98 for kerning)
+ BYTE mnFontCharSetCount; // Number of Charsets of the current font; 0 - if not queried
+ USHORT meOs2CharSet;
+ BYTE mnPitchAndFamily;
+ bool mbAliasSymbolsHigh;
+ bool mbAliasSymbolsLow;
+ PFONTMETRICS pFontMetric;
+
+private:
+ void ReadCmapTable( HDC ) const;
+ void ReadOs2Table( HDC ) const;
+
+#ifdef GNG_VERT_HACK
+ void ReadGsubTable( HDC ) const;
+
+ typedef std::hash_set<int> IntHashSet;
+ mutable IntHashSet maGsubTable;
+ mutable bool mbGsubRead;
+public:
+ bool HasGSUBstitutions( HDC ) const;
+ bool IsGSUBstituted( sal_Unicode ) const;
+#endif // GNG_VERT_HACK
+
+};
+
+
+// -------------------
+// - SalGraphicsData -
+// -------------------
+
+class Os2SalGraphics : public SalGraphics
+{
+public:
+ HPS mhPS; // HPS
+ HDC mhDC; // HDC
+ HWND mhWnd; // HWND
+ LONG mnHeight; // Height of frame Window
+ ULONG mnClipElementCount; // number of clip rects in clip rect array
+ RECTL* mpClipRectlAry; // clip rect array
+ ULONG mnFontMetricCount; // number of entries in the font list
+ PFONTMETRICS mpFontMetrics; // cached font list
+ LONG mnOrientationX; // X-Font orientation
+ LONG mnOrientationY; // Y-Font orientation
+ BOOL mbLine; // draw lines
+ BOOL mbFill; // fill areas
+ BOOL mbPrinter; // is Printer
+ BOOL mbVirDev; // is VirDev
+ BOOL mbWindow; // is Window
+ BOOL mbScreen; // is Screen compatible
+ bool mbXORMode; // _every_ output with RasterOp XOR
+ ULONG mhFonts[ MAX_FALLBACK ]; // Font + Fallbacks
+ const ImplOs2FontData* mpOs2FontData[ MAX_FALLBACK ]; // pointer to the most recent font face
+ ImplOs2FontEntry* mpOs2FontEntry[ MAX_FALLBACK ]; // pointer to the most recent font instance
+ ULONG mhDefFont; // DefaultFont
+ float mfFontScale; // allows metrics emulation of huge font sizes
+ BOOL mbFontKernInit; // FALSE: FontKerns must be queried
+ KERNINGPAIRS* mpFontKernPairs; // Kerning Pairs of the current Font
+ ULONG mnFontKernPairCount;// Number of Kerning Pairs of the current Font
+
+ USHORT ImplDoSetFont( ImplFontSelectData* i_pFont, float& o_rFontScale, int );
+
+public:
+ Os2SalGraphics();
+ virtual ~Os2SalGraphics();
+
+protected:
+ virtual BOOL unionClipRegion( long nX, long nY, long nWidth, long nHeight );
+ virtual bool unionClipRegion( const ::basegfx::B2DPolyPolygon& );
+ // draw --> LineColor and FillColor and RasterOp and ClipRegion
+ virtual void drawPixel( long nX, long nY );
+ virtual void drawPixel( long nX, long nY, SalColor nSalColor );
+ virtual void drawLine( long nX1, long nY1, long nX2, long nY2 );
+ virtual void drawRect( long nX, long nY, long nWidth, long nHeight );
+ virtual void drawPolyLine( ULONG nPoints, const SalPoint* pPtAry );
+ virtual void drawPolygon( ULONG nPoints, const SalPoint* pPtAry );
+ virtual void drawPolyPolygon( ULONG nPoly, const ULONG* pPoints, PCONSTSALPOINT* pPtAry );
+ virtual bool drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double fTransparency );
+ virtual bool drawPolyLine( const ::basegfx::B2DPolygon&, double fTransparency, const ::basegfx::B2DVector& rLineWidth, basegfx::B2DLineJoin );
+ virtual sal_Bool drawPolyLineBezier( ULONG nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry );
+ virtual sal_Bool drawPolygonBezier( ULONG nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry );
+ virtual sal_Bool drawPolyPolygonBezier( ULONG nPoly, const ULONG* pPoints, const SalPoint* const* pPtAry, const BYTE* const* pFlgAry );
+
+ // CopyArea --> No RasterOp, but ClipRegion
+ virtual void copyArea( long nDestX, long nDestY, long nSrcX, long nSrcY, long nSrcWidth,
+ long nSrcHeight, USHORT nFlags );
+
+ // CopyBits and DrawBitmap --> RasterOp and ClipRegion
+ // CopyBits() --> pSrcGraphics == NULL, then CopyBits on same Graphics
+ virtual void copyBits( const SalTwoRect* pPosAry, SalGraphics* pSrcGraphics );
+ virtual void drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap );
+ virtual void drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ SalColor nTransparentColor );
+ virtual void drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ const SalBitmap& rTransparentBitmap );
+ virtual void drawMask( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ SalColor nMaskColor );
+
+ virtual SalBitmap* getBitmap( long nX, long nY, long nWidth, long nHeight );
+ virtual SalColor getPixel( long nX, long nY );
+
+ // invert --> ClipRegion (only Windows or VirDevs)
+ virtual void invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags);
+ virtual void invert( ULONG nPoints, const SalPoint* pPtAry, SalInvert nFlags );
+
+ virtual BOOL drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, ULONG nSize );
+
+#if 0
+ // native widget rendering methods that require mirroring
+ virtual BOOL hitTestNativeControl( ControlType nType, ControlPart nPart, const Region& rControlRegion,
+ const Point& aPos, BOOL& rIsInside );
+ virtual BOOL drawNativeControl( ControlType nType, ControlPart nPart, const Region& rControlRegion,
+ ControlState nState, const ImplControlValue& aValue,
+ rtl::OUString aCaption );
+ virtual BOOL drawNativeControlText( ControlType nType, ControlPart nPart, const Region& rControlRegion,
+ ControlState nState, const ImplControlValue& aValue,
+ rtl::OUString aCaption );
+ virtual BOOL getNativeControlRegion( ControlType nType, ControlPart nPart, const Region& rControlRegion, ControlState nState,
+ const ImplControlValue& aValue, rtl::OUString aCaption,
+ Region &rNativeBoundingRegion, Region &rNativeContentRegion );
+#endif
+
+ virtual bool drawAlphaBitmap( const SalTwoRect&,
+ const SalBitmap& rSourceBitmap,
+ const SalBitmap& rAlphaBitmap );
+ virtual bool drawAlphaRect( long nX, long nY, long nWidth, long nHeight, sal_uInt8 nTransparency );
+
+public:
+ // public SalGraphics methods, the interface to teh independent vcl part
+
+ // get device resolution
+ virtual void GetResolution( long& rDPIX, long& rDPIY );
+ // get the depth of the device
+ virtual USHORT GetBitCount();
+ // get the width of the device
+ virtual long GetGraphicsWidth() const;
+
+ // set the clip region to empty
+ virtual void ResetClipRegion();
+ // begin setting the clip region, add rectangles to the
+ // region with the UnionClipRegion call
+ virtual void BeginSetClipRegion( ULONG nCount );
+ // all rectangles were added and the clip region should be set now
+ virtual void EndSetClipRegion();
+
+ // set the line color to transparent (= don't draw lines)
+ virtual void SetLineColor();
+ // set the line color to a specific color
+ virtual void SetLineColor( SalColor nSalColor );
+ // set the fill color to transparent (= don't fill)
+ virtual void SetFillColor();
+ // set the fill color to a specific color, shapes will be
+ // filled accordingly
+ virtual void SetFillColor( SalColor nSalColor );
+ // enable/disable XOR drawing
+ virtual void SetXORMode( bool bSet, bool );
+ // set line color for raster operations
+ virtual void SetROPLineColor( SalROPColor nROPColor );
+ // set fill color for raster operations
+ virtual void SetROPFillColor( SalROPColor nROPColor );
+ // set the text color to a specific color
+ virtual void SetTextColor( SalColor nSalColor );
+ // set the font
+ virtual USHORT SetFont( ImplFontSelectData*, int nFallbackLevel );
+ // get the current font's etrics
+ virtual void GetFontMetric( ImplFontMetricData* );
+ // get kernign pairs of the current font
+ // return only PairCount if (pKernPairs == NULL)
+ virtual ULONG GetKernPairs( ULONG nPairs, ImplKernPairData* pKernPairs );
+ // get the repertoire of the current font
+ virtual ImplFontCharMap* GetImplFontCharMap() const;
+ // graphics must fill supplied font list
+ virtual void GetDevFontList( ImplDevFontList* );
+ // graphics should call ImplAddDevFontSubstitute on supplied
+ // OutputDevice for all its device specific preferred font substitutions
+ virtual void GetDevFontSubstList( OutputDevice* );
+ virtual bool AddTempDevFont( ImplDevFontList*, const String& rFileURL, const String& rFontName );
+ // CreateFontSubset: a method to get a subset of glyhps of a font
+ // inside a new valid font file
+ // returns TRUE if creation of subset was successfull
+ // parameters: rToFile: contains a osl file URL to write the subset to
+ // pFont: describes from which font to create a subset
+ // pGlyphIDs: the glyph ids to be extracted
+ // pEncoding: the character code corresponding to each glyph
+ // pWidths: the advance widths of the correspoding glyphs (in PS font units)
+ // nGlyphs: the number of glyphs
+ // rInfo: additional outgoing information
+ // implementation note: encoding 0 with glyph id 0 should be added implicitly
+ // as "undefined character"
+ virtual BOOL CreateFontSubset( const rtl::OUString& rToFile,
+ const ImplFontData* pFont,
+ long* pGlyphIDs,
+ sal_uInt8* pEncoding,
+ sal_Int32* pWidths,
+ int nGlyphs,
+ FontSubsetInfo& rInfo // out parameter
+ );
+
+ // GetFontEncodingVector: a method to get the encoding map Unicode
+ // to font encoded character; this is only used for type1 fonts and
+ // may return NULL in case of unknown encoding vector
+ // if ppNonEncoded is set and non encoded characters (that is type1
+ // glyphs with only a name) exist it is set to the corresponding
+ // map for non encoded glyphs; the encoding vector contains -1
+ // as encoding for these cases
+ virtual const Ucs2SIntMap* GetFontEncodingVector( const ImplFontData*, const Ucs2OStrMap** ppNonEncoded );
+
+ // GetEmbedFontData: gets the font data for a font marked
+ // embeddable by GetDevFontList or NULL in case of error
+ // parameters: pFont: describes the font in question
+ // pWidths: the widths of all glyphs from char code 0 to 255
+ // pWidths MUST support at least 256 members;
+ // rInfo: additional outgoing information
+ // pDataLen: out parameter, contains the byte length of the returned buffer
+ virtual const void* GetEmbedFontData( const ImplFontData*,
+ const sal_Ucs* pUnicodes,
+ sal_Int32* pWidths,
+ FontSubsetInfo& rInfo,
+ long* pDataLen );
+ // frees the font data again
+ virtual void FreeEmbedFontData( const void* pData, long nDataLen );
+
+ virtual void GetGlyphWidths( const ImplFontData* pFont,
+ bool bVertical,
+ Int32Vector& rWidths,
+ Ucs2UIntMap& rUnicodeEnc );
+
+ virtual BOOL GetGlyphBoundRect( long nIndex, Rectangle& );
+ virtual BOOL GetGlyphOutline( long nIndex, ::basegfx::B2DPolyPolygon& );
+
+ virtual SalLayout* GetTextLayout( ImplLayoutArgs&, int nFallbackLevel );
+ virtual void DrawServerFontLayout( const ServerFontLayout& );
+ virtual bool supportsOperation( OutDevSupportType ) const;
+
+ // Query the platform layer for control support
+ virtual BOOL IsNativeControlSupported( ControlType nType, ControlPart nPart );
+
+ virtual SystemGraphicsData GetGraphicsData() const;
+ virtual SystemFontData GetSysFontData( int nFallbacklevel ) const;
+};
+
+// Init/Deinit Graphics
+void ImplSalInitGraphics( Os2SalGraphics* mpData );
+void ImplSalDeInitGraphics( Os2SalGraphics* mpData );
+
+// -----------
+// - Defines -
+// -----------
+
+#define RGBCOLOR(r,g,b) ((ULONG)(((BYTE)(b)|((USHORT)(g)<<8))|(((ULONG)(BYTE)(r))<<16)))
+#define TY( y ) (mnHeight-(y)-1)
+
+// offset for lcid field, used for fallback font selection
+#define LCID_BASE 100
+
+// -----------
+// - Inlines -
+// -----------
+
+// #102411# Win's GCP mishandles kerning => we need to do it ourselves
+// SalGraphicsData::mpFontKernPairs is sorted by
+inline bool ImplCmpKernData( const KERNINGPAIRS& a, const KERNINGPAIRS& b )
+{
+ if( a.sFirstChar < b.sFirstChar )
+ return true;
+ if( a.sFirstChar > b.sFirstChar )
+ return false;
+ return (a.sSecondChar < b.sSecondChar);
+}
+
+// called extremely often from just one spot => inline
+inline bool ImplOs2FontData::HasChar( sal_uInt32 cChar ) const
+{
+ if( mpUnicodeMap->HasChar( cChar ) )
+ return true;
+ // second chance to allow symbol aliasing
+ if( mbAliasSymbolsLow && ((cChar-0xF000) <= 0xFF) )
+ cChar -= 0xF000;
+ else if( mbAliasSymbolsHigh && (cChar <= 0xFF) )
+ cChar += 0xF000;
+ return mpUnicodeMap->HasChar( cChar );
+}
+
+#endif // _SV_SALGDI_H
diff --git a/vcl/os2/inc/salids.hrc b/vcl/os2/inc/salids.hrc
new file mode 100644
index 000000000000..b5f2260d307f
--- /dev/null
+++ b/vcl/os2/inc/salids.hrc
@@ -0,0 +1,109 @@
+/*************************************************************************
+ *
+ * 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_SALIDS_HRC
+#define _SV_SALIDS_HRC
+
+// Pointer
+#define SAL_RESID_POINTER_NULL 10000
+#define SAL_RESID_POINTER_HELP 10001
+#define SAL_RESID_POINTER_CROSS 10002
+#define SAL_RESID_POINTER_MOVE 10003
+#define SAL_RESID_POINTER_HSPLIT 10004
+#define SAL_RESID_POINTER_VSPLIT 10005
+#define SAL_RESID_POINTER_HSIZEBAR 10006
+#define SAL_RESID_POINTER_VSIZEBAR 10007
+#define SAL_RESID_POINTER_HAND 10008
+#define SAL_RESID_POINTER_REFHAND 10009
+#define SAL_RESID_POINTER_PEN 10010
+#define SAL_RESID_POINTER_MAGNIFY 10011
+#define SAL_RESID_POINTER_FILL 10012
+#define SAL_RESID_POINTER_ROTATE 10013
+#define SAL_RESID_POINTER_HSHEAR 10014
+#define SAL_RESID_POINTER_VSHEAR 10015
+#define SAL_RESID_POINTER_MIRROR 10016
+#define SAL_RESID_POINTER_CROOK 10017
+#define SAL_RESID_POINTER_CROP 10018
+#define SAL_RESID_POINTER_MOVEPOINT 10019
+#define SAL_RESID_POINTER_MOVEBEZIERWEIGHT 10020
+#define SAL_RESID_POINTER_MOVEDATA 10021
+#define SAL_RESID_POINTER_COPYDATA 10022
+#define SAL_RESID_POINTER_LINKDATA 10023
+#define SAL_RESID_POINTER_MOVEDATALINK 10024
+#define SAL_RESID_POINTER_COPYDATALINK 10025
+#define SAL_RESID_POINTER_MOVEFILE 10026
+#define SAL_RESID_POINTER_COPYFILE 10027
+#define SAL_RESID_POINTER_LINKFILE 10028
+#define SAL_RESID_POINTER_MOVEFILELINK 10029
+#define SAL_RESID_POINTER_COPYFILELINK 10030
+#define SAL_RESID_POINTER_MOVEFILES 10031
+#define SAL_RESID_POINTER_COPYFILES 10032
+#define SAL_RESID_POINTER_DRAW_LINE 10033
+#define SAL_RESID_POINTER_DRAW_RECT 10034
+#define SAL_RESID_POINTER_DRAW_POLYGON 10035
+#define SAL_RESID_POINTER_DRAW_BEZIER 10036
+#define SAL_RESID_POINTER_DRAW_ARC 10037
+#define SAL_RESID_POINTER_DRAW_PIE 10038
+#define SAL_RESID_POINTER_DRAW_CIRCLECUT 10039
+#define SAL_RESID_POINTER_DRAW_ELLIPSE 10040
+#define SAL_RESID_POINTER_DRAW_FREEHAND 10041
+#define SAL_RESID_POINTER_DRAW_CONNECT 10042
+#define SAL_RESID_POINTER_DRAW_TEXT 10043
+#define SAL_RESID_POINTER_DRAW_CAPTION 10044
+#define SAL_RESID_POINTER_CHART 10045
+#define SAL_RESID_POINTER_DETECTIVE 10046
+#define SAL_RESID_POINTER_PIVOT_COL 10047
+#define SAL_RESID_POINTER_PIVOT_ROW 10048
+#define SAL_RESID_POINTER_PIVOT_FIELD 10049
+#define SAL_RESID_POINTER_CHAIN 10050
+#define SAL_RESID_POINTER_CHAIN_NOTALLOWED 10051
+#define SAL_RESID_POINTER_TIMEEVENT_MOVE 10052
+#define SAL_RESID_POINTER_TIMEEVENT_SIZE 10053
+#define SAL_RESID_POINTER_AUTOSCROLL_N 10054
+#define SAL_RESID_POINTER_AUTOSCROLL_S 10055
+#define SAL_RESID_POINTER_AUTOSCROLL_W 10056
+#define SAL_RESID_POINTER_AUTOSCROLL_E 10057
+#define SAL_RESID_POINTER_AUTOSCROLL_NW 10058
+#define SAL_RESID_POINTER_AUTOSCROLL_NE 10059
+#define SAL_RESID_POINTER_AUTOSCROLL_SW 10060
+#define SAL_RESID_POINTER_AUTOSCROLL_SE 10061
+#define SAL_RESID_POINTER_AUTOSCROLL_NS 10062
+#define SAL_RESID_POINTER_AUTOSCROLL_WE 10063
+#define SAL_RESID_POINTER_AUTOSCROLL_NSWE 10064
+#define SAL_RESID_POINTER_AIRBRUSH 10070
+#define SAL_RESID_POINTER_TEXT_VERTICAL 10071
+#define SAL_RESID_POINTER_PIVOT_DELETE 10072
+#define SAL_RESID_POINTER_TAB_SELECT_S 10073
+#define SAL_RESID_POINTER_TAB_SELECT_E 10074
+#define SAL_RESID_POINTER_TAB_SELECT_SE 10075
+#define SAL_RESID_POINTER_TAB_SELECT_W 10076
+#define SAL_RESID_POINTER_TAB_SELECT_SW 10077
+#define SAL_RESID_POINTER_PAINTBRUSH 10078
+
+#define SAL_RESID_ICON_DEFAULT 1
+
+#endif // _SV_SALIDS_HRC
diff --git a/vcl/os2/inc/salinst.h b/vcl/os2/inc/salinst.h
new file mode 100644
index 000000000000..0948f605c286
--- /dev/null
+++ b/vcl/os2/inc/salinst.h
@@ -0,0 +1,103 @@
+/*************************************************************************
+ *
+ * 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_SALINST_H
+#define _SV_SALINST_H
+
+#include <vcl/sv.h>
+#include <vcl/salinst.hxx>
+
+namespace vos { class OMutex; }
+
+// -------------------
+// - SalInstanceData -
+// -------------------
+
+class SalYieldMutex;
+
+#define SAL_COMMANDLINENOINIT ((USHORT)0xFFFF)
+#define SAL_MAXPARAM 40
+
+class Os2SalInstance : public SalInstance
+{
+public:
+ HAB mhAB; // anchor block handle
+ HMQ mhMQ; // handle of os2 message queue
+ HPOINTER mhAppIcon; // app icon
+ int mnArgc; // commandline param count
+ char** mpArgv; // commandline
+ HWND mhComWnd; // window, for communication (between threads and the main thread)
+ SalYieldMutex* mpSalYieldMutex; // Sal-Yield-Mutex
+ vos::OMutex* mpSalWaitMutex; // Sal-Wait-Mutex
+ USHORT mnYieldWaitCount; // Wait-Count
+
+public:
+ Os2SalInstance();
+ virtual ~Os2SalInstance();
+
+ virtual SalFrame* CreateChildFrame( SystemParentData* pParent, ULONG nStyle );
+ virtual SalFrame* CreateFrame( SalFrame* pParent, ULONG nStyle );
+ virtual void DestroyFrame( SalFrame* pFrame );
+ virtual SalObject* CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, BOOL bShow = TRUE );
+ virtual void DestroyObject( SalObject* pObject );
+ virtual SalVirtualDevice* CreateVirtualDevice( SalGraphics* pGraphics,
+ long nDX, long nDY,
+ USHORT nBitCount, const SystemGraphicsData *pData );
+ virtual void DestroyVirtualDevice( SalVirtualDevice* pDevice );
+
+ virtual SalInfoPrinter* CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
+ ImplJobSetup* pSetupData );
+ virtual void DestroyInfoPrinter( SalInfoPrinter* pPrinter );
+ virtual SalPrinter* CreatePrinter( SalInfoPrinter* pInfoPrinter );
+ virtual void DestroyPrinter( SalPrinter* pPrinter );
+ virtual void GetPrinterQueueInfo( ImplPrnQueueList* pList );
+ virtual void GetPrinterQueueState( SalPrinterQueueInfo* pInfo );
+ virtual void DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo );
+ virtual String GetDefaultPrinter();
+ virtual SalTimer* CreateSalTimer();
+ virtual SalI18NImeStatus* CreateI18NImeStatus();
+ virtual SalSystem* CreateSalSystem();
+ virtual SalBitmap* CreateSalBitmap();
+ virtual vos::IMutex* GetYieldMutex();
+ virtual ULONG ReleaseYieldMutex();
+ virtual void AcquireYieldMutex( ULONG nCount );
+ virtual void Yield( bool, bool );
+ virtual bool AnyInput( USHORT nType );
+ virtual SalMenu* CreateMenu( BOOL bMenuBar );
+ virtual void DestroyMenu( SalMenu* );
+ virtual SalMenuItem* CreateMenuItem( const SalItemParams* pItemData );
+ virtual void DestroyMenuItem( SalMenuItem* );
+ virtual SalSession* CreateSalSession();
+ virtual void* GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes );
+ virtual void AddToRecentDocumentList(const rtl::OUString& rFileUrl, const rtl::OUString& rMimeType);
+};
+
+SalFrame* ImplSalCreateFrame( Os2SalInstance* pInst, HWND hWndParent, ULONG nSalFrameStyle );
+SalObject* ImplSalCreateObject( Os2SalInstance* pInst, Os2SalFrame* pParent );
+void ImplSalStartTimer( ULONG nMS, BOOL bMutex = FALSE );
+
+#endif // _SV_SALINST_H
diff --git a/vcl/os2/inc/sallang.hxx b/vcl/os2/inc/sallang.hxx
new file mode 100644
index 000000000000..72d2566571a6
--- /dev/null
+++ b/vcl/os2/inc/sallang.hxx
@@ -0,0 +1,70 @@
+/*************************************************************************
+ *
+ * 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 _SALLANG_HXX
+#define _SALLANG_HXX
+
+//#ifndef _TOOLS_LANG_HXX
+//#include <tools/lang.hxx>
+//#endif
+#include <i18npool/mslangid.hxx>
+
+// --------------------
+// - Language Strings -
+// --------------------
+
+// --- Key-Namen ---
+#define LSTR_KEY_SHIFT 0
+#define LSTR_KEY_CTRL 1
+#define LSTR_KEY_ALT 2
+#define LSTR_KEY_UP 3
+#define LSTR_KEY_DOWN 4
+#define LSTR_KEY_LEFT 5
+#define LSTR_KEY_RIGHT 6
+#define LSTR_KEY_HOME 7
+#define LSTR_KEY_END 8
+#define LSTR_KEY_PAGEUP 9
+#define LSTR_KEY_PAGEDOWN 10
+#define LSTR_KEY_RETURN 11
+#define LSTR_KEY_ESC 12
+#define LSTR_KEY_TAB 13
+#define LSTR_KEY_BACKSPACE 14
+#define LSTR_KEY_SPACE 15
+#define LSTR_KEY_INSERT 16
+#define LSTR_KEY_DELETE 17
+
+// --- Anzahl der Texte ---
+
+#define LSTR_COUNT 18
+
+// --------------------------------------------
+// - Methoden zum Abfragen der Sprach-Strings -
+// --------------------------------------------
+
+const sal_Unicode** ImplGetLangTab( LanguageType eLang );
+
+#endif // _SALLANG_HXX
diff --git a/vcl/os2/inc/sallayout.h b/vcl/os2/inc/sallayout.h
new file mode 100644
index 000000000000..8444b5e758a9
--- /dev/null
+++ b/vcl/os2/inc/sallayout.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALLAYOUT_H
+#define _SV_SALLAYOUT_H
+
+#if 0
+#include <sv.h>
+#include <sallayout.hxx>
+
+class ImplOs2FontEntry;
+
+class Os2SalLayout : public GenericSalLayout
+{
+public:
+ Os2SalLayout( HPS);
+ virtual bool LayoutText( ImplLayoutArgs& );
+ virtual void AdjustLayout( ImplLayoutArgs& );
+ virtual void DrawText( SalGraphics& ) const;
+
+protected:
+ HPS mhPS;
+ FONTMETRICS FontMetrics;
+ int mnBaseAdv;
+
+private:
+ int mnGlyphCount;
+ int mnCharCount;
+ sal_Unicode* mpOutGlyphs;
+ int* mpGlyphAdvances; // if possible this is shared with mpGlyphAdvances[]
+ int* mpGlyphOrigAdvs;
+ int* mpCharWidths; // map rel char pos to char width
+ int* mpChars2Glyphs; // map rel char pos to abs glyph pos
+ int* mpGlyphs2Chars; // map abs glyph pos to abs char pos
+ bool* mpGlyphRTLFlags; // BiDi status for glyphs: true=>RTL
+ mutable long mnWidth;
+ bool mbDisableGlyphs;
+
+ int mnNotdefWidth;
+ BYTE mnCharSet;
+
+};
+#endif
+
+#endif // _SV_SALLAYOUT_H
diff --git a/vcl/os2/inc/salmenu.h b/vcl/os2/inc/salmenu.h
new file mode 100644
index 000000000000..081158bf81f7
--- /dev/null
+++ b/vcl/os2/inc/salmenu.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALMENU_H
+#define _SV_SALMENU_H
+
+#include <vcl/sv.h>
+#include <vcl/bitmap.hxx>
+#include <vcl/salmenu.hxx>
+
+
+class Os2SalMenu : public SalMenu
+{
+public:
+ Os2SalMenu() {}
+ virtual ~Os2SalMenu();
+
+ virtual BOOL VisibleMenuBar(); // must return TRUE to actually DISPLAY native menu bars
+ // otherwise only menu messages are processed (eg, OLE on Windows)
+
+ virtual void InsertItem( SalMenuItem* pSalMenuItem, unsigned nPos );
+ virtual void RemoveItem( unsigned nPos );
+ virtual void SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos );
+ virtual void SetFrame( const SalFrame* pFrame );
+ virtual void CheckItem( unsigned nPos, BOOL bCheck );
+ virtual void EnableItem( unsigned nPos, BOOL bEnable );
+ virtual void SetItemText( unsigned nPos, SalMenuItem* pSalMenuItem, const XubString& rText );
+ virtual void SetItemImage( unsigned nPos, SalMenuItem* pSalMenuItem, const Image& rImage);
+ virtual void SetAccelerator( unsigned nPos, SalMenuItem* pSalMenuItem, const KeyCode& rKeyCode, const XubString& rKeyName );
+ virtual void GetSystemMenuData( SystemMenuData* pData );
+};
+
+class Os2SalMenuItem : public SalMenuItem
+{
+public:
+ Os2SalMenuItem() {}
+ virtual ~Os2SalMenuItem();
+};
+
+#endif // _SV_SALMENU_H
+
diff --git a/vcl/os2/inc/salobj.h b/vcl/os2/inc/salobj.h
new file mode 100644
index 000000000000..5b4ac21ccdd6
--- /dev/null
+++ b/vcl/os2/inc/salobj.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALOBJ_H
+#define _SV_SALOBJ_H
+
+#include <vcl/sv.h>
+#include <vcl/salobj.hxx>
+
+// -----------------
+// - SalObjectData -
+// -----------------
+
+class Os2SalObject : public SalObject
+{
+public:
+ HWND mhWnd; // Window handle
+ HWND mhWndChild; // Child Window handle
+ HWND mhLastFocusWnd; // Child-Window, welches als letztes den Focus hatte
+ SystemChildData maSysData; // SystemEnvData
+ HWND mhLastClipWnd; // LastClip-Window
+ HWND mhOldLastClipWnd; // LastClip-Window befor BeginSetClipRegion
+ long mnHeight; // Fenster-Hoehe fuer Positionsumrechnung
+ Os2SalObject* mpNextObject; // pointer to next object
+ void* mpInst; // instance handle for callback
+ SALOBJECTPROC mpProc; // callback proc
+
+ Os2SalObject();
+ virtual ~Os2SalObject();
+
+ virtual void ResetClipRegion();
+ virtual USHORT GetClipRegionType();
+ virtual void BeginSetClipRegion( ULONG nRects );
+ virtual void UnionClipRegion( long nX, long nY, long nWidth, long nHeight );
+ virtual void EndSetClipRegion();
+ virtual void SetPosSize( long nX, long nY, long nWidth, long nHeight );
+ virtual void Show( BOOL bVisible );
+ virtual void Enable( BOOL nEnable );
+ virtual void GrabFocus();
+ virtual void SetBackground();
+ virtual void SetBackground( SalColor nSalColor );
+ virtual const SystemEnvData* GetSystemData() const;
+};
+
+#endif // _SV_SALOBJ_H
diff --git a/vcl/os2/inc/salprn.h b/vcl/os2/inc/salprn.h
new file mode 100644
index 000000000000..4cb7700ffaae
--- /dev/null
+++ b/vcl/os2/inc/salprn.h
@@ -0,0 +1,146 @@
+/*************************************************************************
+ *
+ * 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_SALPRN_H
+#define _SV_SALPRN_H
+
+#include <vcl/sv.h>
+#include <vcl/salprn.hxx>
+
+class SalGraphics;
+class SalInfoPrinter;
+
+struct ImplFormInfo;
+typedef ImplFormInfo* PIMPLFORMINFO;
+struct ImplTrayInfo;
+typedef ImplTrayInfo* PIMPLTRAYINFO;
+
+// ----------------------
+// - SalInfoPrinterData -
+// ----------------------
+
+//class SalInfoPrinterData
+class Os2SalInfoPrinter : public SalInfoPrinter
+{
+public:
+ Os2SalGraphics* mpGraphics; // Graphics
+ HDC mhDC; // printer hdc
+ HPS mhPS; // printer hps
+ ByteString maPrinterName; // pszPrinters
+ ByteString maName; // pszName bzw. LogAdress
+ ByteString maDriverName; // pszDriverName nach .
+ ByteString maDeviceName; // pszDriverName bis .
+ ByteString maJobSetupDeviceName; // DeviceName aus pDriverData
+ PIMPLFORMINFO* mpFormArray; // PaperForm-Names
+ USHORT mnFormCount; // PaperForm-Count
+ PIMPLTRAYINFO* mpTrayArray; // PaperTray-Names
+ USHORT mnTrayCount; // PaperTray-Count
+ BOOL mbDJPSupported; // is driver DJP enabled
+ BOOL mbGraphics; // is Graphics used
+
+public:
+ Os2SalInfoPrinter();
+ virtual ~Os2SalInfoPrinter();
+
+ virtual SalGraphics* GetGraphics();
+ virtual void ReleaseGraphics( SalGraphics* pGraphics );
+ virtual BOOL Setup( SalFrame* pFrame, ImplJobSetup* pSetupData );
+ virtual BOOL SetPrinterData( ImplJobSetup* pSetupData );
+ virtual BOOL SetData( ULONG nFlags, ImplJobSetup* pSetupData );
+ virtual void GetPageInfo( const ImplJobSetup* pSetupData,
+ long& rOutWidth, long& rOutHeight,
+ long& rPageOffX, long& rPageOffY,
+ long& rPageWidth, long& rPageHeight );
+ virtual ULONG GetCapabilities( const ImplJobSetup* pSetupData, USHORT nType );
+ virtual ULONG GetPaperBinCount( const ImplJobSetup* pSetupData );
+ virtual String GetPaperBinName( const ImplJobSetup* pSetupData, ULONG nPaperBin );
+ virtual void InitPaperFormats( const ImplJobSetup* pSetupData );
+ virtual int GetLandscapeAngle( const ImplJobSetup* pSetupData );
+};
+
+// ------------------
+// - SalPrinterData -
+// ------------------
+
+class SalPrinterData00
+{
+public:
+ Os2SalGraphics* mpGraphics; // current Printer graphics
+ SalInfoPrinter* mpInfoPrinter; // pointer to the compatible InfoPrinter
+ HDC mhDC; // printer hdc
+ HPS mhPS; // printer hps
+ ULONG mnError; // Error Code
+ BOOL mbFirstPage; // IsFirstPage
+ BOOL mbAbort; // JobAborted
+ BOOL mbPrintDJPSupported; // is driver PrintDJP enabled (DEVESC_NEWFRAME_WPROP)
+ char maCommentBuf[33]; // Comment
+ char maCopyBuf[10]; // Kopien
+};
+
+// -----------------
+// - Os2SalPrinter -
+// -----------------
+
+class Os2SalPrinter : public SalPrinter
+{
+public:
+ Os2SalGraphics* mpGraphics; // current Printer graphics
+ Os2SalInfoPrinter* mpInfoPrinter; // pointer to the compatible InfoPrinter
+ Os2SalPrinter* mpNextPrinter; // next printing printer
+ HDC mhDC; // printer hdc
+ HPS mhPS; // printer hps
+ ULONG mnError; // Error Code
+ BOOL mbFirstPage; // IsFirstPage
+ BOOL mbAbort; // JobAborted
+ BOOL mbPrintDJPSupported; // is driver PrintDJP enabled (DEVESC_NEWFRAME_WPROP)
+ char maCommentBuf[33]; // Comment
+ char maCopyBuf[16]; // Kopien
+ //HDC mhDC; // printer hdc
+ //ULONG mnError; // Error Code
+ //ULONG mnCopies; // Kopien
+ //BOOL mbCollate; // Sortierte Kopien
+ //BOOL mbAbort; // Job Aborted
+
+public:
+ Os2SalPrinter();
+ virtual ~Os2SalPrinter();
+
+ virtual BOOL StartJob( const XubString* pFileName,
+ const XubString& rJobName,
+ const XubString& rAppName,
+ ULONG nCopies,
+ bool bCollate,
+ bool bDirect,
+ ImplJobSetup* pSetupData );
+ virtual BOOL EndJob();
+ virtual BOOL AbortJob();
+ virtual SalGraphics* StartPage( ImplJobSetup* pSetupData, BOOL bNewJobData );
+ virtual BOOL EndPage();
+ virtual ULONG GetErrorCode();
+};
+
+#endif // _SV_SALPRN_H
diff --git a/vcl/os2/inc/salsound.h b/vcl/os2/inc/salsound.h
new file mode 100644
index 000000000000..62536678625d
--- /dev/null
+++ b/vcl/os2/inc/salsound.h
@@ -0,0 +1,94 @@
+/*************************************************************************
+ *
+ * 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_SALSOUND_H
+#define _SV_SALSOUND_H
+
+#include <tools/gen.hxx>
+#include <sv.h>
+#include <tools/string.hxx>
+#include <vcl/salframe.hxx>
+#ifndef _SV_SALSTYPE_HXX
+#include <vcl/salstype.hxx>
+#endif
+#include <vcl/salsound.hxx>
+
+// ------------
+// - SalSound -
+// ------------
+
+//class SalSound
+class Os2SalSound : public SalSound
+{
+private:
+
+ static HMODULE mhMCILib;
+ static ULONG mnSoundState;
+ static void* mpMCIFnc;
+ SALSOUNDPROC mpProc;
+ void* mpInst;
+ ULONG mnStartTime;
+ ULONG mnPlayLen;
+ HWND mhSoundWnd;
+ USHORT mnDeviceId;
+ BOOL mbLoop;
+ BOOL mbPaused;
+
+public:
+
+ void ImplSetError( ULONG nMciErr );
+ void ImplNotify( SoundNotification eNotification, ULONG nError );
+
+public:
+
+ BOOL Create();
+ //static BOOL IsValid() { return( SOUND_STATE_VALID == Os2SalSound::mnSoundState ); }
+ //BOOL Init( SalFrame* pFrame, const String& rSoundName, ULONG& rSoundLen );
+ //BOOL Init( SalFrame* pFrame, const BYTE* pSound, ULONG nDataLen, ULONG& rSoundLen );
+
+ void SetNotifyProc( void* pInst, SALSOUNDPROC pProc )
+ { mpInst = pInst; mpProc = pProc; }
+public:
+ Os2SalSound();
+ virtual ~Os2SalSound();
+
+ virtual bool IsValid();
+ virtual bool Init( const String& rSoundName, ULONG& rSoundLen );
+ virtual void Play( ULONG nStartTime, ULONG nPlayTime, bool bLoop );
+ virtual void Stop();
+ virtual void Pause();
+ virtual void Continue();
+ virtual bool IsLoopMode() const;
+ virtual bool IsPlaying() const;
+ virtual bool IsPaused() const;
+
+ bool ImplCreate();
+ void ImplDestroy();
+ static void Release();
+};
+
+#endif // _SV_SALSOUND_H
diff --git a/vcl/os2/inc/salsound.hxx b/vcl/os2/inc/salsound.hxx
new file mode 100644
index 000000000000..7ec2aeed1720
--- /dev/null
+++ b/vcl/os2/inc/salsound.hxx
@@ -0,0 +1,84 @@
+/*************************************************************************
+ *
+ * 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_SALSOUND_HXX
+#define _SV_SALSOUND_HXX
+
+#include <tools/gen.hxx>
+#include <sv.h>
+#include <tools/string.hxx>
+#include <salframe.hxx>
+#ifndef _SV_SALSTYPE_HXX
+#include <salstype.hxx>
+#endif
+#include <salsound.hxx>
+
+// ------------
+// - SalSound -
+// ------------
+
+class SalSound
+{
+private:
+
+ static HMODULE mhMCILib;
+ static ULONG mnSoundState;
+ static void* mpMCIFnc;
+ SALSOUNDPROC mpProc;
+ void* mpInst;
+ ULONG mnStartTime;
+ ULONG mnPlayLen;
+ HWND mhSoundWnd;
+ USHORT mnDeviceId;
+ BOOL mbLoop;
+ BOOL mbPaused;
+
+public:
+
+ void ImplSetError( ULONG nMciErr );
+ void ImplNotify( SoundNotification eNotification, ULONG nError );
+
+public:
+
+ SalSound();
+ ~SalSound();
+
+ BOOL Create();
+ static void Release();
+ static BOOL IsValid() { return( SOUND_STATE_VALID == SalSound::mnSoundState ); }
+
+ BOOL Init( SalFrame* pFrame, const String& rSoundName, ULONG& rSoundLen );
+ BOOL Init( SalFrame* pFrame, const BYTE* pSound, ULONG nDataLen, ULONG& rSoundLen );
+ void Play( ULONG nStartTime, ULONG nPlayTime, BOOL bLoop );
+ void Stop();
+ void Pause();
+
+ void SetNotifyProc( void* pInst, SALSOUNDPROC pProc )
+ { mpInst = pInst; mpProc = pProc; }
+};
+
+#endif // _SV_SALSOUND_HXX
diff --git a/vcl/os2/inc/salsys.h b/vcl/os2/inc/salsys.h
new file mode 100644
index 000000000000..fa76ac349cc9
--- /dev/null
+++ b/vcl/os2/inc/salsys.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 _SV_SALSYS_H
+#define _SV_SALSYS_H
+
+#include <vcl/salsys.hxx>
+#include <vcl/sv.h>
+
+class SalFrame;
+
+// -----------------
+// - SalSystemData -
+// -----------------
+
+class SalSystemData
+{
+};
+
+#endif // _SV_SALSYS_H
diff --git a/vcl/os2/inc/saltimer.h b/vcl/os2/inc/saltimer.h
new file mode 100644
index 000000000000..069e97755d05
--- /dev/null
+++ b/vcl/os2/inc/saltimer.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 _SV_SALTIMER_H
+#define _SV_SALTIMER_H
+
+#include <vcl/saltimer.hxx>
+
+class Os2SalTimer : public SalTimer
+{
+public:
+ Os2SalTimer() {}
+ virtual ~Os2SalTimer();
+
+ // overload all pure virtual methods
+ void Start( ULONG nMS );
+ void Stop();
+};
+
+#endif
diff --git a/vcl/os2/inc/salvd.h b/vcl/os2/inc/salvd.h
new file mode 100644
index 000000000000..8f841f941430
--- /dev/null
+++ b/vcl/os2/inc/salvd.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALVD_H
+#define _SV_SALVD_H
+
+#include <vcl/sv.h>
+#include <vcl/salvd.hxx>
+
+class Os2SalGraphics;
+
+// -----------------
+// - SalVirDevData -
+// -----------------
+
+//class SalVirDevData
+class Os2SalVirtualDevice : public SalVirtualDevice
+{
+public:
+ HPS mhPS; // HPS
+ HDC mhDC; // HDC
+ HBITMAP mhBmp; // Memory Bitmap
+ HBITMAP mhDefBmp; // Default Bitmap
+ Os2SalGraphics* mpGraphics; // current VirDev graphics
+ USHORT mnBitCount; // BitCount (0 or 1)
+ BOOL mbGraphics; // is Graphics used
+
+ Os2SalVirtualDevice();
+ virtual ~Os2SalVirtualDevice();
+
+ virtual SalGraphics* GetGraphics();
+ virtual void ReleaseGraphics( SalGraphics* pGraphics );
+ virtual BOOL SetSize( long nNewDX, long nNewDY );
+ virtual void GetSize( long& rWidth, long& rHeight );
+};
+
+// Help-Functions
+HBITMAP ImplCreateVirDevBitmap( HDC hDC, HPS hPS, long nDX, long nDY,
+ USHORT nBitCount );
+
+#endif // _SV_SALVD_H
diff --git a/vcl/os2/inc/svsys.h b/vcl/os2/inc/svsys.h
new file mode 100644
index 000000000000..39544b83d875
--- /dev/null
+++ b/vcl/os2/inc/svsys.h
@@ -0,0 +1,35 @@
+/*************************************************************************
+ *
+ * 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_SVSYS_H
+#define _SV_SVSYS_H
+
+#ifndef _SVPM_H
+#include <svpm.h>
+#endif
+
+#endif // _SV_SVSYS_H
diff --git a/vcl/os2/inc/wingdi.h b/vcl/os2/inc/wingdi.h
new file mode 100644
index 000000000000..d6085abbd262
--- /dev/null
+++ b/vcl/os2/inc/wingdi.h
@@ -0,0 +1,70 @@
+#ifndef _WINGDI_
+#define _WINGDI_
+
+typedef struct tagPOINT
+{
+ LONG x;
+ LONG y;
+} POINT, *PPOINT, *LPPOINT;
+
+
+typedef unsigned long DWORD;
+typedef unsigned short WORD;
+typedef struct
+{
+ WORD fract;
+ SHORT value;
+} W32FIXED;
+
+typedef struct tagPOINTFX
+{
+ W32FIXED x;
+ W32FIXED y;
+} POINTFX, *LPPOINTFX;
+
+typedef struct tagTTPOLYCURVE
+{
+ WORD wType;
+ WORD cpfx;
+ POINTFX apfx[1];
+} TTPOLYCURVE, *LPTTPOLYCURVE;
+
+typedef struct tagTTPOLYGONHEADER
+{
+ DWORD cb;
+ DWORD dwType;
+ POINTFX pfxStart;
+} TTPOLYGONHEADER, *LPTTPOLYGONHEADER;
+
+typedef struct
+{
+ UINT gmBlackBoxX;
+ UINT gmBlackBoxY;
+ POINT gmptGlyphOrigin;
+ SHORT gmCellIncX;
+ SHORT gmCellIncY;
+} GLYPHMETRICS, *LPGLYPHMETRICS;
+
+#define GGO_METRICS 0
+#define GGO_BITMAP 1
+#define GGO_NATIVE 2
+#define GGO_BEZIER 3
+#define GGO_GRAY2_BITMAP 4
+#define GGO_GRAY4_BITMAP 5
+#define GGO_GRAY8_BITMAP 6
+#define GGO_GLYPH_INDEX 0x80
+
+#define TT_PRIM_LINE 1
+#define TT_PRIM_QSPLINE 2
+#define TT_PRIM_CSPLINE 3
+#define TT_POLYGON_TYPE 24
+
+typedef struct
+{
+ W32FIXED eM11;
+ W32FIXED eM12;
+ W32FIXED eM21;
+ W32FIXED eM22;
+} MAT2, *LPMAT2;
+
+#endif // _WINGDI_
diff --git a/vcl/os2/inc/xwphook.h b/vcl/os2/inc/xwphook.h
new file mode 100644
index 000000000000..07e00bd4c4c1
--- /dev/null
+++ b/vcl/os2/inc/xwphook.h
@@ -0,0 +1,620 @@
+
+/*
+ * xwphook.h:
+ * header for both xwphook.c and xwpdaemon.c. This is also
+ * included from a number of sources for XFLDR.DLL which need
+ * to interface (configure) the daemon.
+ */
+
+/*
+ * Copyright (C) 1999-2002 Ulrich M”ller.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, in version 2 as it comes in the COPYING
+ * file of the XWorkplace main distribution.
+ * This program 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 General Public License for more details.
+ */
+
+#ifndef XWPHOOK_HEADER_INCLUDED
+ #define XWPHOOK_HEADER_INCLUDED
+
+ /* ******************************************************************
+ *
+ * OS2.INI applications and keys
+ *
+ ********************************************************************/
+
+ #define INIAPP_XWPHOOK "XWorkplace:Hook" // added V0.9.0
+ #define INIKEY_HOOK_HOTKEYS "Hotkeys" // added V0.9.0
+ #define INIKEY_HOOK_CONFIG "Config" // added V0.9.0
+ #define INIKEY_HOOK_PAGERCONFIG "PagerConfig" // V0.9.2 (2000-02-25) [umoeller]
+ // changed V0.9.19 (2002-05-07) [umoeller]
+ #define INIKEY_HOOK_PAGERWINPOS "PagerWinPos"
+ // changed V0.9.19 (2002-05-07) [umoeller]
+ #define INIKEY_HOOK_FUNCTIONKEYS "FuncKeys" // added V0.9.3 (2000-04-19) [umoeller]
+ #define INIKEY_HOOK_MOUSEMAPPINGS "MouseMappings" // added V0.9.19 (2002-04-20) [lafaix]
+
+ /* ******************************************************************
+ *
+ * Structures
+ *
+ ********************************************************************/
+
+ // do not change the following, or this will break
+ // binary compatibility of the XPager OS2.INI data
+ #define MAX_STICKIES 64
+ #define STICKYLEN 50
+
+#ifndef __NOPAGER__
+
+ // flags for PAGERCONFIG.aulStickyFlags
+ #define SF_CONTAINS 0x00000000L // default
+ #define SF_BEGINSWITH 0x00000001L
+ #define SF_ENDSWITH 0x00000002L
+ #define SF_EQUALS 0x00000004L
+ #define SF_MATCHES 0x00000008L // V0.9.19 (2002-04-17) [umoeller]
+ #define SF_OPERATOR_MASK 0x0000FFFFL
+
+ #define SF_INCLUDE 0x00000000L // default
+ #define SF_EXCLUDE 0x00010000L
+ #define SF_CRITERIA_MASK 0x00010000L
+
+ #define SF_TITLE 0x00000000L // default
+ #define SF_ATTRIBUTE_MASK 0xFFFE0000L
+
+ #pragma pack(1)
+
+ /*
+ *@@ PAGERCONFIG:
+ * XPager configuration data.
+ * This is stored within the HOOKDATA structure
+ * (statically in the hook DLL) so that both
+ * the daemon and the hook have access to this.
+ *
+ *@@added V0.9.2 (2000-02-25) [umoeller]
+ */
+
+ typedef struct _PAGERCONFIG
+ {
+ BYTE cDesktopsX,
+ cDesktopsY,
+ // no. of virtual Desktops (x and y)
+ bStartX,
+ bStartY;
+ // initial desktop at startup
+
+ ULONG flPager;
+ // flags for "XPager" settings page 1
+ #define PGRFL_WRAPAROUND 0x0001
+ #define PGRFL_HOTKEYS 0x0002
+ #define PGRFL_NOFOLLOWFOCUS 0x0004
+
+ #define PGRMASK_PAGE1 (PGRFL_WRAPAROUND | PGRFL_HOTKEYS)
+ #define PGRFL_PAGE1_DEFAULTS 0
+
+ // flags for "XPager" settings page 2
+ #define PGRFL_PRESERVEPROPS 0x0010
+ // preserve proportions of XPager win when resizing?
+ #define PGRFL_STAYONTOP 0x0020
+ // stay on top?
+ #define PGRFL_FLASHTOTOP 0x0040
+ #define PGRFL_MINIWINDOWS 0x0080
+ // show mini windows in XPager?
+ #define PGRFL_MINIWIN_TITLES 0x0100
+ // show mini window titles?
+ #define PGRFL_MINIWIN_MOUSE 0x0200
+ // allow activate/lower by mouse clicks?
+ #define PGRFL_INCLUDESECONDARY 0x0400
+ #define PGRFL_INCLUDESTICKY 0x0800
+ #define PGRFL_MINIWIN_ICONS 0x1000
+ // show mini window icons?
+ // V0.9.19 (2002-06-13) [umoeller]
+
+ #define PGRMASK_PAGE2 ( PGRFL_PRESERVEPROPS \
+ | PGRFL_STAYONTOP \
+ | PGRFL_FLASHTOTOP \
+ | PGRFL_MINIWINDOWS \
+ | PGRFL_MINIWIN_TITLES \
+ | PGRFL_MINIWIN_MOUSE \
+ | PGRFL_INCLUDESECONDARY \
+ | PGRFL_INCLUDESTICKY \
+ | PGRFL_MINIWIN_ICONS )
+ #define PGRFL_PAGE2_DEFAULTS ( PGRFL_PRESERVEPROPS \
+ | PGRFL_MINIWINDOWS \
+ | PGRFL_MINIWIN_TITLES \
+ | PGRFL_MINIWIN_MOUSE)
+
+ // flags for "XPager" settings page 3
+ #define PGRFL_ADDSTICKYTOGGLE 0x2000
+ // add "sticky" option to system menu?
+ // V1.0.0 (2002-09-14) [lafaix]
+
+ #define PGRMASK_PAGE3 ( PGRFL_ADDSTICKYTOGGLE )
+ #define PGRFL_PAGE3_DEFAULTS 0
+ #define PGRFL_WINDOWS_KEYS 0x00010000
+ // V1.0.3 (2004-10-14) [bird]: Use windows keys for left / right
+
+ ULONG ulFlashDelay;
+ // "flash" delay in milliseconds, if PGRFL_FLASHTOTOP
+ ULONG flKeyShift; // KC_* values
+
+ // paint settings
+ ULONG flPaintMode; // as in BKGNDINFO (gpih.h)
+ LONG lcolDesktop1, // as in BKGNDINFO (gpih.h)
+ lcolDesktop2; // as in BKGNDINFO (gpih.h)
+
+ LONG lcolActiveDesktop; // color of hatching for active desktop
+
+ LONG lcolGrid; // grid color (separators between desktops)
+
+ LONG lcolInactiveWindow,
+ lcolActiveWindow,
+ lcolWindowFrame,
+ lcolInactiveText,
+ lcolActiveText;
+
+ // sticky windows
+ ULONG cStickies;
+ ULONG aulStickyFlags[MAX_STICKIES]; // SF_* flags per sticky
+ CHAR aszStickies[MAX_STICKIES][STICKYLEN];
+
+ } PAGERCONFIG, *PPAGERCONFIG;
+
+ #pragma pack()
+
+#endif
+
+ // flags for HOOKCONFIG.usScrollMode
+ #define SM_LINEWISE 0
+ #define SM_AMPLIFIED 1
+
+ // flags for HOOKCONFIG.ulAutoHideFlags
+ #define AHF_IGNOREMENUS 0x00000001L
+ #define AHF_IGNOREBUTTONS 0x00000002L
+
+ // flags for HOOKCONFIG.ulAutoMoveFlags
+ #define AMF_ALWAYSMOVE 0x00000001L
+ #define AMF_IGNORENOBUTTON 0x00000002L
+ #define AMF_ANIMATE 0x00000004L
+
+ /*
+ *@@ HOOKCONFIG:
+ * configuration data for the hook and the daemon.
+ *
+ * This is stored within the HOOKDATA structure
+ * (statically in the hook DLL) so that both
+ * the daemon and the hook have access to this.
+ *
+ * A mirror of this structure is put into OS2.INI
+ * which gets loaded by the XWorkplace settings
+ * objects in XFLDR.DLL to configure the hook.
+ * This gets (re)loaded by the daemon when XFLDR.DLL
+ * posts XDM_HOOKCONFIG to fnwpDaemonObject.
+ *
+ * So this is seen by the hook and the daemon;
+ * XFLDR.DLL only writes this back to OS2.INI and
+ * notifies the daemon to reload this.
+ *
+ * For every item, the safe default value is null
+ * so the structure can be zeroed to disable
+ * everything.
+ *
+ * If settings are added to this structure, they
+ * must be added to the bottom in order not to
+ * break binary compatibility between XWP versions.
+ *
+ * Note that the object hotkey _definitions_ are
+ * not part of this structure. Those are set using
+ * XDM_HOTKEYSCHANGED instead. However, object
+ * hotkeys are globally enabled in here (fGlobalHotkeys).
+ */
+#pragma pack(4)
+ typedef struct _HOOKCONFIG
+ {
+ // Sliding focus:
+
+ PM_BOOL __fSlidingFocus;
+ // enabled?
+ ULONG __ulSlidingFocusDelay;
+ // delay in ms; 0 = off
+
+ PM_BOOL __fSlidingBring2Top;
+ // bring windows to top or preserve Z-order
+ PM_BOOL __fSlidingIgnoreDesktop;
+ // ignore Desktop windows
+ PM_BOOL __fSlidingIgnoreSeamless;
+ // TRUE: ignore seamless Win-OS/2 windows
+ // FALSE: always bring them to top
+
+ // Screen corner objects:
+ HOBJECT ahobjDummy[4]; // was four screen corner objects;
+ // we extended the array to 8 items
+ // so the array had to be moved to the
+ // bottom in order not to break binary
+ // compatibility
+
+ BYTE bMonitorDrives[30]; // array of 1-byte BOOLs; if any of these
+ // is "1", the corresponding drive letter
+ // will be monitored for media change
+ // (index 1 = A, index 2 = B, index 3 = C, ...).
+ // Index 0 is unused to match logical drive numbers.
+
+ // More mouse mappings: V0.9.1 (99-12-03)
+
+ PM_BOOL fChordWinList; // deprecated V0.9.19 (2002-04-20) [lafaix]
+ // show window list on mb1+2 chord
+ PM_BOOL fSysMenuMB2TitleBar; // deprecated V0.9.19 (2002-04-20) [lafaix]
+ // show system menu on mb2 title-bar click
+
+ // Mouse-button-3 scrolling: V0.9.1 (99-12-03)
+
+ PM_BOOL fMB3Scroll; // deprecated V0.9.19 (2002-04-20) [lafaix]
+ // scroll window contents on MB3Drag
+ PM_BOOL fMB3ScrollReverse; // deprecated V0.9.19 (2002-04-20) [lafaix]
+ // reverse scrolling
+ USHORT usScrollMode; // deprecated V0.9.19 (2002-04-20) [lafaix]
+ // one of the following:
+ // -- SM_LINEWISE (0): scroll fixed, line-wise
+ // -- SM_AMPLIFIED (1): scroll amplified, relative to window size
+ USHORT usMB3ScrollMin;
+ // minimum pixels that mouse must be moved;
+ // 0 means 1, 1 means 2, ...
+ SHORT sAmplification;
+ // amplification (-9 thru +10)
+ // the amplification in percent is calculated like this:
+ // percent = 100 + (sAmplification * 10)
+ // so we get:
+ // 0 --> 100%
+ // 2 --> 120%
+ // 10 --> 200%
+ // -2 --> 80%
+ // -9 --> 10%
+
+ // Auto-hide mouse pointer: V0.9.1 (99-12-03)
+ PM_BOOL __fAutoHideMouse;
+ ULONG __ulAutoHideDelay;
+ // delay in seconds; 0 means 1 second, 2 means 3, ...
+
+ // Global object hotkeys enabled:
+ // this can be disabled even if any hotkeys are defined
+ // because the hotkeys themselves are stored separately
+ // in shared memory
+ PM_BOOL __fGlobalHotkeys;
+
+ // XPager configuration
+ PM_BOOL fRemoved1, // _fXPagerStayOnTop,
+ fRemoved2; //__fSlidingIgnoreXPager;
+ // removed V0.9.19 (2002-05-07) [umoeller]
+
+ // Sliding menus
+ PM_BOOL fSlidingMenus;
+ // enabled?
+ ULONG ulSubmenuDelay;
+ // delay in ms; 0 = off
+ PM_BOOL fMenuImmediateHilite;
+
+ // Mouse-button-3 single-clicks to MB1 double-clicks
+ // V0.9.4 (2000-06-12) [umoeller]
+ PM_BOOL fMB3Click2MB1DblClk; // deprecated V0.9.19 (2002-04-20) [lafaix]
+
+ // Screen corner objects:
+ // moved the array down here (there's a dummy above)
+ // V0.9.4 (2000-06-12) [umoeller]
+ HOBJECT ahobjHotCornerObjects[8];
+ // Indices:
+ // 0 = lower left corner,
+ // 1 = top left corner,
+ // 2 = lower right corner,
+ // 3 = top right corner;
+ // borders added V0.9.4 (2000-06-12) [umoeller]:
+ // 4 = top border,
+ // 5 = left border,
+ // 6 = right border,
+ // 7 = bottom border.
+ // V0.9.18 (2002-02-12) [pr]
+ #define SCREENCORNER_MIN 0
+ #define SCREENCORNER_BOTTOMLEFT 0
+ #define SCREENCORNER_TOPLEFT 1
+ #define SCREENCORNER_BOTTOMRIGHT 2
+ #define SCREENCORNER_TOPRIGHT 3
+ #define SCREENCORNER_TOP 4
+ #define SCREENCORNER_LEFT 5
+ #define SCREENCORNER_RIGHT 6
+ #define SCREENCORNER_BOTTOM 7
+ #define SCREENCORNER_MAX 7
+ // If any item is NULLHANDLE, it means the
+ // corner is inactive (no function defined).
+ // If the hiword of the item is 0xFFFF, this
+ // means a special function has been defined:
+ // (#define's added V0.9.19 (2002-04-17) [umoeller]):
+ #define SPECIALOBJ_FIRST 0xFFFF0000
+ #define SPECIALOBJ_SHOWWINDOWLIST 0xFFFF0000
+ #define SPECIALOBJ_DESKTOPCONTEXTMENU 0xFFFF0001
+ #define SPECIALOBJ_PAGER_SHOW 0xFFFF0002
+ // the following added (2001-01-26) [lafaix]
+ #define SPECIALOBJ_PAGER_UP 0xFFFF0003
+ #define SPECIALOBJ_PAGER_RIGHT 0xFFFF0004
+ #define SPECIALOBJ_PAGER_DOWN 0xFFFF0005
+ #define SPECIALOBJ_PAGER_LEFT 0xFFFF0006
+ // the following added V0.9.18 [pr]
+ #define SPECIALOBJ_SCREENWRAP 0xFFFF0007
+ // Otherwise (> 0 and < 0xFFFF0000), we have
+ // a "real" object handle, and a regular WPS
+ // object is to be opened.
+
+ // special treatment for conditional-cascade submenus when
+ // using sliding menus (V0.9.6 (2000-10-27) [umoeller])
+ PM_BOOL fConditionalCascadeSensitive;
+
+ // more XPager configuration V0.9.7 (2000-12-08) [umoeller]
+ PM_BOOL fRemoved3; // __fSlidingIgnoreXCenter;
+ // removed V0.9.19 (2002-05-07) [umoeller]
+
+ // screen corner objects sensitivity; in percent of the
+ // adjacents borders. 0 = off, 50 = borders objects disabled
+ // V0.9.9 (2001-03-15) [lafaix]
+ ULONG ulCornerSensitivity;
+
+ // Mouse-button-3 autoscroll and push to bottom features
+ PM_BOOL fMB3AutoScroll; // deprecated V0.9.19 (2002-04-20) [lafaix]
+ PM_BOOL fMB3Push2Bottom; // deprecated V0.9.19 (2002-04-20) [lafaix]
+
+ // Auto hide and automatic pointer movement options
+ // V0.9.14 (2001-08-02) [lafaix]
+ ULONG __ulAutoHideFlags;
+ PM_BOOL __fAutoMoveMouse;
+ ULONG __ulAutoMoveFlags;
+ ULONG __ulAutoMoveDelay; // V0.9.14 (2001-08-21) [umoeller]
+ ULONG __ulMouseMappingsCount; // V0.9.19 (2002-04-20) [lafaix]
+ } HOOKCONFIG, *PHOOKCONFIG;
+#pragma pack()
+
+ /*
+ *@@ GLOBALHOTKEY:
+ * single XWorkplace object hotkey definition.
+ * Arrays of this are allocated in shared memory and
+ * used by xwphook.c, xwpdaemn.c, and also XFldObject
+ * for hotkey manipulation and detection.
+ */
+
+ typedef struct _GLOBALHOTKEY
+ {
+ USHORT usFlags;
+ // Keyboard control codes:
+ // SHORT1FROMMP(mp1) of WM_CHAR, filtered.
+ // Only the following flags will be set:
+ // -- KC_CTRL
+ // -- KC_ALT
+ // -- KC_SHIFT
+ // -- KC_VIRTUALKEY
+ // -- KC_INVALIDCOMP: special flag used if the
+ // scan code represents one of the user-defined
+ // function keys in the XWPKeyboard object.
+ // KC_CTRL, KC_ALT, KC_SHIFT work always,
+ // no matter if we're in a PM or VIO session.
+ // However, for some reason, KC_VIRTUALKEY is
+ // never set in VIO sessions. We still store it
+ // in this structure though to be able to display
+ // the hotkey in the configuration pages.
+ // The hook will filter that out since the scan
+ // code is good enough to identify the key.
+ UCHAR ucScanCode;
+ // Hardware scan code:
+ // CHAR4FROMMP(mp1) of WM_CHAR.
+ // As opposed to what we do with folder hotkeys,
+ // this must be stored also, because we must use
+ // the scan code for WM_CHAR processing in the hook
+ // to identify hotkeys. We cannot use usKeyCode
+ // because that's different in VIO sessions, while
+ // this one is always the same.
+ // Even if any of Ctrl, Alt, Shift are pressed, this
+ // has the scan code of the additional key which was
+ // pressed.
+ USHORT usKeyCode;
+ // key code:
+ // if KC_VIRTUALKEY is set in usFlags, this has usvk,
+ // otherwise usch from WM_CHAR.
+ // This is only used to be able to display the hotkey
+ // in the hotkey configuration dialogs; we do _not_ use
+ // this to check WM_CHAR messages in the hook, because
+ // this is different between PM and VIO sessions.
+ ULONG ulHandle;
+ // handle to post to thread-1 object window (kernel.c);
+ // this is normally the HOBJECT of the object to be
+ // opened.
+ } GLOBALHOTKEY, *PGLOBALHOTKEY;
+
+ /*
+ *@@ MOUSEMAPPING:
+ * single XWorkplace mouse mapping definition.
+ * Arrays of this are allocated in shared memory and
+ * used by xwphook.c, xwpdaemn.c, and also XWPMouse
+ * for mouse mappings manipulation and detection.
+ *
+ *@@added V0.9.19 (2002-04-20) [lafaix]
+ */
+
+ typedef struct _MOUSEMAPPING
+ {
+ USHORT usEvent;
+ // One of the MME_* values (or MME_XBUTTON_FIRST+n
+ // to denote extra button n, 0 <= n < 32).
+ // standard mouse events
+ #define MME_BUTTON1CLICK 0x0001
+ #define MME_BUTTON2CLICK 0x0002
+ #define MME_BUTTON3CLICK 0x0003
+ #define MME_BUTTON1DRAG 0x0004
+ #define MME_BUTTON2DRAG 0x0005
+ #define MME_BUTTON3DRAG 0x0006
+ #define MME_CHORD 0x0007
+ // wheel/stick events
+ #define MME_UP 0x1001
+ #define MME_DOWN 0x1002
+ #define MME_LEFT 0x1003
+ #define MME_RIGHT 0x1004
+ // the 2X and 3X variants are handy when mapping an action
+ // to a wheel/stick movement. They map at least 2 (or 3)
+ // consecutive events, and hence disambiguate an unexpected
+ // wheel/stick event.
+ #define MME_UP2X 0x2001
+ #define MME_DOWN2X 0x2002
+ #define MME_LEFT2X 0x2003
+ #define MME_RIGHT2X 0x2004
+ #define MME_UP3X 0x3001
+ #define MME_DOWN3X 0x3002
+ #define MME_LEFT3X 0x3003
+ #define MME_RIGHT3X 0x3004
+ // extra buttons
+ #define MME_XBUTTON_FIRST 0x4000
+ // type helpers
+ #define MME_TYPE_MASK 0xF000
+ #define MME_TYPE_STANDARD 0x0000
+ #define MME_TYPE_WHEEL 0x1000
+ #define MME_TYPE_WHEEL2X 0x2000
+ #define MME_TYPE_WHEEL3X 0x3000
+ #define MME_TYPE_XBUTTON 0x4000
+ #define MME_TYPE_DISABLED 0x8000
+
+ USHORT usModifiers;
+ // A possibly empty combination of KC_SHIFT, KC_CTRL,
+ // and KC_ALT.
+ CHAR achLocation[32];
+ // The class name upon which this mapping applies.
+ // An empty location (i.e., achLocation[0] = 0) means
+ // a global mapping.
+ CHAR achPluginName[8];
+ // The plugin library providing the action defined for
+ // this mapping. An empty location (i.e.,
+ // achPluginName[0] = 0) means a buildin action.
+ USHORT usAction;
+ // The action (relative to the plugin) defined for
+ // this event.
+ BYTE abSetup[16];
+ // A private area possibly refining the action.
+ } MOUSEMAPPING, *PMOUSEMAPPING;
+
+ /*
+ *@@ FUNCTIONKEY:
+ * XWorkplace function key description.
+ * An array of these is returned by
+ * hifQueryFunctionKeys().
+ *
+ *@@added V0.9.3 (2000-04-19) [umoeller]
+ */
+
+ typedef struct _FUNCTIONKEY
+ {
+ UCHAR ucScanCode; // hardware scan code;
+ // CHAR4FROMMP(mp1) of WM_CHAR
+ CHAR szDescription[30]; // key description (e.g. "Win left")
+ PM_BOOL fModifier; // TRUE if the scan code represents
+ // a modifier key which can be pressed
+ // together with another key, similar
+ // to Ctrl or Alt or Del; this will
+ // allow us to do things like "WinLeft + C"
+ } FUNCTIONKEY, *PFUNCTIONKEY;
+
+ /* ******************************************************************
+ *
+ * Messages
+ *
+ ********************************************************************/
+
+ #define XDM_HOOKINSTALL (WM_USER + 400)
+
+ #define XDM_DESKTOPREADY (WM_USER + 401)
+
+ #define XDM_HOOKCONFIG (WM_USER + 402)
+
+#ifndef __NOPAGER__
+ #define XDM_STARTSTOPPAGER (WM_USER + 403)
+
+ #define XDM_PAGERCONFIG (WM_USER + 404)
+ // flags for XDM_PAGERCONFIG:
+ #define PGRCFG_REPAINT 0x0001 // invalidates mini windows
+ #define PGRCFG_REFORMAT 0x0004 // causes PGRM_POSITIONFRAME,
+ // repaints background too
+ #define PGRCFG_STICKIES 0x0008 // sticky windows have changed
+#endif
+
+ #define XDM_HOTKEYPRESSED (WM_USER + 405)
+
+ #define XDM_HOTKEYSCHANGED (WM_USER + 406)
+
+ #define XDM_FUNCTIONKEYSCHANGED (WM_USER + 407)
+
+#ifndef __NOSLIDINGFOCUS__
+ #define XDM_SLIDINGFOCUS (WM_USER + 408)
+#endif
+
+ #define XDM_SLIDINGMENU (WM_USER + 409)
+
+ #define XDM_HOTCORNER (WM_USER + 410)
+
+ #define XDM_WMCHORDWINLIST (WM_USER + 411)
+
+ // added V0.9.9 (2001-03-18) [lafaix]
+ #define XDM_BEGINSCROLL (WM_USER + 413)
+ #define XDM_SETPOINTER (WM_USER + 414)
+ #define XDM_ENDSCROLL (WM_USER + 415)
+
+ // added V0.9.12 (2001-05-12) [umoeller]
+ #define XDM_RECOVERWINDOWS (WM_USER + 416)
+
+ #define XDM_ADDDISKWATCH (WM_USER + 417)
+
+ /*
+ *@@ ADDDISKWATCH:
+ * struct used with XDM_ADDDISKWATCH.
+ *
+ *@@added V0.9.14 (2001-08-01) [umoeller]
+ */
+
+ typedef struct _ADDDISKWATCH
+ {
+ ULONG ulLogicalDrive; // disk to be monitored
+ HWND hwndNotify; // window to be notified on change
+ ULONG ulMessage; // message to be posted to window
+ } ADDDISKWATCH, *PADDDISKWATCH;
+
+ #define XDM_REMOVEDISKWATCH (WM_USER + 418)
+
+ #define XDM_QUERYDISKS (WM_USER + 419)
+
+ #define XDM_ADDCLICKWATCH (WM_USER + 420)
+
+ #define XDM_MOUSECLICKED (WM_USER + 421)
+
+#ifndef __NOMOVEMENT2FEATURES__
+ #define XDM_MOVEPTRTOBUTTON (WM_USER + 422)
+#endif
+
+ #define XDM_DISABLEHOTKEYSTEMP (WM_USER + 423)
+
+ #define XDM_STARTAPP (WM_USER + 424)
+
+ #define XDM_ADDWINLISTWATCH (WM_USER + 425)
+
+ #define XDM_WINDOWCHANGE (WM_USER + 426)
+
+ #define XDM_ICONCHANGE (WM_USER + 427)
+
+ #define XDM_QUERYWINLIST (WM_USER + 428)
+
+ #define XDM_REMOVEWINLISTWATCH (WM_USER + 429) // V0.9.19 (2002-06-14) [lafaix]
+
+ #define XDM_REMOVECLICKWATCH (WM_USER + 430) // V0.9.19 (2002-06-14) [lafaix]
+
+#ifndef __NOPAGER__
+ #define XDM_TOGGLETRANSIENTSTICKY (WM_USER + 431) // V1.0.0 (2002-07-26) [lafaix]
+ #define XDM_ISTRANSIENTSTICKY (WM_USER + 432)
+#endif
+
+ #define XDM_NLSCHANGED (WM_USER + 433) // V1.0.0 (2002-09-15) [lafaix]
+#endif
+
+
+
diff --git a/vcl/os2/source/app/makefile.mk b/vcl/os2/source/app/makefile.mk
new file mode 100644
index 000000000000..80aeb7f568fb
--- /dev/null
+++ b/vcl/os2/source/app/makefile.mk
@@ -0,0 +1,59 @@
+#*************************************************************************
+#
+# 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=SV
+TARGET=salapp
+
+# --- Settings -----------------------------------------------------
+
+#.INCLUDE : svpre.mk
+.INCLUDE : settings.mk
+#.INCLUDE : sv.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+
+# --- Files --------------------------------------------------------
+
+YD00_CXXFILES=\
+ salshl.cxx \
+ salinst.cxx \
+ sallang.cxx \
+ saltimer.cxx \
+ salsys.cxx
+
+SLOFILES= $(SLO)$/salshl.obj \
+ $(SLO)$/printf.obj \
+ $(SLO)$/salinfo.obj \
+ $(SLO)$/salinst.obj \
+ $(SLO)$/sallang.obj \
+ $(SLO)$/saltimer.obj
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
diff --git a/vcl/os2/source/app/printf.c b/vcl/os2/source/app/printf.c
new file mode 100644
index 000000000000..7cfcf4efc559
--- /dev/null
+++ b/vcl/os2/source/app/printf.c
@@ -0,0 +1,284 @@
+/* ----------------------------------------------------------------- */
+/* PRINTF: diverts PRINTF calls to an OS/2 Named Queue */
+/* Copyright (c) IBM Corporation, 1991, 1992 */
+/* ----------------------------------------------------------------- */
+/* This version for OS/2 2.x, 32-bit programs. Mike Cowlishaw */
+/* */
+/* This routine, when linked into an .EXE instead of the usual C */
+/* runtime, sends the edited result string to a named queue (if */
+/* it exists). If the queue does not exist, then all printf data */
+/* are discarded (ignored). */
+/* */
+/* The result string is accumulated until a line feed (LF) character */
+/* is received; the whole line is then sent to the queue. Lines are */
+/* automatically broken at a set (tailorable) length, if necessary. */
+/* */
+/* This routine may be tailored by altering the #defines at the */
+/* top: */
+/* */
+/* PRINTFID - An ID string that is prefixed to each line of */
+/* data before being sent to the queue. This */
+/* can be any string, or the null string. */
+/* PRINTFMAXLEN - Maximum length of string that can be formatted */
+/* in a single call. */
+/* Results are unpredictable if this length is */
+/* exceeded. Default is 250. */
+/* PRINTFLINELEN - Maximum length of a line that will be sent. */
+/* This excludes the prefix and its blank. If the */
+/* calls to printf cause a line to be generated */
+/* that is longer than this, the line will be */
+/* broken at this point. */
+/* PRINTFTHREADS - Maximum number of threads expected. This may */
+/* need to be increased if the process limitation */
+/* is removed, or you can save a little storage */
+/* by decreasing it. PRINTFs from threads larger */
+/* than this number are ignored. */
+/* PRINTFQNAME - The name of the public queue that the result */
+/* is to be sent to. Normally '\QUEUES\PRINTF32'. */
+/* Note that the \QUEUES\ part is required. */
+/* */
+/* Returns: */
+/* n: Count of data characters, if successfully received */
+/* 0: If no queue existed (i.e., no server) */
+/* <0: An error occurred (e.g., out of memory) */
+/* */
+/* Restrictions: */
+/* 1. Total length of data (length of PRINTFID, + PRINTFMAXLEN) */
+/* must be less than 32K-1. */
+/* 2. This has only been tested under IBM C Set/2 compiler. It */
+/* may need modification for other compilers. */
+/* 3. This version uses a static array to point to the per-thread */
+/* data. The code could be made read-only by hanging this */
+/* array (and the other static information) off a system-owned */
+/* anchor of some kind. */
+/* 4. To use PRINTF within other than the main thread in a */
+/* program, that thread must be started with _beginthread */
+/* (not DosCreateThread). This restriction is a consequence of */
+/* the use of C library routines (sprintf) in PRINTF, and may */
+/* not apply to all compilers. */
+/* 5. If the last PRINTF done by a thread does not end in '\n' */
+/* then the final part-line may be lost, or appear later. */
+/* */
+/* Protocol: */
+/* PRINTF writes its data to the named queue using the following */
+/* protocol: */
+/* Address -- Holds the address of the string to be sent. This */
+/* is a 0-terminated string) starting at offset 0. */
+/* Length -- The length of the data, including terminator. */
+/* A negative length indicates a BELL in the data. */
+/* Request -- Timestamp (when queue was written) in C long */
+/* integer format (as returned by time()). */
+/* This may be 0L if not required. */
+/* */
+/* Notes: */
+/* 1. PMPRINTF uses a queue and shared memory messages because: */
+/* (a) It makes collection at the receiving end very easy. */
+/* (b) I wanted to experiment with queues and shared memory. */
+/* This make not be the most cost-effective method. */
+/* 2. Typical IBM C Set/2 compiler invocation: */
+/* icc /c /Gm /O+ /Q /J /Kabgop */
+/* If you get linking errors (duplicate symbols, etc.), try */
+/* recompiling PRINTF.C with the same options as you use for */
+/* your main program. */
+/* 3. PRINTF sends the timestamp across the queue as a GMT long */
+/* integer, the result from a call to the C function time(). */
+/* This will only be correct if the environment variable TZ has */
+/* been set (e.g., TZ=EST5EDT), or you are in the same time */
+/* zone as the default for your compiler. */
+/* For more information, see the tzset() function description */
+/* in your C compiler manual. */
+
+/* ----- Customization variables ----- */
+#define PRINTFID ""
+#define PRINTFMAXLEN 300
+#define PRINTFLINELEN 100
+#define PRINTFTHREADS 54
+#define PRINTFQNAME "\\QUEUES\\PRINTF32"
+
+/* ----- Includes and externals ----- */
+#include <stdlib.h> /* standard C functions */
+#include <stddef.h> /* .. */
+#include <string.h> /* .. */
+#include <time.h> /* .. */
+#include <stdarg.h> /* .. */
+#include <stdio.h> /* (needed to pick up real name) */
+#define INCL_DOS /* Operating system definitions */
+#include <os2.h> /* For OS/2 functions */
+
+#define max(a,b) (a>b ? a : b)
+
+/* ----- Local defines ----- */
+#define PRINTFIDSIZE sizeof(PRINTFID)
+#define PRINTFMAXBUF PRINTFIDSIZE+PRINTFLINELEN
+
+/* ----- Per-thread output buffer and current indices into line ---- */
+struct perthread {
+ LONG lineindex; /* where next char */
+ LONG tidemark; /* rightmost char */
+ int bell; /* TRUE if line has bell */
+ UCHAR line[PRINTFMAXBUF]; /* accumulator */
+ };
+
+/* ----- Local static variables ----- */
+static ULONG ourpid=0; /* our process ID */
+static ULONG servepid=0; /* process IDs of the server */
+static HQUEUE qhandle=0; /* handle for the queue */
+static struct perthread *tps[PRINTFTHREADS+1]; /* -> per-thread data */
+
+/* ----- Local subroutine ----- */
+static int printf_(struct perthread *);
+
+/* ----------------------------------------------------------------- */
+/* The "printf" function. Note this has a variable number of */
+/* arguments. */
+/* ----------------------------------------------------------------- */
+int debug_printf(const char *f, ...)
+ {
+ TIB *ptib; /* process/thread id structures */
+ PIB *ppib; /* .. */
+ TID ourtid; /* thread ID */
+ struct perthread *tp; /* pointer to per-thread data */
+ int rc; /* returncode */
+ ULONG urc; /* returncode */
+
+ urc=DosOpenQueue(&servepid, &qhandle, PRINTFQNAME); /* Open the Q */
+ /* Non-0 RC means Q does not exist or cannot be opened */
+ if (urc==343) return 0; /* queue does not exist, so quit */
+ if (urc!=0) return -1; /* report any other error */
+
+ /* First determine our thread ID (and hence get access to the */
+ /* correct per-thread data. If the per-thread data has not been */
+ /* allocated, then allocate it now. It is never freed, once */
+ /* allocated, as PRINTF is not notified of end-of-thread. */
+ DosGetInfoBlocks(&ptib,&ppib); /* get process/thread info */
+ ourtid=ptib->tib_ptib2->tib2_ultid; /* .. and copy TID */
+ if (ourtid>PRINTFTHREADS) /* too many threads .. */
+ return 0; /* .. so quit, quietly */
+ tp=tps[ourtid]; /* copy to local pointer */
+ if (tp==NULL) { /* uninitialized (NULL=0) */
+ /* allocate a per-thread structure */
+ tp=(struct perthread *)malloc(sizeof(struct perthread));
+ if (tp==NULL) return -1; /* out of memory -- return error */
+ tps[ourtid]=tp; /* save for future calls */
+ strcpy(tp->line,PRINTFID); /* initialize: line.. */
+ tp->lineindex=PRINTFIDSIZE-1; /* ..where next char */
+ tp->tidemark =PRINTFIDSIZE-2; /* ..rightmost char */
+ tp->bell=FALSE; /* ..if line has bell */
+ if (ourpid==0) ourpid=ppib->pib_ulpid; /* save PID for all to use */
+ }
+
+ { /* Block for declarations -- only needed if queue exists, etc. */
+ LONG count; /* count of characters formatted */
+ UCHAR buffer[PRINTFMAXLEN+1]; /* formatting area */
+ LONG i, newind; /* work */
+ UCHAR ch; /* .. */
+ va_list argptr; /* -> variable argument list */
+
+ va_start(argptr, f); /* get pointer to argument list */
+ count=vsprintf(buffer, f, argptr);
+ va_end(argptr); /* done with variable arguments */
+
+ if (count<0) return count-1000;/* bad start */
+
+ if (count>PRINTFMAXLEN) {
+ /* Disaster -- we are probably "dead", but just in case we */
+ /* are not, carry on with truncated data. */
+ count=PRINTFMAXLEN;
+ }
+ buffer[count]='\0'; /* ensure terminated */
+ /* OK, ready to go with the data now in BUFFER */
+ /* We copy from the formatted string to the output (line) buffer, */
+ /* taking note of certain control characters and sending a line */
+ /* the queue whenever we see a LF control, or when the line */
+ /* fills (causing a forced break). */
+ for (i=0; ; i++) {
+ ch=buffer[i]; if (!ch) break;
+ switch(ch) {
+ case '\r': /* carriage return */
+ tp->lineindex=PRINTFIDSIZE-1; /* back to start of line */
+ break;
+ case '\n': /* new line */
+ case '\f': /* form feed */
+ rc=printf_(tp); /* print a line */
+ if (rc!=0) return rc; /* error */
+ break;
+ case '\t': /* tab */
+ newind=tp->lineindex-PRINTFIDSIZE+1; /* offset into data */
+ newind=tp->lineindex+5-newind%5; /* new index requested */
+ if (newind>=PRINTFMAXBUF) newind=PRINTFMAXBUF; /* clamp */
+ for (; tp->lineindex<newind; tp->lineindex++) {
+ if (tp->lineindex>tp->tidemark) { /* beyond current end */
+ tp->line[tp->lineindex]=' '; /* add space */
+ tp->tidemark=tp->lineindex;
+ }
+ }
+ break;
+ case '\v': /* vertical tab */
+ /* ignore it */
+ break;
+ case '\b': /* backspace */
+ tp->lineindex=max(tp->lineindex-1,PRINTFIDSIZE);
+ break;
+ case '\a': /* alert (bell) */
+ tp->bell=TRUE;
+ break;
+ default: /* ordinary character */
+ tp->line[tp->lineindex]=ch;
+ if (tp->lineindex>tp->tidemark) /* is rightmost.. */
+ tp->tidemark=tp->lineindex;
+ tp->lineindex++; /* step for next */
+ } /* switch */
+ if (tp->lineindex>=PRINTFMAXBUF) {
+ rc=printf_(tp); /* print a line */
+ if (rc!=0) return rc; /* error */
+ }
+
+ } /* copy loop */
+ return count; /* all formatted data processed */
+ } /* block */
+ } /* printf */
+
+/* ----- printf_(tp) -- Local subroutine to send a line ------------ */
+/* A line has been completed (or overflowed): write it to the queue. */
+int printf_(struct perthread *tp) /* pointer to per-thread data */
+ {
+ ULONG urc; /* unsigned returncode */
+ PSZ pszTo, pszFrom; /* character pointers */
+ PVOID addr; /* address of output data */
+ long size; /* total size of output data */
+ time_t timenow; /* holds current time */
+
+ tp->line[tp->tidemark+1]='\0'; /* add terminator */
+ size=tp->tidemark+2; /* total length of data */
+
+ /* Get some shared memory that can be given away */
+ urc=DosAllocSharedMem(&addr, NULL, (unsigned)size,
+ OBJ_GIVEABLE|PAG_WRITE|PAG_COMMIT);
+ if (urc!=0) return -2; /* error */
+
+ pszTo=addr; /* copy for clarity */
+ pszFrom=&(tp->line[0]); /* pointer to source */
+ strcpy(pszTo,pszFrom); /* copy the string to shared memory */
+
+ if (ourpid!=servepid) { /* (no giveaway needed if to self) */
+ urc=DosGiveSharedMem(addr, servepid, PAG_READ); /* give access */
+ if (urc!=0) return -3;} /* error */
+
+ /* Write the selector, size, and timestamp to the queue */
+ if (tp->bell) size=-size; /* BELL passed by negation */
+ time(&timenow); /* optional - else use 0 */
+ urc=DosWriteQueue(qhandle, /* handle */
+ (unsigned)timenow, /* 'request' (timestamp) */
+ (unsigned)size, /* 'length' (length/bell) */
+ addr, /* 'address' (address) */
+ 0); /* priority (FIFO if enabled) */
+ if (urc!=0) return -4; /* error */
+ if (ourpid!=servepid) { /* if given away.. */
+ urc=DosFreeMem(addr); /* .. *we* are done with it */
+ if (urc!=0) return -5;} /* error */
+ /* Reset the line buffer and indices */
+ tp->lineindex=PRINTFIDSIZE-1; /* where next char */
+ tp->tidemark =PRINTFIDSIZE-2; /* rightmost char */
+ tp->bell =FALSE; /* true if line has bell */
+ return 0; /* success! */
+ } /* printf_ */
diff --git a/vcl/os2/source/app/salinfo.cxx b/vcl/os2/source/app/salinfo.cxx
new file mode 100644
index 000000000000..e48aacd4c521
--- /dev/null
+++ b/vcl/os2/source/app/salinfo.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.
+ *
+ ************************************************************************/
+
+#define INCL_PM
+#define INCL_DOS
+#define INCL_GPI
+#include <svpm.h>
+
+#include <tools/string.hxx>
+#include <salsys.h>
+#include <salframe.h>
+#include <salinst.h>
+#include "saldata.hxx"
+#include <tools/debug.hxx>
+#include <vcl/svdata.hxx>
+#include <rtl/ustrbuf.hxx>
+#include "vcl/window.hxx"
+
+#ifndef _SV_SALGTYPE_HXX
+//#include <salgtype.hxx>
+#endif
+
+#define CHAR_POINTER(THE_OUSTRING) ::rtl::OUStringToOString (THE_OUSTRING, RTL_TEXTENCODING_UTF8).pData->buffer
+
+class Os2SalSystem : public SalSystem
+{
+public:
+ Os2SalSystem() {}
+ virtual ~Os2SalSystem();
+
+ virtual unsigned int GetDisplayScreenCount();
+ virtual Rectangle GetDisplayScreenPosSizePixel( unsigned int nScreen );
+ //virtual bool GetSalSystemDisplayInfo( DisplayInfo& rInfo );
+
+ virtual bool IsMultiDisplay();
+ virtual unsigned int GetDefaultDisplayNumber();
+ virtual Rectangle GetDisplayWorkAreaPosSizePixel( unsigned int nScreen );
+ virtual rtl::OUString GetScreenName( unsigned int nScreen );
+
+ virtual int ShowNativeMessageBox( const String& rTitle,
+ const String& rMessage,
+ int nButtonCombination,
+ int nDefaultButton);
+};
+
+SalSystem* Os2SalInstance::CreateSalSystem()
+{
+ return new Os2SalSystem();
+}
+
+Os2SalSystem::~Os2SalSystem()
+{
+}
+
+// -----------------------------------------------------------------------
+#if 0
+bool Os2SalSystem::GetSalSystemDisplayInfo( DisplayInfo& rInfo )
+{
+ HDC hDC;
+ if( hDC = WinQueryWindowDC(HWND_DESKTOP) )
+ {
+ LONG bitCount;
+ DevQueryCaps(hDC, CAPS_COLOR_BITCOUNT, CAPS_COLOR_BITCOUNT, &bitCount);
+ rInfo.nWidth = WinQuerySysValue( HWND_DESKTOP, SV_CXSCREEN );
+ rInfo.nHeight = WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN );
+ rInfo.nDepth = bitCount;
+ return true;
+ }
+ else
+ return false;
+}
+#endif
+
+unsigned int Os2SalSystem::GetDisplayScreenCount()
+{
+ return 1;
+}
+
+Rectangle Os2SalSystem::GetDisplayScreenPosSizePixel( unsigned int nScreen )
+{
+ Rectangle aRet;
+ aRet = Rectangle( Point(), Point( WinQuerySysValue( HWND_DESKTOP, SV_CXSCREEN ),
+ WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN ) ) );
+ return aRet;
+}
+
+// -----------------------------------------------------------------------
+/* We have to map the button identifier to the identifier used by the Os232
+ Platform SDK to specify the default button for the MessageBox API.
+ The first dimension is the button combination, the second dimension
+ is the button identifier.
+*/
+static int DEFAULT_BTN_MAPPING_TABLE[][8] =
+{
+ // Undefined OK CANCEL ABORT RETRY IGNORE YES NO
+ { MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1 }, //OK
+ { MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON2, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1 }, //OK_CANCEL
+ { MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON2, MB_DEFBUTTON3, MB_DEFBUTTON1, MB_DEFBUTTON1 }, //ABORT_RETRY_IGNO
+ { MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON3, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON2 }, //YES_NO_CANCEL
+ { MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON2 }, //YES_NO
+ { MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON2, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1 } //RETRY_CANCEL
+};
+
+static int COMBI_BTN_MAPPING_TABLE[] =
+{
+ MB_OK, MB_OKCANCEL, MB_ABORTRETRYIGNORE, MB_YESNO, MB_YESNOCANCEL, MB_RETRYCANCEL
+};
+
+int Os2SalSystem::ShowNativeMessageBox(const String& rTitle, const String& rMessage, int nButtonCombination, int nDefaultButton)
+{
+ DBG_ASSERT( nButtonCombination >= SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_OK &&
+ nButtonCombination <= SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_RETRY_CANCEL &&
+ nDefaultButton >= SALSYSTEM_SHOWNATIVEMSGBOX_BTN_OK &&
+ nDefaultButton <= SALSYSTEM_SHOWNATIVEMSGBOX_BTN_NO, "Invalid arguments!" );
+
+ int nFlags = MB_APPLMODAL | MB_WARNING | COMBI_BTN_MAPPING_TABLE[nButtonCombination];
+
+ if (nButtonCombination >= SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_OK &&
+ nButtonCombination <= SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_RETRY_CANCEL &&
+ nDefaultButton >= SALSYSTEM_SHOWNATIVEMSGBOX_BTN_OK &&
+ nDefaultButton <= SALSYSTEM_SHOWNATIVEMSGBOX_BTN_NO)
+ nFlags |= DEFAULT_BTN_MAPPING_TABLE[nButtonCombination][nDefaultButton];
+
+ //#107209 hide the splash screen if active
+ ImplSVData* pSVData = ImplGetSVData();
+ if (pSVData->mpIntroWindow)
+ pSVData->mpIntroWindow->Hide();
+
+ return WinMessageBox(
+ HWND_DESKTOP, HWND_DESKTOP,
+ (PSZ)CHAR_POINTER(rMessage),
+ (PSZ)CHAR_POINTER(rTitle),
+ 0, nFlags);
+}
+
+
+unsigned int Os2SalSystem::GetDefaultDisplayNumber()
+{
+ return 0;
+}
+
+bool Os2SalSystem::IsMultiDisplay()
+{
+ return false;
+}
+
+Rectangle Os2SalSystem::GetDisplayWorkAreaPosSizePixel( unsigned int nScreen )
+{
+ return GetDisplayScreenPosSizePixel( nScreen );
+}
+
+rtl::OUString Os2SalSystem::GetScreenName( unsigned int nScreen )
+{
+ rtl::OUStringBuffer aBuf( 32 );
+ aBuf.appendAscii( "VirtualScreen " );
+ aBuf.append( sal_Int32(nScreen) );
+ return aBuf.makeStringAndClear();
+}
diff --git a/vcl/os2/source/app/salinst.cxx b/vcl/os2/source/app/salinst.cxx
new file mode 100644
index 000000000000..b08a9769ccf4
--- /dev/null
+++ b/vcl/os2/source/app/salinst.cxx
@@ -0,0 +1,863 @@
+/*************************************************************************
+ *
+ * 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 INCL_DOSMISC
+#define INCL_DOSMODULEMGR
+#define INCL_DOSPROCESS
+
+#include <string.h>
+#include <svpm.h>
+#include <process.h>
+
+#define _SV_SALINST_CXX
+
+#ifndef _VOS_MUTEX_HXX
+#include <vos/mutex.hxx>
+#endif
+#include <tools/debug.hxx>
+
+#ifndef _SV_SALIDS_HRC
+#include <salids.hrc>
+#endif
+#include <vcl/salatype.hxx>
+#include <saldata.hxx>
+#include <salinst.h>
+#include <salframe.h>
+#include <salobj.h>
+#include <saltimer.h>
+#include <salbmp.h>
+#include <vcl/salimestatus.hxx>
+#include <vcl/timer.hxx>
+#include <tools/solarmutex.hxx>
+
+// =======================================================================
+
+void SalAbort( const XubString& rErrorText )
+{
+ ImplFreeSalGDI();
+
+ if( !rErrorText.Len() )
+ fprintf( stderr, "Application Error " );
+ else
+ fprintf( stderr, "%s ",
+ ByteString( rErrorText, gsl_getSystemTextEncoding() ).GetBuffer() );
+ abort();
+}
+
+// =======================================================================
+
+ULONG GetCurrentThreadId()
+{
+ PTIB pptib = NULL;
+ PPIB pppib = NULL;
+
+ DosGetInfoBlocks( &pptib, &pppib );
+ return pptib->tib_ptib2->tib2_ultid;
+}
+
+// =======================================================================
+
+MRESULT EXPENTRY SalComWndProc( HWND hWnd, ULONG nMsg, MPARAM nMP1, MPARAM nMP2 );
+
+// =======================================================================
+
+class SalYieldMutex : public vos::OMutex
+{
+public:
+ Os2SalInstance* mpInstData;
+ ULONG mnCount;
+ ULONG mnThreadId;
+
+public:
+ SalYieldMutex( Os2SalInstance* pInstData );
+
+ virtual void SAL_CALL acquire();
+ virtual void SAL_CALL release();
+ virtual sal_Bool SAL_CALL tryToAcquire();
+
+ ULONG GetAcquireCount( ULONG nThreadId );
+};
+
+// -----------------------------------------------------------------------
+
+SalYieldMutex::SalYieldMutex( Os2SalInstance* pInstData )
+{
+ mpInstData = pInstData;
+ mnCount = 0;
+ mnThreadId = 0;
+}
+
+// -----------------------------------------------------------------------
+
+void SalYieldMutex::acquire()
+{
+ OMutex::acquire();
+ mnCount++;
+ mnThreadId = GetCurrentThreadId();
+}
+
+// -----------------------------------------------------------------------
+
+void SalYieldMutex::release()
+{
+ ULONG nThreadId = GetCurrentThreadId();
+ if ( mnThreadId != nThreadId )
+ OMutex::release();
+ else
+ {
+ SalData* pSalData = GetSalData();
+ if ( pSalData->mnAppThreadId != nThreadId )
+ {
+ if ( mnCount == 1 )
+ {
+ mpInstData->mpSalWaitMutex->acquire();
+ if ( mpInstData->mnYieldWaitCount )
+ WinPostMsg( mpInstData->mhComWnd, SAL_MSG_RELEASEWAITYIELD, 0, 0 );
+ mnThreadId = 0;
+ mnCount--;
+ OMutex::release();
+ mpInstData->mpSalWaitMutex->release();
+ }
+ else
+ {
+ mnCount--;
+ OMutex::release();
+ }
+ }
+ else
+ {
+ if ( mnCount == 1 )
+ mnThreadId = 0;
+ mnCount--;
+ OMutex::release();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool SalYieldMutex::tryToAcquire()
+{
+ if ( OMutex::tryToAcquire() )
+ {
+ mnCount++;
+ mnThreadId = GetCurrentThreadId();
+ return sal_True;
+ }
+ else
+ return sal_False;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG SalYieldMutex::GetAcquireCount( ULONG nThreadId )
+{
+ if ( nThreadId == mnThreadId )
+ return mnCount;
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplSalYieldMutexAcquireWithWait()
+{
+ Os2SalInstance* pInst = GetSalData()->mpFirstInstance;
+ if ( !pInst )
+ return;
+
+ // If we are the main thread, then we must wait with wait, because
+ // in if we don't reschedule, then we create deadlocks if a Windows
+ // Function is called from another thread. If we arn't the main thread,
+ // than we call qcquire directly.
+ ULONG nThreadId = GetCurrentThreadId();
+ SalData* pSalData = GetSalData();
+ if ( pSalData->mnAppThreadId == nThreadId )
+ {
+ // Wenn wir den Mutex nicht bekommen, muessen wir solange
+ // warten, bis wir Ihn bekommen
+ BOOL bAcquire = FALSE;
+ do
+ {
+ if ( pInst->mpSalYieldMutex->tryToAcquire() )
+ bAcquire = TRUE;
+ else
+ {
+ pInst->mpSalWaitMutex->acquire();
+ if ( pInst->mpSalYieldMutex->tryToAcquire() )
+ {
+ bAcquire = TRUE;
+ pInst->mpSalWaitMutex->release();
+ }
+ else
+ {
+ pInst->mnYieldWaitCount++;
+ pInst->mpSalWaitMutex->release();
+ QMSG aTmpMsg;
+ WinGetMsg( pSalData->mhAB, &aTmpMsg, pInst->mhComWnd, SAL_MSG_RELEASEWAITYIELD, SAL_MSG_RELEASEWAITYIELD );
+ pInst->mnYieldWaitCount--;
+ if ( pInst->mnYieldWaitCount )
+ WinPostMsg( pInst->mhComWnd, SAL_MSG_RELEASEWAITYIELD, 0 , 0 );
+ }
+ }
+ }
+ while ( !bAcquire );
+ }
+ else
+ pInst->mpSalYieldMutex->acquire();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplSalYieldMutexTryToAcquire()
+{
+ Os2SalInstance* pInst = GetSalData()->mpFirstInstance;
+ if ( pInst )
+ return pInst->mpSalYieldMutex->tryToAcquire();
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplSalYieldMutexAcquire()
+{
+ Os2SalInstance* pInst = GetSalData()->mpFirstInstance;
+ if ( pInst )
+ pInst->mpSalYieldMutex->acquire();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplSalYieldMutexRelease()
+{
+ Os2SalInstance* pInst = GetSalData()->mpFirstInstance;
+ if ( pInst )
+ pInst->mpSalYieldMutex->release();
+}
+
+// -----------------------------------------------------------------------
+
+ULONG ImplSalReleaseYieldMutex()
+{
+ Os2SalInstance* pInst = GetSalData()->mpFirstInstance;
+ if ( !pInst )
+ return 0;
+
+ SalYieldMutex* pYieldMutex = pInst->mpSalYieldMutex;
+ ULONG nCount = pYieldMutex->GetAcquireCount( GetCurrentThreadId() );
+ ULONG n = nCount;
+ while ( n )
+ {
+ pYieldMutex->release();
+ n--;
+ }
+
+ return nCount;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplSalAcquireYieldMutex( ULONG nCount )
+{
+ Os2SalInstance* pInst = GetSalData()->mpFirstInstance;
+ if ( !pInst )
+ return;
+
+ SalYieldMutex* pYieldMutex = pInst->mpSalYieldMutex;
+ while ( nCount )
+ {
+ pYieldMutex->acquire();
+ nCount--;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+#ifdef DBG_UTIL
+
+void ImplDbgTestSolarMutex()
+{
+ SalData* pSalData = GetSalData();
+ ULONG nCurThreadId = GetCurrentThreadId();
+ if ( pSalData->mnAppThreadId != nCurThreadId )
+ {
+ if ( pSalData->mpFirstInstance )
+ {
+ SalYieldMutex* pYieldMutex = pSalData->mpFirstInstance->mpSalYieldMutex;
+ if ( pYieldMutex->mnThreadId != nCurThreadId )
+ {
+ DBG_ERROR( "SolarMutex not locked, and not thread save code in VCL is called from outside of the main thread" );
+ }
+ }
+ }
+ else
+ {
+ if ( pSalData->mpFirstInstance )
+ {
+ SalYieldMutex* pYieldMutex = pSalData->mpFirstInstance->mpSalYieldMutex;
+ if ( pYieldMutex->mnThreadId != nCurThreadId )
+ {
+ DBG_ERROR( "SolarMutex not locked in the main thread" );
+ }
+ }
+ }
+}
+
+#endif
+
+// =======================================================================
+
+void InitSalData()
+{
+ SalData* pSalData = new SalData;
+ memset( pSalData, 0, sizeof( SalData ) );
+ SetSalData( pSalData );
+}
+
+// -----------------------------------------------------------------------
+
+void DeInitSalData()
+{
+ SalData* pSalData = GetSalData();
+ if ( pSalData->mpFontMetrics )
+ delete pSalData->mpFontMetrics;
+ delete pSalData;
+ SetSalData( NULL );
+}
+
+// -----------------------------------------------------------------------
+
+void InitSalMain()
+{
+ PPIB pib;
+ PTIB tib;
+ HAB hAB;
+ HMQ hMQ;
+ SalData* pData = GetAppSalData();
+#if OSL_DEBUG_LEVEL>0
+printf("InitSalMain\n");
+#endif
+
+ // morph application to PM
+ DosGetInfoBlocks(&tib, &pib);
+ // Change flag from VIO to PM:
+ if (pib->pib_ultype==2) pib->pib_ultype = 3;
+
+ // create anchor block
+ hAB = WinInitialize( 0 );
+ if ( !hAB )
+ return;
+
+ // create message queue
+ hMQ = WinCreateMsgQueue( hAB, 60 );
+ if ( !hMQ )
+ {
+ WinTerminate( hAB );
+ return;
+ }
+
+ if ( pData ) // Im AppServer NULL
+ {
+ // Ankerblock und Messagequeue merken
+ pData->mhAB = hAB;
+ pData->mhMQ = hMQ;
+ }
+
+}
+
+void DeInitSalMain()
+{
+#if OSL_DEBUG_LEVEL>0
+printf("DeInitSalMain\n");
+#endif
+
+ SalData* pData = GetAppSalData();
+ // destroy message queue and anchor block
+ WinDestroyMsgQueue( pData->mhMQ );
+ WinTerminate( pData->mhAB );
+
+}
+
+// -----------------------------------------------------------------------
+
+SalInstance* CreateSalInstance()
+{
+ SalData* pSalData = GetSalData();
+
+ // determine the os2 version
+ ULONG nMayor;
+ ULONG nMinor;
+ DosQuerySysInfo( QSV_VERSION_MAJOR, QSV_VERSION_MAJOR, &nMayor, sizeof( nMayor ) );
+ DosQuerySysInfo( QSV_VERSION_MINOR, QSV_VERSION_MINOR, &nMinor, sizeof( nMinor ) );
+ aSalShlData.mnVersion = (USHORT)(nMayor*10 + nMinor);
+
+ pSalData->mnAppThreadId = GetCurrentThreadId();
+
+ // register frame class
+ if ( !WinRegisterClass( pSalData->mhAB, (PSZ)SAL_FRAME_CLASSNAME,
+ (PFNWP)SalFrameWndProc, CS_MOVENOTIFY /* 17/08 CS_HITTEST | CS_MOVENOTIFY */,
+ SAL_FRAME_WNDEXTRA ) )
+ {
+ return NULL;
+ }
+ // register subframe class
+ if ( !WinRegisterClass( pSalData->mhAB, (PSZ)SAL_SUBFRAME_CLASSNAME,
+ (PFNWP)SalFrameWndProc, CS_SAVEBITS| CS_MOVENOTIFY,
+ SAL_FRAME_WNDEXTRA ) )
+ {
+ return NULL;
+ }
+ // register object class
+ if ( !WinRegisterClass( pSalData->mhAB, (PSZ)SAL_COM_CLASSNAME,
+ (PFNWP)SalComWndProc, 0, 0 ))
+ {
+ return NULL;
+ }
+
+ HWND hComWnd = WinCreateWindow( HWND_OBJECT, (PCSZ)SAL_COM_CLASSNAME,
+ (PCSZ)"", 0, 0, 0, 0, 0,
+ HWND_OBJECT, HWND_TOP,
+ 222, NULL, NULL);
+ if ( !hComWnd )
+ return NULL;
+
+#if OSL_DEBUG_LEVEL>0
+ debug_printf("CreateSalInstance hComWnd %x\n", hComWnd);
+#endif
+ Os2SalInstance* pInst = new Os2SalInstance;
+
+ // init instance (only one instance in this version !!!)
+ pSalData->mpFirstInstance = pInst;
+ pInst->mhAB = pSalData->mhAB;
+ pInst->mhMQ = pSalData->mhMQ;
+ pInst->mnArgc = pSalData->mnArgc;
+ pInst->mpArgv = pSalData->mpArgv;
+ pInst->mhComWnd = hComWnd;
+
+ // AppIcon ermitteln
+ ImplLoadSalIcon( SAL_RESID_ICON_DEFAULT, pInst->mhAppIcon);
+
+ // init static GDI Data
+ ImplInitSalGDI();
+
+ return pInst;
+}
+
+// -----------------------------------------------------------------------
+
+void DestroySalInstance( SalInstance* pInst )
+{
+ SalData* pSalData = GetSalData();
+
+ // (only one instance in this version !!!)
+ ImplFreeSalGDI();
+
+#ifdef ENABLE_IME
+ // IME-Daten freigeben
+ if ( pSalData->mpIMEData )
+ ImplReleaseSALIMEData();
+#endif
+
+ // reset instance
+ if ( pSalData->mpFirstInstance == pInst )
+ pSalData->mpFirstInstance = NULL;
+
+ delete pInst;
+}
+
+// -----------------------------------------------------------------------
+
+Os2SalInstance::Os2SalInstance()
+{
+ mhComWnd = 0;
+ mpSalYieldMutex = new SalYieldMutex( this );
+ mpSalWaitMutex = new vos::OMutex;
+ mnYieldWaitCount = 0;
+ mpSalYieldMutex->acquire();
+ ::tools::SolarMutex::SetSolarMutex( mpSalYieldMutex );
+}
+
+// -----------------------------------------------------------------------
+
+Os2SalInstance::~Os2SalInstance()
+{
+ ::tools::SolarMutex::SetSolarMutex( 0 );
+ mpSalYieldMutex->release();
+ delete mpSalYieldMutex;
+ delete mpSalWaitMutex;
+ WinDestroyWindow( mhComWnd);
+}
+
+// -----------------------------------------------------------------------
+
+vos::IMutex* Os2SalInstance::GetYieldMutex()
+{
+ return mpSalYieldMutex;
+}
+// -----------------------------------------------------------------------
+
+ULONG Os2SalInstance::ReleaseYieldMutex()
+{
+ return ImplSalReleaseYieldMutex();
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalInstance::AcquireYieldMutex( ULONG nCount )
+{
+ ImplSalAcquireYieldMutex( nCount );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplSalYield( BOOL bWait, BOOL bHandleAllCurrentEvents )
+{
+ QMSG aMsg;
+ bool bWasMsg = false, bOneEvent = false;
+ bool bQuit = false;
+
+ Os2SalInstance* pInst = GetSalData()->mpFirstInstance;
+ int nMaxEvents = bHandleAllCurrentEvents ? 100 : 1;
+ do
+ {
+ if ( WinPeekMsg( pInst->mhAB, &aMsg, 0, 0, 0, PM_REMOVE ) )
+ {
+ WinDispatchMsg( pInst->mhAB, &aMsg );
+ bOneEvent = bWasMsg = true;
+ if (aMsg.msg == WM_QUIT)
+ bQuit = true;
+ }
+ else
+ bOneEvent = false;
+ } while( --nMaxEvents && bOneEvent );
+
+ if ( bWait && ! bWasMsg )
+ {
+ if ( WinGetMsg( pInst->mhAB, &aMsg, 0, 0, 0 ) )
+ WinDispatchMsg( pInst->mhAB, &aMsg );
+ else
+ bQuit = true;
+ }
+
+ if (bQuit)
+ {
+ ImplSalYieldMutexAcquireWithWait();
+ Os2SalFrame* pFrame = GetSalData()->mpFirstFrame;
+ if ( pFrame )
+ {
+ if (pFrame->CallCallback( SALEVENT_SHUTDOWN, 0 ))
+ WinCancelShutdown( pFrame->mhAB, FALSE );
+ }
+ ImplSalYieldMutexRelease();
+ }
+
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents )
+{
+ SalYieldMutex* pYieldMutex = mpSalYieldMutex;
+ SalData* pSalData = GetSalData();
+ ULONG nCurThreadId = GetCurrentThreadId();
+ ULONG nCount = pYieldMutex->GetAcquireCount( nCurThreadId );
+ ULONG n = nCount;
+ while ( n )
+ {
+ pYieldMutex->release();
+ n--;
+ }
+ if ( pSalData->mnAppThreadId != nCurThreadId )
+ {
+ // #97739# A SendMessage call blocks until the called thread (here: the main thread)
+ // returns. During a yield however, messages are processed in the main thread that might
+ // result in a new message loop due to opening a dialog. Thus, SendMessage would not
+ // return which will block this thread!
+ // Solution: just give up the time slice and hope that messages are processed
+ // by the main thread anyway (where all windows are created)
+ // If the mainthread is not currently handling messages, then our SendMessage would
+ // also do nothing, so this seems to be reasonable.
+
+ // #i18883# only sleep if potential deadlock scenario, ie, when a dialog is open
+ if( ImplGetSVData()->maAppData.mnModalMode )
+ DosSleep(1);
+ else
+ WinSendMsg( mhComWnd, SAL_MSG_THREADYIELD, (MPARAM)bWait, (MPARAM)bHandleAllCurrentEvents );
+
+ n = nCount;
+ while ( n )
+ {
+ pYieldMutex->acquire();
+ n--;
+ }
+ }
+ else
+ {
+ ImplSalYield( bWait, bHandleAllCurrentEvents );
+
+ n = nCount;
+ while ( n )
+ {
+ ImplSalYieldMutexAcquireWithWait();
+ n--;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+MRESULT EXPENTRY SalComWndProc( HWND hWnd, ULONG nMsg,
+ MPARAM nMP1, MPARAM nMP2 )
+{
+ //debug_printf( "SalComWndProc hWnd 0x%x nMsg %d\n", hWnd, nMsg);
+
+ switch ( nMsg )
+ {
+ case SAL_MSG_PRINTABORTJOB:
+ //ImplSalPrinterAbortJobAsync( (HDC)wParam );
+ break;
+ case SAL_MSG_THREADYIELD:
+ ImplSalYield( (bool)nMP1, (bool) nMP2);
+ return 0;
+ // If we get this message, because another GetMessage() call
+ // has recieved this message, we must post this message to
+ // us again, because in the other case we wait forever.
+ case SAL_MSG_RELEASEWAITYIELD:
+ {
+ Os2SalInstance* pInst = GetSalData()->mpFirstInstance;
+ if ( pInst && pInst->mnYieldWaitCount )
+ WinPostMsg( hWnd, SAL_MSG_RELEASEWAITYIELD, nMP1, nMP2 );
+ }
+ return 0;
+ case SAL_MSG_STARTTIMER:
+ ImplSalStartTimer( (ULONG)nMP2, FALSE);
+ return 0;
+ case SAL_MSG_CREATEFRAME:
+ return (MRESULT)ImplSalCreateFrame( GetSalData()->mpFirstInstance, (HWND)nMP2, (ULONG)nMP1 );
+ case SAL_MSG_DESTROYFRAME:
+ delete (SalFrame*)nMP2;
+ return 0;
+ case SAL_MSG_DESTROYHWND:
+ //We only destroy the native window here. We do NOT destroy the SalFrame contained
+ //in the structure (GetWindowPtr()).
+ if (WinDestroyWindow((HWND)nMP2) == 0)
+ {
+ OSL_ENSURE(0, "DestroyWindow failed!");
+ //Failure: We remove the SalFrame from the window structure. So we avoid that
+ // the window structure may contain an invalid pointer, once the SalFrame is deleted.
+ SetWindowPtr((HWND)nMP2, 0);
+ }
+ return 0;
+ case SAL_MSG_CREATEOBJECT:
+ return (MRESULT)ImplSalCreateObject( GetSalData()->mpFirstInstance, (Os2SalFrame*)(ULONG)nMP2 );
+ case SAL_MSG_DESTROYOBJECT:
+ delete (SalObject*)nMP2;
+ return 0;
+ case SAL_MSG_CREATESOUND:
+ //return (MRESULT)((Os2SalSound*)nMP2)->ImplCreate();
+ return 0;
+ case SAL_MSG_DESTROYSOUND:
+ //((Os2SalSound*)nMP2)->ImplDestroy();
+ return 0;
+ case SAL_MSG_POSTTIMER:
+ SalTimerProc( 0, 0, SALTIMERPROC_RECURSIVE, (ULONG)nMP2 );
+ break;
+ case WM_TIMER:
+ SalTimerProc( hWnd, 0, 0, 0 );
+ break;
+ }
+
+ return WinDefWindowProc( hWnd, nMsg, nMP1, nMP2 );
+}
+
+// -----------------------------------------------------------------------
+
+bool Os2SalInstance::AnyInput( USHORT nType )
+{
+ SalData* pSalData = GetSalData();
+ QMSG aQMSG;
+
+ if ( (nType & (INPUT_ANY)) == INPUT_ANY )
+ {
+ // Any Input
+ if ( WinPeekMsg( pSalData->mhAB, &aQMSG, 0, 0, 0, PM_NOREMOVE ) )
+ return TRUE;
+ }
+ else
+ {
+ if ( nType & INPUT_MOUSE )
+ {
+ // Test auf Mouseinput
+ if ( WinPeekMsg( pSalData->mhAB, &aQMSG, 0,
+ WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE ) )
+ return TRUE;
+ }
+
+ if ( nType & INPUT_KEYBOARD )
+ {
+ // Test auf Keyinput
+ if ( WinPeekMsg( pSalData->mhAB, &aQMSG, 0,
+ WM_CHAR, WM_CHAR, PM_NOREMOVE ) )
+ return !(SHORT1FROMMP( aQMSG.mp1 ) & KC_KEYUP);
+ }
+
+ if ( nType & INPUT_PAINT )
+ {
+ // Test auf Paintinput
+ if ( WinPeekMsg( pSalData->mhAB, &aQMSG, 0,
+ WM_PAINT, WM_PAINT, PM_NOREMOVE ) )
+ return TRUE;
+ }
+
+ if ( nType & INPUT_TIMER )
+ {
+ // Test auf Timerinput
+ if ( WinPeekMsg( pSalData->mhAB, &aQMSG, 0,
+ WM_TIMER, WM_TIMER, PM_NOREMOVE ) )
+ return TRUE;
+ }
+
+ if ( nType & INPUT_OTHER )
+ {
+ // Test auf sonstigen Input
+ if ( WinPeekMsg( pSalData->mhAB, &aQMSG, 0, 0, 0, PM_NOREMOVE ) )
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+SalFrame* Os2SalInstance::CreateChildFrame( SystemParentData* pSystemParentData, ULONG nSalFrameStyle )
+{
+ // Um auf Main-Thread umzuschalten
+ return (SalFrame*)WinSendMsg( mhComWnd, SAL_MSG_CREATEFRAME, (MPARAM)nSalFrameStyle, (MPARAM)pSystemParentData->hWnd );
+}
+
+// -----------------------------------------------------------------------
+
+SalFrame* Os2SalInstance::CreateFrame( SalFrame* pParent, ULONG nSalFrameStyle )
+{
+ // Um auf Main-Thread umzuschalten
+ HWND mhWndClient;
+//31/05/06 YD use client as owner(parent) so positioning will not need to
+// take care of borders and captions
+ if ( pParent )
+ mhWndClient = static_cast<Os2SalFrame*>(pParent)->mhWndClient;
+ else
+ mhWndClient = 0;
+ return (SalFrame*)WinSendMsg( mhComWnd, SAL_MSG_CREATEFRAME, (MPARAM)nSalFrameStyle, (MPARAM)mhWndClient );
+}
+
+
+// -----------------------------------------------------------------------
+
+void Os2SalInstance::DestroyFrame( SalFrame* pFrame )
+{
+ WinSendMsg( mhComWnd, SAL_MSG_DESTROYFRAME, 0, (MPARAM)pFrame );
+}
+
+// -----------------------------------------------------------------------
+
+SalObject* Os2SalInstance::CreateObject( SalFrame* pParent,
+ SystemWindowData* /*pWindowData*/, // SystemWindowData meaningless on Windows
+ BOOL /*bShow*/ )
+{
+ // Um auf Main-Thread umzuschalten
+ return (SalObject*)WinSendMsg( mhComWnd, SAL_MSG_CREATEOBJECT, 0, (MPARAM)pParent );
+}
+
+
+// -----------------------------------------------------------------------
+
+void Os2SalInstance::DestroyObject( SalObject* pObject )
+{
+ WinSendMsg( mhComWnd, SAL_MSG_DESTROYOBJECT, 0, (MPARAM)pObject );
+}
+
+// -----------------------------------------------------------------------
+
+void* Os2SalInstance::GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes )
+{
+ rReturnedBytes = 1;
+ rReturnedType = AsciiCString;
+ return (void*) "";
+}
+
+void Os2SalInstance::AddToRecentDocumentList(const rtl::OUString& /*rFileUrl*/, const rtl::OUString& /*rMimeType*/)
+{
+}
+
+// -----------------------------------------------------------------------
+
+SalTimer* Os2SalInstance::CreateSalTimer()
+{
+ return new Os2SalTimer();
+}
+
+// -----------------------------------------------------------------------
+
+SalBitmap* Os2SalInstance::CreateSalBitmap()
+{
+ return new Os2SalBitmap();
+}
+
+// -----------------------------------------------------------------------
+
+class Os2ImeStatus : public SalI18NImeStatus
+{
+ public:
+ Os2ImeStatus() {}
+ virtual ~Os2ImeStatus() {}
+
+ // asks whether there is a status window available
+ // to toggle into menubar
+ virtual bool canToggle() { return false; }
+ virtual void toggle() {}
+};
+
+SalI18NImeStatus* Os2SalInstance::CreateI18NImeStatus()
+{
+ return new Os2ImeStatus();
+}
+
+// -----------------------------------------------------------------------
+
+const ::rtl::OUString& SalGetDesktopEnvironment()
+{
+ static ::rtl::OUString aDesktopEnvironment( RTL_CONSTASCII_USTRINGPARAM( "OS/2" ) );
+ return aDesktopEnvironment;
+}
+
+SalSession* Os2SalInstance::CreateSalSession()
+{
+ return NULL;
+}
+
diff --git a/vcl/os2/source/app/sallang.cxx b/vcl/os2/source/app/sallang.cxx
new file mode 100644
index 000000000000..f23705077ac3
--- /dev/null
+++ b/vcl/os2/source/app/sallang.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.
+ *
+ ************************************************************************/
+
+#ifndef _SALLANG_HXX
+#include <sallang.hxx>
+#endif
+
+// =======================================================================
+
+// -----------------------------------------------------------------------
+// English (US/UK/AUS/CAN/NZ/EIRE/SAFRICA/JAMAICA/CARRIBEAN)
+static const wchar_t* aImplLangEnglishTab[LSTR_COUNT] =
+{
+ L"Shift", // LSTR_KEY_SHIFT
+ L"Ctrl", // LSTR_KEY_CTRL
+ L"Alt", // LSTR_KEY_ALT
+ L"Up", // LSTR_KEY_UP
+ L"Down", // LSTR_KEY_DOWN
+ L"Left", // LSTR_KEY_LEFT
+ L"Right", // LSTR_KEY_RIGHT
+ L"Home", // LSTR_KEY_HOME
+ L"End", // LSTR_KEY_END
+ L"PageUp", // LSTR_KEY_PAGEUP
+ L"PageDown", // LSTR_KEY_PAGEDOWN
+ L"Enter", // LSTR_KEY_RETURN
+ L"Esc", // LSTR_KEY_ESC
+ L"Tab", // LSTR_KEY_TAB
+ L"Backspace", // LSTR_KEY_BACKSPACE
+ L"Space", // LSTR_KEY_SPACE
+ L"Insert", // LSTR_KEY_INSERT
+ L"Del", // LSTR_KEY_DELETE
+};
+
+// =======================================================================
+
+const sal_Unicode** ImplGetLangTab( LanguageType eLang )
+{
+ // Sprachtabelle ermitteln
+ const wchar_t** pLangTab;
+ //switch ( International::GetNeutralLanguage( eLang ) )
+ switch ( eLang )
+ {
+#if 0
+ case LANGUAGE_DANISH:
+ pLangTab = aImplLangDanishTab;
+ break;
+
+ case LANGUAGE_DUTCH:
+ case LANGUAGE_DUTCH_BELGIAN:
+ pLangTab = aImplLangDutchTab;
+ break;
+
+ case LANGUAGE_FINNISH:
+ pLangTab = aImplLangFinnishTab;
+ break;
+
+ case LANGUAGE_FRENCH:
+ pLangTab = aImplLangFrenchTab;
+ break;
+
+ case LANGUAGE_GERMAN:
+ pLangTab = aImplLangGermanTab;
+ break;
+
+ case LANGUAGE_ITALIAN:
+ pLangTab = aImplLangItalianTab;
+ break;
+
+ case LANGUAGE_NORWEGIAN:
+ case LANGUAGE_NORWEGIAN_BOKMAL:
+ pLangTab = aImplLangNorwegianTab;
+ break;
+
+ case LANGUAGE_PORTUGUESE:
+ case LANGUAGE_PORTUGUESE_BRAZILIAN:
+ pLangTab = aImplLangPortugueseTab;
+ break;
+
+ case LANGUAGE_SPANISH:
+ pLangTab = aImplLangSpanishTab;
+ break;
+
+ case LANGUAGE_SWEDISH:
+ pLangTab = aImplLangSwedishTab;
+ break;
+#endif
+ default:
+ pLangTab = aImplLangEnglishTab;
+ break;
+ }
+
+ return (const sal_Unicode**)pLangTab;
+}
diff --git a/vcl/os2/source/app/salshl.cxx b/vcl/os2/source/app/salshl.cxx
new file mode 100644
index 000000000000..637ddd748f33
--- /dev/null
+++ b/vcl/os2/source/app/salshl.cxx
@@ -0,0 +1,123 @@
+/*************************************************************************
+ *
+ * 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 <svpm.h>
+
+#define _SV_SALSHL_CXX
+#include <saldata.hxx>
+#include <tools/debug.hxx>
+
+// =======================================================================
+
+SalShlData aSalShlData;
+
+HMODULE ImplGetModule(void);
+static HMODULE mhMod = ImplGetModule();
+
+// =======================================================================
+
+APIRET APIENTRY DosQueryModFromEIP (HMODULE *phMod, ULONG *pObjNum,
+ ULONG BuffLen, PCHAR pBuff, ULONG *pOffset, ULONG Address);
+
+HMODULE ImplGetModule(void)
+{
+ HMODULE hMod;
+ ULONG ObjNum;
+ CHAR Buff[2*_MAX_PATH];
+ ULONG Offset;
+ APIRET rc;
+
+ // get module handle (and name)
+ rc = DosQueryModFromEIP( &hMod, &ObjNum, sizeof( Buff), Buff, &Offset, (ULONG)ImplGetModule);
+ if (rc)
+ return NULL;
+ // return module handle
+ aSalShlData.mhMod = hMod;
+ return hMod;
+}
+
+// =======================================================================
+
+HPOINTER ImplLoadSalCursor( int nId )
+{
+ DBG_ASSERT( aSalShlData.mhMod, "no DLL instance handle" );
+
+ HPOINTER hPointer = WinLoadPointer( HWND_DESKTOP, aSalShlData.mhMod, nId );
+
+ DBG_ASSERT( hPointer, "pointer not found in sal resource" );
+#if OSL_DEBUG_LEVEL>0
+ if (!hPointer)
+ debug_printf( "ImplLoadSalCursor: pointer %d not found in sal resource\n", nId);
+#endif
+ return hPointer;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplLoadSalIcon( int nId, HPOINTER& rIcon)
+{
+ DBG_ASSERT( aSalShlData.mhMod, "no DLL instance handle" );
+
+ SalData* pSalData = GetSalData();
+
+ // check the cache first
+ SalIcon *pSalIcon = pSalData->mpFirstIcon;
+ while( pSalIcon )
+ {
+ if( pSalIcon->nId != nId )
+ pSalIcon = pSalIcon->pNext;
+ else
+ {
+ rIcon = pSalIcon->hIcon;
+ return (rIcon != 0);
+ }
+ }
+
+ // Try at first to load the icons from the application exe file
+ rIcon = WinLoadPointer( HWND_DESKTOP, NULL, nId );
+ if ( !rIcon )
+ {
+ // If the application don't provide these icons, then we try
+ // to load the icon from the VCL resource
+ rIcon = WinLoadPointer( HWND_DESKTOP, aSalShlData.mhMod, nId );
+ }
+
+ if( rIcon )
+ {
+ // add to icon cache
+ pSalIcon = new SalIcon();
+ pSalIcon->nId = nId;
+ pSalIcon->hIcon = rIcon;
+ pSalIcon->pNext = pSalData->mpFirstIcon;
+ pSalData->mpFirstIcon = pSalIcon;
+ }
+
+ return (rIcon != 0);
+}
+
+// =======================================================================
+
diff --git a/vcl/os2/source/app/saltimer.cxx b/vcl/os2/source/app/saltimer.cxx
new file mode 100644
index 000000000000..bcdeec94ef25
--- /dev/null
+++ b/vcl/os2/source/app/saltimer.cxx
@@ -0,0 +1,140 @@
+/*************************************************************************
+ *
+ * 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 <svpm.h>
+
+#define _SV_SALTIMER_CXX
+#include <saldata.hxx>
+#include <saltimer.h>
+#include <salinst.h>
+
+// =======================================================================
+
+// Maximale Periode
+#define MAX_SYSPERIOD 65533
+#define IDTIMER 10
+
+// =======================================================================
+
+void ImplSalStartTimer( ULONG nMS, BOOL bMutex )
+{
+ SalData* pSalData = GetSalData();
+
+ // Periode darf nicht zu gross sein, da OS2 2.11 mit USHORT arbeitet
+ // Remenber the time of the timer
+ pSalData->mnTimerMS = nMS;
+ if ( !bMutex )
+ pSalData->mnTimerOrgMS = nMS;
+
+ // Periode darf nicht zu gross sein, da Windows mit USHORT arbeitet
+ if ( nMS > MAX_SYSPERIOD )
+ nMS = MAX_SYSPERIOD;
+
+ // Gibt es einen Timer, dann zerstoren
+ if ( pSalData->mnTimerId )
+ WinStopTimer( pSalData->mhAB, pSalData->mpFirstInstance->mhComWnd, pSalData->mnTimerId );
+
+ // Make a new timer with new period
+ pSalData->mnTimerId = WinStartTimer( pSalData->mhAB, pSalData->mpFirstInstance->mhComWnd, IDTIMER, nMS );
+ pSalData->mnNextTimerTime = pSalData->mnLastEventTime + nMS;
+}
+
+// -----------------------------------------------------------------------
+
+Os2SalTimer::~Os2SalTimer()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalTimer::Start( ULONG nMS )
+{
+ // Um auf Main-Thread umzuschalten
+ SalData* pSalData = GetSalData();
+ if ( pSalData->mpFirstInstance )
+ {
+ if ( pSalData->mnAppThreadId != GetCurrentThreadId() )
+ WinPostMsg( pSalData->mpFirstInstance->mhComWnd, SAL_MSG_STARTTIMER, 0, (MPARAM)nMS );
+ else
+ WinSendMsg( pSalData->mpFirstInstance->mhComWnd, SAL_MSG_STARTTIMER, 0, (MPARAM)nMS );
+ }
+ else
+ ImplSalStartTimer( nMS, FALSE);
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalTimer::Stop()
+{
+ SalData* pSalData = GetSalData();
+
+ // Exitstiert ein Timer, dann diesen zerstoeren
+ if ( pSalData->mnTimerId ) {
+ WinStopTimer( pSalData->mhAB, pSalData->mpFirstInstance->mhComWnd, pSalData->mnTimerId );
+ pSalData->mnTimerId = 0;
+ pSalData->mnNextTimerTime = 0;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SalTimerProc( HWND, UINT, UINT nId, ULONG )
+{
+ SalData* pSalData = GetSalData();
+ ImplSVData* pSVData = ImplGetSVData();
+
+ // Test for MouseLeave
+ SalTestMouseLeave();
+
+ bool bRecursive = pSalData->mbInTimerProc && (nId != SALTIMERPROC_RECURSIVE);
+ if ( pSVData->mpSalTimer && ! bRecursive )
+ {
+ // Try to aquire the mutex. If we don't get the mutex then we
+ // try this a short time later again.
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ bRecursive = pSalData->mbInTimerProc && (nId != SALTIMERPROC_RECURSIVE);
+ if ( pSVData->mpSalTimer && ! bRecursive )
+ {
+ pSalData->mbInTimerProc = TRUE;
+ pSVData->mpSalTimer->CallCallback();
+ pSalData->mbInTimerProc = FALSE;
+ ImplSalYieldMutexRelease();
+
+ // Run the timer in the correct time, if we start this
+ // with a small timeout, because we don't get the mutex
+ if ( pSalData->mnTimerId &&
+ (pSalData->mnTimerMS != pSalData->mnTimerOrgMS) )
+ ImplSalStartTimer( pSalData->mnTimerOrgMS, FALSE );
+ }
+ }
+ else
+ ImplSalStartTimer( 10, TRUE );
+ }
+
+}
+
diff --git a/vcl/os2/source/gdi/makefile.mk b/vcl/os2/source/gdi/makefile.mk
new file mode 100644
index 000000000000..b411c1eb2ce2
--- /dev/null
+++ b/vcl/os2/source/gdi/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=SV
+TARGET=salgdi
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+
+# --- Files --------------------------------------------------------
+
+YD00_CXXFILES= salgdi.cxx \
+ salgdi2.cxx \
+ salgdi3.cxx \
+ salvd.cxx \
+ salprn.cxx \
+ salbmp.cxx
+
+SLOFILES= $(SLO)$/salgdi.obj \
+ $(SLO)$/salgdi2.obj \
+ $(SLO)$/salgdi3.obj \
+ $(SLO)$/salvd.obj \
+ $(SLO)$/salprn.obj \
+ $(SLO)$/salbmp.obj \
+ $(SLO)$/os2layout.obj
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
diff --git a/vcl/os2/source/gdi/os2layout.cxx b/vcl/os2/source/gdi/os2layout.cxx
new file mode 100644
index 000000000000..924770c86869
--- /dev/null
+++ b/vcl/os2/source/gdi/os2layout.cxx
@@ -0,0 +1,1056 @@
+/*************************************************************************
+ *
+ * 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 <tools/svwin.h>
+
+#include <rtl/ustring.hxx>
+#include <osl/module.h>
+#include <salgdi.h>
+#include <saldata.hxx>
+#include <vcl/sallayout.hxx>
+
+#ifndef __H_FT2LIB
+#include <wingdi.h>
+#include <ft2lib.h>
+#endif
+
+#include <cstdio>
+#include <malloc.h>
+
+#ifdef GCP_KERN_HACK
+ #include <algorithm>
+#endif // GCP_KERN_HACK
+
+// for GetMirroredChar
+#include <vcl/svapp.hxx>
+
+#include <hash_map>
+typedef std::hash_map<int,int> IntMap;
+
+#define DROPPED_OUTGLYPH 0xFFFF
+
+using namespace rtl;
+
+// =======================================================================
+
+// OS/2 specific physical font instance
+class ImplOs2FontEntry : public ImplFontEntry
+{
+public:
+ ImplOs2FontEntry( ImplFontSelectData& );
+ ~ImplOs2FontEntry();
+
+private:
+ // TODO: also add HFONT??? Watch out for issues with too many active fonts...
+
+#ifdef GCP_KERN_HACK
+public:
+ bool HasKernData() const;
+ void SetKernData( int, const KERNINGPAIRS* );
+ int GetKerning( sal_Unicode, sal_Unicode ) const;
+private:
+ KERNINGPAIRS* mpKerningPairs;
+ int mnKerningPairs;
+#endif // GCP_KERN_HACK
+
+public:
+ int GetCachedGlyphWidth( int nCharCode ) const;
+ void CacheGlyphWidth( int nCharCode, int nCharWidth );
+private:
+ IntMap maWidthMap;
+};
+
+// -----------------------------------------------------------------------
+
+inline void ImplOs2FontEntry::CacheGlyphWidth( int nCharCode, int nCharWidth )
+{
+ maWidthMap[ nCharCode ] = nCharWidth;
+}
+
+inline int ImplOs2FontEntry::GetCachedGlyphWidth( int nCharCode ) const
+{
+ IntMap::const_iterator it = maWidthMap.find( nCharCode );
+ if( it == maWidthMap.end() )
+ return -1;
+ return it->second;
+}
+
+// =======================================================================
+
+class Os2Layout : public SalLayout
+{
+public:
+ Os2Layout( HDC, const ImplOs2FontData&, ImplOs2FontEntry& );
+ virtual void InitFont() const;
+ void SetFontScale( float f ) { mfFontScale = f; }
+ float GetFontScale() const { return mfFontScale; }
+
+protected:
+ HPS mhPS; // OS2 device handle
+ FATTRS mhFont;
+ int mnBaseAdv; // x-offset relative to Layout origin
+ float mfFontScale; // allows metrics emulation of huge font sizes
+
+ const ImplOs2FontData& mrOs2FontData;
+ ImplOs2FontEntry& mrOs2FontEntry;
+};
+
+// =======================================================================
+
+class Os2SalLayout : public Os2Layout
+{
+public:
+ Os2SalLayout( HPS, BYTE nCharSet, const ImplOs2FontData&, ImplOs2FontEntry& );
+ virtual ~Os2SalLayout();
+
+ virtual bool LayoutText( ImplLayoutArgs& );
+ virtual void AdjustLayout( ImplLayoutArgs& );
+ virtual void DrawText( SalGraphics& ) const;
+
+ virtual int GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, int&,
+ sal_Int32* pGlyphAdvances, int* pCharIndexes ) const;
+
+ virtual long FillDXArray( long* pDXArray ) const;
+ virtual int GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const;
+ virtual void GetCaretPositions( int nArraySize, long* pCaretXArray ) const;
+
+ // for glyph+font+script fallback
+ virtual void MoveGlyph( int nStart, long nNewXPos );
+ virtual void DropGlyph( int nStart );
+ virtual void Simplify( bool bIsBase );
+
+protected:
+ void Justify( long nNewWidth );
+ void ApplyDXArray( const ImplLayoutArgs& );
+
+protected:
+
+private:
+ int mnGlyphCount;
+ int mnCharCount;
+ sal_Unicode* mpOutGlyphs;
+ int* mpGlyphAdvances; // if possible this is shared with mpGlyphAdvances[]
+ int* mpGlyphOrigAdvs;
+ int* mpCharWidths; // map rel char pos to char width
+ int* mpChars2Glyphs; // map rel char pos to abs glyph pos
+ int* mpGlyphs2Chars; // map abs glyph pos to abs char pos
+ bool* mpGlyphRTLFlags; // BiDi status for glyphs: true=>RTL
+ mutable long mnWidth;
+ bool mbDisableGlyphs;
+
+ int mnNotdefWidth;
+ BYTE mnCharSet;
+
+};
+
+// =======================================================================
+
+Os2Layout::Os2Layout( HPS hPS, const ImplOs2FontData& rWFD, ImplOs2FontEntry& rWFE )
+: mhPS( hPS ),
+ mnBaseAdv( 0 ),
+ mfFontScale( 1.0 ),
+ mrOs2FontData( rWFD ),
+ mrOs2FontEntry( rWFE )
+{
+ BOOL fSuccess;
+ fSuccess = Ft2QueryLogicalFont( mhPS, LCID_BASE, NULL, &mhFont, sizeof(FATTRS));
+}
+
+// -----------------------------------------------------------------------
+
+void Os2Layout::InitFont() const
+{
+ // select fallback level 0 font
+ APIRET rc = Ft2CreateLogFont( mhPS, NULL, LCID_BASE, (PFATTRS)&mhFont);
+}
+
+// =======================================================================
+
+Os2SalLayout::Os2SalLayout( HPS hPS, BYTE nCharSet,
+ const ImplOs2FontData& rOs2FontData, ImplOs2FontEntry& rOs2FontEntry )
+: Os2Layout( hPS, rOs2FontData, rOs2FontEntry ),
+ mnGlyphCount( 0 ),
+ mnCharCount( 0 ),
+ mpOutGlyphs( NULL ),
+ mpGlyphAdvances( NULL ),
+ mpGlyphOrigAdvs( NULL ),
+ mpCharWidths( NULL ),
+ mpChars2Glyphs( NULL ),
+ mpGlyphs2Chars( NULL ),
+ mpGlyphRTLFlags( NULL ),
+ mnWidth( 0 ),
+ mnNotdefWidth( -1 ),
+ mnCharSet( nCharSet ),
+ mbDisableGlyphs( false )
+{
+ mbDisableGlyphs = true;
+}
+
+// -----------------------------------------------------------------------
+
+Os2SalLayout::~Os2SalLayout()
+{
+ delete[] mpGlyphRTLFlags;
+ delete[] mpGlyphs2Chars;
+ delete[] mpChars2Glyphs;
+ if( mpCharWidths != mpGlyphAdvances )
+ delete[] mpCharWidths;
+ delete[] mpGlyphOrigAdvs;
+ delete[] mpGlyphAdvances;
+ delete[] mpOutGlyphs;
+}
+
+// -----------------------------------------------------------------------
+
+bool Os2SalLayout::LayoutText( ImplLayoutArgs& rArgs )
+{
+ // prepare layout
+ // TODO: fix case when recyclying old Os2SalLayout object
+ mbDisableGlyphs |= ((rArgs.mnFlags & SAL_LAYOUT_DISABLE_GLYPH_PROCESSING) != 0);
+ mnCharCount = rArgs.mnEndCharPos - rArgs.mnMinCharPos;
+
+ if( !mbDisableGlyphs )
+ {
+ // Win32 glyph APIs have serious problems with vertical layout
+ // => workaround is to use the unicode methods then
+ if( rArgs.mnFlags & SAL_LAYOUT_VERTICAL )
+ mbDisableGlyphs = true;
+ else
+ // use cached value from font face
+ mbDisableGlyphs = mrOs2FontData.IsGlyphApiDisabled();
+ }
+
+ // TODO: use a cached value for bDisableAsianKern from upper layers
+#if 0
+ if( rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN )
+ {
+ TEXTMETRICA aTextMetricA;
+ if( ::GetTextMetricsA( mhDC, &aTextMetricA )
+ && !(aTextMetricA.tmPitchAndFamily & TMPF_FIXED_PITCH) )
+ rArgs.mnFlags &= ~SAL_LAYOUT_KERNING_ASIAN;
+ }
+#endif
+
+ // layout text
+ int i, j;
+
+ mnGlyphCount = 0;
+ bool bVertical = (rArgs.mnFlags & SAL_LAYOUT_VERTICAL) != 0;
+
+ // count the number of chars to process if no RTL run
+ rArgs.ResetPos();
+ bool bHasRTL = false;
+ while( rArgs.GetNextRun( &i, &j, &bHasRTL ) && !bHasRTL )
+ mnGlyphCount += j - i;
+
+ // if there are RTL runs we need room to remember individual BiDi flags
+ if( bHasRTL )
+ {
+ mpGlyphRTLFlags = new bool[ mnCharCount ];
+ for( i = 0; i < mnCharCount; ++i )
+ mpGlyphRTLFlags[i] = false;
+ }
+
+ // rewrite the logical string if needed to prepare for the API calls
+ const sal_Unicode* pBidiStr = rArgs.mpStr + rArgs.mnMinCharPos;
+ if( (mnGlyphCount != mnCharCount) || bVertical )
+ {
+ // we need to rewrite the pBidiStr when any of
+ // - BiDirectional layout
+ // - vertical layout
+ // - partial runs (e.g. with control chars or for glyph fallback)
+ // are involved
+ sal_Unicode* pRewrittenStr = (sal_Unicode*)alloca( mnCharCount * sizeof(sal_Unicode) );
+ pBidiStr = pRewrittenStr;
+
+ // note: glyph to char mapping is relative to first character
+ mpChars2Glyphs = new int[ mnCharCount ];
+ mpGlyphs2Chars = new int[ mnCharCount ];
+ for( i = 0; i < mnCharCount; ++i )
+ mpChars2Glyphs[i] = mpGlyphs2Chars[i] = -1;
+
+ mnGlyphCount = 0;
+ rArgs.ResetPos();
+ bool bIsRTL = false;
+ while( rArgs.GetNextRun( &i, &j, &bIsRTL ) )
+ {
+ do
+ {
+ // get the next leftmost character in this run
+ int nCharPos = bIsRTL ? --j : i++;
+ sal_Unicode cChar = rArgs.mpStr[ nCharPos ];
+
+ // in the RTL case mirror the character and remember its RTL status
+ if( bIsRTL )
+ {
+ cChar = ::GetMirroredChar( cChar );
+ mpGlyphRTLFlags[ mnGlyphCount ] = true;
+ }
+
+ // for vertical writing use vertical alternatives
+ if( bVertical )
+ {
+ sal_Unicode cVert = ::GetVerticalChar( cChar );
+ if( cVert )
+ cChar = cVert;
+ }
+
+ // rewrite the original string
+ // update the mappings between original and rewritten string
+ pRewrittenStr[ mnGlyphCount ] = cChar;
+ mpGlyphs2Chars[ mnGlyphCount ] = nCharPos;
+ mpChars2Glyphs[ nCharPos - rArgs.mnMinCharPos ] = mnGlyphCount;
+ ++mnGlyphCount;
+ } while( i < j );
+ }
+ }
+
+ mpOutGlyphs = new sal_Unicode[ mnGlyphCount ];
+ mpGlyphAdvances = new int[ mnGlyphCount ];
+
+ if( rArgs.mnFlags & (SAL_LAYOUT_KERNING_PAIRS | SAL_LAYOUT_KERNING_ASIAN) )
+ mpGlyphOrigAdvs = new int[ mnGlyphCount ];
+
+#ifndef GCP_KERN_HACK
+ DWORD nGcpOption = 0;
+ // enable kerning if requested
+ if( rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS )
+ nGcpOption |= GCP_USEKERNING;
+#endif // GCP_KERN_HACK
+
+ LONG lLcid = Ft2QueryCharSet( mhPS);
+
+ for( i = 0; i < mnGlyphCount; ++i )
+ mpOutGlyphs[i] = pBidiStr[ i ];
+ mnWidth = 0;
+ for( i = 0; i < mnGlyphCount; ++i )
+ {
+ const sal_Unicode* pCodes = &pBidiStr[i];
+ // check for surrogate pairs
+ if( (pCodes[0] & 0xFC00) == 0xDC00 )
+ continue;
+ bool bSurrogate = ((pCodes[0] & 0xFC00) == 0xD800);
+
+ // get the width of the corresponding code point
+ int nCharCode = pCodes[0];
+ if( bSurrogate )
+ nCharCode = 0x10000 + ((pCodes[0] & 0x03FF) << 10) + (pCodes[1] & 0x03FF);
+ int nGlyphWidth = mrOs2FontEntry.GetCachedGlyphWidth( nCharCode );
+ if( nGlyphWidth == -1 )
+ {
+ if (!Ft2QueryStringWidthW( mhPS, (LPWSTR)&pCodes[0], 1, (LONG*)&nGlyphWidth))
+ nGlyphWidth = 0;
+ mrOs2FontEntry.CacheGlyphWidth( nCharCode, nGlyphWidth );
+ }
+ mpGlyphAdvances[ i ] = nGlyphWidth;
+ mnWidth += nGlyphWidth;
+
+ // remaining codes of surrogate pair get a zero width
+ if( bSurrogate )
+ mpGlyphAdvances[ i+1 ] = 0;
+
+ // check with the font face if glyph fallback is needed
+ if( mrOs2FontData.HasChar( nCharCode ) )
+ continue;
+ // Type1 charmaps are not complete (or buggy), use FT2 to check again
+ if (Ft2FontSupportsUnicodeChar( mhPS, lLcid, TRUE, nCharCode))
+ continue;
+
+#if OSL_DEBUG_LEVEL>0
+ debug_printf("Os2SalLayout::LayoutText font does not support unicode char\n");
+#endif
+ // request glyph fallback at this position in the string
+ bool bRTL = mpGlyphRTLFlags ? mpGlyphRTLFlags[i] : false;
+ int nCharPos = mpGlyphs2Chars ? mpGlyphs2Chars[i]: i + rArgs.mnMinCharPos;
+ rArgs.NeedFallback( nCharPos, bRTL );
+ if( bSurrogate )
+ rArgs.NeedFallback( nCharPos+1, bRTL );
+
+ if( rArgs.mnFlags & SAL_LAYOUT_FOR_FALLBACK )
+ {
+ // when we already are layouting for glyph fallback
+ // then a new unresolved glyph is not interesting
+ mnNotdefWidth = 0;
+ mpOutGlyphs[i] = DROPPED_OUTGLYPH;
+ if( mbDisableGlyphs && bSurrogate )
+ mpOutGlyphs[i+1] = DROPPED_OUTGLYPH;
+ }
+ else
+ {
+ if( mnNotdefWidth < 0 )
+ {
+ // get the width of the NotDef glyph
+ LONG aExtent;
+ mnNotdefWidth = 0;
+ if (Ft2QueryStringWidthW( mhPS, (LPWSTR)&rArgs.mpStr[ nCharPos ], 1, &aExtent))
+ mnNotdefWidth = aExtent;
+ }
+ // use a better NotDef glyph
+ if( !mbDisableGlyphs )
+ mpOutGlyphs[i] = 0;
+ }
+
+ // replace the current glyph with the NotDef glyph
+ mnWidth += mnNotdefWidth - mpGlyphAdvances[i];
+ mpGlyphAdvances[i] = mnNotdefWidth;
+ if( mpGlyphOrigAdvs )
+ mpGlyphOrigAdvs[i] = mnNotdefWidth;
+ }
+
+#ifdef GCP_KERN_HACK
+ // apply kerning if the layout engine has not yet done it
+ if( rArgs.mnFlags & (SAL_LAYOUT_KERNING_ASIAN|SAL_LAYOUT_KERNING_PAIRS) )
+ {
+#else // GCP_KERN_HACK
+ // apply just asian kerning
+ if( rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN )
+ {
+ if( !(rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS) )
+#endif // GCP_KERN_HACK
+ for( i = 0; i < mnGlyphCount; ++i )
+ mpGlyphOrigAdvs[i] = mpGlyphAdvances[i];
+
+ // #99658# also apply asian kerning on the substring border
+ int nLen = mnGlyphCount;
+ if( rArgs.mnMinCharPos + nLen < rArgs.mnLength )
+ ++nLen;
+ for( i = 1; i < nLen; ++i )
+ {
+#ifdef GCP_KERN_HACK
+ if( rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS )
+ {
+ int nKernAmount = mrOs2FontEntry.GetKerning( pBidiStr[i-1], pBidiStr[i] );
+ mpGlyphAdvances[ i-1 ] += nKernAmount;
+ mnWidth += nKernAmount;
+ }
+ else if( rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN )
+#endif // GCP_KERN_HACK
+
+ if( (0x3000 == (0xFF00 & pBidiStr[i-1]))
+ && (0x3000 == (0xFF00 & pBidiStr[i])) )
+ {
+ long nKernFirst = +CalcAsianKerning( pBidiStr[i-1], true, bVertical );
+ long nKernNext = -CalcAsianKerning( pBidiStr[i], false, bVertical );
+
+ long nDelta = (nKernFirst < nKernNext) ? nKernFirst : nKernNext;
+ if( nDelta<0 && nKernFirst!=0 && nKernNext!=0 )
+ {
+ nDelta = (nDelta * mpGlyphAdvances[i-1] + 2) / 4;
+ mpGlyphAdvances[i-1] += nDelta;
+ mnWidth += nDelta;
+ }
+ }
+ }
+ }
+
+ // calculate virtual char widths
+ if( !mpGlyphs2Chars )
+ mpCharWidths = mpGlyphAdvances;
+ else
+ {
+ mpCharWidths = new int[ mnCharCount ];
+ for( i = 0; i < mnCharCount; ++i )
+ mpCharWidths[ i ] = 0;
+ for( i = 0; i < mnGlyphCount; ++i )
+ {
+ int j = mpGlyphs2Chars[ i ] - rArgs.mnMinCharPos;
+ if( j >= 0 )
+ mpCharWidths[ j ] += mpGlyphAdvances[ i ];
+ }
+ }
+
+ // scale layout metrics if needed
+ if( mfFontScale != 1.0 )
+ {
+ mnWidth *= mfFontScale;
+ mnBaseAdv *= mfFontScale;
+ for( i = 0; i < mnCharCount; ++i )
+ mpCharWidths[ i ] *= mfFontScale;
+ if( mpGlyphAdvances != mpCharWidths )
+ for( i = 0; i < mnGlyphCount; ++i )
+ mpGlyphAdvances[ i ] *= mfFontScale;
+ if( mpGlyphOrigAdvs && (mpGlyphOrigAdvs != mpGlyphAdvances) )
+ for( i = 0; i < mnGlyphCount; ++i )
+ mpGlyphOrigAdvs[ i ] *= mfFontScale;
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+int Os2SalLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, int& nStart,
+ sal_Int32* pGlyphAdvances, int* pCharIndexes ) const
+{
+ // return zero if no more glyph found
+ if( nStart >= mnGlyphCount )
+ return 0;
+
+ // calculate glyph position relative to layout base
+ // TODO: avoid for nStart!=0 case by reusing rPos
+ long nXOffset = mnBaseAdv;
+ for( int i = 0; i < nStart; ++i )
+ nXOffset += mpGlyphAdvances[ i ];
+
+ // calculate absolute position in pixel units
+ Point aRelativePos( nXOffset, 0 );
+ rPos = GetDrawPosition( aRelativePos );
+
+ int nCount = 0;
+ while( nCount < nLen )
+ {
+ // update return values {nGlyphIndex,nCharPos,nGlyphAdvance}
+ long nGlyphIndex = mpOutGlyphs[ nStart ];
+ if( mbDisableGlyphs )
+ {
+ if( mnLayoutFlags & SAL_LAYOUT_VERTICAL )
+ {
+ sal_Unicode cChar = (sal_Unicode)(nGlyphIndex & GF_IDXMASK);
+#ifdef GNG_VERT_HACK
+ if( mrOs2FontData.HasGSUBstitutions( mhPS )
+ && mrOs2FontData.IsGSUBstituted( cChar ) )
+ nGlyphIndex |= GF_ROTL | GF_GSUB;
+ else
+#endif // GNG_VERT_HACK
+ {
+ nGlyphIndex |= GetVerticalFlags( cChar );
+ if( !(nGlyphIndex & GF_ROTMASK) )
+ nGlyphIndex |= GF_VERT;
+ }
+ }
+ nGlyphIndex |= GF_ISCHAR;
+ }
+ ++nCount;
+ *(pGlyphs++) = nGlyphIndex;
+ if( pGlyphAdvances )
+ *(pGlyphAdvances++) = mpGlyphAdvances[ nStart ];
+ if( pCharIndexes )
+ {
+ int nCharPos;
+ if( !mpGlyphs2Chars )
+ nCharPos = nStart + mnMinCharPos;
+ else
+ nCharPos = mpGlyphs2Chars[nStart];
+ *(pCharIndexes++) = nCharPos;
+ }
+
+ // stop at last glyph
+ if( ++nStart >= mnGlyphCount )
+ break;
+
+ // stop when next x-position is unexpected
+ if( !pGlyphAdvances && mpGlyphOrigAdvs )
+ if( mpGlyphAdvances[nStart-1] != mpGlyphOrigAdvs[nStart-1] )
+ break;
+ }
+
+ return nCount;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalLayout::DrawText( SalGraphics& rGraphics ) const
+{
+ if( mnGlyphCount <= 0 )
+ return;
+
+ Point aPos = GetDrawPosition( Point( mnBaseAdv, 0 ) );
+ POINTL aPt;
+ APIRET rc;
+
+ aPt.x = aPos.X();
+ aPt.y = static_cast<Os2SalGraphics&>(rGraphics).mnHeight - aPos.Y();
+
+ // ft2lib doesn't work with printer hps, so we fallback to codepage printing
+ // until cp1200 support will work.
+ if (static_cast<Os2SalGraphics&>(rGraphics).mbPrinter) {
+ // convert to codepage
+ ByteString str( mpOutGlyphs, gsl_getSystemTextEncoding() );
+ // gliph size is not recalculated, so it could be wrong!
+ rc = Ft2CharStringPosAtA( static_cast<Os2SalGraphics&>(rGraphics).mhPS,
+ &aPt, NULL, CHS_VECTOR, mnGlyphCount, (PSZ)str.GetBuffer(),
+ (LONG*)mpGlyphAdvances, 0);
+ } else {
+ // try unicode rendering to screen
+ rc = Ft2CharStringPosAtW( static_cast<Os2SalGraphics&>(rGraphics).mhPS,
+ &aPt, NULL, CHS_VECTOR, mnGlyphCount, (LPWSTR)mpOutGlyphs,
+ (LONG*)mpGlyphAdvances, 0);
+ if (rc == GPI_ERROR) {
+ // if *W fails, convert to codepage and use *A (fallback to GPI into ft2)
+ ByteString str( mpOutGlyphs, gsl_getSystemTextEncoding() );
+#if OSL_DEBUG_LEVEL>10
+ debug_printf("Os2SalLayout::DrawText HPS %08x PosAtW failed '%s'!\n",static_cast<Os2SalGraphics&>(rGraphics).mhPS,str.GetBuffer());
+#endif
+ // gliph size is not recalculated, so it could be wrong!
+ rc = Ft2CharStringPosAtA( static_cast<Os2SalGraphics&>(rGraphics).mhPS,
+ &aPt, NULL, CHS_VECTOR, mnGlyphCount, (PSZ)str.GetBuffer(),
+ (LONG*)mpGlyphAdvances, 0);
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+long Os2SalLayout::FillDXArray( long* pDXArray ) const
+{
+ if( !mnWidth )
+ {
+ long mnWidth = mnBaseAdv;
+ for( int i = 0; i < mnGlyphCount; ++i )
+ mnWidth += mpGlyphAdvances[ i ];
+ }
+
+ if( pDXArray != NULL )
+ {
+ for( int i = 0; i < mnCharCount; ++i )
+ pDXArray[ i ] = mpCharWidths[ i ];
+ }
+
+ return mnWidth;
+}
+
+// -----------------------------------------------------------------------
+
+int Os2SalLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const
+// NOTE: the nFactor is used to prevent rounding errors for small nCharExtra values
+{
+ if( mnWidth )
+ if( (mnWidth * nFactor + mnCharCount * nCharExtra) <= nMaxWidth )
+ return STRING_LEN;
+
+ long nExtraWidth = mnBaseAdv * nFactor;
+ for( int n = 0; n < mnCharCount; ++n )
+ {
+ // skip unused characters
+ if( mpChars2Glyphs && (mpChars2Glyphs[n] < 0) )
+ continue;
+ // add char widths until max
+ nExtraWidth += mpCharWidths[ n ] * nFactor;
+ if( nExtraWidth >= nMaxWidth )
+ return (mnMinCharPos + n);
+ nExtraWidth += nCharExtra;
+ }
+
+ return STRING_LEN;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalLayout::GetCaretPositions( int nMaxIdx, long* pCaretXArray ) const
+{
+ long nXPos = mnBaseAdv;
+
+ if( !mpGlyphs2Chars )
+ {
+ for( int i = 0; i < nMaxIdx; i += 2 )
+ {
+ pCaretXArray[ i ] = nXPos;
+ nXPos += mpGlyphAdvances[ i>>1 ];
+ pCaretXArray[ i+1 ] = nXPos;
+ }
+ }
+ else
+ {
+ int i;
+ for( i = 0; i < nMaxIdx; ++i )
+ pCaretXArray[ i ] = -1;
+
+ // assign glyph positions to character positions
+ for( i = 0; i < mnGlyphCount; ++i )
+ {
+ int nCurrIdx = mpGlyphs2Chars[ i ] - mnMinCharPos;
+ long nXRight = nXPos + mpCharWidths[ nCurrIdx ];
+ nCurrIdx *= 2;
+ if( !(mpGlyphRTLFlags && mpGlyphRTLFlags[i]) )
+ {
+ // 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;
+ }
+ nXPos += mpGlyphAdvances[ i ];
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalLayout::Justify( long nNewWidth )
+{
+ long nOldWidth = mnWidth;
+ mnWidth = nNewWidth;
+
+ if( mnGlyphCount <= 0 )
+ return;
+
+ if( nNewWidth == nOldWidth )
+ return;
+
+ // the rightmost glyph cannot be stretched
+ const int nRight = mnGlyphCount - 1;
+ nOldWidth -= mpGlyphAdvances[ nRight ];
+ nNewWidth -= mpGlyphAdvances[ nRight ];
+
+ // count stretchable glyphs
+ int nStretchable = 0, i;
+ for( i = 0; i < nRight; ++i )
+ if( mpGlyphAdvances[i] >= 0 )
+ ++nStretchable;
+
+ // stretch these glyphs
+ int nDiffWidth = nNewWidth - nOldWidth;
+ for( i = 0; (i < nRight) && (nStretchable > 0); ++i )
+ {
+ if( mpGlyphAdvances[i] <= 0 )
+ continue;
+ int nDeltaWidth = nDiffWidth / nStretchable;
+ mpGlyphAdvances[i] += nDeltaWidth;
+ --nStretchable;
+ nDiffWidth -= nDeltaWidth;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalLayout::AdjustLayout( ImplLayoutArgs& rArgs )
+{
+ SalLayout::AdjustLayout( rArgs );
+
+ // adjust positions if requested
+ if( rArgs.mpDXArray )
+ ApplyDXArray( rArgs );
+ else if( rArgs.mnLayoutWidth )
+ Justify( rArgs.mnLayoutWidth );
+ else
+ return;
+
+ // recalculate virtual char widths if they were changed
+ if( mpCharWidths != mpGlyphAdvances )
+ {
+ int i;
+ if( !mpGlyphs2Chars )
+ {
+ // standard LTR case
+ for( i = 0; i < mnGlyphCount; ++i )
+ mpCharWidths[ i ] = mpGlyphAdvances[ i ];
+ }
+ else
+ {
+ // BiDi or complex case
+ for( i = 0; i < mnCharCount; ++i )
+ mpCharWidths[ i ] = 0;
+ for( i = 0; i < mnGlyphCount; ++i )
+ {
+ int j = mpGlyphs2Chars[ i ] - rArgs.mnMinCharPos;
+ if( j >= 0 )
+ mpCharWidths[ j ] += mpGlyphAdvances[ i ];
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalLayout::ApplyDXArray( const ImplLayoutArgs& rArgs )
+{
+ // try to avoid disturbance of text flow for LSB rounding case;
+ const long* pDXArray = rArgs.mpDXArray;
+
+ int i = 0;
+ long nOldWidth = mnBaseAdv;
+ for(; i < mnCharCount; ++i )
+ {
+ int j = !mpChars2Glyphs ? i : mpChars2Glyphs[i];
+ if( j >= 0 )
+ {
+ nOldWidth += mpGlyphAdvances[ j ];
+ int nDiff = nOldWidth - pDXArray[ i ];
+
+ // disabled because of #104768#
+ // works great for static text, but problems when typing
+ // if( nDiff>+1 || nDiff<-1 )
+ // only bother with changing anything when something moved
+ if( nDiff != 0 )
+ break;
+ }
+ }
+ if( i >= mnCharCount )
+ return;
+
+ if( !mpGlyphOrigAdvs )
+ {
+ mpGlyphOrigAdvs = new int[ mnGlyphCount ];
+ for( i = 0; i < mnGlyphCount; ++i )
+ mpGlyphOrigAdvs[ i ] = mpGlyphAdvances[ i ];
+ }
+
+ mnWidth = mnBaseAdv;
+ for( i = 0; i < mnCharCount; ++i )
+ {
+ int j = !mpChars2Glyphs ? i : mpChars2Glyphs[i];
+ if( j >= 0 )
+ mpGlyphAdvances[j] = pDXArray[i] - mnWidth;
+ mnWidth = pDXArray[i];
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalLayout::MoveGlyph( int nStart, long nNewXPos )
+{
+ if( nStart > mnGlyphCount )
+ return;
+
+ // calculate the current x-position of the requested glyph
+ // TODO: cache absolute positions
+ int nXPos = mnBaseAdv;
+ for( int i = 0; i < nStart; ++i )
+ nXPos += mpGlyphAdvances[i];
+
+ // calculate the difference to the current glyph position
+ int nDelta = nNewXPos - nXPos;
+
+ // adjust the width of the layout if it was already cached
+ if( mnWidth )
+ mnWidth += nDelta;
+
+ // depending on whether the requested glyph is leftmost in the layout
+ // adjust either the layout's or the requested glyph's relative position
+ if( nStart > 0 )
+ mpGlyphAdvances[ nStart-1 ] += nDelta;
+ else
+ mnBaseAdv += nDelta;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalLayout::DropGlyph( int nStart )
+{
+ mpOutGlyphs[ nStart ] = DROPPED_OUTGLYPH;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalLayout::Simplify( bool bIsBase )
+{
+ // return early if no glyph has been dropped
+ int i = mnGlyphCount;
+ while( (--i >= 0) && (mpOutGlyphs[ i ] != DROPPED_OUTGLYPH) );
+ if( i < 0 )
+ return;
+
+ // convert the layout to a sparse layout if it is not already
+ if( !mpGlyphs2Chars )
+ {
+ mpGlyphs2Chars = new int[ mnGlyphCount ];
+ mpCharWidths = new int[ mnCharCount ];
+ // assertion: mnGlyphCount == mnCharCount
+ for( int k = 0; k < mnGlyphCount; ++k )
+ {
+ mpGlyphs2Chars[ k ] = mnMinCharPos + k;
+ mpCharWidths[ k ] = mpGlyphAdvances[ k ];
+ }
+ }
+
+ // remove dropped glyphs that are rightmost in the layout
+ for( i = mnGlyphCount; --i >= 0; )
+ {
+ if( mpOutGlyphs[ i ] != DROPPED_OUTGLYPH )
+ break;
+ if( mnWidth )
+ mnWidth -= mpGlyphAdvances[ i ];
+ int nRelCharPos = mpGlyphs2Chars[ i ] - mnMinCharPos;
+ if( nRelCharPos >= 0 )
+ mpCharWidths[ nRelCharPos ] = 0;
+ }
+ mnGlyphCount = i + 1;
+
+ // keep original glyph widths around
+ if( !mpGlyphOrigAdvs )
+ {
+ mpGlyphOrigAdvs = new int[ mnGlyphCount ];
+ for( int k = 0; k < mnGlyphCount; ++k )
+ mpGlyphOrigAdvs[ k ] = mpGlyphAdvances[ k ];
+ }
+
+ // remove dropped glyphs inside the layout
+ int nNewGC = 0;
+ for( i = 0; i < mnGlyphCount; ++i )
+ {
+ if( mpOutGlyphs[ i ] == DROPPED_OUTGLYPH )
+ {
+ // adjust relative position to last valid glyph
+ int nDroppedWidth = mpGlyphAdvances[ i ];
+ mpGlyphAdvances[ i ] = 0;
+ if( nNewGC > 0 )
+ mpGlyphAdvances[ nNewGC-1 ] += nDroppedWidth;
+ else
+ mnBaseAdv += nDroppedWidth;
+
+ // zero the virtual char width for the char that has a fallback
+ int nRelCharPos = mpGlyphs2Chars[ i ] - mnMinCharPos;
+ if( nRelCharPos >= 0 )
+ mpCharWidths[ nRelCharPos ] = 0;
+ }
+ else
+ {
+ if( nNewGC != i )
+ {
+ // rearrange the glyph array to get rid of the dropped glyph
+ mpOutGlyphs[ nNewGC ] = mpOutGlyphs[ i ];
+ mpGlyphAdvances[ nNewGC ] = mpGlyphAdvances[ i ];
+ mpGlyphOrigAdvs[ nNewGC ] = mpGlyphOrigAdvs[ i ];
+ mpGlyphs2Chars[ nNewGC ] = mpGlyphs2Chars[ i ];
+ }
+ ++nNewGC;
+ }
+ }
+
+ mnGlyphCount = nNewGC;
+ if( mnGlyphCount <= 0 )
+ mnWidth = mnBaseAdv = 0;
+}
+
+// =======================================================================
+
+SalLayout* Os2SalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLevel )
+{
+ Os2SalLayout* pLayout = NULL;
+ DBG_ASSERT( mpOs2FontEntry[nFallbackLevel], "WinSalGraphics mpWinFontEntry==NULL");
+
+ const ImplOs2FontData& rFontFace = *mpOs2FontData[ nFallbackLevel ];
+ ImplOs2FontEntry& rFontInstance = *mpOs2FontEntry[ nFallbackLevel ];
+
+ {
+#ifdef GCP_KERN_HACK
+ if( (rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS) && !rFontInstance.HasKernData() )
+ {
+ // TODO: directly cache kerning info in the rFontInstance
+ // TODO: get rid of kerning methods+data in WinSalGraphics object
+ GetKernPairs( 0, NULL );
+ rFontInstance.SetKernData( mnFontKernPairCount, mpFontKernPairs );
+ }
+#endif // GCP_KERN_HACK
+
+ //BYTE eCharSet = ANSI_CHARSET;
+ //if( mpLogFont )
+ // eCharSet = mpLogFont->lfCharSet;
+ pLayout = new Os2SalLayout( mhPS, 0, rFontFace, rFontInstance );
+ }
+
+ if( mfFontScale != 1.0 )
+ pLayout->SetFontScale( mfFontScale );
+
+ return pLayout;
+}
+
+// =======================================================================
+
+ImplOs2FontEntry::ImplOs2FontEntry( ImplFontSelectData& rFSD )
+: ImplFontEntry( rFSD ),
+ maWidthMap( 512 )
+#ifdef GCP_KERN_HACK
+ ,mpKerningPairs( NULL )
+ ,mnKerningPairs( -1 )
+#endif // GCP_KERN_HACK
+{
+}
+
+// -----------------------------------------------------------------------
+
+ImplOs2FontEntry::~ImplOs2FontEntry()
+{
+#ifdef GCP_KERN_HACK
+ delete[] mpKerningPairs;
+#endif // GCP_KERN_HACK
+}
+
+// -----------------------------------------------------------------------
+
+#ifdef GCP_KERN_HACK
+bool ImplOs2FontEntry::HasKernData() const
+{
+ return (mnKerningPairs >= 0);
+}
+
+// -----------------------------------------------------------------------
+
+void ImplOs2FontEntry::SetKernData( int nPairCount, const KERNINGPAIRS* pPairData )
+{
+ mnKerningPairs = nPairCount;
+ mpKerningPairs = new KERNINGPAIRS[ mnKerningPairs ];
+ ::memcpy( mpKerningPairs, (const void*)pPairData, nPairCount*sizeof(KERNINGPAIRS) );
+}
+
+// -----------------------------------------------------------------------
+
+int ImplOs2FontEntry::GetKerning( sal_Unicode cLeft, sal_Unicode cRight ) const
+{
+ int nKernAmount = 0;
+ if( mpKerningPairs )
+ {
+ const KERNINGPAIRS aRefPair = { cLeft, cRight, 0 };
+ const KERNINGPAIRS* pFirstPair = mpKerningPairs;
+ const KERNINGPAIRS* pEndPair = mpKerningPairs + mnKerningPairs;
+ const KERNINGPAIRS* pPair = std::lower_bound( pFirstPair,
+ pEndPair, aRefPair, ImplCmpKernData );
+ if( (pPair != pEndPair)
+ && (pPair->sFirstChar == aRefPair.sFirstChar)
+ && (pPair->sSecondChar == aRefPair.sSecondChar) )
+ nKernAmount = pPair->lKerningAmount;
+ }
+
+ return nKernAmount;
+}
+#endif // GCP_KERN_HACK
+
+// =======================================================================
+
+ImplFontData* ImplOs2FontData::Clone() const
+{
+ if( mpUnicodeMap )
+ mpUnicodeMap->AddReference();
+ ImplFontData* pClone = new ImplOs2FontData( *this );
+ return pClone;
+}
+
+// -----------------------------------------------------------------------
+
+ImplFontEntry* ImplOs2FontData::CreateFontInstance( ImplFontSelectData& rFSD ) const
+{
+ //debug_printf("ImplOs2FontData::CreateFontInstance\n");
+ ImplFontEntry* pEntry = new ImplOs2FontEntry( rFSD );
+ return pEntry;
+}
+
+// =======================================================================
+
diff --git a/vcl/os2/source/gdi/salbmp.cxx b/vcl/os2/source/gdi/salbmp.cxx
new file mode 100644
index 000000000000..3d8f86ddcd1e
--- /dev/null
+++ b/vcl/os2/source/gdi/salbmp.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.
+ *
+ ************************************************************************/
+
+#include <svpm.h>
+
+#define _SV_SALBMP_CXX
+#include <rtl/alloc.h>
+#include <vcl/salbtype.hxx>
+#include <salgdi.h>
+#include <saldata.hxx>
+#include <salbmp.h>
+#include <vcl/bitmap.hxx> // for BitmapSystemData
+#include <string.h>
+
+#ifndef __H_FT2LIB
+#include <wingdi.h>
+#include <ft2lib.h>
+#endif
+
+// -----------
+// - Inlines -
+// -----------
+
+inline void ImplSetPixel4( const HPBYTE pScanline, long nX, const BYTE cIndex )
+{
+ BYTE& rByte = pScanline[ nX >> 1 ];
+
+ ( nX & 1 ) ? ( rByte &= 0xf0, rByte |= ( cIndex & 0x0f ) ) :
+ ( rByte &= 0x0f, rByte |= ( cIndex << 4 ) );
+}
+
+// -------------
+// - Os2SalBitmap -
+// -------------
+
+Os2SalBitmap::Os2SalBitmap() :
+ mhDIB ( 0 ),
+ mhDIB1Subst ( 0 ),
+ mhDDB ( 0 ),
+ mnBitCount ( 0 )
+{
+}
+
+// ------------------------------------------------------------------
+
+Os2SalBitmap::~Os2SalBitmap()
+{
+ Destroy();
+}
+
+// ------------------------------------------------------------------
+
+bool Os2SalBitmap::Create( HANDLE hBitmap, bool bDIB, bool bCopyHandle )
+{
+ BOOL bRet = TRUE;
+
+ if( bDIB )
+ mhDIB = (HANDLE) ( bCopyHandle ? ImplCopyDIBOrDDB( hBitmap, TRUE ) : hBitmap );
+ else
+ mhDDB = (HBITMAP) ( bCopyHandle ? ImplCopyDIBOrDDB( hBitmap, FALSE ) : hBitmap );
+
+ if( mhDIB )
+ {
+ // bitmap-header is the beginning of memory block
+ PBITMAPINFOHEADER2 pBIH = (PBITMAPINFOHEADER2) mhDIB;
+
+ maSize = Size( pBIH->cx, pBIH->cy );
+ mnBitCount = pBIH->cBitCount;
+
+ if( mnBitCount )
+ mnBitCount = ( mnBitCount <= 1 ) ? 1 : ( mnBitCount <= 4 ) ? 4 : ( mnBitCount <= 8 ) ? 8 : 24;
+ }
+ else if( mhDDB )
+ {
+ BITMAPINFOHEADER2 aDDBInfoHeader;
+
+ aDDBInfoHeader.cbFix = sizeof( aDDBInfoHeader );
+
+ if( GpiQueryBitmapInfoHeader( mhDDB, &aDDBInfoHeader ) )
+ {
+ maSize = Size( aDDBInfoHeader.cx, aDDBInfoHeader.cy );
+ mnBitCount = aDDBInfoHeader.cPlanes * aDDBInfoHeader.cBitCount;
+
+ if( mnBitCount )
+ {
+ mnBitCount = ( mnBitCount <= 1 ) ? 1 :
+ ( mnBitCount <= 4 ) ? 4 :
+ ( mnBitCount <= 8 ) ? 8 : 24;
+ }
+ }
+ else
+ {
+ mhDDB = 0;
+ bRet = FALSE;
+ }
+
+ }
+ else
+ bRet = FALSE;
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+bool Os2SalBitmap::Create( const Size& rSize, USHORT nBitCount, const BitmapPalette& rPal )
+{
+ bool bRet = FALSE;
+
+ mhDIB = ImplCreateDIB( rSize, nBitCount, rPal );
+
+ if( mhDIB )
+ {
+ maSize = rSize;
+ mnBitCount = nBitCount;
+ bRet = TRUE;
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+bool Os2SalBitmap::Create( const SalBitmap& rSSalBitmap )
+{
+ bool bRet = FALSE;
+ const Os2SalBitmap& rSalBitmap = static_cast<const Os2SalBitmap&>(rSSalBitmap);
+
+ if ( rSalBitmap.mhDIB || rSalBitmap.mhDDB )
+ {
+ HANDLE hNewHdl = ImplCopyDIBOrDDB( rSalBitmap.mhDIB ? rSalBitmap.mhDIB : rSalBitmap.mhDDB,
+ rSalBitmap.mhDIB != 0 );
+
+ if( hNewHdl )
+ {
+ if( rSalBitmap.mhDIB )
+ mhDIB = (HANDLE) hNewHdl;
+ else if( rSalBitmap.mhDDB )
+ mhDDB = (HBITMAP) hNewHdl;
+
+ maSize = rSalBitmap.maSize;
+ mnBitCount = rSalBitmap.mnBitCount;
+ bRet = TRUE;
+ }
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+bool Os2SalBitmap::Create( const SalBitmap& rSSalBmp, SalGraphics* pSGraphics )
+{
+ bool bRet = FALSE;
+ const Os2SalBitmap& rSalBmp = static_cast<const Os2SalBitmap&>(rSSalBmp);
+ Os2SalGraphics* pGraphics = static_cast<Os2SalGraphics*>(pSGraphics);
+
+ if( rSalBmp.mhDIB )
+ {
+ HPS hPS = pGraphics->mhPS;
+ HBITMAP hNewDDB;
+ BITMAPINFOHEADER2 aInfoHeader;
+ const Size aSize( rSalBmp.GetSize() );
+ long nFormat[ 2 ];
+
+ memset( &aInfoHeader, 0, sizeof( aInfoHeader ) );
+ aInfoHeader.cbFix = 16;
+ aInfoHeader.cx = aSize.Width();
+ aInfoHeader.cy = aSize.Height();
+
+ GpiQueryDeviceBitmapFormats( hPS, 2L, (PLONG) &nFormat );
+ aInfoHeader.cPlanes = nFormat[ 0 ];
+ aInfoHeader.cBitCount = nFormat[ 1 ];
+
+ // ! wegen Postscript-Treiber
+ if( !aInfoHeader.cBitCount )
+ aInfoHeader.cBitCount = 24;
+ else if( ( aInfoHeader.cPlanes == 1 ) && ( aInfoHeader.cBitCount == 1 ) )
+ aInfoHeader.cBitCount = 4;
+
+ // BitCount == 1 ist wegen aller moeglichen Treiberfehler nicht moeglich
+ if( rSalBmp.GetBitCount() == 1 )
+ {
+ HANDLE hTmp = ImplCreateDIB4FromDIB1( rSalBmp.mhDIB );
+ PBYTE pBits = (PBYTE) hTmp + *(ULONG*) hTmp + ImplGetDIBColorCount( hTmp ) * sizeof( RGB2 );
+
+ hNewDDB = GpiCreateBitmap( hPS, &aInfoHeader, CBM_INIT, pBits, (PBITMAPINFO2) hTmp );
+ rtl_freeMemory( (void*)hTmp );
+ }
+ else
+ {
+ PBYTE pBits = (PBYTE) rSalBmp.mhDIB + *(ULONG*) rSalBmp.mhDIB + ImplGetDIBColorCount( rSalBmp.mhDIB ) * sizeof( RGB2 );
+ hNewDDB = GpiCreateBitmap( hPS, &aInfoHeader, CBM_INIT, pBits, (PBITMAPINFO2) rSalBmp.mhDIB );
+ }
+
+ aInfoHeader.cbFix = sizeof( aInfoHeader );
+
+ if( hNewDDB && GpiQueryBitmapInfoHeader( hNewDDB, &aInfoHeader ) )
+ {
+ mhDDB = hNewDDB;
+ maSize = Size( aInfoHeader.cx, aInfoHeader.cy );
+ mnBitCount = aInfoHeader.cPlanes * aInfoHeader.cBitCount;
+
+ if( mnBitCount )
+ {
+ mnBitCount = ( mnBitCount <= 1 ) ? 1 :
+ ( mnBitCount <= 4 ) ? 4 :
+ ( mnBitCount <= 8 ) ? 8 : 24;
+ }
+
+ bRet = TRUE;
+ }
+ else if( hNewDDB )
+ GpiDeleteBitmap( hNewDDB );
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+bool Os2SalBitmap::Create( const SalBitmap& rSSalBmp, USHORT nNewBitCount )
+{
+ bool bRet = FALSE;
+ const Os2SalBitmap& rSalBmp = static_cast<const Os2SalBitmap&>(rSSalBmp);
+
+ if( rSalBmp.mhDDB )
+ {
+ mhDIB = ImplCreateDIB( rSalBmp.maSize, nNewBitCount, BitmapPalette() );
+
+ if( mhDIB )
+ {
+ // bitmap-header is the beginning of memory block
+ PBITMAPINFO2 pBI = (PBITMAPINFO2) mhDIB;
+ const int nLines = (int) rSalBmp.maSize.Height();
+ PBYTE pBits = (PBYTE) pBI + *(ULONG*) pBI + ImplGetDIBColorCount( mhDIB ) * sizeof( RGB2 );
+ SIZEL aSizeL = { rSalBmp.maSize.Width(), nLines };
+ HAB hAB = GetSalData()->mhAB;
+ DEVOPENSTRUC aDevOpenStruc = { NULL, (PSZ)"DISPLAY", NULL, NULL, NULL, NULL, NULL, NULL, NULL };
+ HDC hMemDC = DevOpenDC( hAB, OD_MEMORY, (PSZ)"*", 5L, (PDEVOPENDATA)&aDevOpenStruc, 0 );
+ HPS hMemPS = Ft2CreatePS( hAB, hMemDC, &aSizeL, GPIT_MICRO | GPIA_ASSOC | PU_PELS );
+ HBITMAP hMemOld = (HBITMAP) Ft2SetBitmap( hMemPS, rSalBmp.mhDDB );
+
+ if( GpiQueryBitmapBits( hMemPS, 0, nLines, pBits, pBI ) == nLines )
+ {
+ maSize = rSalBmp.maSize;
+ mnBitCount = nNewBitCount;
+ bRet = TRUE;
+ }
+ else
+ {
+ rtl_freeMemory( (void*)mhDIB );
+ mhDIB = 0;
+ }
+
+ Ft2SetBitmap( hMemPS, hMemOld );
+ Ft2DestroyPS( hMemPS );
+ DevCloseDC( hMemDC );
+ }
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+void Os2SalBitmap::Destroy()
+{
+ if( mhDIB )
+ rtl_freeMemory( (void*)mhDIB );
+ else if( mhDDB )
+ GpiDeleteBitmap( mhDDB );
+
+ if( mhDIB1Subst )
+ {
+ rtl_freeMemory( (void*)mhDIB1Subst );
+ mhDIB1Subst = NULL;
+ }
+
+ maSize = Size();
+ mnBitCount = 0;
+}
+
+// ------------------------------------------------------------------
+
+void Os2SalBitmap::ImplReplacehDIB1Subst( HANDLE hDIB1Subst )
+{
+ if( mhDIB1Subst )
+ rtl_freeMemory( (void*)mhDIB1Subst );
+
+ mhDIB1Subst = hDIB1Subst;
+}
+
+// ------------------------------------------------------------------
+
+USHORT Os2SalBitmap::ImplGetDIBColorCount( HANDLE hDIB )
+{
+ USHORT nColors = 0;
+
+ if( hDIB )
+ {
+ // bitmap infos can be found at the beginning of the memory
+ PBITMAPINFOHEADER2 pBIH = (PBITMAPINFOHEADER2) hDIB;
+
+ if( pBIH->cBitCount <= 8 )
+ {
+ if( pBIH->cclrUsed )
+ nColors = (USHORT) pBIH->cclrUsed;
+ else
+ nColors = 1 << pBIH->cBitCount;
+ }
+ }
+
+ return nColors;
+}
+
+// ------------------------------------------------------------------
+
+HANDLE Os2SalBitmap::ImplCreateDIB( const Size& rSize, USHORT nBits, const BitmapPalette& rPal )
+{
+ DBG_ASSERT( nBits == 1 || nBits == 4 || nBits == 8 || nBits == 24, "Unsupported BitCount!" );
+
+ HANDLE hDIB = 0;
+
+ if ( rSize.Width() && rSize.Height() && ( nBits == 1 || nBits == 4 || nBits == 8 || nBits == 24 ) )
+ {
+ const ULONG nImageSize = AlignedWidth4Bytes( nBits * rSize.Width() ) * rSize.Height();
+ const USHORT nColors = ( nBits <= 8 ) ? ( 1 << nBits ) : 0;
+
+ hDIB = (HANDLE) rtl_allocateZeroMemory( sizeof( BITMAPINFOHEADER2 ) + nColors * sizeof( RGB2 ) + nImageSize );
+
+ if( hDIB )
+ {
+ // bitmap infos can be found at the beginning of the memory
+ PBITMAPINFO2 pBI = (PBITMAPINFO2) hDIB;
+ PBITMAPINFOHEADER2 pBIH = (PBITMAPINFOHEADER2) pBI;
+
+ pBIH->cbFix = sizeof( BITMAPINFOHEADER2 );
+ pBIH->cx = rSize.Width();
+ pBIH->cy = rSize.Height();
+ pBIH->cPlanes = 1;
+ pBIH->cBitCount = nBits;
+ pBIH->ulCompression = BCA_UNCOMP; // BI_RGB;
+ pBIH->cbImage = nImageSize;
+ pBIH->cxResolution = 0;
+ pBIH->cyResolution = 0;
+ pBIH->cclrUsed = 0;
+ pBIH->cclrImportant = 0;
+
+ // Rest auf 0 setzen
+ memset( (PBYTE) &pBIH->usUnits, 0, (PBYTE) pBI->argbColor - (PBYTE) &pBIH->usUnits );
+
+ if( nColors )
+ {
+ const USHORT nMinCount = Min( nColors, rPal.GetEntryCount() );
+
+ if( nMinCount )
+ memcpy( pBI->argbColor, rPal.ImplGetColorBuffer(), nMinCount * sizeof( RGB2 ) );
+ }
+ }
+ }
+
+ return hDIB;
+}
+
+// ------------------------------------------------------------------
+
+HANDLE Os2SalBitmap::ImplCreateDIB4FromDIB1( HANDLE hDIB1 )
+{
+ PBITMAPINFO2 pBI = (PBITMAPINFO2) hDIB1;
+ PBITMAPINFOHEADER2 pBIH = (PBITMAPINFOHEADER2) pBI;
+ PBYTE pBits = (PBYTE) pBI + *(ULONG*) pBIH + Os2SalBitmap::ImplGetDIBColorCount( hDIB1 ) * sizeof( RGB2 );
+ ULONG nWidth = pBIH->cx, nHeight = pBIH->cy;
+ ULONG nAligned = AlignedWidth4Bytes( nWidth );
+ ULONG nAligned4 = AlignedWidth4Bytes( nWidth << 2 );
+ ULONG nSize4 = sizeof( BITMAPINFOHEADER2 ) + ( sizeof( RGB2 ) << 4 ) + nAligned4 * nHeight;
+ PBYTE pDIB4 = (PBYTE) rtl_allocateZeroMemory( nSize4 );
+ PBITMAPINFO2 pBI4 = (PBITMAPINFO2) pDIB4;
+ PBITMAPINFOHEADER2 pBIH4 = (PBITMAPINFOHEADER2) pBI4;
+ BYTE aMap[ 4 ] = { 0x00, 0x01, 0x10, 0x11 };
+
+ memset( pBIH4, 0, sizeof( BITMAPINFOHEADER2 ) );
+ pBIH4->cbFix = sizeof( BITMAPINFOHEADER2 );
+ pBIH4->cx = nWidth;
+ pBIH4->cy = nHeight;
+ pBIH4->cPlanes = 1;
+ pBIH4->cBitCount = 4;
+
+ // die ersten beiden Eintraege der 1Bit-Farbtabelle kopieren
+ memcpy( pBI4->argbColor, pBI->argbColor, sizeof( RGB2 ) << 1 );
+
+ PBYTE pBits4 = (PBYTE) pBI4 + *(ULONG*) pBIH4 + ( sizeof( RGB2 ) << 4 );
+
+ // 4Bit-DIB-Bilddaten setzen
+ for( ULONG nY = 0UL; nY < nHeight; nY++ )
+ {
+ PBYTE pTmp = pBits; pBits += nAligned;
+ PBYTE pTmp4 = pBits4; pBits4 += nAligned4;
+
+ for( ULONG nX = 0UL; nX < nWidth; nX += 8UL )
+ {
+ *pTmp4++ = aMap[ ( *pTmp >> 6 ) & 3 ];
+ *pTmp4++ = aMap[ ( *pTmp >> 4 ) & 3 ];
+ *pTmp4++ = aMap[ ( *pTmp >> 2 ) & 3 ];
+ *pTmp4++ = aMap[ *pTmp++ & 3 ];
+ }
+ }
+
+ return (HANDLE) pDIB4;
+}
+
+// ------------------------------------------------------------------
+
+HANDLE Os2SalBitmap::ImplCopyDIBOrDDB( HANDLE hHdl, BOOL bDIB )
+{
+ HANDLE hCopy = 0;
+
+ if( bDIB && hHdl )
+ {
+ PBITMAPINFOHEADER2 pBIH = (PBITMAPINFOHEADER2) hHdl;
+ const ULONG nSize = sizeof( BITMAPINFOHEADER2 )
+ + ImplGetDIBColorCount( hHdl ) * sizeof( RGB2 ) +
+ ( pBIH->cbImage ? pBIH->cbImage : AlignedWidth4Bytes( pBIH->cx * pBIH->cBitCount ) );
+
+ BYTE* pCopy = (BYTE*)rtl_allocateZeroMemory( nSize );
+ memcpy( pCopy, (BYTE*) hHdl, nSize );
+ hCopy = (HANDLE) pCopy;
+ }
+ else if( hHdl )
+ {
+ HAB hAB = GetSalData()->mhAB;
+ HDC hSrcMemDC;
+ HDC hDestMemDC;
+ HPS hSrcMemPS;
+ HPS hDestMemPS;
+ HBITMAP hCopyBitmap;
+ BITMAPINFOHEADER2 aInfoHeader;
+ DEVOPENSTRUC aDevOpenStruc;
+ SIZEL size;
+
+ aInfoHeader.cbFix = sizeof( BITMAPINFOHEADER2 );
+ GpiQueryBitmapInfoHeader( hHdl, &aInfoHeader );
+ size.cx = aInfoHeader.cx;
+ size.cy = aInfoHeader.cy;
+
+ // Memory DCs erzeugen
+ aDevOpenStruc.pszLogAddress = 0;
+ aDevOpenStruc.pszDriverName = (PSZ)"DISPLAY";
+
+ hSrcMemDC = DevOpenDC( hAB, OD_MEMORY, (PSZ)"*", 2, (PDEVOPENDATA)&aDevOpenStruc, 0 );
+ hDestMemDC = DevOpenDC( hAB, OD_MEMORY, (PSZ)"*", 2, (PDEVOPENDATA)&aDevOpenStruc, 0 );
+
+ // Memory PSs erzeugen
+ hSrcMemPS = Ft2CreatePS( hAB, hSrcMemDC, &size, GPIT_MICRO | GPIA_ASSOC | PU_PELS );
+ hDestMemPS = Ft2CreatePS( hAB, hDestMemDC, &size, GPIT_MICRO | GPIA_ASSOC | PU_PELS );
+
+ Ft2SetBitmap( hSrcMemPS, hHdl );
+
+ if( !hHdl )
+ {
+ memset( &aInfoHeader, 0, sizeof( BITMAPINFOHEADER2 ) );
+ aInfoHeader.cbFix = sizeof( BITMAPINFOHEADER2 );
+ aInfoHeader.cx = 0;
+ aInfoHeader.cy = 0;
+ aInfoHeader.cPlanes = 1;
+ aInfoHeader.cBitCount = 1;
+ }
+
+ hCopy = GpiCreateBitmap( hDestMemPS, &aInfoHeader, 0, NULL, NULL );
+ Ft2SetBitmap( hDestMemPS, hCopy );
+
+ POINTL pts[3];
+
+ pts[0].x = 0;
+ pts[0].y = 0;
+ pts[1].x = size.cx;
+ pts[1].y = size.cy;
+ pts[2].x = 0;
+ pts[2].y = 0;
+
+ GpiBitBlt( hDestMemPS, hSrcMemPS, 3, pts, ROP_SRCCOPY, BBO_IGNORE );
+
+ Ft2SetBitmap( hSrcMemPS, (HBITMAP)0L);
+ Ft2SetBitmap( hDestMemPS, (HBITMAP)0L);
+ Ft2Associate( hSrcMemPS, NULLHANDLE );
+ Ft2Associate( hDestMemPS, NULLHANDLE );
+ Ft2DestroyPS( hSrcMemPS );
+ Ft2DestroyPS( hDestMemPS );
+ DevCloseDC( hSrcMemDC );
+ DevCloseDC( hDestMemDC );
+ }
+
+ return hCopy;
+}
+
+// ------------------------------------------------------------------
+
+BitmapBuffer* Os2SalBitmap::AcquireBuffer( bool bReadOnly )
+{
+ BitmapBuffer* pBuffer = NULL;
+
+ if( mhDIB )
+ {
+ // bitmap infos can be found at the beginning of the memory
+ PBITMAPINFO2 pBI = (PBITMAPINFO2) mhDIB;
+ PBITMAPINFOHEADER2 pBIH = (PBITMAPINFOHEADER2) pBI;
+
+ if( ( pBIH->ulCompression == BCA_RLE4 ) || ( pBIH->ulCompression == BCA_RLE8 ) )
+ {
+ Size aSizePix( pBIH->cx, pBIH->cy );
+ HANDLE hNewDIB = ImplCreateDIB( aSizePix, pBIH->cBitCount, BitmapPalette() );
+
+ if( hNewDIB )
+ {
+ // bitmap infos can be found at the beginning of the memory
+ PBITMAPINFO2 pNewBI = (PBITMAPINFO2) hNewDIB;
+ PBITMAPINFOHEADER2 pNewBIH = (PBITMAPINFOHEADER2) pNewBI;
+ const USHORT nColorCount = ImplGetDIBColorCount( hNewDIB );
+ const ULONG nOffset = *(ULONG*) pBI + nColorCount * sizeof( RGB2 );
+ BYTE* pOldBits = (BYTE*) pBI + nOffset;
+ BYTE* pNewBits = (BYTE*) pNewBI + nOffset;
+
+ memcpy( pNewBI, pBI, nOffset );
+ pNewBIH->ulCompression = 0;
+ ImplDecodeRLEBuffer( pOldBits, pNewBits, aSizePix, pBIH->ulCompression == BCA_RLE4 );
+
+ rtl_freeMemory( (void*)mhDIB );
+
+ mhDIB = hNewDIB;
+ pBI = pNewBI;
+ pBIH = pNewBIH;
+ }
+ }
+
+ if( pBIH->cPlanes == 1 )
+ {
+ pBuffer = new BitmapBuffer;
+
+ pBuffer->mnFormat = BMP_FORMAT_BOTTOM_UP |
+ ( pBIH->cBitCount == 1 ? BMP_FORMAT_1BIT_MSB_PAL :
+ pBIH->cBitCount == 4 ? BMP_FORMAT_4BIT_MSN_PAL :
+ pBIH->cBitCount == 8 ? BMP_FORMAT_8BIT_PAL :
+ pBIH->cBitCount == 16 ? BMP_FORMAT_16BIT_TC_LSB_MASK :
+ pBIH->cBitCount == 24 ? BMP_FORMAT_24BIT_TC_BGR :
+ pBIH->cBitCount == 32 ? BMP_FORMAT_32BIT_TC_MASK : 0UL );
+
+ if( BMP_SCANLINE_FORMAT( pBuffer->mnFormat ) )
+ {
+ pBuffer->mnWidth = maSize.Width();
+ pBuffer->mnHeight = maSize.Height();
+ pBuffer->mnScanlineSize = AlignedWidth4Bytes( maSize.Width() * pBIH->cBitCount );
+ pBuffer->mnBitCount = (USHORT) pBIH->cBitCount;
+
+ if( pBuffer->mnBitCount <= 8 )
+ {
+ const USHORT nPalCount = ImplGetDIBColorCount( mhDIB );
+
+ pBuffer->maPalette.SetEntryCount( nPalCount );
+
+ if( nPalCount )
+ memcpy( pBuffer->maPalette.ImplGetColorBuffer(), pBI->argbColor, nPalCount * sizeof( RGB2 ) );
+
+ pBuffer->mpBits = (BYTE*) pBI + *(ULONG*) pBI + nPalCount * sizeof( RGB2 );
+ }
+ else
+ pBuffer->mpBits = (BYTE*) pBI + *(ULONG*) pBI;
+ }
+ else
+ {
+ delete pBuffer;
+ pBuffer = NULL;
+ }
+ }
+ }
+
+ if( pBuffer && mhDIB1Subst )
+ {
+ rtl_freeMemory( (void*)mhDIB1Subst );
+ mhDIB1Subst = 0;
+ }
+
+ return pBuffer;
+}
+
+// ------------------------------------------------------------------
+
+void Os2SalBitmap::ReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly )
+{
+ if( pBuffer )
+ {
+ if( mhDIB )
+ {
+ if( !bReadOnly && !!pBuffer->maPalette )
+ {
+ // bitmap infos can be found at the beginning of the memory
+ PBITMAPINFO2 pBI = (PBITMAPINFO2) mhDIB;
+ const USHORT nCount = pBuffer->maPalette.GetEntryCount();
+
+ if( nCount )
+ memcpy( pBI->argbColor, pBuffer->maPalette.ImplGetColorBuffer(), nCount * sizeof( RGB2 ) );
+ }
+ }
+
+ delete pBuffer;
+ }
+}
+
+// ------------------------------------------------------------------
+
+void Os2SalBitmap::ImplDecodeRLEBuffer( const BYTE* pSrcBuf, BYTE* pDstBuf,
+ const Size& rSizePixel, BOOL bRLE4 )
+{
+ HPBYTE pRLE = (HPBYTE) pSrcBuf;
+ HPBYTE pDIB = (HPBYTE) pDstBuf;
+ HPBYTE pRow = (HPBYTE) pDstBuf;
+ ULONG nWidthAl = AlignedWidth4Bytes( rSizePixel.Width() * ( bRLE4 ? 4UL : 8UL ) );
+ HPBYTE pLast = pDIB + rSizePixel.Height() * nWidthAl - 1;
+ ULONG nCountByte;
+ ULONG nRunByte;
+ ULONG nX = 0;
+ ULONG i;
+ BYTE cTmp;
+ BOOL bEndDecoding = FALSE;
+
+ if( pRLE && pDIB )
+ {
+ do
+ {
+ if( !( nCountByte = *pRLE++ ) )
+ {
+ nRunByte = *pRLE++;
+
+ if( nRunByte > 2UL )
+ {
+ if( bRLE4 )
+ {
+ nCountByte = nRunByte >> 1UL;
+
+ for( i = 0; i < nCountByte; i++ )
+ {
+ cTmp = *pRLE++;
+ ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
+ ImplSetPixel4( pDIB, nX++, cTmp & 0x0f );
+ }
+
+ if( nRunByte & 1 )
+ ImplSetPixel4( pDIB, nX++, *pRLE++ >> 4 );
+
+ if( ( ( nRunByte + 1 ) >> 1 ) & 1 )
+ pRLE++;
+ }
+ else
+ {
+ memcpy( &pDIB[ nX ], pRLE, nRunByte );
+ pRLE += nRunByte;
+ nX += nRunByte;
+
+ if( nRunByte & 1 )
+ pRLE++;
+ }
+ }
+ else if( !nRunByte )
+ {
+ pDIB = ( pRow += nWidthAl );
+ nX = 0UL;
+ }
+ else if( nRunByte == 1 )
+ bEndDecoding = TRUE;
+ else
+ {
+ nX += *pRLE++;
+ pDIB = ( pRow += ( *pRLE++ ) * nWidthAl );
+ }
+ }
+ else
+ {
+ cTmp = *pRLE++;
+
+ if( bRLE4 )
+ {
+ nRunByte = nCountByte >> 1;
+
+ for( i = 0; i < nRunByte; i++ )
+ {
+ ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
+ ImplSetPixel4( pDIB, nX++, cTmp & 0x0f );
+ }
+
+ if( nCountByte & 1 )
+ ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
+ }
+ else
+ {
+ for( i = 0; i < nCountByte; i++ )
+ pDIB[ nX++ ] = cTmp;
+ }
+ }
+ }
+ while( !bEndDecoding && ( pDIB <= pLast ) );
+ }
+}
+
+bool Os2SalBitmap::GetSystemData( BitmapSystemData& rData )
+{
+ bool bRet = false;
+ if( mhDIB || mhDDB )
+ {
+ bRet = true;
+ rData.pDIB = (void*)mhDIB;
+ rData.pDDB = (void*)mhDDB;
+ }
+ return bRet;
+}
diff --git a/vcl/os2/source/gdi/salgdi.cxx b/vcl/os2/source/gdi/salgdi.cxx
new file mode 100644
index 000000000000..dff1557170fb
--- /dev/null
+++ b/vcl/os2/source/gdi/salgdi.cxx
@@ -0,0 +1,1044 @@
+/*************************************************************************
+ *
+ * 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 <string.h>
+#include <svpm.h>
+
+#define _SV_SALGDI_CXX
+#include <tools/debug.hxx>
+#include <saldata.hxx>
+#include <salgdi.h>
+#include <tools/debug.hxx>
+#include <salframe.h>
+#include <tools/poly.hxx>
+#ifndef _RTL_STRINGBUF_HXX
+#include <rtl/strbuf.hxx>
+#endif
+
+#ifndef __H_FT2LIB
+#include <wingdi.h>
+#include <ft2lib.h>
+#endif
+
+// -----------
+// - Defines -
+// -----------
+
+// ClipRegions funktionieren immer noch nicht auf allen getesteten Druckern
+#define SAL_PRINTER_CLIPPATH 1
+// #define SAL_PRINTER_POLYPATH 1
+
+// =======================================================================
+
+void ImplInitSalGDI()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void ImplFreeSalGDI()
+{
+ SalData* pSalData = GetSalData();
+
+ // delete icon cache
+ SalIcon* pIcon = pSalData->mpFirstIcon;
+ while( pIcon )
+ {
+ SalIcon* pTmp = pIcon->pNext;
+ WinDestroyPointer( pIcon->hIcon );
+ delete pIcon;
+ pIcon = pTmp;
+ }
+
+}
+
+// =======================================================================
+
+void ImplSalInitGraphics( Os2SalGraphics* pData )
+{
+ GpiCreateLogColorTable( pData->mhPS, LCOL_RESET, LCOLF_RGB, 0, 0, NULL );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplSalDeInitGraphics( Os2SalGraphics* pData )
+{
+}
+
+// =======================================================================
+
+Os2SalGraphics::Os2SalGraphics()
+{
+ for( int i = 0; i < MAX_FALLBACK; ++i )
+ {
+ mhFonts[ i ] = 0;
+ mpOs2FontData[ i ] = NULL;
+ mpOs2FontEntry[ i ] = NULL;
+ }
+
+ mfFontScale = 1.0;
+
+ mhPS = 0;
+ mhDC = 0;
+ mbLine = FALSE;
+ mbFill = FALSE;
+ mbXORMode = FALSE;
+ mnFontMetricCount = 0;
+ mpFontMetrics = NULL;
+ mpClipRectlAry = NULL;
+
+ mhDefFont = 0;
+ mpFontKernPairs = NULL;
+ mnFontKernPairCount = 0;
+ mbFontKernInit = FALSE;
+
+}
+
+// -----------------------------------------------------------------------
+
+Os2SalGraphics::~Os2SalGraphics()
+{
+ Ft2DeleteSetId( mhPS, LCID_BASE);
+
+ if ( mpFontMetrics )
+ delete mpFontMetrics;
+
+ if ( mpFontKernPairs )
+ delete mpFontKernPairs;
+
+}
+
+// -----------------------------------------------------------------------
+
+static SalColor ImplGetROPSalColor( SalROPColor nROPColor )
+{
+ SalColor nSalColor;
+
+ switch( nROPColor )
+ {
+ case SAL_ROP_0:
+ nSalColor = MAKE_SALCOLOR( 0, 0, 0 );
+ break;
+
+ case SAL_ROP_1:
+ case SAL_ROP_INVERT:
+ nSalColor = MAKE_SALCOLOR( 255, 255, 255 );
+ break;
+ }
+
+ return nSalColor;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalGraphics::GetResolution( long& rDPIX, long& rDPIY )
+{
+ // since OOo asks for DPI, I will query FONT_RES, which seems to be
+ // more correct than _RESOLUTION fields (on my wide screen lcd)
+ // and does not require conversion
+ DevQueryCaps( mhDC, CAPS_HORIZONTAL_FONT_RES, 1, &rDPIX );
+ DevQueryCaps( mhDC, CAPS_VERTICAL_FONT_RES, 1, &rDPIY );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT Os2SalGraphics::GetBitCount()
+{
+ LONG nBitCount;
+ DevQueryCaps( mhDC, CAPS_COLOR_BITCOUNT, 1, &nBitCount );
+ return (USHORT)nBitCount;
+}
+
+// -----------------------------------------------------------------------
+
+long Os2SalGraphics::GetGraphicsWidth() const
+{
+ if( mhWnd )
+ {
+ Os2SalFrame* pFrame = (Os2SalFrame*)GetWindowPtr( mhWnd );
+ if( pFrame )
+ {
+ if( pFrame->maGeometry.nWidth )
+ return pFrame->maGeometry.nWidth;
+ else
+ {
+ // TODO: perhaps not needed, maGeometry should always be up-to-date
+ RECTL aRect;
+ WinQueryWindowRect( mhWnd, &aRect );
+ return aRect.xRight;
+ }
+ }
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalGraphics::ResetClipRegion()
+{
+#ifdef SAL_PRINTER_CLIPPATH
+ if ( mbPrinter )
+ GpiSetClipPath( mhPS, 0, SCP_RESET );
+ else
+#endif
+ {
+ HRGN hOldRegion;
+
+ GpiSetClipRegion( mhPS, NULL, &hOldRegion );
+ if ( hOldRegion )
+ GpiDestroyRegion( mhPS, hOldRegion );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalGraphics::BeginSetClipRegion( ULONG nCount )
+{
+ mpClipRectlAry = new RECTL[ nCount ];
+ mnClipElementCount = 0;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Os2SalGraphics::unionClipRegion( long nX, long nY, long nWidth, long nHeight )
+{
+ RECTL* pClipRect = &mpClipRectlAry[ mnClipElementCount ];
+ pClipRect->xLeft = nX;
+ pClipRect->yTop = mnHeight - nY;
+ pClipRect->xRight = nX + nWidth;
+ pClipRect->yBottom = mnHeight - (nY + nHeight);
+ mnClipElementCount++;
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+bool Os2SalGraphics::unionClipRegion( const ::basegfx::B2DPolyPolygon& )
+{
+ // TODO: implement and advertise OutDevSupport_B2DClip support
+ return false;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalGraphics::EndSetClipRegion()
+{
+#ifdef SAL_PRINTER_CLIPPATH
+ if ( mbPrinter )
+ {
+ GpiSetClipPath( mhPS, 0, SCP_RESET );
+ GpiBeginPath( mhPS, 1L );
+
+ for( int i = 0; i < mnClipElementCount; i++ )
+ {
+ POINTL aPt;
+ RECTL* pClipRect = &mpClipRectlAry[ i ];
+
+ aPt.x = pClipRect->xLeft;
+ aPt.y = pClipRect->yTop-1;
+ Ft2Move( mhPS, &aPt );
+
+ aPt.x = pClipRect->xRight-1;
+ aPt.y = pClipRect->yBottom;
+
+ Ft2Box( mhPS, DRO_OUTLINE, &aPt, 0, 0 );
+ }
+
+ GpiEndPath( mhPS );
+ GpiSetClipPath( mhPS, 1L, SCP_ALTERNATE | SCP_AND );
+ }
+ else
+#endif
+ {
+ HRGN hClipRegion = GpiCreateRegion( mhPS,
+ mnClipElementCount,
+ mpClipRectlAry );
+ HRGN hOldRegion;
+
+ GpiSetClipRegion( mhPS, hClipRegion, &hOldRegion );
+ if( hOldRegion )
+ GpiDestroyRegion( mhPS, hOldRegion );
+ }
+
+ delete [] mpClipRectlAry;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalGraphics::SetLineColor()
+{
+ // don't draw line!
+ mbLine = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalGraphics::SetLineColor( SalColor nSalColor )
+{
+ LINEBUNDLE lb;
+
+ // set color
+ lb.lColor = RGBCOLOR( SALCOLOR_RED( nSalColor ),
+ SALCOLOR_GREEN( nSalColor ),
+ SALCOLOR_BLUE( nSalColor ) );
+
+ Ft2SetAttrs( mhPS,
+ PRIM_LINE,
+ LBB_COLOR,
+ 0,
+ &lb );
+
+ // draw line!
+ mbLine = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalGraphics::SetFillColor()
+{
+ // don't fill area!
+ mbFill = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalGraphics::SetFillColor( SalColor nSalColor )
+{
+ AREABUNDLE ab;
+
+ // set color
+ ab.lColor = RGBCOLOR( SALCOLOR_RED( nSalColor ),
+ SALCOLOR_GREEN( nSalColor ),
+ SALCOLOR_BLUE( nSalColor ) );
+
+ Ft2SetAttrs( mhPS,
+ PRIM_AREA,
+ ABB_COLOR,
+ 0,
+ &ab );
+
+ // fill area!
+ mbFill = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalGraphics::SetXORMode( bool bSet, bool )
+{
+ mbXORMode = bSet;
+ LONG nMixMode = bSet ? FM_XOR : FM_OVERPAINT;
+
+ // set mix mode for lines
+ LINEBUNDLE lb;
+ lb.usMixMode = nMixMode;
+ Ft2SetAttrs( mhPS,
+ PRIM_LINE,
+ LBB_MIX_MODE,
+ 0,
+ &lb );
+
+ // set mix mode for areas
+ AREABUNDLE ab;
+ ab.usMixMode = nMixMode;
+ Ft2SetAttrs( mhPS,
+ PRIM_AREA,
+ ABB_MIX_MODE,
+ 0,
+ &ab );
+
+ // set mix mode for text
+ CHARBUNDLE cb;
+ cb.usMixMode = nMixMode;
+ Ft2SetAttrs( mhPS,
+ PRIM_CHAR,
+ CBB_MIX_MODE,
+ 0,
+ &cb );
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalGraphics::SetROPLineColor( SalROPColor nROPColor )
+{
+ SetLineColor( ImplGetROPSalColor( nROPColor ) );
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalGraphics::SetROPFillColor( SalROPColor nROPColor )
+{
+ SetFillColor( ImplGetROPSalColor( nROPColor ) );
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalGraphics::drawPixel( long nX, long nY )
+{
+ POINTL aPt;
+
+ aPt.x = nX;
+ aPt.y = TY( nY );
+
+ // set color
+ Ft2SetPel( mhPS, &aPt );
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalGraphics::drawPixel( long nX, long nY, SalColor nSalColor )
+{
+ // save old color
+ LINEBUNDLE oldLb;
+ GpiQueryAttrs( mhPS,
+ PRIM_LINE,
+ LBB_COLOR,
+ &oldLb );
+
+ // set new color
+ LINEBUNDLE lb;
+ lb.lColor = RGBCOLOR( SALCOLOR_RED( nSalColor ),
+ SALCOLOR_GREEN( nSalColor ),
+ SALCOLOR_BLUE( nSalColor ) );
+ Ft2SetAttrs( mhPS,
+ PRIM_LINE,
+ LBB_COLOR,
+ 0,
+ &lb );
+
+ // set color of pixel
+ POINTL aPt;
+ aPt.x = nX;
+ aPt.y = TY( nY );
+ Ft2SetPel( mhPS, &aPt );
+
+ // restore old color
+ Ft2SetAttrs( mhPS,
+ PRIM_LINE,
+ LBB_COLOR,
+ 0,
+ &oldLb );
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 )
+{
+ // OS2 zeichnet den Endpunkt mit
+ POINTL aPt;
+ aPt.x = nX1;
+ aPt.y = TY( nY1 );
+ Ft2Move( mhPS, &aPt );
+ aPt.x = nX2;
+ aPt.y = TY( nY2 );
+ GpiLine( mhPS, &aPt );
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalGraphics::drawRect( long nX, long nY, long nWidth, long nHeight )
+{
+ POINTL aPt;
+ long lControl;
+
+ if ( mbFill )
+ {
+ if ( mbLine )
+ lControl = DRO_OUTLINEFILL;
+ else
+ lControl = DRO_FILL;
+ }
+ else
+ {
+ if ( mbLine )
+ lControl = DRO_OUTLINE;
+ else
+ return;
+ }
+
+ aPt.x = nX;
+ aPt.y = TY( nY );
+ Ft2Move( mhPS, &aPt );
+ aPt.x = nX + nWidth - 1;
+ aPt.y = TY( nY + nHeight - 1 );
+ Ft2Box( mhPS, lControl, &aPt, 0, 0 );
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalGraphics::drawPolyLine( ULONG nPoints, const SalPoint* pPtAry )
+{
+ // convert all points to sys orientation
+ POINTL* pOS2PtAry = new POINTL[ nPoints ];
+ POINTL* pTempOS2PtAry = pOS2PtAry;
+ const SalPoint* pTempPtAry = pPtAry;
+ ULONG nTempPoints = nPoints;
+ long nHeight = mnHeight - 1;
+
+ while( nTempPoints-- )
+ {
+ (*pTempOS2PtAry).x = (*pTempPtAry).mnX;
+ (*pTempOS2PtAry).y = nHeight - (*pTempPtAry).mnY;
+ pTempOS2PtAry++;
+ pTempPtAry++;
+ }
+
+ Ft2Move( mhPS, pOS2PtAry );
+ GpiPolyLine( mhPS, nPoints, pOS2PtAry );
+ delete [] pOS2PtAry;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalGraphics::drawPolygon( ULONG nPoints, const SalPoint* pPtAry )
+{
+ PM_POLYGON aPolygon;
+
+ // create polygon
+ aPolygon.aPointl = new POINTL[ nPoints ];
+ aPolygon.ulPoints = nPoints;
+
+ // convert all points to sys orientation
+ POINTL* pTempOS2PtAry = aPolygon.aPointl;
+ const SalPoint* pTempPtAry = pPtAry;
+ ULONG nTempPoints = nPoints;
+ long nHeight = mnHeight - 1;
+
+ while( nTempPoints-- )
+ {
+ (*pTempOS2PtAry).x = (*pTempPtAry).mnX;
+ (*pTempOS2PtAry).y = nHeight - (*pTempPtAry).mnY;
+ pTempOS2PtAry++;
+ pTempPtAry++;
+ }
+
+ // Innenleben zeichnen
+ if ( mbFill )
+ {
+#ifdef SAL_PRINTER_POLYPATH
+ if ( mbPrinter )
+ {
+ Ft2BeginPath( mhPS, 1 );
+ Ft2Move( mhPS, aPolygon.aPointl );
+ Ft2PolyLine( mhPS, aPolygon.ulPoints, aPolygon.aPointl );
+ Ft2EndPath( mhPS );
+ Ft2FillPath( mhPS, 1, 0 );
+
+ if ( mbLine )
+ {
+ Ft2Move( mhPS, aPolygon.aPointl );
+ Ft2PolyLine( mhPS, aPolygon.ulPoints, aPolygon.aPointl );
+ }
+ }
+ else
+#endif
+ {
+ ULONG nOptions = POLYGON_ALTERNATE;
+
+ if ( mbLine )
+ nOptions |= POLYGON_BOUNDARY;
+ else
+ nOptions |= POLYGON_NOBOUNDARY;
+
+ Ft2Move( mhPS, aPolygon.aPointl );
+ GpiPolygons( mhPS, 1, &aPolygon, nOptions, POLYGON_EXCL );
+ }
+ }
+ else
+ {
+ if ( mbLine )
+ {
+ Ft2Move( mhPS, aPolygon.aPointl );
+ GpiPolyLine( mhPS, nPoints, aPolygon.aPointl );
+ }
+ }
+
+ delete [] aPolygon.aPointl;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalGraphics::drawPolyPolygon( ULONG nPoly, const ULONG* pPoints,
+ PCONSTSALPOINT* pPtAry )
+{
+ ULONG i;
+ long nHeight = mnHeight - 1;
+ PM_POLYGON* aPolygonAry = new PM_POLYGON[ nPoly ];
+
+ for( i = 0; i < nPoly; i++ )
+ {
+ const SalPoint * pTempPtAry = (const SalPoint*)pPtAry[ i ];
+
+ // create polygon
+ ULONG nTempPoints = pPoints[ i ];
+ POINTL * pTempOS2PtAry = new POINTL[ nTempPoints ];
+
+ // convert all points to sys orientation
+ aPolygonAry[ i ].ulPoints = nTempPoints;
+ aPolygonAry[ i ].aPointl = pTempOS2PtAry;
+
+ while( nTempPoints-- )
+ {
+ (*pTempOS2PtAry).x = (*pTempPtAry).mnX;
+ (*pTempOS2PtAry).y = nHeight - (*pTempPtAry).mnY;
+ pTempOS2PtAry++;
+ pTempPtAry++;
+ }
+ }
+
+ // Innenleben zeichnen
+ if ( mbFill )
+ {
+#ifdef SAL_PRINTER_POLYPATH
+ if ( mbPrinter )
+ {
+ Ft2BeginPath( mhPS, 1 );
+ for ( i = 0; i < nPoly; i++ )
+ {
+ Ft2Move( mhPS, aPolygonAry[i].aPointl );
+ Ft2PolyLine( mhPS, aPolygonAry[i].ulPoints, aPolygonAry[i].aPointl );
+ }
+ Ft2EndPath( mhPS );
+ Ft2FillPath( mhPS, 1, 0 );
+ }
+ else
+#endif
+ {
+ ULONG nOptions = POLYGON_ALTERNATE;
+
+ if ( mbLine )
+ nOptions |= POLYGON_BOUNDARY;
+ else
+ nOptions |= POLYGON_NOBOUNDARY;
+
+ Ft2Move( mhPS, aPolygonAry[ 0 ].aPointl );
+ GpiPolygons( mhPS, nPoly, aPolygonAry, nOptions, POLYGON_EXCL );
+ }
+ }
+ else
+ {
+ if ( mbLine )
+ {
+ for( i = 0; i < nPoly; i++ )
+ {
+ Ft2Move( mhPS, aPolygonAry[ i ].aPointl );
+ GpiPolyLine( mhPS, aPolygonAry[ i ].ulPoints, aPolygonAry[ i ].aPointl );
+ }
+ }
+ }
+
+ // cleanup
+ for( i = 0; i < nPoly; i++ )
+ delete [] aPolygonAry[ i ].aPointl;
+ delete [] aPolygonAry;
+}
+
+// -----------------------------------------------------------------------
+
+bool Os2SalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double /*fTransparency*/ )
+{
+ // TODO: implement and advertise OutDevSupport_B2DDraw support
+ return false;
+}
+
+// -----------------------------------------------------------------------
+
+bool Os2SalGraphics::drawPolyLine(
+ const basegfx::B2DPolygon& /*rPolygon*/,
+ double /*fTransparency*/,
+ const basegfx::B2DVector& /*rLineWidths*/,
+ basegfx::B2DLineJoin /*eLineJoin*/)
+{
+ // TODO: implement
+ return false;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool Os2SalGraphics::drawPolyLineBezier( ULONG nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry )
+{
+ return sal_False;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool Os2SalGraphics::drawPolygonBezier( ULONG nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry )
+{
+ return sal_False;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool Os2SalGraphics::drawPolyPolygonBezier( ULONG nPoly, const ULONG* pPoints,
+ const SalPoint* const* pPtAry, const BYTE* const* pFlgAry )
+{
+ return sal_False;
+}
+
+// =======================================================================
+
+// MAXIMUM BUFSIZE EQ 0xFFFF
+#define POSTSCRIPT_BUFSIZE 0x4000
+// we only try to get the BoundingBox in the first 4096 bytes
+#define POSTSCRIPT_BOUNDINGSEARCH 0x1000
+
+static BYTE* ImplSearchEntry( BYTE* pSource, BYTE* pDest, ULONG nComp, ULONG nSize )
+{
+ while ( nComp-- >= nSize )
+ {
+ ULONG i;
+ for ( i = 0; i < nSize; i++ )
+ {
+ if ( ( pSource[i]&~0x20 ) != ( pDest[i]&~0x20 ) )
+ break;
+ }
+ if ( i == nSize )
+ return pSource;
+ pSource++;
+ }
+ return NULL;
+}
+
+
+static BOOL ImplGetBoundingBox( double* nNumb, BYTE* pSource, ULONG nSize )
+{
+ BOOL bRetValue = FALSE;
+ BYTE* pDest = ImplSearchEntry( pSource, (BYTE*)"%%BoundingBox:", nSize, 14 );
+ if ( pDest )
+ {
+ nNumb[0] = nNumb[1] = nNumb[2] = nNumb[3] = 0;
+ pDest += 14;
+
+ int nSizeLeft = nSize - ( pDest - pSource );
+ if ( nSizeLeft > 100 )
+ nSizeLeft = 100; // only 100 bytes following the bounding box will be checked
+
+ int i;
+ for ( i = 0; ( i < 4 ) && nSizeLeft; i++ )
+ {
+ int nDivision = 1;
+ BOOL bDivision = FALSE;
+ BOOL bNegative = FALSE;
+ BOOL bValid = TRUE;
+
+ while ( ( --nSizeLeft ) && ( *pDest == ' ' ) || ( *pDest == 0x9 ) ) pDest++;
+ BYTE nByte = *pDest;
+ while ( nSizeLeft && ( nByte != ' ' ) && ( nByte != 0x9 ) && ( nByte != 0xd ) && ( nByte != 0xa ) )
+ {
+ switch ( nByte )
+ {
+ case '.' :
+ if ( bDivision )
+ bValid = FALSE;
+ else
+ bDivision = TRUE;
+ break;
+ case '-' :
+ bNegative = TRUE;
+ break;
+ default :
+ if ( ( nByte < '0' ) || ( nByte > '9' ) )
+ nSizeLeft = 1; // error parsing the bounding box values
+ else if ( bValid )
+ {
+ if ( bDivision )
+ nDivision*=10;
+ nNumb[i] *= 10;
+ nNumb[i] += nByte - '0';
+ }
+ break;
+ }
+ nSizeLeft--;
+ nByte = *(++pDest);
+ }
+ if ( bNegative )
+ nNumb[i] = -nNumb[i];
+ if ( bDivision && ( nDivision != 1 ) )
+ nNumb[i] /= nDivision;
+ }
+ if ( i == 4 )
+ bRetValue = TRUE;
+ }
+ return bRetValue;
+}
+
+#if 0
+static void ImplWriteDouble( BYTE** pBuf, double nNumber )
+{
+// *pBuf += sprintf( (char*)*pBuf, "%f", nNumber );
+
+ if ( nNumber < 0 )
+ {
+ *(*pBuf)++ = (BYTE)'-';
+ nNumber = -nNumber;
+ }
+ ULONG nTemp = (ULONG)nNumber;
+ const String aNumber1( nTemp );
+ ULONG nLen = aNumber1.Len();
+
+ for ( USHORT n = 0; n < nLen; n++ )
+ *(*pBuf)++ = aNumber1[ n ];
+
+ nTemp = (ULONG)( ( nNumber - nTemp ) * 100000 );
+ if ( nTemp )
+ {
+ *(*pBuf)++ = (BYTE)'.';
+ const String aNumber2( nTemp );
+
+ ULONG nLen = aNumber2.Len();
+ if ( nLen < 8 )
+ {
+ for ( n = 0; n < ( 5 - nLen ); n++ )
+ {
+ *(*pBuf)++ = (BYTE)'0';
+ }
+ }
+ for ( USHORT n = 0; n < nLen; n++ )
+ {
+ *(*pBuf)++ = aNumber2[ n ];
+ }
+ }
+ *(*pBuf)++ = ' ';
+}
+#endif
+
+inline void ImplWriteString( BYTE** pBuf, const char* sString )
+{
+ strcpy( (char*)*pBuf, sString );
+ *pBuf += strlen( sString );
+}
+
+BOOL Os2SalGraphics::drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, ULONG nSize )
+{
+ if ( !mbPrinter )
+ return FALSE;
+
+ BOOL bRet = FALSE;
+ LONG nLong = 0;
+ if ( !(DevQueryCaps( mhDC, CAPS_TECHNOLOGY, 1, &nLong ) &&
+ (CAPS_TECH_POSTSCRIPT == nLong)) )
+ return FALSE;
+
+ BYTE* pBuf = new BYTE[ POSTSCRIPT_BUFSIZE ];
+ double nBoundingBox[4];
+
+ if ( pBuf && ImplGetBoundingBox( nBoundingBox, (BYTE*)pPtr, nSize ) )
+ {
+ LONG pOS2DXAry[4]; // hack -> print always 2 white space
+ POINTL aPt;
+ aPt.x = 0;
+ aPt.y = 0;
+ PCH pStr = (PCH) " ";
+ for( long i = 0; i < 4; i++ )
+ pOS2DXAry[i] = i;
+ Ft2CharStringPosAt( mhPS, &aPt, NULL, 0, 2, (PCH)pStr,(PLONG)&pOS2DXAry[0] );
+
+ OStringBuffer aBuf( POSTSCRIPT_BUFSIZE );
+
+ // reserve place for a USHORT
+ aBuf.append( "aa" );
+
+ // #107797# Write out EPS encapsulation header
+ // ----------------------------------------------------------------------------------
+
+ // directly taken from the PLRM 3.0, p. 726. Note:
+ // this will definitely cause problems when
+ // recursively creating and embedding PostScript files
+ // in OOo, since we use statically-named variables
+ // here (namely, b4_Inc_state_salWin, dict_count_salWin and
+ // op_count_salWin). Currently, I have no idea on how to
+ // work around that, except from scanning and
+ // interpreting the EPS for unused identifiers.
+
+ // append the real text
+ aBuf.append( "\n\n/b4_Inc_state_salWin save def\n"
+ "/dict_count_salWin countdictstack def\n"
+ "/op_count_salWin count 1 sub def\n"
+ "userdict begin\n"
+ "/showpage {} def\n"
+ "0 setgray 0 setlinecap\n"
+ "1 setlinewidth 0 setlinejoin\n"
+ "10 setmiterlimit [] 0 setdash newpath\n"
+ "/languagelevel where\n"
+ "{\n"
+ " pop languagelevel\n"
+ " 1 ne\n"
+ " {\n"
+ " false setstrokeadjust false setoverprint\n"
+ " } if\n"
+ "} if\n\n" );
+
+#if 0
+ // #i10737# Apply clipping manually
+ // ----------------------------------------------------------------------------------
+
+ // Windows seems to ignore any clipping at the HDC,
+ // when followed by a POSTSCRIPT_PASSTHROUGH
+
+ // Check whether we've got a clipping, consisting of
+ // exactly one rect (other cases should be, but aren't
+ // handled currently)
+
+ // TODO: Handle more than one rectangle here (take
+ // care, the buffer can handle only POSTSCRIPT_BUFSIZE
+ // characters!)
+ if ( mhRegion != 0 &&
+ mpStdClipRgnData != NULL &&
+ mpClipRgnData == mpStdClipRgnData &&
+ mpClipRgnData->rdh.nCount == 1 )
+ {
+ RECT* pRect = &(mpClipRgnData->rdh.rcBound);
+
+ aBuf.append( "\nnewpath\n" );
+ aBuf.append( pRect->left );
+ aBuf.append( " " );
+ aBuf.append( pRect->top );
+ aBuf.append( " moveto\n" );
+ aBuf.append( pRect->right );
+ aBuf.append( " " );
+ aBuf.append( pRect->top );
+ aBuf.append( " lineto\n" );
+ aBuf.append( pRect->right );
+ aBuf.append( " " );
+ aBuf.append( pRect->bottom );
+ aBuf.append( " lineto\n" );
+ aBuf.append( pRect->left );
+ aBuf.append( " " );
+ aBuf.append( pRect->bottom );
+ aBuf.append( " lineto\n"
+ "closepath\n"
+ "clip\n"
+ "newpath\n" );
+ }
+#endif
+
+ // #107797# Write out buffer
+ // ----------------------------------------------------------------------------------
+ *((USHORT*)aBuf.getStr()) = (USHORT)( aBuf.getLength() - 2 );
+ //Escape ( mhDC, nEscape, aBuf.getLength(), (LPTSTR)aBuf.getStr(), 0 );
+ DevEscape( mhDC, DEVESC_RAWDATA, aBuf.getLength(),
+ (PBYTE)aBuf.getStr(), 0, NULL );
+
+ double dM11 = nWidth / ( nBoundingBox[2] - nBoundingBox[0] );
+ double dM22 = - ( nHeight / (nBoundingBox[1] - nBoundingBox[3] ) );
+
+ // reserve a USHORT again
+ aBuf.setLength( 2 );
+ aBuf.append( "\n\n[" );
+ aBuf.append( dM11 );
+ aBuf.append( " 0 0 " );
+ aBuf.append( dM22 );
+ aBuf.append( ' ' );
+ aBuf.append( nX - ( dM11 * nBoundingBox[0] ) );
+ aBuf.append( ' ' );
+ aBuf.append( nY - ( dM22 * nBoundingBox[3] ) );
+ aBuf.append( "] concat\n"
+ "%%BeginDocument:\n" );
+ *((USHORT*)aBuf.getStr()) = (USHORT)( aBuf.getLength() - 2 );
+ DevEscape( mhDC, DEVESC_RAWDATA, aBuf.getLength(),
+ (PBYTE)aBuf.getStr(), 0, NULL );
+#if 0
+ BYTE* pTemp = pBuf;
+ ImplWriteString( &pTemp, "save\n[ " );
+ ImplWriteDouble( &pTemp, dM11 );
+ ImplWriteDouble( &pTemp, 0 );
+ ImplWriteDouble( &pTemp, 0 );
+ ImplWriteDouble( &pTemp, dM22 );
+ ImplWriteDouble( &pTemp, nX - ( dM11 * nBoundingBox[0] ) );
+ ImplWriteDouble( &pTemp, mnHeight - nY - ( dM22 * nBoundingBox[3] ) );
+ ImplWriteString( &pTemp, "] concat /showpage {} def\n" );
+
+ if ( DevEscape( mhDC, DEVESC_RAWDATA, pTemp - pBuf,
+ (PBYTE)pBuf, 0, NULL ) == DEV_OK )
+#endif //
+ {
+ UINT32 nToDo = nSize;
+ UINT32 nDoNow;
+ bRet = TRUE;
+ while( nToDo && bRet )
+ {
+ nDoNow = 0x4000;
+ if ( nToDo < nDoNow )
+ nDoNow = nToDo;
+
+ if ( DevEscape( mhDC, DEVESC_RAWDATA, nDoNow, (PBYTE)pPtr + nSize - nToDo,
+ 0, NULL ) == -1 )
+ bRet = FALSE;
+ nToDo -= nDoNow;
+ }
+
+ if ( bRet )
+ {
+ strcpy ( (char*)pBuf, "\nrestore\n" );
+ if ( DevEscape( mhDC, DEVESC_RAWDATA, 9, (PBYTE)pBuf,
+ 0, NULL ) == DEV_OK ) bRet = TRUE;
+ }
+
+ // #107797# Write out EPS encapsulation footer
+ // ----------------------------------------------------------------------------------
+ // reserve a USHORT again
+ aBuf.setLength( 2 );
+ aBuf.append( "%%EndDocument\n"
+ "count op_count_salWin sub {pop} repeat\n"
+ "countdictstack dict_count_salWin sub {end} repeat\n"
+ "b4_Inc_state_salWin restore\n\n" );
+ *((USHORT*)aBuf.getStr()) = (USHORT)( aBuf.getLength() - 2 );
+ DevEscape( mhDC, DEVESC_RAWDATA, aBuf.getLength(),
+ (PBYTE)aBuf.getStr(), 0, NULL );
+ bRet = TRUE;
+
+ }
+ }
+ delete [] pBuf;
+ return bRet;
+}
+
+/*
+ * IsNativeControlSupported()
+ *
+ * Returns TRUE if the platform supports native
+ * drawing of the control defined by nPart
+ */
+BOOL Os2SalGraphics::IsNativeControlSupported( ControlType nType, ControlPart nPart )
+{
+ return( FALSE );
+}
+
+// -----------------------------------------------------------------------
+
+SystemGraphicsData Os2SalGraphics::GetGraphicsData() const
+{
+ SystemGraphicsData aRes;
+ aRes.nSize = sizeof(aRes);
+#if 0
+ aRes.hDC = mhDC;
+#endif
+ return aRes;
+}
+
+// -----------------------------------------------------------------------
diff --git a/vcl/os2/source/gdi/salgdi2.cxx b/vcl/os2/source/gdi/salgdi2.cxx
new file mode 100644
index 000000000000..37621ee1f6a8
--- /dev/null
+++ b/vcl/os2/source/gdi/salgdi2.cxx
@@ -0,0 +1,786 @@
+/*************************************************************************
+ *
+ * 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 <string.h>
+#include <svpm.h>
+
+#define _SV_SALGDI2_CXX
+#include <salbmp.h>
+#include <saldata.hxx>
+#ifndef _SV_SALIDS_HRC
+#include <salids.hrc>
+#endif
+#include <salgdi.h>
+#include <salvd.h>
+#include <vcl/salbtype.hxx>
+
+#ifndef __H_FT2LIB
+#include <wingdi.h>
+#include <ft2lib.h>
+#endif
+
+BOOL bFastTransparent = FALSE;
+
+// -----------
+// - Defines -
+// -----------
+
+#define RGBCOLOR( r, g, b ) ((ULONG)(((BYTE)(b)|((USHORT)(g)<<8))|(((ULONG)(BYTE)(r))<<16)))
+#define TY( y ) (mnHeight-(y)-1)
+
+// ---------------
+// - SalGraphics -
+// ---------------
+
+bool Os2SalGraphics::supportsOperation( OutDevSupportType ) const
+{
+ return false;
+}
+
+
+void Os2SalGraphics::copyBits( const SalTwoRect* pPosAry, SalGraphics* pSrcGraphics )
+{
+ HPS hSrcPS;
+ POINTL thePoints[4];
+ long nSrcHeight;
+
+ if ( pSrcGraphics )
+ {
+ //hSrcPS = pSrcGraphics->mhPS;
+ //nSrcHeight = pSrcGraphics->mnHeight;
+ hSrcPS = static_cast<Os2SalGraphics*>(pSrcGraphics)->mhPS;
+ nSrcHeight = static_cast<Os2SalGraphics*>(pSrcGraphics)->mnHeight;
+ }
+ else
+ {
+ hSrcPS = mhPS;
+ nSrcHeight = mnHeight;
+ }
+
+ // lower-left corner of target
+ thePoints[0].x = pPosAry->mnDestX;
+ thePoints[0].y = TY( pPosAry->mnDestY + pPosAry->mnDestHeight - 1 );
+
+ // upper-right corner of target
+ thePoints[1].x = pPosAry->mnDestX + pPosAry->mnDestWidth;
+ thePoints[1].y = TY( pPosAry->mnDestY - 1 );
+
+ // lower-left corner of source
+ thePoints[2].x = pPosAry->mnSrcX;
+ thePoints[2].y = nSrcHeight - ( pPosAry->mnSrcY + pPosAry->mnSrcHeight );
+
+ if ( ( pPosAry->mnDestWidth != pPosAry->mnSrcWidth ) || ( pPosAry->mnDestHeight != pPosAry->mnSrcHeight ) )
+ {
+ // upper-right corner of Source
+ thePoints[3].x = pPosAry->mnSrcX + pPosAry->mnSrcWidth;
+ thePoints[3].y = nSrcHeight - pPosAry->mnSrcY + pPosAry->mnSrcHeight;
+
+ GpiBitBlt( mhPS, hSrcPS, 4, thePoints,
+ mbXORMode ? ROP_SRCINVERT : ROP_SRCCOPY, BBO_IGNORE );
+ }
+ else
+ {
+ GpiBitBlt( mhPS, hSrcPS, 3, thePoints,
+ mbXORMode ? ROP_SRCINVERT : ROP_SRCCOPY, BBO_IGNORE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalGraphics::copyArea( long nDestX, long nDestY,
+ long nSrcX, long nSrcY,
+ long nSrcWidth, long nSrcHeight,
+ USHORT nFlags )
+{
+ POINTL thePoints[3];
+
+ // lower-left corner of target
+ thePoints[0].x = nDestX;
+ thePoints[0].y = TY( nDestY + nSrcHeight - 1 );
+
+ // upper-right corner of target
+ thePoints[1].x = nDestX + nSrcWidth;
+ thePoints[1].y = TY( nDestY - 1 );
+
+ // lower-left corner of source
+ thePoints[2].x = nSrcX;
+ thePoints[2].y = TY( nSrcY + nSrcHeight - 1);
+
+ if ( (nFlags & SAL_COPYAREA_WINDOWINVALIDATE) && mbWindow )
+ {
+ // Overlap-Bereich berechnen und invalidieren
+ Point aVCLSrcPos( nSrcX, nSrcY );
+ Size aVCLSrcSize( nSrcWidth, nSrcHeight );
+ Rectangle aVCLSrcRect( aVCLSrcPos, aVCLSrcSize );
+ Rectangle aVCLClipRect;
+ SWP aSWP;
+
+ WinQueryWindowPos( mhWnd, &aSWP );
+ aVCLClipRect.Right() = aSWP.cx-1;
+ aVCLClipRect.Bottom() = aSWP.cy-1;
+ if ( !aVCLSrcRect.Intersection( aVCLClipRect ).IsEmpty() )
+ {
+ RECTL aSrcRect;
+ RECTL aTempRect;
+ HRGN hInvalidateRgn;
+ HRGN hTempRgn;
+ HWND hWnd;
+ long nRgnType;
+
+ long nVCLScrHeight = aVCLSrcRect.GetHeight();
+ aSrcRect.xLeft = aVCLSrcRect.Left();
+ aSrcRect.yBottom = TY( aVCLSrcRect.Top()+nVCLScrHeight-1 );
+ aSrcRect.xRight = aSrcRect.xLeft+aVCLSrcRect.GetWidth();
+ aSrcRect.yTop = aSrcRect.yBottom+nVCLScrHeight;
+
+ // Rechteck in Screen-Koordinaaten umrechnen
+ POINTL aPt;
+ long nScreenDX = WinQuerySysValue( HWND_DESKTOP, SV_CXSCREEN );
+ long nScreenDY = WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN );
+ aPt.x = 0;
+ aPt.y = 0;
+ WinMapWindowPoints( mhWnd, HWND_DESKTOP, &aPt, 1 );
+ aSrcRect.xLeft += aPt.x;
+ aSrcRect.yTop += aPt.y;
+ aSrcRect.xRight += aPt.x;
+ aSrcRect.yBottom += aPt.y;
+ hInvalidateRgn = 0;
+ // Bereiche ausserhalb des sichtbaren Bereiches berechnen
+ if ( aSrcRect.xLeft < 0 )
+ {
+ if ( !hInvalidateRgn )
+ hInvalidateRgn = GpiCreateRegion( mhPS, 1, &aSrcRect );
+ aTempRect.xLeft = -31999;
+ aTempRect.yBottom = 0;
+ aTempRect.xRight = 0;
+ aTempRect.yTop = 31999;
+ hTempRgn = GpiCreateRegion( mhPS, 1, &aTempRect );
+ GpiCombineRegion( mhPS, hInvalidateRgn, hInvalidateRgn, hTempRgn, CRGN_DIFF );
+ GpiDestroyRegion( mhPS, hTempRgn );
+ }
+ if ( aSrcRect.yBottom < 0 )
+ {
+ if ( !hInvalidateRgn )
+ hInvalidateRgn = GpiCreateRegion( mhPS, 1, &aSrcRect );
+ aTempRect.xLeft = 0;
+ aTempRect.yBottom = -31999;
+ aTempRect.xRight = 31999;
+ aTempRect.yTop = 0;
+ hTempRgn = GpiCreateRegion( mhPS, 1, &aTempRect );
+ GpiCombineRegion( mhPS, hInvalidateRgn, hInvalidateRgn, hTempRgn, CRGN_DIFF );
+ GpiDestroyRegion( mhPS, hTempRgn );
+ }
+ if ( aSrcRect.xRight > nScreenDX )
+ {
+ if ( !hInvalidateRgn )
+ hInvalidateRgn = GpiCreateRegion( mhPS, 1, &aSrcRect );
+ aTempRect.xLeft = nScreenDX;
+ aTempRect.yBottom = 0;
+ aTempRect.xRight = 31999;
+ aTempRect.yTop = 31999;
+ hTempRgn = GpiCreateRegion( mhPS, 1, &aTempRect );
+ GpiCombineRegion( mhPS, hInvalidateRgn, hInvalidateRgn, hTempRgn, CRGN_DIFF );
+ GpiDestroyRegion( mhPS, hTempRgn );
+ }
+ if ( aSrcRect.yTop > nScreenDY )
+ {
+ if ( !hInvalidateRgn )
+ hInvalidateRgn = GpiCreateRegion( mhPS, 1, &aSrcRect );
+ aTempRect.xLeft = 0;
+ aTempRect.yBottom = nScreenDY;
+ aTempRect.xRight = 31999;
+ aTempRect.yTop = 31999;
+ hTempRgn = GpiCreateRegion( mhPS, 1, &aTempRect );
+ GpiCombineRegion( mhPS, hInvalidateRgn, hInvalidateRgn, hTempRgn, CRGN_DIFF );
+ GpiDestroyRegion( mhPS, hTempRgn );
+ }
+
+ // Bereiche die von anderen Fenstern ueberlagert werden berechnen
+ // Calculate areas that are overlapped by other windows
+ HWND hWndParent = WinQueryWindow( mhWnd, QW_PARENT );
+ hWnd = WinQueryWindow( HWND_DESKTOP, QW_TOP );
+ aVCLSrcRect = Rectangle( aSrcRect.xLeft, aSrcRect.yBottom, aSrcRect.xRight, aSrcRect.yTop );
+ while ( hWnd )
+ {
+ if ( hWnd == hWndParent )
+ break;
+ if ( WinIsWindowVisible( hWnd ) )
+ {
+ WinQueryWindowPos( hWnd, &aSWP );
+ if ( !(aSWP.fl & SWP_MINIMIZE) )
+ {
+ aVCLClipRect = Rectangle( Point( aSWP.x, aSWP.y ), Size( aSWP.cx, aSWP.cy ) );
+ if ( aVCLSrcRect.IsOver( aVCLClipRect ) )
+ {
+ if ( !hInvalidateRgn )
+ hInvalidateRgn = GpiCreateRegion( mhPS, 1, &aSrcRect );
+ aTempRect.xLeft = aSWP.x;
+ aTempRect.yBottom = aSWP.y;
+ aTempRect.xRight = aTempRect.xLeft+aSWP.cx;
+ aTempRect.yTop = aTempRect.yBottom+aSWP.cy;
+ hTempRgn = GpiCreateRegion( mhPS, 1, &aTempRect );
+ GpiCombineRegion( mhPS, hInvalidateRgn, hInvalidateRgn, hTempRgn, CRGN_DIFF );
+ GpiDestroyRegion( mhPS, hTempRgn );
+ }
+ }
+ }
+ hWnd = WinQueryWindow( hWnd, QW_NEXT );
+ }
+
+ if ( hInvalidateRgn )
+ {
+ hTempRgn = GpiCreateRegion( mhPS, 1, &aSrcRect );
+ nRgnType = GpiCombineRegion( mhPS, hInvalidateRgn, hTempRgn, hInvalidateRgn, CRGN_DIFF );
+ GpiDestroyRegion( mhPS, hTempRgn );
+ if ( (nRgnType != RGN_ERROR) && (nRgnType != RGN_NULL) )
+ {
+ long nOffX = (nDestX-nSrcX);
+ long nOffY = (nSrcY-nDestY);
+ aPt.x = nOffX-aPt.x;
+ aPt.y = nOffY-aPt.y;
+ GpiOffsetRegion( mhPS, hInvalidateRgn, &aPt );
+ WinInvalidateRegion( mhWnd, hInvalidateRgn, TRUE );
+ // Hier loesen wir nur ein Update aus, wenn es der
+ // MainThread ist, damit es beim Bearbeiten der
+ // Paint-Message keinen Deadlock gibt, da der
+ // SolarMutex durch diesen Thread schon gelockt ist
+ SalData* pSalData = GetSalData();
+ ULONG nCurThreadId = GetCurrentThreadId();
+ if ( pSalData->mnAppThreadId == nCurThreadId )
+ WinUpdateWindow( mhWnd );
+ }
+ GpiDestroyRegion( mhPS, hInvalidateRgn );
+ }
+ }
+ }
+
+ GpiBitBlt( mhPS, mhPS, 3, thePoints,
+ ROP_SRCCOPY, BBO_IGNORE );
+
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDrawBitmap( HPS hPS, long nScreenHeight,
+ const SalTwoRect* pPosAry, const Os2SalBitmap& rSalBitmap,
+ BOOL bPrinter, int nDrawMode )
+{
+ if( hPS )
+ {
+ HANDLE hDrawDIB;
+ HBITMAP hDrawDDB = rSalBitmap.ImplGethDDB();
+ Os2SalBitmap* pTmpSalBmp = NULL;
+ BOOL bPrintDDB = ( bPrinter && hDrawDDB );
+ BOOL bDrawDDB1 = ( ( rSalBitmap.GetBitCount() == 1 ) && hDrawDDB );
+
+ if( bPrintDDB || bDrawDDB1 )
+ {
+ pTmpSalBmp = new Os2SalBitmap;
+ pTmpSalBmp->Create( rSalBitmap, rSalBitmap.GetBitCount() );
+ hDrawDIB = pTmpSalBmp->ImplGethDIB();
+ }
+ else
+ hDrawDIB = rSalBitmap.ImplGethDIB();
+
+ if( hDrawDIB )
+ {
+ HANDLE hSubst = rSalBitmap.ImplGethDIB1Subst();
+ POINTL pts[ 4 ];
+ BITMAPINFO2* pBI = (BITMAPINFO2*) hDrawDIB;
+ BITMAPINFOHEADER2* pBIH = (BITMAPINFOHEADER2*) pBI;
+ const long nHeight = pBIH->cy;
+ long nInfoSize = *(ULONG*) pBI + rSalBitmap.ImplGetDIBColorCount( hDrawDIB ) * sizeof( RGB2 );
+ BYTE* pBits = (BYTE*) pBI + nInfoSize;
+
+ pts[0].x = pPosAry->mnDestX;
+ pts[0].y = nScreenHeight - pPosAry->mnDestY - pPosAry->mnDestHeight;
+ pts[1].x = pPosAry->mnDestX + pPosAry->mnDestWidth - 1;
+ pts[1].y = nScreenHeight - pPosAry->mnDestY - 1;
+
+ pts[2].x = pPosAry->mnSrcX;
+ pts[2].y = nHeight - ( pPosAry->mnSrcY + pPosAry->mnSrcHeight );
+ pts[3].x = pPosAry->mnSrcX + pPosAry->mnSrcWidth;
+ pts[3].y = nHeight - pPosAry->mnSrcY;
+
+ // if we've got a 1Bit DIB, we create a 4Bit substitute
+ if( ( pBIH->cBitCount == 1 ) && !hSubst )
+ {
+ // create 4Bit substitute
+ hSubst = Os2SalBitmap::ImplCreateDIB4FromDIB1( hDrawDIB );
+
+ // replace substitute only, if it is no temporary SalBitmap
+ if( !( bPrintDDB || bDrawDDB1 ) )
+ ( (Os2SalBitmap&) rSalBitmap ).ImplReplacehDIB1Subst( hSubst );
+ }
+
+ if( hSubst )
+ {
+ pBI = (BITMAPINFO2*) hSubst;
+ pBIH = (BITMAPINFOHEADER2*) pBI;
+ nInfoSize = *(ULONG*) pBI + rSalBitmap.ImplGetDIBColorCount( hSubst ) * sizeof( RGB2 );
+ pBits = (BYTE*) pBI + nInfoSize;
+ }
+
+ if( bPrinter )
+ {
+ BYTE* pDummy;
+
+ // expand 8Bit-DIB's to 24Bit-DIB's, because some printer drivers
+ // have problems to print these DIB's (strange)
+ if( pBIH->cBitCount == 8 && pBIH->ulCompression == BCA_UNCOMP )
+ {
+ const long nWidth = pBIH->cx;
+ const long nHeight = pBIH->cy;
+ const long nWidthAl8 = AlignedWidth4Bytes( nWidth * 8 );
+ const long nWidthAl24 = AlignedWidth4Bytes( nWidth * 24 );
+ const long nNewImageSize = nHeight * nWidthAl24;
+ BITMAPINFOHEADER2* pNewInfo;
+
+ pDummy = new BYTE[ sizeof( BITMAPINFO2 ) + nNewImageSize ];
+ memset( pDummy, 0, sizeof( BITMAPINFO2 ) );
+
+ pNewInfo = (BITMAPINFOHEADER2*) pDummy;
+ pNewInfo->cbFix = sizeof( BITMAPINFOHEADER2 );
+ pNewInfo->cx = nWidth;
+ pNewInfo->cy = nHeight;
+ pNewInfo->cPlanes = 1;
+ pNewInfo->cBitCount = 24;
+ pNewInfo->ulCompression = BCA_UNCOMP;
+ pNewInfo->cbImage = nNewImageSize;
+
+ BYTE* pBitsSrc = (BYTE*) pBIH + nInfoSize;
+ BYTE* pBitsDst = pDummy + sizeof( BITMAPINFO2 );
+
+ for( long nY = 0UL; nY < nHeight; nY++ )
+ {
+ BYTE* pSrcLine = pBitsSrc + nY * nWidthAl8;
+ BYTE* pDstLine = pBitsDst + nY * nWidthAl24;
+
+ for( long nX = 0UL; nX < nWidth; nX++ )
+ {
+ const RGB2& rQuad = pBI->argbColor[ *pSrcLine++ ];
+
+ *pDstLine++ = rQuad.bBlue;
+ *pDstLine++ = rQuad.bGreen;
+ *pDstLine++ = rQuad.bRed;
+ }
+ }
+
+ nInfoSize = sizeof( BITMAPINFO2 );
+ }
+ else
+ {
+ const long nImageSize = ( pBIH->cbImage ? pBIH->cbImage : ( pBIH->cy * AlignedWidth4Bytes( pBIH->cx * pBIH->cBitCount ) ) );
+ const long nTotalSize = nInfoSize + nImageSize;
+
+ pDummy = new BYTE[ nTotalSize ];
+ memcpy( pDummy, pBI, nTotalSize );
+ }
+
+ GpiDrawBits( hPS, pDummy + nInfoSize, (BITMAPINFO2*) pDummy, 4L, pts, nDrawMode, BBO_IGNORE );
+ delete[] pDummy;
+ }
+ else
+ GpiDrawBits( hPS, pBits, pBI, 4L, pts, nDrawMode, BBO_IGNORE );
+ }
+ else if( hDrawDDB && !bPrintDDB )
+ {
+ POINTL pts[ 4 ];
+
+ pts[0].x = pPosAry->mnDestX;
+ pts[0].y = nScreenHeight - pPosAry->mnDestY - pPosAry->mnDestHeight;
+ pts[1].x = pPosAry->mnDestX + pPosAry->mnDestWidth - 1;
+ pts[1].y = nScreenHeight - pPosAry->mnDestY - 1;
+
+ pts[2].x = pPosAry->mnSrcX;
+ pts[2].y = rSalBitmap.GetSize().Height() - ( pPosAry->mnSrcY + pPosAry->mnSrcHeight );
+ pts[3].x = pPosAry->mnSrcX + pPosAry->mnSrcWidth;
+ pts[3].y = rSalBitmap.GetSize().Height() - pPosAry->mnSrcY;
+
+ GpiWCBitBlt( hPS, hDrawDDB, 4L, pts, nDrawMode, BBO_IGNORE );
+/*
+ HPS hDrawPS = ImplGetCachedPS( CACHED_HPS_DRAW, hDrawDDB );
+ Ft2BitBlt( hPS, hDrawPS, 4, pts, nDrawMode, BBO_IGNORE );
+ ImplReleaseCachedPS( CACHED_HPS_DRAW );
+*/
+ }
+
+ if( bPrintDDB || bDrawDDB1 )
+ delete pTmpSalBmp;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalGraphics::drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap )
+{
+ ImplDrawBitmap( mhPS, mnHeight,
+ pPosAry, static_cast<const Os2SalBitmap&>(rSalBitmap),
+ mbPrinter,
+ mbXORMode ? ROP_SRCINVERT : ROP_SRCCOPY );
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalGraphics::drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ SalColor nTransparentColor )
+{
+ DBG_ASSERT( !mbPrinter, "No transparency print possible!" );
+ //const Os2SalBitmap& rSalBitmap = static_cast<const Os2SalBitmap&>(rSSalBitmap);
+ // an FM: kann erst einmal unberuecksichtigt bleiben
+ drawBitmap( pPosAry, rSalBitmap );
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalGraphics::drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSSalBitmap,
+ const SalBitmap& rSTransparentBitmap )
+{
+ DBG_ASSERT( !mbPrinter, "No transparency print possible!" );
+
+ const Os2SalBitmap& rSalBitmap = static_cast<const Os2SalBitmap&>(rSSalBitmap);
+ const Os2SalBitmap& rTransparentBitmap = static_cast<const Os2SalBitmap&>(rSTransparentBitmap);
+
+ if( bFastTransparent )
+ {
+ ImplDrawBitmap( mhPS, mnHeight, pPosAry, rTransparentBitmap, FALSE, ROP_SRCAND );
+ ImplDrawBitmap( mhPS, mnHeight, pPosAry, rSalBitmap, FALSE, ROP_SRCPAINT );
+ }
+ else
+ {
+ SalTwoRect aPosAry = *pPosAry;
+ int nDstX = (int) aPosAry.mnDestX;
+ int nDstY = (int) aPosAry.mnDestY;
+ int nDstWidth = (int) aPosAry.mnDestWidth;
+ int nDstHeight = (int) aPosAry.mnDestHeight;
+ HAB hAB = GetSalData()->mhAB;
+ HPS hPS = mhPS;
+ DEVOPENSTRUC aDevOpenStruc = { NULL, (PSZ)"DISPLAY", NULL, NULL, NULL, NULL, NULL, NULL, NULL };
+ SIZEL aSizeL = { nDstWidth, nDstHeight };
+ POINTL aPtL[ 3 ];
+
+ HDC hMemDC = DevOpenDC( hAB, OD_MEMORY, (PSZ)"*", 5L, (PDEVOPENDATA)&aDevOpenStruc, 0 );
+ HPS hMemPS = Ft2CreatePS( hAB, hMemDC, &aSizeL, GPIT_MICRO | GPIA_ASSOC | PU_PELS );
+ HBITMAP hMemBitmap = ImplCreateVirDevBitmap( hMemDC, hMemPS, nDstWidth, nDstHeight, 0 );
+ HBITMAP hMemOld = (HBITMAP) Ft2SetBitmap( hMemPS, hMemBitmap );
+ HDC hMaskDC = DevOpenDC( hAB, OD_MEMORY, (PSZ)"*", 5L, (PDEVOPENDATA)&aDevOpenStruc, 0 );
+ HPS hMaskPS = Ft2CreatePS( hAB, hMaskDC, &aSizeL, GPIT_MICRO | GPIA_ASSOC | PU_PELS );
+ HBITMAP hMaskBitmap = ImplCreateVirDevBitmap( hMaskDC, hMaskPS, nDstWidth, nDstHeight, 0 );
+ HBITMAP hMaskOld = (HBITMAP) Ft2SetBitmap( hMaskPS, hMaskBitmap );
+/*
+ HPS hMemPS = ImplGetCachedPS( CACHED_HPS_1, 0 );
+ HPS hMaskPS = ImplGetCachedPS( CACHED_HPS_2, 0 );
+*/
+ aPosAry.mnDestX = aPosAry.mnDestY = 0L;
+
+ aPtL[ 0 ].x = 0;
+ aPtL[ 0 ].y = 0;
+ aPtL[ 1 ].x = nDstWidth;
+ aPtL[ 1 ].y = nDstHeight;
+ aPtL[ 2 ].x = nDstX;
+ aPtL[ 2 ].y = TY( nDstY + nDstHeight - 1 );
+
+ GpiBitBlt( hMemPS, hPS, 3, aPtL, ROP_SRCCOPY, BBO_IGNORE );
+ ImplDrawBitmap( hMaskPS, nDstHeight, &aPosAry, rTransparentBitmap, FALSE, ROP_SRCCOPY );
+
+ aPtL[ 2 ].x = 0;
+ aPtL[ 2 ].y = 0;
+
+ GpiBitBlt( hMemPS, hMaskPS, 3, aPtL, ROP_SRCAND, BBO_IGNORE );
+ ImplDrawBitmap( hMaskPS, nDstHeight, &aPosAry, rSalBitmap, FALSE, ROP_SRCERASE );
+ GpiBitBlt( hMemPS, hMaskPS, 3, aPtL, ROP_SRCPAINT, BBO_IGNORE );
+
+ aPtL[ 0 ].x = nDstX;
+ aPtL[ 0 ].y = TY( nDstY + nDstHeight - 1 );
+ aPtL[ 1 ].x = nDstX + nDstWidth;
+ aPtL[ 1 ].y = TY( nDstY - 1 );
+
+ GpiBitBlt( hPS, hMemPS, 3, aPtL, ROP_SRCCOPY, BBO_IGNORE );
+
+ Ft2SetBitmap( hMaskPS, hMaskOld );
+ Ft2DestroyPS( hMaskPS );
+ DevCloseDC( hMaskDC );
+ GpiDeleteBitmap( hMaskBitmap );
+
+ Ft2SetBitmap( hMemPS, hMemOld );
+ Ft2DestroyPS( hMemPS );
+ DevCloseDC( hMemDC );
+ GpiDeleteBitmap( hMemBitmap );
+
+/*
+ ImplReleaseCachedPS( CACHED_HPS_1 );
+ ImplReleaseCachedPS( CACHED_HPS_2 );
+*/
+ }
+}
+
+// -----------------------------------------------------------------------
+
+bool Os2SalGraphics::drawAlphaBitmap( const SalTwoRect& rTR,
+ const SalBitmap& rSrcBitmap,
+ const SalBitmap& rAlphaBmp )
+{
+ // TODO(P3) implement alpha blending
+ return false;
+}
+
+// -----------------------------------------------------------------------
+
+bool Os2SalGraphics::drawAlphaRect( long nX, long nY, long nWidth,
+ long nHeight, sal_uInt8 nTransparency )
+{
+ // TODO(P3) implement alpha blending
+ return false;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalGraphics::drawMask( const SalTwoRect* pPosAry,
+ const SalBitmap& rSSalBitmap,
+ SalColor nMaskColor )
+{
+ DBG_ASSERT( !mbPrinter, "No transparency print possible!" );
+
+ const Os2SalBitmap& rSalBitmap = static_cast<const Os2SalBitmap&>(rSSalBitmap);
+
+ SalTwoRect aPosAry = *pPosAry;
+ HPS hPS = mhPS;
+ IMAGEBUNDLE aBundle, aOldBundle;
+ AREABUNDLE aAreaBundle, aOldAreaBundle;
+ const ULONG nColor = RGBCOLOR( SALCOLOR_RED( nMaskColor ),
+ SALCOLOR_GREEN( nMaskColor ),
+ SALCOLOR_BLUE( nMaskColor ) );
+
+ GpiQueryAttrs( hPS, PRIM_IMAGE, IBB_COLOR | IBB_BACK_COLOR, &aOldBundle );
+ aBundle.lColor = RGBCOLOR( 0, 0, 0 );
+ aBundle.lBackColor = RGBCOLOR( 0xFF, 0xFF, 0xFF );
+ Ft2SetAttrs( hPS, PRIM_IMAGE, IBB_COLOR | IBB_BACK_COLOR, 0, &aBundle );
+
+ GpiQueryAttrs( hPS, PRIM_AREA, ABB_COLOR | ABB_BACK_COLOR | ABB_SYMBOL |
+ ABB_MIX_MODE | ABB_BACK_MIX_MODE, &aOldAreaBundle );
+ aAreaBundle.lColor = nColor;
+ aAreaBundle.lBackColor = nColor;
+ aAreaBundle.usSymbol = PATSYM_SOLID;
+ aAreaBundle.usMixMode = FM_OVERPAINT;
+ aAreaBundle.usBackMixMode = BM_OVERPAINT;
+ Ft2SetAttrs( hPS, PRIM_AREA, ABB_COLOR | ABB_BACK_COLOR | ABB_SYMBOL |
+ ABB_MIX_MODE | ABB_BACK_MIX_MODE, 0, &aAreaBundle );
+
+ ImplDrawBitmap( hPS, mnHeight, &aPosAry, rSalBitmap, FALSE, 0x00B8L );
+
+ Ft2SetAttrs( hPS, PRIM_IMAGE, IBB_COLOR | IBB_BACK_COLOR, 0, &aOldBundle );
+ Ft2SetAttrs( hPS, PRIM_AREA, ABB_COLOR | ABB_BACK_COLOR | ABB_SYMBOL |
+ ABB_MIX_MODE | ABB_BACK_MIX_MODE, 0, &aOldAreaBundle );
+}
+
+// -----------------------------------------------------------------------
+
+SalBitmap* Os2SalGraphics::getBitmap( long nX, long nY, long nDX, long nDY )
+{
+ HAB hAB = GetSalData()->mhAB;
+ SIZEL size = { nDX, nDY };
+ Os2SalBitmap* pSalBitmap = NULL;
+
+ // create device context (at this time allways display compatible)
+ DEVOPENSTRUC aDevOpenStruc = { NULL, (PSZ)"DISPLAY", NULL, NULL, NULL, NULL, NULL, NULL, NULL };
+ HDC hMemDC = DevOpenDC( hAB, OD_MEMORY, (PSZ)"*", 5L, (PDEVOPENDATA)&aDevOpenStruc, 0 );
+ HPS hMemPS = Ft2CreatePS( hAB, hMemDC, &size, GPIT_MICRO | GPIA_ASSOC | PU_PELS );
+ HBITMAP hMemBmp = ImplCreateVirDevBitmap( hMemDC, hMemPS, nDX, nDY, 0 );
+ HBITMAP hMemOld = Ft2SetBitmap( hMemPS, hMemBmp );
+
+ // creation successfull?
+ if( hMemDC && hMemPS && hMemBmp )
+ {
+ POINTL thePoints[ 3 ];
+
+ // lower-left corner of target
+ thePoints[ 0 ].x = 0;
+ thePoints[ 0 ].y = 0;
+
+ // upper-right corner of target
+ thePoints[ 1 ].x = nDX;
+ thePoints[ 1 ].y = nDY;
+
+ // lower-left corner of source
+ thePoints[ 2 ].x = nX;
+ thePoints[ 2 ].y = TY( nY + nDY - 1 );
+
+ long lHits = GpiBitBlt( hMemPS, mhPS, 3, thePoints,
+ mbXORMode ? ROP_SRCINVERT : ROP_SRCCOPY, BBO_IGNORE );
+
+ if( hMemPS )
+ {
+ Ft2SetBitmap( hMemPS, hMemOld );
+ Ft2DestroyPS( hMemPS );
+ }
+
+ if( hMemDC )
+ DevCloseDC( hMemDC );
+
+ if( lHits == GPI_OK )
+ {
+ pSalBitmap = new Os2SalBitmap;
+
+ if( !pSalBitmap->Create( hMemBmp, FALSE, FALSE ) )
+ {
+ delete pSalBitmap;
+ pSalBitmap = NULL;
+ }
+ }
+ }
+
+ if( !pSalBitmap )
+ GpiDeleteBitmap( hMemBmp );
+
+ // return pointer to SAL-Bitmap
+ return pSalBitmap;
+}
+
+// -----------------------------------------------------------------------
+
+SalColor Os2SalGraphics::getPixel( long nX, long nY )
+{
+ POINTL aPt = { nX, TY( nY ) };
+ LONG nColor = Ft2QueryPel( mhPS, &aPt );
+
+ return MAKE_SALCOLOR( (BYTE) ( nColor >> 16 ), (BYTE) ( nColor >> 8 ), (BYTE) nColor );
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalGraphics::invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags )
+{
+ if( nFlags & SAL_INVERT_TRACKFRAME )
+ {
+ // save old vylues
+ LINEBUNDLE oldLb;
+ LINEBUNDLE lb;
+ GpiQueryAttrs( mhPS, PRIM_LINE, LBB_MIX_MODE | LBB_TYPE | LBB_COLOR, &oldLb );
+
+ // set linetype to short dash
+ lb.lColor = RGBCOLOR( 255, 255, 255 );
+ lb.usMixMode = FM_XOR;
+ lb.usType = LINETYPE_ALTERNATE;
+ Ft2SetAttrs( mhPS, PRIM_LINE, LBB_MIX_MODE | LBB_TYPE | LBB_COLOR, 0, &lb );
+
+ // draw inverted box
+ POINTL aPt;
+
+ aPt.x = nX;
+ aPt.y = TY( nY );
+
+ Ft2Move( mhPS, &aPt );
+
+ aPt.x = nX + nWidth - 1;
+ aPt.y = TY( nY + nHeight - 1 );
+
+ Ft2Box( mhPS, DRO_OUTLINE, &aPt, 0, 0 );
+
+ // restore old values
+ Ft2SetAttrs( mhPS, PRIM_LINE, LBB_MIX_MODE | LBB_TYPE | LBB_COLOR, 0, &oldLb );
+
+ }
+ else
+ {
+ // save old values
+ AREABUNDLE oldAb;
+ AREABUNDLE ab;
+
+ GpiQueryAttrs( mhPS, PRIM_AREA, ABB_COLOR | ABB_MIX_MODE | ABB_SYMBOL, &oldAb );
+
+ // set fill color to black
+ ab.lColor = RGBCOLOR( 255, 255, 255 );
+ ab.usMixMode = FM_XOR;
+ ab.usSymbol = (nFlags & SAL_INVERT_50) ? PATSYM_DENSE5 : PATSYM_SOLID;
+ Ft2SetAttrs( mhPS, PRIM_AREA, ABB_COLOR | ABB_MIX_MODE | ABB_SYMBOL, 0, &ab );
+
+ // draw inverted box
+ POINTL aPt;
+
+ aPt.x = nX;
+ aPt.y = TY( nY );
+
+ Ft2Move( mhPS, &aPt );
+
+ aPt.x = nX + nWidth - 1;
+ aPt.y = TY( nY + nHeight - 1 );
+
+ Ft2Box( mhPS, DRO_FILL, &aPt, 0, 0 );
+
+ // restore old values
+ Ft2SetAttrs( mhPS, PRIM_AREA, ABB_COLOR | ABB_MIX_MODE | ABB_SYMBOL, 0, &oldAb );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalGraphics::invert( ULONG nPoints, const SalPoint* pPtAry, SalInvert nFlags )
+{
+ if( nFlags & SAL_INVERT_TRACKFRAME )
+ {
+ // save old vylues
+ LINEBUNDLE oldLb;
+ LINEBUNDLE lb;
+ GpiQueryAttrs( mhPS, PRIM_LINE, LBB_MIX_MODE | LBB_TYPE | LBB_COLOR, &oldLb );
+
+ // set linetype to short dash
+ lb.lColor = RGBCOLOR( 255, 255, 255 );
+ lb.usMixMode = FM_XOR;
+ lb.usType = LINETYPE_ALTERNATE;
+ Ft2SetAttrs( mhPS, PRIM_LINE, LBB_MIX_MODE | LBB_TYPE | LBB_COLOR, 0, &lb );
+
+ // Draw Polyline
+ drawPolyLine( nPoints, pPtAry );
+
+ // restore old values
+ Ft2SetAttrs( mhPS, PRIM_LINE, LBB_MIX_MODE | LBB_TYPE | LBB_COLOR, 0, &oldLb );
+ }
+ else
+ {
+ // save old values
+ AREABUNDLE oldAb;
+ AREABUNDLE ab;
+
+ GpiQueryAttrs( mhPS, PRIM_AREA, ABB_COLOR | ABB_MIX_MODE | ABB_SYMBOL, &oldAb );
+
+ // set fill color to black
+ ab.lColor = RGBCOLOR( 255, 255, 255 );
+ ab.usMixMode = FM_XOR;
+ ab.usSymbol = (nFlags & SAL_INVERT_50) ? PATSYM_DENSE5 : PATSYM_SOLID;
+ Ft2SetAttrs( mhPS, PRIM_AREA, ABB_COLOR | ABB_MIX_MODE | ABB_SYMBOL, 0, &ab );
+
+ // Draw Polyline
+ drawPolygon( nPoints, pPtAry );
+
+ // restore old values
+ Ft2SetAttrs( mhPS, PRIM_AREA, ABB_COLOR | ABB_MIX_MODE | ABB_SYMBOL, 0, &oldAb );
+ }
+}
+
diff --git a/vcl/os2/source/gdi/salgdi3.cxx b/vcl/os2/source/gdi/salgdi3.cxx
new file mode 100644
index 000000000000..e25e68ee5a4c
--- /dev/null
+++ b/vcl/os2/source/gdi/salgdi3.cxx
@@ -0,0 +1,1769 @@
+/*************************************************************************
+ *
+ * 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 INCL_GRE_STRINGS
+#define INCL_GPI
+#define INCL_DOS
+
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+#include <svpm.h>
+
+#define _SV_SALGDI3_CXX
+#include <tools/svwin.h>
+#include <rtl/tencinfo.h>
+#ifndef _OSL_FILE_HXX
+#include <osl/file.hxx>
+#endif
+#ifndef _OSL_THREAD_HXX
+#include <osl/thread.hxx>
+#endif
+#ifndef _OSL_PROCESS_HXX
+#include <osl/process.h>
+#endif
+#include <vcl/svapp.hxx>
+#include <saldata.hxx>
+#include <salgdi.h>
+#include <vcl/font.hxx>
+#include <vcl/sallayout.hxx>
+#include <tools/poly.hxx>
+#include <tools/debug.hxx>
+#include <rtl/textcvt.h>
+#include <tools/debug.hxx>
+#include <saldata.hxx>
+#include <salgdi.h>
+#ifndef _SV_OUTFONT_HXX
+#include <vcl/outfont.hxx>
+#endif
+#include <sallayout.h>
+#include <tools/poly.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+
+#ifndef __H_FT2LIB
+#include <wingdi.h>
+#include <ft2lib.h>
+#endif
+
+#include "sft.hxx"
+
+#ifdef GCP_KERN_HACK
+#include <algorithm>
+#endif
+
+using namespace vcl;
+
+// -----------
+// - Inlines -
+// -----------
+
+
+inline W32FIXED FixedFromDouble( double d )
+{
+ const long l = (long) ( d * 65536. );
+ return *(W32FIXED*) &l;
+}
+
+// -----------------------------------------------------------------------
+
+inline int IntTimes256FromFixed(W32FIXED f)
+{
+ int nFixedTimes256 = (f.value << 8) + ((f.fract+0x80) >> 8);
+ return nFixedTimes256;
+}
+
+// -----------
+// - Defines -
+// -----------
+
+// this is a special codepage code, used to identify OS/2 symbol font.
+#define SYMBOL_CHARSET 65400
+
+// =======================================================================
+
+UniString ImplSalGetUniString( const sal_Char* pStr, xub_StrLen nLen = STRING_LEN)
+{
+ return UniString( pStr, nLen, gsl_getSystemTextEncoding(),
+ RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_DEFAULT |
+ RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT |
+ RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT );
+}
+
+// =======================================================================
+
+static USHORT ImplSalToCharSet( CharSet eCharSet )
+{
+ // !!! Fuer DBCS-Systeme muss dieser Code auskommentiert werden und 0
+ // !!! zurueckgegeben werden, solange die DBCS-Charsets nicht
+ // !!! durchgereicht werden
+
+ switch ( eCharSet )
+ {
+ case RTL_TEXTENCODING_IBM_437:
+ return 437;
+
+ case RTL_TEXTENCODING_IBM_850:
+ return 850;
+
+ case RTL_TEXTENCODING_IBM_860:
+ return 860;
+
+ case RTL_TEXTENCODING_IBM_861:
+ return 861;
+
+ case RTL_TEXTENCODING_IBM_863:
+ return 863;
+
+ case RTL_TEXTENCODING_IBM_865:
+ return 865;
+ case RTL_TEXTENCODING_MS_1252:
+ return 1004;
+ case RTL_TEXTENCODING_SYMBOL:
+ return 65400;
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+static CharSet ImplCharSetToSal( USHORT usCodePage )
+{
+ switch ( usCodePage )
+ {
+ case 437:
+ return RTL_TEXTENCODING_IBM_437;
+
+ case 850:
+ return RTL_TEXTENCODING_IBM_850;
+
+ case 860:
+ return RTL_TEXTENCODING_IBM_860;
+
+ case 861:
+ return RTL_TEXTENCODING_IBM_861;
+
+ case 863:
+ return RTL_TEXTENCODING_IBM_863;
+
+ case 865:
+ return RTL_TEXTENCODING_IBM_865;
+ case 1004:
+ return RTL_TEXTENCODING_MS_1252;
+ case 65400:
+ return RTL_TEXTENCODING_SYMBOL;
+ }
+
+ return RTL_TEXTENCODING_DONTKNOW;
+}
+
+// -----------------------------------------------------------------------
+
+static FontFamily ImplFamilyToSal( BYTE bFamilyType )
+{
+ switch ( bFamilyType )
+ {
+ case 4:
+ return FAMILY_DECORATIVE;
+ case 3:
+ return FAMILY_SCRIPT;
+ }
+
+ return FAMILY_DONTKNOW;
+}
+
+// -----------------------------------------------------------------------
+
+static FontWeight ImplWeightToSal( USHORT nWeight )
+{
+ // Falls sich jemand an die alte Doku gehalten hat
+ if ( nWeight > 999 )
+ nWeight /= 1000;
+
+ switch ( nWeight )
+ {
+ case 1:
+ return WEIGHT_THIN;
+
+ case 2:
+ return WEIGHT_ULTRALIGHT;
+
+ case 3:
+ return WEIGHT_LIGHT;
+
+ case 4:
+ return WEIGHT_SEMILIGHT;
+
+ case 5:
+ return WEIGHT_NORMAL;
+
+ case 6:
+ return WEIGHT_SEMIBOLD;
+
+ case 7:
+ return WEIGHT_BOLD;
+
+ case 8:
+ return WEIGHT_ULTRABOLD;
+
+ case 9:
+ return WEIGHT_BLACK;
+ }
+
+ return WEIGHT_DONTKNOW;
+}
+
+// -----------------------------------------------------------------------
+
+static UniString ImpStyleNameToSal( const char* pFamilyName,
+ const char* pFaceName,
+ USHORT nLen )
+{
+ if ( !nLen )
+ nLen = strlen(pFamilyName);
+
+ // strip FamilyName from FaceName
+ if ( strncmp( pFamilyName, pFaceName, nLen ) == 0 )
+ {
+ USHORT nFaceLen = (USHORT)strlen( pFaceName+nLen );
+ // Ist Facename laenger, schneiden wir den FamilyName ab
+ if ( nFaceLen > 1 )
+ return UniString( pFaceName+(nLen+1), gsl_getSystemTextEncoding());
+ else
+ return UniString();
+ }
+ else
+ return UniString( pFaceName, gsl_getSystemTextEncoding());
+}
+
+// -----------------------------------------------------------------------
+
+inline FontPitch ImplLogPitchToSal( BYTE fsType )
+{
+ if ( fsType & FM_TYPE_FIXED )
+ return PITCH_FIXED;
+ else
+ return PITCH_VARIABLE;
+}
+
+// -----------------------------------------------------------------------
+
+inline BYTE ImplPitchToWin( FontPitch ePitch )
+{
+ if ( ePitch == PITCH_FIXED )
+ return FM_TYPE_FIXED;
+ //else if ( ePitch == PITCH_VARIABLE )
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+static ImplDevFontAttributes Os2Font2DevFontAttributes( const PFONTMETRICS pFontMetric)
+{
+ ImplDevFontAttributes aDFA;
+
+ // get font face attributes
+ aDFA.meFamily = ImplFamilyToSal( pFontMetric->panose.bFamilyType);
+ aDFA.meWidthType = WIDTH_DONTKNOW;
+ aDFA.meWeight = ImplWeightToSal( pFontMetric->usWeightClass);
+ aDFA.meItalic = (pFontMetric->fsSelection & FM_SEL_ITALIC) ? ITALIC_NORMAL : ITALIC_NONE;
+ aDFA.mePitch = ImplLogPitchToSal( pFontMetric->fsType );
+ aDFA.mbSymbolFlag = (pFontMetric->usCodePage == SYMBOL_CHARSET);
+
+ // get the font face name
+ // the maName field stores the font name without the style, so under OS/2
+ // we must use the family name
+ aDFA.maName = UniString( pFontMetric->szFamilyname, gsl_getSystemTextEncoding());
+
+ aDFA.maStyleName = ImpStyleNameToSal( pFontMetric->szFamilyname,
+ pFontMetric->szFacename,
+ strlen( pFontMetric->szFamilyname) );
+
+ // get device specific font attributes
+ aDFA.mbOrientation = (pFontMetric->fsDefn & FM_DEFN_OUTLINE) != 0;
+ aDFA.mbDevice = (pFontMetric->fsDefn & FM_DEFN_GENERIC) ? FALSE : TRUE;
+
+ aDFA.mbEmbeddable = false;
+ aDFA.mbSubsettable = false;
+ DWORD fontType = Ft2QueryFontType( 0, pFontMetric->szFamilyname);
+ if( fontType == FT2_FONTTYPE_TRUETYPE && !aDFA.mbDevice)
+ aDFA.mbSubsettable = true;
+ // for now we can only embed Type1 fonts
+ if( fontType == FT2_FONTTYPE_TYPE1 )
+ aDFA.mbEmbeddable = true;
+
+ // heuristics for font quality
+ // - standard-type1 > opentypeTT > truetype > non-standard-type1 > raster
+ // - subsetting > embedding > none
+ aDFA.mnQuality = 0;
+ if( fontType == FT2_FONTTYPE_TRUETYPE )
+ aDFA.mnQuality += 50;
+ if( aDFA.mbSubsettable )
+ aDFA.mnQuality += 200;
+ else if( aDFA.mbEmbeddable )
+ aDFA.mnQuality += 100;
+
+ // #i38665# prefer Type1 versions of the standard postscript fonts
+ if( aDFA.mbEmbeddable )
+ {
+ if( aDFA.maName.EqualsAscii( "AvantGarde" )
+ || aDFA.maName.EqualsAscii( "Bookman" )
+ || aDFA.maName.EqualsAscii( "Courier" )
+ || aDFA.maName.EqualsAscii( "Helvetica" )
+ || aDFA.maName.EqualsAscii( "NewCenturySchlbk" )
+ || aDFA.maName.EqualsAscii( "Palatino" )
+ || aDFA.maName.EqualsAscii( "Symbol" )
+ || aDFA.maName.EqualsAscii( "Times" )
+ || aDFA.maName.EqualsAscii( "ZapfChancery" )
+ || aDFA.maName.EqualsAscii( "ZapfDingbats" ) )
+ aDFA.mnQuality += 500;
+ }
+
+ aDFA.meEmbeddedBitmap = EMBEDDEDBITMAP_DONTKNOW;
+ aDFA.meAntiAlias = ANTIALIAS_DONTKNOW;
+
+ // TODO: add alias names
+
+ return aDFA;
+}
+
+// =======================================================================
+
+// -----------------------------------------------------------------------
+
+// =======================================================================
+
+ImplOs2FontData::ImplOs2FontData( PFONTMETRICS _pFontMetric,
+ int nHeight, BYTE nPitchAndFamily )
+: ImplFontData( Os2Font2DevFontAttributes(_pFontMetric), 0 ),
+ pFontMetric( _pFontMetric ),
+ meOs2CharSet( _pFontMetric->usCodePage),
+ mnPitchAndFamily( nPitchAndFamily ),
+ mpFontCharSets( NULL ),
+ mpUnicodeMap( NULL ),
+ mbDisableGlyphApi( false ),
+ mbHasKoreanRange( false ),
+ mbHasCJKSupport( false ),
+ mbAliasSymbolsLow( false ),
+ mbAliasSymbolsHigh( false ),
+ mnId( 0 )
+{
+ SetBitmapSize( 0, nHeight );
+}
+
+// -----------------------------------------------------------------------
+
+ImplOs2FontData::~ImplOs2FontData()
+{
+ delete[] mpFontCharSets;
+
+ if( mpUnicodeMap )
+ mpUnicodeMap->DeReference();
+}
+
+// -----------------------------------------------------------------------
+
+sal_IntPtr ImplOs2FontData::GetFontId() const
+{
+ return mnId;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplOs2FontData::UpdateFromHPS( HPS hPS ) const
+{
+ // short circuit if already initialized
+ if( mpUnicodeMap != NULL )
+ return;
+
+ ReadCmapTable( hPS );
+ ReadOs2Table( hPS );
+
+ // even if the font works some fonts have problems with the glyph API
+ // => the heuristic below tries to figure out which fonts have the problem
+ DWORD fontType = Ft2QueryFontType( 0, pFontMetric->szFacename);
+ if( fontType != FT2_FONTTYPE_TRUETYPE
+ && (pFontMetric->fsDefn & FM_DEFN_GENERIC) == 0)
+ mbDisableGlyphApi = true;
+}
+
+// -----------------------------------------------------------------------
+
+#ifdef GNG_VERT_HACK
+bool ImplOs2FontData::HasGSUBstitutions( HPS hPS ) const
+{
+ if( !mbGsubRead )
+ ReadGsubTable( hPS );
+ return !maGsubTable.empty();
+}
+
+// -----------------------------------------------------------------------
+
+bool ImplOs2FontData::IsGSUBstituted( sal_Ucs cChar ) const
+{
+ return( maGsubTable.find( cChar ) != maGsubTable.end() );
+}
+#endif // GNG_VERT_HACK
+
+// -----------------------------------------------------------------------
+
+ImplFontCharMap* ImplOs2FontData::GetImplFontCharMap() const
+{
+ mpUnicodeMap->AddReference();
+ return mpUnicodeMap;
+}
+
+// -----------------------------------------------------------------------
+
+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]));}
+static inline DWORD CalcTag( const char p[4]) { return (p[0]+(p[1]<<8)+(p[2]<<16)+(p[3]<<24)); }
+
+void ImplOs2FontData::ReadOs2Table( HPS hPS ) const
+{
+ const DWORD Os2Tag = CalcTag( "OS/2" );
+ DWORD nLength = Ft2GetFontData( hPS, Os2Tag, 0, NULL, 0 );
+ if( (nLength == FT2_ERROR) || !nLength )
+ return;
+ std::vector<unsigned char> aOS2map( nLength );
+ unsigned char* pOS2map = &aOS2map[0];
+ DWORD nRC = Ft2GetFontData( hPS, Os2Tag, 0, pOS2map, nLength );
+ sal_uInt32 nVersion = GetUShort( pOS2map );
+ if ( nVersion >= 0x0001 && nLength >= 58 )
+ {
+ // We need at least version 0x0001 (TrueType rev 1.66)
+ // to have access to the needed struct members.
+ sal_uInt32 ulUnicodeRange1 = GetUInt( pOS2map + 42 );
+ sal_uInt32 ulUnicodeRange2 = GetUInt( pOS2map + 46 );
+ sal_uInt32 ulUnicodeRange3 = GetUInt( pOS2map + 50 );
+ sal_uInt32 ulUnicodeRange4 = GetUInt( pOS2map + 54 );
+
+ // Check for CJK capabilities of the current font
+ mbHasCJKSupport = (ulUnicodeRange2 & 0x2fff0000)
+ | (ulUnicodeRange3 & 0x00000001);
+ mbHasKoreanRange= (ulUnicodeRange1 & 0x10000000)
+ | (ulUnicodeRange2 & 0x01100000);
+ }
+}
+
+
+// -----------------------------------------------------------------------
+
+#ifdef GNG_VERT_HACK
+void ImplOs2FontData::ReadGsubTable( HPS hPS ) const
+{
+ mbGsubRead = true;
+
+ // check the existence of a GSUB table
+ const DWORD GsubTag = CalcTag( "GSUB" );
+ DWORD nRC = Ft2GetFontData( hPS, GsubTag, 0, NULL, 0 );
+ if( (nRC == FT2_ERROR) || !nRC )
+ return;
+
+ // TODO: directly read the GSUB table instead of going through sft
+
+ // get raw font file data
+ DWORD nFontSize = Ft2GetFontData( hPS, 0, 0, NULL, 0 );
+ if( nFontSize == FT2_ERROR )
+ return;
+ std::vector<char> aRawFont( nFontSize+1 );
+ aRawFont[ nFontSize ] = 0;
+ DWORD nFontSize2 = Ft2GetFontData( hPS, 0, 0, (void*)&aRawFont[0], nFontSize );
+ if( nFontSize != nFontSize2 )
+ return;
+
+ // open font file
+ sal_uInt32 nFaceNum = 0;
+ if( !aRawFont[0] ) // TTC candidate
+ nFaceNum = ~0U; // indicate "TTC font extracts only"
+
+ TrueTypeFont* pTTFont = NULL;
+ ::OpenTTFontBuffer( &aRawFont[0], nFontSize, nFaceNum, &pTTFont );
+ if( !pTTFont )
+ return;
+
+ // add vertically substituted characters to list
+ static const sal_Unicode aGSUBCandidates[] = {
+ 0x0020, 0x0080, // ASCII
+ 0x2000, 0x2600, // misc
+ 0x3000, 0x3100, // CJK punctutation
+ 0x3300, 0x3400, // squared words
+ 0xFF00, 0xFFF0, // halfwidth|fullwidth forms
+ 0 };
+
+ for( const sal_Unicode* pPair = aGSUBCandidates; *pPair; pPair += 2 )
+ for( sal_Unicode cChar = pPair[0]; cChar < pPair[1]; ++cChar )
+ if( ::MapChar( pTTFont, cChar, 0 ) != ::MapChar( pTTFont, cChar, 1 ) )
+ maGsubTable.insert( cChar ); // insert GSUBbed unicodes
+
+ CloseTTFont( pTTFont );
+
+#if 0
+ TrueTypeFont* pTTFont = NULL;
+ ::OpenTTFont( &aRawFont[0], nFontSize, nFaceNum, &pTTFont );
+ if( !pTTFont )
+ return;
+
+ // add vertically substituted characters to list
+ static const sal_Unicode aGSUBCandidates[] = {
+ 0x0020, 0x0080, // ASCII
+ 0x2000, 0x2600, // misc
+ 0x3000, 0x3100, // CJK punctutation
+ 0x3300, 0x3400, // squared words
+ 0xFF00, 0xFFF0, // halfwidth|fullwidth forms
+ 0 };
+
+ for( const sal_Unicode* pPair = aGSUBCandidates; *pPair; pPair += 2 )
+ for( sal_Unicode cChar = pPair[0]; cChar < pPair[1]; ++cChar )
+ if( ::MapChar( pTTFont, cChar, 0 ) != ::MapChar( pTTFont, cChar, 1 ) )
+ maGsubTable.insert( cChar ); // insert GSUBbed unicodes
+
+ CloseTTFont( pTTFont );
+#endif
+}
+#endif // GNG_VERT_HACK
+
+// -----------------------------------------------------------------------
+
+void ImplOs2FontData::ReadCmapTable( HPS hPS ) const
+{
+ CmapResult aResult;
+ aResult.mnPairCount = 0;
+ aResult.mbSymbolic = (meOs2CharSet == SYMBOL_CHARSET);
+ aResult.mbRecoded = true;
+
+ // get the CMAP table from the font which is selected into the DC
+ const DWORD CmapTag = CalcTag( "cmap" );
+ DWORD nRC = Ft2GetFontData( hPS, CmapTag, 0, NULL, 0 );
+ // read the CMAP table if available
+ if( nRC != FT2_ERROR )
+ {
+ const int nLength = nRC;
+ std::vector<unsigned char> aCmap( nLength );
+ unsigned char* pCmap = &aCmap[0];
+ nRC = Ft2GetFontData( hPS, CmapTag, 0, pCmap, nLength );
+ // parse the CMAP table
+ if( nRC == nLength )
+ ParseCMAP( pCmap, nLength, aResult );
+ } else {
+ // we need to define at least a simple charmap, otherwise this font
+ // will be mapped to default charmap, and OOo doesn't accept the
+ // system font to match the default charmap
+ aResult.mnPairCount = 1;
+ // ImplFontCharMap destructor will free this memory
+ aResult.mpPairCodes = new sal_uInt32[ 2 * aResult.mnPairCount ];
+ aResult.mpPairCodes[0] = 0x0020;
+ aResult.mpPairCodes[1] = 0x00FF;
+ aResult.mpStartGlyphs = NULL;
+ }
+
+ mbDisableGlyphApi |= aResult.mbRecoded;
+
+ if( aResult.mnPairCount > 0 )
+ mpUnicodeMap = new ImplFontCharMap( aResult.mnPairCount,
+ aResult.mpPairCodes, aResult.mpStartGlyphs );
+ else
+ mpUnicodeMap = ImplFontCharMap::GetDefaultMap();
+}
+
+// =======================================================================
+
+void Os2SalGraphics::SetTextColor( SalColor nSalColor )
+{
+ CHARBUNDLE cb;
+
+ cb.lColor = RGBCOLOR( SALCOLOR_RED( nSalColor ),
+ SALCOLOR_GREEN( nSalColor ),
+ SALCOLOR_BLUE( nSalColor ) );
+
+ // set default color attributes
+ Ft2SetAttrs( mhPS,
+ PRIM_CHAR,
+ CBB_COLOR,
+ 0,
+ &cb );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT Os2SalGraphics::ImplDoSetFont( ImplFontSelectData* i_pFont, float& o_rFontScale, int nFallbackLevel)
+{
+
+#if OSL_DEBUG_LEVEL>10
+ debug_printf( "Os2SalGraphics::ImplDoSetFont\n");
+#endif
+
+ ImplOs2FontData* pFontData = (ImplOs2FontData*)i_pFont->mpFontData;
+ PFONTMETRICS pFontMetric = NULL;
+ FATTRS aFAttrs;
+ BOOL bOutline = FALSE;
+ APIRET rc;
+
+ memset( &aFAttrs, 0, sizeof( FATTRS ) );
+ aFAttrs.usRecordLength = sizeof( FATTRS );
+
+ aFAttrs.lMaxBaselineExt = i_pFont->mnHeight;
+ aFAttrs.lAveCharWidth = i_pFont->mnWidth;
+
+ // do we have a pointer to the FONTMETRICS of the selected font? -> use it!
+ if ( pFontData )
+ {
+ pFontMetric = pFontData->GetFontMetrics();
+
+ bOutline = (pFontMetric->fsDefn & FM_DEFN_OUTLINE) != 0;
+
+ // use match&registry fields to get correct match
+ aFAttrs.lMatch = pFontMetric->lMatch;
+ aFAttrs.idRegistry = pFontMetric->idRegistry;
+ aFAttrs.usCodePage = pFontMetric->usCodePage;
+
+ if ( bOutline )
+ {
+ aFAttrs.fsFontUse |= FATTR_FONTUSE_OUTLINE;
+ if ( i_pFont->mnOrientation )
+ aFAttrs.fsFontUse |= FATTR_FONTUSE_TRANSFORMABLE;
+ }
+ else
+ {
+ aFAttrs.lMaxBaselineExt = pFontMetric->lMaxBaselineExt;
+ aFAttrs.lAveCharWidth = pFontMetric->lAveCharWidth;
+ }
+
+ }
+
+ // use family name for outline fonts
+ if ( mbPrinter ) {
+ // use font face name for printers because otherwise ft2lib will fail
+ // to select the correct font for GPI (ticket#117)
+ strncpy( (char*)(aFAttrs.szFacename), pFontMetric->szFacename, sizeof( aFAttrs.szFacename ) );
+ } else if ( !pFontMetric) {
+ // use OOo name if fontmetrics not available!
+ ByteString aName( i_pFont->maName.GetToken( 0 ), gsl_getSystemTextEncoding());
+ strncpy( (char*)(aFAttrs.szFacename), aName.GetBuffer(), sizeof( aFAttrs.szFacename ) );
+ } else if ( bOutline) {
+ // use fontmetric family name for outline fonts
+ strncpy( (char*)(aFAttrs.szFacename), pFontMetric->szFamilyname, sizeof( aFAttrs.szFacename ) );
+ } else {
+ // use real font face name for bitmaps (WarpSans only)
+ strncpy( (char*)(aFAttrs.szFacename), pFontMetric->szFacename, sizeof( aFAttrs.szFacename ) );
+ }
+
+ if ( i_pFont->meItalic != ITALIC_NONE )
+ aFAttrs.fsSelection |= FATTR_SEL_ITALIC;
+ if ( i_pFont->meWeight > WEIGHT_MEDIUM )
+ aFAttrs.fsSelection |= FATTR_SEL_BOLD;
+
+#if OSL_DEBUG_LEVEL>1
+ if (pFontMetric->szFacename[0] == 'A') {
+ debug_printf( "Os2SalGraphics::SetFont hps %x lMatch '%d'\n", mhPS, pFontMetric->lMatch);
+ debug_printf( "Os2SalGraphics::SetFont hps %x fontmetrics facename '%s'\n", mhPS, pFontMetric->szFacename);
+ debug_printf( "Os2SalGraphics::SetFont hps %x fattrs facename '%s'\n", mhPS, aFAttrs.szFacename);
+ }
+#endif
+
+ Ft2DeleteSetId( mhPS, nFallbackLevel + LCID_BASE);
+ if ( (rc=Ft2CreateLogFont( mhPS, NULL, nFallbackLevel + LCID_BASE, &aFAttrs)) == GPI_ERROR ) {
+#if OSL_DEBUG_LEVEL>1
+ ERRORID nLastError = WinGetLastError( GetSalData()->mhAB );
+ debug_printf( "Os2SalGraphics::SetFont hps %x Ft2CreateLogFont failed err %x\n", mhPS, nLastError );
+#endif
+ return SAL_SETFONT_REMOVEANDMATCHNEW;
+ }
+
+ CHARBUNDLE aBundle;
+
+ ULONG nAttrsDefault = 0;
+ ULONG nAttrs = CBB_SET;
+ aBundle.usSet = nFallbackLevel + LCID_BASE;
+
+ if ( bOutline )
+ {
+ nAttrs |= CBB_BOX;
+ aBundle.sizfxCell.cy = MAKEFIXED( i_pFont->mnHeight, 0 );
+
+ if ( !i_pFont->mnWidth )
+ {
+ LONG nXFontRes;
+ LONG nYFontRes;
+ LONG nHeight;
+
+ // Auf die Aufloesung achten, damit das Ergebnis auch auf
+ // Drucken mit 180*360 DPI stimmt. Ausserdem muss gerundet
+ // werden, da auf meinem OS2 beispielsweise als
+ // Bildschirmaufloesung 3618*3622 PixelPerMeter zurueck-
+ // gegeben wird
+ GetResolution( nXFontRes, nYFontRes );
+ nHeight = i_pFont->mnHeight;
+ nHeight *= nXFontRes;
+ nHeight += nYFontRes/2;
+ nHeight /= nYFontRes;
+ aBundle.sizfxCell.cx = MAKEFIXED( nHeight, 0 );
+ }
+ else
+ aBundle.sizfxCell.cx = MAKEFIXED( i_pFont->mnWidth, 0 );
+ }
+
+ // set orientation for outlinefonts
+ if ( i_pFont->mnOrientation )
+ {
+ if ( bOutline )
+ {
+ nAttrs |= CBB_ANGLE;
+ double alpha = (double)(i_pFont->mnOrientation);
+ alpha *= 0.0017453292; // *PI / 1800
+ mnOrientationY = (long) (1000.0 * sin( alpha ));
+ mnOrientationX = (long) (1000.0 * cos( alpha ));
+ aBundle.ptlAngle.x = mnOrientationX;
+ aBundle.ptlAngle.y = mnOrientationY;
+ }
+ else
+ {
+ mnOrientationX = 1;
+ mnOrientationY = 0;
+ nAttrs |= CBB_ANGLE;
+ aBundle.ptlAngle.x = 1;
+ aBundle.ptlAngle.y = 0;
+ }
+ }
+ else
+ {
+ mnOrientationX = 1;
+ mnOrientationY = 0;
+ nAttrs |= CBB_ANGLE;
+ aBundle.ptlAngle.x = 1;
+ aBundle.ptlAngle.y = 0;
+ }
+
+ rc = Ft2SetAttrs( mhPS, PRIM_CHAR, nAttrs, nAttrsDefault, &aBundle );
+
+#if OSL_DEBUG_LEVEL>1
+ FONTMETRICS aOS2Metric = {0};
+ Ft2QueryFontMetrics( mhPS, sizeof( aOS2Metric ), &aOS2Metric );
+#endif
+
+ return 0;
+}
+
+
+USHORT Os2SalGraphics::SetFont( ImplFontSelectData* pFont, int nFallbackLevel )
+{
+
+ // return early if there is no new font
+ if( !pFont )
+ {
+#if 0
+ // deselect still active font
+ if( mhDefFont )
+ Ft2SetCharSet( mhPS, mhDefFont );
+ // release no longer referenced font handles
+ for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
+ {
+ if( mhFonts[i] )
+ Ft2DeleteSetId( mhPS, mhFonts[i] );
+ mhFonts[ i ] = 0;
+ }
+#endif
+ mhDefFont = 0;
+ return 0;
+ }
+
+#if OSL_DEBUG_LEVEL>10
+ debug_printf( "Os2SalGraphics::SetFont\n");
+#endif
+
+ DBG_ASSERT( pFont->mpFontData, "WinSalGraphics mpFontData==NULL");
+ mpOs2FontEntry[ nFallbackLevel ] = reinterpret_cast<ImplOs2FontEntry*>( pFont->mpFontEntry );
+ mpOs2FontData[ nFallbackLevel ] = static_cast<const ImplOs2FontData*>( pFont->mpFontData );
+
+ ImplDoSetFont( pFont, mfFontScale, nFallbackLevel);
+
+ if( !mhDefFont )
+ {
+ // keep default font
+ mhDefFont = nFallbackLevel + LCID_BASE;
+ }
+ else
+ {
+ // release no longer referenced font handles
+ for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
+ {
+ if( mhFonts[i] )
+ {
+#if 0
+ Ft2DeleteSetId( mhPS, mhFonts[i] );
+#endif
+ mhFonts[i] = 0;
+ }
+ }
+ }
+
+ // store new font in correct layer
+ mhFonts[ nFallbackLevel ] = nFallbackLevel + LCID_BASE;
+
+ // now the font is live => update font face
+ if( mpOs2FontData[ nFallbackLevel ] )
+ mpOs2FontData[ nFallbackLevel ]->UpdateFromHPS( mhPS );
+
+ if( !nFallbackLevel )
+ {
+ mbFontKernInit = TRUE;
+ if ( mpFontKernPairs )
+ {
+ delete[] mpFontKernPairs;
+ mpFontKernPairs = NULL;
+ }
+ mnFontKernPairCount = 0;
+ }
+
+ // some printers have higher internal resolution, so their
+ // text output would be different from what we calculated
+ // => suggest DrawTextArray to workaround this problem
+ if ( mbPrinter )
+ return SAL_SETFONT_USEDRAWTEXTARRAY;
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalGraphics::GetFontMetric( ImplFontMetricData* pMetric )
+{
+ FONTMETRICS aOS2Metric;
+ Ft2QueryFontMetrics( mhPS, sizeof( aOS2Metric ), &aOS2Metric );
+
+#if OSL_DEBUG_LEVEL>1
+ debug_printf( "Os2SalGraphics::GetFontMetric hps %x\n", mhPS);
+ if (aOS2Metric.szFacename[0] == 'A') {
+ debug_printf( "Os2SalGraphics::GetFontMetric hps %x fontmetrics facename '%s'\n", mhPS, aOS2Metric.szFacename);
+ debug_printf( "Os2SalGraphics::GetFontMetric hps %x fontmetrics lMatch '%d'\n", mhPS, aOS2Metric.lMatch);
+ }
+#endif
+
+ pMetric->maName = UniString( aOS2Metric.szFamilyname, gsl_getSystemTextEncoding());
+ pMetric->maStyleName = ImpStyleNameToSal( aOS2Metric.szFamilyname,
+ aOS2Metric.szFacename,
+ strlen( aOS2Metric.szFamilyname ) );
+
+ // device independent font attributes
+ pMetric->meFamily = ImplFamilyToSal( aOS2Metric.panose.bFamilyType);
+ pMetric->mbSymbolFlag = (aOS2Metric.usCodePage == SYMBOL_CHARSET);
+ pMetric->meWeight = ImplWeightToSal( aOS2Metric.usWeightClass );
+ pMetric->mePitch = ImplLogPitchToSal( aOS2Metric.fsType );
+ pMetric->meItalic = (aOS2Metric.fsSelection & FM_SEL_ITALIC) ? ITALIC_NORMAL : ITALIC_NONE;
+ pMetric->mnSlant = 0;
+
+ // device dependend font attributes
+ pMetric->mbDevice = (aOS2Metric.fsDefn & FM_DEFN_GENERIC) ? FALSE : TRUE;
+ pMetric->mbScalableFont = (aOS2Metric.fsDefn & FM_DEFN_OUTLINE) ? true : false;
+ if( pMetric->mbScalableFont )
+ {
+ // check if there are kern pairs
+ // TODO: does this work with GPOS kerning?
+ pMetric->mbKernableFont = (aOS2Metric.sKerningPairs > 0);
+ }
+ else
+ {
+ // bitmap fonts cannot be rotated directly
+ pMetric->mnOrientation = 0;
+ // bitmap fonts have no kerning
+ pMetric->mbKernableFont = false;
+ }
+
+ // transformation dependend font metrics
+ if ( aOS2Metric.fsDefn & FM_DEFN_OUTLINE )
+ {
+ pMetric->mnWidth = aOS2Metric.lEmInc;
+ }
+ else
+ {
+ pMetric->mnWidth = aOS2Metric.lAveCharWidth;
+ pMetric->mnOrientation = 0;
+ }
+ pMetric->mnIntLeading = aOS2Metric.lInternalLeading;
+ pMetric->mnExtLeading = aOS2Metric.lExternalLeading;
+ pMetric->mnAscent = aOS2Metric.lMaxAscender;
+ pMetric->mnDescent = aOS2Metric.lMaxDescender;
+
+ // #107888# improved metric compatibility for Asian fonts...
+ // TODO: assess workaround below for CWS >= extleading
+ // TODO: evaluate use of aWinMetric.sTypo* members for CJK
+ if( mpOs2FontData[0] && mpOs2FontData[0]->SupportsCJK() )
+ {
+ pMetric->mnIntLeading += pMetric->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 = pMetric->mnExtLeading / 2;
+ const long nOtherHalfTmpExtLeading = pMetric->mnExtLeading - nHalfTmpExtLeading;
+
+ // #110641# external leading for Asian fonts.
+ // The factor 0.3 has been confirmed with experiments.
+ long nCJKExtLeading = static_cast<long>(0.30 * (pMetric->mnAscent + pMetric->mnDescent));
+ nCJKExtLeading -= pMetric->mnExtLeading;
+ pMetric->mnExtLeading = (nCJKExtLeading > 0) ? nCJKExtLeading : 0;
+
+ pMetric->mnAscent += nHalfTmpExtLeading;
+ pMetric->mnDescent += nOtherHalfTmpExtLeading;
+
+ // #109280# HACK korean only: increase descent for wavelines and impr
+ // YD win9x only
+ }
+
+}
+
+// -----------------------------------------------------------------------
+
+ULONG Os2SalGraphics::GetKernPairs( ULONG nPairs, ImplKernPairData* pKernPairs )
+{
+ DBG_ASSERT( sizeof( KERNINGPAIRS ) == sizeof( ImplKernPairData ),
+ "Os2SalGraphics::GetKernPairs(): KERNINGPAIRS != ImplKernPairData" );
+
+ if ( mbFontKernInit )
+ {
+ if( mpFontKernPairs )
+ {
+ delete[] mpFontKernPairs;
+ mpFontKernPairs = NULL;
+ }
+ mnFontKernPairCount = 0;
+
+ {
+ KERNINGPAIRS* pPairs = NULL;
+ FONTMETRICS aOS2Metric;
+ Ft2QueryFontMetrics( mhPS, sizeof( aOS2Metric ), &aOS2Metric );
+ int nCount = aOS2Metric.sKerningPairs;
+ if( nCount )
+ {
+#ifdef GCP_KERN_HACK
+ pPairs = new KERNINGPAIRS[ nCount+1 ];
+ mpFontKernPairs = pPairs;
+ mnFontKernPairCount = nCount;
+ Ft2QueryKerningPairs( mhPS, nCount, (KERNINGPAIRS*)pPairs );
+#else // GCP_KERN_HACK
+ pPairs = (KERNINGPAIRS*)pKernPairs;
+ nCount = (nCount < nPairs) ? nCount : nPairs;
+ Ft2QueryKerningPairs( mhPS, nCount, (KERNINGPAIRS*)pPairs );
+ return nCount;
+#endif // GCP_KERN_HACK
+ }
+ }
+
+ mbFontKernInit = FALSE;
+
+ std::sort( mpFontKernPairs, mpFontKernPairs + mnFontKernPairCount, ImplCmpKernData );
+ }
+
+ if( !pKernPairs )
+ return mnFontKernPairCount;
+ else if( mpFontKernPairs )
+ {
+ if ( nPairs < mnFontKernPairCount )
+ nPairs = mnFontKernPairCount;
+ memcpy( pKernPairs, mpFontKernPairs,
+ nPairs*sizeof( ImplKernPairData ) );
+ return nPairs;
+ }
+
+ return 0;
+}
+
+
+// -----------------------------------------------------------------------
+
+static ImplFontCharMap* pOs2DefaultImplFontCharMap = NULL;
+static const sal_uInt32 pOs2DefaultRangeCodes[] = {0x0020,0x00FF};
+
+ImplFontCharMap* Os2SalGraphics::GetImplFontCharMap() const
+{
+ if( !mpOs2FontData[0] )
+ return ImplFontCharMap::GetDefaultMap();
+ return mpOs2FontData[0]->GetImplFontCharMap();
+}
+
+// -----------------------------------------------------------------------
+
+bool Os2SalGraphics::AddTempDevFont( ImplDevFontList* pFontList,
+ const String& rFontFileURL, const String& rFontName )
+{
+#if OSL_DEBUG_LEVEL>0
+ debug_printf("Os2SalGraphics::AddTempDevFont\n");
+#endif
+ return false;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalGraphics::GetDevFontList( ImplDevFontList* pList )
+{
+ PFONTMETRICS pFontMetrics;
+ ULONG nFontMetricCount;
+ SalData* pSalData;
+
+#if OSL_DEBUG_LEVEL>0
+ debug_printf("Os2SalGraphics::GetDevFontList\n");
+#endif
+
+ // install OpenSymbol
+ HMODULE hMod;
+ ULONG ObjNum, Offset, rc;
+ CHAR Buff[2*_MAX_PATH];
+ char drive[_MAX_DRIVE], dir[_MAX_DIR];
+ char fname[_MAX_FNAME], ext[_MAX_EXT];
+ // get module handle (and name)
+ rc = DosQueryModFromEIP( &hMod, &ObjNum, sizeof( Buff), Buff,
+ &Offset, (ULONG)ImplSalGetUniString);
+ DosQueryModuleName(hMod, sizeof(Buff), Buff);
+ // replace module path with font path
+ char* slash = strrchr( Buff, '\\');
+ *slash = '\0';
+ slash = strrchr( Buff, '\\');
+ *slash = '\0';
+ strcat( Buff, "\\SHARE\\FONTS\\TRUETYPE\\OPENS___.TTF");
+ rc = GpiLoadPublicFonts( GetSalData()->mhAB, Buff);
+
+ if ( !mbPrinter )
+ {
+ // Bei Bildschirm-Devices cachen wir die Liste global, da
+ // dies im unabhaengigen Teil auch so gemacht wird und wir
+ // ansonsten auf geloeschten Systemdaten arbeiten koennten
+ pSalData = GetSalData();
+ nFontMetricCount = pSalData->mnFontMetricCount;
+ pFontMetrics = pSalData->mpFontMetrics;
+ // Bei Bildschirm-Devices holen wir uns die Fontliste jedesmal neu
+ if ( pFontMetrics )
+ {
+ delete pFontMetrics;
+ pFontMetrics = NULL;
+ nFontMetricCount = 0;
+ }
+ }
+ else
+ {
+ nFontMetricCount = mnFontMetricCount;
+ pFontMetrics = mpFontMetrics;
+ }
+
+ // do we have to create the cached font list first?
+ if ( !pFontMetrics )
+ {
+ // query the number of fonts available
+ LONG nTemp = 0;
+ nFontMetricCount = Ft2QueryFonts( mhPS,
+ QF_PUBLIC | QF_PRIVATE,
+ NULL, &nTemp,
+ sizeof( FONTMETRICS ), NULL );
+
+ // procede only if at least one is available!
+ if ( nFontMetricCount )
+ {
+ // allocate memory for font list
+ pFontMetrics = new FONTMETRICS[nFontMetricCount];
+
+ // query font list
+ Ft2QueryFonts( mhPS,
+ QF_PUBLIC | QF_PRIVATE,
+ NULL,
+ (PLONG)&nFontMetricCount,
+ (LONG) sizeof( FONTMETRICS ),
+ pFontMetrics );
+ }
+
+ if ( !mbPrinter )
+ {
+ pSalData->mnFontMetricCount = nFontMetricCount;
+ pSalData->mpFontMetrics = pFontMetrics;
+ }
+ else
+ {
+ mnFontMetricCount = nFontMetricCount;
+ mpFontMetrics = pFontMetrics;
+ }
+ }
+
+ // copy data from the font list
+ for( ULONG i = 0; i < nFontMetricCount; i++ )
+ {
+ PFONTMETRICS pFontMetric = &pFontMetrics[i];
+
+ // skip font starting with '@', this is an alias internally
+ // used by truetype engine.
+ if (pFontMetric->szFacename[0] == '@')
+ continue;
+
+ // skip bitmap fonts (but keep WarpSans)
+ if ( (pFontMetric->fsDefn & FM_DEFN_OUTLINE) == 0
+ && strncmp( pFontMetric->szFacename, "WarpSans", 8) )
+ // Font nicht aufnehmen
+ continue;
+
+ // replace '-' in facename with ' ' (for ft2lib)
+ char* dash = pFontMetric->szFacename;
+ while( (dash=strchr( dash, '-')))
+ *dash++ = ' ';
+
+ // create new font list element
+ ImplOs2FontData* pData = new ImplOs2FontData( pFontMetric, 0, 0 );
+
+ // add font list element to font list
+ pList->Add( pData );
+
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+void Os2SalGraphics::GetDevFontSubstList( OutputDevice* pOutDev )
+{
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Os2SalGraphics::GetGlyphBoundRect( long nIndex, Rectangle& rRect )
+{
+ // use unity matrix
+ MAT2 aMat;
+ aMat.eM11 = aMat.eM22 = FixedFromDouble( 1.0 );
+ aMat.eM12 = aMat.eM21 = FixedFromDouble( 0.0 );
+
+ UINT nGGOFlags = GGO_METRICS;
+ if( !(nIndex & GF_ISCHAR) )
+ nGGOFlags |= GGO_GLYPH_INDEX;
+ nIndex &= GF_IDXMASK;
+
+ GLYPHMETRICS aGM;
+ DWORD nSize = FT2_ERROR;
+ nSize = Ft2GetGlyphOutline( mhPS, nIndex, nGGOFlags, &aGM, 0, NULL, &aMat );
+ if( nSize == FT2_ERROR )
+ return false;
+
+ rRect = Rectangle( Point( +aGM.gmptGlyphOrigin.x, -aGM.gmptGlyphOrigin.y ),
+ Size( aGM.gmBlackBoxX, aGM.gmBlackBoxY ) );
+ rRect.Left() = static_cast<int>( mfFontScale * rRect.Left() );
+ rRect.Right() = static_cast<int>( mfFontScale * rRect.Right() );
+ rRect.Top() = static_cast<int>( mfFontScale * rRect.Top() );
+ rRect.Bottom() = static_cast<int>( mfFontScale * rRect.Bottom() );
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Os2SalGraphics::GetGlyphOutline( long nIndex, ::basegfx::B2DPolyPolygon& rB2DPolyPoly )
+{
+#if OSL_DEBUG_LEVEL>0
+ debug_printf("Os2SalGraphics::GetGlyphOutline\n");
+#endif
+ rB2DPolyPoly.clear();
+
+ BOOL bRet = FALSE;
+
+ // use unity matrix
+ MAT2 aMat;
+ aMat.eM11 = aMat.eM22 = FixedFromDouble( 1.0 );
+ aMat.eM12 = aMat.eM21 = FixedFromDouble( 0.0 );
+
+ UINT nGGOFlags = GGO_NATIVE;
+ if( !(nIndex & GF_ISCHAR) )
+ nGGOFlags |= GGO_GLYPH_INDEX;
+ nIndex &= GF_IDXMASK;
+
+ GLYPHMETRICS aGlyphMetrics;
+ DWORD nSize1 = FT2_ERROR;
+ nSize1 = Ft2GetGlyphOutline( mhPS, nIndex, nGGOFlags, &aGlyphMetrics, 0, NULL, &aMat );
+
+ if( !nSize1 ) // blank glyphs are ok
+ bRet = TRUE;
+ else if( nSize1 != FT2_ERROR )
+ {
+ BYTE* pData = new BYTE[ nSize1 ];
+ ULONG nTotalCount = 0;
+ DWORD nSize2;
+ nSize2 = Ft2GetGlyphOutline( mhPS, nIndex, nGGOFlags,
+ &aGlyphMetrics, nSize1, pData, &aMat );
+
+ if( nSize1 == nSize2 )
+ {
+ bRet = TRUE;
+
+ int nPtSize = 512;
+ Point* pPoints = new Point[ nPtSize ];
+ BYTE* pFlags = new BYTE[ nPtSize ];
+
+ TTPOLYGONHEADER* pHeader = (TTPOLYGONHEADER*)pData;
+ while( (BYTE*)pHeader < pData+nSize2 )
+ {
+ // only outline data is interesting
+ if( pHeader->dwType != TT_POLYGON_TYPE )
+ break;
+
+ // get start point; next start points are end points
+ // of previous segment
+ int nPnt = 0;
+
+ long nX = IntTimes256FromFixed( pHeader->pfxStart.x );
+ long nY = IntTimes256FromFixed( pHeader->pfxStart.y );
+ pPoints[ nPnt ] = Point( nX, nY );
+ pFlags[ nPnt++ ] = POLY_NORMAL;
+
+ bool bHasOfflinePoints = false;
+ TTPOLYCURVE* pCurve = (TTPOLYCURVE*)( pHeader + 1 );
+ pHeader = (TTPOLYGONHEADER*)( (BYTE*)pHeader + pHeader->cb );
+ while( (BYTE*)pCurve < (BYTE*)pHeader )
+ {
+ int nNeededSize = nPnt + 16 + 3 * pCurve->cpfx;
+ if( nPtSize < nNeededSize )
+ {
+ Point* pOldPoints = pPoints;
+ BYTE* pOldFlags = pFlags;
+ nPtSize = 2 * nNeededSize;
+ pPoints = new Point[ nPtSize ];
+ pFlags = new BYTE[ nPtSize ];
+ for( int i = 0; i < nPnt; ++i )
+ {
+ pPoints[ i ] = pOldPoints[ i ];
+ pFlags[ i ] = pOldFlags[ i ];
+ }
+ delete[] pOldPoints;
+ delete[] pOldFlags;
+ }
+
+ int i = 0;
+ if( TT_PRIM_LINE == pCurve->wType )
+ {
+ while( i < pCurve->cpfx )
+ {
+ nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
+ nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
+ ++i;
+ pPoints[ nPnt ] = Point( nX, nY );
+ pFlags[ nPnt ] = POLY_NORMAL;
+ ++nPnt;
+ }
+ }
+ else if( TT_PRIM_QSPLINE == pCurve->wType )
+ {
+ bHasOfflinePoints = true;
+ while( i < pCurve->cpfx )
+ {
+ // get control point of quadratic bezier spline
+ nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
+ nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
+ ++i;
+ Point aControlP( nX, nY );
+
+ // calculate first cubic control point
+ // P0 = 1/3 * (PBeg + 2 * PQControl)
+ nX = pPoints[ nPnt-1 ].X() + 2 * aControlP.X();
+ nY = pPoints[ nPnt-1 ].Y() + 2 * aControlP.Y();
+ pPoints[ nPnt+0 ] = Point( (2*nX+3)/6, (2*nY+3)/6 );
+ pFlags[ nPnt+0 ] = POLY_CONTROL;
+
+ // calculate endpoint of segment
+ nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
+ nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
+
+ if ( i+1 >= pCurve->cpfx )
+ {
+ // endpoint is either last point in segment => advance
+ ++i;
+ }
+ else
+ {
+ // or endpoint is the middle of two control points
+ nX += IntTimes256FromFixed( pCurve->apfx[ i-1 ].x );
+ nY += IntTimes256FromFixed( pCurve->apfx[ i-1 ].y );
+ nX = (nX + 1) / 2;
+ nY = (nY + 1) / 2;
+ // no need to advance, because the current point
+ // is the control point in next bezier spline
+ }
+
+ pPoints[ nPnt+2 ] = Point( nX, nY );
+ pFlags[ nPnt+2 ] = POLY_NORMAL;
+
+ // calculate second cubic control point
+ // P1 = 1/3 * (PEnd + 2 * PQControl)
+ nX = pPoints[ nPnt+2 ].X() + 2 * aControlP.X();
+ nY = pPoints[ nPnt+2 ].Y() + 2 * aControlP.Y();
+ pPoints[ nPnt+1 ] = Point( (2*nX+3)/6, (2*nY+3)/6 );
+ pFlags[ nPnt+1 ] = POLY_CONTROL;
+
+ nPnt += 3;
+ }
+ }
+
+ // next curve segment
+ pCurve = (TTPOLYCURVE*)&pCurve->apfx[ i ];
+ }
+
+ // end point is start point for closed contour
+ // disabled, because Polygon class closes the contour itself
+ // pPoints[nPnt++] = pPoints[0];
+ // #i35928#
+ // Added again, but add only when not yet closed
+ if(pPoints[nPnt - 1] != pPoints[0])
+ {
+ if( bHasOfflinePoints )
+ pFlags[nPnt] = pFlags[0];
+
+ pPoints[nPnt++] = pPoints[0];
+ }
+
+ // convert y-coordinates W32 -> VCL
+ for( int i = 0; i < nPnt; ++i )
+ pPoints[i].Y() = -pPoints[i].Y();
+
+ // insert into polypolygon
+ Polygon aPoly( nPnt, pPoints, (bHasOfflinePoints ? pFlags : NULL) );
+ // convert to B2DPolyPolygon
+ // TODO: get rid of the intermediate PolyPolygon
+ rB2DPolyPoly.append( aPoly.getB2DPolygon() );
+ }
+
+ delete[] pPoints;
+ delete[] pFlags;
+ }
+
+ delete[] pData;
+ }
+
+ // rescaling needed for the PolyPolygon conversion
+ if( rB2DPolyPoly.count() )
+ {
+ const double fFactor((1.0/256) * mfFontScale);
+ rB2DPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix(fFactor, fFactor));
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+// TODO: Replace this class with boost::scoped_array
+class ScopedCharArray
+{
+public:
+ inline explicit ScopedCharArray(char * pArray): m_pArray(pArray) {}
+
+ inline ~ScopedCharArray() { delete[] m_pArray; }
+
+ inline char * get() const { return m_pArray; }
+
+private:
+ char * m_pArray;
+};
+
+class ScopedFont
+{
+public:
+ explicit ScopedFont(Os2SalGraphics & rData);
+
+ ~ScopedFont();
+
+private:
+ Os2SalGraphics & m_rData;
+ ULONG m_hOrigFont;
+};
+
+ScopedFont::ScopedFont(Os2SalGraphics & rData): m_rData(rData)
+{
+#if 0
+ m_hOrigFont = m_rData.mhFonts[0];
+ m_rData.mhFonts[0] = 0; // avoid deletion of current font
+#endif
+}
+
+ScopedFont::~ScopedFont()
+{
+#if 0
+ if( m_hOrigFont )
+ {
+ // restore original font, destroy temporary font
+ HFONT hTempFont = m_rData.mhFonts[0];
+ m_rData.mhFonts[0] = m_hOrigFont;
+ SelectObject( m_rData.mhDC, m_hOrigFont );
+ DeleteObject( hTempFont );
+ }
+#endif
+}
+
+class ScopedTrueTypeFont
+{
+public:
+ inline ScopedTrueTypeFont(): m_pFont(0) {}
+
+ ~ScopedTrueTypeFont();
+
+ int open(void * pBuffer, sal_uInt32 nLen, sal_uInt32 nFaceNum);
+
+ inline TrueTypeFont * get() const { return m_pFont; }
+
+private:
+ TrueTypeFont * m_pFont;
+};
+
+ScopedTrueTypeFont::~ScopedTrueTypeFont()
+{
+ if (m_pFont != 0)
+ CloseTTFont(m_pFont);
+}
+
+int ScopedTrueTypeFont::open(void * pBuffer, sal_uInt32 nLen,
+ sal_uInt32 nFaceNum)
+{
+ OSL_ENSURE(m_pFont == 0, "already open");
+ return OpenTTFontBuffer(pBuffer, nLen, nFaceNum, &m_pFont);
+}
+
+BOOL Os2SalGraphics::CreateFontSubset( const rtl::OUString& rToFile,
+ const ImplFontData* pFont, long* pGlyphIDs, sal_uInt8* pEncoding,
+ sal_Int32* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rInfo )
+{
+ // create matching ImplFontSelectData
+ // we need just enough to get to the font file data
+ // use height=1000 for easier debugging (to match psprint's font units)
+ ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
+
+ // TODO: much better solution: move SetFont and restoration of old font to caller
+ ScopedFont aOldFont(*this);
+ SetFont( &aIFSD, 0 );
+
+#if OSL_DEBUG_LEVEL > 100
+ // get font metrics
+ TEXTMETRICA aWinMetric;
+ if( !::GetTextMetricsA( mhDC, &aWinMetric ) )
+ return FALSE;
+
+ DBG_ASSERT( !(aWinMetric.tmPitchAndFamily & TMPF_DEVICE), "cannot subset device font" );
+ DBG_ASSERT( aWinMetric.tmPitchAndFamily & TMPF_TRUETYPE, "can only subset TT font" );
+#endif
+
+ // get raw font file data
+ DWORD nFontSize1 = Ft2GetFontData( mhPS, 0, 0, NULL, 0 );
+ if( nFontSize1 == FT2_ERROR )
+ return FALSE;
+ ScopedCharArray xRawFontData(new char[ nFontSize1 ]);
+ DWORD nFontSize2 = Ft2GetFontData( mhPS, 0, 0, (void*)xRawFontData.get(), nFontSize1 );
+ if( nFontSize1 != nFontSize2 )
+ return FALSE;
+
+ // open font file
+ sal_uInt32 nFaceNum = 0;
+ if( !*xRawFontData.get() ) // TTC candidate
+ nFaceNum = ~0U; // indicate "TTC font extracts only"
+
+ ScopedTrueTypeFont aSftTTF;
+ int nRC = aSftTTF.open( xRawFontData.get(), nFontSize1, nFaceNum );
+ if( nRC != SF_OK )
+ return FALSE;
+
+ TTGlobalFontInfo aTTInfo;
+ ::GetTTGlobalFontInfo( aSftTTF.get(), &aTTInfo );
+ rInfo.m_nFontType = SAL_FONTSUBSETINFO_TYPE_TRUETYPE;
+ rInfo.m_aPSName = ImplSalGetUniString( aTTInfo.psname );
+ rInfo.m_nAscent = +aTTInfo.winAscent;
+ rInfo.m_nDescent = -aTTInfo.winDescent;
+ rInfo.m_aFontBBox = Rectangle( Point( aTTInfo.xMin, aTTInfo.yMin ),
+ Point( aTTInfo.xMax, aTTInfo.yMax ) );
+ rInfo.m_nCapHeight = aTTInfo.yMax; // Well ...
+
+ // subset glyphs and get their properties
+ // take care that subset fonts require the NotDef glyph in pos 0
+ int nOrigCount = nGlyphCount;
+ USHORT aShortIDs[ 256 ];
+ sal_uInt8 aTempEncs[ 256 ];
+
+ int nNotDef=-1, i;
+ for( i = 0; i < nGlyphCount; ++i )
+ {
+ aTempEncs[i] = pEncoding[i];
+ sal_uInt32 nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK;
+ if( pGlyphIDs[i] & GF_ISCHAR )
+ {
+ bool bVertical = (pGlyphIDs[i] & GF_ROTMASK) != 0;
+ nGlyphIdx = ::MapChar( aSftTTF.get(), sal::static_int_cast<sal_uInt16>(nGlyphIdx), bVertical );
+ if( nGlyphIdx == 0 && pFont->IsSymbolFont() )
+ {
+ // #i12824# emulate symbol aliasing U+FXXX <-> U+0XXX
+ nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK;
+ nGlyphIdx = (nGlyphIdx & 0xF000) ? (nGlyphIdx & 0x00FF) : (nGlyphIdx | 0xF000 );
+ nGlyphIdx = ::MapChar( aSftTTF.get(), sal::static_int_cast<sal_uInt16>(nGlyphIdx), bVertical );
+ }
+ }
+ aShortIDs[i] = static_cast<USHORT>( nGlyphIdx );
+ if( !nGlyphIdx )
+ if( nNotDef < 0 )
+ nNotDef = i; // first NotDef glyph found
+ }
+
+ if( nNotDef != 0 )
+ {
+ // add fake NotDef glyph if needed
+ if( nNotDef < 0 )
+ nNotDef = nGlyphCount++;
+
+ // NotDef glyph must be in pos 0 => swap glyphids
+ aShortIDs[ nNotDef ] = aShortIDs[0];
+ aTempEncs[ nNotDef ] = aTempEncs[0];
+ aShortIDs[0] = 0;
+ aTempEncs[0] = 0;
+ }
+ DBG_ASSERT( nGlyphCount < 257, "too many glyphs for subsetting" );
+
+ // fill pWidth array
+ TTSimpleGlyphMetrics* pMetrics =
+ ::GetTTSimpleGlyphMetrics( aSftTTF.get(), aShortIDs, nGlyphCount, aIFSD.mbVertical );
+ if( !pMetrics )
+ return FALSE;
+ sal_uInt16 nNotDefAdv = pMetrics[0].adv;
+ pMetrics[0].adv = pMetrics[nNotDef].adv;
+ pMetrics[nNotDef].adv = nNotDefAdv;
+ for( i = 0; i < nOrigCount; ++i )
+ pGlyphWidths[i] = pMetrics[i].adv;
+ free( pMetrics );
+
+ // write subset into destination file
+ rtl::OUString aSysPath;
+ if( osl_File_E_None != osl_getSystemPathFromFileURL( rToFile.pData, &aSysPath.pData ) )
+ return FALSE;
+ rtl_TextEncoding aThreadEncoding = osl_getThreadTextEncoding();
+ ByteString aToFile( rtl::OUStringToOString( aSysPath, aThreadEncoding ) );
+ nRC = ::CreateTTFromTTGlyphs( aSftTTF.get(), aToFile.GetBuffer(), aShortIDs,
+ aTempEncs, nGlyphCount, 0, NULL, 0 );
+ return nRC == SF_OK;
+}
+
+//--------------------------------------------------------------------------
+
+const void* Os2SalGraphics::GetEmbedFontData( const ImplFontData* pFont,
+ const sal_Ucs* pUnicodes, sal_Int32* pCharWidths,
+ FontSubsetInfo& rInfo, long* pDataLen )
+{
+ // create matching ImplFontSelectData
+ // we need just enough to get to the font file data
+ ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
+
+ // TODO: much better solution: move SetFont and restoration of old font to caller
+ ScopedFont aOldFont(*this);
+ SetFont( &aIFSD, 0 );
+
+ // get the raw font file data
+ DWORD nFontSize1 = Ft2GetFontData( mhPS, 0, 0, NULL, 0 );
+ if( nFontSize1 == FT2_ERROR || nFontSize1 <= 0 )
+ return NULL;
+ *pDataLen = nFontSize1;
+ void* pData = reinterpret_cast<void*>(new char[ nFontSize1 ]);
+ DWORD nFontSize2 = Ft2GetFontData( mhPS, 0, 0, pData, nFontSize1 );
+ if( nFontSize1 != nFontSize2 )
+ *pDataLen = 0;
+
+ // get important font properties
+ FONTMETRICS aOS2Metric;
+ if (Ft2QueryFontMetrics( mhPS, sizeof( aOS2Metric ), &aOS2Metric ) == GPI_ERROR)
+ *pDataLen = 0;
+ rInfo.m_nFontType = SAL_FONTSUBSETINFO_TYPE_TYPE1;
+ rInfo.m_aPSName = ImplSalGetUniString( aOS2Metric.szFacename );
+ rInfo.m_nAscent = +aOS2Metric.lMaxAscender;
+ rInfo.m_nDescent = -aOS2Metric.lMaxDescender;
+ rInfo.m_aFontBBox = Rectangle( Point( 0, -aOS2Metric.lMaxDescender ),
+ Point( aOS2Metric.lMaxCharInc, aOS2Metric.lMaxAscender+aOS2Metric.lExternalLeading ) );
+ rInfo.m_nCapHeight = aOS2Metric.lMaxAscender; // Well ...
+
+ // get individual character widths
+ for( int i = 0; i < 256; ++i )
+ {
+ LONG nCharWidth = 0;
+ const sal_Ucs cChar = pUnicodes[i];
+ if( !Ft2QueryStringWidthW( mhPS, (LPWSTR)&cChar, 1, &nCharWidth ) )
+ *pDataLen = 0;
+ pCharWidths[i] = nCharWidth;
+ }
+
+ if( !*pDataLen )
+ {
+ FreeEmbedFontData( pData, nFontSize1 );
+ pData = NULL;
+ }
+
+ return pData;
+}
+
+//--------------------------------------------------------------------------
+
+void Os2SalGraphics::FreeEmbedFontData( const void* pData, long /*nLen*/ )
+{
+ delete[] reinterpret_cast<char*>(const_cast<void*>(pData));
+}
+
+const Ucs2SIntMap* Os2SalGraphics::GetFontEncodingVector( const ImplFontData* pFont, const Ucs2OStrMap** pNonEncoded )
+{
+ // TODO: even for builtin fonts we get here... why?
+ if( !pFont->IsEmbeddable() )
+ return NULL;
+
+ // fill the encoding vector
+ Ucs2SIntMap& rMap = *new Ucs2SIntMap;
+#if 0
+ // TODO: get correct encoding vector
+ ImplWinFontData* pWinFontData = reinterpret_cast<ImplWinFontData*>(pFont);
+
+ GLYPHSET aGlyphSet;
+ aGlyphSet.cbThis = sizeof(aGlyphSet);
+ DWORD aW = ::GetFontUnicodeRanges( mhDC, &aGlyphSet);
+#else
+ for( sal_Unicode i = 32; i < 256; ++i )
+ rMap[i] = i;
+ if( pNonEncoded )
+ *pNonEncoded = NULL;
+#endif
+
+ return &rMap;
+}
+
+//--------------------------------------------------------------------------
+
+void Os2SalGraphics::GetGlyphWidths( const ImplFontData* pFont,
+ bool bVertical,
+ Int32Vector& rWidths,
+ Ucs2UIntMap& rUnicodeEnc )
+{
+ // create matching ImplFontSelectData
+ // we need just enough to get to the font file data
+ ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
+
+ // TODO: much better solution: move SetFont and restoration of old font to caller
+ ScopedFont aOldFont(*this);
+
+ float fScale = 0.0;
+ ImplDoSetFont( &aIFSD, fScale, 0);
+
+ if( pFont->IsSubsettable() )
+ {
+ // get raw font file data
+ DWORD nFontSize1 = ::Ft2GetFontData( mhPS, 0, 0, NULL, 0 );
+ if( nFontSize1 == FT2_ERROR )
+ return;
+ ScopedCharArray xRawFontData(new char[ nFontSize1 ]);
+ DWORD nFontSize2 = ::Ft2GetFontData( mhPS, 0, 0, (void*)xRawFontData.get(), nFontSize1 );
+ if( nFontSize1 != nFontSize2 )
+ return;
+
+ // open font file
+ sal_uInt32 nFaceNum = 0;
+ if( !*xRawFontData.get() ) // TTC candidate
+ nFaceNum = ~0U; // indicate "TTC font extracts only"
+
+ ScopedTrueTypeFont aSftTTF;
+ int nRC = aSftTTF.open( xRawFontData.get(), nFontSize1, nFaceNum );
+ if( nRC != SF_OK )
+ return;
+
+ int nGlyphs = GetTTGlyphCount( aSftTTF.get() );
+ if( nGlyphs > 0 )
+ {
+ rWidths.resize(nGlyphs);
+ std::vector<sal_uInt16> aGlyphIds(nGlyphs);
+ for( int i = 0; i < nGlyphs; i++ )
+ aGlyphIds[i] = sal_uInt16(i);
+ TTSimpleGlyphMetrics* pMetrics = ::GetTTSimpleGlyphMetrics( aSftTTF.get(),
+ &aGlyphIds[0],
+ nGlyphs,
+ bVertical ? 1 : 0 );
+ if( pMetrics )
+ {
+ for( int i = 0; i< nGlyphs; i++ )
+ rWidths[i] = pMetrics[i].adv;
+ free( pMetrics );
+ rUnicodeEnc.clear();
+ }
+ const ImplOs2FontData* pWinFont = static_cast<const ImplOs2FontData*>(pFont);
+ ImplFontCharMap* pMap = pWinFont->GetImplFontCharMap();
+ DBG_ASSERT( pMap && pMap->GetCharCount(), "no map" );
+
+ int nCharCount = pMap->GetCharCount();
+ sal_uInt32 nChar = pMap->GetFirstChar();
+ for( int i = 0; i < nCharCount; i++ )
+ {
+ if( nChar < 0x00010000 )
+ {
+ sal_uInt16 nGlyph = ::MapChar( aSftTTF.get(),
+ static_cast<sal_uInt16>(nChar),
+ bVertical ? 1 : 0 );
+ if( nGlyph )
+ rUnicodeEnc[ static_cast<sal_Unicode>(nChar) ] = nGlyph;
+ }
+ nChar = pMap->GetNextChar( nChar );
+ }
+ }
+ }
+ else if( pFont->IsEmbeddable() )
+ {
+ // get individual character widths
+ rWidths.clear();
+ rUnicodeEnc.clear();
+ rWidths.reserve( 224 );
+ for( sal_Unicode i = 32; i < 256; ++i )
+ {
+ int nCharWidth = 0;
+ if( Ft2QueryStringWidthW( mhPS, (LPWSTR)&i, 1, (LONG*)&nCharWidth ) )
+ {
+ rUnicodeEnc[ i ] = rWidths.size();
+ rWidths.push_back( nCharWidth );
+ }
+ }
+ }
+}
+
+//--------------------------------------------------------------------------
+
+void Os2SalGraphics::DrawServerFontLayout( const ServerFontLayout& )
+{}
+
+//--------------------------------------------------------------------------
+
+SystemFontData Os2SalGraphics::GetSysFontData( int nFallbacklevel ) const
+{
+ SystemFontData aSysFontData;
+
+ if (nFallbacklevel >= MAX_FALLBACK) nFallbacklevel = MAX_FALLBACK - 1;
+ if (nFallbacklevel < 0 ) nFallbacklevel = 0;
+
+ aSysFontData.nSize = sizeof( SystemFontData );
+ aSysFontData.hFont = mhFonts[nFallbacklevel];
+ aSysFontData.bFakeBold = false;
+ aSysFontData.bFakeItalic = false;
+ aSysFontData.bAntialias = true;
+ aSysFontData.bVerticalCharacterType = false;
+
+ return aSysFontData;
+}
+
+//--------------------------------------------------------------------------
diff --git a/vcl/os2/source/gdi/salprn.cxx b/vcl/os2/source/gdi/salprn.cxx
new file mode 100644
index 000000000000..1aef34631f2e
--- /dev/null
+++ b/vcl/os2/source/gdi/salprn.cxx
@@ -0,0 +1,1833 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// use this define to disable the DJP support
+// #define NO_DJP
+
+#define INCL_DOSMODULEMGR
+#define INCL_DEV
+#define INCL_SPL
+#define INCL_SPLERRORS
+#define INCL_SPLDOSPRINT
+#define INCL_DEVDJP
+
+#define INCL_GPI
+#define INCL_DOSSEMAPHORES
+#define INCL_PM
+#include <svpm.h>
+#include <pmdjp.h>
+
+#include <string.h>
+
+#define _SV_SALPRN_CXX
+#include <tools/debug.hxx>
+#include <saldata.hxx>
+#include <salinst.h>
+#include <salgdi.h>
+#include <salframe.h>
+#include <vcl/salptype.hxx>
+#include <salprn.h>
+#include <vcl/print.h>
+#include <vcl/jobset.h>
+
+#ifndef __H_FT2LIB
+#include <wingdi.h>
+#include <ft2lib.h>
+#endif
+
+// =======================================================================
+
+// -----------------------
+// - struct ImplFormInfo -
+// -----------------------
+
+struct ImplFormInfo
+{
+ long mnPaperWidth;
+ long mnPaperHeight;
+#ifndef NO_DJP
+ DJPT_PAPERSIZE mnId;
+#endif
+};
+
+// =======================================================================
+
+// -----------------------
+// - struct ImplTrayInfo -
+// -----------------------
+
+struct ImplTrayInfo
+{
+ CHAR maName[32];
+ CHAR maDisplayName[64];
+ DJPT_TRAYTYPE mnId;
+
+ ImplTrayInfo( const char* pTrayName,
+ const char* pTrayDisplayName )
+ {
+ strcpy( maName, pTrayName);
+ strcpy( maDisplayName, pTrayDisplayName);
+ }
+};
+
+// =======================================================================
+
+struct ImplQueueSalSysData
+{
+ ByteString maPrinterName; // pszPrinters
+ ByteString maName; // pszName bzw. LogAddress
+ ByteString maOrgDriverName; // pszDriverName (maDriverName.maDeviceName)
+ ByteString maDriverName; // pszDriverName bis .
+ ByteString maDeviceName; // pszDriverName nach .
+ PDRIVDATA mpDrivData;
+
+ ImplQueueSalSysData( const ByteString& rPrinterName,
+ const ByteString& rName,
+ const ByteString& rDriverName,
+ const ByteString& rDeviceName,
+ const ByteString& rOrgDriverName,
+ PDRIVDATA pDrivData );
+ ~ImplQueueSalSysData();
+};
+
+// -----------------------------------------------------------------------
+
+ImplQueueSalSysData::ImplQueueSalSysData( const ByteString& rPrinterName,
+ const ByteString& rName,
+ const ByteString& rOrgDriverName,
+ const ByteString& rDriverName,
+ const ByteString& rDeviceName,
+ PDRIVDATA pDrivData ) :
+ maPrinterName( rPrinterName ),
+ maName( rName ),
+ maOrgDriverName( rName ),
+ maDriverName( rDriverName ),
+ maDeviceName( rDeviceName )
+{
+ if ( pDrivData )
+ {
+ mpDrivData = (PDRIVDATA)new BYTE[pDrivData->cb];
+ memcpy( mpDrivData, pDrivData, pDrivData->cb );
+ }
+ else
+ mpDrivData = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+ImplQueueSalSysData::~ImplQueueSalSysData()
+{
+ delete mpDrivData;
+}
+
+// =======================================================================
+
+static ULONG ImplPMQueueStatusToSal( USHORT nPMStatus )
+{
+ ULONG nStatus = 0;
+ if ( nPMStatus & PRQ3_PAUSED )
+ nStatus |= QUEUE_STATUS_PAUSED;
+ if ( nPMStatus & PRQ3_PENDING )
+ nStatus |= QUEUE_STATUS_PENDING_DELETION;
+ if ( !nStatus )
+ nStatus |= QUEUE_STATUS_READY;
+ return nStatus;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList )
+{
+ APIRET rc;
+ ULONG nNeeded;
+ ULONG nReturned;
+ ULONG nTotal;
+
+ // query needed size of the buffer for the QueueInfo
+ rc = SplEnumQueue( (PSZ)NULL, 3, NULL, 0, &nReturned, &nTotal, &nNeeded, NULL );
+ if( nNeeded == 0 )
+ return;
+
+ // create the buffer for the QueueInfo
+ PCHAR pQueueData = new CHAR[nNeeded];
+
+ // query QueueInfos
+ rc = SplEnumQueue( (PSZ)NULL, 3, pQueueData, nNeeded, &nReturned, &nTotal, &nNeeded, NULL );
+
+ PPRQINFO3 pPrqInfo = (PPRQINFO3)pQueueData;
+ for ( int i = 0; i < nReturned; i++ )
+ {
+ // create entry for the QueueInfo array
+ SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo;
+
+ ByteString aOrgDriverName( pPrqInfo->pszDriverName);
+ ByteString aName( pPrqInfo->pszName);
+ pInfo->maDriver = ::rtl::OStringToOUString (aOrgDriverName, gsl_getSystemTextEncoding());
+ pInfo->maPrinterName = ::rtl::OStringToOUString (pPrqInfo->pszComment, gsl_getSystemTextEncoding());
+ pInfo->maLocation = ::rtl::OStringToOUString (aName, gsl_getSystemTextEncoding());
+ pInfo->mnStatus = ImplPMQueueStatusToSal( pPrqInfo->fsStatus );
+ pInfo->mnJobs = pPrqInfo->cJobs;
+ // pInfo->maComment = !!!
+
+ // Feststellen, ob Name doppelt
+ PPRQINFO3 pTempPrqInfo = (PPRQINFO3)pQueueData;
+ for ( int j = 0; j < nReturned; j++ )
+ {
+ // Wenn Name doppelt, erweitern wir diesen um die Location
+ if ( (j != i) &&
+ (strcmp( pPrqInfo->pszComment, pTempPrqInfo->pszComment ) == 0) )
+ {
+ pInfo->maPrinterName += ';';
+ pInfo->maPrinterName += pInfo->maLocation;
+ }
+ pTempPrqInfo++;
+ }
+
+ // pszDriver in DriverName (bis .) und DeviceName (nach .) aufsplitten
+ PSZ pDriverName;
+ PSZ pDeviceName;
+ if ( (pDriverName = strchr( pPrqInfo->pszDriverName, '.' )) != 0 )
+ {
+ *pDriverName = 0;
+ pDeviceName = pDriverName + 1;
+ }
+ else
+ pDeviceName = NULL;
+
+ // Alle Bytes hinter dem DeviceNamen auf 0 initialisieren, damit
+ // ein memcmp vom JobSetup auch funktioniert
+ if ( pPrqInfo->pDriverData &&
+ (pPrqInfo->pDriverData->cb >= sizeof( pPrqInfo->pDriverData )) )
+ {
+ int nDeviceNameLen = strlen( pPrqInfo->pDriverData->szDeviceName );
+ memset( pPrqInfo->pDriverData->szDeviceName+nDeviceNameLen,
+ 0,
+ sizeof( pPrqInfo->pDriverData->szDeviceName )-nDeviceNameLen );
+ }
+
+ // save driver data and driver names
+ ByteString aPrinterName( pPrqInfo->pszPrinters);
+ ByteString aDriverName( pPrqInfo->pszDriverName);
+ ByteString aDeviceName;
+ if ( pDeviceName )
+ aDeviceName = pDeviceName;
+ pInfo->mpSysData = new ImplQueueSalSysData( aPrinterName, aName,
+ aOrgDriverName,
+ aDriverName, aDeviceName,
+ pPrqInfo->pDriverData );
+
+ // add queue to the list
+ pList->Add( pInfo );
+
+ // increment to next element of the QueueInfo array
+ pPrqInfo++;
+ }
+
+ delete [] pQueueData;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalInstance::GetPrinterQueueState( SalPrinterQueueInfo* pInfo )
+{
+ APIRET rc;
+ ULONG nNeeded;
+ ULONG nReturned;
+ ULONG nTotal;
+
+ // query needed size of the buffer for the QueueInfo
+ rc = SplEnumQueue( (PSZ)NULL, 3, NULL, 0, &nReturned, &nTotal, &nNeeded, NULL );
+ if( nNeeded == 0 )
+ return;
+
+ // create the buffer for the QueueInfo
+ PCHAR pQueueData = new CHAR[nNeeded];
+
+ // query QueueInfos
+ rc = SplEnumQueue( (PSZ)NULL, 3, pQueueData, nNeeded, &nReturned, &nTotal, &nNeeded, NULL );
+
+ PPRQINFO3 pPrqInfo = (PPRQINFO3)pQueueData;
+ for ( int i = 0; i < nReturned; i++ )
+ {
+ ImplQueueSalSysData* pSysData = (ImplQueueSalSysData*)(pInfo->mpSysData);
+ if ( pSysData->maPrinterName.Equals( pPrqInfo->pszPrinters ) &&
+ pSysData->maName.Equals( pPrqInfo->pszName ) &&
+ pSysData->maOrgDriverName.Equals( pPrqInfo->pszDriverName ) )
+ {
+ pInfo->mnStatus = ImplPMQueueStatusToSal( pPrqInfo->fsStatus );
+ pInfo->mnJobs = pPrqInfo->cJobs;
+ break;
+ }
+
+ // increment to next element of the QueueInfo array
+ pPrqInfo++;
+ }
+
+ delete [] pQueueData;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo )
+{
+ delete ((ImplQueueSalSysData*)(pInfo->mpSysData));
+ delete pInfo;
+}
+
+// -----------------------------------------------------------------------
+
+XubString Os2SalInstance::GetDefaultPrinter()
+{
+ APIRET rc;
+ ULONG nNeeded;
+ ULONG nReturned;
+ ULONG nTotal;
+ char szQueueName[255];
+ XubString aDefaultName;
+
+ // query default queue
+ if ( !PrfQueryProfileString( HINI_PROFILE, SPL_INI_SPOOLER, "QUEUE", 0, szQueueName, sizeof( szQueueName ) ) )
+ return aDefaultName;
+
+ // extract first queue name
+ PSZ pStr;
+ if ( (pStr = strchr( szQueueName, ';' )) != 0 )
+ *pStr = 0;
+
+ // query needed size of the buffer for the QueueInfo
+ rc = SplEnumQueue( (PSZ)NULL, 3, NULL, 0, &nReturned, &nTotal, &nNeeded, NULL );
+ if ( nNeeded == 0 )
+ return aDefaultName;
+
+ // create the buffer for the QueueInfo
+ PCHAR pQueueData = new CHAR[ nNeeded ];
+
+ // query QueueInfos
+ rc = SplEnumQueue ((PSZ)NULL, 3, pQueueData, nNeeded, &nReturned, &nTotal, &nNeeded, NULL );
+
+ // find printer name for default queue
+ PPRQINFO3 pPrqInfo = (PPRQINFO3) pQueueData;
+ for ( int i = 0; i < nReturned; i++ )
+ {
+ if ( strcmp( pPrqInfo->pszName, szQueueName ) == 0 )
+ {
+ aDefaultName = ::rtl::OStringToOUString (pPrqInfo->pszComment, gsl_getSystemTextEncoding());
+
+ // Feststellen, ob Name doppelt
+ PPRQINFO3 pTempPrqInfo = (PPRQINFO3)pQueueData;
+ for ( int j = 0; j < nReturned; j++ )
+ {
+ // Wenn Name doppelt, erweitern wir diesen um die Location
+ if ( (j != i) &&
+ (strcmp( pPrqInfo->pszComment, pTempPrqInfo->pszComment ) == 0) )
+ {
+ String pszName( ::rtl::OStringToOUString (pPrqInfo->pszName, gsl_getSystemTextEncoding()));
+ aDefaultName += ';';
+ aDefaultName += pszName;
+ }
+ pTempPrqInfo++;
+ }
+ break;
+ }
+
+ // increment to next element of the QueueInfo array
+ pPrqInfo++;
+ }
+
+ delete [] pQueueData;
+
+ return aDefaultName;
+}
+
+// =======================================================================
+
+static void* ImplAllocPrnMemory( size_t n )
+{
+ return calloc( n, 1);
+}
+
+// -----------------------------------------------------------------------
+
+inline void ImplFreePrnMemory( void* p )
+{
+ free( p );
+}
+
+// -----------------------------------------------------------------------
+
+static PDRIVDATA ImplPrnDrivData( const ImplJobSetup* pSetupData )
+{
+ // Diese Funktion wird eingesetzt, damit Druckertreiber nicht auf
+ // unseren Daten arbeiten, da es durch Konfigurationsprobleme
+ // sein kann, das der Druckertreiber bei uns Daten ueberschreibt.
+ // Durch diese vorgehensweise werden einige Abstuerze vermieden, bzw.
+ // sind dadurch leichter zu finden
+
+ if ( !pSetupData->mpDriverData )
+ return NULL;
+
+ DBG_ASSERT( ((PDRIVDATA)(pSetupData->mpDriverData))->cb == pSetupData->mnDriverDataLen,
+ "ImplPrnDrivData() - SetupDataLen != DriverDataLen" );
+
+ PDRIVDATA pDrivData = (PDRIVDATA)ImplAllocPrnMemory( pSetupData->mnDriverDataLen );
+ memcpy( pDrivData, pSetupData->mpDriverData, pSetupData->mnDriverDataLen );
+ return pDrivData;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplUpdateSetupData( const PDRIVDATA pDrivData, ImplJobSetup* pSetupData )
+{
+ // Diese Funktion wird eingesetzt, damit Druckertreiber nicht auf
+ // unseren Daten arbeiten, da es durch Konfigurationsprobleme
+ // sein kann, das der Druckertreiber bei uns Daten ueberschreibt.
+ // Durch diese vorgehensweise werden einige Abstuerze vermieden, bzw.
+ // sind dadurch leichter zu finden
+
+ if ( !pDrivData || !pDrivData->cb )
+ {
+ if ( pSetupData->mpDriverData )
+ rtl_freeMemory( pSetupData->mpDriverData );
+ pSetupData->mpDriverData = NULL;
+ pSetupData->mnDriverDataLen = 0;
+ }
+ else
+ {
+ // Alle Bytes hinter dem DeviceNamen auf 0 initialisieren, damit
+ // ein memcmp vom JobSetup auch funktioniert
+ if ( pDrivData->cb >= sizeof( pDrivData ) )
+ {
+ int nDeviceNameLen = strlen( pDrivData->szDeviceName );
+ memset( pDrivData->szDeviceName+nDeviceNameLen,
+ 0,
+ sizeof( pDrivData->szDeviceName )-nDeviceNameLen );
+ }
+
+ if ( pSetupData->mpDriverData )
+ {
+ if ( pSetupData->mnDriverDataLen != pDrivData->cb )
+ rtl_freeMemory( pSetupData->mpDriverData );
+ pSetupData->mpDriverData = (BYTE*)rtl_allocateMemory( pDrivData->cb);
+ }
+ else
+ pSetupData->mpDriverData = (BYTE*)rtl_allocateMemory( pDrivData->cb);
+ pSetupData->mnDriverDataLen = pDrivData->cb;
+ memcpy( pSetupData->mpDriverData, pDrivData, pDrivData->cb );
+ }
+
+ if ( pDrivData )
+ ImplFreePrnMemory( pDrivData );
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplPaperSizeEqual( long nPaperWidth1, long nPaperHeight1,
+ long nPaperWidth2, long nPaperHeight2 )
+{
+ return (((nPaperWidth1 >= nPaperWidth2-1) && (nPaperWidth1 <= nPaperWidth2+1)) &&
+ ((nPaperHeight1 >= nPaperHeight2-1) && (nPaperHeight1 <= nPaperHeight2+1)));
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplIsDriverDJPEnabled( HDC hDC )
+{
+#ifdef NO_DJP
+ return FALSE;
+#else
+ // Ueber OS2-Ini kann DJP disablte werden
+ if ( !PrfQueryProfileInt( HINI_PROFILE, SAL_PROFILE_APPNAME, SAL_PROFILE_USEDJP, 1 ) )
+ return FALSE;
+
+ // Testen, ob DJP-Interface am Drucker vorhanden
+ LONG lQuery;
+ APIRET rc;
+
+ lQuery = DEVESC_QUERYSIZE;
+ rc = DevEscape( hDC,
+ DEVESC_QUERYESCSUPPORT,
+ sizeof( lQuery ),
+ (PBYTE)&lQuery,
+ 0,
+ (PBYTE)NULL );
+ if ( DEV_OK != rc )
+ return FALSE;
+
+ lQuery = DEVESC_QUERYJOBPROPERTIES;
+ rc = DevEscape( hDC,
+ DEVESC_QUERYESCSUPPORT,
+ sizeof( lQuery ),
+ (PBYTE)&lQuery,
+ 0,
+ (PBYTE)NULL );
+ if ( DEV_OK != rc )
+ return FALSE;
+
+ lQuery = DEVESC_SETJOBPROPERTIES;
+ rc = DevEscape( hDC,
+ DEVESC_QUERYESCSUPPORT,
+ sizeof( lQuery ),
+ (PBYTE)&lQuery,
+ 0,
+ (PBYTE)NULL );
+ if ( DEV_OK != rc )
+ return FALSE;
+
+ return TRUE;
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplFormatInputList( PDJP_ITEM pDJP, PQUERYTUPLE pTuple )
+{
+ // Loop through the query elements
+ BOOL fContinue = TRUE;
+ do
+ {
+ pDJP->cb = sizeof (DJP_ITEM);
+ pDJP->ulProperty = pTuple->ulProperty;
+ pDJP->lType = pTuple->lType;
+ pDJP->ulNumReturned = 0;
+ pDJP->ulValue = DJP_NONE;
+
+ // at EOL?
+ fContinue = DJP_NONE != pTuple->ulProperty;
+
+ // Move to next item structure and tuplet
+ pDJP++;
+ pTuple++;
+ }
+ while ( fContinue );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplFreeFormAndTrayList( Os2SalInfoPrinter* pOs2SalInfoPrinter )
+{
+ if ( pOs2SalInfoPrinter->mnFormCount )
+ {
+ for ( USHORT i = 0; i < pOs2SalInfoPrinter->mnFormCount; i++ )
+ delete pOs2SalInfoPrinter->mpFormArray[i];
+ delete [] pOs2SalInfoPrinter->mpFormArray;
+ pOs2SalInfoPrinter->mnFormCount = 0;
+ }
+
+ if ( pOs2SalInfoPrinter->mnTrayCount )
+ {
+ for ( USHORT i = 0; i < pOs2SalInfoPrinter->mnTrayCount; i++ )
+ delete pOs2SalInfoPrinter->mpTrayArray[i];
+ delete [] pOs2SalInfoPrinter->mpTrayArray;
+ pOs2SalInfoPrinter->mnTrayCount = 0;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplGetFormAndTrayList( Os2SalInfoPrinter* pOs2SalInfoPrinter, const ImplJobSetup* pSetupData )
+{
+ ImplFreeFormAndTrayList( pOs2SalInfoPrinter );
+
+ LONG alQuery[] =
+ {
+ 0, 0, // First two members of QUERYSIZE
+ DJP_CJ_FORM, DJP_ALL,
+ DJP_CJ_TRAYNAME, DJP_ALL,
+ DJP_NONE, DJP_NONE // EOL marker
+ };
+
+ APIRET rc;
+ PQUERYSIZE pQuerySize = (PQUERYSIZE)alQuery;
+ PBYTE pBuffer = NULL;
+ LONG nAlloc = 0;
+ PDRIVDATA pCopyDrivData = ImplPrnDrivData( pSetupData );
+ LONG nDrivDataSize = pCopyDrivData->cb;
+ PBYTE pDrivData = (PBYTE)pCopyDrivData;
+
+ // find out how many bytes to allocate
+ pQuerySize->cb = sizeof( alQuery );
+ rc = DevEscape( pOs2SalInfoPrinter->mhDC,
+ DEVESC_QUERYSIZE,
+ sizeof( alQuery ),
+ (PBYTE)pQuerySize,
+ &nDrivDataSize,
+ pDrivData );
+ if ( DEV_OK != rc )
+ {
+ ImplFreePrnMemory( pCopyDrivData );
+ return;
+ }
+
+ // allocate the memory
+ nAlloc = pQuerySize->ulSizeNeeded;
+ pBuffer = (PBYTE)new BYTE[nAlloc];
+
+ // set up the input
+ PDJP_ITEM pDJP = (PDJP_ITEM)pBuffer;
+ ImplFormatInputList( pDJP, pQuerySize->aTuples );
+
+ // do it!
+ rc = DevEscape( pOs2SalInfoPrinter->mhDC,
+ DEVESC_QUERYJOBPROPERTIES,
+ nAlloc,
+ pBuffer,
+ &nDrivDataSize,
+ pDrivData );
+ ImplFreePrnMemory( pCopyDrivData );
+
+ if ( (DEV_OK == rc) || (DEV_WARNING == rc) )
+ {
+ // Loop through the query elements
+ PQUERYTUPLE pTuple = pQuerySize->aTuples;
+ while ( DJP_NONE != pTuple->ulProperty )
+ {
+ if ( pDJP->ulProperty == DJP_CJ_FORM )
+ {
+ if ( pDJP->ulNumReturned )
+ {
+ PDJPT_FORM pElm = DJP_ELEMENTP( *pDJP, DJPT_FORM );
+
+ pOs2SalInfoPrinter->mnFormCount = pDJP->ulNumReturned;
+ pOs2SalInfoPrinter->mpFormArray = new PIMPLFORMINFO[pOs2SalInfoPrinter->mnFormCount];
+ for( int i = 0; i < pDJP->ulNumReturned; i++, pElm++ )
+ {
+ ImplFormInfo* pInfo = new ImplFormInfo;
+ pInfo->mnPaperWidth = pElm->hcInfo.cx;
+ pInfo->mnPaperHeight = pElm->hcInfo.cy;
+ pInfo->mnId = pElm->djppsFormID;
+ pOs2SalInfoPrinter->mpFormArray[i] = pInfo;
+ }
+ }
+ }
+ else if ( pDJP->ulProperty == DJP_CJ_TRAYNAME )
+ {
+ if ( pDJP->ulNumReturned )
+ {
+ PDJPT_TRAYNAME pElm = DJP_ELEMENTP( *pDJP, DJPT_TRAYNAME );
+
+ pOs2SalInfoPrinter->mnTrayCount = pDJP->ulNumReturned;
+ pOs2SalInfoPrinter->mpTrayArray = new PIMPLTRAYINFO[pOs2SalInfoPrinter->mnTrayCount];
+ for( int i = 0; i < pDJP->ulNumReturned; i++, pElm++ )
+ {
+ ImplTrayInfo* pInfo = new ImplTrayInfo( pElm->szTrayname, pElm->szDisplayTrayname );
+ pInfo->mnId = pElm->djpttTrayID;
+ pOs2SalInfoPrinter->mpTrayArray[i] = pInfo;
+ }
+ }
+ }
+
+ pDJP = DJP_NEXT_STRUCTP( pDJP );
+ pTuple++;
+ }
+ }
+
+ delete [] pBuffer;
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplGetCurrentSettings( Os2SalInfoPrinter* pOs2SalInfoPrinter, ImplJobSetup* pSetupData )
+{
+ // Um den aktuellen Tray zu ermitteln, brauchen wir auch die Listen dazu
+ if ( !pOs2SalInfoPrinter->mnFormCount )
+ ImplGetFormAndTrayList( pOs2SalInfoPrinter, pSetupData );
+
+ LONG alQuery[] =
+ {
+ 0, 0, // First two members of QUERYSIZE
+ DJP_SJ_ORIENTATION, DJP_CURRENT,
+ DJP_CJ_FORM, DJP_CURRENT,
+ DJP_NONE, DJP_NONE // EOL marker
+ };
+
+ APIRET rc;
+ PQUERYSIZE pQuerySize = (PQUERYSIZE)alQuery;
+ PBYTE pBuffer = NULL;
+ LONG nAlloc = 0;
+ PDRIVDATA pCopyDrivData = ImplPrnDrivData( pSetupData );
+ LONG nDrivDataSize = pCopyDrivData->cb;
+ PBYTE pDrivData = (PBYTE)pCopyDrivData;
+ BOOL bResult;
+
+ // find out how many bytes to allocate
+ pQuerySize->cb = sizeof( alQuery );
+ rc = DevEscape( pOs2SalInfoPrinter->mhDC,
+ DEVESC_QUERYSIZE,
+ sizeof( alQuery ),
+ (PBYTE)pQuerySize,
+ &nDrivDataSize,
+ pDrivData );
+ if ( DEV_OK != rc )
+ {
+ ImplFreePrnMemory( pCopyDrivData );
+ return FALSE;
+ }
+
+ // allocate the memory
+ nAlloc = pQuerySize->ulSizeNeeded;
+ pBuffer = (PBYTE)new BYTE[nAlloc];
+
+ // set up the input
+ PDJP_ITEM pDJP = (PDJP_ITEM)pBuffer;
+ ImplFormatInputList( pDJP, pQuerySize->aTuples );
+
+ rc = DevEscape( pOs2SalInfoPrinter->mhDC,
+ DEVESC_QUERYJOBPROPERTIES,
+ nAlloc,
+ pBuffer,
+ &nDrivDataSize,
+ pDrivData );
+ if ( (DEV_OK == rc) || (DEV_WARNING == rc) )
+ {
+ // aktuelle Setup-Daten uebernehmen
+ ImplUpdateSetupData( pCopyDrivData, pSetupData );
+
+ // Loop through the query elements
+ PQUERYTUPLE pTuple = pQuerySize->aTuples;
+ while ( DJP_NONE != pTuple->ulProperty )
+ {
+ if ( pDJP->ulProperty == DJP_SJ_ORIENTATION )
+ {
+ if ( pDJP->ulNumReturned )
+ {
+ PDJPT_ORIENTATION pElm = DJP_ELEMENTP( *pDJP, DJPT_ORIENTATION );
+ if ( (DJP_ORI_PORTRAIT == *pElm) || (DJP_ORI_REV_PORTRAIT == *pElm) )
+ pSetupData->meOrientation = ORIENTATION_PORTRAIT;
+ else
+ pSetupData->meOrientation = ORIENTATION_LANDSCAPE;
+ }
+ }
+ else if ( pDJP->ulProperty == DJP_CJ_FORM )
+ {
+ if ( pDJP->ulNumReturned )
+ {
+ PDJPT_FORM pElm = DJP_ELEMENTP( *pDJP, DJPT_FORM );
+
+ pSetupData->mnPaperWidth = pElm->hcInfo.cx*100;
+ pSetupData->mnPaperHeight = pElm->hcInfo.cy*100;
+ switch( pElm->djppsFormID )
+ {
+ case DJP_PSI_A3:
+ pSetupData->mePaperFormat = PAPER_A3;
+ break;
+
+ case DJP_PSI_A4:
+ pSetupData->mePaperFormat = PAPER_A4;
+ break;
+
+ case DJP_PSI_A5:
+ pSetupData->mePaperFormat = PAPER_A5;
+ break;
+
+ case DJP_PSI_B4:
+ pSetupData->mePaperFormat = PAPER_B4;
+ break;
+
+ case DJP_PSI_B5:
+ pSetupData->mePaperFormat = PAPER_B5;
+ break;
+
+ case DJP_PSI_LETTER:
+ pSetupData->mePaperFormat = PAPER_LETTER;
+ break;
+
+ case DJP_PSI_LEGAL:
+ pSetupData->mePaperFormat = PAPER_LEGAL;
+ break;
+
+ case DJP_PSI_TABLOID:
+ pSetupData->mePaperFormat = PAPER_TABLOID;
+ break;
+
+ default:
+ pSetupData->mePaperFormat = PAPER_USER;
+ break;
+ }
+
+ // Wir suchen zuerst ueber den Namen/Id und dann ueber die Id
+ BOOL bTrayFound = FALSE;
+ USHORT j;
+ for ( j = 0; j < pOs2SalInfoPrinter->mnTrayCount; j++ )
+ {
+ if ( (pOs2SalInfoPrinter->mpTrayArray[j]->mnId == pElm->djpttTrayID) &&
+ (pOs2SalInfoPrinter->mpTrayArray[j]->maName == pElm->szTrayname) )
+ {
+ pSetupData->mnPaperBin = j;
+ bTrayFound = TRUE;
+ break;
+ }
+ }
+ if ( !bTrayFound )
+ {
+ for ( j = 0; j < pOs2SalInfoPrinter->mnTrayCount; j++ )
+ {
+ if ( pOs2SalInfoPrinter->mpTrayArray[j]->mnId == pElm->djpttTrayID )
+ {
+ pSetupData->mnPaperBin = j;
+ bTrayFound = TRUE;
+ break;
+ }
+ }
+ }
+ // Wenn wir Ihn immer noch nicht gefunden haben, setzen
+ // wir ihn auf DontKnow
+ if ( !bTrayFound )
+ pSetupData->mnPaperBin = 0xFFFF;
+ }
+ }
+
+ pDJP = DJP_NEXT_STRUCTP( pDJP );
+ pTuple++;
+ }
+
+ bResult = TRUE;
+ }
+ else
+ {
+ ImplFreePrnMemory( pCopyDrivData );
+ bResult = FALSE;
+ }
+
+ delete [] pBuffer;
+
+ return bResult;
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplSetOrientation( HDC hPrinterDC, PDRIVDATA pDriverData,
+ Orientation eOrientation )
+{
+ LONG alQuery[] =
+ {
+ 0, 0, // First two members of QUERYSIZE
+ DJP_SJ_ORIENTATION, DJP_CURRENT,
+ DJP_NONE, DJP_NONE // EOL marker
+ };
+
+ APIRET rc;
+ PQUERYSIZE pQuerySize = (PQUERYSIZE)alQuery;
+ PBYTE pBuffer = NULL;
+ LONG nAlloc = 0;
+ LONG nDrivDataSize = pDriverData->cb;
+
+ // find out how many bytes to allocate
+ pQuerySize->cb = sizeof( alQuery );
+ rc = DevEscape( hPrinterDC,
+ DEVESC_QUERYSIZE,
+ sizeof( alQuery ),
+ (PBYTE)pQuerySize,
+ &nDrivDataSize,
+ (PBYTE)pDriverData );
+ if ( DEV_OK != rc )
+ return FALSE;
+
+ // allocate the memory
+ nAlloc = pQuerySize->ulSizeNeeded;
+ pBuffer = (PBYTE)new BYTE[nAlloc];
+
+ // set up the input
+ PDJP_ITEM pDJP = (PDJP_ITEM)pBuffer;
+ ImplFormatInputList( pDJP, pQuerySize->aTuples );
+
+ pDJP->cb = sizeof( DJP_ITEM );
+ pDJP->ulProperty = DJP_SJ_ORIENTATION;
+ pDJP->lType = DJP_CURRENT;
+ pDJP->ulValue = (eOrientation == ORIENTATION_PORTRAIT)
+ ? DJP_ORI_PORTRAIT
+ : DJP_ORI_LANDSCAPE;
+
+ // do it!
+ rc = DevEscape( hPrinterDC,
+ DEVESC_SETJOBPROPERTIES,
+ nAlloc,
+ pBuffer,
+ &nDrivDataSize,
+ (PBYTE)pDriverData );
+
+ delete [] pBuffer;
+
+ return ((DEV_OK == rc) || (DEV_WARNING == rc));
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplSetPaperSize( HDC hPrinterDC, PDRIVDATA pDriverData,
+ DJPT_PAPERSIZE nOS2PaperFormat )
+{
+ LONG alQuery[] =
+ {
+ 0, 0, // First two members of QUERYSIZE
+ DJP_SJ_PAPERSIZE, DJP_CURRENT,
+ DJP_NONE, DJP_NONE // EOL marker
+ };
+
+ APIRET rc;
+ PQUERYSIZE pQuerySize = (PQUERYSIZE)alQuery;
+ PBYTE pBuffer = NULL;
+ LONG nAlloc = 0;
+ LONG nDrivDataSize = pDriverData->cb;
+
+ // find out how many bytes to allocate
+ pQuerySize->cb = sizeof( alQuery );
+ rc = DevEscape( hPrinterDC,
+ DEVESC_QUERYSIZE,
+ sizeof( alQuery ),
+ (PBYTE)pQuerySize,
+ &nDrivDataSize,
+ (PBYTE)pDriverData );
+ if ( DEV_OK != rc )
+ return FALSE;
+
+ // allocate the memory
+ nAlloc = pQuerySize->ulSizeNeeded;
+ pBuffer = (PBYTE)new BYTE[nAlloc];
+
+ // set up the input
+ PDJP_ITEM pDJP = (PDJP_ITEM)pBuffer;
+ PDJP_ITEM pStartDJP = pDJP;
+ ImplFormatInputList( pDJP, pQuerySize->aTuples );
+
+ // Neue Daten zuweisen
+ pDJP->cb = sizeof( DJP_ITEM );
+ pDJP->ulProperty = DJP_SJ_PAPERSIZE;
+ pDJP->lType = DJP_CURRENT;
+ pDJP->ulValue = nOS2PaperFormat;
+
+ // und setzen
+ rc = DevEscape( hPrinterDC,
+ DEVESC_SETJOBPROPERTIES,
+ nAlloc,
+ pBuffer,
+ &nDrivDataSize,
+ (PBYTE)pDriverData );
+
+ delete [] pBuffer;
+
+ return ((DEV_OK == rc) || (DEV_WARNING == rc));
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplSetPaperBin( HDC hPrinterDC, PDRIVDATA pDriverData,
+ ImplTrayInfo* pTrayInfo )
+{
+ LONG alQuery[] =
+ {
+ 0, 0, // First two members of QUERYSIZE
+ DJP_SJ_TRAYTYPE, DJP_CURRENT,
+ DJP_NONE, DJP_NONE // EOL marker
+ };
+
+ APIRET rc;
+ PQUERYSIZE pQuerySize = (PQUERYSIZE)alQuery;
+ PBYTE pBuffer = NULL;
+ LONG nAlloc = 0;
+ LONG nDrivDataSize = pDriverData->cb;
+
+ // find out how many bytes to allocate
+ pQuerySize->cb = sizeof( alQuery );
+ rc = DevEscape( hPrinterDC,
+ DEVESC_QUERYSIZE,
+ sizeof( alQuery ),
+ (PBYTE)pQuerySize,
+ &nDrivDataSize,
+ (PBYTE)pDriverData );
+ if ( DEV_OK != rc )
+ return FALSE;
+
+ // allocate the memory
+ nAlloc = pQuerySize->ulSizeNeeded;
+ pBuffer = (PBYTE)new BYTE[nAlloc];
+
+ // set up the input
+ PDJP_ITEM pDJP = (PDJP_ITEM)pBuffer;
+ ImplFormatInputList( pDJP, pQuerySize->aTuples );
+
+ // Neue Daten zuweisen
+ pDJP->cb = sizeof( DJP_ITEM );
+ pDJP->ulProperty = DJP_SJ_TRAYTYPE;
+ pDJP->lType = DJP_CURRENT;
+ pDJP->ulValue = pTrayInfo->mnId;
+
+ // und setzen
+ rc = DevEscape( hPrinterDC,
+ DEVESC_SETJOBPROPERTIES,
+ nAlloc,
+ pBuffer,
+ &nDrivDataSize,
+ (PBYTE)pDriverData );
+
+ delete [] pBuffer;
+
+ return ((DEV_OK == rc) || (DEV_WARNING == rc));
+}
+
+// =======================================================================
+
+static BOOL ImplSalCreateInfoPrn( Os2SalInfoPrinter* pPrinter, PDRIVDATA pDriverData,
+ HDC& rDC, HPS& rPS )
+{
+ SalData* pSalData = GetSalData();
+
+ // create info context
+ DEVOPENSTRUC devOpenStruc;
+ memset( &devOpenStruc, 0, sizeof( devOpenStruc ) );
+ devOpenStruc.pszLogAddress = (char*)pPrinter->maName.GetBuffer();
+ devOpenStruc.pszDriverName = (char*)pPrinter->maDriverName.GetBuffer();
+ devOpenStruc.pdriv = pDriverData;
+ devOpenStruc.pszDataType = "PM_Q_STD";
+
+ HDC hDC = DevOpenDC( pSalData->mhAB, OD_INFO, "*",
+ 4, (PDEVOPENDATA)&devOpenStruc, (HDC)NULL);
+ if ( !hDC )
+ return FALSE;
+
+ // create presentation space
+ SIZEL sizel;
+ sizel.cx = 0;
+ sizel.cy = 0;
+ HPS hPS = Ft2CreatePS( pSalData->mhAB, hDC, &sizel, GPIA_ASSOC | GPIT_MICRO | PU_PELS );
+ if ( !hPS )
+ {
+ DevCloseDC( hDC );
+ return FALSE;
+ }
+
+ rDC = hDC;
+ rPS = hPS;
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplSalDestroyInfoPrn( Os2SalInfoPrinter* pPrinter )
+{
+ ImplSalDeInitGraphics( pPrinter->mpGraphics);
+ Ft2Associate( pPrinter->mhPS, 0 );
+ Ft2DestroyPS( pPrinter->mhPS );
+ DevCloseDC( pPrinter->mhDC );
+}
+
+// =======================================================================
+
+SalInfoPrinter* Os2SalInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
+ ImplJobSetup* pSetupData )
+{
+ ImplQueueSalSysData* pSysQueueData = (ImplQueueSalSysData*)(pQueueInfo->mpSysData);
+ Os2SalInfoPrinter* pPrinter = new Os2SalInfoPrinter;
+ pPrinter->maPrinterName = pSysQueueData->maPrinterName;
+ pPrinter->maName = pSysQueueData->maName;
+ pPrinter->maDriverName = pSysQueueData->maDriverName;
+ pPrinter->maDeviceName = pSysQueueData->maDeviceName;
+
+ // Nur Setup-Daten uebernehmen, wenn Treiber und Laenge der Treiberdaten
+ // uebereinstimmt
+ PDRIVDATA pDriverData;
+ BOOL bUpdateDriverData;
+ if ( pSetupData->mpDriverData && pSysQueueData->mpDrivData &&
+ (pSetupData->mnSystem == JOBSETUP_SYSTEM_OS2) &&
+ (pSetupData->mnDriverDataLen == pSysQueueData->mpDrivData->cb) &&
+ (strcmp( ((PDRIVDATA)pSetupData->mpDriverData)->szDeviceName,
+ pSysQueueData->mpDrivData->szDeviceName ) == 0) )
+ {
+ pDriverData = PDRIVDATA( pSetupData->mpDriverData );
+ bUpdateDriverData = FALSE;
+ }
+ else
+ {
+ pDriverData = pSysQueueData->mpDrivData;
+ bUpdateDriverData = TRUE;
+ }
+ if ( pDriverData )
+ pPrinter->maJobSetupDeviceName = pDriverData->szDeviceName;
+
+ if ( !ImplSalCreateInfoPrn( pPrinter, pDriverData,
+ pPrinter->mhDC,
+ pPrinter->mhPS ) )
+ {
+ delete pPrinter;
+ return NULL;
+ }
+
+ // create graphics object for output
+ Os2SalGraphics* pGraphics = new Os2SalGraphics;
+ pGraphics->mhDC = pPrinter->mhDC;
+ pGraphics->mhPS = pPrinter->mhPS;
+ pGraphics->mhWnd = 0;
+ pGraphics->mbPrinter = TRUE;
+ pGraphics->mbVirDev = FALSE;
+ pGraphics->mbWindow = FALSE;
+ pGraphics->mbScreen = FALSE;
+
+ ImplSalInitGraphics( pGraphics );
+ pPrinter->mpGraphics = pGraphics;
+
+ // check printer driver for DJP support
+ pPrinter->mbDJPSupported = ImplIsDriverDJPEnabled( pPrinter->mhDC );
+
+ if ( bUpdateDriverData )
+ {
+ if ( pSetupData->mpDriverData )
+ rtl_freeMemory( pSetupData->mpDriverData);
+ pSetupData->mpDriverData = (BYTE*)rtl_allocateMemory( pDriverData->cb);
+ memcpy( pSetupData->mpDriverData, pDriverData, pDriverData->cb );
+ pSetupData->mnDriverDataLen = pDriverData->cb;
+ }
+
+ // retrieve current settings from printer driver and store them to system independend data!
+ if ( pPrinter->mbDJPSupported )
+ ImplGetCurrentSettings( pPrinter, pSetupData );
+ pSetupData->mnSystem = JOBSETUP_SYSTEM_OS2;
+
+ return pPrinter;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter )
+{
+ delete pPrinter;
+}
+
+// =======================================================================
+
+Os2SalInfoPrinter::Os2SalInfoPrinter()
+{
+ mhDC = 0;
+ mhPS = 0;
+ mpGraphics = NULL;
+ mbGraphics = FALSE;
+ mbDJPSupported = FALSE;
+ mnFormCount = 0;
+ mpFormArray = NULL;
+ mnTrayCount = 0;
+ mpTrayArray = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+Os2SalInfoPrinter::~Os2SalInfoPrinter()
+{
+ if ( mpGraphics )
+ {
+ ImplSalDestroyInfoPrn( this );
+ delete mpGraphics;
+ }
+
+ ImplFreeFormAndTrayList( this );
+}
+
+// -----------------------------------------------------------------------
+
+SalGraphics* Os2SalInfoPrinter::GetGraphics()
+{
+ if ( mbGraphics )
+ return NULL;
+
+ if ( mpGraphics )
+ mbGraphics = TRUE;
+
+ return mpGraphics;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalInfoPrinter::ReleaseGraphics( SalGraphics* )
+{
+ mbGraphics = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Os2SalInfoPrinter::Setup( SalFrame* pFrame, ImplJobSetup* pSetupData )
+{
+ PDRIVDATA pDrivData = ImplPrnDrivData( pSetupData );
+ if ( !pDrivData )
+ return FALSE;
+
+ APIRET rc = DevPostDeviceModes( GetSalData()->mhAB, pDrivData,
+ maDriverName.GetBuffer(),
+ maDeviceName.GetBuffer(),
+ maPrinterName.GetBuffer(),
+ DPDM_POSTJOBPROP );
+ if ( rc == DEV_OK )
+ {
+ ImplUpdateSetupData( pDrivData, pSetupData );
+
+ // update DC and PS
+ HDC hDC;
+ HPS hPS;
+ if ( !ImplSalCreateInfoPrn( this, (PDRIVDATA)(pSetupData->mpDriverData), hDC, hPS ) )
+ return FALSE;
+
+ // Alten Printer DC/PS zerstoeren
+ ImplSalDestroyInfoPrn( this );
+
+ // Neue Daten setzen und initialisieren
+ mhDC = hDC;
+ mhPS = hPS;
+ mpGraphics->mhDC = mhDC;
+ mpGraphics->mhPS = mhPS;
+ ImplSalInitGraphics( mpGraphics );
+
+ // retrieve current settings from printer driver and store them to system independend data!
+ ImplFreeFormAndTrayList( this );
+ if ( mbDJPSupported )
+ ImplGetCurrentSettings( this, pSetupData );
+
+ return TRUE;
+ }
+ else
+ {
+ ImplFreePrnMemory( pDrivData );
+ return FALSE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Os2SalInfoPrinter::SetPrinterData( ImplJobSetup* pSetupData )
+{
+ // Wir koennen nur Treiberdaten von OS2 setzen
+ if ( pSetupData->mnSystem != JOBSETUP_SYSTEM_OS2 )
+ return FALSE;
+
+ PDRIVDATA pNewDrivData = (PDRIVDATA)(pSetupData->mpDriverData);
+ if ( !pNewDrivData )
+ return FALSE;
+
+ // Testen, ob Printerdaten fuer den gleichen Printer uebergeben werden,
+ // da einige Treiber zu Abstuerzen neigen, wenn Daten von einem anderen
+ // Printer gesetzt werden
+ if ( !maJobSetupDeviceName.Equals( pNewDrivData->szDeviceName ))
+ return FALSE;
+
+ // update DC and PS
+ HDC hDC;
+ HPS hPS;
+ if ( !ImplSalCreateInfoPrn( this, pNewDrivData, hDC, hPS ) )
+ return FALSE;
+
+ // Alten Printer DC/PS zerstoeren
+ ImplSalDestroyInfoPrn( this );
+
+ // Neue Daten setzen und initialisieren
+ mhDC = hDC;
+ mhPS = hPS;
+ mpGraphics->mhDC = mhDC;
+ mpGraphics->mhPS = mhPS;
+ ImplSalInitGraphics( mpGraphics );
+
+ // retrieve current settings from printer driver and store them to system independend data!
+ ImplFreeFormAndTrayList( this );
+ if ( mbDJPSupported )
+ ImplGetCurrentSettings( this, pSetupData );
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Os2SalInfoPrinter::SetData( ULONG nFlags, ImplJobSetup* pSetupData )
+{
+ // needs DJP support
+ if ( !mbDJPSupported )
+ return FALSE;
+
+ PDRIVDATA pDrivData = ImplPrnDrivData( pSetupData );
+
+ if ( !pDrivData )
+ return FALSE;
+
+ BOOL bOK = FALSE;
+
+ // set orientation
+ if ( nFlags & SAL_JOBSET_ORIENTATION )
+ {
+ if ( ImplSetOrientation( mhDC, pDrivData, pSetupData->meOrientation ) )
+ bOK = TRUE;
+ }
+
+ // set paper size
+ if ( nFlags & SAL_JOBSET_PAPERSIZE )
+ {
+ // Papierformat ermitteln
+ DJPT_PAPERSIZE nOS2PaperFormat;
+ switch ( pSetupData->mePaperFormat )
+ {
+ case PAPER_A3:
+ nOS2PaperFormat = DJP_PSI_A3;
+ break;
+
+ case PAPER_A4:
+ nOS2PaperFormat = DJP_PSI_A4;
+ break;
+
+ case PAPER_A5:
+ nOS2PaperFormat = DJP_PSI_A5;
+ break;
+
+ case PAPER_B4:
+ nOS2PaperFormat = DJP_PSI_B4;
+ break;
+
+ case PAPER_B5:
+ nOS2PaperFormat = DJP_PSI_B5;
+ break;
+
+ case PAPER_LETTER:
+ nOS2PaperFormat = DJP_PSI_LETTER;
+ break;
+
+ case PAPER_LEGAL:
+ nOS2PaperFormat = DJP_PSI_LEGAL;
+ break;
+
+ case PAPER_TABLOID:
+ nOS2PaperFormat = DJP_PSI_TABLOID;
+ break;
+
+ default:
+ {
+ nOS2PaperFormat = DJP_PSI_NONE;
+ // OS2 rechnet in Millimetern
+ long nPaperWidth = pSetupData->mnPaperWidth / 100;
+ long nPaperHeight = pSetupData->mnPaperHeight / 100;
+ // Ansonsten ueber die Papiergroesse suchen
+ for( int i = 0; i < mnFormCount; i++ )
+ {
+ ImplFormInfo* pFormInfo = mpFormArray[i];
+ if ( ImplPaperSizeEqual( nPaperWidth, nPaperHeight,
+ pFormInfo->mnPaperWidth, pFormInfo->mnPaperHeight ) )
+ {
+ nOS2PaperFormat = pFormInfo->mnId;
+ break;
+ }
+ }
+ }
+ break;
+ }
+
+ if ( nOS2PaperFormat != DJP_PSI_NONE )
+ {
+ if ( ImplSetPaperSize( mhDC, pDrivData, nOS2PaperFormat ) )
+ bOK = TRUE;
+ }
+ }
+
+ // set paper tray
+ if ( (nFlags & SAL_JOBSET_PAPERBIN) && (pSetupData->mnPaperBin < mnTrayCount) )
+ {
+ if ( ImplSetPaperBin( mhDC, pDrivData,
+ mpTrayArray[pSetupData->mnPaperBin] ) )
+ bOK = TRUE;
+ }
+
+ if ( bOK )
+ {
+ ImplUpdateSetupData( pDrivData, pSetupData );
+
+ // query current driver settings
+ ImplFreeFormAndTrayList( this );
+ if ( ImplGetCurrentSettings( this, pSetupData ) )
+ {
+ // update DC and PS
+ HDC hDC;
+ HPS hPS;
+ if ( ImplSalCreateInfoPrn( this, (PDRIVDATA)(pSetupData->mpDriverData), hDC, hPS ) )
+ {
+ // Alten Printer DC/PS zerstoeren
+ ImplSalDestroyInfoPrn( this );
+
+ // Neue Daten setzen und initialisieren
+ mhDC = hDC;
+ mhPS = hPS;
+ mpGraphics->mhDC = mhDC;
+ mpGraphics->mhPS = mhPS;
+ ImplSalInitGraphics( mpGraphics );
+ }
+ else
+ bOK = FALSE;
+ }
+ else
+ bOK = FALSE;
+ }
+
+ return bOK;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG Os2SalInfoPrinter::GetPaperBinCount( const ImplJobSetup* pJobSetup )
+{
+ if ( !mbDJPSupported )
+ return 1;
+
+ // init paperbinlist if empty
+ if ( !mnTrayCount )
+ ImplGetFormAndTrayList( this, pJobSetup );
+
+ // Wir haben immer einen PaperTray und wenn, das eben einen ohne
+ // Namen
+ if ( !mnTrayCount )
+ return 1;
+ else
+ return mnTrayCount;
+}
+
+// -----------------------------------------------------------------------
+
+XubString Os2SalInfoPrinter::GetPaperBinName( const ImplJobSetup* pJobSetup,
+ ULONG nPaperBin )
+{
+ XubString aPaperBinName;
+
+ if ( mbDJPSupported )
+ {
+ // init paperbinlist if empty
+ if ( !mnTrayCount )
+ ImplGetFormAndTrayList( this, pJobSetup );
+
+ if ( nPaperBin < mnTrayCount )
+ aPaperBinName = ::rtl::OStringToOUString (mpTrayArray[nPaperBin]->maDisplayName, gsl_getSystemTextEncoding());
+ }
+
+ return aPaperBinName;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG Os2SalInfoPrinter::GetCapabilities( const ImplJobSetup*, USHORT nType )
+{
+ switch ( nType )
+ {
+ case PRINTER_CAPABILITIES_SUPPORTDIALOG:
+ return TRUE;
+ case PRINTER_CAPABILITIES_COPIES:
+ return 0xFFFF;
+ case PRINTER_CAPABILITIES_COLLATECOPIES:
+ return 0;
+ case PRINTER_CAPABILITIES_SETORIENTATION:
+ case PRINTER_CAPABILITIES_SETPAPERBIN:
+ case PRINTER_CAPABILITIES_SETPAPERSIZE:
+ case PRINTER_CAPABILITIES_SETPAPER:
+ return mbDJPSupported;
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalInfoPrinter::GetPageInfo( const ImplJobSetup*,
+ long& rOutWidth, long& rOutHeight,
+ long& rPageOffX, long& rPageOffY,
+ long& rPageWidth, long& rPageHeight )
+{
+ HDC hDC = mhDC;
+
+ // search current form
+ HCINFO aInfo;
+ int nForms = DevQueryHardcopyCaps( hDC, 0, 0, &aInfo );
+ for( int i = 0; i < nForms; i++ )
+ {
+ if ( DevQueryHardcopyCaps( hDC, i, 1, &aInfo ) >= 0 )
+ {
+ if ( aInfo.flAttributes & HCAPS_CURRENT )
+ {
+ // query resolution
+ long nXResolution;
+ long nYResolution;
+ DevQueryCaps( hDC, CAPS_HORIZONTAL_RESOLUTION, 1, &nXResolution );
+ DevQueryCaps( hDC, CAPS_VERTICAL_RESOLUTION, 1, &nYResolution );
+ rPageOffX = aInfo.xLeftClip * nXResolution / 1000;
+ rPageOffY = (aInfo.cy-aInfo.yTopClip) * nYResolution / 1000;
+ rPageWidth = aInfo.cx * nXResolution / 1000;
+ rPageHeight = aInfo.cy * nYResolution / 1000;
+ rOutWidth = aInfo.xPels;
+ rOutHeight = aInfo.yPels;
+ return;
+ }
+ }
+ }
+
+ // use device caps if no form selected/found
+ long lCapsWidth = 0;
+ long lCapsHeight = 0;
+ DevQueryCaps( hDC, CAPS_WIDTH, 1L, &lCapsWidth );
+ DevQueryCaps( hDC, CAPS_HEIGHT, 1L, &lCapsHeight );
+ rPageOffX = 0;
+ rPageOffY = 0;
+ rOutWidth = lCapsWidth;
+ rOutHeight = lCapsHeight;
+ rPageWidth = rOutWidth;
+ rPageHeight = rOutHeight;
+}
+
+// =======================================================================
+
+static BOOL ImplIsDriverPrintDJPEnabled( HDC hDC )
+{
+#ifdef NO_DJP
+ return FALSE;
+#else
+ // Ueber OS2-Ini kann DJP disablte werden
+ if ( !PrfQueryProfileInt( HINI_PROFILE, SAL_PROFILE_APPNAME, SAL_PROFILE_PRINTDJP, 1 ) )
+ return FALSE;
+
+ // Testen, ob DJP-Interface am Drucker vorhanden
+ LONG lQuery;
+ APIRET rc;
+
+ lQuery = DEVESC_QUERYSIZE;
+ rc = DevEscape( hDC,
+ DEVESC_QUERYESCSUPPORT,
+ sizeof( lQuery ),
+ (PBYTE)&lQuery,
+ 0,
+ (PBYTE)NULL );
+ if ( DEV_OK != rc )
+ return FALSE;
+
+ return TRUE;
+#endif
+}
+
+// =======================================================================
+
+SalPrinter* Os2SalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter )
+{
+ Os2SalPrinter* pPrinter = new Os2SalPrinter;
+ pPrinter->mpInfoPrinter = static_cast<Os2SalInfoPrinter*>(pInfoPrinter);
+ return pPrinter;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalInstance::DestroyPrinter( SalPrinter* pPrinter )
+{
+ delete pPrinter;
+}
+
+// =======================================================================
+
+Os2SalPrinter::Os2SalPrinter()
+{
+ mhDC = 0;
+ mhPS = 0;
+ mpGraphics = NULL;
+ mbAbort = FALSE;
+ mbPrintDJPSupported = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+Os2SalPrinter::~Os2SalPrinter()
+{
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Os2SalPrinter::StartJob( const XubString* pFileName,
+ const XubString& rJobName,
+ const XubString& rAppName,
+ ULONG nCopies,
+ bool bCollate,
+ bool bDirect,
+ ImplJobSetup* pSetupData )
+{
+ DEVOPENSTRUC aDevOpenStruc;
+ LONG lType;
+ APIRET rc;
+
+ // prepare queue information
+ memset( &aDevOpenStruc, 0, sizeof( aDevOpenStruc ) );
+ aDevOpenStruc.pszDriverName = (PSZ)(mpInfoPrinter->maDriverName.GetBuffer());
+
+ // print into file?
+ if ( pFileName )
+ {
+ aDevOpenStruc.pszLogAddress = (PSZ)pFileName->GetBuffer();
+ aDevOpenStruc.pszDataType = "PM_Q_RAW";
+ lType = OD_DIRECT;
+ }
+ else
+ {
+ aDevOpenStruc.pszLogAddress = (PSZ)(mpInfoPrinter->maName.GetBuffer());
+ if ( PrfQueryProfileInt( HINI_PROFILE, SAL_PROFILE_APPNAME, SAL_PROFILE_PRINTRAW, 0 ) )
+ aDevOpenStruc.pszDataType = "PM_Q_RAW";
+ else
+ aDevOpenStruc.pszDataType = "PM_Q_STD";
+ lType = OD_QUEUED;
+ }
+
+#if 0 // YD FIXME
+ // Set comment (AppName nur bis zum 1. Space-Zeichen nehmen)
+ const xub_Unicode* pComment = rAppName;
+ USHORT nCommentLen = 0;
+ memset( maCommentBuf, 0, sizeof( maCommentBuf ) );
+ while ( (nCommentLen < 32) &&
+ (((*pComment >= 'a') && (*pComment <= 'z')) ||
+ ((*pComment >= 'A') && (*pComment <= 'Z')) ||
+ ((*pComment >= '0') && (*pComment <= '9')) ||
+ (*pComment == '-')))
+ {
+ maCommentBuf[nCommentLen] = (char)(*pComment);
+ nCommentLen++;
+ pComment++;
+ }
+ aDevOpenStruc.pszComment = (PSZ)maCommentBuf;
+#endif
+ ByteString jobName( rJobName, gsl_getSystemTextEncoding());
+ aDevOpenStruc.pszComment = (PSZ)jobName.GetBuffer();
+
+ // Kopien
+ if ( nCopies > 1 )
+ {
+ // OS2 kann maximal 999 Kopien
+ if ( nCopies > 999 )
+ nCopies = 999;
+ sprintf( maCopyBuf, "COP=%d", nCopies);
+ aDevOpenStruc.pszQueueProcParams = (PSZ)maCopyBuf;
+ }
+
+ // open device context
+ SalData* pSalData = GetSalData();
+ HAB hAB = pSalData->mhAB;
+ aDevOpenStruc.pdriv = (PDRIVDATA)pSetupData->mpDriverData;
+ mhDC = DevOpenDC( hAB,
+ lType,
+ "*",
+ 7,
+ (PDEVOPENDATA)&aDevOpenStruc,
+ 0 );
+ if ( mhDC == 0 )
+ {
+ ERRORID nLastError = WinGetLastError( hAB );
+ if ( (nLastError & 0xFFFF) == PMERR_SPL_PRINT_ABORT )
+ mnError = SAL_PRINTER_ERROR_ABORT;
+ else
+ mnError = SAL_PRINTER_ERROR_GENERALERROR;
+ return FALSE;
+ }
+
+ // open presentation space
+ SIZEL sizel;
+ sizel.cx = 0;
+ sizel.cy = 0;
+ mhPS = Ft2CreatePS( hAB, mhDC, &sizel, GPIA_ASSOC | GPIT_MICRO | PU_PELS );
+ if ( !mhPS )
+ {
+ DevCloseDC( mhDC );
+ mnError = SAL_PRINTER_ERROR_GENERALERROR;
+ return NULL;
+ }
+
+ // Can we print with DJP
+ mbPrintDJPSupported = ImplIsDriverPrintDJPEnabled( mhDC );
+
+ // JobName ermitteln und Job starten
+ PSZ pszJobName = NULL;
+ int nJobNameLen = 0;
+ if ( jobName.Len() > 0 )
+ {
+ pszJobName = (PSZ)jobName.GetBuffer();
+ nJobNameLen = jobName.Len();
+ }
+ rc = DevEscape( mhDC,
+ DEVESC_STARTDOC,
+ nJobNameLen, (PBYTE)pszJobName,
+ 0, (PBYTE)NULL );
+
+ if ( rc != DEV_OK )
+ {
+ ERRORID nLastError = WinGetLastError( hAB );
+ if ( (nLastError & 0xFFFF) == PMERR_SPL_PRINT_ABORT )
+ mnError = SAL_PRINTER_ERROR_ABORT;
+ else
+ mnError = SAL_PRINTER_ERROR_GENERALERROR;
+ Ft2Associate( mhPS, NULL );
+ Ft2DestroyPS( mhPS );
+ DevCloseDC( mhDC );
+ return FALSE;
+ }
+
+ // init for first page
+ mbFirstPage = TRUE;
+ mnError = 0;
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Os2SalPrinter::EndJob()
+{
+ APIRET rc;
+ rc = DevEscape( mhDC,
+ DEVESC_ENDDOC,
+ 0, NULL,
+ 0, NULL);
+
+ // destroy presentation space and device context
+ Ft2Associate( mhPS, NULL );
+ Ft2DestroyPS( mhPS );
+ DevCloseDC( mhDC );
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Os2SalPrinter::AbortJob()
+{
+ APIRET rc;
+
+ rc = DevEscape( mhDC,
+ DEVESC_ABORTDOC,
+ 0, NULL,
+ 0, NULL );
+
+ // destroy SalGraphics
+ if ( mpGraphics )
+ {
+ ImplSalDeInitGraphics( mpGraphics );
+ delete mpGraphics;
+ mpGraphics = NULL;
+ }
+
+ // destroy presentation space and device context
+ Ft2Associate( mhPS, NULL );
+ Ft2DestroyPS( mhPS );
+ DevCloseDC( mhDC );
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+SalGraphics* Os2SalPrinter::StartPage( ImplJobSetup* pSetupData, BOOL bNewJobSetup )
+{
+ APIRET rc;
+
+ if ( mbFirstPage )
+ mbFirstPage = FALSE;
+ else
+ {
+ PBYTE pJobData;
+ LONG nJobDataSize;
+ LONG nEscape;
+ if ( mbPrintDJPSupported && bNewJobSetup )
+ {
+ nEscape = DEVESC_NEWFRAME_WPROP;
+ nJobDataSize = ((PDRIVDATA)(pSetupData->mpDriverData))->cb;
+ pJobData = (PBYTE)(pSetupData->mpDriverData);
+ }
+ else
+ {
+ nEscape = DEVESC_NEWFRAME;
+ nJobDataSize = 0;
+ pJobData = NULL;
+ }
+ rc = DevEscape( mhDC,
+ nEscape,
+ 0, NULL,
+ &nJobDataSize, pJobData );
+
+ if ( rc != DEV_OK )
+ {
+ DevEscape( mhDC, DEVESC_ENDDOC, 0, NULL, 0, NULL);
+ Ft2Associate( mhPS, NULL );
+ Ft2DestroyPS( mhPS );
+ DevCloseDC( mhDC );
+ mnError = SAL_PRINTER_ERROR_GENERALERROR;
+ return NULL;
+ }
+ }
+
+ // create SalGraphics with copy of hPS
+ Os2SalGraphics* pGraphics = new Os2SalGraphics;
+ pGraphics->mhDC = mhDC;
+ pGraphics->mhPS = mhPS;
+ pGraphics->mhWnd = 0;
+ pGraphics->mbPrinter = TRUE;
+ pGraphics->mbVirDev = FALSE;
+ pGraphics->mbWindow = FALSE;
+ pGraphics->mbScreen = FALSE;
+ pGraphics->mnHeight = 0;
+ // search current form for actual page height
+ HCINFO aInfo;
+ int nForms = DevQueryHardcopyCaps( mhDC, 0, 0, &aInfo );
+ for( int i = 0; i < nForms; i++ )
+ {
+ if ( DevQueryHardcopyCaps( mhDC, i, 1, &aInfo ) >= 0 )
+ {
+ if ( aInfo.flAttributes & HCAPS_CURRENT )
+ pGraphics->mnHeight = aInfo.yPels;
+ }
+ }
+ // use device caps if no form selected/found
+ if ( !pGraphics->mnHeight )
+ DevQueryCaps( mhDC, CAPS_HEIGHT, 1L, &pGraphics->mnHeight );
+
+ ImplSalInitGraphics( pGraphics );
+ mpGraphics = pGraphics;
+
+ return pGraphics;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Os2SalPrinter::EndPage()
+{
+ if ( mpGraphics )
+ {
+ // destroy SalGraphics
+ ImplSalDeInitGraphics( mpGraphics );
+ delete mpGraphics;
+ mpGraphics = NULL;
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG Os2SalPrinter::GetErrorCode()
+{
+ return mnError;
+}
+
+void Os2SalInfoPrinter::InitPaperFormats( const ImplJobSetup* pSetupData )
+{
+ printf("Os2SalInfoPrinter::InitPaperFormats\n");
+}
+int Os2SalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* pSetupData )
+{
+ printf("Os2SalInfoPrinter::GetLandscapeAngle\n");
+ return 0;
+}
+
diff --git a/vcl/os2/source/gdi/salvd.cxx b/vcl/os2/source/gdi/salvd.cxx
new file mode 100644
index 000000000000..4e53782be8ea
--- /dev/null
+++ b/vcl/os2/source/gdi/salvd.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.
+ *
+ ************************************************************************/
+
+#include <string.h>
+
+#include <svpm.h>
+
+#define _SV_SALVD_CXX
+#include <saldata.hxx>
+#include <salinst.h>
+#include <salgdi.h>
+#include <salvd.h>
+
+#ifndef __H_FT2LIB
+#include <wingdi.h>
+#include <ft2lib.h>
+#endif
+
+// =======================================================================
+
+HBITMAP ImplCreateVirDevBitmap( HDC hDC, HPS hPS, long nDX, long nDY,
+ USHORT nBitCount )
+{
+ if( !nBitCount )
+ {
+ LONG nDevBitCount;
+ DevQueryCaps( hDC, CAPS_COLOR_BITCOUNT, 1, &nDevBitCount );
+ nBitCount = nDevBitCount;
+ }
+
+ LONG nPlanes;
+ DevQueryCaps( hDC, CAPS_COLOR_PLANES, 1, &nPlanes );
+
+ // entsprechende Bitmap zum OutputDevice erzeugen
+ HBITMAP hBitmap;
+ BITMAPINFOHEADER2 aBitmapInfo;
+ memset( &aBitmapInfo, 0, sizeof( BITMAPINFOHEADER2 ) );
+ aBitmapInfo.cbFix = sizeof( BITMAPINFOHEADER2 );
+ aBitmapInfo.cx = nDX;
+ aBitmapInfo.cy = nDY;
+ aBitmapInfo.cPlanes = nPlanes;
+ aBitmapInfo.cBitCount = (nBitCount < 4) ? 4 : nBitCount;
+ hBitmap = GpiCreateBitmap( hPS, &aBitmapInfo, 0, NULL, NULL );
+ return hBitmap;
+}
+
+// -----------------------------------------------------------------------
+
+SalVirtualDevice* Os2SalInstance::CreateVirtualDevice( SalGraphics* pSGraphics,
+ long nDX, long nDY,
+ USHORT nBitCount,
+ const SystemGraphicsData* pData )
+{
+ Os2SalGraphics* pGraphics = static_cast<Os2SalGraphics*>(pSGraphics);
+ HAB hAB = GetSalData()->mhAB;
+ SIZEL size;
+
+ // create device context (at this time allways display compatible)
+ DEVOPENSTRUC aDevOpenStruc = { NULL, "DISPLAY", NULL, NULL, NULL, NULL, NULL, NULL, NULL };
+ HDC hDC = DevOpenDC( hAB, OD_MEMORY, (PSZ)"*", 5, (PDEVOPENDATA)&aDevOpenStruc, 0 );
+ if ( !hDC )
+ return NULL;
+
+ // create presentation space
+ size.cx = nDX;
+ size.cy = nDY;
+ HPS hPS = Ft2CreatePS( hAB, hDC, &size, GPIT_MICRO | GPIA_ASSOC | PU_PELS );
+ if ( !hPS )
+ {
+ DevCloseDC( hDC );
+ return NULL;
+ }
+
+ // create bitmap for the virtual device
+ HBITMAP hBmp = ImplCreateVirDevBitmap( hDC, hPS, nDX, nDY, nBitCount );
+ if ( !hBmp )
+ {
+ Ft2DestroyPS( hPS );
+ DevCloseDC( hDC );
+ return NULL;
+ }
+
+ // init data
+ Os2SalVirtualDevice* pVDev = new Os2SalVirtualDevice;
+ Os2SalGraphics* pVirGraphics = new Os2SalGraphics;
+
+ pVirGraphics->mhDC = hDC;
+ pVirGraphics->mhPS = hPS;
+ pVirGraphics->mhWnd = 0;
+ pVirGraphics->mnHeight = nDY;
+ pVirGraphics->mbPrinter = FALSE;
+ pVirGraphics->mbVirDev = TRUE;
+ pVirGraphics->mbWindow = FALSE;
+ pVirGraphics->mbScreen = pGraphics->mbScreen;
+ ImplSalInitGraphics( pVirGraphics );
+
+ pVDev->mhDC = hDC;
+ pVDev->mhPS = hPS;
+ pVDev->mhBmp = hBmp;
+ pVDev->mhDefBmp = Ft2SetBitmap( hPS, hBmp );
+ pVDev->mpGraphics = pVirGraphics;
+ pVDev->mnBitCount = nBitCount;
+ pVDev->mbGraphics = FALSE;
+ return pVDev;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalInstance::DestroyVirtualDevice( SalVirtualDevice* pDevice )
+{
+ delete pDevice;
+}
+
+// =======================================================================
+
+Os2SalVirtualDevice::Os2SalVirtualDevice()
+{
+}
+
+// -----------------------------------------------------------------------
+
+Os2SalVirtualDevice::~Os2SalVirtualDevice()
+{
+ ImplSalDeInitGraphics( mpGraphics );
+
+ Ft2SetBitmap( mpGraphics->mhPS, mhDefBmp );
+ GpiDeleteBitmap( mhBmp );
+ Ft2DestroyPS( mpGraphics->mhPS );
+ DevCloseDC( mpGraphics->mhDC );
+ delete mpGraphics;
+}
+
+// -----------------------------------------------------------------------
+
+SalGraphics* Os2SalVirtualDevice::GetGraphics()
+{
+ if ( mbGraphics )
+ return NULL;
+
+ if ( mpGraphics )
+ mbGraphics = TRUE;
+
+ return mpGraphics;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalVirtualDevice::ReleaseGraphics( SalGraphics* )
+{
+ mbGraphics = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Os2SalVirtualDevice::SetSize( long nDX, long nDY )
+{
+ HBITMAP hNewBmp = ImplCreateVirDevBitmap( mhDC,
+ mhPS, nDX, nDY,
+ mnBitCount );
+ if ( hNewBmp )
+ {
+ Ft2SetBitmap( mhPS, hNewBmp );
+ GpiDeleteBitmap( mhBmp );
+ mhBmp = hNewBmp;
+ mpGraphics->mnHeight = nDY;
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+void Os2SalVirtualDevice::GetSize( long& rWidth, long& rHeight )
+{
+ DevQueryCaps( mpGraphics->mhDC, CAPS_WIDTH, CAPS_WIDTH, (LONG*)rWidth );
+ DevQueryCaps( mpGraphics->mhDC, CAPS_HEIGHT, CAPS_HEIGHT, (LONG*)rHeight );
+}
diff --git a/vcl/os2/source/src/airbrush.ptr b/vcl/os2/source/src/airbrush.ptr
new file mode 100644
index 000000000000..89a99d763d94
--- /dev/null
+++ b/vcl/os2/source/src/airbrush.ptr
Binary files differ
diff --git a/vcl/os2/source/src/ase.ptr b/vcl/os2/source/src/ase.ptr
new file mode 100755
index 000000000000..1f6c4e764901
--- /dev/null
+++ b/vcl/os2/source/src/ase.ptr
Binary files differ
diff --git a/vcl/os2/source/src/asn.ptr b/vcl/os2/source/src/asn.ptr
new file mode 100755
index 000000000000..b526c17a83e0
--- /dev/null
+++ b/vcl/os2/source/src/asn.ptr
Binary files differ
diff --git a/vcl/os2/source/src/asne.ptr b/vcl/os2/source/src/asne.ptr
new file mode 100755
index 000000000000..4ed44679918f
--- /dev/null
+++ b/vcl/os2/source/src/asne.ptr
Binary files differ
diff --git a/vcl/os2/source/src/asns.ptr b/vcl/os2/source/src/asns.ptr
new file mode 100755
index 000000000000..12395e641b4f
--- /dev/null
+++ b/vcl/os2/source/src/asns.ptr
Binary files differ
diff --git a/vcl/os2/source/src/asnswe.ptr b/vcl/os2/source/src/asnswe.ptr
new file mode 100755
index 000000000000..46f1f790b474
--- /dev/null
+++ b/vcl/os2/source/src/asnswe.ptr
Binary files differ
diff --git a/vcl/os2/source/src/asnw.ptr b/vcl/os2/source/src/asnw.ptr
new file mode 100755
index 000000000000..d934c3b69a79
--- /dev/null
+++ b/vcl/os2/source/src/asnw.ptr
Binary files differ
diff --git a/vcl/os2/source/src/ass.ptr b/vcl/os2/source/src/ass.ptr
new file mode 100755
index 000000000000..059ce40126cd
--- /dev/null
+++ b/vcl/os2/source/src/ass.ptr
Binary files differ
diff --git a/vcl/os2/source/src/asse.ptr b/vcl/os2/source/src/asse.ptr
new file mode 100755
index 000000000000..78a1f7ff5c64
--- /dev/null
+++ b/vcl/os2/source/src/asse.ptr
Binary files differ
diff --git a/vcl/os2/source/src/assw.ptr b/vcl/os2/source/src/assw.ptr
new file mode 100755
index 000000000000..5adf85360e30
--- /dev/null
+++ b/vcl/os2/source/src/assw.ptr
Binary files differ
diff --git a/vcl/os2/source/src/asw.ptr b/vcl/os2/source/src/asw.ptr
new file mode 100755
index 000000000000..160a775abe22
--- /dev/null
+++ b/vcl/os2/source/src/asw.ptr
Binary files differ
diff --git a/vcl/os2/source/src/aswe.ptr b/vcl/os2/source/src/aswe.ptr
new file mode 100755
index 000000000000..b4e6580c560d
--- /dev/null
+++ b/vcl/os2/source/src/aswe.ptr
Binary files differ
diff --git a/vcl/os2/source/src/chain.ptr b/vcl/os2/source/src/chain.ptr
new file mode 100644
index 000000000000..0e248b324daa
--- /dev/null
+++ b/vcl/os2/source/src/chain.ptr
Binary files differ
diff --git a/vcl/os2/source/src/chainnot.ptr b/vcl/os2/source/src/chainnot.ptr
new file mode 100644
index 000000000000..0e248b324daa
--- /dev/null
+++ b/vcl/os2/source/src/chainnot.ptr
Binary files differ
diff --git a/vcl/os2/source/src/chart.ptr b/vcl/os2/source/src/chart.ptr
new file mode 100644
index 000000000000..66c685d111c7
--- /dev/null
+++ b/vcl/os2/source/src/chart.ptr
Binary files differ
diff --git a/vcl/os2/source/src/copydata.ptr b/vcl/os2/source/src/copydata.ptr
new file mode 100644
index 000000000000..e7e7ccd17e41
--- /dev/null
+++ b/vcl/os2/source/src/copydata.ptr
Binary files differ
diff --git a/vcl/os2/source/src/copydlnk.ptr b/vcl/os2/source/src/copydlnk.ptr
new file mode 100644
index 000000000000..acbf27b3462e
--- /dev/null
+++ b/vcl/os2/source/src/copydlnk.ptr
Binary files differ
diff --git a/vcl/os2/source/src/copyf.ptr b/vcl/os2/source/src/copyf.ptr
new file mode 100644
index 000000000000..8ebcbded233b
--- /dev/null
+++ b/vcl/os2/source/src/copyf.ptr
Binary files differ
diff --git a/vcl/os2/source/src/copyf2.ptr b/vcl/os2/source/src/copyf2.ptr
new file mode 100644
index 000000000000..dcfa6c089c10
--- /dev/null
+++ b/vcl/os2/source/src/copyf2.ptr
Binary files differ
diff --git a/vcl/os2/source/src/copyflnk.ptr b/vcl/os2/source/src/copyflnk.ptr
new file mode 100644
index 000000000000..3bd6e9d4706e
--- /dev/null
+++ b/vcl/os2/source/src/copyflnk.ptr
Binary files differ
diff --git a/vcl/os2/source/src/crook.ptr b/vcl/os2/source/src/crook.ptr
new file mode 100644
index 000000000000..0b639614ddb3
--- /dev/null
+++ b/vcl/os2/source/src/crook.ptr
Binary files differ
diff --git a/vcl/os2/source/src/crop.ptr b/vcl/os2/source/src/crop.ptr
new file mode 100644
index 000000000000..076e522e1b7f
--- /dev/null
+++ b/vcl/os2/source/src/crop.ptr
Binary files differ
diff --git a/vcl/os2/source/src/cross.ptr b/vcl/os2/source/src/cross.ptr
new file mode 100644
index 000000000000..1a2cd8dae5f6
--- /dev/null
+++ b/vcl/os2/source/src/cross.ptr
Binary files differ
diff --git a/vcl/os2/source/src/darc.ptr b/vcl/os2/source/src/darc.ptr
new file mode 100644
index 000000000000..eba024e6a09a
--- /dev/null
+++ b/vcl/os2/source/src/darc.ptr
Binary files differ
diff --git a/vcl/os2/source/src/data.ptr b/vcl/os2/source/src/data.ptr
new file mode 100644
index 000000000000..4c3c9eeb5e7a
--- /dev/null
+++ b/vcl/os2/source/src/data.ptr
Binary files differ
diff --git a/vcl/os2/source/src/dbezier.ptr b/vcl/os2/source/src/dbezier.ptr
new file mode 100644
index 000000000000..8972b0007c13
--- /dev/null
+++ b/vcl/os2/source/src/dbezier.ptr
Binary files differ
diff --git a/vcl/os2/source/src/dcapt.ptr b/vcl/os2/source/src/dcapt.ptr
new file mode 100644
index 000000000000..b04b21bad1a7
--- /dev/null
+++ b/vcl/os2/source/src/dcapt.ptr
Binary files differ
diff --git a/vcl/os2/source/src/dcirccut.ptr b/vcl/os2/source/src/dcirccut.ptr
new file mode 100644
index 000000000000..936b337ebcc7
--- /dev/null
+++ b/vcl/os2/source/src/dcirccut.ptr
Binary files differ
diff --git a/vcl/os2/source/src/dconnect.ptr b/vcl/os2/source/src/dconnect.ptr
new file mode 100644
index 000000000000..f8bc2cf454aa
--- /dev/null
+++ b/vcl/os2/source/src/dconnect.ptr
Binary files differ
diff --git a/vcl/os2/source/src/dellipse.ptr b/vcl/os2/source/src/dellipse.ptr
new file mode 100644
index 000000000000..388bc2f2b00c
--- /dev/null
+++ b/vcl/os2/source/src/dellipse.ptr
Binary files differ
diff --git a/vcl/os2/source/src/detectiv.ptr b/vcl/os2/source/src/detectiv.ptr
new file mode 100644
index 000000000000..44ca1546a93b
--- /dev/null
+++ b/vcl/os2/source/src/detectiv.ptr
Binary files differ
diff --git a/vcl/os2/source/src/dfree.ptr b/vcl/os2/source/src/dfree.ptr
new file mode 100644
index 000000000000..52d95d814d98
--- /dev/null
+++ b/vcl/os2/source/src/dfree.ptr
Binary files differ
diff --git a/vcl/os2/source/src/dline.ptr b/vcl/os2/source/src/dline.ptr
new file mode 100644
index 000000000000..e7b80ae56735
--- /dev/null
+++ b/vcl/os2/source/src/dline.ptr
Binary files differ
diff --git a/vcl/os2/source/src/dpie.ptr b/vcl/os2/source/src/dpie.ptr
new file mode 100644
index 000000000000..abd68b899f3a
--- /dev/null
+++ b/vcl/os2/source/src/dpie.ptr
Binary files differ
diff --git a/vcl/os2/source/src/dpolygon.ptr b/vcl/os2/source/src/dpolygon.ptr
new file mode 100644
index 000000000000..94fa158b4186
--- /dev/null
+++ b/vcl/os2/source/src/dpolygon.ptr
Binary files differ
diff --git a/vcl/os2/source/src/drect.ptr b/vcl/os2/source/src/drect.ptr
new file mode 100644
index 000000000000..3ec044f267d6
--- /dev/null
+++ b/vcl/os2/source/src/drect.ptr
Binary files differ
diff --git a/vcl/os2/source/src/dtext.ptr b/vcl/os2/source/src/dtext.ptr
new file mode 100644
index 000000000000..8c221303b0b6
--- /dev/null
+++ b/vcl/os2/source/src/dtext.ptr
Binary files differ
diff --git a/vcl/os2/source/src/fill.ptr b/vcl/os2/source/src/fill.ptr
new file mode 100644
index 000000000000..e7247a6d107b
--- /dev/null
+++ b/vcl/os2/source/src/fill.ptr
Binary files differ
diff --git a/vcl/os2/source/src/hand.ptr b/vcl/os2/source/src/hand.ptr
new file mode 100644
index 000000000000..b1d65c7f19d0
--- /dev/null
+++ b/vcl/os2/source/src/hand.ptr
Binary files differ
diff --git a/vcl/os2/source/src/help.ptr b/vcl/os2/source/src/help.ptr
new file mode 100644
index 000000000000..3df4d88bddc4
--- /dev/null
+++ b/vcl/os2/source/src/help.ptr
Binary files differ
diff --git a/vcl/os2/source/src/hshear.ptr b/vcl/os2/source/src/hshear.ptr
new file mode 100644
index 000000000000..76bbebba5865
--- /dev/null
+++ b/vcl/os2/source/src/hshear.ptr
Binary files differ
diff --git a/vcl/os2/source/src/hsizebar.ptr b/vcl/os2/source/src/hsizebar.ptr
new file mode 100644
index 000000000000..9b78ff9ee9a9
--- /dev/null
+++ b/vcl/os2/source/src/hsizebar.ptr
Binary files differ
diff --git a/vcl/os2/source/src/hsplit.ptr b/vcl/os2/source/src/hsplit.ptr
new file mode 100644
index 000000000000..62f3b590a414
--- /dev/null
+++ b/vcl/os2/source/src/hsplit.ptr
Binary files differ
diff --git a/vcl/os2/source/src/linkdata.ptr b/vcl/os2/source/src/linkdata.ptr
new file mode 100644
index 000000000000..e5e6ace59be3
--- /dev/null
+++ b/vcl/os2/source/src/linkdata.ptr
Binary files differ
diff --git a/vcl/os2/source/src/linkf.ptr b/vcl/os2/source/src/linkf.ptr
new file mode 100644
index 000000000000..62bf7e739e32
--- /dev/null
+++ b/vcl/os2/source/src/linkf.ptr
Binary files differ
diff --git a/vcl/os2/source/src/magnify.ptr b/vcl/os2/source/src/magnify.ptr
new file mode 100644
index 000000000000..1d9a0c149ebd
--- /dev/null
+++ b/vcl/os2/source/src/magnify.ptr
Binary files differ
diff --git a/vcl/os2/source/src/makefile.mk b/vcl/os2/source/src/makefile.mk
new file mode 100644
index 000000000000..1dba7496be65
--- /dev/null
+++ b/vcl/os2/source/src/makefile.mk
@@ -0,0 +1,111 @@
+#*************************************************************************
+#
+# 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=salsrc
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+# --- Files --------------------------------------------------------
+
+RCDEPN= nullptr.ptr \
+ help.ptr \
+ cross.ptr \
+ move.ptr \
+ hsplit.ptr \
+ vsplit.ptr \
+ hsizebar.ptr \
+ vsizebar.ptr \
+ hand.ptr \
+ refhand.ptr \
+ pen.ptr \
+ magnify.ptr \
+ fill.ptr \
+ rotate.ptr \
+ hshear.ptr \
+ vshear.ptr \
+ mirror.ptr \
+ crook.ptr \
+ crop.ptr \
+ movept.ptr \
+ movebw.ptr \
+ movedata.ptr \
+ copydata.ptr \
+ linkdata.ptr \
+ movedlnk.ptr \
+ copydlnk.ptr \
+ movef.ptr \
+ copyf.ptr \
+ linkf.ptr \
+ moveflnk.ptr \
+ copyflnk.ptr \
+ movef2.ptr \
+ copyf2.ptr \
+ dline.ptr \
+ drect.ptr \
+ dpolygon.ptr \
+ dbezier.ptr \
+ darc.ptr \
+ dpie.ptr \
+ dcirccut.ptr \
+ dellipse.ptr \
+ dfree.ptr \
+ dconnect.ptr \
+ dtext.ptr \
+ dcapt.ptr \
+ chart.ptr \
+ detectiv.ptr \
+ pivotcol.ptr \
+ pivotrow.ptr \
+ pivotfld.ptr \
+ chain.ptr \
+ chainnot.ptr \
+ timemove.ptr \
+ timesize.ptr \
+ asn.ptr \
+ ass.ptr \
+ asw.ptr \
+ ase.ptr \
+ asnw.ptr \
+ asne.ptr \
+ assw.ptr \
+ asse.ptr \
+ asns.ptr \
+ aswe.ptr \
+ asnswe.ptr \
+ sd.ico
+
+RCFILES= salsrc.rc
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
diff --git a/vcl/os2/source/src/mirror.ptr b/vcl/os2/source/src/mirror.ptr
new file mode 100644
index 000000000000..9135331048c9
--- /dev/null
+++ b/vcl/os2/source/src/mirror.ptr
Binary files differ
diff --git a/vcl/os2/source/src/move.ptr b/vcl/os2/source/src/move.ptr
new file mode 100644
index 000000000000..6b5a11d31219
--- /dev/null
+++ b/vcl/os2/source/src/move.ptr
Binary files differ
diff --git a/vcl/os2/source/src/movebw.ptr b/vcl/os2/source/src/movebw.ptr
new file mode 100644
index 000000000000..e766b885db0a
--- /dev/null
+++ b/vcl/os2/source/src/movebw.ptr
Binary files differ
diff --git a/vcl/os2/source/src/movedata.ptr b/vcl/os2/source/src/movedata.ptr
new file mode 100644
index 000000000000..689f38da772f
--- /dev/null
+++ b/vcl/os2/source/src/movedata.ptr
Binary files differ
diff --git a/vcl/os2/source/src/movedlnk.ptr b/vcl/os2/source/src/movedlnk.ptr
new file mode 100644
index 000000000000..d533e7135ad0
--- /dev/null
+++ b/vcl/os2/source/src/movedlnk.ptr
Binary files differ
diff --git a/vcl/os2/source/src/movef.ptr b/vcl/os2/source/src/movef.ptr
new file mode 100644
index 000000000000..e9fabda359c8
--- /dev/null
+++ b/vcl/os2/source/src/movef.ptr
Binary files differ
diff --git a/vcl/os2/source/src/movef2.ptr b/vcl/os2/source/src/movef2.ptr
new file mode 100644
index 000000000000..9940890840cb
--- /dev/null
+++ b/vcl/os2/source/src/movef2.ptr
Binary files differ
diff --git a/vcl/os2/source/src/moveflnk.ptr b/vcl/os2/source/src/moveflnk.ptr
new file mode 100644
index 000000000000..d651491ad001
--- /dev/null
+++ b/vcl/os2/source/src/moveflnk.ptr
Binary files differ
diff --git a/vcl/os2/source/src/movept.ptr b/vcl/os2/source/src/movept.ptr
new file mode 100644
index 000000000000..d34332dd89e5
--- /dev/null
+++ b/vcl/os2/source/src/movept.ptr
Binary files differ
diff --git a/vcl/os2/source/src/nullptr.ptr b/vcl/os2/source/src/nullptr.ptr
new file mode 100644
index 000000000000..f8b0f784ba7a
--- /dev/null
+++ b/vcl/os2/source/src/nullptr.ptr
Binary files differ
diff --git a/vcl/os2/source/src/pen.ptr b/vcl/os2/source/src/pen.ptr
new file mode 100644
index 000000000000..3b4495697597
--- /dev/null
+++ b/vcl/os2/source/src/pen.ptr
Binary files differ
diff --git a/vcl/os2/source/src/pivotcol.ptr b/vcl/os2/source/src/pivotcol.ptr
new file mode 100644
index 000000000000..369fdeebf2d0
--- /dev/null
+++ b/vcl/os2/source/src/pivotcol.ptr
Binary files differ
diff --git a/vcl/os2/source/src/pivotfld.ptr b/vcl/os2/source/src/pivotfld.ptr
new file mode 100644
index 000000000000..047c45a711df
--- /dev/null
+++ b/vcl/os2/source/src/pivotfld.ptr
Binary files differ
diff --git a/vcl/os2/source/src/pivotrow.ptr b/vcl/os2/source/src/pivotrow.ptr
new file mode 100644
index 000000000000..e66e752e51d0
--- /dev/null
+++ b/vcl/os2/source/src/pivotrow.ptr
Binary files differ
diff --git a/vcl/os2/source/src/pntbrsh.ptr b/vcl/os2/source/src/pntbrsh.ptr
new file mode 100644
index 000000000000..506965e6b52d
--- /dev/null
+++ b/vcl/os2/source/src/pntbrsh.ptr
Binary files differ
diff --git a/vcl/os2/source/src/refhand.ptr b/vcl/os2/source/src/refhand.ptr
new file mode 100644
index 000000000000..33d613134cb5
--- /dev/null
+++ b/vcl/os2/source/src/refhand.ptr
Binary files differ
diff --git a/vcl/os2/source/src/rotate.ptr b/vcl/os2/source/src/rotate.ptr
new file mode 100644
index 000000000000..622b05346cfc
--- /dev/null
+++ b/vcl/os2/source/src/rotate.ptr
Binary files differ
diff --git a/vcl/os2/source/src/salsrc.rc b/vcl/os2/source/src/salsrc.rc
new file mode 100644
index 000000000000..6e3b40c76da0
--- /dev/null
+++ b/vcl/os2/source/src/salsrc.rc
@@ -0,0 +1,108 @@
+/*************************************************************************
+ *
+ * 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_SALIDS_HRC
+#include <salids.hrc>
+#endif
+
+POINTER SAL_RESID_POINTER_NULL NULLPTR.PTR
+POINTER SAL_RESID_POINTER_HELP HELP.PTR
+POINTER SAL_RESID_POINTER_CROSS CROSS.PTR
+POINTER SAL_RESID_POINTER_MOVE MOVE.PTR
+POINTER SAL_RESID_POINTER_HSPLIT HSPLIT.PTR
+POINTER SAL_RESID_POINTER_VSPLIT VSPLIT.PTR
+POINTER SAL_RESID_POINTER_HSIZEBAR HSIZEBAR.PTR
+POINTER SAL_RESID_POINTER_VSIZEBAR VSIZEBAR.PTR
+POINTER SAL_RESID_POINTER_HAND HAND.PTR
+POINTER SAL_RESID_POINTER_REFHAND REFHAND.PTR
+POINTER SAL_RESID_POINTER_PEN PEN.PTR
+POINTER SAL_RESID_POINTER_MAGNIFY MAGNIFY.PTR
+POINTER SAL_RESID_POINTER_FILL FILL.PTR
+POINTER SAL_RESID_POINTER_ROTATE ROTATE.PTR
+POINTER SAL_RESID_POINTER_HSHEAR HSHEAR.PTR
+POINTER SAL_RESID_POINTER_VSHEAR VSHEAR.PTR
+POINTER SAL_RESID_POINTER_MIRROR MIRROR.PTR
+POINTER SAL_RESID_POINTER_CROOK CROOK.PTR
+POINTER SAL_RESID_POINTER_CROP CROP.PTR
+POINTER SAL_RESID_POINTER_MOVEPOINT MOVEPT.PTR
+POINTER SAL_RESID_POINTER_MOVEBEZIERWEIGHT MOVEBW.PTR
+POINTER SAL_RESID_POINTER_MOVEDATA MOVEDATA.PTR
+POINTER SAL_RESID_POINTER_COPYDATA COPYDATA.PTR
+POINTER SAL_RESID_POINTER_LINKDATA LINKDATA.PTR
+POINTER SAL_RESID_POINTER_MOVEDATALINK MOVEDLNK.PTR
+POINTER SAL_RESID_POINTER_COPYDATALINK COPYDLNK.PTR
+POINTER SAL_RESID_POINTER_MOVEFILE MOVEF.PTR
+POINTER SAL_RESID_POINTER_COPYFILE COPYF.PTR
+POINTER SAL_RESID_POINTER_LINKFILE LINKF.PTR
+POINTER SAL_RESID_POINTER_MOVEFILELINK MOVEFLNK.PTR
+POINTER SAL_RESID_POINTER_COPYFILELINK COPYFLNK.PTR
+POINTER SAL_RESID_POINTER_MOVEFILES MOVEF2.PTR
+POINTER SAL_RESID_POINTER_COPYFILES COPYF2.PTR
+POINTER SAL_RESID_POINTER_DRAW_LINE DLINE.PTR
+POINTER SAL_RESID_POINTER_DRAW_RECT DRECT.PTR
+POINTER SAL_RESID_POINTER_DRAW_POLYGON DPOLYGON.PTR
+POINTER SAL_RESID_POINTER_DRAW_BEZIER DBEZIER.PTR
+POINTER SAL_RESID_POINTER_DRAW_ARC DARC.PTR
+POINTER SAL_RESID_POINTER_DRAW_PIE DPIE.PTR
+POINTER SAL_RESID_POINTER_DRAW_CIRCLECUT DCIRCCUT.PTR
+POINTER SAL_RESID_POINTER_DRAW_ELLIPSE DELLIPSE.PTR
+POINTER SAL_RESID_POINTER_DRAW_FREEHAND DFREE.PTR
+POINTER SAL_RESID_POINTER_DRAW_CONNECT DCONNECT.PTR
+POINTER SAL_RESID_POINTER_DRAW_TEXT DTEXT.PTR
+POINTER SAL_RESID_POINTER_DRAW_CAPTION DCAPT.PTR
+POINTER SAL_RESID_POINTER_CHART CHART.PTR
+POINTER SAL_RESID_POINTER_DETECTIVE DETECTIV.PTR
+POINTER SAL_RESID_POINTER_PIVOT_COL PIVOTCOL.PTR
+POINTER SAL_RESID_POINTER_PIVOT_ROW PIVOTROW.PTR
+POINTER SAL_RESID_POINTER_PIVOT_FIELD PIVOTFLD.PTR
+POINTER SAL_RESID_POINTER_CHAIN CHAIN.PTR
+POINTER SAL_RESID_POINTER_CHAIN_NOTALLOWED CHAINNOT.PTR
+POINTER SAL_RESID_POINTER_TIMEEVENT_MOVE TIMEMOVE.PTR
+POINTER SAL_RESID_POINTER_TIMEEVENT_SIZE TIMESIZE.PTR
+POINTER SAL_RESID_POINTER_AUTOSCROLL_N ASN.PTR
+POINTER SAL_RESID_POINTER_AUTOSCROLL_S ASS.PTR
+POINTER SAL_RESID_POINTER_AUTOSCROLL_W ASW.PTR
+POINTER SAL_RESID_POINTER_AUTOSCROLL_E ASE.PTR
+POINTER SAL_RESID_POINTER_AUTOSCROLL_NW ASNW.PTR
+POINTER SAL_RESID_POINTER_AUTOSCROLL_NE ASNE.PTR
+POINTER SAL_RESID_POINTER_AUTOSCROLL_SW ASSW.PTR
+POINTER SAL_RESID_POINTER_AUTOSCROLL_SE ASSE.PTR
+POINTER SAL_RESID_POINTER_AUTOSCROLL_NS ASNS.PTR
+POINTER SAL_RESID_POINTER_AUTOSCROLL_WE ASWE.PTR
+POINTER SAL_RESID_POINTER_AUTOSCROLL_NSWE ASNSWE.PTR
+
+POINTER SAL_RESID_POINTER_AIRBRUSH AIRBRUSH.PTR
+POINTER SAL_RESID_POINTER_TEXT_VERTICAL VTEXT.PTR
+POINTER SAL_RESID_POINTER_TAB_SELECT_S TBLSELS.PTR
+POINTER SAL_RESID_POINTER_TAB_SELECT_E TBLSELE.PTR
+POINTER SAL_RESID_POINTER_TAB_SELECT_SE TBLSELSE.PTR
+POINTER SAL_RESID_POINTER_TAB_SELECT_W TBLSELW.PTR
+POINTER SAL_RESID_POINTER_TAB_SELECT_SW TBLSELSW.PTR
+POINTER SAL_RESID_POINTER_PAINTBRUSH PNTBRSH.PTR
+
+ICON SAL_RESID_ICON_DEFAULT SD2.ICO
+
diff --git a/vcl/os2/source/src/sd.ico b/vcl/os2/source/src/sd.ico
new file mode 100644
index 000000000000..22cb33630b85
--- /dev/null
+++ b/vcl/os2/source/src/sd.ico
Binary files differ
diff --git a/vcl/os2/source/src/sd2.ico b/vcl/os2/source/src/sd2.ico
new file mode 100644
index 000000000000..f7edd4524bc1
--- /dev/null
+++ b/vcl/os2/source/src/sd2.ico
Binary files differ
diff --git a/vcl/os2/source/src/tblsele.ptr b/vcl/os2/source/src/tblsele.ptr
new file mode 100644
index 000000000000..627c2f61662b
--- /dev/null
+++ b/vcl/os2/source/src/tblsele.ptr
Binary files differ
diff --git a/vcl/os2/source/src/tblsels.ptr b/vcl/os2/source/src/tblsels.ptr
new file mode 100644
index 000000000000..3553c0d1f5ae
--- /dev/null
+++ b/vcl/os2/source/src/tblsels.ptr
Binary files differ
diff --git a/vcl/os2/source/src/tblselse.ptr b/vcl/os2/source/src/tblselse.ptr
new file mode 100644
index 000000000000..355e5105f58f
--- /dev/null
+++ b/vcl/os2/source/src/tblselse.ptr
Binary files differ
diff --git a/vcl/os2/source/src/tblselsw.ptr b/vcl/os2/source/src/tblselsw.ptr
new file mode 100644
index 000000000000..435dec00c3e1
--- /dev/null
+++ b/vcl/os2/source/src/tblselsw.ptr
Binary files differ
diff --git a/vcl/os2/source/src/tblselw.ptr b/vcl/os2/source/src/tblselw.ptr
new file mode 100644
index 000000000000..de64ad06d6a2
--- /dev/null
+++ b/vcl/os2/source/src/tblselw.ptr
Binary files differ
diff --git a/vcl/os2/source/src/timemove.ptr b/vcl/os2/source/src/timemove.ptr
new file mode 100755
index 000000000000..a9298cee867b
--- /dev/null
+++ b/vcl/os2/source/src/timemove.ptr
Binary files differ
diff --git a/vcl/os2/source/src/timesize.ptr b/vcl/os2/source/src/timesize.ptr
new file mode 100755
index 000000000000..e543c1ff790c
--- /dev/null
+++ b/vcl/os2/source/src/timesize.ptr
Binary files differ
diff --git a/vcl/os2/source/src/vshear.ptr b/vcl/os2/source/src/vshear.ptr
new file mode 100644
index 000000000000..f335d5ea949b
--- /dev/null
+++ b/vcl/os2/source/src/vshear.ptr
Binary files differ
diff --git a/vcl/os2/source/src/vsizebar.ptr b/vcl/os2/source/src/vsizebar.ptr
new file mode 100644
index 000000000000..b238889c594c
--- /dev/null
+++ b/vcl/os2/source/src/vsizebar.ptr
Binary files differ
diff --git a/vcl/os2/source/src/vsplit.ptr b/vcl/os2/source/src/vsplit.ptr
new file mode 100644
index 000000000000..662d760b0b2f
--- /dev/null
+++ b/vcl/os2/source/src/vsplit.ptr
Binary files differ
diff --git a/vcl/os2/source/src/vtext.ptr b/vcl/os2/source/src/vtext.ptr
new file mode 100644
index 000000000000..a7f9901bdf68
--- /dev/null
+++ b/vcl/os2/source/src/vtext.ptr
Binary files differ
diff --git a/vcl/os2/source/window/makefile b/vcl/os2/source/window/makefile
new file mode 100644
index 000000000000..e9aba563d9e8
--- /dev/null
+++ b/vcl/os2/source/window/makefile
@@ -0,0 +1,53 @@
+#*************************************************************************
+#
+# 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=SV
+TARGET=salwin
+
+# --- Settings -----------------------------------------------------
+
+!INCLUDE <svpre.mak>
+!INCLUDE <settings.mak>
+!INCLUDE <sv.mak>
+
+!IF "$(COM)"=="ICC"
+ENVCFLAGS=$(ENVCFLAGS) -D_STD_NO_NAMESPACE -D_VOS_NO_NAMESPACE -D_UNO_NO_NAMESPACE
+!ENDIF
+
+# --- Files --------------------------------------------------------
+
+CXXFILES= salframe.cxx \
+ salobj.cxx
+
+SLOFILES= $(SLO)\salframe.obj \
+ $(SLO)\salobj.obj
+
+# --- Targets ------------------------------------------------------
+
+!INCLUDE <target.mak>
diff --git a/vcl/os2/source/window/makefile.mk b/vcl/os2/source/window/makefile.mk
new file mode 100644
index 000000000000..f4a6ad0cb870
--- /dev/null
+++ b/vcl/os2/source/window/makefile.mk
@@ -0,0 +1,47 @@
+#*************************************************************************
+#
+# 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=SV
+TARGET=salwin
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+
+# --- Files --------------------------------------------------------
+
+CXXFILES__YD= salframe.cxx \
+ salobj.cxx
+
+SLOFILES= $(SLO)$/salframe.obj \
+ $(SLO)$/salobj.obj $(SLO)$/salmenu.obj
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
diff --git a/vcl/os2/source/window/salframe.cxx b/vcl/os2/source/window/salframe.cxx
new file mode 100644
index 000000000000..f3314c725255
--- /dev/null
+++ b/vcl/os2/source/window/salframe.cxx
@@ -0,0 +1,3774 @@
+/*************************************************************************
+ *
+ * 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 <string.h>
+
+#define INCL_DOS
+#define INCL_PM
+#define INCL_WIN
+#include <svpm.h>
+
+// =======================================================================
+
+#define _SV_SALFRAME_CXX
+
+#ifndef DEBUG_HXX
+#include <tools/debug.hxx>
+#endif
+
+#define private public
+
+#ifndef _SV_SALLANG_HXX
+#include <sallang.hxx>
+#endif
+#ifndef _SV_SALIDS_HRC
+#include <salids.hrc>
+#endif
+#include <saldata.hxx>
+#include <salinst.h>
+#include <salgdi.h>
+#include <salframe.h>
+#include <vcl/timer.hxx>
+#include <vcl/settings.hxx>
+#ifndef _SV_KEYCOES_HXX
+#include <vcl/keycodes.hxx>
+#endif
+#include <saltimer.h>
+
+#if OSL_DEBUG_LEVEL>10
+extern "C" int debug_printf(const char *f, ...);
+
+static BOOL _bCapture;
+
+#else
+#define debug_printf( ...) { 1; }
+#endif
+
+// =======================================================================
+
+HPOINTER ImplLoadPointer( ULONG nId );
+
+static void SetMaximizedFrameGeometry( HWND hWnd, Os2SalFrame* pFrame );
+static void UpdateFrameGeometry( HWND hWnd, Os2SalFrame* pFrame );
+static void ImplSalCalcFrameSize( HWND hWnd,
+ LONG& nFrameX, LONG& nFrameY, LONG& nCaptionY );
+static void ImplSalCalcFrameSize( const Os2SalFrame* pFrame,
+ LONG& nFrameX, LONG& nFrameY, LONG& nCaptionY );
+MRESULT EXPENTRY SalFrameSubClassWndProc( HWND hWnd, ULONG nMsg,
+ MPARAM nMP1, MPARAM nMP2 );
+
+// =======================================================================
+
+static LanguageType eImplKeyboardLanguage = LANGUAGE_DONTKNOW;
+BOOL Os2SalFrame::mbInReparent = FALSE;
+ULONG Os2SalFrame::mnInputLang = 0;
+
+// =======================================================================
+
+// define a new flag
+#define SWP_CENTER (SWP_NOAUTOCLOSE<<4)
+#define SWP_SHOWMAXIMIZED (SWP_ACTIVATE | SWP_SHOW | SWP_MAXIMIZE)
+#define SWP_SHOWMINIMIZED (SWP_ACTIVATE | SWP_SHOW | SWP_MINIMIZE)
+#define SWP_SHOWNORMAL (SWP_ACTIVATE | SWP_SHOW | SWP_RESTORE)
+
+static LONG nScreenHeight = WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN);
+static LONG nScreenWidth = WinQuerySysValue( HWND_DESKTOP, SV_CXSCREEN );
+
+BOOL APIENTRY _WinQueryWindowRect( HWND hwnd, PRECTL prclDest)
+{
+ BOOL rc = WinQueryWindowRect( hwnd, prclDest);
+ ULONG tmp = prclDest->yBottom;
+ prclDest->yBottom = prclDest->yTop;
+ prclDest->yTop = tmp;
+ return rc;
+}
+
+BOOL APIENTRY _WinQueryPointerPos (HWND hwndDesktop, PPOINTL pptl)
+{
+ BOOL rc = WinQueryPointerPos( hwndDesktop, pptl);
+ pptl->y = nScreenHeight - pptl->y;
+ return rc;
+}
+
+BOOL APIENTRY _WinQueryWindowPos( Os2SalFrame* pFrame, PSWP pswp)
+{
+ SWP swpOwner;
+ BOOL rc = WinQueryWindowPos( pFrame->mhWndFrame, pswp);
+
+#if OSL_DEBUG_LEVEL>1
+ debug_printf( "> WinQueryWindowPos hwnd %x at %d,%d (%dx%d)\n",
+ pFrame->mhWndFrame, pswp->x, pswp->y, pswp->cx, pswp->cy);
+#endif
+
+ Os2SalFrame* pParentFrame = pFrame->mpParentFrame;
+
+ //YD adjust to owner coordinates
+ if ( pParentFrame )
+ {
+ POINTL ptlOwner = {0};
+
+ // coords are relative to screen, map to parent frame client area
+ ptlOwner.x = pswp->x;
+ ptlOwner.y = pswp->y;
+ WinMapWindowPoints( HWND_DESKTOP, pParentFrame->mhWndClient, &ptlOwner, 1);
+ pswp->x = ptlOwner.x;
+ pswp->y = ptlOwner.y;
+ // get parent client area size
+ WinQueryWindowPos( pParentFrame->mhWndClient, &swpOwner);
+ } else
+ {
+ // no owner info, use DESKTOP????
+ swpOwner.cx = nScreenWidth;
+ swpOwner.cy = nScreenHeight;
+ }
+
+ // invert Y coordinate
+ pswp->y = swpOwner.cy - (pswp->y + pswp->cy);
+
+#if OSL_DEBUG_LEVEL>1
+ debug_printf( "< WinQueryWindowPos hwnd %x at %d,%d (%dx%d)\n",
+ pFrame->mhWndFrame, pswp->x, pswp->y, pswp->cx, pswp->cy);
+#endif
+ return rc;
+}
+
+BOOL APIENTRY _WinSetWindowPos( Os2SalFrame* pFrame, HWND hwndInsertBehind, LONG x, LONG y,
+ LONG cx, LONG cy, ULONG fl)
+{
+ SWP swpOwner = {0};
+ POINTL ptlOwner = {0};
+ HWND hParent = NULL;
+
+#if OSL_DEBUG_LEVEL>1
+ debug_printf( ">WinSetWindowPos hwnd %x at %d,%d (%dx%d) fl 0x%08x\n",
+ pFrame->mhWndFrame, x, y, cx, cy, fl);
+#endif
+
+ // first resize window if requested
+ if ( (fl & SWP_SIZE) ) {
+ ULONG flag = SWP_SIZE;
+ LONG nX = 0, nY = 0;
+ LONG frameFrameX, frameFrameY, frameCaptionY;
+
+ ImplSalCalcFrameSize( pFrame, frameFrameX, frameFrameY, frameCaptionY );
+ // if we change y size, we need to move the window down
+ // because os2 window origin is lower left corner
+ if (pFrame->maGeometry.nHeight != cy) {
+ SWP aSWP;
+ WinQueryWindowPos( pFrame->mhWndFrame, &aSWP);
+ nX = aSWP.x;
+ nY = aSWP.y - (cy + 2*frameFrameY + frameCaptionY - aSWP.cy);
+ flag |= SWP_MOVE;
+ }
+ WinSetWindowPos( pFrame->mhWndFrame, NULL, nX, nY,
+ cx+2*frameFrameX, cy+2*frameFrameY+frameCaptionY, flag);
+ fl = fl & ~SWP_SIZE;
+ }
+ else // otherwise get current size
+ {
+ SWP swp = {0};
+ WinQueryWindowPos( pFrame->mhWndClient, &swp);
+ cx = swp.cx;
+ cy = swp.cy;
+ }
+
+ // get parent window handle
+ Os2SalFrame* pParentFrame = pFrame->mpParentFrame;
+
+ // use desktop if parent is not defined
+ hParent = pParentFrame ? pParentFrame->mhWndClient : HWND_DESKTOP;
+ // if parent is not visible, use desktop as reference
+ hParent = WinIsWindowVisible( hParent) ? hParent : HWND_DESKTOP;
+
+ WinQueryWindowPos( hParent, &swpOwner);
+
+ //YD adjust to owner coordinates only when moving and not centering
+ //if (!(fl & SWP_CENTER) && (fl & SWP_MOVE))
+ if ((fl & SWP_MOVE))
+ {
+
+ // if SWP_CENTER is specified, change position to parent center
+ if (fl & SWP_CENTER) {
+ ptlOwner.x = (swpOwner.cx - cx) / 2;
+ ptlOwner.y = (swpOwner.cy - cy) / 2;
+#if OSL_DEBUG_LEVEL>0
+ debug_printf( "_WinSetWindowPos SWP_CENTER\n");
+#endif
+ fl = fl & ~SWP_CENTER;
+ } else {
+ // coords are relative to parent frame client area, map to screen
+ // map Y to OS/2 system coordinates
+ ptlOwner.x = x;
+ ptlOwner.y = swpOwner.cy - (y + cy);
+
+#if OSL_DEBUG_LEVEL>0
+ debug_printf( "_WinSetWindowPos owner 0x%x at %d,%d (%dx%d) OS2\n",
+ hParent, ptlOwner.x, ptlOwner.y, swpOwner.cx, swpOwner.cy);
+#endif
+ }
+ // map from client area to screen
+ WinMapWindowPoints( hParent, HWND_DESKTOP, &ptlOwner, 1);
+ x = ptlOwner.x;
+ y = ptlOwner.y;
+
+#if OSL_DEBUG_LEVEL>0
+ debug_printf( "_WinSetWindowPos owner 0x%x at %d,%d (%dx%d) MAPPED OS2\n",
+ hParent, ptlOwner.x, ptlOwner.y, swpOwner.cx, swpOwner.cy);
+#endif
+ }
+
+#if OSL_DEBUG_LEVEL>0
+ debug_printf( "<WinSetWindowPos hwnd %x at %d,%d (%dx%d) fl=%x\n",
+ pFrame->mhWndFrame, x, y, cx, cy, fl);
+#endif
+ return WinSetWindowPos( pFrame->mhWndFrame, hwndInsertBehind, x, y, 0, 0, fl);
+}
+
+// =======================================================================
+
+#if OSL_DEBUG_LEVEL > 0
+static void dumpWindowInfo( char* fnc, HWND hwnd)
+{
+ SWP aSWP;
+ HWND hwnd2;
+ char szTitle[256];
+
+#if 0
+ _WinQueryWindowPos( hwnd, &aSWP );
+ strcpy(szTitle,"");
+ WinQueryWindowText(hwnd, sizeof(szTitle), szTitle);
+ debug_printf( "%s: window %08x at %d,%d (size %dx%d) '%s'\n", fnc, hwnd,
+ aSWP.x, aSWP.y, aSWP.cx, aSWP.cy, szTitle);
+ hwnd2 = WinQueryWindow(hwnd, QW_PARENT);
+ _WinQueryWindowPos( hwnd2, &aSWP );
+ strcpy(szTitle,"");
+ WinQueryWindowText(hwnd2, sizeof(szTitle), szTitle);
+ debug_printf( "%s: parent %08x at %d,%d (size %dx%d) '%s'\n", fnc, hwnd2,
+ aSWP.x, aSWP.y, aSWP.cx, aSWP.cy, szTitle);
+ hwnd2 = WinQueryWindow(hwnd, QW_OWNER);
+ _WinQueryWindowPos( hwnd2, &aSWP );
+ strcpy(szTitle,"");
+ WinQueryWindowText(hwnd2, sizeof(szTitle), szTitle);
+ debug_printf( "%s: owner %08x at %d,%d (size %dx%d) '%s'\n", fnc, hwnd2,
+ aSWP.x, aSWP.y, aSWP.cx, aSWP.cy, szTitle);
+#endif
+}
+#endif
+
+// =======================================================================
+
+#ifdef ENABLE_IME
+
+struct ImplSalIMEProc
+{
+ ULONG nOrd;
+ PFN* pProc;
+};
+
+#define SAL_IME_PROC_COUNT 12
+
+// -----------------------------------------------------------------------
+
+static SalIMEData* GetSalIMEData()
+{
+ SalData* pSalData = GetSalData();
+
+ if ( !pSalData->mbIMEInit )
+ {
+ pSalData->mbIMEInit = TRUE;
+
+ HMODULE hMod = 0;
+ if ( 0 == DosLoadModule( NULL, 0, "OS2IM", &hMod ) )
+ {
+ SalIMEData* pIMEData = new SalIMEData;
+ BOOL bError = FALSE;
+ ImplSalIMEProc aProcAry[SAL_IME_PROC_COUNT] =
+ {
+ { 101, (PFN*)&(pIMEData->mpAssocIME) },
+ { 104, (PFN*)&(pIMEData->mpGetIME) },
+ { 106, (PFN*)&(pIMEData->mpReleaseIME) },
+ { 117, (PFN*)&(pIMEData->mpSetConversionFont) },
+ { 144, (PFN*)&(pIMEData->mpSetConversionFontSize) },
+ { 118, (PFN*)&(pIMEData->mpGetConversionString) },
+ { 122, (PFN*)&(pIMEData->mpGetResultString) },
+ { 115, (PFN*)&(pIMEData->mpSetCandidateWin) },
+ { 130, (PFN*)&(pIMEData->mpQueryIMEProperty) },
+ { 131, (PFN*)&(pIMEData->mpRequestIME) },
+ { 128, (PFN*)&(pIMEData->mpSetIMEMode) },
+ { 127, (PFN*)&(pIMEData->mpQueryIMEMode) }
+ };
+
+ pIMEData->mhModIME = hMod;
+ for ( USHORT i = 0; i < SAL_IME_PROC_COUNT; i++ )
+ {
+ if ( 0 != DosQueryProcAddr( pIMEData->mhModIME, aProcAry[i].nOrd, 0, aProcAry[i].pProc ) )
+ {
+ bError = TRUE;
+ break;
+ }
+ }
+
+ if ( bError )
+ {
+ DosFreeModule( pIMEData->mhModIME );
+ delete pIMEData;
+ }
+ else
+ pSalData->mpIMEData = pIMEData;
+ }
+ }
+
+ return pSalData->mpIMEData;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplReleaseSALIMEData()
+{
+ SalData* pSalData = GetSalData();
+
+ if ( pSalData->mpIMEData )
+ {
+ DosFreeModule( pSalData->mpIMEData->mhModIME );
+ delete pSalData->mpIMEData;
+ }
+}
+
+#endif
+
+// =======================================================================
+
+static void ImplSaveFrameState( Os2SalFrame* pFrame )
+{
+ // Position, Groesse und Status fuer GetWindowState() merken
+ if ( !pFrame->mbFullScreen )
+ {
+ SWP aSWP;
+ BOOL bVisible = WinIsWindowVisible( pFrame->mhWndFrame);
+
+ // Query actual state (maState uses screen coords)
+ WinQueryWindowPos( pFrame->mhWndFrame, &aSWP );
+
+ if ( aSWP.fl & SWP_MINIMIZE )
+ {
+#if OSL_DEBUG_LEVEL>0
+ debug_printf("Os2SalFrame::GetWindowState %08x SAL_FRAMESTATE_MINIMIZED\n",
+ pFrame->mhWndFrame);
+#endif
+ pFrame->maState.mnState |= SAL_FRAMESTATE_MINIMIZED;
+ if ( bVisible )
+ pFrame->mnShowState = SWP_SHOWMAXIMIZED;
+ }
+ else if ( aSWP.fl & SWP_MAXIMIZE )
+ {
+#if OSL_DEBUG_LEVEL>0
+ debug_printf("Os2SalFrame::GetWindowState %08x SAL_FRAMESTATE_MAXIMIZED\n",
+ pFrame->mhWndFrame);
+#endif
+ pFrame->maState.mnState &= ~SAL_FRAMESTATE_MINIMIZED;
+ pFrame->maState.mnState |= SAL_FRAMESTATE_MAXIMIZED;
+ if ( bVisible )
+ pFrame->mnShowState = SWP_SHOWMINIMIZED;
+ pFrame->mbRestoreMaximize = TRUE;
+ }
+ else
+ {
+ LONG nFrameX, nFrameY, nCaptionY;
+ ImplSalCalcFrameSize( pFrame, nFrameX, nFrameY, nCaptionY );
+ // to be consistent with Unix, the frame state is without(!) decoration
+ long nTopDeco = nFrameY + nCaptionY;
+ long nLeftDeco = nFrameX;
+ long nBottomDeco = nFrameY;
+ long nRightDeco = nFrameX;
+
+ pFrame->maState.mnState &= ~(SAL_FRAMESTATE_MINIMIZED | SAL_FRAMESTATE_MAXIMIZED);
+ // subtract decoration, store screen coords
+ pFrame->maState.mnX = aSWP.x+nLeftDeco;
+ pFrame->maState.mnY = nScreenHeight - (aSWP.y+aSWP.cy)+nTopDeco;
+ pFrame->maState.mnWidth = aSWP.cx-nLeftDeco-nRightDeco;
+ pFrame->maState.mnHeight = aSWP.cy-nTopDeco-nBottomDeco;
+#if OSL_DEBUG_LEVEL>0
+ debug_printf("Os2SalFrame::GetWindowState %08x (%dx%d) at %d,%d VCL\n",
+ pFrame->mhWndFrame,
+ pFrame->maState.mnWidth,pFrame->maState.mnHeight,pFrame->maState.mnX,pFrame->maState.mnY);
+#endif
+ if ( bVisible )
+ pFrame->mnShowState = SWP_SHOWNORMAL;
+ pFrame->mbRestoreMaximize = FALSE;
+ //debug_printf( "ImplSaveFrameState: window %08x at %d,%d (size %dx%d)\n",
+ // pFrame->mhWndFrame,
+ // pFrame->maState.mnX, pFrame->maState.mnY, pFrame->maState.mnWidth, pFrame->maState.mnHeight);
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+long ImplSalCallbackDummy( void*, SalFrame*, USHORT, const void* )
+{
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplSalCalcFrameSize( HWND hWnd,
+ LONG& nFrameX, LONG& nFrameY, LONG& nCaptionY )
+{
+ Os2SalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( !pFrame )
+ return;
+ return ImplSalCalcFrameSize( pFrame, nFrameX, nFrameY, nCaptionY );
+}
+
+static void ImplSalCalcFrameSize( const Os2SalFrame* pFrame,
+ LONG& nFrameX, LONG& nFrameY, LONG& nCaptionY )
+{
+ if ( pFrame->mbSizeBorder )
+ {
+ nFrameX = WinQuerySysValue( HWND_DESKTOP, SV_CXSIZEBORDER );
+ nFrameY = WinQuerySysValue( HWND_DESKTOP, SV_CYSIZEBORDER );
+ }
+ else if ( pFrame->mbFixBorder )
+ {
+ nFrameX = WinQuerySysValue( HWND_DESKTOP, SV_CXDLGFRAME );
+ nFrameY = WinQuerySysValue( HWND_DESKTOP, SV_CYDLGFRAME );
+ }
+ else if ( pFrame->mbBorder )
+ {
+ nFrameX = WinQuerySysValue( HWND_DESKTOP, SV_CXBORDER );
+ nFrameY = WinQuerySysValue( HWND_DESKTOP, SV_CYBORDER );
+ }
+ else
+ {
+ nFrameX = 0;
+ nFrameY = 0;
+ }
+ if ( pFrame->mbCaption )
+ nCaptionY = WinQuerySysValue( HWND_DESKTOP, SV_CYTITLEBAR );
+ else
+ nCaptionY = 0;
+
+#if OSL_DEBUG_LEVEL>0
+ //if (_bCapture)
+ debug_printf("ImplSalCalcFrameSize 0x%08x x=%d y=%d t=%d\n", pFrame->mhWndFrame, nFrameX, nFrameY, nCaptionY);
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplSalCalcFullScreenSize( const Os2SalFrame* pFrame,
+ LONG& rX, LONG& rY, LONG& rDX, LONG& rDY )
+{
+ // set window to screen size
+ LONG nFrameX, nFrameY, nCaptionY;
+ LONG rScreenDX = WinQuerySysValue( HWND_DESKTOP, SV_CXSCREEN );
+ LONG rScreenDY = WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN );
+
+ // Framegroessen berechnen
+ ImplSalCalcFrameSize( pFrame, nFrameX, nFrameY, nCaptionY );
+
+ rX = -nFrameX;
+ rY = -(nFrameY+nCaptionY);
+ rDX = rScreenDX+(nFrameX*2);
+ rDY = rScreenDY+(nFrameY*2)+nCaptionY;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplSalFrameFullScreenPos( Os2SalFrame* pFrame, BOOL bAlways = FALSE )
+{
+ SWP aSWP;
+ _WinQueryWindowPos( pFrame, &aSWP );
+ if ( bAlways || !(aSWP.fl & SWP_MINIMIZE) )
+ {
+ // set window to screen size
+ LONG nX;
+ LONG nY;
+ LONG nWidth;
+ LONG nHeight;
+ ImplSalCalcFullScreenSize( pFrame, nX, nY, nWidth, nHeight );
+ _WinSetWindowPos( pFrame, 0,
+ nX, nY, nWidth, nHeight,
+ SWP_MOVE | SWP_SIZE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+// Uebersetzungstabelle von System-Keycodes in StarView-Keycodes
+#define KEY_TAB_SIZE (VK_ENDDRAG+1)
+
+static USHORT aImplTranslateKeyTab[KEY_TAB_SIZE] =
+{
+ // StarView-Code System-Code Index
+ 0, // 0x00
+ 0, // VK_BUTTON1 0x01
+ 0, // VK_BUTTON2 0x02
+ 0, // VK_BUTTON3 0x03
+ 0, // VK_BREAK 0x04
+ KEY_BACKSPACE, // VK_BACKSPACE 0x05
+ KEY_TAB, // VK_TAB 0x06
+ KEY_TAB, // VK_BACKTAB 0x07
+ KEY_RETURN, // VK_NEWLINE 0x08
+ 0, // VK_SHIFT 0x09
+ 0, // VK_CTRL 0x0A
+ 0, // VK_ALT 0x0B
+ 0, // VK_ALTGRAF 0x0C
+ 0, // VK_PAUSE 0x0D
+ 0, // VK_CAPSLOCK 0x0E
+ KEY_ESCAPE, // VK_ESC 0x0F
+ KEY_SPACE, // VK_SPACE 0x10
+ KEY_PAGEUP, // VK_PAGEUP 0x11
+ KEY_PAGEDOWN, // VK_PAGEDOWN 0x12
+ KEY_END, // VK_END 0x13
+ KEY_HOME, // VK_HOME 0x14
+ KEY_LEFT, // VK_LEFT 0x15
+ KEY_UP, // VK_UP 0x16
+ KEY_RIGHT, // VK_RIGHT 0x17
+ KEY_DOWN, // VK_DOWN 0x18
+ 0, // VK_PRINTSCRN 0x19
+ KEY_INSERT, // VK_INSERT 0x1A
+ KEY_DELETE, // VK_DELETE 0x1B
+ 0, // VK_SCRLLOCK 0x1C
+ 0, // VK_NUMLOCK 0x1D
+ KEY_RETURN, // VK_ENTER 0x1E
+ 0, // VK_SYSRQ 0x1F
+ KEY_F1, // VK_F1 0x20
+ KEY_F2, // VK_F2 0x21
+ KEY_F3, // VK_F3 0x22
+ KEY_F4, // VK_F4 0x23
+ KEY_F5, // VK_F5 0x24
+ KEY_F6, // VK_F6 0x25
+ KEY_F7, // VK_F7 0x26
+ KEY_F8, // VK_F8 0x27
+ KEY_F9, // VK_F9 0x28
+ KEY_F10, // VK_F10 0x29
+ KEY_F11, // VK_F11 0x2A
+ KEY_F12, // VK_F12 0x2B
+ KEY_F13, // VK_F13 0x2C
+ KEY_F14, // VK_F14 0x2D
+ KEY_F15, // VK_F15 0x2E
+ KEY_F16, // VK_F16 0x2F
+ KEY_F17, // VK_F17 0x30
+ KEY_F18, // VK_F18 0x31
+ KEY_F19, // VK_F19 0x32
+ KEY_F20, // VK_F20 0x33
+ KEY_F21, // VK_F21 0x34
+ KEY_F22, // VK_F22 0x35
+ KEY_F23, // VK_F23 0x36
+ KEY_F24, // VK_F24 0x37
+ 0 // VK_ENDDRAG 0x38
+};
+
+// =======================================================================
+
+SalFrame* ImplSalCreateFrame( Os2SalInstance* pInst, HWND hWndParent, ULONG nSalFrameStyle )
+{
+ SalData* pSalData = GetSalData();
+ Os2SalFrame* pFrame = new Os2SalFrame;
+ HWND hWndFrame;
+ HWND hWndClient;
+ ULONG nFrameFlags = FCF_NOBYTEALIGN | FCF_SCREENALIGN;
+ ULONG nFrameStyle = 0;
+ ULONG nClientStyle = WS_CLIPSIBLINGS;
+ BOOL bSubFrame = FALSE;
+
+#if OSL_DEBUG_LEVEL>0
+ debug_printf(">ImplSalCreateFrame hWndParent 0x%x, nSalFrameStyle 0x%x\n", hWndParent, nSalFrameStyle);
+#endif
+
+ if ( hWndParent )
+ {
+ bSubFrame = TRUE;
+ pFrame->mbNoIcon = TRUE;
+ }
+
+ // determine creation data (bei Moveable nehmen wir DLG-Border, damit
+ // es besser aussieht)
+ if ( nSalFrameStyle & SAL_FRAME_STYLE_CLOSEABLE )
+ nFrameFlags |= FCF_CLOSEBUTTON;
+
+ if ( nSalFrameStyle & SAL_FRAME_STYLE_MOVEABLE ) {
+ pFrame->mbCaption = TRUE;
+ nFrameStyle = WS_ANIMATE;
+ nFrameFlags |= FCF_SYSMENU | FCF_TITLEBAR | FCF_DLGBORDER;
+ if ( !hWndParent )
+ nFrameFlags |= FCF_MINBUTTON;
+
+ if ( nSalFrameStyle & SAL_FRAME_STYLE_SIZEABLE )
+ {
+ pFrame->mbSizeBorder = TRUE;
+ nFrameFlags |= FCF_SIZEBORDER;
+ if ( !hWndParent )
+ nFrameFlags |= FCF_MAXBUTTON;
+ }
+ else
+ pFrame->mbFixBorder = TRUE;
+
+ // add task list style if not a tool window
+ if ( !(nSalFrameStyle & SAL_FRAME_STYLE_TOOLWINDOW) ) {
+ nFrameFlags |= FCF_TASKLIST;
+ }
+ }
+
+ if( nSalFrameStyle & SAL_FRAME_STYLE_TOOLWINDOW )
+ {
+ pFrame->mbNoIcon = TRUE;
+ // YD gives small caption -> nExSysStyle |= WS_EX_TOOLWINDOW;
+ }
+
+ if ( nSalFrameStyle & SAL_FRAME_STYLE_FLOAT )
+ {
+ //nExSysStyle |= WS_EX_TOOLWINDOW;
+ pFrame->mbFloatWin = TRUE;
+ }
+ //if( nSalFrameStyle & SAL_FRAME_STYLE_TOOLTIP )
+ // nExSysStyle |= WS_EX_TOPMOST;
+
+ // init frame data
+ pFrame->mnStyle = nSalFrameStyle;
+
+ // determine show style
+ pFrame->mnShowState = SWP_SHOWNORMAL;
+
+ // create frame
+ //YD FIXME this is a potential bug with multiple threads and cuncurrent
+ //window creation, because this field is accessed in
+ //WM_CREATE to get window data,
+ pSalData->mpCreateFrame = pFrame;
+
+ //YD FIXME if SAL_FRAME_CHILD is specified, use hWndParent as parent handle...
+ hWndFrame = WinCreateStdWindow( HWND_DESKTOP, nFrameStyle, &nFrameFlags,
+ (PSZ)(bSubFrame ? SAL_SUBFRAME_CLASSNAME : SAL_FRAME_CLASSNAME),
+ NULL,
+ nClientStyle, 0, 0, &hWndClient );
+ debug_printf("ImplSalCreateFrame hWndParent 0x%x, hWndFrame 0x%x, hWndClient 0x%x\n", hWndParent, hWndFrame, hWndClient);
+ if ( !hWndFrame )
+ {
+ delete pFrame;
+ return NULL;
+ }
+
+ // Parent setzen (Owner)
+ if ( hWndParent != 0 && hWndParent != HWND_DESKTOP )
+ WinSetOwner( hWndFrame, hWndParent );
+
+ Os2SalFrame* pParentFrame = GetWindowPtr( hWndParent );
+ if ( pParentFrame )
+ pFrame->mpParentFrame = pParentFrame;
+
+ // Icon setzen (YD win32 does it in the class registration)
+ if ( nFrameFlags & FCF_MINBUTTON )
+ WinSendMsg( hWndFrame, WM_SETICON, (MPARAM)pInst->mhAppIcon, (MPARAM)0 );
+
+ // If we have an Window with an Caption Bar and without
+ // an MaximizeBox, we change the SystemMenu
+ if ( (nFrameFlags & (FCF_TITLEBAR | FCF_MAXBUTTON)) == (FCF_TITLEBAR) )
+ {
+ HWND hSysMenu = WinWindowFromID( hWndFrame, FID_SYSMENU );
+ if ( hSysMenu )
+ {
+ if ( !(nFrameFlags & (FCF_MINBUTTON | FCF_MAXBUTTON)) )
+ WinEnableMenuItem(hSysMenu, SC_RESTORE, FALSE);
+ if ( !(nFrameFlags & FCF_MINBUTTON) )
+ WinEnableMenuItem(hSysMenu, SC_MINIMIZE, FALSE);
+ if ( !(nFrameFlags & FCF_MAXBUTTON) )
+ WinEnableMenuItem(hSysMenu, SC_MAXIMIZE, FALSE);
+ if ( !(nFrameFlags & FCF_SIZEBORDER) )
+ WinEnableMenuItem(hSysMenu, SC_SIZE, FALSE);
+ }
+ }
+ if ( (nFrameFlags & FCF_SYSMENU) && !(nSalFrameStyle & SAL_FRAME_STYLE_CLOSEABLE) )
+ {
+ HWND hSysMenu = WinWindowFromID( hWndFrame, FID_SYSMENU );
+ if ( hSysMenu )
+ {
+ WinEnableMenuItem(hSysMenu, SC_CLOSE, FALSE);
+ }
+ }
+
+ // ticket#124 subclass frame window: we need to intercept TRACK message
+ aSalShlData.mpFrameProc = WinSubclassWindow( hWndFrame, SalFrameSubClassWndProc);
+
+ // init OS/2 frame data
+ pFrame->mhAB = pInst->mhAB;
+
+ // YD 18/08 under OS/2, invisible frames have size 0,0 at 0,0, so
+ // we need to set an initial size/position manually
+ SWP aSWP;
+ memset( &aSWP, 0, sizeof( aSWP ) );
+ WinQueryTaskSizePos( pInst->mhAB, 0, &aSWP );
+ WinSetWindowPos( hWndFrame, NULL, aSWP.x, aSWP.y, aSWP.cx, aSWP.cy,
+ SWP_MOVE | SWP_SIZE);
+
+#ifdef ENABLE_IME
+ // Input-Context einstellen
+ SalIMEData* pIMEData = GetSalIMEData();
+ if ( pIMEData )
+ {
+ pFrame->mhIMEContext = 0;
+ if ( 0 != pIMEData->mpAssocIME( hWndClient, pFrame->mhIMEContext, &pFrame->mhDefIMEContext ) )
+ pFrame->mhDefIMEContext = 0;
+ }
+ else
+ {
+ pFrame->mhIMEContext = 0;
+ pFrame->mhDefIMEContext = 0;
+ }
+#endif
+
+ RECTL rectl;
+ _WinQueryWindowRect( hWndClient, &rectl );
+ pFrame->mnWidth = rectl.xRight;
+ pFrame->mnHeight = rectl.yBottom;
+ debug_printf( "ImplSalCreateFrame %dx%d\n", pFrame->mnWidth, pFrame->mnHeight);
+ ImplSaveFrameState( pFrame );
+ pFrame->mbDefPos = TRUE;
+
+ UpdateFrameGeometry( hWndFrame, pFrame );
+
+ if( pFrame->mnShowState == SWP_SHOWMAXIMIZED )
+ {
+ // #96084 set a useful internal window size because
+ // the window will not be maximized (and the size updated) before show()
+ SetMaximizedFrameGeometry( hWndFrame, pFrame );
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ dumpWindowInfo( "<ImplSalCreateFrame (exit)", hWndFrame);
+#endif
+
+ return pFrame;
+}
+
+// =======================================================================
+
+Os2SalFrame::Os2SalFrame()
+{
+ SalData* pSalData = GetSalData();
+
+ mbGraphics = NULL;
+ mhPointer = WinQuerySysPointer( HWND_DESKTOP, SPTR_ARROW, FALSE );
+ mpGraphics = NULL;
+ mpInst = NULL;
+ mbFullScreen = FALSE;
+ mbAllwayOnTop = FALSE;
+ mbVisible = FALSE;
+ mbMinHide = FALSE;
+ mbInShow = FALSE;
+ mbRestoreMaximize = FALSE;
+ mbInMoveMsg = FALSE;
+ mbInSizeMsg = FALSE;
+ mbDefPos = TRUE;
+ mbOverwriteState = TRUE;
+ mbHandleIME = FALSE;
+ mbConversionMode = FALSE;
+ mbCandidateMode = FALSE;
+ mbCaption = FALSE;
+ //mhDefIMEContext = 0;
+ mpGraphics = NULL;
+ mnShowState = SWP_SHOWNORMAL;
+ mnWidth = 0;
+ mnHeight = 0;
+ mnMinWidth = 0;
+ mnMinHeight = 0;
+ mnMaxWidth = SHRT_MAX;
+ mnMaxHeight = SHRT_MAX;
+ mnInputLang = 0;
+ mnKeyboardHandle = 0;
+ mbGraphics = FALSE;
+ mbCaption = FALSE;
+ mbBorder = FALSE;
+ mbFixBorder = FALSE;
+ mbSizeBorder = FALSE;
+ mbFullScreen = FALSE;
+ //mbPresentation = FALSE;
+ mbInShow = FALSE;
+ mbRestoreMaximize = FALSE;
+ mbInMoveMsg = FALSE;
+ mbInSizeMsg = FALSE;
+ //mbFullScreenToolWin = FALSE;
+ mbDefPos = TRUE;
+ mbOverwriteState = TRUE;
+ //mbIME = FALSE;
+ mbHandleIME = FALSE;
+ //mbSpezIME = FALSE;
+ //mbAtCursorIME = FALSE;
+ mbCandidateMode = FALSE;
+ mbFloatWin = FALSE;
+ mbNoIcon = FALSE;
+ //mSelectedhMenu = 0;
+ //mLastActivatedhMenu = 0;
+ mpParentFrame = NULL;
+
+ memset( &maState, 0, sizeof( SalFrameState ) );
+ maSysData.nSize = sizeof( SystemEnvData );
+ memset( &maGeometry, 0, sizeof( maGeometry ) );
+
+ // insert frame in framelist
+ mpNextFrame = pSalData->mpFirstFrame;
+ pSalData->mpFirstFrame = this;
+}
+
+// -----------------------------------------------------------------------
+
+Os2SalFrame::~Os2SalFrame()
+{
+ SalData* pSalData = GetSalData();
+
+ // destroy DC
+ if ( mpGraphics )
+ {
+ ImplSalDeInitGraphics( mpGraphics );
+ WinReleasePS( mpGraphics->mhPS );
+ delete mpGraphics;
+ }
+
+ // destroy system frame
+ WinDestroyWindow( mhWndFrame );
+
+ // remove frame from framelist
+ if ( this == pSalData->mpFirstFrame )
+ pSalData->mpFirstFrame = mpNextFrame;
+ else
+ {
+ Os2SalFrame* pTempFrame = pSalData->mpFirstFrame;
+ while ( pTempFrame->mpNextFrame != this )
+ pTempFrame = pTempFrame->mpNextFrame;
+
+ pTempFrame->mpNextFrame = mpNextFrame;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static HDC ImplWinGetDC( HWND hWnd )
+{
+ HDC hDC = WinQueryWindowDC( hWnd );
+ if ( !hDC )
+ hDC = WinOpenWindowDC( hWnd );
+ return hDC;
+}
+
+// -----------------------------------------------------------------------
+
+SalGraphics* Os2SalFrame::GetGraphics()
+{
+ if ( mbGraphics )
+ return NULL;
+
+ if ( !mpGraphics )
+ {
+ SalData* pSalData = GetSalData();
+ mpGraphics = new Os2SalGraphics;
+ mpGraphics->mhPS = WinGetPS( mhWndClient );
+ mpGraphics->mhDC = ImplWinGetDC( mhWndClient );
+ mpGraphics->mhWnd = mhWndClient;
+ mpGraphics->mnHeight = mnHeight;
+ mpGraphics->mbPrinter = FALSE;
+ mpGraphics->mbVirDev = FALSE;
+ mpGraphics->mbWindow = TRUE;
+ mpGraphics->mbScreen = TRUE;
+ ImplSalInitGraphics( mpGraphics );
+ mbGraphics = TRUE;
+ }
+ else
+ mbGraphics = TRUE;
+
+ return mpGraphics;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalFrame::ReleaseGraphics( SalGraphics* )
+{
+ mbGraphics = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Os2SalFrame::PostEvent( void* pData )
+{
+ return (BOOL)WinPostMsg( mhWndClient, SAL_MSG_USEREVENT, 0, (MPARAM)pData );
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalFrame::SetTitle( const XubString& rTitle )
+{
+ // set window title
+ ByteString title( rTitle, gsl_getSystemTextEncoding() );
+ debug_printf("Os2SalFrame::SetTitle %x '%s'\n", mhWndFrame, title.GetBuffer() );
+ WinSetWindowText( mhWndFrame, title.GetBuffer() );
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalFrame::SetIcon( USHORT nIcon )
+{
+ debug_printf("Os2SalFrame::SetIcon\n");
+
+ // If we have a window without an Icon (for example a dialog), ignore this call
+ if ( mbNoIcon )
+ return;
+
+ // 0 means default (class) icon
+ HPOINTER hIcon = NULL;
+ if ( !nIcon )
+ nIcon = 1;
+
+ ImplLoadSalIcon( nIcon, hIcon );
+
+ DBG_ASSERT( hIcon , "Os2SalFrame::SetIcon(): Could not load icon !" );
+
+ // Icon setzen
+ WinSendMsg( mhWndFrame, WM_SETICON, (MPARAM)hIcon, (MPARAM)0 );
+}
+
+// -----------------------------------------------------------------------
+
+SalFrame* Os2SalFrame::GetParent() const
+{
+ //debug_printf("Os2SalFrame::GetParent\n");
+ return GetWindowPtr( WinQueryWindow(mhWndFrame, QW_OWNER) );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplSalShow( HWND hWnd, ULONG bVisible, ULONG bNoActivate )
+{
+ Os2SalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( !pFrame )
+ return;
+
+ if ( bVisible )
+ {
+ pFrame->mbDefPos = FALSE;
+ pFrame->mbOverwriteState = TRUE;
+ pFrame->mbInShow = TRUE;
+
+#if OSL_DEBUG_LEVEL > 0
+ debug_printf( "ImplSalShow hwnd %x visible flag %d, no activate: flag %d\n", hWnd, bVisible, bNoActivate);
+#endif
+
+ if( bNoActivate )
+ WinSetWindowPos(hWnd, NULL, 0, 0, 0, 0, SWP_SHOW);
+ else
+ WinSetWindowPos(hWnd, NULL, 0, 0, 0, 0, pFrame->mnShowState);
+
+ pFrame->mbInShow = FALSE;
+
+ // Direct Paint only, if we get the SolarMutx
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ WinUpdateWindow( hWnd );
+ ImplSalYieldMutexRelease();
+ }
+ }
+ else
+ {
+#if OSL_DEBUG_LEVEL > 0
+ debug_printf( "ImplSalShow hwnd %x HIDE\n");
+#endif
+ WinSetWindowPos(hWnd, NULL, 0, 0, 0, 0, SWP_HIDE);
+ }
+}
+
+
+// -----------------------------------------------------------------------
+
+
+void Os2SalFrame::SetExtendedFrameStyle( SalExtStyle nExtStyle )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalFrame::Show( BOOL bVisible, BOOL bNoActivate )
+{
+ // Post this Message to the window, because this only works
+ // in the thread of the window, which has create this window.
+ // We post this message to avoid deadlocks
+ if ( GetSalData()->mnAppThreadId != GetCurrentThreadId() )
+ WinPostMsg( mhWndFrame, SAL_MSG_SHOW, (MPARAM)bVisible, (MPARAM)bNoActivate );
+ else
+ ImplSalShow( mhWndFrame, bVisible, bNoActivate );
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalFrame::Enable( BOOL bEnable )
+{
+ WinEnableWindow( mhWndFrame, bEnable );
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalFrame::SetMinClientSize( long nWidth, long nHeight )
+{
+ debug_printf("Os2SalFrame::SetMinClientSize\n");
+ mnMinWidth = nWidth;
+ mnMinHeight = nHeight;
+}
+
+void Os2SalFrame::SetMaxClientSize( long nWidth, long nHeight )
+{
+ debug_printf("Os2SalFrame::SetMaxClientSize\n");
+ mnMaxWidth = nWidth;
+ mnMaxHeight = nHeight;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalFrame::SetPosSize( long nX, long nY, long nWidth, long nHeight,
+ USHORT nFlags )
+{
+ // calculation frame size
+ USHORT nEvent = 0;
+ ULONG nPosFlags = 0;
+
+#if OSL_DEBUG_LEVEL > 0
+ //dumpWindowInfo( "-Os2SalFrame::SetPosSize", mhWndFrame);
+ debug_printf( ">Os2SalFrame::SetPosSize go to %d,%d (%dx%d) VCL\n",nX,nY,nWidth,nHeight);
+#endif
+
+ SWP aSWP;
+ _WinQueryWindowPos( this, &aSWP );
+ BOOL bVisible = WinIsWindowVisible( mhWndFrame );
+ if ( !bVisible )
+ {
+ if ( mbFloatWin )
+ mnShowState = SWP_SHOW;
+ else
+ mnShowState = SWP_SHOWNORMAL;
+ }
+ else
+ {
+ if ( (aSWP.fl & SWP_MINIMIZE) || (aSWP.fl & SWP_MAXIMIZE) )
+ WinSetWindowPos(mhWndFrame, NULL, 0, 0, 0, 0, SWP_RESTORE );
+ }
+
+ if ( (nFlags & (SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y)) ) {
+ nPosFlags |= SWP_MOVE;
+#if OSL_DEBUG_LEVEL > 0
+ debug_printf( "-Os2SalFrame::SetPosSize MOVE to %d,%d\n", nX, nY);
+#endif
+ //DBG_ASSERT( nX && nY, " Windowposition of (0,0) requested!" );
+ nEvent = SALEVENT_MOVE;
+ }
+
+ if ( (nFlags & (SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT)) ) {
+ nPosFlags |= SWP_SIZE;
+#if OSL_DEBUG_LEVEL > 0
+ debug_printf( "-Os2SalFrame::SetPosSize SIZE to %d,%d\n", nWidth,nHeight);
+#endif
+ nEvent = (nEvent == SALEVENT_MOVE) ? SALEVENT_MOVERESIZE : SALEVENT_RESIZE;
+ }
+
+ // Default-Position, dann zentrieren, ansonsten Position beibehalten
+ if ( mbDefPos && !(nPosFlags & SWP_MOVE))
+ {
+ // calculate bottom left corner of frame
+ mbDefPos = FALSE;
+ nPosFlags |= SWP_MOVE | SWP_CENTER;
+ nEvent = SALEVENT_MOVERESIZE;
+#if OSL_DEBUG_LEVEL > 10
+ debug_printf( "-Os2SalFrame::SetPosSize CENTER\n");
+ debug_printf( "-Os2SalFrame::SetPosSize default position to %d,%d\n", nX, nY);
+#endif
+ }
+
+ // Adjust Window in the screen
+ BOOL bCheckOffScreen = TRUE;
+
+ // but don't do this for floaters or ownerdraw windows that are currently moved interactively
+ if( (mnStyle & SAL_FRAME_STYLE_FLOAT) && !(mnStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) )
+ bCheckOffScreen = FALSE;
+
+ if( mnStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION )
+ {
+ // may be the window is currently being moved (mouse is captured), then no check is required
+ if( mhWndClient == WinQueryCapture( HWND_DESKTOP) )
+ bCheckOffScreen = FALSE;
+ else
+ bCheckOffScreen = TRUE;
+ }
+
+ if( bCheckOffScreen )
+ {
+ if ( nX+nWidth > nScreenWidth )
+ nX = nScreenWidth - nWidth;
+ if ( nY+nHeight > nScreenHeight )
+ nY = nScreenHeight - nHeight;
+ if ( nX < 0 )
+ nX = 0;
+ if ( nY < 0 )
+ nY = 0;
+ }
+
+ // bring floating windows always to top
+ // do not change zorder, otherwise tooltips will bring main window to top (ticket:14)
+ //if( (mnStyle & SAL_FRAME_STYLE_FLOAT) )
+ // nPosFlags |= SWP_ZORDER; // do not change z-order
+
+ // set new position
+ _WinSetWindowPos( this, HWND_TOP, nX, nY, nWidth, nHeight, nPosFlags); // | SWP_RESTORE
+
+ UpdateFrameGeometry( mhWndFrame, this );
+
+ // Notification -- really ???
+ if( nEvent )
+ CallCallback( nEvent, NULL );
+
+#if OSL_DEBUG_LEVEL > 0
+ dumpWindowInfo( "<Os2SalFrame::SetPosSize (exit)", mhWndFrame);
+#endif
+
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalFrame::SetParent( SalFrame* pNewParent )
+{
+ APIRET rc;
+#if OSL_DEBUG_LEVEL>0
+ debug_printf("Os2SalFrame::SetParent mhWndFrame 0x%08x to 0x%08x\n",
+ static_cast<Os2SalFrame*>(this)->mhWndFrame,
+ static_cast<Os2SalFrame*>(pNewParent)->mhWndClient);
+#endif
+ Os2SalFrame::mbInReparent = TRUE;
+ //rc = WinSetParent(static_cast<Os2SalFrame*>(this)->mhWndFrame,
+ // static_cast<Os2SalFrame*>(pNewParent)->mhWndClient, TRUE);
+ rc = WinSetOwner(static_cast<Os2SalFrame*>(this)->mhWndFrame,
+ static_cast<Os2SalFrame*>(pNewParent)->mhWndClient);
+ mpParentFrame = static_cast<Os2SalFrame*>(pNewParent);
+ Os2SalFrame::mbInReparent = FALSE;
+}
+
+bool Os2SalFrame::SetPluginParent( SystemParentData* pNewParent )
+{
+ APIRET rc;
+ if ( pNewParent->hWnd == 0 )
+ {
+ pNewParent->hWnd = HWND_DESKTOP;
+ }
+
+ Os2SalFrame::mbInReparent = TRUE;
+ rc = WinSetOwner(static_cast<Os2SalFrame*>(this)->mhWndFrame,
+ pNewParent->hWnd);
+ Os2SalFrame::mbInReparent = FALSE;
+ return true;
+}
+
+
+// -----------------------------------------------------------------------
+
+void Os2SalFrame::GetWorkArea( RECTL &rRect )
+{
+ rRect.xLeft = rRect.yTop = 0;
+ rRect.xRight = WinQuerySysValue( HWND_DESKTOP, SV_CXSCREEN )-1;
+ rRect.yBottom = WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN )-1;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalFrame::GetWorkArea( Rectangle &rRect )
+{
+ RECTL aRect;
+ GetWorkArea( aRect);
+ rRect.nLeft = aRect.xLeft;
+ rRect.nRight = aRect.xRight; // win -1;
+ rRect.nTop = aRect.yTop;
+ rRect.nBottom = aRect.yBottom; // win -1;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalFrame::GetClientSize( long& rWidth, long& rHeight )
+{
+ rWidth = maGeometry.nWidth;
+ rHeight = maGeometry.nHeight;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalFrame::SetWindowState( const SalFrameState* pState )
+{
+ LONG nX;
+ LONG nY;
+ LONG nWidth;
+ LONG nHeight;
+ ULONG nPosSize = 0;
+
+#if OSL_DEBUG_LEVEL>0
+ debug_printf("Os2SalFrame::SetWindowState\n");
+ debug_printf("Os2SalFrame::SetWindowState %08x (%dx%d) at %d,%d VCL\n",
+ mhWndFrame,
+ pState->mnWidth,pState->mnHeight,pState->mnX,pState->mnY);
+#endif
+
+ BOOL bVisible = WinIsWindowVisible( mhWndFrame );
+
+ // get screen coordinates
+ SWP aSWP;
+ WinQueryWindowPos( mhWndFrame, &aSWP );
+ LONG nFrameX, nFrameY, nCaptionY;
+ ImplSalCalcFrameSize( this, nFrameX, nFrameY, nCaptionY );
+
+ long nTopDeco = nFrameY + nCaptionY;
+ long nLeftDeco = nFrameX;
+ long nBottomDeco = nFrameY;
+ long nRightDeco = nFrameX;
+
+ // Fenster-Position/Groesse in den Bildschirm einpassen
+ if ((pState->mnMask & (SAL_FRAMESTATE_MASK_X | SAL_FRAMESTATE_MASK_Y)) )
+ nPosSize |= SWP_MOVE;
+ if ((pState->mnMask & (SAL_FRAMESTATE_MASK_WIDTH | SAL_FRAMESTATE_MASK_HEIGHT)) )
+ nPosSize |= SWP_SIZE;
+
+ if ( pState->mnMask & SAL_FRAMESTATE_MASK_X )
+ nX = (int)pState->mnX - nLeftDeco;
+ else
+ nX = aSWP.x;
+
+ // keep Y inverted since height is still unknown, will invert later
+ if ( pState->mnMask & SAL_FRAMESTATE_MASK_Y )
+ nY = (int)pState->mnY - nTopDeco;
+ else
+ nY = nScreenHeight - (aSWP.y+aSWP.cy);
+
+ if ( pState->mnMask & SAL_FRAMESTATE_MASK_WIDTH )
+ nWidth = (int)pState->mnWidth + nLeftDeco + nRightDeco;
+ else
+ nWidth = aSWP.cx;
+ if ( pState->mnMask & SAL_FRAMESTATE_MASK_HEIGHT )
+ nHeight = (int)pState->mnHeight + nTopDeco + nBottomDeco;
+ else
+ nHeight = aSWP.cy;
+
+#if OSL_DEBUG_LEVEL>0
+ debug_printf("Os2SalFrame::SetWindowState (%dx%d) at %d,%d\n", nWidth,nHeight,nX,nY);
+#endif
+
+ // Adjust Window in the screen:
+ // if it does not fit into the screen do nothing, ie default pos/size will be used
+ // if there is an overlap with the screen border move the window while keeping its size
+
+ //if( nWidth > nScreenWidth || nHeight > nScreenHeight )
+ // nPosSize |= (SWP_NOMOVE | SWP_NOSIZE);
+
+ if ( nX+nWidth > nScreenWidth )
+ nX = (nScreenWidth) - nWidth;
+ if ( nY+nHeight > nScreenHeight )
+ nY = (nScreenHeight) - nHeight;
+ if ( nX < 0 )
+ nX = 0;
+ if ( nY < 0 )
+ nY = 0;
+
+ // Restore-Position setzen
+ SWP aPlacement;
+ WinQueryWindowPos( mhWndFrame, &aPlacement );
+
+ // Status setzen
+ bVisible = WinIsWindowVisible( mhWndFrame);
+ BOOL bUpdateHiddenFramePos = FALSE;
+ if ( !bVisible )
+ {
+ aPlacement.fl = SWP_HIDE;
+
+ if ( mbOverwriteState )
+ {
+ if ( pState->mnMask & SAL_FRAMESTATE_MASK_STATE )
+ {
+ if ( pState->mnState & SAL_FRAMESTATE_MINIMIZED )
+ mnShowState = SWP_SHOWMINIMIZED;
+ else if ( pState->mnState & SAL_FRAMESTATE_MAXIMIZED )
+ {
+ mnShowState = SWP_SHOWMAXIMIZED;
+ bUpdateHiddenFramePos = TRUE;
+ }
+ else if ( pState->mnState & SAL_FRAMESTATE_NORMAL )
+ mnShowState = SWP_SHOWNORMAL;
+ }
+ }
+ }
+ else
+ {
+ if ( pState->mnMask & SAL_FRAMESTATE_MASK_STATE )
+ {
+ if ( pState->mnState & SAL_FRAMESTATE_MINIMIZED )
+ {
+ //if ( pState->mnState & SAL_FRAMESTATE_MAXIMIZED )
+ // aPlacement.flags |= WPF_RESTORETOMAXIMIZED;
+ aPlacement.fl = SWP_SHOWMINIMIZED;
+ }
+ else if ( pState->mnState & SAL_FRAMESTATE_MAXIMIZED )
+ aPlacement.fl = SWP_SHOWMAXIMIZED;
+ else if ( pState->mnState & SAL_FRAMESTATE_NORMAL )
+ aPlacement.fl = SWP_RESTORE;
+ }
+ }
+
+ // Wenn Fenster nicht minimiert/maximiert ist oder nicht optisch
+ // umgesetzt werden muss, dann SetWindowPos() benutzen, da
+ // SetWindowPlacement() die TaskBar mit einrechnet
+ if ( !(aPlacement.fl & SWP_MINIMIZE)
+ && !( aPlacement.fl & SWP_MAXIMIZE )
+ && (!bVisible || (aPlacement.fl == SWP_RESTORE)) )
+ {
+ if( bUpdateHiddenFramePos )
+ {
+ // #96084 set a useful internal window size because
+ // the window will not be maximized (and the size updated) before show()
+ SetMaximizedFrameGeometry( mhWndFrame, this );
+ }
+ else
+ WinSetWindowPos( mhWndFrame, 0, nX,
+ nScreenHeight - (nY+nHeight), nWidth, nHeight, nPosSize);
+ }
+ else
+ {
+ if( (nPosSize & (SWP_MOVE|SWP_SIZE)) )
+ {
+ aPlacement.x = nX;
+ aPlacement.y = nScreenHeight-(nY+nHeight);
+ aPlacement.cx = nWidth;
+ aPlacement.cy = nHeight;
+ }
+ WinSetWindowPos( mhWndFrame, 0, aPlacement.x, aPlacement.y,
+ aPlacement.cx, aPlacement.cy, aPlacement.fl );
+ }
+
+#if OSL_DEBUG_LEVEL>0
+ debug_printf("Os2SalFrame::SetWindowState DONE\n");
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Os2SalFrame::GetWindowState( SalFrameState* pState )
+{
+ if ( maState.mnWidth && maState.mnHeight )
+ {
+ *pState = maState;
+ // #94144# allow Minimize again, should be masked out when read from configuration
+ // 91625 - Don't save minimize
+ //if ( !(pState->mnState & SAL_FRAMESTATE_MAXIMIZED) )
+ if ( !(pState->mnState & (SAL_FRAMESTATE_MINIMIZED | SAL_FRAMESTATE_MAXIMIZED)) )
+ pState->mnState |= SAL_FRAMESTATE_NORMAL;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalFrame::SetScreenNumber( unsigned int nNewScreen )
+{
+#if 0
+ WinSalSystem* pSys = static_cast<WinSalSystem*>(ImplGetSalSystem());
+ if( pSys )
+ {
+ const std::vector<WinSalSystem::DisplayMonitor>& rMonitors =
+ pSys->getMonitors();
+ size_t nMon = rMonitors.size();
+ if( nNewScreen < nMon )
+ {
+ Point aOldMonPos, aNewMonPos( rMonitors[nNewScreen].m_aArea.TopLeft() );
+ Point aCurPos( maGeometry.nX, maGeometry.nY );
+ for( size_t i = 0; i < nMon; i++ )
+ {
+ if( rMonitors[i].m_aArea.IsInside( aCurPos ) )
+ {
+ aOldMonPos = rMonitors[i].m_aArea.TopLeft();
+ break;
+ }
+ }
+ mnDisplay = nNewScreen;
+ maGeometry.nScreenNumber = nNewScreen;
+ SetPosSize( aNewMonPos.X() + (maGeometry.nX - aOldMonPos.X()),
+ aNewMonPos.Y() + (maGeometry.nY - aOldMonPos.Y()),
+ 0, 0,
+ SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y );
+ }
+ }
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+// native menu implementation - currently empty
+void Os2SalFrame::DrawMenuBar()
+{
+}
+
+void Os2SalFrame::SetMenu( SalMenu* pSalMenu )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalFrame::ShowFullScreen( BOOL bFullScreen, sal_Int32 nDisplay )
+{
+ if ( mbFullScreen == bFullScreen )
+ return;
+
+ mbFullScreen = bFullScreen;
+ if ( bFullScreen )
+ {
+ // save old position
+ memset( &maFullScreenRect, 0, sizeof( SWP ) );
+ _WinQueryWindowPos( this, &maFullScreenRect );
+
+ // set window to screen size
+ ImplSalFrameFullScreenPos( this, TRUE );
+ }
+ else
+ {
+ _WinSetWindowPos( this,
+ 0,
+ maFullScreenRect.x, maFullScreenRect.y,
+ maFullScreenRect.cx, maFullScreenRect.cy,
+ SWP_MOVE | SWP_SIZE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalFrame::StartPresentation( BOOL bStart )
+{
+ // SysSetObjectData("<WP_DESKTOP>","Autolockup=no"); oder OS2.INI: PM_Lockup
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalFrame::SetAlwaysOnTop( BOOL bOnTop )
+{
+ mbAllwayOnTop = bOnTop;
+#if 0
+ HWND hWnd;
+ if ( bOnTop )
+ hWnd = HWND_TOPMOST;
+ else
+ hWnd = HWND_NOTOPMOST;
+ SetWindowPos( mhWnd, hWnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
+#endif
+}
+
+
+// -----------------------------------------------------------------------
+
+static void ImplSalToTop( HWND hWnd, ULONG nFlags )
+{
+ Os2SalFrame* pFrame = GetWindowPtr( hWnd );
+#if OSL_DEBUG_LEVEL>0
+ debug_printf("ImplSalToTop hWnd %08x, nFlags %x\n", hWnd, nFlags);
+#endif
+
+ // if window is minimized, first restore it
+ SWP aSWP;
+ WinQueryWindowPos( hWnd, &aSWP );
+ if ( aSWP.fl & SWP_MINIMIZE )
+ WinSetWindowPos( hWnd, NULL, 0, 0, 0, 0, SWP_RESTORE );
+
+ if ( nFlags & SAL_FRAME_TOTOP_FOREGROUNDTASK )
+ WinSetWindowPos( pFrame->mhWndFrame, HWND_TOP, 0, 0, 0, 0, SWP_ACTIVATE | SWP_ZORDER);
+
+ if ( nFlags & SAL_FRAME_TOTOP_RESTOREWHENMIN )
+ {
+ ULONG nStyle;
+ if ( pFrame->mbRestoreMaximize )
+ nStyle = SWP_MAXIMIZE;
+ else
+ nStyle = SWP_RESTORE;
+
+ WinSetWindowPos( pFrame->mhWndFrame, NULL, 0, 0, 0, 0, nStyle );
+ }
+ WinSetFocus( HWND_DESKTOP, pFrame->mhWndClient );
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalFrame::ToTop( USHORT nFlags )
+{
+ nFlags &= ~SAL_FRAME_TOTOP_GRABFOCUS; // this flag is not needed on win32
+ // Post this Message to the window, because this only works
+ // in the thread of the window, which has create this window.
+ // We post this message to avoid deadlocks
+ if ( GetSalData()->mnAppThreadId != GetCurrentThreadId() )
+ WinPostMsg( mhWndFrame, SAL_MSG_TOTOP, (MPARAM)nFlags, 0 );
+ else
+ ImplSalToTop( mhWndFrame, nFlags );
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalFrame::SetPointer( PointerStyle ePointerStyle )
+{
+ struct ImplPtrData
+ {
+ HPOINTER mhPointer;
+ ULONG mnSysId;
+ ULONG mnOwnId;
+ };
+
+ static ImplPtrData aImplPtrTab[POINTER_COUNT] =
+ {
+ { 0, SPTR_ARROW, 0 }, // POINTER_ARROW
+ { 0, 0, SAL_RESID_POINTER_NULL }, // POINTER_NULL
+ { 0, SPTR_WAIT, 0 }, // POINTER_WAIT
+ { 0, SPTR_TEXT, 0 }, // POINTER_BEAM
+ { 0, 0, SAL_RESID_POINTER_HELP }, // POINTER_HELP
+ { 0, 0, SAL_RESID_POINTER_CROSS }, // POINTER_CROSS
+ { 0, 0, SAL_RESID_POINTER_MOVE }, // POINTER_MOVE
+ { 0, SPTR_SIZENS, 0 }, // POINTER_NSIZE
+ { 0, SPTR_SIZENS, 0 }, // POINTER_SSIZE
+ { 0, SPTR_SIZEWE, 0 }, // POINTER_WSIZE
+ { 0, SPTR_SIZEWE, 0 }, // POINTER_ESIZE
+ { 0, SPTR_SIZENWSE, 0 }, // POINTER_NWSIZE
+ { 0, SPTR_SIZENESW, 0 }, // POINTER_NESIZE
+ { 0, SPTR_SIZENESW, 0 }, // POINTER_SWSIZE
+ { 0, SPTR_SIZENWSE, 0 }, // POINTER_SESIZE
+ { 0, SPTR_SIZENS, 0 }, // POINTER_WINDOW_NSIZE
+ { 0, SPTR_SIZENS, 0 }, // POINTER_WINDOW_SSIZE
+ { 0, SPTR_SIZEWE, 0 }, // POINTER_WINDOW_WSIZE
+ { 0, SPTR_SIZEWE, 0 }, // POINTER_WINDOW_ESIZE
+ { 0, SPTR_SIZENWSE, 0 }, // POINTER_WINDOW_NWSIZE
+ { 0, SPTR_SIZENESW, 0 }, // POINTER_WINDOW_NESIZE
+ { 0, SPTR_SIZENESW, 0 }, // POINTER_WINDOW_SWSIZE
+ { 0, SPTR_SIZENWSE, 0 }, // POINTER_WINDOW_SESIZE
+ { 0, 0, SAL_RESID_POINTER_HSPLIT }, // POINTER_HSPLIT
+ { 0, 0, SAL_RESID_POINTER_VSPLIT }, // POINTER_VSPLIT
+ { 0, 0, SAL_RESID_POINTER_HSIZEBAR }, // POINTER_HSIZEBAR
+ { 0, 0, SAL_RESID_POINTER_VSIZEBAR }, // POINTER_VSIZEBAR
+ { 0, 0, SAL_RESID_POINTER_HAND }, // POINTER_HAND
+ { 0, 0, SAL_RESID_POINTER_REFHAND }, // POINTER_REFHAND
+ { 0, 0, SAL_RESID_POINTER_PEN }, // POINTER_PEN
+ { 0, 0, SAL_RESID_POINTER_MAGNIFY }, // POINTER_MAGNIFY
+ { 0, 0, SAL_RESID_POINTER_FILL }, // POINTER_FILL
+ { 0, 0, SAL_RESID_POINTER_ROTATE }, // POINTER_ROTATE
+ { 0, 0, SAL_RESID_POINTER_HSHEAR }, // POINTER_HSHEAR
+ { 0, 0, SAL_RESID_POINTER_VSHEAR }, // POINTER_VSHEAR
+ { 0, 0, SAL_RESID_POINTER_MIRROR }, // POINTER_MIRROR
+ { 0, 0, SAL_RESID_POINTER_CROOK }, // POINTER_CROOK
+ { 0, 0, SAL_RESID_POINTER_CROP }, // POINTER_CROP
+ { 0, 0, SAL_RESID_POINTER_MOVEPOINT }, // POINTER_MOVEPOINT
+ { 0, 0, SAL_RESID_POINTER_MOVEBEZIERWEIGHT }, // POINTER_MOVEBEZIERWEIGHT
+ { 0, 0, SAL_RESID_POINTER_MOVEDATA }, // POINTER_MOVEDATA
+ { 0, 0, SAL_RESID_POINTER_COPYDATA }, // POINTER_COPYDATA
+ { 0, 0, SAL_RESID_POINTER_LINKDATA }, // POINTER_LINKDATA
+ { 0, 0, SAL_RESID_POINTER_MOVEDATALINK }, // POINTER_MOVEDATALINK
+ { 0, 0, SAL_RESID_POINTER_COPYDATALINK }, // POINTER_COPYDATALINK
+ { 0, 0, SAL_RESID_POINTER_MOVEFILE }, // POINTER_MOVEFILE
+ { 0, 0, SAL_RESID_POINTER_COPYFILE }, // POINTER_COPYFILE
+ { 0, 0, SAL_RESID_POINTER_LINKFILE }, // POINTER_LINKFILE
+ { 0, 0, SAL_RESID_POINTER_MOVEFILELINK }, // POINTER_MOVEFILELINK
+ { 0, 0, SAL_RESID_POINTER_COPYFILELINK }, // POINTER_COPYFILELINK
+ { 0, 0, SAL_RESID_POINTER_MOVEFILES }, // POINTER_MOVEFILES
+ { 0, 0, SAL_RESID_POINTER_COPYFILES }, // POINTER_COPYFILES
+ { 0, SPTR_ILLEGAL, 0 }, // POINTER_NOTALLOWED
+ { 0, 0, SAL_RESID_POINTER_DRAW_LINE }, // POINTER_DRAW_LINE
+ { 0, 0, SAL_RESID_POINTER_DRAW_RECT }, // POINTER_DRAW_RECT
+ { 0, 0, SAL_RESID_POINTER_DRAW_POLYGON }, // POINTER_DRAW_POLYGON
+ { 0, 0, SAL_RESID_POINTER_DRAW_BEZIER }, // POINTER_DRAW_BEZIER
+ { 0, 0, SAL_RESID_POINTER_DRAW_ARC }, // POINTER_DRAW_ARC
+ { 0, 0, SAL_RESID_POINTER_DRAW_PIE }, // POINTER_DRAW_PIE
+ { 0, 0, SAL_RESID_POINTER_DRAW_CIRCLECUT }, // POINTER_DRAW_CIRCLECUT
+ { 0, 0, SAL_RESID_POINTER_DRAW_ELLIPSE }, // POINTER_DRAW_ELLIPSE
+ { 0, 0, SAL_RESID_POINTER_DRAW_FREEHAND }, // POINTER_DRAW_FREEHAND
+ { 0, 0, SAL_RESID_POINTER_DRAW_CONNECT }, // POINTER_DRAW_CONNECT
+ { 0, 0, SAL_RESID_POINTER_DRAW_TEXT }, // POINTER_DRAW_TEXT
+ { 0, 0, SAL_RESID_POINTER_DRAW_CAPTION }, // POINTER_DRAW_CAPTION
+ { 0, 0, SAL_RESID_POINTER_CHART }, // POINTER_CHART
+ { 0, 0, SAL_RESID_POINTER_DETECTIVE }, // POINTER_DETECTIVE
+ { 0, 0, SAL_RESID_POINTER_PIVOT_COL }, // POINTER_PIVOT_COL
+ { 0, 0, SAL_RESID_POINTER_PIVOT_ROW }, // POINTER_PIVOT_ROW
+ { 0, 0, SAL_RESID_POINTER_PIVOT_FIELD }, // POINTER_PIVOT_FIELD
+ { 0, 0, SAL_RESID_POINTER_CHAIN }, // POINTER_CHAIN
+ { 0, 0, SAL_RESID_POINTER_CHAIN_NOTALLOWED }, // POINTER_CHAIN_NOTALLOWED
+ { 0, 0, SAL_RESID_POINTER_TIMEEVENT_MOVE }, // POINTER_TIMEEVENT_MOVE
+ { 0, 0, SAL_RESID_POINTER_TIMEEVENT_SIZE }, // POINTER_TIMEEVENT_SIZE
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_N }, // POINTER_AUTOSCROLL_N
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_S }, // POINTER_AUTOSCROLL_S
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_W }, // POINTER_AUTOSCROLL_W
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_E }, // POINTER_AUTOSCROLL_E
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_NW }, // POINTER_AUTOSCROLL_NW
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_NE }, // POINTER_AUTOSCROLL_NE
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_SW }, // POINTER_AUTOSCROLL_SW
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_SE }, // POINTER_AUTOSCROLL_SE
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_NS }, // POINTER_AUTOSCROLL_NS
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_WE }, // POINTER_AUTOSCROLL_WE
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_NSWE }, // POINTER_AUTOSCROLL_NSWE
+ { 0, 0, SAL_RESID_POINTER_AIRBRUSH }, // POINTER_AIRBRUSH
+ { 0, 0, SAL_RESID_POINTER_TEXT_VERTICAL }, // POINTER_TEXT_VERTICAL
+ { 0, 0, SAL_RESID_POINTER_PIVOT_DELETE }, // POINTER_PIVOT_DELETE
+
+ // --> FME 2004-07-30 #i32329# Enhanced table selection
+ { 0, 0, SAL_RESID_POINTER_TAB_SELECT_S }, // POINTER_TAB_SELECT_S
+ { 0, 0, SAL_RESID_POINTER_TAB_SELECT_E }, // POINTER_TAB_SELECT_E
+ { 0, 0, SAL_RESID_POINTER_TAB_SELECT_SE }, // POINTER_TAB_SELECT_SE
+ { 0, 0, SAL_RESID_POINTER_TAB_SELECT_W }, // POINTER_TAB_SELECT_W
+ { 0, 0, SAL_RESID_POINTER_TAB_SELECT_SW }, // POINTER_TAB_SELECT_SW
+ // <--
+
+ // --> FME 2004-08-16 #i20119# Paintbrush tool
+ { 0, 0, SAL_RESID_POINTER_PAINTBRUSH } // POINTER_PAINTBRUSH
+ // <--
+ };
+
+#if POINTER_COUNT != 94
+#error New Pointer must be defined!
+#endif
+
+ //debug_printf("Os2SalFrame::SetPointer\n");
+
+ // Mousepointer loaded ?
+ if ( !aImplPtrTab[ePointerStyle].mhPointer )
+ {
+ if ( aImplPtrTab[ePointerStyle].mnOwnId )
+ aImplPtrTab[ePointerStyle].mhPointer = ImplLoadSalCursor( (ULONG)aImplPtrTab[ePointerStyle].mnOwnId );
+ else
+ aImplPtrTab[ePointerStyle].mhPointer = WinQuerySysPointer( HWND_DESKTOP, aImplPtrTab[ePointerStyle].mnSysId, FALSE );
+ }
+ if (aImplPtrTab[ePointerStyle].mhPointer == 0) {
+ debug_printf( "SetPointer ePointerStyle %d unknown\n", ePointerStyle);
+ aImplPtrTab[ePointerStyle].mhPointer = SPTR_ICONERROR;
+ }
+
+ // Unterscheidet sich der Mauspointer, dann den neuen setzen
+ if ( mhPointer != aImplPtrTab[ePointerStyle].mhPointer )
+ {
+ mhPointer = aImplPtrTab[ePointerStyle].mhPointer;
+ WinSetPointer( HWND_DESKTOP, mhPointer );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalFrame::CaptureMouse( BOOL bCapture )
+{
+#if OSL_DEBUG_LEVEL>10
+ _bCapture=bCapture;
+ debug_printf("Os2SalFrame::CaptureMouse bCapture %d\n", bCapture);
+#endif
+ if ( bCapture )
+ WinSetCapture( HWND_DESKTOP, mhWndClient );
+ else
+ WinSetCapture( HWND_DESKTOP, 0 );
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalFrame::SetPointerPos( long nX, long nY )
+{
+ POINTL aPt;
+ aPt.x = nX;
+ aPt.y = mnHeight - nY - 1; // convert sal coords to sys
+ WinMapWindowPoints( mhWndClient, HWND_DESKTOP, &aPt, 1 );
+ WinSetPointerPos( HWND_DESKTOP, aPt.x, aPt.y );
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalFrame::Flush()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalFrame::Sync()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalFrame::SetInputContext( SalInputContext* pContext )
+{
+#ifdef ENABLE_IME
+ SalIMEData* pIMEData = GetSalIMEData();
+ if ( pIMEData )
+ {
+ HWND hWnd = mhWndClient;
+ HIMI hIMI = 0;
+ pIMEData->mpGetIME( hWnd, &hIMI );
+ if ( hIMI )
+ {
+ ULONG nInputMode;
+ ULONG nConversionMode;
+ if ( 0 == pIMEData->mpQueryIMEMode( hIMI, &nInputMode, &nConversionMode ) )
+ {
+ if ( pContext->mnOptions & SAL_INPUTCONTEXT_TEXT )
+ {
+ nInputMode &= ~IMI_IM_IME_DISABLE;
+ if ( pContext->mnOptions & SAL_INPUTCONTEXT_EXTTEXTINPUT_OFF )
+ nInputMode &= ~IMI_IM_IME_ON;
+// !!! Da derzeit ueber das OS2-IME-UI der IME-Mode nicht einschaltbar ist !!!
+// if ( SAL_INPUTCONTEXT_EXTTEXTINPUT_ON )
+ nInputMode |= IMI_IM_IME_ON;
+ }
+ else
+ nInputMode |= IMI_IM_IME_DISABLE;
+ pIMEData->mpSetIMEMode( hIMI, nInputMode, nConversionMode );
+ }
+
+ pIMEData->mpReleaseIME( hWnd, hIMI );
+ }
+ }
+#endif
+}
+
+// -----------------------------------------------------------------------
+#if 0
+void Os2SalFrame::UpdateExtTextInputArea()
+{
+#ifdef ENABLE_IME
+#endif
+}
+#endif
+
+// -----------------------------------------------------------------------
+
+void Os2SalFrame::EndExtTextInput( USHORT nFlags )
+{
+#ifdef ENABLE_IME
+ SalIMEData* pIMEData = GetSalIMEData();
+ if ( pIMEData )
+ {
+ HWND hWnd = mhWndClient;
+ HIMI hIMI = 0;
+ pIMEData->mpGetIME( hWnd, &hIMI );
+ if ( hIMI )
+ {
+ ULONG nIndex;
+ if ( nFlags & SAL_FRAME_ENDEXTTEXTINPUT_COMPLETE )
+ nIndex = CNV_COMPLETE;
+ else
+ nIndex = CNV_CANCEL;
+
+ pIMEData->mpRequestIME( hIMI, REQ_CONVERSIONSTRING, nIndex, 0 );
+ pIMEData->mpReleaseIME( hWnd, hIMI );
+ }
+ }
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+XubString Os2SalFrame::GetKeyName( USHORT nCode )
+{
+ if ( eImplKeyboardLanguage == LANGUAGE_DONTKNOW )
+ eImplKeyboardLanguage = MsLangId::getSystemLanguage();
+
+ XubString aKeyCode;
+ XubString aCode;
+ const sal_Unicode** pLangTab = ImplGetLangTab( eImplKeyboardLanguage );
+
+ if ( nCode & KEY_SHIFT )
+ aKeyCode = pLangTab[LSTR_KEY_SHIFT];
+
+ if ( nCode & KEY_MOD1 )
+ {
+ if ( aKeyCode.Len() == 0 )
+ aKeyCode = pLangTab[LSTR_KEY_CTRL];
+ else
+ {
+ aKeyCode += '+';
+ aKeyCode += pLangTab[LSTR_KEY_CTRL];
+ }
+ }
+
+ if ( nCode & KEY_MOD2 )
+ {
+ if ( aKeyCode.Len() == 0 )
+ aKeyCode = pLangTab[LSTR_KEY_ALT];
+ else
+ {
+ aKeyCode += '+';
+ aKeyCode += pLangTab[LSTR_KEY_ALT];
+ }
+ }
+
+ USHORT nKeyCode = nCode & 0x0FFF;
+ if ( (nKeyCode >= KEY_0) && (nKeyCode <= KEY_9) )
+ aCode = sal::static_int_cast<sal_Char>('0' + (nKeyCode - KEY_0));
+ else if ( (nKeyCode >= KEY_A) && (nKeyCode <= KEY_Z) )
+ aCode = sal::static_int_cast<sal_Char>('A' + (nKeyCode - KEY_A));
+ else if ( (nKeyCode >= KEY_F1) && (nKeyCode <= KEY_F26) )
+ {
+ aCode += 'F';
+ if ( (nKeyCode >= KEY_F1) && (nKeyCode <= KEY_F9) )
+ {
+ aCode += sal::static_int_cast<sal_Char>('1' + (nKeyCode - KEY_F1));
+ }
+ else if ( (nKeyCode >= KEY_F10) && (nKeyCode <= KEY_F19) )
+ {
+ aCode += '1';
+ aCode += sal::static_int_cast<sal_Char>('0' + (nKeyCode - KEY_F10));
+ }
+ else
+ {
+ aCode += '2';
+ aCode += sal::static_int_cast<sal_Char>('0' + (nKeyCode - KEY_F20));
+ }
+ }
+ else
+ {
+ switch ( nKeyCode )
+ {
+ case KEY_DOWN:
+ aCode = pLangTab[LSTR_KEY_DOWN];
+ break;
+ case KEY_UP:
+ aCode = pLangTab[LSTR_KEY_UP];
+ break;
+ case KEY_LEFT:
+ aCode = pLangTab[LSTR_KEY_LEFT];
+ break;
+ case KEY_RIGHT:
+ aCode = pLangTab[LSTR_KEY_RIGHT];
+ break;
+ case KEY_HOME:
+ aCode = pLangTab[LSTR_KEY_HOME];
+ break;
+ case KEY_END:
+ aCode = pLangTab[LSTR_KEY_END];
+ break;
+ case KEY_PAGEUP:
+ aCode = pLangTab[LSTR_KEY_PAGEUP];
+ break;
+ case KEY_PAGEDOWN:
+ aCode = pLangTab[LSTR_KEY_PAGEDOWN];
+ break;
+ case KEY_RETURN:
+ aCode = pLangTab[LSTR_KEY_RETURN];
+ break;
+ case KEY_ESCAPE:
+ aCode = pLangTab[LSTR_KEY_ESC];
+ break;
+ case KEY_TAB:
+ aCode = pLangTab[LSTR_KEY_TAB];
+ break;
+ case KEY_BACKSPACE:
+ aCode = pLangTab[LSTR_KEY_BACKSPACE];
+ break;
+ case KEY_SPACE:
+ aCode = pLangTab[LSTR_KEY_SPACE];
+ break;
+ case KEY_INSERT:
+ aCode = pLangTab[LSTR_KEY_INSERT];
+ break;
+ case KEY_DELETE:
+ aCode = pLangTab[LSTR_KEY_DELETE];
+ break;
+
+ case KEY_ADD:
+ aCode += '+';
+ break;
+ case KEY_SUBTRACT:
+ aCode += '-';
+ break;
+ case KEY_MULTIPLY:
+ aCode += '*';
+ break;
+ case KEY_DIVIDE:
+ aCode += '/';
+ break;
+ case KEY_POINT:
+ aCode += '.';
+ break;
+ case KEY_COMMA:
+ aCode += ',';
+ break;
+ case KEY_LESS:
+ aCode += '<';
+ break;
+ case KEY_GREATER:
+ aCode += '>';
+ break;
+ case KEY_EQUAL:
+ aCode += '=';
+ break;
+ }
+ }
+
+ if ( aCode.Len() )
+ {
+ if ( aKeyCode.Len() == 0 )
+ aKeyCode = aCode;
+ else
+ {
+ aKeyCode += '+';
+ aKeyCode += aCode;
+ }
+ }
+
+ return aKeyCode;
+}
+
+// -----------------------------------------------------------------------
+
+XubString Os2SalFrame::GetSymbolKeyName( const XubString&, USHORT nKeyCode )
+{
+ return GetKeyName( nKeyCode );
+}
+
+// -----------------------------------------------------------------------
+
+inline long ImplOS2ColorToSal( long nOS2Color )
+{
+ return MAKE_SALCOLOR( (BYTE)( nOS2Color>>16), (BYTE)(nOS2Color>>8), (BYTE)nOS2Color );
+}
+
+// -----------------------------------------------------------------------
+
+static USHORT ImplMouseSysValueToSAL( int iSysValue, USHORT& rCode, USHORT& rClicks, BOOL& rDown )
+{
+ LONG lValue = WinQuerySysValue( HWND_DESKTOP, iSysValue );
+
+ rCode = 0;
+ rClicks = 1;
+ rDown = TRUE;
+
+ switch ( lValue & 0xFFFF )
+ {
+ case WM_BUTTON1UP:
+ case WM_BUTTON1CLICK:
+ rCode = MOUSE_LEFT;
+ rDown = FALSE;
+ break;
+ case WM_BUTTON1DOWN:
+ case WM_BUTTON1MOTIONSTART:
+ rCode = MOUSE_LEFT;
+ break;
+ case WM_BUTTON1DBLCLK:
+ rCode = MOUSE_LEFT;
+ rClicks = 2;
+ break;
+
+ case WM_BUTTON2UP:
+ case WM_BUTTON2CLICK:
+ rCode = MOUSE_RIGHT;
+ rDown = FALSE;
+ break;
+ case WM_BUTTON2DOWN:
+ case WM_BUTTON2MOTIONSTART:
+ rCode = MOUSE_RIGHT;
+ break;
+ case WM_BUTTON2DBLCLK:
+ rCode = MOUSE_RIGHT;
+ rClicks = 2;
+ break;
+
+ case WM_BUTTON3UP:
+ case WM_BUTTON3CLICK:
+ rCode = MOUSE_MIDDLE;
+ rDown = FALSE;
+ break;
+ case WM_BUTTON3DOWN:
+ case WM_BUTTON3MOTIONSTART:
+ rCode = MOUSE_MIDDLE;
+ break;
+ case WM_BUTTON3DBLCLK:
+ rCode = MOUSE_MIDDLE;
+ rClicks = 2;
+ break;
+ }
+
+ if ( !rCode )
+ return FALSE;
+
+ lValue = (lValue & 0xFFFF0000) >> 16;
+ if ( lValue != 0xFFFF )
+ {
+ if ( lValue & KC_SHIFT )
+ rCode |= KEY_SHIFT;
+ if ( lValue & KC_CTRL )
+ rCode |= KEY_MOD1;
+ if ( lValue & KC_ALT )
+ rCode |= KEY_MOD2;
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplSalIsSameColor( const Color& rColor1, const Color& rColor2 )
+{
+ ULONG nWrong = 0;
+ nWrong += Abs( (short)rColor1.GetRed()-(short)rColor2.GetRed() );
+ nWrong += Abs( (short)rColor1.GetGreen()-(short)rColor2.GetGreen() );
+ nWrong += Abs( (short)rColor1.GetBlue()-(short)rColor2.GetBlue() );
+ return (nWrong < 30);
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplOS2NameFontToVCLFont( const char* pFontName, Font& rFont )
+{
+ char aNumBuf[10];
+ int nNumBufLen = 0;
+
+ while ( *pFontName && (*pFontName != '.') &&
+ (nNumBufLen < sizeof(aNumBuf)-1) )
+ {
+ aNumBuf[nNumBufLen] = *pFontName;
+ nNumBufLen++;
+ pFontName++;
+ }
+ aNumBuf[nNumBufLen] = '\0';
+
+ pFontName++;
+ while ( *pFontName == ' ' )
+ pFontName++;
+
+ int nFontHeight = atoi( aNumBuf );
+ int nFontNameLen = strlen( pFontName );
+ if ( nFontHeight && nFontNameLen )
+ {
+ rFont.SetFamily( FAMILY_DONTKNOW );
+ rFont.SetWeight( WEIGHT_NORMAL );
+ rFont.SetItalic( ITALIC_NONE );
+ // search for a style embedded in the name, e.g. 'WarpSans Bold'
+ // because we need to split the style from the family name
+ if (strstr( pFontName, " Bold")
+ || strstr( pFontName, " Italic")
+ || strstr( pFontName, "-Normal"))
+ {
+ char* fontName = strdup( pFontName);
+ char* style = strstr( fontName, " Bold");
+ if (style)
+ rFont.SetWeight( WEIGHT_BOLD );
+
+ if (!style)
+ style = strstr( fontName, " Italic");
+ if (style)
+ rFont.SetItalic( ITALIC_NORMAL );
+
+ if (!style)
+ style = strstr( fontName, "-Normal");
+ // store style, skip whitespace char
+ rFont.SetStyleName( ::rtl::OStringToOUString ( style+1, gsl_getSystemTextEncoding()) );
+ // truncate name
+ *style = 0;
+ // store family name
+ rFont.SetName( ::rtl::OStringToOUString ( fontName, gsl_getSystemTextEncoding()) );
+ free( fontName);
+ }
+ else
+ {
+ rFont.SetName( ::rtl::OStringToOUString (pFontName, gsl_getSystemTextEncoding()) );
+ rFont.SetStyleName( ::rtl::OStringToOUString ("", gsl_getSystemTextEncoding()) );
+ }
+
+ rFont.SetSize( Size( 0, nFontHeight ) );
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalFrame::UpdateSettings( AllSettings& rSettings )
+{
+ static char aControlPanel[] = "PM_ControlPanel";
+ static char aSystemFonts[] = "PM_SystemFonts";
+ char aDummyStr[] = "";
+
+ // --- Mouse setting ---
+ USHORT nCode;
+ USHORT nClicks;
+ BOOL bDown;
+ MouseSettings aMouseSettings = rSettings.GetMouseSettings();
+ aMouseSettings.SetDoubleClickTime( WinQuerySysValue( HWND_DESKTOP, SV_DBLCLKTIME ) );
+ if ( ImplMouseSysValueToSAL( SV_BEGINDRAG, nCode, nClicks, bDown ) )
+ aMouseSettings.SetStartDragCode( nCode );
+ if ( ImplMouseSysValueToSAL( SV_CONTEXTMENU, nCode, nClicks, bDown ) )
+ {
+ aMouseSettings.SetContextMenuCode( nCode );
+ aMouseSettings.SetContextMenuClicks( nClicks );
+ aMouseSettings.SetContextMenuDown( bDown );
+ }
+ aMouseSettings.SetButtonStartRepeat( WinQuerySysValue( HWND_DESKTOP, SV_FIRSTSCROLLRATE ) );
+ aMouseSettings.SetButtonRepeat( WinQuerySysValue( HWND_DESKTOP, SV_SCROLLRATE ) );
+ rSettings.SetMouseSettings( aMouseSettings );
+
+ // --- Style settings ---
+ StyleSettings aStyleSettings = rSettings.GetStyleSettings();
+ BOOL bCompBorder = (aStyleSettings.GetOptions() & (STYLE_OPTION_MACSTYLE | STYLE_OPTION_UNIXSTYLE)) == 0;
+
+ // General settings
+ LONG nDisplayTime = PrfQueryProfileInt( HINI_PROFILE, (PSZ)aControlPanel, (PSZ)"LogoDisplayTime", -1 );
+ ULONG nSalDisplayTime;
+ if ( nDisplayTime < 0 )
+ nSalDisplayTime = LOGO_DISPLAYTIME_STARTTIME;
+ else if ( !nDisplayTime )
+ nSalDisplayTime = LOGO_DISPLAYTIME_NOLOGO;
+ else
+ nSalDisplayTime = (ULONG)nDisplayTime;
+ aStyleSettings.SetLogoDisplayTime( nSalDisplayTime );
+
+ aStyleSettings.SetCursorBlinkTime( WinQuerySysValue( HWND_DESKTOP, SV_CURSORRATE ) );
+ ULONG nDragFullOptions = aStyleSettings.GetDragFullOptions();
+ if ( WinQuerySysValue( HWND_DESKTOP, SV_DYNAMICDRAG ) )
+ nDragFullOptions |= DRAGFULL_OPTION_WINDOWMOVE | DRAGFULL_OPTION_WINDOWSIZE | DRAGFULL_OPTION_DOCKING | DRAGFULL_OPTION_SPLIT;
+ else
+ nDragFullOptions &= ~(DRAGFULL_OPTION_WINDOWMOVE | DRAGFULL_OPTION_WINDOWSIZE | DRAGFULL_OPTION_DOCKING | DRAGFULL_OPTION_SPLIT);
+ aStyleSettings.SetDragFullOptions( nDragFullOptions );
+
+ // Size settings
+ aStyleSettings.SetScrollBarSize( WinQuerySysValue( HWND_DESKTOP, SV_CYHSCROLL ) );
+ if ( bCompBorder )
+ {
+ aStyleSettings.SetTitleHeight( WinQuerySysValue( HWND_DESKTOP, SV_CYTITLEBAR ) );
+ }
+
+ // Color settings
+ if ( bCompBorder )
+ {
+ aStyleSettings.SetFaceColor( ImplOS2ColorToSal( WinQuerySysColor( HWND_DESKTOP, SYSCLR_BUTTONMIDDLE, 0 ) ) );
+ aStyleSettings.SetInactiveTabColor( aStyleSettings.GetFaceColor() );
+ aStyleSettings.SetLightColor( ImplOS2ColorToSal( WinQuerySysColor( HWND_DESKTOP, SYSCLR_BUTTONLIGHT, 0 ) ) );
+ aStyleSettings.SetLightBorderColor( ImplOS2ColorToSal( WinQuerySysColor( HWND_DESKTOP, SYSCLR_BUTTONMIDDLE, 0 ) ) );
+ aStyleSettings.SetShadowColor( ImplOS2ColorToSal( WinQuerySysColor( HWND_DESKTOP, SYSCLR_BUTTONDARK, 0 ) ) );
+ aStyleSettings.SetDarkShadowColor( Color( COL_BLACK ) );
+ aStyleSettings.SetDialogColor( ImplOS2ColorToSal( WinQuerySysColor( HWND_DESKTOP, SYSCLR_DIALOGBACKGROUND, 0 ) ) );
+ aStyleSettings.SetButtonTextColor( ImplOS2ColorToSal( WinQuerySysColor( HWND_DESKTOP, SYSCLR_MENUTEXT, 0 ) ) );
+ aStyleSettings.SetActiveColor( ImplOS2ColorToSal( WinQuerySysColor( HWND_DESKTOP, SYSCLR_ACTIVETITLE, 0 ) ) );
+ aStyleSettings.SetActiveTextColor( ImplOS2ColorToSal( WinQuerySysColor( HWND_DESKTOP, SYSCLR_ACTIVETITLETEXT, 0 ) ) );
+ aStyleSettings.SetActiveBorderColor( ImplOS2ColorToSal( WinQuerySysColor( HWND_DESKTOP, SYSCLR_ACTIVEBORDER, 0 ) ) );
+ aStyleSettings.SetDeactiveColor( ImplOS2ColorToSal( WinQuerySysColor( HWND_DESKTOP, SYSCLR_INACTIVETITLE, 0 ) ) );
+ aStyleSettings.SetDeactiveTextColor( ImplOS2ColorToSal( WinQuerySysColor( HWND_DESKTOP, SYSCLR_INACTIVETITLETEXT, 0 ) ) );
+ aStyleSettings.SetDeactiveBorderColor( ImplOS2ColorToSal( WinQuerySysColor( HWND_DESKTOP, SYSCLR_INACTIVEBORDER, 0 ) ) );
+ aStyleSettings.SetMenuColor( ImplOS2ColorToSal( WinQuerySysColor( HWND_DESKTOP, SYSCLR_MENU, 0 ) ) );
+ aStyleSettings.SetMenuTextColor( ImplOS2ColorToSal( WinQuerySysColor( HWND_DESKTOP, SYSCLR_MENUTEXT, 0 ) ) );
+ aStyleSettings.SetMenuBarTextColor( ImplOS2ColorToSal( WinQuerySysColor( HWND_DESKTOP, SYSCLR_MENUTEXT, 0 ) ) );
+ }
+ aStyleSettings.SetDialogTextColor( aStyleSettings.GetButtonTextColor() );
+ aStyleSettings.SetRadioCheckTextColor( aStyleSettings.GetButtonTextColor() );
+ aStyleSettings.SetGroupTextColor( ImplOS2ColorToSal( WinQuerySysColor( HWND_DESKTOP, SYSCLR_WINDOWSTATICTEXT, 0 ) ) );
+ aStyleSettings.SetLabelTextColor( aStyleSettings.GetGroupTextColor() );
+ aStyleSettings.SetInfoTextColor( aStyleSettings.GetGroupTextColor() );
+ aStyleSettings.SetWindowColor( ImplOS2ColorToSal( WinQuerySysColor( HWND_DESKTOP, SYSCLR_WINDOW, 0 ) ) );
+ aStyleSettings.SetActiveTabColor( aStyleSettings.GetWindowColor() );
+ aStyleSettings.SetWindowTextColor( ImplOS2ColorToSal( WinQuerySysColor( HWND_DESKTOP, SYSCLR_WINDOWTEXT, 0 ) ) );
+ aStyleSettings.SetFieldColor( ImplOS2ColorToSal( WinQuerySysColor( HWND_DESKTOP, SYSCLR_ENTRYFIELD, 0 ) ) );
+ aStyleSettings.SetFieldTextColor( aStyleSettings.GetWindowTextColor() );
+ aStyleSettings.SetDisableColor( ImplOS2ColorToSal( WinQuerySysColor( HWND_DESKTOP, SYSCLR_MENUDISABLEDTEXT, 0 ) ) );
+ aStyleSettings.SetHighlightColor( ImplOS2ColorToSal( WinQuerySysColor( HWND_DESKTOP, SYSCLR_HILITEBACKGROUND, 0 ) ) );
+ aStyleSettings.SetHighlightTextColor( ImplOS2ColorToSal( WinQuerySysColor( HWND_DESKTOP, SYSCLR_HILITEFOREGROUND, 0 ) ) );
+ Color aMenuHighColor = ImplOS2ColorToSal( WinQuerySysColor( HWND_DESKTOP, SYSCLR_MENUHILITEBGND, 0 ) );
+ if ( ImplSalIsSameColor( aMenuHighColor, aStyleSettings.GetMenuColor() ) )
+ {
+ if ( bCompBorder )
+ {
+ aStyleSettings.SetMenuHighlightColor( Color( COL_BLUE ) );
+ aStyleSettings.SetMenuHighlightTextColor( Color( COL_WHITE ) );
+ }
+ }
+ else
+ {
+ aStyleSettings.SetMenuHighlightColor( aMenuHighColor );
+ aStyleSettings.SetMenuHighlightTextColor( ImplOS2ColorToSal( WinQuerySysColor( HWND_DESKTOP, SYSCLR_MENUHILITE, 0 ) ) );
+ }
+ // Checked-Color berechnen
+ Color aColor1 = aStyleSettings.GetFaceColor();
+ Color aColor2 = aStyleSettings.GetLightColor();
+ BYTE nRed = (BYTE)(((USHORT)aColor1.GetRed() + (USHORT)aColor2.GetRed())/2);
+ BYTE nGreen = (BYTE)(((USHORT)aColor1.GetGreen() + (USHORT)aColor2.GetGreen())/2);
+ BYTE nBlue = (BYTE)(((USHORT)aColor1.GetBlue() + (USHORT)aColor2.GetBlue())/2);
+ aStyleSettings.SetCheckedColor( Color( nRed, nGreen, nBlue ) );
+
+ // Fonts updaten
+ Font aFont;
+ char aFontNameBuf[255];
+ aFont = aStyleSettings.GetMenuFont();
+ if ( PrfQueryProfileString( HINI_PROFILE, (PSZ)aSystemFonts, (PSZ)"Menus", aDummyStr, aFontNameBuf, sizeof( aFontNameBuf ) ) > 5 )
+ {
+ if ( ImplOS2NameFontToVCLFont( aFontNameBuf, aFont ) ) {
+#if 0
+ // Add Workplace Sans if not already listed
+ if ( aFont.GetName().Search( (sal_Unicode*)L"WorkPlace Sans" ) == STRING_NOTFOUND )
+ {
+ XubString aFontName = aFont.GetName();
+ aFontName.Insert( (sal_Unicode*)L"WorkPlace Sans;", 0 );
+ aFont.SetName( aFontName );
+ aFont.SetSize( Size( 0, 9 ) );
+ }
+#endif
+ aStyleSettings.SetMenuFont( aFont );
+ }
+ }
+ aFont = aStyleSettings.GetIconFont();
+ if ( PrfQueryProfileString( HINI_PROFILE, (PSZ)aSystemFonts, (PSZ)"IconText", aDummyStr, aFontNameBuf, sizeof( aFontNameBuf ) ) > 5 )
+ {
+ if ( ImplOS2NameFontToVCLFont( aFontNameBuf, aFont ) )
+ aStyleSettings.SetIconFont( aFont );
+ }
+ aFont = aStyleSettings.GetTitleFont();
+ if ( PrfQueryProfileString( HINI_PROFILE, (PSZ)aSystemFonts, (PSZ)"WindowTitles", aDummyStr, aFontNameBuf, sizeof( aFontNameBuf ) ) > 5 )
+ {
+ if ( ImplOS2NameFontToVCLFont( aFontNameBuf, aFont ) )
+ {
+ // Add Workplace Sans if not already listed
+ if ( aFont.GetName().Search( (sal_Unicode*)L"WorkPlace Sans" ) == STRING_NOTFOUND )
+ {
+ XubString aFontName = aFont.GetName();
+ aFontName.Insert( (sal_Unicode*)L"WorkPlace Sans;", 0 );
+ aFont.SetName( aFontName );
+ aFont.SetSize( Size( 0, 9 ) );
+ aFont.SetWeight( WEIGHT_BOLD );
+ aFont.SetItalic( ITALIC_NONE );
+ }
+ aStyleSettings.SetTitleFont( aFont );
+ aStyleSettings.SetFloatTitleFont( aFont );
+ }
+ }
+ aFont = aStyleSettings.GetAppFont();
+ if ( PrfQueryProfileString( HINI_PROFILE, (PSZ)aSystemFonts, (PSZ)"WindowText", aDummyStr, aFontNameBuf, sizeof( aFontNameBuf ) ) > 5 )
+ {
+ if ( ImplOS2NameFontToVCLFont( aFontNameBuf, aFont ) )
+ {
+ Font aHelpFont = aFont;
+ aHelpFont.SetName( (sal_Unicode*)L"Helv;WarpSans" );
+ aHelpFont.SetSize( Size( 0, 8 ) );
+ aHelpFont.SetWeight( WEIGHT_NORMAL );
+ aHelpFont.SetItalic( ITALIC_NONE );
+ aStyleSettings.SetHelpFont( aHelpFont );
+
+ // Add Workplace Sans if not already listed
+ if ( aFont.GetName().Search( (sal_Unicode*)L"WorkPlace Sans" ) == STRING_NOTFOUND )
+ {
+ XubString aFontName = aFont.GetName();
+ aFontName.Insert( (sal_Unicode*)L"WorkPlace Sans;", 0 );
+ aFont.SetName( aFontName );
+ aFont.SetSize( Size( 0, 9 ) );
+ }
+ aStyleSettings.SetAppFont( aFont );
+ aStyleSettings.SetToolFont( aFont );
+ aStyleSettings.SetLabelFont( aFont );
+ aStyleSettings.SetInfoFont( aFont );
+ aStyleSettings.SetRadioCheckFont( aFont );
+ aStyleSettings.SetPushButtonFont( aFont );
+ aStyleSettings.SetFieldFont( aFont );
+ aStyleSettings.SetGroupFont( aFont );
+ }
+ }
+
+ rSettings.SetStyleSettings( aStyleSettings );
+}
+
+// -----------------------------------------------------------------------
+
+SalBitmap* Os2SalFrame::SnapShot()
+{
+debug_printf("Os2SalFrame::SnapShot\n");
+return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+const SystemEnvData* Os2SalFrame::GetSystemData() const
+{
+ return &maSysData;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalFrame::Beep( SoundType eSoundType )
+{
+ static ULONG aImplSoundTab[5] =
+ {
+ WA_NOTE, // SOUND_DEFAULT
+ WA_NOTE, // SOUND_INFO
+ WA_WARNING, // SOUND_WARNING
+ WA_ERROR, // SOUND_ERROR
+ WA_NOTE // SOUND_QUERY
+ };
+
+#if 0
+#if SOUND_COUNT != 5
+#error New Sound must be defined!
+#endif
+#endif
+
+ debug_printf("Os2SalFrame::Beep %d\n", eSoundType);
+ WinAlarm( HWND_DESKTOP, aImplSoundTab[eSoundType] );
+}
+
+// -----------------------------------------------------------------------
+
+SalFrame::SalPointerState Os2SalFrame::GetPointerState()
+{
+ SalPointerState aState;
+ aState.mnState = 0;
+
+ // MausModus feststellen und setzen
+ if ( WinGetKeyState( HWND_DESKTOP, VK_BUTTON1 ) & 0x8000 )
+ aState.mnState |= MOUSE_LEFT;
+ if ( WinGetKeyState( HWND_DESKTOP, VK_BUTTON2 ) & 0x8000 )
+ aState.mnState |= MOUSE_RIGHT;
+ if ( WinGetKeyState( HWND_DESKTOP, VK_BUTTON3 ) & 0x8000 )
+ aState.mnState |= MOUSE_MIDDLE;
+ // Modifier-Tasten setzen
+ if ( WinGetKeyState( HWND_DESKTOP, VK_SHIFT ) & 0x8000 )
+ aState.mnState |= KEY_SHIFT;
+ if ( WinGetKeyState( HWND_DESKTOP, VK_CTRL ) & 0x8000 )
+ aState.mnState |= KEY_MOD1;
+ if ( WinGetKeyState( HWND_DESKTOP, VK_ALT ) & 0x8000 )
+ aState.mnState |= KEY_MOD2;
+
+ POINTL pt;
+ _WinQueryPointerPos( HWND_DESKTOP, &pt );
+
+ aState.maPos = Point( pt.x - maGeometry.nX, pt.y - maGeometry.nY );
+ return aState;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalFrame::SetBackgroundBitmap( SalBitmap* )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void SalTestMouseLeave()
+{
+ SalData* pSalData = GetSalData();
+
+ if ( pSalData->mhWantLeaveMsg && !::WinQueryCapture( HWND_DESKTOP ) )
+ {
+ POINTL aPt;
+ WinQueryPointerPos( HWND_DESKTOP, &aPt );
+ if ( pSalData->mhWantLeaveMsg != WinWindowFromPoint( HWND_DESKTOP, &aPt, TRUE ) )
+ WinSendMsg( pSalData->mhWantLeaveMsg, SAL_MSG_MOUSELEAVE, 0, MPFROM2SHORT( aPt.x, aPt.y ) );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static long ImplHandleMouseMsg( HWND hWnd,
+ UINT nMsg, MPARAM nMP1, MPARAM nMP2 )
+{
+ SalMouseEvent aMouseEvt;
+ long nRet;
+ USHORT nEvent;
+ BOOL bCall = TRUE;
+ USHORT nFlags = SHORT2FROMMP( nMP2 );
+ Os2SalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( !pFrame )
+ return 0;
+
+ aMouseEvt.mnX = (short)SHORT1FROMMP( nMP1 );
+ aMouseEvt.mnY = pFrame->mnHeight - (short)SHORT2FROMMP( nMP1 ) - 1;
+ aMouseEvt.mnCode = 0;
+ aMouseEvt.mnTime = WinQueryMsgTime( pFrame->mhAB );
+
+ // MausModus feststellen und setzen
+ if ( WinGetKeyState( HWND_DESKTOP, VK_BUTTON1 ) & 0x8000 )
+ aMouseEvt.mnCode |= MOUSE_LEFT;
+ if ( WinGetKeyState( HWND_DESKTOP, VK_BUTTON2 ) & 0x8000 )
+ aMouseEvt.mnCode |= MOUSE_RIGHT;
+ if ( WinGetKeyState( HWND_DESKTOP, VK_BUTTON3 ) & 0x8000 )
+ aMouseEvt.mnCode |= MOUSE_MIDDLE;
+ // Modifier-Tasten setzen
+ if ( WinGetKeyState( HWND_DESKTOP, VK_SHIFT ) & 0x8000 )
+ aMouseEvt.mnCode |= KEY_SHIFT;
+ if ( WinGetKeyState( HWND_DESKTOP, VK_CTRL ) & 0x8000 )
+ aMouseEvt.mnCode |= KEY_MOD1;
+ if ( WinGetKeyState( HWND_DESKTOP, VK_ALT ) & 0x8000 )
+ aMouseEvt.mnCode |= KEY_MOD2;
+
+ switch ( nMsg )
+ {
+ case WM_MOUSEMOVE:
+ {
+ SalData* pSalData = GetSalData();
+
+ // Da bei Druecken von Modifier-Tasten die MouseEvents
+ // nicht zusammengefast werden (da diese durch KeyEvents
+ // unterbrochen werden), machen wir dieses hier selber
+ if ( aMouseEvt.mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2) )
+ {
+ QMSG aTempMsg;
+ if ( WinPeekMsg( pSalData->mhAB, &aTempMsg,
+ pFrame->mhWndClient,
+ WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE ) )
+ {
+ if ( (aTempMsg.msg == WM_MOUSEMOVE) &&
+ (aTempMsg.mp2 == nMP2) )
+ return 1;
+ }
+ }
+
+ // Test for MouseLeave
+ if ( pSalData->mhWantLeaveMsg &&
+ (pSalData->mhWantLeaveMsg != pFrame->mhWndClient) )
+ {
+ POINTL aMousePoint;
+ WinQueryMsgPos( pFrame->mhAB, &aMousePoint );
+ WinSendMsg( pSalData->mhWantLeaveMsg,
+ SAL_MSG_MOUSELEAVE,
+ 0, MPFROM2SHORT( aMousePoint.x, aMousePoint.y ) );
+ }
+ pSalData->mhWantLeaveMsg = pFrame->mhWndClient;
+ // Start MouseLeave-Timer
+ if ( !pSalData->mpMouseLeaveTimer )
+ {
+ pSalData->mpMouseLeaveTimer = new AutoTimer;
+ pSalData->mpMouseLeaveTimer->SetTimeout( SAL_MOUSELEAVE_TIMEOUT );
+ pSalData->mpMouseLeaveTimer->Start();
+ // We dont need to set a timeout handler, because we test
+ // for mouseleave in the timeout callback
+ }
+ aMouseEvt.mnButton = 0;
+ nEvent = SALEVENT_MOUSEMOVE;
+ }
+ break;
+
+ case SAL_MSG_MOUSELEAVE:
+ {
+ SalData* pSalData = GetSalData();
+ if ( pSalData->mhWantLeaveMsg == pFrame->mhWndClient )
+ {
+ pSalData->mhWantLeaveMsg = 0;
+ if ( pSalData->mpMouseLeaveTimer )
+ {
+ delete pSalData->mpMouseLeaveTimer;
+ pSalData->mpMouseLeaveTimer = NULL;
+ }
+
+ // Mouse-Coordinaates are relativ to the screen
+ POINTL aPt;
+ aPt.x = (short)SHORT1FROMMP( nMP2 );
+ aPt.y = (short)SHORT2FROMMP( nMP2 );
+ WinMapWindowPoints( HWND_DESKTOP, pFrame->mhWndClient, &aPt, 1 );
+ aPt.y = pFrame->mnHeight - aPt.y - 1;
+ aMouseEvt.mnX = aPt.x;
+ aMouseEvt.mnY = aPt.y;
+ aMouseEvt.mnButton = 0;
+ nEvent = SALEVENT_MOUSELEAVE;
+ }
+ else
+ bCall = FALSE;
+ }
+ break;
+
+ case WM_BUTTON1DBLCLK:
+ case WM_BUTTON1DOWN:
+ aMouseEvt.mnButton = MOUSE_LEFT;
+ nEvent = SALEVENT_MOUSEBUTTONDOWN;
+ break;
+
+ case WM_BUTTON2DBLCLK:
+ case WM_BUTTON2DOWN:
+ aMouseEvt.mnButton = MOUSE_RIGHT;
+ nEvent = SALEVENT_MOUSEBUTTONDOWN;
+ break;
+
+ case WM_BUTTON3DBLCLK:
+ case WM_BUTTON3DOWN:
+ aMouseEvt.mnButton = MOUSE_MIDDLE;
+ nEvent = SALEVENT_MOUSEBUTTONDOWN;
+ break;
+
+ case WM_BUTTON1UP:
+ aMouseEvt.mnButton = MOUSE_LEFT;
+ nEvent = SALEVENT_MOUSEBUTTONUP;
+ break;
+
+ case WM_BUTTON2UP:
+ aMouseEvt.mnButton = MOUSE_RIGHT;
+ nEvent = SALEVENT_MOUSEBUTTONUP;
+ break;
+
+ case WM_BUTTON3UP:
+ aMouseEvt.mnButton = MOUSE_MIDDLE;
+ nEvent = SALEVENT_MOUSEBUTTONUP;
+ break;
+ }
+
+ // check if this window was destroyed - this might happen if we are the help window
+ // and sent a mouse leave message to the application which killed the help window, ie ourself
+ if( !WinIsWindow( pFrame->mhAB, hWnd ) )
+ return 0;
+
+#if OSL_DEBUG_LEVEL>10
+ //if (_bCapture)
+ debug_printf("ImplHandleMouseMsg mouse %d,%d\n",aMouseEvt.mnX,aMouseEvt.mnY);
+#endif
+
+ if ( bCall )
+ {
+ if ( nEvent == SALEVENT_MOUSEBUTTONDOWN )
+ WinUpdateWindow( pFrame->mhWndClient );
+
+ // --- RTL --- (mirror mouse pos)
+ //if( Application::GetSettings().GetLayoutRTL() )
+ // aMouseEvt.mnX = pFrame->maGeometry.nWidth-1-aMouseEvt.mnX;
+
+ nRet = pFrame->CallCallback( nEvent, &aMouseEvt );
+ if ( nMsg == WM_MOUSEMOVE )
+ {
+ WinSetPointer( HWND_DESKTOP, pFrame->mhPointer );
+ nRet = TRUE;
+ }
+ }
+ else
+ nRet = 0;
+
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+static long ImplHandleWheelMsg( HWND hWnd, UINT nMsg, MPARAM nMP1, MPARAM nMP2 )
+{
+
+ ImplSalYieldMutexAcquireWithWait();
+
+ long nRet = 0;
+ Os2SalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+
+ // Mouse-Coordinaates are relativ to the screen
+ POINTL aPt;
+ WinQueryMsgPos( pFrame->mhAB, &aPt );
+ WinMapWindowPoints( HWND_DESKTOP, pFrame->mhWndClient, &aPt, 1 );
+ aPt.y = pFrame->mnHeight - aPt.y - 1;
+
+ SalWheelMouseEvent aWheelEvt;
+ aWheelEvt.mnTime = WinQueryMsgTime( pFrame->mhAB );
+ aWheelEvt.mnX = aPt.x;
+ aWheelEvt.mnY = aPt.y;
+ aWheelEvt.mnCode = 0;
+ bool bNeg = (SHORT2FROMMP(nMP2) == SB_LINEDOWN || SHORT2FROMMP(nMP2) == SB_PAGEDOWN );
+ aWheelEvt.mnDelta = bNeg ? -120 : 120;
+ aWheelEvt.mnNotchDelta = bNeg ? -1 : 1;
+ if (SHORT2FROMMP(nMP2) == SB_PAGEUP || SHORT2FROMMP(nMP2) == SB_PAGEDOWN)
+ aWheelEvt.mnScrollLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
+ else
+ aWheelEvt.mnScrollLines = 1;
+
+ if( nMsg == WM_HSCROLL )
+ aWheelEvt.mbHorz = TRUE;
+
+ // Modifier-Tasten setzen
+ if ( WinGetKeyState( HWND_DESKTOP, VK_SHIFT ) & 0x8000 )
+ aWheelEvt.mnCode |= KEY_SHIFT;
+ if ( WinGetKeyState( HWND_DESKTOP, VK_CTRL ) & 0x8000 )
+ aWheelEvt.mnCode |= KEY_MOD1;
+ if ( WinGetKeyState( HWND_DESKTOP, VK_ALT ) & 0x8000 )
+ aWheelEvt.mnCode |= KEY_MOD2;
+
+ nRet = pFrame->CallCallback( SALEVENT_WHEELMOUSE, &aWheelEvt );
+ }
+
+ ImplSalYieldMutexRelease();
+
+ return nRet;
+}
+
+
+// -----------------------------------------------------------------------
+
+static USHORT ImplSalGetKeyCode( Os2SalFrame* pFrame, MPARAM aMP1, MPARAM aMP2 )
+{
+ USHORT nKeyFlags = SHORT1FROMMP( aMP1 );
+ UCHAR nCharCode = (UCHAR)SHORT1FROMMP( aMP2 );
+ USHORT nKeyCode = (UCHAR)SHORT2FROMMP( aMP2 );
+ UCHAR nScanCode = (UCHAR)CHAR4FROMMP( aMP1 );
+ USHORT rSVCode = 0;
+
+ // Ist virtueller KeyCode gesetzt und befindet sich der KeyCode in der
+ // Tabelle, dann mappen
+ if ( (nKeyFlags & KC_VIRTUALKEY) && (nKeyCode < KEY_TAB_SIZE) )
+ rSVCode = aImplTranslateKeyTab[nKeyCode];
+
+ // Wenn kein KeyCode ermittelt werden konnte, versuchen wir aus dem
+ // CharCode einen zu erzeugen
+ if ( !rSVCode && nCharCode )
+ {
+ // Bei 0-9, a-z und A-Z auch KeyCode setzen
+ if ( (nCharCode >= '0') && (nCharCode <= '9') && (!rSVCode || !(nKeyFlags & KC_SHIFT)) )
+ rSVCode = KEYGROUP_NUM + (nCharCode-'0');
+ else if ( (nCharCode >= 'a') && (nCharCode <= 'z') )
+ rSVCode = KEYGROUP_ALPHA + (nCharCode-'a');
+ else if ( (nCharCode >= 'A') && (nCharCode <= 'Z') )
+ rSVCode = KEYGROUP_ALPHA + (nCharCode-'A');
+ else
+ {
+ switch ( nCharCode )
+ {
+ case '+':
+ rSVCode = KEY_ADD;
+ break;
+ case '-':
+ rSVCode = KEY_SUBTRACT;
+ break;
+ case '*':
+ rSVCode = KEY_MULTIPLY;
+ break;
+ case '/':
+ rSVCode = KEY_DIVIDE;
+ break;
+ case '.':
+ rSVCode = KEY_POINT;
+ break;
+ case ',':
+ rSVCode = KEY_COMMA;
+ break;
+ case '<':
+ rSVCode = KEY_LESS;
+ break;
+ case '>':
+ rSVCode = KEY_GREATER;
+ break;
+ case '=':
+ rSVCode = KEY_EQUAL;
+ break;
+ }
+ }
+ }
+
+ // "Numlock-Hack": we want to get correct keycodes from the numpad
+ if ( (nCharCode >= '0') && (nCharCode <= '9') && !(nKeyFlags & KC_SHIFT) )
+ rSVCode = KEYGROUP_NUM + (nCharCode-'0');
+ if ( nCharCode == ',' )
+ rSVCode = KEY_COMMA;
+ if ( nCharCode == '.' )
+ rSVCode = KEY_POINT;
+
+ return rSVCode;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplUpdateInputLang( Os2SalFrame* pFrame )
+{
+ BOOL bLanguageChange = FALSE;
+ ULONG nLang = 0;
+ APIRET rc;
+ UconvObject uconv_object = NULL;
+ LocaleObject locale_object = NULL;
+ UniChar *pinfo_item;
+
+ // we do not support change of input language while working,
+ // so exit if already defined (mnInputLang is a static class field)
+ if (pFrame->mnInputLang)
+ return;
+
+ // get current locale
+ rc = UniCreateLocaleObject(UNI_UCS_STRING_POINTER, (UniChar *)L"", &locale_object);
+ // get Win32 locale id and sublanguage (hex uni string)
+ rc = UniQueryLocaleItem(locale_object, LOCI_xWinLocale, &pinfo_item);
+ // convert uni string to integer
+ rc = UniStrtoul(locale_object, pinfo_item, &pinfo_item, 16, &nLang);
+ rc = UniFreeMem(pinfo_item);
+#if OSL_DEBUG_LEVEL>10
+ debug_printf("ImplUpdateInputLang nLang %04x\n", nLang);
+ char char_buffer[256];
+ rc = UniCreateUconvObject((UniChar *)L"", &uconv_object);
+ rc = UniQueryLocaleItem(locale_object, LOCI_sKeyboard, &pinfo_item);
+ rc = UniStrFromUcs(uconv_object, char_buffer, pinfo_item, sizeof(char_buffer));
+ debug_printf("Keyboard name is: %s\n", char_buffer );
+ rc = UniFreeMem(pinfo_item);
+#endif
+ rc = UniFreeLocaleObject(locale_object);
+
+ // keep input lang up-to-date
+#if OSL_DEBUG_LEVEL>10
+ debug_printf("ImplUpdateInputLang pFrame %08x lang changed from %d to %d\n",
+ pFrame, pFrame->mnInputLang, nLang);
+#endif
+ pFrame->mnInputLang = nLang;
+}
+
+
+static sal_Unicode ImplGetCharCode( Os2SalFrame* pFrame, USHORT nKeyFlags,
+ sal_Char nCharCode, UCHAR nScanCode )
+{
+ ImplUpdateInputLang( pFrame );
+#if OSL_DEBUG_LEVEL>10
+ debug_printf("ImplGetCharCode nCharCode %c, %04x\n", nCharCode, nCharCode);
+#endif
+ return OUString( &nCharCode, 1, gsl_getSystemTextEncoding()).toChar();
+}
+
+// -----------------------------------------------------------------------
+
+LanguageType Os2SalFrame::GetInputLanguage()
+{
+ if( !mnInputLang )
+ ImplUpdateInputLang( this );
+
+ if( !mnInputLang )
+ return LANGUAGE_DONTKNOW;
+ else
+ return (LanguageType) mnInputLang;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL Os2SalFrame::MapUnicodeToKeyCode( sal_Unicode , LanguageType , KeyCode& )
+{
+ // not supported yet
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+static sal_Unicode ImplConvertKey( Os2SalFrame* pFrame, MPARAM aMP1, MPARAM aMP2 )
+{
+ USHORT nKeyFlags = SHORT1FROMMP( aMP1 );
+ UCHAR nCharCode = (UCHAR)SHORT1FROMMP( aMP2 );
+ USHORT nKeyCode = (UCHAR)SHORT2FROMMP( aMP2 );
+ UCHAR nScanCode = (UCHAR)CHAR4FROMMP( aMP1 );
+ sal_Unicode rSVCharCode = 0;
+
+ // Ist Character-Code gesetzt
+ // !!! Bei CTRL/ALT ist KC_CHAR nicht gesetzt, jedoch moechten wir
+ // !!! dann auch einen CharCode und machen die Behandlung deshalb
+ // !!! selber
+ if ( (nKeyFlags & KC_CHAR) || (nKeyFlags & KC_CTRL) || (nKeyFlags & KC_ALT) )
+ rSVCharCode = ImplGetCharCode( pFrame, nKeyFlags, nCharCode, nScanCode);
+
+ // ret unicode
+ return rSVCharCode;
+}
+
+// -----------------------------------------------------------------------
+
+static long ImplHandleKeyMsg( HWND hWnd,
+ UINT nMsg, MPARAM nMP1, MPARAM nMP2 )
+{
+ static USHORT nLastOS2KeyChar = 0;
+ static sal_Unicode nLastChar = 0;
+ USHORT nRepeat = CHAR3FROMMP( nMP1 ) - 1;
+ SHORT nFlags = SHORT1FROMMP( nMP1 );
+ USHORT nModCode = 0;
+ USHORT nSVCode = 0;
+ USHORT nOS2KeyCode = (UCHAR)SHORT2FROMMP( nMP2 );
+ sal_Unicode nSVCharCode = 0;
+ long nRet = 0;
+
+ Os2SalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( !pFrame )
+ return 0;
+
+ // determine modifiers
+ if ( nFlags & KC_SHIFT )
+ nModCode |= KEY_SHIFT;
+ if ( nFlags & KC_CTRL )
+ nModCode |= KEY_MOD1;
+ if ( nFlags & KC_ALT )
+ nModCode |= KEY_MOD2;
+
+ // Bei Shift, Control und Alt schicken wir einen KeyModChange-Event
+ if ( (nOS2KeyCode == VK_SHIFT) || (nOS2KeyCode == VK_CTRL) ||
+ (nOS2KeyCode == VK_ALT) || (nOS2KeyCode == VK_ALTGRAF) )
+ {
+ SalKeyModEvent aModEvt;
+ aModEvt.mnTime = WinQueryMsgTime( pFrame->mhAB );
+ aModEvt.mnCode = nModCode;
+#if OSL_DEBUG_LEVEL>10
+ debug_printf("SALEVENT_KEYMODCHANGE\n");
+#endif
+ nRet = pFrame->CallCallback( SALEVENT_KEYMODCHANGE, &aModEvt );
+ }
+ else
+ {
+ nSVCode = ImplSalGetKeyCode( pFrame, nMP1, nMP2 );
+ nSVCharCode = ImplConvertKey( pFrame, nMP1, nMP2 );
+#if OSL_DEBUG_LEVEL>10
+ debug_printf("nSVCode %04x nSVCharCode %04x\n",nSVCode,nSVCharCode );
+#endif
+
+ // Fuer Java muessen wir bei KeyUp einen CharCode liefern
+ if ( nFlags & KC_KEYUP )
+ {
+ if ( !nSVCharCode )
+ {
+ if ( nLastOS2KeyChar == nOS2KeyCode )
+ {
+ nSVCharCode = nLastChar;
+ nLastOS2KeyChar = 0;
+ nLastChar = 0;
+ }
+ }
+ else
+ {
+ nLastOS2KeyChar = 0;
+ nLastChar = 0;
+ }
+ }
+ else
+ {
+ nLastOS2KeyChar = nOS2KeyCode;
+ nLastChar = nSVCharCode;
+ }
+
+ if ( nSVCode || nSVCharCode )
+ {
+ SalKeyEvent aKeyEvt;
+ aKeyEvt.mnCode = nSVCode;
+ aKeyEvt.mnTime = WinQueryMsgTime( pFrame->mhAB );
+ aKeyEvt.mnCode |= nModCode;
+ aKeyEvt.mnCharCode = nSVCharCode;
+ aKeyEvt.mnRepeat = nRepeat;
+
+#if OSL_DEBUG_LEVEL>10
+ debug_printf( (nFlags & KC_KEYUP) ? "SALEVENT_KEYUP\n" : "SALEVENT_KEYINPUT\n");
+#endif
+ nRet = pFrame->CallCallback( (nFlags & KC_KEYUP) ? SALEVENT_KEYUP : SALEVENT_KEYINPUT,
+ &aKeyEvt );
+ }
+ }
+
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+static bool ImplHandlePaintMsg( HWND hWnd )
+{
+ BOOL bMutex = FALSE;
+
+ if ( ImplSalYieldMutexTryToAcquire() )
+ bMutex = TRUE;
+
+ // if we don't get the mutex, we can also change the clip region,
+ // because other threads doesn't use the mutex from the main
+ // thread --> see GetGraphics()
+
+ Os2SalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ // Laut Window-Doku soll man erst abfragen, ob ueberhaupt eine
+ // Paint-Region anliegt
+ if ( WinQueryUpdateRect( hWnd, NULL ) )
+ {
+ // Call BeginPaint/EndPaint to query the rect and send
+ // this Notofication to rect
+ HPS hPS;
+ RECTL aUpdateRect;
+ hPS = WinBeginPaint( hWnd, NULLHANDLE, &aUpdateRect );
+ WinEndPaint( hPS );
+
+ // Paint
+ if ( bMutex )
+ {
+ SalPaintEvent aPEvt( aUpdateRect.xLeft, pFrame->mnHeight - aUpdateRect.yTop, aUpdateRect.xRight- aUpdateRect.xLeft, aUpdateRect.yTop - aUpdateRect.yBottom );
+
+ pFrame->CallCallback( SALEVENT_PAINT, &aPEvt );
+ }
+ else
+ {
+ RECTL* pRect = new RECTL;
+ WinCopyRect( pFrame->mhAB, pRect, &aUpdateRect );
+ WinPostMsg( hWnd, SAL_MSG_POSTPAINT, (MPARAM)pRect, 0 );
+ }
+ }
+ }
+
+ if ( bMutex )
+ ImplSalYieldMutexRelease();
+
+ return bMutex ? true : false;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandlePaintMsg2( HWND hWnd, RECTL* pRect )
+{
+ // Paint
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ Os2SalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ SalPaintEvent aPEvt( pRect->xLeft, pFrame->mnHeight - pRect->yTop, pRect->xRight - pRect->xLeft, pRect->yTop - pRect->yBottom );
+ pFrame->CallCallback( SALEVENT_PAINT, &aPEvt );
+ }
+ ImplSalYieldMutexRelease();
+ delete pRect;
+ }
+ else
+ WinPostMsg( hWnd, SAL_MSG_POSTPAINT, (MPARAM)pRect, 0 );
+}
+
+// -----------------------------------------------------------------------
+
+static void SetMaximizedFrameGeometry( HWND hWnd, Os2SalFrame* pFrame )
+{
+ // calculate and set frame geometry of a maximized window - useful if the window is still hidden
+
+ RECTL aRect;
+ pFrame->GetWorkArea( aRect);
+
+ // a maximized window has no other borders than the caption
+ pFrame->maGeometry.nLeftDecoration = pFrame->maGeometry.nRightDecoration = pFrame->maGeometry.nBottomDecoration = 0;
+ pFrame->maGeometry.nTopDecoration = pFrame->mbCaption ? WinQuerySysValue( HWND_DESKTOP, SV_CYTITLEBAR ) : 0;
+
+ aRect.yTop += pFrame->maGeometry.nTopDecoration;
+ pFrame->maGeometry.nX = aRect.xLeft;
+ pFrame->maGeometry.nY = aRect.yBottom;
+ pFrame->maGeometry.nWidth = aRect.xRight - aRect.xLeft + 1;
+ pFrame->maGeometry.nHeight = aRect.yBottom - aRect.yTop + 1;
+}
+
+static void UpdateFrameGeometry( HWND hWnd, Os2SalFrame* pFrame )
+{
+ if( !pFrame )
+ return;
+
+ //SalFrame has a
+ //maGeometry member that holds absolute screen positions (and needs to be
+ //updated if the window is moved by the way).
+
+ // reset data
+ memset(&pFrame->maGeometry, 0, sizeof(SalFrameGeometry) );
+
+ SWP swp;
+ LONG nFrameX, nFrameY, nCaptionY;
+
+ // get frame size
+ WinQueryWindowPos(pFrame->mhWndFrame, &swp);
+ if (swp.fl & SWP_MINIMIZE)
+ return;
+
+ // map from client area to screen
+ ImplSalCalcFrameSize( pFrame, nFrameX, nFrameY, nCaptionY);
+ pFrame->maGeometry.nTopDecoration = nFrameY + nCaptionY;
+ pFrame->maGeometry.nLeftDecoration = nFrameX;
+ pFrame->maGeometry.nRightDecoration = nFrameX;
+ pFrame->maGeometry.nBottomDecoration = nFrameY;
+
+ // position of client area, not of frame corner!
+ pFrame->maGeometry.nX = swp.x + nFrameX;
+ pFrame->maGeometry.nY = nScreenHeight - (swp.y + swp.cy) + nFrameY + nCaptionY;
+
+ int nWidth = swp.cx - pFrame->maGeometry.nRightDecoration - pFrame->maGeometry.nLeftDecoration;
+ int nHeight = swp.cy - pFrame->maGeometry.nBottomDecoration - pFrame->maGeometry.nTopDecoration;
+
+ // clamp to zero
+ pFrame->maGeometry.nHeight = nHeight < 0 ? 0 : nHeight;
+ pFrame->maGeometry.nWidth = nWidth < 0 ? 0 : nWidth;
+#if OSL_DEBUG_LEVEL>0
+ debug_printf( "UpdateFrameGeometry: hwnd %x, frame %x at %d,%d (%dx%d)\n",
+ hWnd, pFrame->mhWndFrame,
+ pFrame->maGeometry.nX, pFrame->maGeometry.nY,
+ pFrame->maGeometry.nWidth,pFrame->maGeometry.nHeight);
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleMoveMsg( HWND hWnd)
+{
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ Os2SalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ UpdateFrameGeometry( hWnd, pFrame );
+
+ if ( WinIsWindowVisible( hWnd ))
+ pFrame->mbDefPos = FALSE;
+
+ // Gegen moegliche Rekursionen sichern
+ if ( !pFrame->mbInMoveMsg )
+ {
+ // Fenster im FullScreenModus wieder einpassen
+ pFrame->mbInMoveMsg = TRUE;
+ if ( pFrame->mbFullScreen )
+ ImplSalFrameFullScreenPos( pFrame );
+ pFrame->mbInMoveMsg = FALSE;
+ }
+
+ // Status merken
+ ImplSaveFrameState( pFrame );
+
+ // Call Hdl
+ //#93851 if we call this handler, VCL floating windows are not updated correctly
+ //ImplCallMoveHdl( hWnd );
+
+ }
+
+ ImplSalYieldMutexRelease();
+ }
+ else
+ WinPostMsg( hWnd, SAL_MSG_POSTMOVE, 0, 0 );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleSizeMsg( HWND hWnd, MPARAM nMP2 )
+{
+ Os2SalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ UpdateFrameGeometry( hWnd, pFrame );
+ pFrame->mbDefPos = FALSE;
+ pFrame->mnWidth = (short)SHORT1FROMMP( nMP2 );
+ pFrame->mnHeight = (short)SHORT2FROMMP( nMP2 );
+ if ( pFrame->mpGraphics )
+ pFrame->mpGraphics->mnHeight = (int)SHORT2FROMMP(nMP2);
+ // Status merken
+ ImplSaveFrameState( pFrame );
+ pFrame->CallCallback( SALEVENT_RESIZE, 0 );
+ if ( WinIsWindowVisible( pFrame->mhWndFrame ) && !pFrame->mbInShow )
+ WinUpdateWindow( pFrame->mhWndClient );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static long ImplHandleFocusMsg( Os2SalFrame* pFrame, MPARAM nMP2 )
+{
+if ( pFrame && !Os2SalFrame::mbInReparent )
+{
+ if ( SHORT1FROMMP( nMP2 ) )
+ {
+ if ( WinIsWindowVisible( pFrame->mhWndFrame ) && !pFrame->mbInShow )
+ WinUpdateWindow( pFrame->mhWndClient );
+ return pFrame->CallCallback( SALEVENT_GETFOCUS, 0 );
+ }
+ else
+ {
+ return pFrame->CallCallback( SALEVENT_LOSEFOCUS, 0 );
+ }
+}
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleCloseMsg( HWND hWnd )
+{
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ Os2SalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ pFrame->CallCallback( SALEVENT_CLOSE, 0 );
+ }
+
+ ImplSalYieldMutexRelease();
+ }
+ else
+ WinPostMsg( hWnd, WM_CLOSE, 0, 0 );
+}
+
+// -----------------------------------------------------------------------
+
+inline void ImplHandleUserEvent( HWND hWnd, MPARAM nMP2 )
+{
+ ImplSalYieldMutexAcquireWithWait();
+ Os2SalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ pFrame->CallCallback( SALEVENT_USEREVENT, (void*)nMP2 );
+ }
+ ImplSalYieldMutexRelease();
+}
+
+// -----------------------------------------------------------------------
+
+static int SalImplHandleProcessMenu( Os2SalFrame* pFrame, ULONG nMsg, MPARAM nMP1, MPARAM nMP2)
+{
+ long nRet = 0;
+debug_printf("SalImplHandleProcessMenu\n");
+#if 0
+ DWORD err=0;
+ if( !HIWORD(wParam) )
+ {
+ // Menu command
+ WORD nId = LOWORD(wParam);
+ if( nId ) // zero for separators
+ {
+ SalMenuEvent aMenuEvt;
+ aMenuEvt.mnId = nId;
+ WinSalMenuItem *pSalMenuItem = ImplGetSalMenuItem( pFrame->mSelectedhMenu, nId, FALSE );
+ if( pSalMenuItem )
+ aMenuEvt.mpMenu = pSalMenuItem->mpMenu;
+ else
+ aMenuEvt.mpMenu = NULL;
+
+ nRet = pFrame->CallCallback( SALEVENT_MENUCOMMAND, &aMenuEvt );
+ }
+ }
+#endif
+ //return (nRet != 0);
+ return (nRet == 0);
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleInputLangChange( HWND hWnd )
+{
+ ImplSalYieldMutexAcquireWithWait();
+
+ // Feststellen, ob wir IME unterstuetzen
+ Os2SalFrame* pFrame = GetWindowPtr( hWnd );
+#if 0
+ if ( pFrame && pFrame->mbIME && pFrame->mhDefIMEContext )
+ {
+ HWND hWnd = pFrame->mhWnd;
+ HKL hKL = (HKL)lParam;
+ UINT nImeProps = ImmGetProperty( hKL, IGP_PROPERTY );
+
+ pFrame->mbSpezIME = (nImeProps & IME_PROP_SPECIAL_UI) != 0;
+ pFrame->mbAtCursorIME = (nImeProps & IME_PROP_AT_CARET) != 0;
+ pFrame->mbHandleIME = !pFrame->mbSpezIME;
+ }
+#endif
+
+ // trigger input language and codepage update
+ UINT nLang = pFrame->mnInputLang;
+ ImplUpdateInputLang( pFrame );
+ debug_printf("ImplHandleInputLangChange new language 0x%04x\n",pFrame->mnInputLang);
+
+ // notify change
+ if( nLang != pFrame->mnInputLang )
+ pFrame->CallCallback( SALEVENT_INPUTLANGUAGECHANGE, 0 );
+
+ ImplSalYieldMutexRelease();
+}
+
+// -----------------------------------------------------------------------
+
+#ifdef ENABLE_IME
+
+static long ImplHandleIMEStartConversion( Os2SalFrame* pFrame )
+{
+ long nRet = FALSE;
+ SalIMEData* pIMEData = GetSalIMEData();
+ if ( pIMEData )
+ {
+ HWND hWnd = pFrame->mhWndClient;
+ HIMI hIMI = 0;
+ pIMEData->mpGetIME( hWnd, &hIMI );
+ if ( hIMI )
+ {
+ ULONG nProp;
+ if ( 0 != pIMEData->mpQueryIMEProperty( hIMI, QIP_PROPERTY, &nProp ) )
+ pFrame->mbHandleIME = FALSE;
+ else
+ {
+ pFrame->mbHandleIME = !(nProp & PRP_SPECIALUI);
+
+ }
+ if ( pFrame->mbHandleIME )
+ {
+/* Windows-Code, der noch nicht angepasst wurde !!!
+ // Cursor-Position ermitteln und aus der die Default-Position fuer
+ // das Composition-Fenster berechnen
+ SalCursorPosEvent aCursorPosEvt;
+ pFrame->CallCallback( pFrame->mpInst, pFrame,
+ SALEVENT_CURSORPOS, (void*)&aCursorPosEvt );
+ COMPOSITIONFORM aForm;
+ memset( &aForm, 0, sizeof( aForm ) );
+ if ( !aCursorPosEvt.mnWidth || !aCursorPosEvt.mnHeight )
+ aForm.dwStyle |= CFS_DEFAULT;
+ else
+ {
+ aForm.dwStyle |= CFS_POINT;
+ aForm.ptCurrentPos.x = aCursorPosEvt.mnX;
+ aForm.ptCurrentPos.y = aCursorPosEvt.mnY;
+ }
+ ImmSetCompositionWindow( hIMC, &aForm );
+
+ // Den InputContect-Font ermitteln und diesem dem Composition-Fenster
+ // bekannt machen
+*/
+
+ pFrame->mbConversionMode = TRUE;
+ pFrame->CallCallback( SALEVENT_STARTEXTTEXTINPUT, (void*)NULL );
+ nRet = TRUE;
+ }
+
+ pIMEData->mpReleaseIME( hWnd, hIMI );
+ }
+ }
+
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+static long ImplHandleIMEConversion( Os2SalFrame* pFrame, MPARAM nMP2Param )
+{
+ long nRet = FALSE;
+ SalIMEData* pIMEData = GetSalIMEData();
+ if ( pIMEData )
+ {
+ HWND hWnd = pFrame->mhWndClient;
+ HIMI hIMI = 0;
+ ULONG nMP2 = (ULONG)nMP2Param;
+ pIMEData->mpGetIME( hWnd, &hIMI );
+ if ( hIMI )
+ {
+ if ( nMP2 & (IMR_RESULT_RESULTSTRING |
+ IMR_CONV_CONVERSIONSTRING | IMR_CONV_CONVERSIONATTR |
+ IMR_CONV_CURSORPOS | IMR_CONV_CURSORATTR) )
+ {
+ SalExtTextInputEvent aEvt;
+ aEvt.mnTime = WinQueryMsgTime( pFrame->mhAB );
+ aEvt.mpTextAttr = NULL;
+ aEvt.mnCursorPos = 0;
+ aEvt.mnDeltaStart = 0;
+ aEvt.mbOnlyCursor = FALSE;
+ aEvt.mbCursorVisible = TRUE;
+
+ ULONG nBufLen = 0;
+ xub_Unicode* pBuf = NULL;
+ ULONG nAttrBufLen = 0;
+ PM_BYTE* pAttrBuf = NULL;
+ BOOL bLastCursor = FALSE;
+ if ( nMP2 & IMR_RESULT_RESULTSTRING )
+ {
+ pIMEData->mpGetResultString( hIMI, IMR_RESULT_RESULTSTRING, 0, &nBufLen );
+ if ( nBufLen > 0 )
+ {
+ pBuf = new xub_Unicode[nBufLen];
+ pIMEData->mpGetResultString( hIMI, IMR_RESULT_RESULTSTRING, pBuf, &nBufLen );
+ }
+
+ bLastCursor = TRUE;
+ aEvt.mbCursorVisible = TRUE;
+ }
+ else if ( nMP2 & (IMR_CONV_CONVERSIONSTRING | IMR_CONV_CONVERSIONATTR |
+ IMR_CONV_CURSORPOS | IMR_CONV_CURSORATTR) )
+ {
+ pIMEData->mpGetConversionString( hIMI, IMR_CONV_CONVERSIONSTRING, 0, &nBufLen );
+ if ( nBufLen > 0 )
+ {
+ pBuf = new xub_Unicode[nBufLen];
+ pIMEData->mpGetConversionString( hIMI, IMR_CONV_CONVERSIONSTRING, pBuf, &nBufLen );
+ }
+
+ pIMEData->mpGetConversionString( hIMI, IMR_CONV_CONVERSIONATTR, 0, &nAttrBufLen );
+ if ( nAttrBufLen > 0 )
+ {
+ pAttrBuf = new PM_BYTE[nAttrBufLen];
+ pIMEData->mpGetConversionString( hIMI, IMR_CONV_CONVERSIONATTR, pAttrBuf, &nAttrBufLen );
+ }
+
+/* !!! Wir bekommen derzeit nur falsche Daten, deshalb zeigen wir derzeit
+ !!! auch keine Cursor an
+ ULONG nTempBufLen;
+ ULONG nCursorPos = 0;
+ ULONG nCursorAttr = 0;
+ ULONG nChangePos = 0;
+ nTempBufLen = sizeof( ULONG );
+ pIMEData->mpGetConversionString( hIMI, IMR_CONV_CURSORPOS, &nCursorPos, &nTempBufLen );
+ nTempBufLen = sizeof( ULONG );
+ pIMEData->mpGetConversionString( hIMI, IMR_CONV_CURSORATTR, &nCursorAttr, &nTempBufLen );
+ nTempBufLen = sizeof( ULONG );
+ pIMEData->mpGetConversionString( hIMI, IMR_CONV_CHANGESTART, &nChangePos, &nTempBufLen );
+
+ aEvt.mnCursorPos = nCursorPos;
+ aEvt.mnDeltaStart = nChangePos;
+ if ( nCursorAttr & CP_CURSORATTR_INVISIBLE )
+ aEvt.mbCursorVisible = FALSE;
+*/
+ aEvt.mnCursorPos = 0;
+ aEvt.mnDeltaStart = 0;
+ aEvt.mbCursorVisible = FALSE;
+
+ if ( (nMP2 == IMR_CONV_CURSORPOS) ||
+ (nMP2 == IMR_CONV_CURSORATTR) )
+ aEvt.mbOnlyCursor = TRUE;
+ }
+
+ USHORT* pSalAttrAry = NULL;
+ if ( pBuf )
+ {
+ aEvt.maText = XubString( pBuf, (USHORT)nBufLen );
+ delete [] pBuf;
+ if ( pAttrBuf )
+ {
+ USHORT nTextLen = aEvt.maText.Len();
+ if ( nTextLen )
+ {
+ pSalAttrAry = new USHORT[nTextLen];
+ memset( pSalAttrAry, 0, nTextLen*sizeof( USHORT ) );
+ for ( USHORT i = 0; (i < nTextLen) && (i < nAttrBufLen); i++ )
+ {
+ PM_BYTE nOS2Attr = pAttrBuf[i];
+ USHORT nSalAttr;
+ if ( nOS2Attr == CP_ATTR_TARGET_CONVERTED )
+ nSalAttr = SAL_EXTTEXTINPUT_ATTR_TARGETCONVERTED | SAL_EXTTEXTINPUT_ATTR_UNDERLINE | SAL_EXTTEXTINPUT_ATTR_HIGHLIGHT;
+ else if ( nOS2Attr == CP_ATTR_CONVERTED )
+ nSalAttr = SAL_EXTTEXTINPUT_ATTR_CONVERTED | SAL_EXTTEXTINPUT_ATTR_DASHDOTUNDERLINE;
+ else if ( nOS2Attr == CP_ATTR_TARGET_NOTCONVERTED )
+ nSalAttr = SAL_EXTTEXTINPUT_ATTR_TARGETNOTCONVERTED | SAL_EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE;
+ else if ( nOS2Attr == CP_ATTR_INPUT_ERROR )
+ nSalAttr = SAL_EXTTEXTINPUT_ATTR_INPUTERROR | SAL_EXTTEXTINPUT_ATTR_REDTEXT | SAL_EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE;
+ else /* ( nOS2Attr == CP_ATTR_INPUT ) */
+ nSalAttr = SAL_EXTTEXTINPUT_ATTR_INPUT | SAL_EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE;
+ pSalAttrAry[i] = nSalAttr;
+ }
+ aEvt.mpTextAttr = pSalAttrAry;
+ }
+ delete [] pAttrBuf;
+ }
+ if ( bLastCursor )
+ aEvt.mnCursorPos = aEvt.maText.Len();
+ }
+
+ pIMEData->mpReleaseIME( hWnd, hIMI );
+
+ // Handler rufen und wenn wir ein Attribute-Array haben, danach
+ // wieder zerstoeren
+ pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&aEvt );
+ if ( pSalAttrAry )
+ delete [] pSalAttrAry;
+ }
+ else
+ pIMEData->mpReleaseIME( hWnd, hIMI );
+ }
+
+ nRet = TRUE;
+ }
+
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+inline long ImplHandleIMEEndConversion( Os2SalFrame* pFrame )
+{
+ pFrame->mbConversionMode = FALSE;
+ pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, (void*)NULL );
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleIMEOpenCandidate( Os2SalFrame* pFrame )
+{
+ pFrame->mbCandidateMode = TRUE;
+
+ long nRet = FALSE;
+ SalIMEData* pIMEData = GetSalIMEData();
+ if ( pIMEData )
+ {
+ HWND hWnd = pFrame->mhWndClient;
+ HIMI hIMI = 0;
+ pIMEData->mpGetIME( hWnd, &hIMI );
+ if ( hIMI )
+ {
+ ULONG nBufLen = 0;
+ pIMEData->mpGetConversionString( hIMI, IMR_CONV_CONVERSIONSTRING, 0, &nBufLen );
+ if ( nBufLen > 0 )
+ {
+/* !!! Wir bekommen derzeit nur falsche Daten steht der Cursor immer bei 0
+ ULONG nTempBufLen = sizeof( ULONG );
+ ULONG nCursorPos = 0;
+ pIMEData->mpGetConversionString( hIMI, IMR_CONV_CURSORPOS, &nCursorPos, &nTempBufLen );
+*/
+ ULONG nCursorPos = 0;
+
+ SalExtTextInputPosEvent aEvt;
+ aEvt.mnTime = WinQueryMsgTime( pFrame->mhAB );
+ aEvt.mnFirstPos = nCursorPos;
+ aEvt.mnChars = nBufLen-nCursorPos;
+ aEvt.mpPosAry = new SalExtCharPos[aEvt.mnChars];
+ memset( aEvt.mpPosAry, 0, aEvt.mnChars*sizeof(SalExtCharPos) );
+
+ pFrame->CallCallback( SALEVENT_EXTTEXTINPUTPOS, (void*)&aEvt );
+
+ long nMinLeft = aEvt.mpPosAry[0].mnX;
+ long nMinTop = aEvt.mpPosAry[0].mnY;
+ long nMaxBottom = aEvt.mpPosAry[0].mnY+aEvt.mpPosAry[0].mnHeight;
+ long nMaxRight = nMinLeft;
+ USHORT i = 0;
+ while ( i < aEvt.mnChars )
+ {
+ // Solange wir uns auf der gleichen Zeile bewegen,
+ // ermitteln wir die Rechteck-Grenzen
+ if ( !aEvt.mpPosAry[i].mnHeight ||
+ (aEvt.mpPosAry[i].mnY < nMaxBottom-1) )
+ {
+ if ( aEvt.mpPosAry[i].mnX < nMinLeft )
+ nMinLeft = aEvt.mpPosAry[i].mnX;
+ if ( aEvt.mpPosAry[i].mnX+aEvt.mpPosAry[0].mnWidth > nMaxRight )
+ nMaxRight = aEvt.mpPosAry[i].mnX+aEvt.mpPosAry[0].mnWidth;
+ if ( aEvt.mpPosAry[i].mnY < nMinTop )
+ nMinTop = aEvt.mpPosAry[i].mnY;
+ i++;
+ }
+ else
+ break;
+ }
+
+ CANDIDATEPOS aForm;
+ aForm.ulIndex = 0;
+ aForm.ulStyle = CPS_EXCLUDE;
+ aForm.ptCurrentPos.x = aEvt.mpPosAry[0].mnX;
+ aForm.ptCurrentPos.y = pFrame->mnHeight - (nMaxBottom+1) - 1;
+ aForm.rcArea.xLeft = nMinLeft;
+ aForm.rcArea.yBottom = pFrame->mnHeight - nMaxBottom - 1;
+ aForm.rcArea.xRight = nMaxRight+1;
+ aForm.rcArea.yTop = pFrame->mnHeight - nMinTop - 1;
+ pIMEData->mpSetCandidateWin( hIMI, &aForm );
+
+ delete aEvt.mpPosAry;
+ }
+
+ pIMEData->mpReleaseIME( hWnd, hIMI );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+inline void ImplHandleIMECloseCandidate( Os2SalFrame* pFrame )
+{
+ pFrame->mbCandidateMode = FALSE;
+}
+
+#endif
+
+// -----------------------------------------------------------------------
+
+MRESULT EXPENTRY SalFrameWndProc( HWND hWnd, ULONG nMsg,
+ MPARAM nMP1, MPARAM nMP2 )
+{
+ Os2SalFrame* pFrame = (Os2SalFrame*)GetWindowPtr( hWnd );
+ MRESULT nRet = (MRESULT)0;
+ BOOL bDef = TRUE;
+ bool bCheckTimers= false;
+
+#if OSL_DEBUG_LEVEL>10
+ if (nMsg!=WM_TIMER && nMsg!=WM_MOUSEMOVE)
+ debug_printf( "SalFrameWndProc hWnd 0x%x nMsg 0x%x\n", hWnd, nMsg);
+#endif
+
+ switch( nMsg )
+ {
+ case WM_MOUSEMOVE:
+ case WM_BUTTON1DOWN:
+ case WM_BUTTON2DOWN:
+ case WM_BUTTON3DOWN:
+ case WM_BUTTON1DBLCLK:
+ case WM_BUTTON2DBLCLK:
+ case WM_BUTTON3DBLCLK:
+ case WM_BUTTON1UP:
+ case WM_BUTTON2UP:
+ case WM_BUTTON3UP:
+ case SAL_MSG_MOUSELEAVE:
+ // ButtonUp/Down nie an die WinDefWindowProc weiterleiten, weil sonst
+ // die Message an den Owner weitergeleitet wird
+ ImplSalYieldMutexAcquireWithWait();
+ bDef = !ImplHandleMouseMsg( hWnd, nMsg, nMP1, nMP2 );
+ ImplSalYieldMutexRelease();
+ break;
+
+ case WM_CHAR:
+ if ( pFrame->mbConversionMode )
+ bDef = FALSE;
+ else
+ bDef = !ImplHandleKeyMsg( hWnd, nMsg, nMP1, nMP2 );
+ break;
+
+ case WM_ERASEBACKGROUND:
+ nRet = (MRESULT)FALSE;
+ bDef = FALSE;
+ break;
+
+ case WM_PAINT:
+ bCheckTimers = ImplHandlePaintMsg( hWnd );
+ bDef = FALSE;
+ break;
+ case SAL_MSG_POSTPAINT:
+ ImplHandlePaintMsg2( hWnd, (RECTL*)nMP1 );
+ bCheckTimers = true;
+ bDef = FALSE;
+ break;
+
+ case WM_MOVE:
+ case SAL_MSG_POSTMOVE:
+ ImplHandleMoveMsg( hWnd );
+ bDef = FALSE;
+ break;
+
+ case WM_SIZE:
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ ImplHandleSizeMsg( hWnd, nMP2 );
+ ImplSalYieldMutexRelease();
+ }
+ else
+ WinPostMsg( hWnd, SAL_MSG_POSTSIZE, nMP1, nMP2 );
+ break;
+ case SAL_MSG_POSTSIZE:
+ ImplHandleSizeMsg( hWnd, nMP2 );
+ break;
+ case WM_MINMAXFRAME:
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ PSWP pswp = (PSWP) nMP1;
+ ImplHandleSizeMsg( hWnd, MPFROM2SHORT( pswp->cx, pswp->cy) );
+ ImplSalYieldMutexRelease();
+ }
+ else
+ WinPostMsg( hWnd, SAL_MSG_POSTSIZE, 0, nMP2 );
+ break;
+
+ case WM_CALCVALIDRECTS:
+ return (MRESULT)(CVR_ALIGNLEFT | CVR_ALIGNTOP);
+
+ case WM_SETFOCUS:
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ ImplHandleFocusMsg( pFrame, nMP2 );
+ ImplSalYieldMutexRelease();
+ }
+ else
+ WinPostMsg( hWnd, SAL_MSG_POSTFOCUS, 0, nMP2 );
+ break;
+ case SAL_MSG_POSTFOCUS:
+ ImplHandleFocusMsg( pFrame, nMP2 );
+ break;
+
+ case WM_TRANSLATEACCEL:
+ {
+ // Da uns OS/2 zu viele Tasten abfaegnt, unternehmen wir etwas,
+ // damit wir Shift+F1, Shift+F10 und Shift+Enter bekommen
+ PQMSG pMsg = (PQMSG)nMP1;
+ USHORT nKeyFlags = SHORT1FROMMP( pMsg->mp1 );
+ USHORT nKeyCode = (UCHAR)SHORT2FROMMP( pMsg->mp2 );
+
+ if ( !(nKeyFlags & KC_KEYUP) && (nKeyFlags & KC_VIRTUALKEY) &&
+ (nKeyFlags & KC_SHIFT) && (nKeyCode != VK_ESC) )
+ return (MRESULT)FALSE;
+
+ if ( nKeyCode == VK_F1 )
+ return (MRESULT)FALSE;
+ }
+ break;
+
+ case WM_CREATE:
+ {
+ HWND hWndFrame = WinQueryWindow(hWnd, QW_PARENT);
+ if (hWndFrame == 0)
+ debug_printf(" WARNING NULL FRAME!!\n");
+ SalData* pSalData = GetSalData();
+ // Window-Instanz am Windowhandle speichern
+ pFrame = pSalData->mpCreateFrame;
+ pSalData->mpCreateFrame = NULL;
+ SetWindowPtr( hWnd, pFrame );
+ SetWindowPtr( hWndFrame, pFrame);
+ // HWND schon hier setzen, da schon auf den Instanzdaten
+ // gearbeitet werden kann, wenn Messages waehrend
+ // CreateWindow() gesendet werden
+ pFrame->mhWndClient = hWnd;
+ pFrame->mhWndFrame = hWndFrame;
+ pFrame->maSysData.hWnd = hWnd;
+ }
+ break;
+
+ case WM_CLOSE:
+ ImplHandleCloseMsg( hWnd );
+ bDef = FALSE;
+ break;
+
+ case WM_SYSVALUECHANGED:
+ if ( pFrame->mbFullScreen )
+ ImplSalFrameFullScreenPos( pFrame );
+ // kein break, da der Rest auch noch verarbeitet werden soll
+ case PL_ALTERED:
+ case WM_SYSCOLORCHANGE:
+ ImplSalYieldMutexAcquire();
+ pFrame->CallCallback( SALEVENT_SETTINGSCHANGED, 0 );
+ ImplSalYieldMutexRelease();
+ break;
+
+ case SAL_MSG_USEREVENT:
+ ImplHandleUserEvent( hWnd, nMP2 );
+ bDef = FALSE;
+ break;
+ case SAL_MSG_TOTOP:
+ ImplSalToTop( hWnd, (ULONG)nMP1 );
+ bDef = FALSE;
+ break;
+ case SAL_MSG_SHOW:
+ ImplSalShow( hWnd, (ULONG)nMP1, (ULONG)nMP2 );
+ bDef = FALSE;
+ break;
+
+ case WM_KBDLAYERCHANGED:
+ debug_printf("hWnd 0x%08x WM_KBDLAYERCHANGED\n", hWnd);
+ ImplHandleInputLangChange( hWnd );
+ break;
+
+ case WM_HSCROLL:
+ case WM_VSCROLL:
+ ImplHandleWheelMsg( hWnd, nMsg, nMP1, nMP2 );
+ bDef = FALSE;
+ break;
+
+ case WM_COMMAND:
+ case SAL_MSG_SYSPROCESSMENU:
+ if ( SalImplHandleProcessMenu( pFrame, nMsg, nMP1, nMP2 ) )
+ {
+ bDef = FALSE;
+ nRet = (MRESULT)1;
+ }
+ break;
+
+#ifdef ENABLE_IME
+ case WM_IMEREQUEST:
+ if ( (ULONG)nMP1 == IMR_CONVRESULT )
+ {
+ if ( pFrame->mbHandleIME )
+ {
+ // Nur im Conversionmodus akzeptieren wir den IME-Input
+ if ( pFrame->mbConversionMode )
+ {
+ ImplSalYieldMutexAcquire();
+ if ( ImplHandleIMEConversion( pFrame, nMP2 ) )
+ {
+ bDef = FALSE;
+ nRet = (MRESULT)TRUE;
+ }
+ ImplSalYieldMutexRelease();
+ }
+ }
+ }
+ else if ( (ULONG)nMP1 == IMR_CANDIDATE )
+ {
+ if ( pFrame->mbHandleIME )
+ {
+ ImplSalYieldMutexAcquire();
+ if ( (ULONG)nMP2 & IMR_CANDIDATE_SHOW )
+ ImplHandleIMEOpenCandidate( pFrame );
+ else if ( (ULONG)nMP2 & IMR_CANDIDATE_HIDE )
+ ImplHandleIMECloseCandidate( pFrame );
+ ImplSalYieldMutexRelease();
+ }
+ }
+ break;
+
+ case WM_IMENOTIFY:
+ if ( (ULONG)nMP1 == IMN_STARTCONVERSION )
+ {
+ ImplSalYieldMutexAcquire();
+ if ( ImplHandleIMEStartConversion( pFrame ) )
+ {
+ bDef = FALSE;
+ nRet = (MRESULT)TRUE;
+ }
+ ImplSalYieldMutexRelease();
+ }
+ else if ( (ULONG)nMP1 == IMN_ENDCONVERSION )
+ {
+ if ( pFrame->mbHandleIME )
+ {
+ ImplSalYieldMutexAcquire();
+ if ( ImplHandleIMEEndConversion( pFrame ) )
+ {
+ bDef = FALSE;
+ nRet = (MRESULT)TRUE;
+ }
+ ImplSalYieldMutexRelease();
+ }
+ }
+ break;
+#endif
+ }
+
+ if( bCheckTimers )
+ {
+ SalData* pSalData = GetSalData();
+ if( pSalData->mnNextTimerTime )
+ {
+ ULONG nCurTime;
+ DosQuerySysInfo( QSV_MS_COUNT, QSV_MS_COUNT, (PVOID)&nCurTime, sizeof(ULONG));
+ if( pSalData->mnNextTimerTime < nCurTime )
+ {
+ QMSG aMsg;
+ if (!WinPeekMsg( pFrame->mhAB, &aMsg, 0, WM_PAINT, WM_PAINT, PM_NOREMOVE ) )
+ WinPostMsg( pSalData->mpFirstInstance->mhComWnd, SAL_MSG_POSTTIMER, 0, (MPARAM)nCurTime );
+ }
+ }
+ }
+
+ if ( bDef )
+ nRet = WinDefWindowProc( hWnd, nMsg, nMP1, nMP2 );
+
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalFrame::ResetClipRegion()
+{
+}
+
+void Os2SalFrame::BeginSetClipRegion( ULONG )
+{
+}
+
+void Os2SalFrame::UnionClipRegion( long, long, long, long )
+{
+}
+
+void Os2SalFrame::EndSetClipRegion()
+{
+}
+
+// -----------------------------------------------------------------------
+
+MRESULT EXPENTRY SalFrameSubClassWndProc( HWND hWnd, ULONG nMsg,
+ MPARAM nMP1, MPARAM nMP2 )
+{
+ MRESULT mReturn = 0L;
+
+ // ticket#124 min size of 132 px is too much
+ if (nMsg == WM_QUERYTRACKINFO) {
+ PTRACKINFO pti;
+ // first, let PM initialize TRACKINFO
+ mReturn = aSalShlData.mpFrameProc( hWnd, nMsg, nMP1, nMP2 );
+ // now change default min size
+ pti = (PTRACKINFO) nMP2;
+ pti->ptlMinTrackSize.x = 64L;
+ // now return to PM
+ return mReturn;
+ }
+
+ return aSalShlData.mpFrameProc( hWnd, nMsg, nMP1, nMP2 );
+}
+
+// -----------------------------------------------------------------------
diff --git a/vcl/os2/source/window/salmenu.cxx b/vcl/os2/source/window/salmenu.cxx
new file mode 100644
index 000000000000..339ab5dbfadb
--- /dev/null
+++ b/vcl/os2/source/window/salmenu.cxx
@@ -0,0 +1,132 @@
+/*************************************************************************
+ *
+ * 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 INCL_DOS
+#define INCL_PM
+#define INCL_WIN
+#include <svpm.h>
+#include <saldata.hxx>
+#include <salinst.h>
+#include <salmenu.h>
+
+
+// =======================================================================
+
+// Os2SalInst factory methods
+
+SalMenu* Os2SalInstance::CreateMenu( BOOL bMenuBar )
+{
+ return NULL; // no support for native menues
+}
+
+void Os2SalInstance::DestroyMenu( SalMenu* pSalMenu )
+{
+ delete pSalMenu;
+}
+
+
+SalMenuItem* Os2SalInstance::CreateMenuItem( const SalItemParams* pItemData )
+{
+ return NULL; // no support for native menues
+}
+
+void Os2SalInstance::DestroyMenuItem( SalMenuItem* pSalMenuItem )
+{
+ delete pSalMenuItem;
+}
+
+
+// =======================================================================
+
+
+/*
+ * Os2SalMenu
+ */
+
+
+Os2SalMenu::~Os2SalMenu()
+{
+}
+
+BOOL Os2SalMenu::VisibleMenuBar()
+{
+ return FALSE;
+}
+
+void Os2SalMenu::SetFrame( const SalFrame *pFrame )
+{
+}
+
+void Os2SalMenu::InsertItem( SalMenuItem* pSalMenuItem, unsigned nPos )
+{
+}
+
+void Os2SalMenu::RemoveItem( unsigned nPos )
+{
+}
+
+void Os2SalMenu::SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos )
+{
+}
+
+void Os2SalMenu::CheckItem( unsigned nPos, BOOL bCheck )
+{
+}
+
+void Os2SalMenu::EnableItem( unsigned nPos, BOOL bEnable )
+{
+}
+
+void Os2SalMenu::SetItemImage( unsigned nPos, SalMenuItem* pSalMenuItem, const Image& rImage )
+{
+}
+
+void Os2SalMenu::SetItemText( unsigned nPos, SalMenuItem* pSalMenuItem, const XubString& rText )
+{
+}
+
+void Os2SalMenu::SetAccelerator( unsigned nPos, SalMenuItem* pSalMenuItem, const KeyCode& rKeyCode, const XubString& rKeyName )
+{
+}
+
+void Os2SalMenu::GetSystemMenuData( SystemMenuData* pData )
+{
+}
+
+// =======================================================================
+
+/*
+ * SalMenuItem
+ */
+
+
+Os2SalMenuItem::~Os2SalMenuItem()
+{
+}
+
+// -------------------------------------------------------------------
+
diff --git a/vcl/os2/source/window/salobj.cxx b/vcl/os2/source/window/salobj.cxx
new file mode 100644
index 000000000000..85ed1a606d08
--- /dev/null
+++ b/vcl/os2/source/window/salobj.cxx
@@ -0,0 +1,568 @@
+/*************************************************************************
+ *
+ * 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 <svpm.h>
+
+#define _SV_SALOBJ_CXX
+#include <saldata.hxx>
+#include <salinst.h>
+#include <salframe.h>
+#include <salobj.h>
+
+// =======================================================================
+
+static BOOL ImplIsSysWindowOrChild( HWND hWndParent, HWND hWndChild )
+{
+ if ( hWndParent == hWndChild )
+ return TRUE;
+
+ HWND hTempWnd = WinQueryWindow( hWndChild, QW_PARENT );
+ while ( hTempWnd )
+ {
+ if ( hTempWnd == hWndParent )
+ return TRUE;
+ hTempWnd = WinQueryWindow( hTempWnd, QW_PARENT );
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+static Os2SalObject* ImplFindOs2SalObject( HWND hWndChild )
+{
+ SalData* pSalData = GetSalData();
+ Os2SalObject* pObject = pSalData->mpFirstObject;
+ while ( pObject )
+ {
+ if ( ImplIsSysWindowOrChild( pObject->mhWndChild, hWndChild ) )
+ return pObject;
+
+ pObject = pObject->mpNextObject;
+ }
+
+ return NULL;
+}
+
+// =======================================================================
+
+BOOL EXPENTRY SalSysMsgProc( HAB /* hAB */, QMSG* pMsg, ULONG /* fs */ )
+{
+ if ( (pMsg->msg == WM_BUTTON1DOWN) ||
+ (pMsg->msg == WM_BUTTON2DOWN) ||
+ (pMsg->msg == WM_BUTTON3DOWN) )
+ {
+ SalData* pSalData = GetSalData();
+ Os2SalObject* pObject = ImplFindOs2SalObject( pMsg->hwnd );
+ if ( pObject )
+ WinPostMsg( pObject->mhWnd, SALOBJ_MSG_TOTOP, 0, 0 );
+ }
+
+ // Focus fangen wir hier nicht ab, da wir erstmal davon ausgehen,
+ // das unser Os2SalObject-Fenster immer eine WM_FOCUSCHANGE-Message
+ // bekommt.
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+MRESULT EXPENTRY SalSysObjWndProc( HWND hWnd, ULONG nMsg,
+ MPARAM nMP1, MPARAM nMP2 )
+{
+ Os2SalObject* pSysObj;
+ MRESULT nRet = 0;
+ int bDef = TRUE;
+
+#if OSL_DEBUG_LEVEL>0
+ debug_printf( "SalSysObjWndProc hWnd 0x%x nMsg %d\n", hWnd, nMsg);
+#endif
+
+ switch( nMsg )
+ {
+ case WM_ERASEBACKGROUND:
+ nRet = (MRESULT)FALSE;
+ bDef = FALSE;
+ break;
+ case WM_PAINT:
+ {
+ HPS hPS;
+ RECTL aRect;
+ hPS = WinBeginPaint( hWnd, NULLHANDLE, &aRect );
+ WinEndPaint( hPS );
+ bDef = FALSE;
+ }
+ bDef = FALSE;
+ break;
+
+ case WM_BUTTON1DOWN:
+ case WM_BUTTON2DOWN:
+ case WM_BUTTON3DOWN:
+ case SALOBJ_MSG_TOTOP:
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ pSysObj = GetSalObjWindowPtr( hWnd );
+ pSysObj->mpProc( pSysObj->mpInst, pSysObj,
+ SALOBJ_EVENT_TOTOP, 0 );
+ ImplSalYieldMutexRelease();
+ }
+ else
+ WinPostMsg( hWnd, SALOBJ_MSG_TOTOP, 0, 0 );
+ break;
+
+ case WM_FOCUSCHANGE:
+ case SALOBJ_MSG_POSTFOCUS:
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ pSysObj = GetSalObjWindowPtr( hWnd );
+ if ( SHORT1FROMMP( nMP2 ) )
+ {
+ pSysObj->mhLastFocusWnd = WinQueryFocus( HWND_DESKTOP );
+ pSysObj->mpProc( pSysObj->mpInst, pSysObj,
+ SALOBJ_EVENT_GETFOCUS, 0 );
+ }
+ else
+ {
+ HWND hWndFocus = HWNDFROMMP( nMP1 );
+ if ( !hWndFocus || !ImplIsSysWindowOrChild( hWnd, hWndFocus ) )
+ {
+ pSysObj->mpProc( pSysObj->mpInst, pSysObj,
+ SALOBJ_EVENT_LOSEFOCUS, 0 );
+ }
+ }
+ ImplSalYieldMutexRelease();
+ }
+ else
+ WinPostMsg( hWnd, SALOBJ_MSG_POSTFOCUS, nMP1, nMP2 );
+ break;
+
+ case WM_SIZE:
+ {
+ pSysObj = GetSalObjWindowPtr( hWnd );
+ pSysObj->mnHeight = (short)SHORT2FROMMP( nMP2 );
+ WinSetWindowPos( pSysObj->mhWndChild, 0,
+ 0, 0,
+ (short)SHORT1FROMMP( nMP2 ), (short)SHORT2FROMMP( nMP2 ),
+ SWP_SIZE | SWP_MOVE );
+ bDef = FALSE;
+ }
+ break;
+
+ case WM_CREATE:
+ {
+ // Window-Instanz am Windowhandle speichern
+ CREATESTRUCT* pStruct = (CREATESTRUCT*)nMP2;
+ pSysObj = (Os2SalObject*)pStruct->pPresParams;
+ SetSalObjWindowPtr( hWnd, pSysObj );
+ bDef = FALSE;
+ }
+ break;
+ }
+
+ if ( bDef )
+ nRet = WinDefWindowProc( hWnd, nMsg, nMP1, nMP2 );
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+MRESULT EXPENTRY SalSysObjChildWndProc( HWND hWnd, ULONG nMsg,
+ MPARAM nMP1, MPARAM nMP2 )
+{
+ MRESULT nRet = 0;
+ int bDef = TRUE;
+
+ debug_printf( "SalSysObjChildWndProc hWnd 0x%x nMsg %d\n", hWnd, nMsg);
+
+ switch( nMsg )
+ {
+ case WM_ERASEBACKGROUND:
+ // Wegen PlugIn's loeschen wir erstmal den Hintergrund
+/*
+ nRet = (MRESULT)FALSE;
+ bDef = FALSE;
+*/
+ break;
+ case WM_PAINT:
+ {
+ HPS hPS;
+ RECTL aRect;
+ hPS = WinBeginPaint( hWnd, NULLHANDLE, &aRect );
+ WinEndPaint( hPS );
+ bDef = FALSE;
+ }
+ break;
+ }
+
+ if ( bDef )
+ nRet = WinDefWindowProc( hWnd, nMsg, nMP1, nMP2 );
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+MRESULT EXPENTRY SalSysObjClipWndProc( HWND hWnd, ULONG nMsg,
+ MPARAM nMP1, MPARAM nMP2 )
+{
+ MRESULT nRet = 0;
+ int bDef = TRUE;
+
+ debug_printf( "SalSysObjClipWndProc hWnd 0x%x nMsg %d\n", hWnd, nMsg);
+
+ switch( nMsg )
+ {
+ case WM_MOUSEMOVE:
+ case WM_BUTTON1DOWN:
+ case WM_BUTTON2DOWN:
+ case WM_BUTTON3DOWN:
+ case WM_BUTTON1DBLCLK:
+ case WM_BUTTON2DBLCLK:
+ case WM_BUTTON3DBLCLK:
+ case WM_BUTTON1UP:
+ case WM_BUTTON2UP:
+ case WM_BUTTON3UP:
+ {
+ // Alle Events an den Frame weiterreichen, da diese Bereiche
+ // dem Frame gehoeren. Dazu muessen die Mouse-Koordinaaten
+ // entsprechend umgerechnet werden
+ HWND hWndParent = WinQueryWindow( hWnd, QW_PARENT ); // ergibt SysChild-Fenster
+ hWndParent = WinQueryWindow( hWndParent, QW_PARENT );
+ short nX = (short)SHORT1FROMMP( nMP1 );
+ short nY = (short)SHORT2FROMMP( nMP1 );
+ POINTL aPos;
+ aPos.x = nX;
+ aPos.y = nY;
+ WinMapWindowPoints( hWnd, hWndParent, &aPos, 1 );
+ nMP1 = MPFROM2SHORT( (short)aPos.x, (short)aPos.y );
+ bDef = FALSE;
+ nRet = WinSendMsg( hWndParent, nMsg, nMP1, nMP2 );
+ }
+ break;
+
+ case WM_HITTEST:
+ // Damit im disablten Zustand die MouseKlicks immer noch
+ // an den Frame geschickt werden
+ // Dieser Code reicht leider nicht aus, deshalb wir unter
+ // OS2 immer das Child-Fenster disablen, im Gegensatz
+ // zu Windows, wo immer der Parent disablte wird, da
+ // sich das Fenster evtl. anders Darstellen koennte,
+ // wenn es disablte wird. Da dieser Fall uns bisher
+ // nicht bekannt ist, ignorieren wir das.
+ nRet = HT_NORMAL;
+ bDef = FALSE;
+ break;
+
+ case WM_ERASEBACKGROUND:
+ nRet = (MRESULT)FALSE;
+ bDef = FALSE;
+ break;
+ case WM_PAINT:
+ {
+ HPS hPS;
+ RECTL aRect;
+ hPS = WinBeginPaint( hWnd, NULLHANDLE, &aRect );
+ WinEndPaint( hPS );
+ bDef = FALSE;
+ }
+ break;
+ }
+
+ if ( bDef )
+ nRet = WinDefWindowProc( hWnd, nMsg, nMP1, nMP2 );
+ return nRet;
+}
+
+// =======================================================================
+
+void ImplDestroyAllClipWindows( HWND hWndLast )
+{
+ if ( hWndLast == HWND_TOP )
+ return;
+
+ HWND hWndPrev;
+ while ( hWndLast )
+ {
+ hWndPrev = WinQueryWindow( hWndLast, QW_PREV );
+ WinDestroyWindow( hWndLast );
+ hWndLast = hWndPrev;
+ }
+}
+
+// =======================================================================
+
+SalObject* ImplSalCreateObject( Os2SalInstance* pInst, Os2SalFrame* pParent )
+{
+ SalData* pSalData = GetSalData();
+
+ if ( !pSalData->mbObjClassInit )
+ {
+ if ( WinRegisterClass( pSalData->mhAB, (PSZ)SAL_OBJECT_CLASSNAME,
+ (PFNWP)SalSysObjWndProc, CS_MOVENOTIFY,
+ SAL_OBJECT_WNDEXTRA ) )
+ {
+ if ( WinRegisterClass( pSalData->mhAB, (PSZ)SAL_OBJECT_CLIPCLASSNAME,
+ (PFNWP)SalSysObjClipWndProc, CS_HITTEST | CS_MOVENOTIFY, 0 ) )
+ {
+ if ( WinRegisterClass( pSalData->mhAB, (PSZ)SAL_OBJECT_CHILDCLASSNAME,
+ (PFNWP)SalSysObjChildWndProc, CS_HITTEST | CS_MOVENOTIFY, 32 ) )
+ pSalData->mbObjClassInit = TRUE;
+ }
+ }
+ }
+
+ if ( pSalData->mbObjClassInit )
+ {
+ Os2SalObject* pObject = new Os2SalObject;
+ HWND hWnd = WinCreateWindow( pParent->mhWndClient, SAL_OBJECT_CLASSNAME, "",
+ 0,
+ 0, 0, 0, 0,
+ pParent->mhWndClient, HWND_TOP,
+ 0, NULL, (void*)pObject );
+ HWND hWndChild = WinCreateWindow( hWnd, SAL_OBJECT_CHILDCLASSNAME, "",
+ WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE,
+ 0, 0, 0, 0,
+ hWnd, HWND_TOP,
+ 0, NULL, NULL );
+
+ if ( !hWndChild )
+ {
+ if ( hWnd )
+ WinDestroyWindow( hWnd );
+ delete pObject;
+ return NULL;
+ }
+
+ if ( hWnd )
+ {
+ debug_printf("ImplSalCreateObject hWndChild %x\n", hWndChild);
+ debug_printf("ImplSalCreateObject hWnd %x\n", hWnd);
+ pObject->mhWnd = hWnd;
+ pObject->mhWndChild = hWndChild;
+ pObject->maSysData.hWnd = hWndChild;
+ return pObject;
+ }
+ }
+
+ return NULL;
+}
+
+// =======================================================================
+
+long ImplSalObjCallbackDummy( void*, SalObject*, USHORT, const void* )
+{
+ return 0;
+}
+
+// =======================================================================
+
+Os2SalObject::Os2SalObject()
+{
+ SalData* pSalData = GetSalData();
+
+ mhLastClipWnd = HWND_TOP;
+
+ mhWnd = 0;
+ mhWndChild = 0;
+ mhLastFocusWnd = 0;
+ maSysData.nSize = sizeof( SystemEnvData );
+ mnHeight = 0;
+ mpInst = NULL;
+ mpProc = ImplSalObjCallbackDummy;
+
+ // Hook installieren, wenn es das erste Os2SalObject ist
+ if ( !pSalData->mpFirstObject )
+ {
+ WinSetHook( pSalData->mhAB, pSalData->mhMQ,
+ HK_INPUT, (PFN)SalSysMsgProc, (HMODULE)0 );
+ }
+
+ // Insert object in objectlist
+ mpNextObject = pSalData->mpFirstObject;
+ pSalData->mpFirstObject = this;
+}
+
+// -----------------------------------------------------------------------
+
+Os2SalObject::~Os2SalObject()
+{
+ SalData* pSalData = GetSalData();
+
+ // remove frame from framelist
+ if ( this == pSalData->mpFirstObject )
+ {
+ pSalData->mpFirstObject = mpNextObject;
+
+ // Wenn letztes Os2SalObject, dann Hook wieder entfernen
+ if ( !pSalData->mpFirstObject )
+ {
+ WinReleaseHook( pSalData->mhAB, pSalData->mhMQ,
+ HK_INPUT, (PFN)SalSysMsgProc, (HMODULE)0 );
+ }
+ }
+ else
+ {
+ Os2SalObject* pTempObject = pSalData->mpFirstObject;
+ while ( pTempObject->mpNextObject != this )
+ pTempObject = pTempObject->mpNextObject;
+
+ pTempObject->mpNextObject = mpNextObject;
+ }
+
+ // Cache-Daten zerstoeren
+ ImplDestroyAllClipWindows( mhLastClipWnd );
+
+ if ( mhWndChild )
+ WinDestroyWindow( mhWndChild );
+ if ( mhWnd )
+ WinDestroyWindow( mhWnd );
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalObject::ResetClipRegion()
+{
+ ImplDestroyAllClipWindows( mhLastClipWnd );
+ mhLastClipWnd = HWND_TOP;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT Os2SalObject::GetClipRegionType()
+{
+ return SAL_OBJECT_CLIP_EXCLUDERECTS;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalObject::BeginSetClipRegion( ULONG nRectCount )
+{
+ mhOldLastClipWnd = mhLastClipWnd;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalObject::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
+{
+ HWND hClipWnd = WinCreateWindow( mhWnd, SAL_OBJECT_CLIPCLASSNAME, "",
+ WS_VISIBLE,
+ nX, mnHeight-(nY+nHeight), nWidth, nHeight,
+ mhWnd, mhLastClipWnd,
+ 0, NULL, NULL );
+ debug_printf("Os2SalObject::UnionClipRegion hClipWnd %x\n", hClipWnd);
+ mhLastClipWnd = hClipWnd;
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalObject::EndSetClipRegion()
+{
+ ImplDestroyAllClipWindows( mhOldLastClipWnd );
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalObject::SetPosSize( long nX, long nY, long nWidth, long nHeight )
+{
+ ULONG nStyle = 0;
+ BOOL bVisible = WinIsWindowVisible( mhWnd );
+ if ( bVisible )
+ {
+ WinShowWindow( mhWnd, FALSE );
+ nStyle |= SWP_SHOW;
+ }
+ SWP aParentSWP;
+ WinQueryWindowPos( WinQueryWindow( mhWnd, QW_PARENT ), &aParentSWP );
+ WinSetWindowPos( mhWnd, 0, nX, aParentSWP.cy-(nY+nHeight), nWidth, nHeight,
+ SWP_MOVE | SWP_SIZE | nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalObject::Show( BOOL bVisible )
+{
+ WinShowWindow( mhWnd, bVisible );
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalObject::Enable( BOOL bEnable )
+{
+ // Im Gegensatz zu Windows disablen wir das Childfenster,
+ // da ansonsten unser Clippen nicht mehr funktioniert, da
+ // wir keine Events mehr bekommen. Dadurch kann sich evtl.
+ // das Fenster anders darstellen, was wir eigentlich nicht
+ // wollen. Aber da uns bisher kein Fall bekannt ist,
+ // ignorieren wir dies. Ansonsten muss ein Fenster dazwischen
+ // gezogen werden oder getestet werden, wie wir die
+ // Maustransparenz erreichen, wenn mhWnd
+ // disablte wird.
+ WinEnableWindow( mhWndChild, bEnable );
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalObject::GrabFocus()
+{
+ if ( mhLastFocusWnd &&
+ WinIsWindow( GetSalData()->mhAB, mhLastFocusWnd ) &&
+ ImplIsSysWindowOrChild( mhWndChild, mhLastFocusWnd ) )
+ WinSetFocus( HWND_DESKTOP, mhLastFocusWnd );
+ else
+ WinSetFocus( HWND_DESKTOP, mhWndChild );
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalObject::SetBackground()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void Os2SalObject::SetBackground( SalColor nSalColor )
+{
+}
+
+// -----------------------------------------------------------------------
+
+const SystemChildData* Os2SalObject::GetSystemData() const
+{
+ return &maSysData;
+}
+
+// -----------------------------------------------------------------------
+#if 0
+void Os2SalObject::SetCallback( void* pInst, SALOBJECTPROC pProc )
+{
+ mpInst = pInst;
+ if ( pProc )
+ mpProc = pProc;
+ else
+ mpProc = ImplSalObjCallbackDummy;
+}
+#endif
+
diff --git a/vcl/prj/build.lst b/vcl/prj/build.lst
new file mode 100644
index 000000000000..e6f636522acb
--- /dev/null
+++ b/vcl/prj/build.lst
@@ -0,0 +1,50 @@
+vc vcl : l10n apple_remote BOOST:boost rsc sot ucbhelper unotools ICU:icu GRAPHITE:graphite i18npool i18nutil unoil ridljar X11_EXTENSIONS:x11_extensions offuh basegfx basebmp tools l10ntools icc SO:print_header cpputools shell svl NULL
+vc vcl usr1 - all vc_mkout NULL
+vc vcl\inc nmake - all vc_inc NULL
+vc vcl\source\glyphs nmake - all vc_glyphs vc_inc NULL
+vc vcl\source\app nmake - all vc_app vc_inc NULL
+vc vcl\source\gdi nmake - all vc_gdi vc_inc NULL
+vc vcl\source\window nmake - all vc_win vc_inc NULL
+vc vcl\source\control nmake - all vc_ctrl vc_inc NULL
+vc vcl\source\src nmake - all vc_src vc_inc NULL
+vc vcl\source\helper nmake - all vc_hlp vc_inc NULL
+vc vcl\source\fontsubset nmake - all vc_fts vc_inc NULL
+vc vcl\source\salmain nmake - all vc_salmain vc_inc NULL
+vc vcl\os2\source\app nmake - p vc__appp vc_inc NULL
+vc vcl\os2\source\gdi nmake - p vc__gdip vc_inc NULL
+vc vcl\os2\source\window nmake - p vc__winp vc_inc NULL
+vc vcl\os2\source\src nmake - p vc__srcp vc_inc NULL
+vc vcl\source\components nmake - all vc_components vc_inc NULL
+vc vcl\win\source\app nmake - w vc__appw vc_inc NULL
+vc vcl\win\source\gdi nmake - w vc__gdiw vc_inc NULL
+vc vcl\win\source\window nmake - w vc__winw vc_inc NULL
+vc vcl\win\source\src nmake - w vc__srcw vc_inc NULL
+vc vcl\unx\source\plugadapt nmake - u vc__plug vc_inc NULL
+vc vcl\unx\source\desktopdetect nmake - u vc__desk vc_inc NULL
+vc vcl\unx\source\app nmake - u vc__appu vc_inc NULL
+vc vcl\unx\source\dtrans nmake - u vc__dtru vc_inc NULL
+vc vcl\unx\source\fontmanager nmake - u vc__ftmu vc_inc NULL
+vc vcl\unx\source\gdi nmake - u vc__gdiu vc_inc NULL
+vc vcl\unx\source\printer nmake - u vc__prnu vc_inc NULL
+vc vcl\unx\source\printergfx nmake - u vc__prgu vc_inc NULL
+vc vcl\unx\source\window nmake - u vc__winu vc_inc NULL
+vc vcl\unx\gtk\a11y nmake - u vc__gtky vc_inc NULL
+vc vcl\unx\gtk\app nmake - u vc__gtka vc_inc NULL
+vc vcl\unx\gtk\window nmake - u vc__gtkw vc_inc NULL
+vc vcl\unx\gtk\gdi nmake - u vc__gtkg vc_inc NULL
+vc vcl\unx\headless nmake - u vc__hl vc_inc NULL
+vc vcl\unx\kde nmake - u vc__kde vc_inc NULL
+vc vcl\unx\kde4 nmake - u vc__kde4 vc_inc NULL
+vc vcl\aqua\source\a11y nmake - u vc__aquy vc_inc NULL
+vc vcl\aqua\source\app nmake - u vc__appa vc_inc NULL
+vc vcl\aqua\source\dtrans nmake - u vc__dtra vc_inc NULL
+vc vcl\aqua\source\gdi nmake - u vc__gdia vc_inc NULL
+vc vcl\aqua\source\res nmake - u vc__resa NULL
+vc vcl\aqua\source\window nmake - u vc__wina vc_inc NULL
+vc vcl\mac\source\app nmake - m vc__appm vc_inc NULL
+vc vcl\mac\source\gdi nmake - m vc__gdim vc_inc NULL
+vc vcl\mac\source\window nmake - m vc__winm vc_inc NULL
+vc vcl\mac\source\src nmake - m vc__srcm vc_inc NULL
+vc vcl\util nmake - all vc_util vc__plug.u vc__desk.u vc__aquy.u vc__appa.u vc__dtra.u vc__appm.m vc__appu.u vc__dtru.u vc__appw.w vc__appp.p vc__gdia.u vc__gdim.m vc__gdiu.u vc__gdiw.w vc__gdip.p vc__srcm.m vc__srcw.w vc__srcp.p vc__wina.u vc__winm.m vc__winu.u vc__winw.w vc__winp.p vc__gtka.u vc__gtky.u vc__gtkw.u vc__gtkg.u vc__kde.u vc__kde4.u vc__hl.u vc__ftmu.u vc__prgu.u vc__prnu.u vc_app vc_ctrl vc_gdi vc_hlp vc_src vc_win vc_glyphs vc_fts vc_components NULL
+vc vcl\util\linksvp nmake - u vc_lsvp vc_util NULL
+vc vcl\workben nmake - all vc_wrkb vc_util vc_salmain NULL
diff --git a/vcl/prj/d.lst b/vcl/prj/d.lst
new file mode 100644
index 000000000000..8345b155ce58
--- /dev/null
+++ b/vcl/prj/d.lst
@@ -0,0 +1,156 @@
+mkdir: %COMMON_DEST%\bin%_EXT%\hid
+mkdir: %_DEST%\inc%_EXT%\vcl
+
+..\%COMMON_OUTDIR%\bin\*.zip %COMMON_DEST%\bin%_EXT%\*.zip
+..\%COMMON_OUTDIR%\misc\*.hid %COMMON_DEST%\bin%_EXT%\hid\*.hid
+..\%__SRC%\bin\vcl*.res %_DEST%\bin%_EXT%\vcl*.res
+..\%__SRC%\bin\vcl?????.dll %_DEST%\bin%_EXT%\vcl?????.dll
+..\%__SRC%\bin\vcl?????.sym %_DEST%\bin%_EXT%\vcl?????.sym
+..\%__SRC%\lib\lib*.so %_DEST%\lib%_EXT%\lib*.so
+..\%__SRC%\lib\*.dylib %_DEST%\lib%_EXT%\*.dylib
+..\%__SRC%\lib\ivcl.lib %_DEST%\lib%_EXT%\ivcl.lib
+..\%__SRC%\misc\vcl?????.map %_DEST%\bin%_EXT%\vcl?????.map
+..\%__SRC%\obj\salmain.obj %_DEST%\lib%_EXT%\salmain.obj
+..\%__SRC%\obj\salmain.o %_DEST%\lib%_EXT%\salmain.o
+
+..\inc\vcl\accel.hxx %_DEST%\inc%_EXT%\vcl\accel.hxx
+..\inc\vcl\alpha.hxx %_DEST%\inc%_EXT%\vcl\alpha.hxx
+..\inc\vcl\animate.hxx %_DEST%\inc%_EXT%\vcl\animate.hxx
+..\inc\vcl\apptypes.hxx %_DEST%\inc%_EXT%\vcl\apptypes.hxx
+..\inc\vcl\bitmap.hxx %_DEST%\inc%_EXT%\vcl\bitmap.hxx
+..\inc\vcl\bitmapex.hxx %_DEST%\inc%_EXT%\vcl\bitmapex.hxx
+..\inc\vcl\bmpacc.hxx %_DEST%\inc%_EXT%\vcl\bmpacc.hxx
+..\inc\vcl\btndlg.hxx %_DEST%\inc%_EXT%\vcl\btndlg.hxx
+..\inc\vcl\button.hxx %_DEST%\inc%_EXT%\vcl\button.hxx
+..\inc\vcl\button.hxx %_DEST%\inc%_EXT%\vcl\imagebtn.hxx
+..\inc\vcl\cmdevt.h %_DEST%\inc%_EXT%\vcl\cmdevt.h
+..\inc\vcl\cmdevt.hxx %_DEST%\inc%_EXT%\vcl\cmdevt.hxx
+..\inc\vcl\combobox.h %_DEST%\inc%_EXT%\vcl\combobox.h
+..\inc\vcl\combobox.hxx %_DEST%\inc%_EXT%\vcl\combobox.hxx
+..\inc\vcl\ctrl.hxx %_DEST%\inc%_EXT%\vcl\ctrl.hxx
+..\inc\vcl\cursor.hxx %_DEST%\inc%_EXT%\vcl\cursor.hxx
+..\inc\vcl\cvtgrf.hxx %_DEST%\inc%_EXT%\vcl\cvtgrf.hxx
+..\inc\vcl\cvtsvm.hxx %_DEST%\inc%_EXT%\vcl\cvtsvm.hxx
+..\inc\vcl\decoview.hxx %_DEST%\inc%_EXT%\vcl\decoview.hxx
+..\inc\vcl\dialog.hxx %_DEST%\inc%_EXT%\vcl\dialog.hxx
+..\inc\vcl\dockingarea.hxx %_DEST%\inc%_EXT%\vcl\dockingarea.hxx
+..\inc\vcl\dockwin.hxx %_DEST%\inc%_EXT%\vcl\dockwin.hxx
+..\inc\vcl\dllapi.h %_DEST%\inc%_EXT%\vcl\dllapi.h
+..\inc\vcl\edit.hxx %_DEST%\inc%_EXT%\vcl\edit.hxx
+..\inc\vcl\event.hxx %_DEST%\inc%_EXT%\vcl\event.hxx
+..\inc\vcl\field.hxx %_DEST%\inc%_EXT%\vcl\field.hxx
+..\inc\vcl\fixbrd.hxx %_DEST%\inc%_EXT%\vcl\fixbrd.hxx
+..\inc\vcl\fixed.hxx %_DEST%\inc%_EXT%\vcl\fixed.hxx
+..\inc\vcl\fldunit.hxx %_DEST%\inc%_EXT%\vcl\fldunit.hxx
+..\inc\vcl\floatwin.hxx %_DEST%\inc%_EXT%\vcl\floatwin.hxx
+..\inc\vcl\fntstyle.hxx %_DEST%\inc%_EXT%\vcl\fntstyle.hxx
+..\inc\vcl\font.hxx %_DEST%\inc%_EXT%\vcl\font.hxx
+..\inc\vcl\fontcvt.hxx %_DEST%\inc%_EXT%\vcl\fontcvt.hxx
+..\inc\vcl\gdimtf.hxx %_DEST%\inc%_EXT%\vcl\gdimtf.hxx
+..\inc\vcl\gfxlink.hxx %_DEST%\inc%_EXT%\vcl\gfxlink.hxx
+..\inc\vcl\gradient.hxx %_DEST%\inc%_EXT%\vcl\gradient.hxx
+..\inc\vcl\graph.h %_DEST%\inc%_EXT%\vcl\graph.h
+..\inc\vcl\graph.hxx %_DEST%\inc%_EXT%\vcl\graph.hxx
+..\inc\vcl\group.hxx %_DEST%\inc%_EXT%\vcl\group.hxx
+..\inc\vcl\hatch.hxx %_DEST%\inc%_EXT%\vcl\hatch.hxx
+..\inc\vcl\help.hxx %_DEST%\inc%_EXT%\vcl\help.hxx
+..\inc\vcl\image.hxx %_DEST%\inc%_EXT%\vcl\image.hxx
+..\inc\vcl\imagerepository.hxx %_DEST%\inc%_EXT%\vcl\imagerepository.hxx
+..\inc\vcl\imgcons.hxx %_DEST%\inc%_EXT%\vcl\imgcons.hxx
+..\inc\vcl\imgctrl.hxx %_DEST%\inc%_EXT%\vcl\imgctrl.hxx
+..\inc\vcl\impdel.hxx %_DEST%\inc%_EXT%\vcl\impdel.hxx
+..\inc\vcl\inputctx.hxx %_DEST%\inc%_EXT%\vcl\inputctx.hxx
+..\inc\vcl\javachild.hxx %_DEST%\inc%_EXT%\vcl\javachild.hxx
+..\inc\vcl\jobset.hxx %_DEST%\inc%_EXT%\vcl\jobset.hxx
+..\unx\inc\kde_headers.h %_DEST%\inc%_EXT%\vcl\kde_headers.h
+..\inc\vcl\keycod.hxx %_DEST%\inc%_EXT%\vcl\keycod.hxx
+..\inc\vcl\keycodes.hxx %_DEST%\inc%_EXT%\vcl\keycodes.hxx
+..\inc\vcl\lineinfo.hxx %_DEST%\inc%_EXT%\vcl\lineinfo.hxx
+..\inc\vcl\longcurr.hxx %_DEST%\inc%_EXT%\vcl\longcurr.hxx
+..\inc\vcl\lstbox.h %_DEST%\inc%_EXT%\vcl\lstbox.h
+..\inc\vcl\lstbox.hxx %_DEST%\inc%_EXT%\vcl\lstbox.hxx
+..\inc\vcl\mapmod.hxx %_DEST%\inc%_EXT%\vcl\mapmod.hxx
+..\inc\vcl\mapunit.hxx %_DEST%\inc%_EXT%\vcl\mapunit.hxx
+..\inc\vcl\menu.hxx %_DEST%\inc%_EXT%\vcl\menu.hxx
+..\inc\vcl\menubtn.hxx %_DEST%\inc%_EXT%\vcl\menubtn.hxx
+..\inc\vcl\metaact.hxx %_DEST%\inc%_EXT%\vcl\metaact.hxx
+..\inc\vcl\graphictools.hxx %_DEST%\inc%_EXT%\vcl\graphictools.hxx
+..\inc\vcl\metric.hxx %_DEST%\inc%_EXT%\vcl\metric.hxx
+..\inc\vcl\mnemonic.hxx %_DEST%\inc%_EXT%\vcl\mnemonic.hxx
+..\inc\vcl\mnemonicengine.hxx %_DEST%\inc%_EXT%\vcl\mnemonicengine.hxx
+..\inc\vcl\morebtn.hxx %_DEST%\inc%_EXT%\vcl\morebtn.hxx
+..\inc\vcl\msgbox.hxx %_DEST%\inc%_EXT%\vcl\msgbox.hxx
+..\inc\vcl\octree.hxx %_DEST%\inc%_EXT%\vcl\octree.hxx
+..\inc\vcl\oldprintadaptor.hxx %_DEST%\inc%_EXT%\vcl\oldprintadaptor.hxx
+..\inc\vcl\outdev.hxx %_DEST%\inc%_EXT%\vcl\outdev.hxx
+..\inc\vcl\pointr.hxx %_DEST%\inc%_EXT%\vcl\pointr.hxx
+..\inc\vcl\popupmenuwindow.hxx %_DEST%\inc%_EXT%\vcl\popupmenuwindow.hxx
+..\inc\vcl\print.hxx %_DEST%\inc%_EXT%\vcl\print.hxx
+..\inc\vcl\prntypes.hxx %_DEST%\inc%_EXT%\vcl\prntypes.hxx
+..\inc\vcl\ptrstyle.hxx %_DEST%\inc%_EXT%\vcl\ptrstyle.hxx
+..\inc\vcl\regband.hxx %_DEST%\inc%_EXT%\vcl\regband.hxx
+..\inc\vcl\region.hxx %_DEST%\inc%_EXT%\vcl\region.hxx
+..\inc\vcl\salbtype.hxx %_DEST%\inc%_EXT%\vcl\salbtype.hxx
+..\inc\vcl\salctype.hxx %_DEST%\inc%_EXT%\vcl\salctype.hxx
+..\inc\vcl\salgtype.hxx %_DEST%\inc%_EXT%\vcl\salgtype.hxx
+..\inc\vcl\salstype.hxx %_DEST%\inc%_EXT%\vcl\salstype.hxx
+..\inc\vcl\salnativewidgets.hxx %_DEST%\inc%_EXT%\vcl\salnativewidgets.hxx
+..\inc\vcl\scrbar.hxx %_DEST%\inc%_EXT%\vcl\scrbar.hxx
+..\inc\vcl\seleng.hxx %_DEST%\inc%_EXT%\vcl\seleng.hxx
+..\inc\vcl\settings.hxx %_DEST%\inc%_EXT%\vcl\settings.hxx
+..\inc\vcl\slider.hxx %_DEST%\inc%_EXT%\vcl\slider.hxx
+..\inc\vcl\sndstyle.hxx %_DEST%\inc%_EXT%\vcl\sndstyle.hxx
+..\inc\vcl\sound.hxx %_DEST%\inc%_EXT%\vcl\sound.hxx
+..\inc\vcl\spin.h %_DEST%\inc%_EXT%\vcl\spin.h
+..\inc\vcl\spin.hxx %_DEST%\inc%_EXT%\vcl\spin.hxx
+..\inc\vcl\spinfld.hxx %_DEST%\inc%_EXT%\vcl\spinfld.hxx
+..\inc\vcl\split.hxx %_DEST%\inc%_EXT%\vcl\split.hxx
+..\inc\vcl\splitwin.hxx %_DEST%\inc%_EXT%\vcl\splitwin.hxx
+..\inc\vcl\status.hxx %_DEST%\inc%_EXT%\vcl\status.hxx
+..\inc\vcl\stdtext.hxx %_DEST%\inc%_EXT%\vcl\stdtext.hxx
+..\inc\vcl\sv.h %_DEST%\inc%_EXT%\vcl\sv.h
+..\inc\vcl\svapp.hxx %_DEST%\inc%_EXT%\vcl\svapp.hxx
+..\inc\vcl\symbol.hxx %_DEST%\inc%_EXT%\vcl\symbol.hxx
+..\inc\vcl\syschild.hxx %_DEST%\inc%_EXT%\vcl\syschild.hxx
+..\inc\vcl\sysdata.hxx %_DEST%\inc%_EXT%\vcl\sysdata.hxx
+..\inc\vcl\syswin.hxx %_DEST%\inc%_EXT%\vcl\syswin.hxx
+..\inc\vcl\tabctrl.hxx %_DEST%\inc%_EXT%\vcl\tabctrl.hxx
+..\inc\vcl\tabdlg.hxx %_DEST%\inc%_EXT%\vcl\tabdlg.hxx
+..\inc\vcl\tabpage.hxx %_DEST%\inc%_EXT%\vcl\tabpage.hxx
+..\inc\vcl\taskpanelist.hxx %_DEST%\inc%_EXT%\vcl\taskpanelist.hxx
+..\inc\vcl\timer.hxx %_DEST%\inc%_EXT%\vcl\timer.hxx
+..\inc\vcl\toolbox.hxx %_DEST%\inc%_EXT%\vcl\toolbox.hxx
+..\inc\vcl\unowrap.hxx %_DEST%\inc%_EXT%\vcl\unowrap.hxx
+..\inc\vcl\canvastools.hxx %_DEST%\inc%_EXT%\vcl\canvastools.hxx
+..\inc\vcl\vclenum.hxx %_DEST%\inc%_EXT%\vcl\vclenum.hxx
+..\inc\vcl\vclevent.hxx %_DEST%\inc%_EXT%\vcl\vclevent.hxx
+..\inc\vcl\virdev.hxx %_DEST%\inc%_EXT%\vcl\virdev.hxx
+..\inc\vcl\waitobj.hxx %_DEST%\inc%_EXT%\vcl\waitobj.hxx
+..\inc\vcl\wall.hxx %_DEST%\inc%_EXT%\vcl\wall.hxx
+..\inc\vcl\window.hxx %_DEST%\inc%_EXT%\vcl\window.hxx
+..\inc\vcl\wintypes.hxx %_DEST%\inc%_EXT%\vcl\wintypes.hxx
+..\inc\vcl\wrkwin.hxx %_DEST%\inc%_EXT%\vcl\wrkwin.hxx
+..\inc\vcl\threadex.hxx %_DEST%\inc%_EXT%\vcl\threadex.hxx
+..\inc\vcl\evntpost.hxx %_DEST%\inc%_EXT%\vcl\evntpost.hxx
+..\inc\vcl\unohelp.hxx %_DEST%\inc%_EXT%\vcl\unohelp.hxx
+..\inc\vcl\unohelp2.hxx %_DEST%\inc%_EXT%\vcl\unohelp2.hxx
+..\inc\vcl\i18nhelp.hxx %_DEST%\inc%_EXT%\vcl\i18nhelp.hxx
+..\inc\vcl\dndhelp.hxx %_DEST%\inc%_EXT%\vcl\dndhelp.hxx
+..\inc\vcl\pdfwriter.hxx %_DEST%\inc%_EXT%\vcl\pdfwriter.hxx
+..\inc\vcl\controllayout.hxx %_DEST%\inc%_EXT%\vcl\controllayout.hxx
+..\inc\vcl\introwin.hxx %_DEST%\inc%_EXT%\vcl\introwin.hxx
+..\inc\vcl\abstdlg.hxx %_DEST%\inc%_EXT%\vcl\abstdlg.hxx
+..\inc\vcl\extoutdevdata.hxx %_DEST%\inc%_EXT%\vcl\extoutdevdata.hxx
+..\inc\vcl\pdfextoutdevdata.hxx %_DEST%\inc%_EXT%\vcl\pdfextoutdevdata.hxx
+..\inc\vcl\pngread.hxx %_DEST%\inc%_EXT%\vcl\pngread.hxx
+..\inc\vcl\pngwrite.hxx %_DEST%\inc%_EXT%\vcl\pngwrite.hxx
+..\inc\vcl\smartid.hxx %_DEST%\inc%_EXT%\vcl\smartid.hxx
+..\inc\vcl\configsettings.hxx %_DEST%\inc%_EXT%\vcl\configsettings.hxx
+..\inc\vcl\ImageListProvider.hxx %_DEST%\inc%_EXT%\vcl\ImageListProvider.hxx
+..\inc\vcl\fontmanager.hxx %_DEST%\inc%_EXT%\vcl\fontmanager.hxx
+..\inc\vcl\printerinfomanager.hxx %_DEST%\inc%_EXT%\vcl\printerinfomanager.hxx
+..\inc\vcl\jobdata.hxx %_DEST%\inc%_EXT%\vcl\jobdata.hxx
+..\inc\vcl\ppdparser.hxx %_DEST%\inc%_EXT%\vcl\ppdparser.hxx
+..\inc\vcl\helper.hxx %_DEST%\inc%_EXT%\vcl\helper.hxx
+..\inc\vcl\strhelper.hxx %_DEST%\inc%_EXT%\vcl\strhelper.hxx
+..\inc\vcl\lazydelete.hxx %_DEST%\inc%_EXT%\vcl\lazydelete.hxx \ No newline at end of file
diff --git a/vcl/qa/complex/memCheck/CheckMemoryUsage.java b/vcl/qa/complex/memCheck/CheckMemoryUsage.java
new file mode 100644
index 000000000000..9f8272240403
--- /dev/null
+++ b/vcl/qa/complex/memCheck/CheckMemoryUsage.java
@@ -0,0 +1,340 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+package complex.memCheck;
+
+import com.sun.star.beans.PropertyValue;
+import com.sun.star.frame.XStorable;
+import com.sun.star.lang.XComponent;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.util.XCloseable;
+import complexlib.ComplexTestCase;
+import helper.ProcessHandler;
+import java.io.File;
+import java.io.FilePermission;
+import java.io.FileWriter;
+import java.io.FilenameFilter;
+import java.io.PrintWriter;
+import java.util.Enumeration;
+import java.util.StringTokenizer;
+import java.util.Vector;
+import util.DesktopTools;
+import util.WriterTools;
+import util.utils;
+
+/**
+ * Documents are opened and exported with StarOffice. The memory usage of
+ * StarOffice is monitored and if the usage exceeds the allowed kilobytes,
+ * the test is failed. Used for monitoring the StarOffice process is the
+ * command line tool 'pmap', available on Solaris or Linux. This test will not
+ * run on Windows.<br>Test procedure: every given document type is searched in
+ * the source directory
+ * Needed paramters:
+ * <ul>
+ * <li>"TestDocumentPath" - the path where test documents are located.</li>
+ * <li>"AllowMemoryIncrease" (optional) - the allowed memory increase measured in kByte per exported document. The default is 10 kByte.</li>
+ * <li>"ExportDocCount" (optional) - the amount of exports for each document that is loaded. Is defaulted to 25.
+ * <li>"FileExportFilter" (optional) - a relation between loaded document type and used export filter. Is defaulted to
+ * writer, calc and impress. This parameter can be set with a number to give more than one relation. Example:<br>
+ * "FileExportFilter1=sxw,writer_pdf_Export"<br>
+ * "FileExportFilter2=sxc,calc_pdf_Export"<br>
+ * "FileExportFilter3=sxi,impress_pdf_Export"<br></li>
+ * All parameters are used for iteration over the test document path.
+ * </ul>
+ */
+public class CheckMemoryUsage extends ComplexTestCase {
+ private final String sWriterDoc = "sxw,writer_pdf_Export";
+ private final String sCalcDoc = "sxc,calc_pdf_Export";
+ private final String sImpressDoc = "sxi,impress_pdf_Export";
+ private String sProcessId = "ps -ef | grep $USER | grep soffice | grep -v grep";
+ private String sMemoryMonitor = "pmap <processID> | grep total";
+ private String sChmod = "chmod 777 ";
+ private String sProcessIdCommand = null;
+ private String sOfficeMemoryCommand = null;
+ private String sTempDir = null;
+ private String sFS = null;
+ private String sMemoryMap1 = null;
+ private String sMemoryMap2 = null;
+ private String bash = "#!/bin/bash";
+ private String sDocumentPath = "";
+ private String[][] sDocTypeExportFilter;
+ private String[][] sDocuments;
+ private int iAllowMemoryIncrease = 10;
+ private int iExportDocCount = 25;
+
+ /**
+ * Get all test methods
+ * @return The test methods.
+ */
+ public String[] getTestMethodNames() {
+ return new String[] {"loadAndSaveDocuments"};
+ }
+
+ /**
+ * Collect all documnets to load and all filters used for export.
+ */
+ public void before() {
+ // test does definitely not run on Windows.
+ if (param.get("OperatingSystem").equals("wntmsci")) {
+ log.println("Test can only reasonably be executed with a tool that "
+ + "displays the memory usage of StarOffice.");
+ failed("Test does not run on Windows, only on Solaris or Linux.");
+ }
+
+ // how many times is every document exported.
+ int count = param.getInt("ExportDocCount");
+ if (count != 0)
+ iExportDocCount = count;
+
+ // get the temp dir for creating the command scripts.
+ sTempDir = System.getProperty("java.io.tmpdir");
+ sProcessIdCommand = sTempDir + "getPS";
+ sOfficeMemoryCommand = sTempDir + "getPmap";
+
+ // get the file extension, export filter connection
+ Enumeration keys = param.keys();
+ Vector v = new Vector();
+ while(keys.hasMoreElements()) {
+ String key = (String)keys.nextElement();
+ if (key.startsWith("FileExportFilter")) {
+ v.add(param.get(key));
+ }
+ }
+ // if no param given, set defaults.
+ if (v.size() == 0){
+ v.add(sWriterDoc);
+ v.add(sCalcDoc);
+ v.add(sImpressDoc);
+ }
+ // store a file extension
+ sDocTypeExportFilter = new String[v.size()][2];
+ for (int i=0; i<v.size(); i++) {
+ // 2do: error routine for wrong given params
+ StringTokenizer t = new StringTokenizer((String)v.get(i), ",");
+ sDocTypeExportFilter[i][0] = t.nextToken();
+ sDocTypeExportFilter[i][1] = t.nextToken();
+ }
+
+ // get files to load and export
+ sDocumentPath = (String)param.get("TestDocumentPath");
+ File f = new File(sDocumentPath);
+ sDocumentPath = f.getAbsolutePath();
+ String sFS = System.getProperty("file.separator");
+ sDocuments = new String[sDocTypeExportFilter.length][];
+ for (int j=0; j<sDocTypeExportFilter.length; j++) {
+ FileFilter filter = new FileFilter(sDocTypeExportFilter[j][0]);
+ String[] doc = f.list(filter);
+ sDocuments[j] = new String[doc.length];
+ for (int i=0; i<doc.length; i++) {
+ if (sDocumentPath.endsWith(sFS))
+ sDocuments[j][i] = sDocumentPath + doc[i];
+ else
+ sDocuments[j][i] = sDocumentPath + sFS + doc[i];
+ sDocuments[j][i] = utils.getFullURL(sDocuments[j][i]);
+ }
+ }
+ }
+
+ /**
+ * delete all created files on disk
+ */
+ public void after() {
+ // delete the constructed files.
+ for (int i=0; i<iExportDocCount; i++) {
+ File f = new File(sTempDir + "DocExport" + i + ".pdf");
+ f.delete();
+ }
+ File f = new File(sProcessIdCommand);
+ f.delete();
+ f = new File(sOfficeMemoryCommand);
+ f.delete();
+ }
+
+ /**
+ * Thet etst function: load documents and save them using the given filters
+ * for each given document type.
+ */
+ public void loadAndSaveDocuments() {
+ int storageBefore = getOfficeMemoryUsage();
+
+ XMultiServiceFactory xMSF = (XMultiServiceFactory)param.getMSF();
+
+ // iterate over all document types
+ for (int k=0; k<sDocTypeExportFilter.length; k++) {
+ // iterate over all documents of this type
+ for (int i=0; i<sDocuments[k].length; i++) {
+ System.out.println("Document: "+ sDocuments[k][i]);
+ XComponent xComponent = DesktopTools.loadDoc(xMSF, sDocuments[k][i], null);
+ XStorable xStorable = (XStorable)UnoRuntime.queryInterface(XStorable.class, xComponent);
+ if (xStorable != null) {
+ // export each document iExportDocCount times
+ for (int j=0; j<iExportDocCount; j++) {
+ String url = utils.getFullURL(sTempDir + "DocExport" + j + ".pdf");
+ try {
+ PropertyValue[] props = new PropertyValue[1];
+ props[0] = new PropertyValue();
+ props[0].Name = "FilterName";
+ // use export filter for this doc type
+ props[0].Value = sDocTypeExportFilter[k][1];
+ xStorable.storeToURL(url, props);
+ }
+ catch(com.sun.star.io.IOException e) {
+ failed("Could not store to '" + url + "'", true);
+ }
+ }
+ // close the doc
+ XCloseable xCloseable = (XCloseable)UnoRuntime.queryInterface(XCloseable.class, xStorable);
+ try {
+ xCloseable.close(true);
+ }
+ catch(com.sun.star.util.CloseVetoException e) {
+ e.printStackTrace((java.io.PrintWriter)log);
+ failed("Cannot close document: test is futile, Office will surely use more space.");
+ }
+ }
+ else {
+ log.println("Cannot query for XStorable interface on document '" + sDocuments[i] + "'");
+ log.println(" -> Skipping storage.");
+ }
+ }
+ }
+ // short wait for the office to 'calm down' and free some memory
+ shortWait(5000);
+ // wait util memory is not freed anymore.
+ int storageAfter = getOfficeMemoryUsage();
+ int mem = 0;
+ int count = 0;
+ while (storageAfter != mem && count < 10) {
+ count++;
+ mem = storageAfter;
+ storageAfter = getOfficeMemoryUsage();
+ shortWait(1000);
+ }
+ assure("The Office consumes now " + (storageAfter - storageBefore)
+ + "K more memory than at the start of the test; allowed were "
+ + iAllowMemoryIncrease * iExportDocCount + "K.",
+ storageAfter - storageBefore < iAllowMemoryIncrease * iExportDocCount);
+
+ }
+
+ /**
+ * Get the process ID from the Office
+ * @return the Id as String
+ */
+ private String getOfficeProcessID() {
+ writeExecutableFile(sProcessIdCommand, sProcessId);
+ ProcessHandler processID = new ProcessHandler(sProcessIdCommand);
+ processID.executeSynchronously();
+ String text = processID.getOutputText();
+ if (text == null || text.equals("") || text.indexOf(' ') == -1)
+ failed("Could not determine Office process ID. Check " + sProcessIdCommand);
+ StringTokenizer aToken = new StringTokenizer(text);
+ // this is not nice, but ps gives the same output on every machine
+ aToken.nextToken();
+ String id = aToken.nextToken();
+ return id;
+ }
+
+ /**
+ * Get the memory usage of the Office in KByte.
+ * @return The memory used by the Office.
+ */
+ private int getOfficeMemoryUsage() {
+ String command = sMemoryMonitor.replaceAll("<processID>", getOfficeProcessID());
+ writeExecutableFile(sOfficeMemoryCommand, command);
+ ProcessHandler processID = new ProcessHandler(sOfficeMemoryCommand);
+ processID.executeSynchronously();
+ String text = processID.getOutputText();
+ if (text == null || text.equals("") || text.indexOf(' ') == -1) {
+ failed("Could not determine Office memory usage. Check " + sOfficeMemoryCommand);
+ }
+ StringTokenizer aToken = new StringTokenizer(text);
+ // this works, because the output of pmap is quite standardized.
+ aToken.nextToken();
+ String mem = aToken.nextToken();
+ mem = mem.substring(0, mem.indexOf('K'));
+ Integer memory = new Integer(mem);
+ return memory.intValue();
+ }
+
+ /**
+ * Write a script file and set its rights to rwxrwxrwx.
+ * @param fileName The name of the created file
+ * @param line The commandline that has to be written inside of the file.
+ */
+ private void writeExecutableFile(String fileName, String line) {
+ try {
+ PrintWriter fWriter = new PrintWriter(new FileWriter(fileName));
+ fWriter.println(bash);
+ fWriter.println(line);
+ fWriter.close();
+ // change rights to rwxrwxrwx
+ ProcessHandler processID = new ProcessHandler(sChmod + fileName);
+ processID.executeSynchronously();
+ }
+ catch(java.io.IOException e) {
+ }
+ }
+
+ /**
+ * Let this thread sleep for some time
+ * @param milliSeconds time to wait in milliseconds.
+ */
+ private void shortWait(int milliSeconds) {
+ try {
+ Thread.sleep(milliSeconds);
+ }
+ catch(java.lang.InterruptedException e) { // ignore
+ }
+ }
+
+ /**
+ * Own file filter, will just return ok for all files that end with a given
+ * suffix
+ */
+ private class FileFilter implements FilenameFilter {
+ private String suffix = null;
+ /**
+ * C'tor.
+ * @param suffix The suffix each filename should end with.
+ */
+ public FileFilter(String suffix) {
+ this.suffix = suffix;
+ }
+ /**
+ * Returns true, if the name of the file has the suffix given to the
+ * c'tor.
+ * @param name The filename that is tested.
+ * @param file Not used.
+ * @return True, if name ends with suffix.
+ */
+ public boolean accept(File file, String name) {
+ return name.endsWith(suffix);
+ }
+ };
+
+}
diff --git a/vcl/qa/complex/memCheck/CheckMemoryUsage.props b/vcl/qa/complex/memCheck/CheckMemoryUsage.props
new file mode 100644
index 000000000000..5d1333186950
--- /dev/null
+++ b/vcl/qa/complex/memCheck/CheckMemoryUsage.props
@@ -0,0 +1,14 @@
+# the path to the test documents
+TestDocumentPath=../../testdocuments
+
+# the allowed memory increase per exported document: if the memory increase is higher than this number, the test will fail
+AllowMemoryIncrease=20
+
+# the amount of exported documents: each loaded document will be written 'ExportDocCount' times
+ExportDocCount=25
+
+# the import and export filters, separated by comma; further relations can be added with increasing numbers, like
+#'FileExportFilter4=sxd,draw_pdf_Export'
+FileExportFilter1=sxw,writer_pdf_Export
+FileExportFilter2=sxc,calc_pdf_Export
+FileExportFilter3=sxi,impress_pdf_Export
diff --git a/vcl/qa/complex/memCheck/makefile.mk b/vcl/qa/complex/memCheck/makefile.mk
new file mode 100755
index 000000000000..d1d4b5c08c98
--- /dev/null
+++ b/vcl/qa/complex/memCheck/makefile.mk
@@ -0,0 +1,89 @@
+#*************************************************************************
+#
+# 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 = ..$/..$/..
+TARGET = MemoryCheck
+PRJNAME = $(TARGET)
+PACKAGE = complex$/memCheck
+
+# --- Settings -----------------------------------------------------
+.INCLUDE: settings.mk
+
+
+#----- compile .java files -----------------------------------------
+
+JARFILES = ridl.jar unoil.jar jurt.jar juh.jar java_uno.jar OOoRunner.jar
+JAVAFILES = CheckMemoryUsage.java
+
+#----- make a jar from compiled files ------------------------------
+
+MAXLINELENGTH = 100000
+
+JARCLASSDIRS = $(PACKAGE)
+JARTARGET = $(TARGET).jar
+JARCOMPRESS = TRUE
+
+# --- Parameters for the test --------------------------------------
+
+# start an office if the parameter is set for the makefile
+.IF "$(OFFICE)" == ""
+CT_APPEXECCOMMAND =
+.ELSE
+CT_APPEXECCOMMAND = -AppExecutionCommand \
+ "$(OFFICE)$/soffice -accept=socket,host=localhost,port=8100;urp;"
+.ENDIF
+
+# test base is java complex
+CT_TESTBASE = -TestBase java_complex
+
+# replace $/ with . in package name
+CT_PACKAGE = -o $(PACKAGE:s\$/\.\)
+
+# start the runner application
+CT_APP = org.openoffice.Runner
+
+# --- Targets ------------------------------------------------------
+
+.IF "$(depend)" == ""
+$(CLASSDIR)$/$(PACKAGE)$/CheckMemoryUsage.props : ALLTAR
+.ELSE
+$(CLASSDIR)$/$(PACKAGE)$/CheckMemoryUsage.props : ALLTAR
+.ENDIF
+
+.INCLUDE : target.mk
+
+
+
+$(CLASSDIR)$/$(PACKAGE)$/CheckMemoryUsage.props : CheckMemoryUsage.props
+ cp $(@:f) $@
+ jar uf $(CLASSDIR)$/$(JARTARGET) -C $(CLASSDIR) $(PACKAGE)$/$(@:f)
+
+
+RUN: run
+
+run:
+ java -cp $(CLASSPATH) $(CT_APP) $(CT_TESTBASE) $(CT_APPEXECCOMMAND) $(CT_PACKAGE).CheckMemoryUsage
diff --git a/vcl/qa/complex/persistent_window_states/DocumentHandle.java b/vcl/qa/complex/persistent_window_states/DocumentHandle.java
new file mode 100644
index 000000000000..0b32eaaeff51
--- /dev/null
+++ b/vcl/qa/complex/persistent_window_states/DocumentHandle.java
@@ -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.
+ *
+ ************************************************************************/
+package complex.persistent_window_states;
+
+
+import com.sun.star.awt.Rectangle;
+import com.sun.star.awt.PosSize;
+import com.sun.star.frame.XComponentLoader;
+import com.sun.star.lang.XComponent;
+import com.sun.star.awt.XWindow;
+import com.sun.star.beans.PropertyValue;
+import com.sun.star.beans.PropertyState;
+import com.sun.star.frame.XController;
+import com.sun.star.frame.FrameSearchFlag;
+import com.sun.star.text.XTextDocument;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.frame.XFrame;
+import com.sun.star.frame.FrameSearchFlag;
+import com.sun.star.frame.XFramesSupplier;
+import helper.WindowListener;
+
+/**
+ * Load and resize a document.
+ *
+ */
+public class DocumentHandle {
+ // the component loader to load a document
+ XComponentLoader xCompLoader = null;
+ // the document
+ XComponent xComp = null;
+ // the current window
+ XWindow xWin = null;
+ // a own window listener
+ WindowListener wl = null;
+
+ /**
+ * Constructor
+ * @param xComponentLoader A loader to load a document
+ */
+ public DocumentHandle(XComponentLoader xCompLoader) {
+ this.xCompLoader = xCompLoader;
+ wl = new WindowListener();
+ }
+
+ /**
+ * Load/Create a document.
+ * @param docName The name of a document as file URL
+ * @param hidden If true, the document is loaded hidden.
+ * @return The size of the opened/created document.
+ */
+ public Rectangle loadDocument(String docName, boolean hidden)
+ throws Exception{
+ wl.resetTrigger();
+ try {
+ PropertyValue [] szArgs = null;
+ if (hidden) {
+ szArgs = new PropertyValue [1];
+ PropertyValue Arg = new PropertyValue();
+ Arg.Name = "Hidden";
+ Arg.Value = hidden?"True":"False";
+ Arg.Handle = -1;
+ Arg.State = PropertyState.DEFAULT_VALUE;
+ szArgs[0] = Arg;
+ }
+ else {
+ szArgs = new PropertyValue [0];
+ }
+
+ // get the current active window
+ XFrame xCurFrame = (XFrame)UnoRuntime.queryInterface(XFrame.class, xCompLoader);
+
+ // create a new frame
+ XFrame xFrame = xCurFrame.findFrame("_blank", FrameSearchFlag.CREATE);
+
+ // load document in this frame
+ XComponentLoader xFrameLoader = (XComponentLoader)UnoRuntime.queryInterface(XComponentLoader.class, xFrame);
+ xComp = xFrameLoader.loadComponentFromURL(
+ docName, "_self", 0, szArgs);
+ // wait for the document to load.
+ try {
+ Thread.sleep(10000);
+ }
+ catch(java.lang.InterruptedException e) {}
+
+ xWin = xFrame.getContainerWindow();
+ xWin.addWindowListener(wl);
+ }
+ catch(com.sun.star.io.IOException e) {
+ e.printStackTrace();
+ return null;
+ }
+ catch(com.sun.star.lang.IllegalArgumentException e) {
+ e.printStackTrace();
+ return null;
+ }
+ catch(java.lang.Exception e) {
+ System.out.println("DH3");
+ e.printStackTrace();
+ throw e;
+ }
+ return xWin.getPosSize();
+
+ }
+
+ /**
+ * Get the size of the current window.
+ * @return The size of the window as Rectangle.
+ */
+ public Rectangle getDocumentPosSize() {
+ return xWin.getPosSize();
+ }
+
+ /**
+ * Resize the window in defined steps:
+ * width -10 pixel;
+ * height -10 pixel;
+ * X-Position +10 pixel;
+ * Y-Position +10 pixel
+ * @return True if resize worked.
+ */
+ public boolean resizeDocument() {
+ Rectangle newPosSize = xWin.getPosSize();
+ newPosSize.Width = newPosSize.Width - 20;
+ newPosSize.Height = newPosSize.Height - 20;
+ newPosSize.X = newPosSize.X + 80;
+ newPosSize.Y = newPosSize.Y + 80;
+ return resizeDocument(newPosSize);
+ }
+
+ /**
+ * Resize window to the given Rectangle
+ * @param newPosSize The new position and size of the window.
+ * @return True if resize worked.
+ */
+ public boolean resizeDocument(Rectangle newPosSize){
+ wl.resetTrigger();
+ xWin.setPosSize(newPosSize.X, newPosSize.Y, newPosSize.Width,
+ newPosSize.Height, PosSize.POSSIZE);
+ try {
+ Thread.sleep(3000);
+ }
+ catch(java.lang.InterruptedException e) {}
+ return wl.resizedTrigger;
+ }
+}
diff --git a/vcl/qa/complex/persistent_window_states/PersistentWindowTest.java b/vcl/qa/complex/persistent_window_states/PersistentWindowTest.java
new file mode 100644
index 000000000000..edceeeafd883
--- /dev/null
+++ b/vcl/qa/complex/persistent_window_states/PersistentWindowTest.java
@@ -0,0 +1,393 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+package complex.persistent_window_states;
+
+
+import com.sun.star.lang.XServiceInfo;
+import com.sun.star.lang.XInitialization;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.Any;
+import com.sun.star.lang.XTypeProvider;
+import com.sun.star.lang.XSingleServiceFactory;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.lang.XComponent;
+import com.sun.star.frame.XDesktop;
+import com.sun.star.frame.XFramesSupplier;
+import com.sun.star.frame.XFrames;
+import com.sun.star.registry.XRegistryKey;
+import com.sun.star.comp.loader.FactoryHelper;
+import com.sun.star.container.XIndexAccess;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.AnyConverter;
+import com.sun.star.frame.XComponentLoader;
+import com.sun.star.awt.Rectangle;
+import com.sun.star.util.XCloseable;
+import helper.ConfigurationRead;
+import complexlib.ComplexTestCase;
+import helper.OfficeProvider;
+import complex.persistent_window_states.DocumentHandle;
+
+/**
+ * Parameters:
+ * <ul>
+ * <li>NoOffice=yes - StarOffice is not started initially.</li>
+ * </ul>
+ */
+public class PersistentWindowTest extends ComplexTestCase {
+
+ private XMultiServiceFactory xMSF;
+ private OfficeProvider oProvider;
+ private int iOfficeCloseTime = 0;
+
+ /**
+ * A frunction to tell the framework, which test functions are available.
+ * Right now, it's only 'checkPersistentWindowState'.
+ * @return All test methods.
+ */
+ public String[] getTestMethodNames() {
+ return new String[]{"checkPersistentWindowState"};
+ }
+
+ /**
+ * Test if all available document types change the
+ * persistent Window Attributes
+ *
+ * The test follows basically these steps:
+ * - Create a configuration reader and a componentloader
+ * - Look for all document types in the configuration
+ * - Do for every doc type
+ * - start office
+ * - read configuration attibute settings
+ * - create a new document
+ * - resize the document and close it
+ * - close office
+ * - start office
+ * - read configuration attribute settings
+ * - create another new document
+ * - compare old settings with new ones: should be different
+ * - compare the document size with the resized document: should be equal
+ * - close office
+ * - Test finished
+ */
+ public void checkPersistentWindowState()
+ {
+ try {
+
+ log.println("Connect the first time.");
+ log.println("AppExecCommand: " + (String)param.get("AppExecutionCommand"));
+ log.println("ConnString: " + (String)param.get("ConnectionString"));
+ oProvider = new OfficeProvider();
+ iOfficeCloseTime = param.getInt("OfficeCloseTime");
+ if ( iOfficeCloseTime == 0 ) {
+ iOfficeCloseTime = 1000;
+ }
+
+ if (!connect()) return;
+
+ // create the configuration provider
+ Object o = null;
+ try {
+ o = xMSF.createInstance(
+ "com.sun.star.configuration.ConfigurationProvider");
+ }
+ catch(com.sun.star.uno.Exception e) {
+ failed("Cannot create \"com.sun.star.configuration."+
+ "ConfigurationProvider\"");
+ return;
+ }
+
+ // fetch the multi service factory for setup
+ XMultiServiceFactory xCP = (XMultiServiceFactory)
+ UnoRuntime.queryInterface(XMultiServiceFactory.class, o);
+
+ // create the configuration reader
+ ConfigurationRead cfgRead = new ConfigurationRead(xCP);
+
+ // just test the wrong ones, not all.
+ String [] els = new String[]{
+ "Office/Factories/com.sun.star.drawing.DrawingDocument",
+ "Office/Factories/com.sun.star.formula.FormulaProperties",
+ //"Office/Factories/com.sun.star.presentation.PresentationDocument",
+ "Office/Factories/com.sun.star.sheet.SpreadsheetDocument",
+ "Office/Factories/com.sun.star.text.GlobalDocument",
+ "Office/Factories/com.sun.star.text.TextDocument",
+ "Office/Factories/com.sun.star.text.WebDocument",
+ };
+ // uncomment the following line for all doc types
+// String [] els = cfgRead.getSubNodeNames("Office/Factories");
+
+ log.println("Found "+ els.length + " document types to test.\n");
+ if (!disconnect()) return;
+
+ // for all types
+ for(int i=0; i<els.length; i++) {
+ log.println("\tStart test for document type " + i + ": " + els[i]);
+ // exclude chart documents: cannot be created this way.
+ if ( els[i].indexOf("ChartDocument") != -1) {
+ log.println("Skipping chart document: cannot be create like this.");
+ continue;
+ }
+
+ // start an office
+ if (!connect()) return;
+
+ // get configuration
+ String[] settings = getConfigurationAndLoader(xMSF, els[i]);
+ if (settings == null) {
+ log.println("Skipping document type " + els[i]);
+ disconnect();
+ continue;
+ }
+ String cfg = settings[1];
+
+ // load a document
+ DocumentHandle handle = loadDocument(xMSF, settings[0]);
+
+ // first size
+ Rectangle rect1 = handle.getDocumentPosSize();
+
+ // resize
+ handle.resizeDocument();
+ // after resize
+ Rectangle rect2 = handle.getDocumentPosSize();
+
+ // disposeManager and start a new office
+ if (!disconnect()) return;
+
+ if (!connect()) return;
+
+ // get configuration
+ settings = getConfigurationAndLoader(xMSF, els[i]);
+
+ String newCfg = settings[1];
+
+ // load a document
+ handle = loadDocument(xMSF, settings[0]);
+
+ Rectangle newRect = handle.getDocumentPosSize();
+
+ // print the settings and window sizes
+ log.println("----------------------------");
+ log.println("Initial Config String : " + cfg);
+ log.println("Config String after restart: " + newCfg);
+
+ log.println("----------------------------");
+ log.println("Initial window (X,Y,Width,Height): "
+ +rect1.X+";"+rect1.Y+";"+ rect1.Width+";"+rect1.Height);
+ log.println("Window after resize (X,Y,Width,Height): "
+ +rect2.X+";"+rect2.Y+";"+ rect2.Width+";"+rect2.Height);
+ log.println("Window after restart (X,Y,Width,Height): "
+ +newRect.X+";"+newRect.Y+";"+newRect.Width+";"
+ +newRect.Height);
+
+ // compare to see if resize worked
+ log.println("----------------------------");
+ assure("Resize values for "+ els[i] +
+ " are equal.", !compareRectangles(rect1, rect2), true);
+ // compare settings and sizes
+ assure("Config settings for "+ els[i] +
+ " were not changed.", !cfg.equals(newCfg), true);
+ assure("Resized and restarted window for "+ els[i] +
+ " are not equal.", compareRectangles(rect2, newRect), true);
+ log.println("----------------------------");
+
+ // disposeManager
+ if (!disconnect()) return;
+
+ log.println("\tFinish test for document type " + i + ": " + els[i]);
+
+ }
+ }
+ catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Get the configuration settings and the document loader
+ * @param xMSF A MultiServiceFactory from an office
+ * @param cfgString A configuration string
+ * @return Settings and Loader
+ */
+ private static String[] getConfigurationAndLoader(XMultiServiceFactory xMSF,
+ String cfgString) {
+ String[] conf = new String[2];
+
+ try {
+ Object o = xMSF.createInstance(
+ "com.sun.star.configuration.ConfigurationProvider");
+
+ // fetch the multi service factory for setup
+ XMultiServiceFactory xCP = (XMultiServiceFactory)
+ UnoRuntime.queryInterface(XMultiServiceFactory.class, o);
+
+ // create the configuration reader
+ ConfigurationRead cfgRead = new ConfigurationRead(xCP);
+
+ // get the document loader
+ String loader = getStringFromObject(
+ cfgRead.getByHierarchicalName(cfgString + "/ooSetupFactoryEmptyDocumentURL"));
+
+ if (loader == null) return null;
+ log.println("\tLoader: " + loader);
+
+ // read attributes
+ String hierchName = cfgString + "/ooSetupFactoryWindowAttributes";
+ String setupSettings = getStringFromObject(cfgRead.getByHierarchicalName(hierchName));
+ // remove slots: just plain document types have to start
+ if ( loader.indexOf("?slot") != -1 ) {
+ loader = loader.substring(0, loader.indexOf("?slot"));
+ System.out.println("Loader: "+loader);
+ }
+
+ conf[0] = loader;
+ conf[1] = setupSettings;
+ }
+ catch(com.sun.star.uno.Exception e) {}
+ return conf;
+ }
+
+ /**
+ * Load a document
+ * @param xMSF A MultiServiceFactory from an office
+ * @param docLoader A documet loader
+ * @return A handle to the document
+ */
+ private DocumentHandle loadDocument(XMultiServiceFactory xMSF,
+ String docLoader) {
+ DocumentHandle docHandle = null;
+ try {
+ // create component loaader
+ XComponentLoader xCompLoader = (XComponentLoader)
+ UnoRuntime.queryInterface(
+ XComponentLoader.class, xMSF.createInstance(
+ "com.sun.star.frame.Desktop"));
+ XFramesSupplier xFrameSupp = (XFramesSupplier)UnoRuntime.queryInterface(XFramesSupplier.class, xCompLoader);
+ // close all existing frames
+ XFrames xFrames = xFrameSupp.getFrames();
+ XIndexAccess xAcc = (XIndexAccess)UnoRuntime.queryInterface(XIndexAccess.class, xFrames);
+ for ( int i=0; i<xAcc.getCount(); i++ ) {
+ XCloseable xClose = (XCloseable)UnoRuntime.queryInterface(XCloseable.class, xAcc.getByIndex(i));
+ try {
+ if ( xClose != null ) {
+ xClose.close(false);
+ }
+ else {
+ failed("Could not query frame for XCloseable!");
+ }
+ }
+ catch( com.sun.star.uno.Exception e ) {
+ e.printStackTrace((java.io.PrintWriter)log);
+ failed("Could not query frame for XCloseable!");
+ }
+ }
+ docHandle = new DocumentHandle(xCompLoader);
+ docHandle.loadDocument(docLoader, false);
+ }
+ catch(com.sun.star.uno.Exception e) {
+ e.printStackTrace();
+ }
+ catch(java.lang.Exception e) {
+ e.printStackTrace();
+ }
+ return docHandle;
+ }
+
+ private boolean connect() {
+ try {
+ xMSF = (XMultiServiceFactory)oProvider.getManager(param);
+ try {
+ Thread.sleep(10000);
+ }
+ catch(java.lang.InterruptedException e) {}
+ }
+ catch (java.lang.Exception e) {
+ log.println(e.getClass().getName());
+ log.println("Message: " + e.getMessage());
+ failed("Cannot connect the Office.");
+ return false;
+ }
+ return true;
+ }
+
+ private boolean disconnect() {
+ try {
+ XDesktop desk = null;
+ desk = (XDesktop) UnoRuntime.queryInterface(
+ XDesktop.class, xMSF.createInstance(
+ "com.sun.star.frame.Desktop"));
+ xMSF = null;
+ desk.terminate();
+ log.println("Waiting " + iOfficeCloseTime + " milliseconds for the Office to close down");
+ try {
+ Thread.sleep(iOfficeCloseTime);
+ }
+ catch(java.lang.InterruptedException e) {}
+ }
+ catch (java.lang.Exception e) {
+ e.printStackTrace();
+ failed("Cannot dispose the Office.");
+ return false;
+ }
+ return true;
+ }
+
+ private static String getStringFromObject(Object oName) {
+ if (oName instanceof String)
+ return (String)oName;
+ String value = null;
+ if (oName instanceof Any) {
+ try {
+ value = AnyConverter.toString(oName);
+ if (value == null) {
+ log.println("Got a void css.uno.Any as loading string.");
+ }
+ }
+ catch(Exception e) {
+ log.println("This document type cannot be opened directly.");
+ }
+ }
+ return value;
+ }
+
+ /**
+ * Compare two rectangles. Return true, if both are equal, false
+ * otherwise.
+ * @param rect1 First Rectangle.
+ * @param rect2 Second Rectangle.
+ * @return True, if the rectangles are equal.
+ */
+ private boolean compareRectangles(Rectangle rect1, Rectangle rect2) {
+ boolean result = true;
+ result &= (rect1.X==rect2.X);
+ result &= (rect1.Y==rect2.Y);
+ result &= (rect1.Width==rect2.Width);
+ result &= (rect1.Height==rect2.Height);
+ return result;
+ }
+}
diff --git a/vcl/qa/complex/persistent_window_states/PersistentWindowTest.props b/vcl/qa/complex/persistent_window_states/PersistentWindowTest.props
new file mode 100644
index 000000000000..df96e1592834
--- /dev/null
+++ b/vcl/qa/complex/persistent_window_states/PersistentWindowTest.props
@@ -0,0 +1,10 @@
+# test can be long: so increase the time until the test is interrupted
+# time in milliseconds
+ThreadTimeOut=50000000
+
+# wait for the Office to close: may be increased on slower machines
+# time in milliseconds
+OfficeCloseTime=5000
+
+# do not start an Office initially
+NoOffice=yes
diff --git a/vcl/qa/complex/persistent_window_states/makefile.mk b/vcl/qa/complex/persistent_window_states/makefile.mk
new file mode 100644
index 000000000000..4c61d8969b8d
--- /dev/null
+++ b/vcl/qa/complex/persistent_window_states/makefile.mk
@@ -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.
+#
+#*************************************************************************
+
+PRJ = ..$/..$/..
+TARGET = PersistentWindowTest
+PRJNAME = $(TARGET)
+PACKAGE = complex$/persistent_window_states
+
+# --- Settings -----------------------------------------------------
+.INCLUDE: settings.mk
+
+#----- compile .java files -----------------------------------------
+
+JARFILES = ridl.jar unoil.jar jurt.jar juh.jar java_uno.jar OOoRunner.jar
+JAVAFILES = PersistentWindowTest.java DocumentHandle.java
+
+#----- make a jar from compiled files ------------------------------
+
+MAXLINELENGTH = 100000
+
+JARCLASSDIRS = $(PACKAGE)
+JARTARGET = $(TARGET).jar
+JARCOMPRESS = TRUE
+
+# --- Parameters for the test --------------------------------------
+
+# test base is java complex
+CT_TESTBASE = -TestBase java_complex
+
+# test looks something like the.full.package.TestName
+CT_TEST = -o $(PACKAGE:s\$/\.\).$(TARGET)
+
+# start the runner application
+CT_APP = org.openoffice.Runner
+
+# --- Targets ------------------------------------------------------
+
+$(CLASSDIR)$/$(PACKAGE)$/$(TARGET).props : ALLTAR
+
+.INCLUDE : target.mk
+
+$(CLASSDIR)$/$(PACKAGE)$/$(TARGET).props : $(TARGET).props
+ cp $(TARGET).props $@
+ jar uf $(CLASSDIR)$/$(JARTARGET) -C $(CLASSDIR) $(PACKAGE)$/$(TARGET).props
+
+RUN: run
+
+# start an office if the parameter is set for the makefile
+.IF "$(OFFICE)" == ""
+run:
+ @echo "Execute this test with 'dmake run OFFICE=/system/path/to/office/program'."
+ @echo "The office will be started by the test with a socket connection on port 8100"
+.ELSE
+run: $(CLASSDIR)$/$(PACKAGE)$/$(TARGET).props
+ java -cp $(CLASSPATH) $(CT_APP) -AppExecutionCommand "$(OFFICE)$/soffice -accept=socket,host=localhost,port=8100;urp;" $(CT_TESTBASE) $(CT_TEST)
+.ENDIF
+
diff --git a/vcl/qa/testdocuments/CalcDoc.sxc b/vcl/qa/testdocuments/CalcDoc.sxc
new file mode 100755
index 000000000000..4b2b572085dc
--- /dev/null
+++ b/vcl/qa/testdocuments/CalcDoc.sxc
Binary files differ
diff --git a/vcl/qa/testdocuments/ImpressDoc.sxi b/vcl/qa/testdocuments/ImpressDoc.sxi
new file mode 100755
index 000000000000..efcdf9b6a25e
--- /dev/null
+++ b/vcl/qa/testdocuments/ImpressDoc.sxi
Binary files differ
diff --git a/vcl/qa/testdocuments/WriterDoc.sxw b/vcl/qa/testdocuments/WriterDoc.sxw
new file mode 100755
index 000000000000..1b2c2cb2dab6
--- /dev/null
+++ b/vcl/qa/testdocuments/WriterDoc.sxw
Binary files differ
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..ac1da931ba06
--- /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
+ Region aCtrlRegion = Region( Rectangle( 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..980e0f1c5b58
--- /dev/null
+++ b/vcl/source/app/settings.cxx
@@ -0,0 +1,2080 @@
+/*************************************************************************
+ *
+ * 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( "industrial" );
+ 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_INDUSTRIAL;
+ 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" ) )
+ 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..d66389eee62d
--- /dev/null
+++ b/vcl/source/control/button.cxx
@@ -0,0 +1,4510 @@
+/*************************************************************************
+ *
+ * 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;
+ 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();
+}
+
+// -----------------------------------------------------------------------
+
+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();
+
+ 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,
+ 1, nDrawFlags, nTextStyle, NULL, (GetStyle() & WB_FLATBUTTON) != 0 );
+ }
+ else
+ ImplCalcSymbolRect( aInRect );
+
+ if( ! bLayout )
+ {
+ DecorationView aDecoView( pDev );
+ aDecoView.DrawSymbol( aInRect, SYMBOL_SPIN_DOWN, aColor, nStyle );
+ }
+ }
+ else
+ {
+ Rectangle aSymbolRect;
+ ULONG nImageSep = 1 + (pDev->GetTextHeight()-10)/2;
+ if( nImageSep < 1 )
+ nImageSep = 1;
+ // 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 );
+ }
+
+ 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;
+ Region aCtrlRegion( aInRect );
+ 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, aCtrlRegion, nState,
+ aControlValue, rtl::OUString() );
+ }
+ }
+ }
+
+ if( bNativeOK )
+ return;
+
+ bool bRollOver = (IsMouseOver() && aInRect.IsInside( GetPointerPosPixel() ));
+ if ( (bNativeOK=IsNativeControlSupported(CTRL_PUSHBUTTON, PART_ENTIRE_CONTROL)) == TRUE )
+ {
+ PushButtonValue aPBVal;
+ ImplControlValue aControlValue;
+ aControlValue.setOptionalVal( &aPBVal );
+ Region 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 )
+ aPBVal.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() ) ) );
+ aPBVal.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 )
+ {
+ Region aBoundingRgn, aContentRgn;
+ 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;
+ Region 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(),
+ aBoundingRgn, aContentRgn ) )
+ {
+ Rectangle aCont(aContentRgn.GetBoundRect());
+ Rectangle aBound(aBoundingRgn.GetBoundRect());
+
+ 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 );
+ }
+ 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, rtl::OUString(), 0 );
+ Rectangle aCtrlRect( maStateRect.TopLeft(), maStateRect.GetSize() );
+ Region aCtrlRegion( aCtrlRect );
+ 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, aCtrlRegion, 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
+ Region aCtrlRegion = Region( Rectangle( Point( 0, 0 ), GetSizePixel() ) );
+ ControlState nState = CTRL_STATE_DEFAULT|CTRL_STATE_ENABLED;
+ Region aBoundingRgn, aContentRgn;
+
+ // get native size of a radio button
+ if( pThis->GetNativeControlRegion( CTRL_RADIOBUTTON, PART_ENTIRE_CONTROL, aCtrlRegion,
+ nState, aControlValue, rtl::OUString(),
+ aBoundingRgn, aContentRgn ) )
+ {
+ Rectangle aCont(aContentRgn.GetBoundRect());
+ aSize = aCont.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() );
+ Region aCtrlRegion = Region( Rectangle( Point( 0, 0 ), aCurSize ) );
+ Region 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 ) )
+ {
+ Rectangle aCont(aContentRgn.GetBoundRect());
+ Size aSize = aCont.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, rtl::OUString(), 0 );
+ Region 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
+ Region aCtrlRegion = Region( Rectangle( Point( 0, 0 ), GetSizePixel() ) );
+ ControlState nState = CTRL_STATE_DEFAULT|CTRL_STATE_ENABLED;
+ Region aBoundingRgn, aContentRgn;
+
+ // get native size of a check box
+ if( pThis->GetNativeControlRegion( CTRL_CHECKBOX, PART_ENTIRE_CONTROL, aCtrlRegion,
+ nState, aControlValue, rtl::OUString(),
+ aBoundingRgn, aContentRgn ) )
+ {
+ Rectangle aCont(aContentRgn.GetBoundRect());
+ aSize = aCont.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() );
+ Region aCtrlRegion = Region( Rectangle( Point( 0, 0 ), aCurSize ) );
+ Region 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 ) )
+ {
+ Rectangle aCont(aContentRgn.GetBoundRect());
+ Size aSize = aCont.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, rtl::OUString(), 0 );
+ Region 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..f5c04b7c3cfa
--- /dev/null
+++ b/vcl/source/control/combobox.cxx
@@ -0,0 +1,1584 @@
+/*************************************************************************
+ *
+ * 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;
+
+ Region aCtrlRegion( Rectangle( (const Point&)Point(), Size( 10, 10 ) ) );
+ Region 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.GetBoundRect().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;
+ Region aContent, aBound;
+
+ // use the full extent of the control
+ Region aArea( Rectangle(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.GetBoundRect().Left(), nTop, aContent.GetBoundRect().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
+ Rectangle aContentRect = aContent.GetBoundRect();
+ mpSubEdit->SetPosSizePixel( aContentRect.TopLeft(), aContentRect.GetSize() );
+ }
+ else
+ {
+ // use the themes drop down size for the button
+ aOutSz.Width() -= aContent.GetBoundRect().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..0a29a627b8e3
--- /dev/null
+++ b/vcl/source/control/edit.cxx
@@ -0,0 +1,3141 @@
+/*************************************************************************
+ *
+ * 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 an border
+ aSize.Height() += 4;
+
+ aSize = CalcWindowSize( aSize );
+
+ // ask NWF what if it has an opinion, too
+ ImplControlValue aControlValue;
+ Rectangle aRect( Point( 0, 0 ), aSize );
+ Region aContent, aBound;
+ if( const_cast<Edit*>(this)->GetNativeControlRegion(
+ CTRL_EDITBOX, PART_ENTIRE_CONTROL,
+ aRect, 0, aControlValue, rtl::OUString(), aBound, aContent) )
+ {
+ Rectangle aBoundRect( aContent.GetBoundRect() );
+ if( aBoundRect.GetHeight() > aSize.Height() )
+ aSize.Height() = aBoundRect.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..ebccfdc1e6bb
--- /dev/null
+++ b/vcl/source/control/ilstbox.cxx
@@ -0,0 +1,3234 @@
+/*************************************************************************
+ *
+ * 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 );
+ Region aCtrlRegion( Rectangle( 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() );
+ Region aParentReg( aParentRect );
+ pWin->DrawNativeControl( CTRL_LISTBOX, PART_ENTIRE_CONTROL, aParentReg,
+ 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..6c7df5b106bf
--- /dev/null
+++ b/vcl/source/control/lstbox.cxx
@@ -0,0 +1,1639 @@
+/*************************************************************************
+ *
+ * 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"
+
+
+
+ // =======================================================================
+
+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();
+
+ 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;
+ Region aCtrlRegion( Rectangle( (const Point&)Point(), Size( 20, mnDDHeight ) ) );
+ Region aBoundingRgn( aCtrlRegion );
+ Region aContentRgn( aCtrlRegion );
+ if( GetNativeControlRegion( CTRL_LISTBOX, PART_ENTIRE_CONTROL, aCtrlRegion,
+ CTRL_STATE_ENABLED, aControlValue, rtl::OUString(),
+ aBoundingRgn, aContentRgn ) )
+ {
+ sal_Int32 nHeight = aBoundingRgn.GetBoundRect().GetHeight();
+ if( nHeight > mnDDHeight )
+ mnDDHeight = static_cast<USHORT>(nHeight);
+ }
+ }
+
+ mpFloatWin = new ImplListBoxFloatingWindow( this );
+ mpFloatWin->SetAutoWidth( TRUE );
+ mpFloatWin->SetPopupModeEndHdl( LINK( this, ListBox, ImplPopupModeEndHdl ) );
+
+ 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();
+
+ mpBtn = new ImplBtn( this, WB_NOLIGHTBORDER | WB_RECTSTYLE );
+ ImplInitDropDownButton( mpBtn );
+ mpBtn->SetMBDownHdl( LINK( this, ListBox, ImplClickBtnHdl ) );
+ mpBtn->Show();
+
+ }
+
+ 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();
+
+ 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;
+ Region aContent, aBound;
+
+ // use the full extent of the control
+ Region aArea( Rectangle(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.GetBoundRect().Left();
+ mpBtn->SetPosSizePixel( aContent.GetBoundRect().Left(), nTop, aContent.GetBoundRect().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
+ Rectangle aContentRect = aContent.GetBoundRect();
+ 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 = aContentRect.Top() - (aSz.Height() - aContentRect.GetHeight())/2;
+ aContentRect.Top() -= nDiff;
+ aContentRect.Bottom() -= nDiff;
+ }
+ mpImplWin->SetPosSizePixel( aContentRect.TopLeft(), aContentRect.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;
+ Region aContent, aBound;
+ Size aTestSize( 100, 20 );
+ Region aArea( Rectangle( 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
+ Rectangle aContentRect = aContent.GetBoundRect();
+ aSz.Width() += aTestSize.Width() - aContentRect.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 );
+ Region aContent, aBound;
+ if( const_cast<ListBox*>(this)->GetNativeControlRegion(
+ CTRL_LISTBOX, PART_ENTIRE_CONTROL, aRect, 0, aControlValue, rtl::OUString(), aBound, aContent) )
+ {
+ Rectangle aBoundRect( aBound.GetBoundRect() );
+ if( aBoundRect.GetHeight() > aSz.Height() )
+ aSz.Height() = aBoundRect.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..94f61818ac92
--- /dev/null
+++ b/vcl/source/control/menubtn.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"
+
+#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 )
+{
+ if ( mnMenuMode & MENUBUTTON_MENUMODE_TIMED )
+ {
+ if ( !mpMenuTimer )
+ {
+ mpMenuTimer = new Timer;
+ mpMenuTimer->SetTimeoutHdl( LINK( this, MenuButton, ImplMenuTimeoutHdl ) );
+ }
+
+ mpMenuTimer->SetTimeout( GetSettings().GetMouseSettings().GetActionDelay() );
+ mpMenuTimer->Start();
+
+ PushButton::MouseButtonDown( rMEvt );
+ }
+ else
+ {
+ 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..54a1e0a97eab
--- /dev/null
+++ b/vcl/source/control/scrbar.cxx
@@ -0,0 +1,1655 @@
+/*************************************************************************
+ *
+ * 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 Region aControlRegion( Rectangle( (const Point&)Point(0,0), aSize ) );
+ Region 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.GetBoundRect();
+ maBtn2Rect = aBtn2Region.GetBoundRect();
+ }
+ 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.GetBoundRect();
+ 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.GetBoundRect();
+ maBtn2Rect = aBtn2Region.GetBoundRect();
+ }
+ 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.GetBoundRect();
+ 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 )
+{
+ ImplControlValue aControlValue( BUTTONVALUE_DONTKNOW, rtl::OUString(), 0 );
+
+ 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 );
+ ScrollbarValue scrValue;
+
+ 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;
+ }
+ }
+
+ aControlValue.setOptionalVal( (void *)(&scrValue) );
+
+#if 1
+ Region aCtrlRegion;
+ aCtrlRegion.Union( maBtn1Rect );
+ aCtrlRegion.Union( maBtn2Rect );
+ aCtrlRegion.Union( maPage1Rect );
+ aCtrlRegion.Union( maPage2Rect );
+ aCtrlRegion.Union( maThumbRect );
+#else
+ const Region aCtrlRegion( Rectangle( Point(0,0), GetOutputSizePixel() ) );
+#endif
+ bNativeOK = DrawNativeControl( CTRL_SCROLLBAR, (bHorz ? PART_DRAW_BACKGROUND_HORZ : PART_DRAW_BACKGROUND_VERT),
+ aCtrlRegion, nState, aControlValue, 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;
+ Region aCtrlRegion1( maPage1Rect );
+ Region 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,
+ aControlValue, rtl::OUString() );
+
+ if ( nDrawFlags & SCRBAR_DRAW_PAGE2 )
+ bNativeOK = DrawNativeControl( CTRL_SCROLLBAR, part2, aCtrlRegion2, nState2,
+ aControlValue, 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;
+ Region aCtrlRegion1( maBtn1Rect );
+ Region 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,
+ aControlValue, rtl::OUString() );
+
+ if ( nDrawFlags & SCRBAR_DRAW_BTN2 )
+ bNativeOK = DrawNativeControl( CTRL_SCROLLBAR, part2, aCtrlRegion2, nState2,
+ aControlValue, rtl::OUString() );
+ }
+ if ( (nDrawFlags & SCRBAR_DRAW_THUMB) && !maThumbRect.IsEmpty() )
+ {
+ ControlState nState = IsEnabled() ? CTRL_STATE_ENABLED : 0;
+ Region 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, aControlValue, 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 );
+ Region aControlRegion( Rectangle( 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,
+ Region( 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,
+ Region( 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 );
+ Region aControlRegion( Rectangle( 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,
+ Region( 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,
+ Region( 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 );
+ Region aControlRegion( Rectangle( 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,
+ Region( 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,
+ Region( 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,
+ Region( 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..2390a8e3e9a6
--- /dev/null
+++ b/vcl/source/control/slider.cxx
@@ -0,0 +1,1093 @@
+/*************************************************************************
+ *
+ * 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 Region aControlRegion( Rectangle( Point(0,0), Size( SLIDER_THUMB_SIZE, 10 ) ) );
+ Region aThumbBounds, aThumbContent;
+ if ( GetNativeControlRegion( CTRL_SLIDER, PART_THUMB_HORZ,
+ aControlRegion, 0, ImplControlValue(), rtl::OUString(),
+ aThumbBounds, aThumbContent ) )
+ {
+ Rectangle aRect( aThumbBounds.GetBoundRect() );
+ maThumbRect.Left() = mnThumbPixPos - aRect.GetWidth()/2;
+ maThumbRect.Right() = maThumbRect.Left() + aRect.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 Region aControlRegion( Rectangle( Point(0,0), Size( 10, SLIDER_THUMB_SIZE ) ) );
+ Region aThumbBounds, aThumbContent;
+ if ( GetNativeControlRegion( CTRL_SLIDER, PART_THUMB_VERT,
+ aControlRegion, 0, ImplControlValue(), rtl::OUString(),
+ aThumbBounds, aThumbContent ) )
+ {
+ Rectangle aRect( aThumbBounds.GetBoundRect() );
+ maThumbRect.Top() = mnThumbPixPos - aRect.GetHeight()/2;
+ maThumbRect.Bottom() = maThumbRect.Top() + aRect.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;
+ ImplControlValue aControlValue( BUTTONVALUE_DONTKNOW, rtl::OUString(), 0 );
+ 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;
+ }
+ aControlValue.setOptionalVal( (void *)(&sldValue) );
+
+ const Region aCtrlRegion( Rectangle( Point(0,0), GetOutputSizePixel() ) );
+ bool bNativeOK = DrawNativeControl( CTRL_SLIDER, nPart,
+ aCtrlRegion, nState, aControlValue, 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..d18a412e31cc
--- /dev/null
+++ b/vcl/source/control/spinfld.cxx
@@ -0,0 +1,1098 @@
+/*************************************************************************
+ *
+ * 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) )
+ {
+ ImplControlValue aControlValue;
+ aControlValue.setOptionalVal( (void*) &rSpinbuttonValue );
+
+ 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, Region(), CTRL_STATE_ENABLED,
+ aControlValue, 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
+ Region aBound, aContent;
+ Region aNatRgn( Rectangle( aPt, aSize ) );
+ if( pBorder->GetNativeControlRegion(CTRL_SPINBOX, PART_ENTIRE_CONTROL,
+ aNatRgn, 0, aControlValue, rtl::OUString(), aBound, aContent) )
+ {
+ aSize = aContent.GetBoundRect().GetSize();
+ }
+
+ Region aRgn( Rectangle( aPt, aSize ) );
+ bNativeOK = pBorder->DrawNativeControl( CTRL_SPINBOX, PART_ENTIRE_CONTROL, aRgn, CTRL_STATE_ENABLED,
+ aControlValue, 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) )
+ {
+ ImplControlValue aControlValue;
+ aControlValue.setOptionalVal( (void*) &rSpinbuttonValue );
+
+ // only paint the standalone spin buttons, all buttons are painted at once
+ bNativeOK = pWin->DrawNativeControl( CTRL_SPINBUTTONS, PART_ALL_BUTTONS, Region(), CTRL_STATE_ENABLED,
+ aControlValue, 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;
+ Region 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;
+ Region aBound;
+ Point aPoint;
+
+ // use the full extent of the control
+ Region aArea( Rectangle( 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.GetBoundRect();
+ rSpinDownArea = aContentDown.GetBoundRect();
+ }
+ 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;
+ Region aContent, aBound;
+
+ // use the full extent of the control
+ Window *pBorder = GetWindow( WINDOW_BORDER );
+ Region aArea( Rectangle(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
+ Rectangle aContentRect = aContent.GetBoundRect();
+ mpEdit->SetPosPixel( aContentRect.TopLeft() );
+ bSubEditPositioned = true;
+ aSize = aContentRect.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..95f84626b582
--- /dev/null
+++ b/vcl/source/control/tabctrl.cxx
@@ -0,0 +1,2361 @@
+/*************************************************************************
+ *
+ * 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;
+
+ Region aCtrlRegion( Rectangle( (const Point&)Point( 0, 0 ), aSize ) );
+ Region aBoundingRgn, aContentRgn;
+ const ImplControlValue aControlValue( BUTTONVALUE_DONTKNOW, rtl::OUString(), 0 );
+ if(GetNativeControlRegion( CTRL_TAB_ITEM, PART_ENTIRE_CONTROL, aCtrlRegion,
+ CTRL_STATE_ENABLED, aControlValue, rtl::OUString(),
+ aBoundingRgn, aContentRgn ) )
+ {
+ Rectangle aCont(aContentRgn.GetBoundRect());
+ return aCont.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 )
+ {
+ ImplControlValue aControlValue;
+ Region 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;
+ aControlValue.setOptionalVal( (void *)(&tiValue) );
+
+ bNativeOK = DrawNativeControl( CTRL_TAB_ITEM, PART_ENTIRE_CONTROL, aCtrlRegion, nState,
+ aControlValue, 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( BUTTONVALUE_DONTKNOW, rtl::OUString(), 0 );
+
+ 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 );
+
+ Region aCtrlRegion( aRect );
+ Rectangle aClipRect( aClipRgn.GetBoundRect() );
+ if( !aClipRgn.IsEmpty() ) //&& aClipRect.getHeight() && aClipRect.getWidth() )
+ bNativeOK = DrawNativeControl( CTRL_TAB_PANE, part, aCtrlRegion, 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..468d4be36b0a
--- /dev/null
+++ b/vcl/source/fontsubset/sft.cxx
@@ -0,0 +1,3354 @@
+/*************************************************************************
+ *
+ * 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 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) {
+ ThreeOne = offset; break;
+ }
+
+ 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;
+ }
+ }
+ }
+
+ 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..4d32990f9335
--- /dev/null
+++ b/vcl/source/gdi/gfxlink.cxx
@@ -0,0 +1,512 @@
+/*************************************************************************
+ *
+ * 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 <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 = INetURLObject(aTempFile.GetURL());
+
+ if( maURL.GetMainURL( INetURLObject::NO_DECODE ).getLength() )
+ {
+ SvStream* pOStm = ::utl::UcbStreamHelper::CreateStream( maURL.GetMainURL( INetURLObject::NO_DECODE ), STREAM_READWRITE | STREAM_SHARE_DENYWRITE );
+
+ if( pOStm )
+ {
+ pOStm->Write( pData, mnDataSize );
+ sal_Bool bError = ( ERRCODE_NONE != pOStm->GetError() );
+ delete pOStm;
+
+ if( bError )
+ {
+ try
+ {
+ ::ucbhelper::Content aCnt( maURL.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& )
+ {
+ }
+
+ maURL = INetURLObject();
+ }
+ }
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+ImpSwap::~ImpSwap()
+{
+ if( IsSwapped() )
+ {
+ try
+ {
+ ::ucbhelper::Content aCnt( maURL.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& )
+ {
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+BYTE* ImpSwap::GetData() const
+{
+ BYTE* pData;
+
+ if( IsSwapped() )
+ {
+ SvStream* pIStm = ::utl::UcbStreamHelper::CreateStream( maURL.GetMainURL( INetURLObject::NO_DECODE ), 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/imgcons.cxx b/vcl/source/gdi/imgcons.cxx
new file mode 100644
index 000000000000..0826c5f2310b
--- /dev/null
+++ b/vcl/source/gdi/imgcons.cxx
@@ -0,0 +1,574 @@
+/*************************************************************************
+ *
+ * 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 <vcl/bmpacc.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/image.hxx>
+#include <vcl/imgcons.hxx>
+
+// -------------------
+// - ImplColorMapper -
+// -------------------
+
+class ImplColorMapper
+{
+ Color maCol;
+ ULONG mnR;
+ ULONG mnG;
+ ULONG mnB;
+ ULONG mnT;
+ ULONG mnRShift;
+ ULONG mnGShift;
+ ULONG mnBShift;
+ ULONG mnTShift;
+
+ ULONG ImplCalcMaskShift( ULONG nVal );
+
+public:
+
+ ImplColorMapper( ULONG nRMask, ULONG nGMask, ULONG nBMask, ULONG nTMask );
+ ~ImplColorMapper();
+
+ const Color& ImplGetColor( ULONG nColor )
+ {
+ maCol.SetRed( (UINT8) ( ( nColor & mnR ) >> mnRShift ) );
+ maCol.SetGreen( (UINT8) ( ( nColor & mnG ) >> mnGShift ) );
+ maCol.SetBlue( (UINT8) ( ( nColor & mnB ) >> mnBShift ) );
+ maCol.SetTransparency( (UINT8) ( ( nColor & mnT ) >> mnTShift ) );
+ return maCol;
+ }
+};
+
+// -----------------------------------------------------------------------------
+
+ImplColorMapper::ImplColorMapper( ULONG nRMask, ULONG nGMask, ULONG nBMask, ULONG nTMask ) :
+ mnR( nRMask ),
+ mnG( nGMask ),
+ mnB( nBMask ),
+ mnT( nTMask )
+{
+ mnRShift = ImplCalcMaskShift( mnR );
+ mnGShift = ImplCalcMaskShift( mnG );
+ mnBShift = ImplCalcMaskShift( mnB );
+ mnTShift = ImplCalcMaskShift( mnT );
+}
+
+// -----------------------------------------------------------------------------
+
+ImplColorMapper::~ImplColorMapper()
+{
+}
+
+// -----------------------------------------------------------------------------
+
+ULONG ImplColorMapper::ImplCalcMaskShift( ULONG nVal )
+{
+ DBG_ASSERT( nVal > 0, "Mask has no value!" );
+
+ ULONG nRet = 0UL;
+
+ for( ULONG i = 0UL; i < 32; i++ )
+ {
+ if( nVal & ( 1UL << i ) )
+ {
+ nRet = i;
+ break;
+ }
+ }
+
+ return nRet;
+}
+
+// -----------------
+// - ImageConsumer -
+// -----------------
+
+ImageConsumer::ImageConsumer() :
+ mpMapper( NULL ),
+ mpPal ( NULL ),
+ mnStatus( 0UL ),
+ mbTrans ( FALSE )
+{
+}
+
+// -----------------------------------------------------------------------------
+
+ImageConsumer::~ImageConsumer()
+{
+ delete[] mpPal;
+ delete mpMapper;
+}
+
+// -----------------------------------------------------------------------------
+
+void ImageConsumer::Init( sal_uInt32 nWidth, sal_uInt32 nHeight )
+{
+ maSize = Size( nWidth, nHeight );
+ maBitmap = maMask = Bitmap();
+ mnStatus = 0UL;
+ mbTrans = FALSE;
+}
+
+// -----------------------------------------------------------------------------
+
+void ImageConsumer::SetColorModel( USHORT nBitCount,
+ sal_uInt32 nPalEntries, const sal_uInt32* pRGBAPal,
+ sal_uInt32 nRMask, sal_uInt32 nGMask, sal_uInt32 nBMask, sal_uInt32 nAMask )
+{
+ DBG_ASSERT( maSize.Width() && maSize.Height(), "Missing call to ImageConsumer::Init(...)!" );
+
+ BitmapPalette aPal( Min( (USHORT) nPalEntries, (USHORT) 256 ) );
+
+ if( nPalEntries )
+ {
+ BitmapColor aCol;
+ const sal_Int32* pTmp = (sal_Int32*) pRGBAPal;
+
+ delete mpMapper;
+ mpMapper = NULL;
+
+ delete[] mpPal;
+ mpPal = new Color[ nPalEntries ];
+
+ for( ULONG i = 0; i < nPalEntries; i++, pTmp++ )
+ {
+ Color& rCol = mpPal[ i ];
+ BYTE cVal;
+
+ cVal = (BYTE) ( ( *pTmp & 0xff000000UL ) >> 24L );
+ rCol.SetRed( cVal );
+
+ if( i < (ULONG) aPal.GetEntryCount() )
+ aPal[ (USHORT) i ].SetRed( cVal );
+
+ cVal = (BYTE) ( ( *pTmp & 0x00ff0000UL ) >> 16L );
+ rCol.SetGreen( cVal );
+
+ if( i < (ULONG) aPal.GetEntryCount() )
+ aPal[ (USHORT) i ].SetGreen( cVal );
+
+ cVal = (BYTE) ( ( *pTmp & 0x0000ff00UL ) >> 8L );
+ rCol.SetBlue( cVal );
+
+ if( i < (ULONG) aPal.GetEntryCount() )
+ aPal[ (USHORT) i ].SetBlue( cVal );
+
+ rCol.SetTransparency( (BYTE) ( ( *pTmp & 0x000000ffL ) ) );
+ }
+
+ if( nBitCount <= 1 )
+ nBitCount = 1;
+ else if( nBitCount <= 4 )
+ nBitCount = 4;
+ else if( nBitCount <= 8 )
+ nBitCount = 8;
+ else
+ nBitCount = 24;
+ }
+ else
+ {
+ delete mpMapper;
+ mpMapper = new ImplColorMapper( nRMask, nGMask, nBMask, nAMask );
+
+ delete[] mpPal;
+ mpPal = NULL;
+
+ nBitCount = 24;
+ }
+
+ if( !maBitmap )
+ {
+
+ maBitmap = Bitmap( maSize, nBitCount, &aPal );
+ maMask = Bitmap( maSize, 1 );
+ maMask.Erase( COL_BLACK );
+ mbTrans = FALSE;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void ImageConsumer::SetPixelsByBytes( sal_uInt32 nConsX, sal_uInt32 nConsY,
+ sal_uInt32 nConsWidth, sal_uInt32 nConsHeight,
+ const BYTE* pData, sal_uInt32 nOffset, sal_uInt32 nScanSize )
+{
+ DBG_ASSERT( !!maBitmap && !!maMask, "Missing call to ImageConsumer::SetColorModel(...)!" );
+
+ BitmapWriteAccess* pBmpAcc = maBitmap.AcquireWriteAccess();
+ BitmapWriteAccess* pMskAcc = maMask.AcquireWriteAccess();
+ sal_Bool bDataChanged = sal_False;
+
+ if( pBmpAcc && pMskAcc )
+ {
+ const long nWidth = pBmpAcc->Width();
+ const long nHeight = pBmpAcc->Height();
+
+ maChangedRect = Rectangle( Point(), Size( nWidth, nHeight ) );
+ maChangedRect.Intersection( Rectangle( Point( nConsX, nConsY ), Size( nConsWidth, nConsHeight ) ) );
+
+ if( !maChangedRect.IsEmpty() )
+ {
+ const long nStartX = maChangedRect.Left();
+ const long nEndX = maChangedRect.Right();
+ const long nStartY = maChangedRect.Top();
+ const long nEndY = maChangedRect.Bottom();
+
+ if( mpMapper && ( pBmpAcc->GetBitCount() > 8 ) )
+ {
+ BitmapColor aCol;
+ BitmapColor aMskWhite( pMskAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
+
+ for( long nY = nStartY; nY <= nEndY; nY++ )
+ {
+ const BYTE* pTmp = pData + ( nY - nStartY ) * nScanSize + nOffset;
+
+ for( long nX = nStartX; nX <= nEndX; nX++ )
+ {
+ const Color& rCol = mpMapper->ImplGetColor( *pTmp++ );
+
+ // 0: Transparent; >0: Non-Transparent
+ if( !rCol.GetTransparency() )
+ {
+ pMskAcc->SetPixel( nY, nX, aMskWhite );
+ mbTrans = TRUE;
+ }
+ else
+ {
+ aCol.SetRed( rCol.GetRed() );
+ aCol.SetGreen( rCol.GetGreen() );
+ aCol.SetBlue( rCol.GetBlue() );
+ pBmpAcc->SetPixel( nY, nX, aCol );
+ }
+ }
+ }
+
+ bDataChanged = sal_True;
+ }
+ else if( mpPal && ( pBmpAcc->GetBitCount() <= 8 ) )
+ {
+ BitmapColor aIndex( (BYTE) 0 );
+ BitmapColor aMskWhite( pMskAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
+
+ for( long nY = nStartY; nY <= nEndY; nY++ )
+ {
+ const BYTE* pTmp = pData + ( nY - nStartY ) * nScanSize + nOffset;
+
+ for( long nX = nStartX; nX <= nEndX; nX++ )
+ {
+ const BYTE cIndex = *pTmp++;
+ const Color& rCol = mpPal[ cIndex ];
+
+ // 0: Transparent; >0: Non-Transparent
+ if( !rCol.GetTransparency() )
+ {
+ pMskAcc->SetPixel( nY, nX, aMskWhite );
+ mbTrans = TRUE;
+ }
+ else
+ {
+ aIndex.SetIndex( cIndex );
+ pBmpAcc->SetPixel( nY, nX, aIndex );
+ }
+ }
+ }
+
+ bDataChanged = sal_True;
+ }
+ else if( mpPal && ( pBmpAcc->GetBitCount() > 8 ) )
+ {
+ BitmapColor aCol;
+ BitmapColor aMskWhite( pMskAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
+
+ for( long nY = nStartY; nY <= nEndY; nY++ )
+ {
+ const BYTE* pTmp = pData + ( nY - nStartY ) * nScanSize + nOffset;
+
+ for( long nX = nStartX; nX <= nEndX; nX++ )
+ {
+ const BYTE cIndex = *pTmp++;
+ const Color& rCol = mpPal[ cIndex ];
+
+ // 0: Transparent; >0: Non-Transparent
+ if( !rCol.GetTransparency() )
+ {
+ pMskAcc->SetPixel( nY, nX, aMskWhite );
+ mbTrans = TRUE;
+ }
+ else
+ {
+ aCol.SetRed( rCol.GetRed() );
+ aCol.SetGreen( rCol.GetGreen() );
+ aCol.SetBlue( rCol.GetBlue() );
+ pBmpAcc->SetPixel( nY, nX, aCol );
+ }
+ }
+ }
+
+ bDataChanged = sal_True;
+ }
+ else
+ {
+ DBG_ERROR( "Producer format error!" );
+ maChangedRect.SetEmpty();
+ }
+ }
+ }
+ else
+ maChangedRect.SetEmpty();
+
+ maBitmap.ReleaseAccess( pBmpAcc );
+ maMask.ReleaseAccess( pMskAcc );
+
+ if( bDataChanged )
+ DataChanged();
+}
+
+// -----------------------------------------------------------------------------
+
+void ImageConsumer::SetPixelsByLongs( sal_uInt32 nConsX, sal_uInt32 nConsY,
+ sal_uInt32 nConsWidth, sal_uInt32 nConsHeight,
+ const sal_uInt32* pData, sal_uInt32 nOffset, sal_uInt32 nScanSize )
+{
+ DBG_ASSERT( !!maBitmap && !!maMask, "Missing call to ImageConsumer::SetColorModel(...)!" );
+
+ BitmapWriteAccess* pBmpAcc = maBitmap.AcquireWriteAccess();
+ BitmapWriteAccess* pMskAcc = maMask.AcquireWriteAccess();
+ sal_Bool bDataChanged = sal_False;
+
+ if( pBmpAcc && pMskAcc )
+ {
+ const long nWidth = pBmpAcc->Width();
+ const long nHeight = pBmpAcc->Height();
+
+ maChangedRect = Rectangle( Point(), Size( nWidth, nHeight ) );
+ maChangedRect.Intersection( Rectangle( Point( nConsX, nConsY ), Size( nConsWidth, nConsHeight ) ) );
+
+ if( !maChangedRect.IsEmpty() )
+ {
+ const long nStartX = maChangedRect.Left();
+ const long nEndX = maChangedRect.Right();
+ const long nStartY = maChangedRect.Top();
+ const long nEndY = maChangedRect.Bottom();
+
+ if( mpMapper && ( pBmpAcc->GetBitCount() > 8 ) )
+ {
+ BitmapColor aCol;
+ BitmapColor aMskWhite( pMskAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
+
+ for( long nY = nStartY; nY <= nEndY; nY++ )
+ {
+ const sal_Int32* pTmp = (sal_Int32*) pData + ( nY - nStartY ) * nScanSize + nOffset;
+
+ for( long nX = nStartX; nX <= nEndX; nX++ )
+ {
+ const Color& rCol = mpMapper->ImplGetColor( *pTmp++ );
+
+ // 0: Transparent; >0: Non-Transparent
+ if( !rCol.GetTransparency() )
+ {
+ pMskAcc->SetPixel( nY, nX, aMskWhite );
+ mbTrans = TRUE;
+ }
+ else
+ {
+ aCol.SetRed( rCol.GetRed() );
+ aCol.SetGreen( rCol.GetGreen() );
+ aCol.SetBlue( rCol.GetBlue() );
+ pBmpAcc->SetPixel( nY, nX, aCol );
+ }
+ }
+ }
+
+ bDataChanged = sal_True;
+ }
+ else if( mpPal && ( pBmpAcc->GetBitCount() <= 8 ) )
+ {
+ BitmapColor aIndex( (BYTE) 0 );
+ BitmapColor aMskWhite( pMskAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
+
+ for( long nY = nStartY; nY <= nEndY; nY++ )
+ {
+ const sal_Int32* pTmp = (sal_Int32*) pData + ( nY - nStartY ) * nScanSize + nOffset;
+
+ for( long nX = nStartX; nX <= nEndX; nX++ )
+ {
+ const sal_Int32 nIndex = *pTmp++;
+ const Color& rCol = mpPal[ nIndex ];
+
+ // 0: Transparent; >0: Non-Transparent
+ if( !rCol.GetTransparency() )
+ {
+ pMskAcc->SetPixel( nY, nX, aMskWhite );
+ mbTrans = TRUE;
+ }
+ else
+ {
+ aIndex.SetIndex( (BYTE) nIndex );
+ pBmpAcc->SetPixel( nY, nX, aIndex );
+ }
+ }
+ }
+
+ bDataChanged = sal_True;
+ }
+ else if( mpPal && ( pBmpAcc->GetBitCount() > 8 ) )
+ {
+ BitmapColor aCol;
+ BitmapColor aMskWhite( pMskAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
+
+ for( long nY = nStartY; nY <= nEndY; nY++ )
+ {
+ const sal_Int32* pTmp = (sal_Int32*) pData + ( nY - nStartY ) * nScanSize + nOffset;
+
+ for( long nX = nStartX; nX <= nEndX; nX++ )
+ {
+ const sal_Int32 nIndex = *pTmp++;
+ const Color& rCol = mpPal[ nIndex ];
+
+ // 0: Transparent; >0: Non-Transparent
+ if( !rCol.GetTransparency() )
+ {
+ pMskAcc->SetPixel( nY, nX, aMskWhite );
+ mbTrans = TRUE;
+ }
+ else
+ {
+ aCol.SetRed( rCol.GetRed() );
+ aCol.SetGreen( rCol.GetGreen() );
+ aCol.SetBlue( rCol.GetBlue() );
+ pBmpAcc->SetPixel( nY, nX, aCol );
+ }
+ }
+ }
+
+ bDataChanged = sal_True;
+ }
+ else
+ {
+ DBG_ERROR( "Producer format error!" );
+ maChangedRect.SetEmpty();
+ }
+ }
+ }
+ else
+ maChangedRect.SetEmpty();
+
+ maBitmap.ReleaseAccess( pBmpAcc );
+ maMask.ReleaseAccess( pMskAcc );
+
+ if( bDataChanged )
+ DataChanged();
+}
+
+// -----------------------------------------------------------------------------
+
+void ImageConsumer::Completed( sal_uInt32 nStatus /*, ImageProducer& rProducer */ )
+{
+ delete mpMapper;
+ mpMapper = NULL;
+ delete[] mpPal;
+ mpPal = NULL;
+ maSize = Size();
+ mnStatus = nStatus;
+
+ switch( nStatus )
+ {
+ case( SINGLEFRAMEDONE ):
+ case( STATICIMAGEDONE ):
+ {
+ if( !mbTrans )
+ maMask = Bitmap();
+ }
+ break;
+
+ case( IMAGEERROR ):
+ case( IMAGEABORTED ):
+ maBitmap = maMask = Bitmap();
+ break;
+
+ default:
+ break;
+ }
+
+// rProducer.RemoveConsumer( *this );
+
+ if( maDoneLink.IsSet() )
+ maDoneLink.Call( this );
+}
+
+// -----------------------------------------------------------------------------
+
+void ImageConsumer::DataChanged()
+{
+ if( maChgLink.IsSet() )
+ maChgLink.Call( this );
+}
+
+// -----------------------------------------------------------------------------
+
+sal_uInt32 ImageConsumer::GetStatus() const
+{
+ return mnStatus;
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL ImageConsumer::GetData( BitmapEx& rBmpEx ) const
+{
+ const BOOL bRet = ( SINGLEFRAMEDONE == mnStatus || STATICIMAGEDONE == mnStatus );
+
+ if( bRet )
+ {
+ if( !!maMask )
+ rBmpEx = BitmapEx( maBitmap, maMask );
+ else
+ rBmpEx = BitmapEx( maBitmap );
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------------
+
+BOOL ImageConsumer::GetData( Image& rImage ) const
+{
+ const BOOL bRet = ( SINGLEFRAMEDONE == mnStatus || STATICIMAGEDONE == mnStatus );
+
+ if( bRet )
+ {
+ if( !!maMask )
+ rImage = Image( maBitmap, maMask );
+ else
+ rImage = Image( maBitmap );
+ }
+
+ return bRet;
+}
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..f069828f25f9
--- /dev/null
+++ b/vcl/source/gdi/makefile.mk
@@ -0,0 +1,122 @@
+#*************************************************************************
+#
+# 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)$/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)$/imgcons.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)$/outdevnative.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..3826a3dbc7b0
--- /dev/null
+++ b/vcl/source/gdi/outdev2.cxx
@@ -0,0 +1,2278 @@
+/*************************************************************************
+ *
+ * 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 );
+}
+
+// ------------------------------------------------------------------------
+
+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;
+ BYTE nSrcAlpha, nDstAlpha;
+ 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 );
+ nSrcAlpha = 255 - pA->GetPixel( nMapY, nMapX ).GetBlueOrIndex();
+ nDstAlpha = 255 - pAlphaW->GetPixel( nY, nX ).GetBlueOrIndex();
+
+ if( nSrcAlpha + nDstAlpha == 0 )
+ {
+ // #i70653# zero alpha -> zero color values
+ aIndex.SetIndex( (BYTE) ( nVCLRLut[ ( nVCLLut[ 0 ] + nD ) >> 16UL ] +
+ nVCLGLut[ ( nVCLLut[ 0 ] + nD ) >> 16UL ] +
+ nVCLBLut[ ( nVCLLut[ 0 ] + nD ) >> 16UL ] ) );
+ }
+ else
+ {
+ aDstCol.SetRed( (BYTE)(((int)(aSrcCol.GetRed())*nSrcAlpha + (int)(aDstCol.GetRed())*nDstAlpha) /
+ (nSrcAlpha+nDstAlpha)) );
+ aDstCol.SetGreen( (BYTE)(((int)(aSrcCol.GetGreen())*nSrcAlpha + (int)(aDstCol.GetGreen())*nDstAlpha) /
+ (nSrcAlpha+nDstAlpha)) );
+ aDstCol.SetBlue( (BYTE)(((int)(aSrcCol.GetBlue())*nSrcAlpha + (int)(aDstCol.GetBlue())*nDstAlpha) /
+ (nSrcAlpha+nDstAlpha)) );
+
+ 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.
+ nSrcAlpha = 255-COLOR_CHANNEL_MERGE( 255, (BYTE)nDstAlpha, nSrcAlpha );
+
+ 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 );
+ nSrcAlpha = 255 - pA->GetPixel( nMapY, nMapX ).GetBlueOrIndex();
+ nDstAlpha = 255 - pAlphaW->GetPixel( nY, nX ).GetBlueOrIndex();
+
+ if( nSrcAlpha + nDstAlpha == 0 )
+ {
+ // #i70653# zero alpha -> zero color values
+ aDstCol.SetRed(0);
+ aDstCol.SetGreen(0);
+ aDstCol.SetBlue(0);
+ }
+ else
+ {
+ aDstCol.SetRed( (BYTE)(((int)(aSrcCol.GetRed())*nSrcAlpha + (int)(aDstCol.GetRed())*nDstAlpha) /
+ (nSrcAlpha+nDstAlpha)) );
+ aDstCol.SetGreen( (BYTE)(((int)(aSrcCol.GetGreen())*nSrcAlpha + (int)(aDstCol.GetGreen())*nDstAlpha) /
+ (nSrcAlpha+nDstAlpha)) );
+ aDstCol.SetBlue( (BYTE)(((int)(aSrcCol.GetBlue())*nSrcAlpha + (int)(aDstCol.GetBlue())*nDstAlpha) /
+ (nSrcAlpha+nDstAlpha)) );
+ }
+
+ 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.
+ nSrcAlpha = 255-COLOR_CHANNEL_MERGE( 255, (BYTE)nDstAlpha, nSrcAlpha );
+
+ 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..949d3df5275f
--- /dev/null
+++ b/vcl/source/gdi/outdev3.cxx
@@ -0,0 +1,8021 @@
+/*************************************************************************
+ *
+ * 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
+ if( (rSearchFamilyName.Len() && pData->maMatchFamilyName.Len())
+ && ((rSearchFamilyName.Search( pData->maMatchFamilyName ) != STRING_NOTFOUND)
+ || (pData->maMatchFamilyName.Search( rSearchFamilyName ) != STRING_NOTFOUND)) )
+ nTestMatch += 100000*2;
+
+ // 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..47b150ddc4c5
--- /dev/null
+++ b/vcl/source/gdi/outdev6.cxx
@@ -0,0 +1,1231 @@
+/*************************************************************************
+ *
+ * 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 )
+ {
+ 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;
+ // TODO What is the correct VALUE???
+ default: nMove = 0; break;
+ }
+
+ Push( PUSH_CLIPREGION | PUSH_LINECOLOR );
+ IntersectClipRegion( rPolyPoly );
+ SetLineColor( GetFillColor() );
+
+ Rectangle aRect( aPolyRect.TopLeft(), Size( aPolyRect.GetWidth(), nBaseExtent ) );
+
+ const BOOL bOldMap = mbMap;
+ EnableMapMode( FALSE );
+
+ 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 );
+ }
+
+ 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;
+ Region aCtrlRegion( Rectangle( 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..fed41ec4de85
--- /dev/null
+++ b/vcl/source/gdi/outdevnative.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 "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;
+ }
+}
+
+// -----------------------------------------------------------------------
+// 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 Region& rControlRegion,
+ const Point& aPos,
+ BOOL& rIsInside )
+{
+ if( !lcl_enableNativeWidget( *this ) )
+ return FALSE;
+
+ if ( !mpGraphics )
+ if ( !ImplGetGraphics() )
+ return FALSE;
+
+ Point aWinOffs( mnOutOffX, mnOutOffY );
+ Region screenRegion( rControlRegion );
+ screenRegion.Move( aWinOffs.X(), aWinOffs.Y());
+
+ return( mpGraphics->HitTestNativeControl(nType, nPart, screenRegion, Point( aPos.X() + mnOutOffX, aPos.Y() + mnOutOffY ),
+ rIsInside, this ) );
+}
+
+// -----------------------------------------------------------------------
+
+static void lcl_moveControlValue( ControlType nType, const ImplControlValue& aValue, const Point& rDelta )
+{
+ if( aValue.getOptionalVal() )
+ {
+ switch( nType )
+ {
+ case CTRL_SLIDER:
+ {
+ SliderValue* pSlVal = reinterpret_cast<SliderValue*>(aValue.getOptionalVal());
+ pSlVal->maThumbRect.Move( rDelta.X(), rDelta.Y() );
+ }
+ break;
+ case CTRL_SCROLLBAR:
+ {
+ ScrollbarValue* pScVal = reinterpret_cast<ScrollbarValue*>(aValue.getOptionalVal());
+ 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 = reinterpret_cast<SpinbuttonValue*>(aValue.getOptionalVal());
+ pSpVal->maUpperRect.Move( rDelta.X(), rDelta.Y() );
+ pSpVal->maLowerRect.Move( rDelta.X(), rDelta.Y() );
+ }
+ break;
+ case CTRL_TOOLBAR:
+ {
+ ToolbarValue* pTVal = reinterpret_cast<ToolbarValue*>(aValue.getOptionalVal());
+ pTVal->maGripRect.Move( rDelta.X(), rDelta.Y() );
+ }
+ break;
+ }
+ }
+}
+
+BOOL OutputDevice::DrawNativeControl( ControlType nType,
+ ControlPart nPart,
+ const Region& 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
+ Point aWinOffs( mnOutOffX, mnOutOffY );
+ Region screenRegion( rControlRegion );
+ screenRegion.Move( aWinOffs.X(), aWinOffs.Y());
+
+ // do so for ImplControlValue members, also
+ lcl_moveControlValue( nType, aValue, aWinOffs );
+
+ 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, aValue, aCaption, this );
+
+ // transform back ImplControlValue members
+ lcl_moveControlValue( nType, aValue, Point()-aWinOffs );
+
+ return bRet;
+}
+
+
+// -----------------------------------------------------------------------
+
+BOOL OutputDevice::DrawNativeControlText(ControlType nType,
+ ControlPart nPart,
+ const Region& 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
+ Point aWinOffs( mnOutOffX, mnOutOffY );
+ Region screenRegion( rControlRegion );
+ screenRegion.Move( aWinOffs.X(), aWinOffs.Y());
+ lcl_moveControlValue( nType, aValue, aWinOffs );
+
+ BOOL bRet = mpGraphics->DrawNativeControlText(nType, nPart, screenRegion, nState, aValue, aCaption, this );
+
+ // transform back ImplControlValue members
+ lcl_moveControlValue( nType, aValue, Point()-aWinOffs );
+
+ return bRet;
+}
+
+
+// -----------------------------------------------------------------------
+
+BOOL OutputDevice::GetNativeControlRegion( ControlType nType,
+ ControlPart nPart,
+ const Region& rControlRegion,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ ::rtl::OUString aCaption,
+ Region &rNativeBoundingRegion,
+ Region &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
+ Point aWinOffs( mnOutOffX, mnOutOffY );
+ Region screenRegion( rControlRegion );
+ screenRegion.Move( aWinOffs.X(), aWinOffs.Y());
+ lcl_moveControlValue( nType, aValue, aWinOffs );
+
+ BOOL bRet = mpGraphics->GetNativeControlRegion(nType, nPart, screenRegion, nState, aValue,
+ aCaption, rNativeBoundingRegion,
+ rNativeContentRegion, this );
+ if( bRet )
+ {
+ // transform back native regions
+ rNativeBoundingRegion.Move( -aWinOffs.X(), -aWinOffs.Y() );
+ rNativeContentRegion.Move( -aWinOffs.X(), -aWinOffs.Y() );
+ }
+ // transform back ImplControlValue members
+ lcl_moveControlValue( nType, aValue, Point()-aWinOffs );
+
+ 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..6cb0a7d07697
--- /dev/null
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -0,0 +1,12304 @@
+/*************************************************************************
+ *
+ * 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 <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 100644
index 000000000000..191f8f26dc75
--- /dev/null
+++ b/vcl/source/gdi/print3.cxx
@@ -0,0 +1,1866 @@
+/*************************************************************************
+ *
+ * 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 nRepeatCount = bUserCopy ? mnCopyCount : 1;
+ if( bSinglePrintJobs )
+ {
+ nJobs = mnCopyCount;
+ nCopies = 1;
+ nRepeatCount = 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 nIteration = 0; nIteration < nRepeatCount; nIteration++ )
+ {
+ for( int nPage = 0; nPage < nPages; nPage++ )
+ {
+ if( nPage == nPages-1 && nIteration == nRepeatCount-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 100644
index 000000000000..7a6808a0e392
--- /dev/null
+++ b/vcl/source/gdi/salgdilayout.cxx
@@ -0,0 +1,823 @@
+/*************************************************************************
+ *
+ * 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 Region& rControlRegion,
+ const Point& aPos, BOOL& rIsInside, const OutputDevice *pOutDev )
+{
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) )
+ {
+ Point pt( aPos );
+ Region 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 nType, const ImplControlValue& rVal, const OutputDevice* pOutDev, bool bBack ) const
+{
+ if( rVal.getOptionalVal() )
+ {
+ switch( nType )
+ {
+ case CTRL_SLIDER:
+ {
+ SliderValue* pSlVal = reinterpret_cast<SliderValue*>(rVal.getOptionalVal());
+ mirror(pSlVal->maThumbRect,pOutDev,bBack);
+ }
+ break;
+ case CTRL_SCROLLBAR:
+ {
+ ScrollbarValue* pScVal = reinterpret_cast<ScrollbarValue*>(rVal.getOptionalVal());
+ mirror(pScVal->maThumbRect,pOutDev,bBack);
+ mirror(pScVal->maButton1Rect,pOutDev,bBack);
+ mirror(pScVal->maButton2Rect,pOutDev,bBack);
+ }
+ break;
+ case CTRL_SPINBOX:
+ case CTRL_SPINBUTTONS:
+ {
+ SpinbuttonValue* pSpVal = reinterpret_cast<SpinbuttonValue*>(rVal.getOptionalVal());
+ mirror(pSpVal->maUpperRect,pOutDev,bBack);
+ mirror(pSpVal->maLowerRect,pOutDev,bBack);
+ }
+ break;
+ case CTRL_TOOLBAR:
+ {
+ ToolbarValue* pTVal = reinterpret_cast<ToolbarValue*>(rVal.getOptionalVal());
+ mirror(pTVal->maGripRect,pOutDev,bBack);
+ }
+ break;
+ }
+ }
+}
+
+BOOL SalGraphics::DrawNativeControl( ControlType nType, ControlPart nPart, const Region& rControlRegion,
+ ControlState nState, const ImplControlValue& aValue,
+ const OUString& aCaption, const OutputDevice *pOutDev )
+{
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) )
+ {
+ Region 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 Region& rControlRegion,
+ ControlState nState, const ImplControlValue& aValue,
+ const OUString& aCaption, const OutputDevice *pOutDev )
+{
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) )
+ {
+ Region 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 Region& rControlRegion, ControlState nState,
+ const ImplControlValue& aValue, const OUString& aCaption,
+ Region &rNativeBoundingRegion, Region &rNativeContentRegion, const OutputDevice *pOutDev )
+{
+ if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (pOutDev && pOutDev->IsRTLEnabled()) )
+ {
+ Region 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..7faf12d062fe
--- /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 Region&,
+ 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 Region&,
+ 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 Region&,
+ 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 Region&,
+ ControlState,
+ const ImplControlValue&,
+ const OUString&,
+ Region &,
+ Region & )
+{
+ 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..f66f5b48e39e
--- /dev/null
+++ b/vcl/source/glyphs/graphite_adaptors.cxx
@@ -0,0 +1,326 @@
+/*************************************************************************
+ *
+ * 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.
+ const sal_Unicode * name = font.GetFontSelData().maName.GetBuffer();
+ const size_t name_sz = std::min(sizeof szFaceName/sizeof(wchar_t)-1,
+ size_t(font.GetFontSelData().maName.Len()));
+
+ std::copy(name, name + 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)
+{
+ //std::wstring face_name(maFontProperties.szFaceName);
+ const rtl::OString aLang = MsLangId::convertLanguageToIsoByteString( sfont.GetFontSelData().meLanguage );
+#ifdef DEBUG
+ printf("GraphiteFontAdaptor %lx\n", (long)this);
+#endif
+ rtl::OString name = rtl::OUStringToOString(
+ sfont.GetFontSelData().maTargetName, RTL_TEXTENCODING_UTF8 );
+ 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)
+{
+ // Graphite gets really confused if the glyphs have been transformed, so
+ // if orientation has been set we can't use the font's glyph cache
+ // unfortunately the font selection data, doesn't always have the orientation
+ // set, even if it was when the glyphs were cached, so we use our own cache.
+
+// 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();
+
+ 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
diff --git a/vcl/source/glyphs/graphite_cache.cxx b/vcl/source/glyphs/graphite_cache.cxx
new file mode 100644
index 000000000000..64bbb0a38d60
--- /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() > SEG_CACHE_SIZE)
+ {
+ 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..ff2fd8f306b1
--- /dev/null
+++ b/vcl/source/glyphs/graphite_layout.cxx
@@ -0,0 +1,1487 @@
+/*************************************************************************
+ *
+ * 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
+
+#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 fMinX = rSegment.advanceWidth();
+ 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, 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, 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, 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 = rSeg.advanceWidth();
+ nNextOrigin = round(rSeg.advanceWidth() * fScaling + rDXOffset);
+ aBounds.second = std::max(rSeg.advanceWidth(), 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(false);
+ // 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);
+ 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;
+ };
+
+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
+ {
+ 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,%ld ", (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,%ld ", (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%d last glyph %d/%d\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 %ld(%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 %ld\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,%ld-%ld\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..2b9c705a5ea7
--- /dev/null
+++ b/vcl/source/glyphs/graphite_textsrc.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#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);
+
+ 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..8eedf76043da
--- /dev/null
+++ b/vcl/source/window/brdwin.cxx
@@ -0,0 +1,2354 @@
+/*************************************************************************
+ *
+ * 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;
+ Region aCtrlRegion( Rectangle( (const Point&)Point(), Size( mnWidth < 10 ? 10 : mnWidth, mnHeight < 10 ? 10 : mnHeight ) ) );
+ Region aBoundingRgn( aCtrlRegion );
+ Region aContentRgn( aCtrlRegion );
+ if( pWin->GetNativeControlRegion( aCtrlType, PART_ENTIRE_CONTROL, aCtrlRegion,
+ CTRL_STATE_ENABLED, aControlValue, rtl::OUString(),
+ aBoundingRgn, aContentRgn ) )
+ {
+ Rectangle aBounds( aBoundingRgn.GetBoundRect() );
+ Rectangle aContent( aContentRgn.GetBoundRect() );
+ 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;
+ Region aCtrlRegion( Rectangle( aPoint, Size( mnWidth, mnHeight ) ) );
+
+ Region aBoundingRgn( Rectangle( aPoint, Size( mnWidth, mnHeight ) ) );
+ Region 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..a32790cfb0d4
--- /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 );
+ Region aBound, aContent;
+ Region aNatRgn( rRect );
+ if(pWin && pWin->GetNativeControlRegion(CTRL_FRAME, PART_BORDER,
+ aNatRgn, 0, aControlValue, rtl::OUString(), aBound, aContent) )
+ {
+ rRect = aContent.GetBoundRect();
+ }
+ 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 );
+ Region aBound, aContent;
+ Region 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.GetBoundRect();
+ 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..efc49be6fbf8
--- /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 <dndevdis.hxx>
+#include <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/dndevdis.hxx b/vcl/source/window/dndevdis.hxx
new file mode 100644
index 000000000000..5b91bd0713ec
--- /dev/null
+++ b/vcl/source/window/dndevdis.hxx
@@ -0,0 +1,114 @@
+/*************************************************************************
+ *
+ * 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 _DNDEVDIS_HXX_
+#define _DNDEVDIS_HXX_
+
+#include <com/sun/star/datatransfer/dnd/XDropTargetListener.hpp>
+#include <com/sun/star/datatransfer/dnd/XDropTargetDragContext.hpp>
+
+#ifndef _COM_SUN_STAR_DATATRANSFER_DND_XDRAGESTURERECOGNIZER_HPP_
+#include <com/sun/star/datatransfer/dnd/XDragGestureRecognizer.hpp>
+#endif
+#include <cppuhelper/implbase3.hxx>
+#include <vcl/window.hxx>
+
+class DNDEventDispatcher: public ::cppu::WeakImplHelper3<
+ ::com::sun::star::datatransfer::dnd::XDropTargetListener,
+ ::com::sun::star::datatransfer::dnd::XDropTargetDragContext,
+ ::com::sun::star::datatransfer::dnd::XDragGestureListener >
+{
+ Window * m_pTopWindow;
+ Window * m_pCurrentWindow;
+
+ ::osl::Mutex m_aMutex;
+ ::com::sun::star::uno::Sequence< ::com::sun::star::datatransfer::DataFlavor > m_aDataFlavorList;
+
+ /*
+ * fire the events on the dnd listener container of the specified window
+ */
+
+ sal_Int32 fireDragEnterEvent( Window *pWindow, const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDropTargetDragContext >& xContext,
+ const sal_Int8 nDropAction, const Point& rLocation, const sal_Int8 nSourceAction,
+ const ::com::sun::star::uno::Sequence< ::com::sun::star::datatransfer::DataFlavor >& aFlavorList ) throw(::com::sun::star::uno::RuntimeException);
+
+ sal_Int32 fireDragOverEvent( Window *pWindow, const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDropTargetDragContext >& xContext,
+ const sal_Int8 nDropAction, const Point& rLocation, const sal_Int8 nSourceAction ) throw(::com::sun::star::uno::RuntimeException);
+
+ sal_Int32 fireDragExitEvent( Window *pWindow ) throw(::com::sun::star::uno::RuntimeException);
+
+ sal_Int32 fireDropActionChangedEvent( Window *pWindow, const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDropTargetDragContext >& xContext,
+ const sal_Int8 nDropAction, const Point& rLocation, const sal_Int8 nSourceAction ) throw(::com::sun::star::uno::RuntimeException);
+
+ sal_Int32 fireDropEvent( Window *pWindow, const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDropTargetDropContext >& xContext,
+ const sal_Int8 nDropAction, const Point& rLocation, const sal_Int8 nSourceAction,
+ const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >& xTransferable ) throw(::com::sun::star::uno::RuntimeException);
+
+ sal_Int32 fireDragGestureEvent( Window *pWindow, const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSource >& xSource,
+ const ::com::sun::star::uno::Any event, const Point& rOrigin, const sal_Int8 nDragAction )throw(::com::sun::star::uno::RuntimeException);
+
+public:
+
+ DNDEventDispatcher( Window * pTopWindow );
+ virtual ~DNDEventDispatcher();
+
+ /*
+ * XDropTargetDragContext
+ */
+
+ virtual void SAL_CALL acceptDrag( sal_Int8 dropAction ) throw(::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL rejectDrag() throw(::com::sun::star::uno::RuntimeException);
+
+ /*
+ * XDropTargetListener
+ */
+
+ virtual void SAL_CALL drop( const ::com::sun::star::datatransfer::dnd::DropTargetDropEvent& dtde ) throw(::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL dragEnter( const ::com::sun::star::datatransfer::dnd::DropTargetDragEnterEvent& dtdee ) throw(::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL dragExit( const ::com::sun::star::datatransfer::dnd::DropTargetEvent& dte ) throw(::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL dragOver( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& dtde ) throw(::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL dropActionChanged( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& dtde ) throw(::com::sun::star::uno::RuntimeException);
+
+ /*
+ * XDragGestureListener
+ */
+
+ virtual void SAL_CALL dragGestureRecognized( const ::com::sun::star::datatransfer::dnd::DragGestureEvent& dge ) throw(::com::sun::star::uno::RuntimeException);
+
+
+ /*
+ * XEventListener
+ */
+
+ virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& eo ) throw(::com::sun::star::uno::RuntimeException);
+};
+
+//==================================================================================================
+//
+//==================================================================================================
+
+#endif
diff --git a/vcl/source/window/dndlcon.cxx b/vcl/source/window/dndlcon.cxx
new file mode 100644
index 000000000000..c5d78dd6bae3
--- /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<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/dndlcon.hxx b/vcl/source/window/dndlcon.hxx
new file mode 100644
index 000000000000..5a41a20e4271
--- /dev/null
+++ b/vcl/source/window/dndlcon.hxx
@@ -0,0 +1,124 @@
+/*************************************************************************
+ *
+ * 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 _DNDLCON_HXX_
+#define _DNDLCON_HXX_
+
+#include <com/sun/star/datatransfer/dnd/XDragGestureRecognizer.hpp>
+#include <com/sun/star/datatransfer/dnd/XDragSource.hpp>
+#include <com/sun/star/datatransfer/dnd/XDropTarget.hpp>
+#include <com/sun/star/datatransfer/dnd/XDropTargetDragContext.hpp>
+#include <com/sun/star/datatransfer/dnd/XDropTargetDropContext.hpp>
+#include <cppuhelper/compbase4.hxx>
+
+#include <vcl/unohelp2.hxx>
+
+class DNDListenerContainer : public ::vcl::unohelper::MutexHelper,
+ public ::cppu::WeakComponentImplHelper4<
+ ::com::sun::star::datatransfer::dnd::XDragGestureRecognizer, \
+ ::com::sun::star::datatransfer::dnd::XDropTargetDragContext,
+ ::com::sun::star::datatransfer::dnd::XDropTargetDropContext,
+ ::com::sun::star::datatransfer::dnd::XDropTarget >
+{
+ sal_Bool m_bActive;
+ sal_Int8 m_nDefaultActions;
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDropTargetDragContext > m_xDropTargetDragContext;
+ ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDropTargetDropContext > m_xDropTargetDropContext;
+
+public:
+
+ DNDListenerContainer( sal_Int8 nDefaultActions );
+ virtual ~DNDListenerContainer();
+
+ sal_uInt32 fireDropEvent(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDropTargetDropContext >& context,
+ sal_Int8 dropAction, sal_Int32 locationX, sal_Int32 locationY, sal_Int8 sourceActions,
+ const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >& transferable );
+
+ sal_uInt32 fireDragExitEvent();
+
+ sal_uInt32 fireDragOverEvent(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDropTargetDragContext >& context,
+ sal_Int8 dropAction, sal_Int32 locationX, sal_Int32 locationY, sal_Int8 sourceActions );
+
+ sal_uInt32 fireDragEnterEvent(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDropTargetDragContext >& context,
+ sal_Int8 dropAction, sal_Int32 locationX, sal_Int32 locationY, sal_Int8 sourceActions,
+ const ::com::sun::star::uno::Sequence< ::com::sun::star::datatransfer::DataFlavor >& dataFlavor );
+
+ sal_uInt32 fireDropActionChangedEvent(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDropTargetDragContext >& context,
+ sal_Int8 dropAction, sal_Int32 locationX, sal_Int32 locationY, sal_Int8 sourceActions );
+
+ sal_uInt32 fireDragGestureEvent(
+ sal_Int8 dragAction, sal_Int32 dragOriginX, sal_Int32 dragOriginY,
+ const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSource >& dragSource,
+ const ::com::sun::star::uno::Any& triggerEvent );
+
+ /*
+ * XDragGestureRecognizer
+ */
+
+ virtual void SAL_CALL addDragGestureListener( const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragGestureListener >& dgl ) throw(::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL removeDragGestureListener( const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragGestureListener >& dgl ) throw(::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL resetRecognizer( ) throw(::com::sun::star::uno::RuntimeException);
+
+ /*
+ * XDropTargetDragContext
+ */
+
+ virtual void SAL_CALL acceptDrag( sal_Int8 dragOperation ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL rejectDrag( ) throw (::com::sun::star::uno::RuntimeException);
+
+
+ /*
+ * XDropTargetDropContext
+ */
+
+ virtual void SAL_CALL acceptDrop( sal_Int8 dropOperation ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL rejectDrop( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL dropComplete( sal_Bool success ) throw (::com::sun::star::uno::RuntimeException);
+
+ /*
+ * XDropTarget
+ */
+
+ virtual void SAL_CALL addDropTargetListener( const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDropTargetListener >& dtl ) throw(::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL removeDropTargetListener( const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDropTargetListener >& dtl ) throw(::com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL isActive( ) throw(::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL setActive( sal_Bool active ) throw(::com::sun::star::uno::RuntimeException);
+ virtual sal_Int8 SAL_CALL getDefaultActions( ) throw(::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL setDefaultActions( sal_Int8 actions ) throw(::com::sun::star::uno::RuntimeException);
+};
+
+
+//==================================================================================================
+//
+//==================================================================================================
+
+#endif
diff --git a/vcl/source/window/dockingarea.cxx b/vcl/source/window/dockingarea.cxx
new file mode 100644
index 000000000000..95e6c6113c45
--- /dev/null
+++ b/vcl/source/window/dockingarea.cxx
@@ -0,0 +1,248 @@
+/*************************************************************************
+ *
+ * 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 ) )
+ {
+ ImplControlValue aControlValue;
+ ToolbarValue aToolbarValue;
+
+ 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
+ aToolbarValue.mbIsTopDockingArea = TRUE;
+ }
+ aControlValue.setOptionalVal( (void *)(&aToolbarValue) );
+ ControlState nState = CTRL_STATE_ENABLED;
+
+ if( !ImplGetSVData()->maNWFData.mbDockingAreaSeparateTB )
+ {
+ // draw a single toolbar background covering the whole docking area
+ Point tmp;
+ Region aCtrlRegion( Rectangle( 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,
+ Region( 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..1723d26ce399
--- /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 = MENU_FLAG_SHOWCHECKIMAGES;
+ 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;
+ Region aNativeBounds;
+ Region aNativeContent;
+ Point tmp( 0, 0 );
+ Region 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.GetBoundRect().GetHeight();
+ rMaxWidth = aNativeContent.GetBoundRect().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.GetBoundRect().GetHeight();
+ rMaxWidth = Max (rMaxWidth, aNativeContent.GetBoundRect().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;
+
+ 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 )))
+ {
+ 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)
+ {
+ // 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)
+ {
+ 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;
+ Region aNativeBounds;
+ Region aNativeContent;
+ Point tmp( 0, 0 );
+ Region aCtrlRegion( Rectangle( 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.GetBoundRect().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;
+ Region 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,
+ Region( 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,
+ Region( 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,
+ Region( 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,
+ Region( 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)
+ ImplControlValue aControlValue;
+ MenubarValue aMenubarValue;
+ aMenubarValue.maTopDockingAreaHeight = ImplGetTopDockingAreaHeight( this );
+ aControlValue.setOptionalVal( (void *)(&aMenubarValue) );
+
+ Point tmp(0,0);
+ Region aBgRegion( Rectangle( tmp, GetOutputSizePixel() ) );
+ DrawNativeControl( CTRL_MENUBAR, PART_ENTIRE_CONTROL,
+ aBgRegion,
+ CTRL_STATE_ENABLED,
+ aControlValue,
+ OUString() );
+ ImplAddNWFSeparator( this, aMenubarValue );
+
+ // draw selected item
+ DrawNativeControl( CTRL_MENUBAR, PART_MENU_ITEM,
+ Region( 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) )
+ {
+ ImplControlValue aControlValue;
+ MenubarValue aMenubarValue;
+ aMenubarValue.maTopDockingAreaHeight = ImplGetTopDockingAreaHeight( this );
+ aControlValue.setOptionalVal( (void *)(&aMenubarValue) );
+
+ // use full window size to get proper gradient
+ // but clip accordingly
+ Point aPt;
+ Rectangle aCtrlRect( aPt, GetOutputSizePixel() );
+ Region aCtrlRegion( aCtrlRect );
+
+ DrawNativeControl( CTRL_MENUBAR, PART_ENTIRE_CONTROL, aCtrlRegion, CTRL_STATE_ENABLED, aControlValue, 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;
+ Region aCtrlRegion( Rectangle( aPt, GetOutputSizePixel() ) );
+
+ ImplControlValue aControlValue;
+ MenubarValue aMenubarValue;
+ aMenubarValue.maTopDockingAreaHeight = ImplGetTopDockingAreaHeight( this );
+ aControlValue.setOptionalVal( (void *)(&aMenubarValue) );
+
+ DrawNativeControl( CTRL_MENUBAR, PART_ENTIRE_CONTROL, aCtrlRegion, CTRL_STATE_ENABLED, aControlValue, 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..35077b1cff0e
--- /dev/null
+++ b/vcl/source/window/printdlg.cxx
@@ -0,0 +1,2601 @@
+/*************************************************************************
+ *
+ * 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( 5, 5 ), MapMode( MAP_APPFONT ) ) );
+ long nIndent = 3*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;
+ Region aControlRegion( Rectangle( Point(), Size( 100, mnProgressHeight ) ) );
+ Region aNativeControlRegion, aNativeContentRegion;
+ if( GetNativeControlRegion( CTRL_PROGRESS, PART_ENTIRE_CONTROL, aControlRegion,
+ CTRL_STATE_ENABLED, aValue, rtl::OUString(),
+ aNativeControlRegion, aNativeContentRegion ) )
+ {
+ mnProgressHeight = aNativeControlRegion.GetBoundRect().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..c139ae1ffb30
--- /dev/null
+++ b/vcl/source/window/status.cxx
@@ -0,0 +1,1795 @@
+/*************************************************************************
+ *
+ * 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 ) );
+ Region 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;
+ Region aControlRegion( Rectangle( (const Point&)Point(), maPrgsFrameRect.GetSize() ) );
+ Region aNativeControlRegion, aNativeContentRegion;
+ if( (bNativeOK = GetNativeControlRegion( CTRL_PROGRESS, PART_ENTIRE_CONTROL, aControlRegion,
+ CTRL_STATE_ENABLED, aValue, rtl::OUString(),
+ aNativeControlRegion, aNativeContentRegion ) ) != FALSE )
+ {
+ long nProgressHeight = aNativeControlRegion.GetBoundRect().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;
+ Region aControlRegion( Rectangle( (const Point&)Point(), Size( nCalcWidth, nMinHeight ) ) );
+ Region aNativeControlRegion, aNativeContentRegion;
+ if( pThis->GetNativeControlRegion( CTRL_PROGRESS, PART_ENTIRE_CONTROL, aControlRegion,
+ CTRL_STATE_ENABLED, aValue, rtl::OUString(),
+ aNativeControlRegion, aNativeContentRegion ) )
+ {
+ nProgressHeight = aNativeControlRegion.GetBoundRect().GetHeight();
+ }
+ }
+
+ if( mpImplData->mbDrawItemFrames &&
+ pThis->IsNativeControlSupported( CTRL_FRAME, PART_BORDER ) )
+ {
+ ImplControlValue aControlValue( FRAME_DRAW_NODRAW );
+ Region aBound, aContent;
+ Region aNatRgn( Rectangle( Point( 0, 0 ), Size( 150, 50 ) ) );
+ if( pThis->GetNativeControlRegion(CTRL_FRAME, PART_BORDER,
+ aNatRgn, 0, aControlValue, rtl::OUString(), aBound, aContent) )
+ {
+ mpImplData->mnItemBorderWidth =
+ ( aBound.GetBoundRect().GetHeight() -
+ aContent.GetBoundRect().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..7bfd115af8f9
--- /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( BUTTONVALUE_DONTKNOW, rtl::OUString(), 0 );
+
+ 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
+ Region aCtrlRegion( Rectangle( 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..9ad0b8734437
--- /dev/null
+++ b/vcl/source/window/toolbox.cxx
@@ -0,0 +1,6336 @@
+/*************************************************************************
+ *
+ * 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;
+ Region aContent, aBound;
+ Region aArea( Rectangle(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.GetBoundRect().GetWidth() : aContent.GetBoundRect().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 ) )
+ {
+ ImplControlValue aControlValue;
+ ToolbarValue aToolbarValue;
+ aToolbarValue.maGripRect = pWrapper->GetDragArea();
+ aControlValue.setOptionalVal( (void *)(&aToolbarValue) );
+ Point aPt;
+ Region aCtrlRegion( Rectangle( aPt, pThis->GetOutputSizePixel() ) );
+ ControlState nState = CTRL_STATE_ENABLED;
+
+ bNativeOk = pThis->DrawNativeControl( CTRL_TOOLBAR, pThis->mbHorz ? PART_THUMB_VERT : PART_THUMB_HORZ,
+ aCtrlRegion, nState, aControlValue, 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;
+ Region aCtrlRegion( Rectangle( 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 ) );
+ Region aReg = aRect;
+ ImplControlValue aVal;
+ Region 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.GetBoundRect();
+ 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.GetBoundRect();
+ 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.GetBoundRect();
+ 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.GetBoundRect();
+ 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;
+ Region aCtrlRegion( rRect );
+ 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,
+ aCtrlRegion, 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..ebeb5c94d68a
--- /dev/null
+++ b/vcl/source/window/window.cxx
@@ -0,0 +1,9973 @@
+/*************************************************************************
+ *
+ * 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 "dndlcon.hxx"
+#include "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;
+ Region aCtrlRegion( (const Rectangle&)Rectangle( Point(), Size( nTextWidth < 10 ? 10 : nTextWidth, nTextHeight < 10 ? 10 : nTextHeight ) ) );
+ Region aBoundingRgn( aCtrlRegion );
+ Region aContentRgn( aCtrlRegion );
+ if( pWindow->GetNativeControlRegion( CTRL_EDITBOX, PART_ENTIRE_CONTROL, aCtrlRegion,
+ CTRL_STATE_ENABLED, aControlValue, rtl::OUString(),
+ aBoundingRgn, aContentRgn ) )
+ {
+ Rectangle aContentRect( aContentRgn.GetBoundRect() );
+ // comment: the magical +6 is for the extra border in bordered
+ // (which is the standard) edit fields
+ if( aContentRect.GetHeight() - nTextHeight > (nTextHeight+4)/4 )
+ pSVData->maGDIData.mnAppFontY = (aContentRect.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..7b0512a1320b
--- /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 <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;
+}
diff --git a/vcl/test/canvasbitmaptest.cxx b/vcl/test/canvasbitmaptest.cxx
new file mode 100644
index 000000000000..1b70161d6cb0
--- /dev/null
+++ b/vcl/test/canvasbitmaptest.cxx
@@ -0,0 +1,1046 @@
+/*************************************************************************
+ *
+ * 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"
+
+// bootstrap stuff
+#include <sal/main.h>
+#include <rtl/bootstrap.hxx>
+#include <rtl/ref.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/regpathhelper.hxx>
+#include <cppuhelper/servicefactory.hxx>
+#include <cppuhelper/bootstrap.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/registry/XSimpleRegistry.hpp>
+#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 <com/sun/star/rendering/XIntegerReadOnlyBitmap.hpp>
+#include <com/sun/star/rendering/XIntegerBitmapColorSpace.hpp>
+#include <com/sun/star/rendering/XBitmapPalette.hpp>
+
+#include <ucbhelper/contentbroker.hxx>
+#include <ucbhelper/configurationkeys.hxx>
+#include <cppuhelper/compbase3.hxx>
+
+#include <tools/diagnose_ex.h>
+#include <tools/extendapplicationenvironment.hxx>
+
+#include "vcl/svapp.hxx"
+#include "vcl/canvastools.hxx"
+#include "vcl/canvasbitmap.hxx"
+#include "vcl/dialog.hxx"
+#include "vcl/outdev.hxx"
+#include "vcl/bmpacc.hxx"
+#include "vcl/virdev.hxx"
+#include "vcl/bitmapex.hxx"
+
+
+using namespace ::com::sun::star;
+using namespace ::vcl::unotools;
+
+// -----------------------------------------------------------------------
+
+void Main();
+
+// -----------------------------------------------------------------------
+
+SAL_IMPLEMENT_MAIN()
+{
+ tools::extendApplicationEnvironment();
+
+ uno::Reference< lang::XMultiServiceFactory > xMS;
+ xMS = cppu::createRegistryServiceFactory(
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "applicat.rdb" ) ),
+ sal_True );
+
+ InitVCL( xMS );
+ ::Main();
+ DeInitVCL();
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+namespace com { namespace sun { namespace star { namespace rendering
+{
+
+bool operator==( const RGBColor& rLHS, const ARGBColor& rRHS )
+{
+ return rLHS.Red == rRHS.Red && rLHS.Green == rRHS.Green && rLHS.Blue == rRHS.Blue;
+}
+bool operator==( const ARGBColor& rLHS, const RGBColor& rRHS )
+{
+ return rLHS.Red == rRHS.Red && rLHS.Green == rRHS.Green && rLHS.Blue == rRHS.Blue;
+}
+
+} } } }
+
+//----------------------------------------------------------------------------------
+
+namespace
+{
+
+class TestApp : public Application
+{
+public:
+ virtual void Main();
+ virtual USHORT Exception( USHORT nError );
+};
+
+class TestWindow : public Dialog
+{
+ public:
+ TestWindow() : Dialog( (Window *) NULL )
+ {
+ SetText( rtl::OUString::createFromAscii( "CanvasBitmap test harness" ) );
+ SetSizePixel( Size( 1024, 1024 ) );
+ EnablePaint( true );
+ Show();
+ }
+
+ virtual ~TestWindow() {}
+ virtual void Paint( const Rectangle& rRect );
+};
+
+//----------------------------------------------------------------------------------
+
+static bool g_failure=false;
+
+void test( bool bResult, const char* msg )
+{
+ if( bResult )
+ {
+ OSL_TRACE("Testing: %s - PASSED", msg);
+ }
+ else
+ {
+ g_failure = true;
+ OSL_TRACE("Testing: %s - FAILED", msg);
+ }
+}
+
+//----------------------------------------------------------------------------------
+
+bool rangeCheck( const rendering::RGBColor& rColor )
+{
+ return rColor.Red < 0.0 || rColor.Red > 1.0 ||
+ rColor.Green < 0.0 || rColor.Green > 1.0 ||
+ rColor.Blue < 0.0 || rColor.Blue > 1.0;
+}
+
+//----------------------------------------------------------------------------------
+
+void checkCanvasBitmap( const rtl::Reference<VclCanvasBitmap>& xBmp,
+ const char* msg,
+ int nOriginalDepth )
+{
+ OSL_TRACE("-------------------------");
+ OSL_TRACE("Testing %s, with depth %d", msg, nOriginalDepth);
+
+ BitmapEx aContainedBmpEx( xBmp->getBitmapEx() );
+ Bitmap aContainedBmp( aContainedBmpEx.GetBitmap() );
+ int nDepth = nOriginalDepth;
+
+ {
+ ScopedBitmapReadAccess pAcc( aContainedBmp.AcquireReadAccess(),
+ aContainedBmp );
+ nDepth = pAcc->GetBitCount();
+ }
+
+ test( aContainedBmp.GetSizePixel() == Size(200,200),
+ "Original bitmap size" );
+
+ test( xBmp->getSize().Width == 200 && xBmp->getSize().Height == 200,
+ "Original bitmap size via API" );
+
+ test( xBmp->hasAlpha() == aContainedBmpEx.IsTransparent(),
+ "Correct alpha state" );
+
+ test( xBmp->getScaledBitmap( geometry::RealSize2D(500,500), sal_False ).is(),
+ "getScaledBitmap()" );
+
+ rendering::IntegerBitmapLayout aLayout;
+ uno::Sequence<sal_Int8> aPixelData = xBmp->getData(aLayout, geometry::IntegerRectangle2D(0,0,1,1));
+
+ const sal_Int32 nExpectedBitsPerPixel(
+ aContainedBmpEx.IsTransparent() ? std::max(8,nDepth)+8 : nDepth);
+ test( aLayout.ScanLines == 1,
+ "# scanlines" );
+ test( aLayout.ScanLineBytes == (nExpectedBitsPerPixel+7)/8,
+ "# scanline bytes" );
+ test( aLayout.ScanLineStride == (nExpectedBitsPerPixel+7)/8 ||
+ aLayout.ScanLineStride == -(nExpectedBitsPerPixel+7)/8,
+ "# scanline stride" );
+ test( aLayout.PlaneStride == 0,
+ "# plane stride" );
+
+ test( aLayout.ColorSpace.is(),
+ "Color space there" );
+
+ test( aLayout.Palette.is() == (nDepth <= 8),
+ "Palette existance conforms to bitmap" );
+
+ uno::Sequence<sal_Int8> aPixelData2 = xBmp->getPixel( aLayout, geometry::IntegerPoint2D(0,0) );
+
+ test( aPixelData2.getLength() == aPixelData.getLength(),
+ "getData and getPixel return same amount of data" );
+
+ aPixelData = xBmp->getData(aLayout, geometry::IntegerRectangle2D(0,0,200,1));
+ test( aLayout.ScanLines == 1,
+ "# scanlines" );
+ test( aLayout.ScanLineBytes == (200*nExpectedBitsPerPixel+7)/8,
+ "# scanline bytes" );
+ test( aLayout.ScanLineStride == (200*nExpectedBitsPerPixel+7)/8 ||
+ aLayout.ScanLineStride == -(200*nExpectedBitsPerPixel+7)/8,
+ "# scanline stride" );
+
+ uno::Sequence< rendering::RGBColor > aRGBColors = xBmp->convertIntegerToRGB( aPixelData );
+ uno::Sequence< rendering::ARGBColor > aARGBColors = xBmp->convertIntegerToARGB( aPixelData );
+
+ const rendering::RGBColor* pRGBStart ( aRGBColors.getConstArray() );
+ const rendering::RGBColor* pRGBEnd ( aRGBColors.getConstArray()+aRGBColors.getLength() );
+ const rendering::ARGBColor* pARGBStart( aARGBColors.getConstArray() );
+ std::pair<const rendering::RGBColor*,
+ const rendering::ARGBColor*> aRes = std::mismatch( pRGBStart, pRGBEnd, pARGBStart );
+ test( aRes.first == pRGBEnd,
+ "argb and rgb colors are equal" );
+
+ test( std::find_if(pRGBStart,pRGBEnd,&rangeCheck) == pRGBEnd,
+ "rgb colors are within [0,1] range" );
+
+ test( pRGBStart[0].Red == 1.0 && pRGBStart[0].Green == 1.0 && pRGBStart[0].Blue == 1.0,
+ "First pixel is white" );
+ test( pARGBStart[1].Alpha == 1.0,
+ "Second pixel is opaque" );
+ if( aContainedBmpEx.IsTransparent() )
+ {
+ test( pARGBStart[0].Alpha == 0.0,
+ "First pixel is fully transparent" );
+ }
+
+ test( pRGBStart[1].Red == 0.0 && pRGBStart[1].Green == 0.0 && pRGBStart[1].Blue == 0.0,
+ "Second pixel is black" );
+
+ if( nOriginalDepth > 8 )
+ {
+ const Color aCol(COL_GREEN);
+ test( pRGBStart[5].Red == vcl::unotools::toDoubleColor(aCol.GetRed()) &&
+ pRGBStart[5].Green == vcl::unotools::toDoubleColor(aCol.GetGreen()) &&
+ pRGBStart[5].Blue == vcl::unotools::toDoubleColor(aCol.GetBlue()),
+ "Sixth pixel is green" );
+ }
+ else if( nDepth <= 8 )
+ {
+ uno::Reference<rendering::XBitmapPalette> xPal = xBmp->getPalette();
+ test( xPal.is(),
+ "8bit or less: needs palette" );
+ test( xPal->getNumberOfEntries() == 1L << nOriginalDepth,
+ "Palette has correct entry count" );
+ uno::Sequence<double> aIndex;
+ test( xPal->setIndex(aIndex,sal_True,0) == sal_False,
+ "Palette is read-only" );
+ test( xPal->getIndex(aIndex,0),
+ "Palette entry 0 is opaque" );
+ test( xPal->getColorSpace().is(),
+ "Palette has a valid color space" );
+ }
+
+ test( pRGBStart[150].Red == 1.0 && pRGBStart[150].Green == 1.0 && pRGBStart[150].Blue == 1.0,
+ "150th pixel is white" );
+
+ if( nOriginalDepth > 8 )
+ {
+ const uno::Sequence<sal_Int8> aComponentTags( xBmp->getComponentTags() );
+ uno::Sequence<rendering::ARGBColor> aARGBColor(1);
+ uno::Sequence<rendering::RGBColor> aRGBColor(1);
+ uno::Sequence<sal_Int8> aPixel3, aPixel4;
+
+ const Color aCol(COL_GREEN);
+ aARGBColor[0].Red = vcl::unotools::toDoubleColor(aCol.GetRed());
+ aARGBColor[0].Green = vcl::unotools::toDoubleColor(aCol.GetGreen());
+ aARGBColor[0].Blue = vcl::unotools::toDoubleColor(aCol.GetBlue());
+ aARGBColor[0].Alpha = 1.0;
+
+ aRGBColor[0].Red = vcl::unotools::toDoubleColor(aCol.GetRed());
+ aRGBColor[0].Green = vcl::unotools::toDoubleColor(aCol.GetGreen());
+ aRGBColor[0].Blue = vcl::unotools::toDoubleColor(aCol.GetBlue());
+
+ aPixel3 = xBmp->convertIntegerFromARGB( aARGBColor );
+ aPixel4 = xBmp->getPixel( aLayout, geometry::IntegerPoint2D(5,0) );
+ test( aPixel3 == aPixel4,
+ "Green pixel from bitmap matches with manually converted green pixel" );
+
+ if( !aContainedBmpEx.IsTransparent() )
+ {
+ aPixel3 = xBmp->convertIntegerFromRGB( aRGBColor );
+ test( aPixel3 == aPixel4,
+ "Green pixel from bitmap matches with manually RGB-converted green pixel" );
+ }
+ }
+}
+
+//----------------------------------------------------------------------------------
+
+void checkBitmapImport( const rtl::Reference<VclCanvasBitmap>& xBmp,
+ const char* msg,
+ int nOriginalDepth )
+{
+ OSL_TRACE("-------------------------");
+ OSL_TRACE("Testing %s, with depth %d", msg, nOriginalDepth);
+
+ BitmapEx aContainedBmpEx( xBmp->getBitmapEx() );
+ Bitmap aContainedBmp( aContainedBmpEx.GetBitmap() );
+ int nDepth = nOriginalDepth;
+
+ {
+ ScopedBitmapReadAccess pAcc( aContainedBmp.AcquireReadAccess(),
+ aContainedBmp );
+ nDepth = pAcc->GetBitCount();
+ }
+
+ test( aContainedBmp.GetSizePixel() == Size(200,200),
+ "Original bitmap size" );
+
+ test( xBmp->getSize().Width == 200 && xBmp->getSize().Height == 200,
+ "Original bitmap size via API" );
+
+ test( xBmp->hasAlpha() == aContainedBmpEx.IsTransparent(),
+ "Correct alpha state" );
+
+ test( xBmp->getScaledBitmap( geometry::RealSize2D(500,500), sal_False ).is(),
+ "getScaledBitmap()" );
+
+ rendering::IntegerBitmapLayout aLayout;
+ uno::Sequence<sal_Int8> aPixelData = xBmp->getData(aLayout, geometry::IntegerRectangle2D(0,0,1,1));
+
+ const sal_Int32 nExpectedBitsPerPixel(
+ aContainedBmpEx.IsTransparent() ? std::max(8,nDepth)+8 : nDepth);
+ test( aLayout.ScanLines == 1,
+ "# scanlines" );
+ test( aLayout.ScanLineBytes == (nExpectedBitsPerPixel+7)/8,
+ "# scanline bytes" );
+ test( aLayout.ScanLineStride == (nExpectedBitsPerPixel+7)/8 ||
+ aLayout.ScanLineStride == -(nExpectedBitsPerPixel+7)/8,
+ "# scanline stride" );
+ test( aLayout.PlaneStride == 0,
+ "# plane stride" );
+
+ test( aLayout.ColorSpace.is(),
+ "Color space there" );
+
+ test( aLayout.Palette.is() == (nDepth <= 8),
+ "Palette existance conforms to bitmap" );
+
+ uno::Sequence<sal_Int8> aPixelData2 = xBmp->getPixel( aLayout, geometry::IntegerPoint2D(0,0) );
+
+ test( aPixelData2.getLength() == aPixelData.getLength(),
+ "getData and getPixel return same amount of data" );
+
+ aPixelData = xBmp->getData(aLayout, geometry::IntegerRectangle2D(0,0,200,1));
+ test( aLayout.ScanLines == 1,
+ "# scanlines" );
+ test( aLayout.ScanLineBytes == (200*nExpectedBitsPerPixel+7)/8,
+ "# scanline bytes" );
+ test( aLayout.ScanLineStride == (200*nExpectedBitsPerPixel+7)/8 ||
+ aLayout.ScanLineStride == -(200*nExpectedBitsPerPixel+7)/8,
+ "# scanline stride" );
+
+ uno::Sequence< rendering::RGBColor > aRGBColors = xBmp->convertIntegerToRGB( aPixelData );
+ uno::Sequence< rendering::ARGBColor > aARGBColors = xBmp->convertIntegerToARGB( aPixelData );
+
+ const rendering::RGBColor* pRGBStart ( aRGBColors.getConstArray() );
+ const rendering::RGBColor* pRGBEnd ( aRGBColors.getConstArray()+aRGBColors.getLength() );
+ const rendering::ARGBColor* pARGBStart( aARGBColors.getConstArray() );
+ std::pair<const rendering::RGBColor*,
+ const rendering::ARGBColor*> aRes = std::mismatch( pRGBStart, pRGBEnd, pARGBStart );
+ test( aRes.first == pRGBEnd,
+ "argb and rgb colors are equal" );
+
+ test( std::find_if(pRGBStart,pRGBEnd,&rangeCheck) == pRGBEnd,
+ "rgb colors are within [0,1] range" );
+
+ test( pRGBStart[0].Red == 1.0 && pRGBStart[0].Green == 1.0 && pRGBStart[0].Blue == 1.0,
+ "First pixel is white" );
+ test( pARGBStart[1].Alpha == 1.0,
+ "Second pixel is opaque" );
+ if( aContainedBmpEx.IsTransparent() )
+ {
+ test( pARGBStart[0].Alpha == 0.0,
+ "First pixel is fully transparent" );
+ }
+
+ test( pRGBStart[1].Red == 0.0 && pRGBStart[1].Green == 0.0 && pRGBStart[1].Blue == 0.0,
+ "Second pixel is black" );
+
+ if( nOriginalDepth > 8 )
+ {
+ const Color aCol(COL_GREEN);
+ test( pRGBStart[5].Red == vcl::unotools::toDoubleColor(aCol.GetRed()) &&
+ pRGBStart[5].Green == vcl::unotools::toDoubleColor(aCol.GetGreen()) &&
+ pRGBStart[5].Blue == vcl::unotools::toDoubleColor(aCol.GetBlue()),
+ "Sixth pixel is green" );
+ }
+ else if( nDepth <= 8 )
+ {
+ uno::Reference<rendering::XBitmapPalette> xPal = xBmp->getPalette();
+ test( xPal.is(),
+ "8bit or less: needs palette" );
+ test( xPal->getNumberOfEntries() == 1L << nOriginalDepth,
+ "Palette has correct entry count" );
+ uno::Sequence<double> aIndex;
+ test( xPal->setIndex(aIndex,sal_True,0) == sal_False,
+ "Palette is read-only" );
+ test( xPal->getIndex(aIndex,0),
+ "Palette entry 0 is opaque" );
+ test( xPal->getColorSpace().is(),
+ "Palette has a valid color space" );
+ }
+
+ test( pRGBStart[150].Red == 1.0 && pRGBStart[150].Green == 1.0 && pRGBStart[150].Blue == 1.0,
+ "150th pixel is white" );
+
+ if( nOriginalDepth > 8 )
+ {
+ const uno::Sequence<sal_Int8> aComponentTags( xBmp->getComponentTags() );
+ uno::Sequence<rendering::ARGBColor> aARGBColor(1);
+ uno::Sequence<rendering::RGBColor> aRGBColor(1);
+ uno::Sequence<sal_Int8> aPixel3, aPixel4;
+
+ const Color aCol(COL_GREEN);
+ aARGBColor[0].Red = vcl::unotools::toDoubleColor(aCol.GetRed());
+ aARGBColor[0].Green = vcl::unotools::toDoubleColor(aCol.GetGreen());
+ aARGBColor[0].Blue = vcl::unotools::toDoubleColor(aCol.GetBlue());
+ aARGBColor[0].Alpha = 1.0;
+
+ aRGBColor[0].Red = vcl::unotools::toDoubleColor(aCol.GetRed());
+ aRGBColor[0].Green = vcl::unotools::toDoubleColor(aCol.GetGreen());
+ aRGBColor[0].Blue = vcl::unotools::toDoubleColor(aCol.GetBlue());
+
+ aPixel3 = xBmp->convertIntegerFromARGB( aARGBColor );
+ aPixel4 = xBmp->getPixel( aLayout, geometry::IntegerPoint2D(5,0) );
+ test( aPixel3 == aPixel4,
+ "Green pixel from bitmap matches with manually converted green pixel" );
+
+ if( !aContainedBmpEx.IsTransparent() )
+ {
+ aPixel3 = xBmp->convertIntegerFromRGB( aRGBColor );
+ test( aPixel3 == aPixel4,
+ "Green pixel from bitmap matches with manually RGB-converted green pixel" );
+ }
+ }
+}
+
+//----------------------------------------------------------------------------------
+
+class TestBitmap : public cppu::WeakImplHelper3< rendering::XIntegerReadOnlyBitmap,
+ rendering::XBitmapPalette,
+ rendering::XIntegerBitmapColorSpace >
+{
+private:
+ geometry::IntegerSize2D maSize;
+ uno::Sequence<sal_Int8> maComponentTags;
+ uno::Sequence<sal_Int32> maComponentBitCounts;
+ rendering::IntegerBitmapLayout maLayout;
+ const sal_Int32 mnBitsPerPixel;
+
+ // XBitmap
+ virtual geometry::IntegerSize2D SAL_CALL getSize() throw (uno::RuntimeException) { return maSize; }
+ virtual ::sal_Bool SAL_CALL hasAlpha( ) throw (uno::RuntimeException) { return mnBitsPerPixel != 8; }
+ virtual uno::Reference< rendering::XBitmap > SAL_CALL getScaledBitmap( const geometry::RealSize2D&,
+ sal_Bool ) throw (uno::RuntimeException) { return this; }
+
+ // XIntegerReadOnlyBitmap
+ virtual uno::Sequence< ::sal_Int8 > SAL_CALL getData( rendering::IntegerBitmapLayout& bitmapLayout,
+ const geometry::IntegerRectangle2D& rect ) throw (lang::IndexOutOfBoundsException,
+ rendering::VolatileContentDestroyedException, uno::RuntimeException)
+ {
+ test( rect.X1 >= 0, "X1 within bounds" );
+ test( rect.Y1 >= 0, "Y1 within bounds" );
+ test( rect.X2 <= maSize.Width, "X2 within bounds" );
+ test( rect.Y2 <= maSize.Height, "Y2 within bounds" );
+
+ bitmapLayout = getMemoryLayout();
+
+ const sal_Int32 nWidth = rect.X2-rect.X1;
+ const sal_Int32 nHeight = rect.Y2-rect.Y1;
+ const sal_Int32 nScanlineLen = (nWidth * mnBitsPerPixel + 7)/8;
+ uno::Sequence<sal_Int8> aRes( nScanlineLen * nHeight );
+ sal_Int8* pOut = aRes.getArray();
+
+ bitmapLayout.ScanLines = nHeight;
+ bitmapLayout.ScanLineBytes =
+ bitmapLayout.ScanLineStride= nScanlineLen;
+
+ if( mnBitsPerPixel == 8 )
+ {
+ for( sal_Int32 y=0; y<nHeight; ++y )
+ {
+ for( sal_Int32 x=0; x<nWidth; ++x )
+ pOut[ y*nScanlineLen + x ] = sal_Int8(x);
+ }
+ }
+ else
+ {
+ for( sal_Int32 y=0; y<nHeight; ++y )
+ {
+ for( sal_Int32 x=0; x<nWidth; ++x )
+ {
+ pOut[ y*nScanlineLen + 4*x ] = sal_Int8(rect.X1);
+ pOut[ y*nScanlineLen + 4*x + 1 ] = sal_Int8(rect.Y2);
+ pOut[ y*nScanlineLen + 4*x + 2 ] = sal_Int8(x);
+ pOut[ y*nScanlineLen + 4*x + 3 ] = sal_Int8(rect.Y1);
+ }
+ }
+ }
+
+ return aRes;
+ }
+
+ virtual uno::Sequence< ::sal_Int8 > SAL_CALL getPixel( rendering::IntegerBitmapLayout&,
+ const geometry::IntegerPoint2D& ) throw (lang::IndexOutOfBoundsException,
+ rendering::VolatileContentDestroyedException, uno::RuntimeException)
+ {
+ test(false, "Method not implemented");
+ return uno::Sequence< sal_Int8 >();
+ }
+
+ virtual uno::Reference< rendering::XBitmapPalette > SAL_CALL getPalette( ) throw (uno::RuntimeException)
+ {
+ uno::Reference< XBitmapPalette > aRet;
+ if( mnBitsPerPixel == 8 )
+ aRet.set(this);
+ return aRet;
+ }
+
+ virtual rendering::IntegerBitmapLayout SAL_CALL getMemoryLayout( ) throw (uno::RuntimeException)
+ {
+ rendering::IntegerBitmapLayout aLayout( maLayout );
+
+ const sal_Int32 nScanlineLen = (maSize.Width * mnBitsPerPixel + 7)/8;
+
+ aLayout.ScanLines = maSize.Height;
+ aLayout.ScanLineBytes =
+ aLayout.ScanLineStride= nScanlineLen;
+ aLayout.Palette = getPalette();
+ aLayout.ColorSpace.set( this );
+
+ return aLayout;
+ }
+
+ // XBitmapPalette
+ virtual sal_Int32 SAL_CALL getNumberOfEntries() throw (uno::RuntimeException)
+ {
+ test( getPalette().is(),
+ "Got palette interface call without handing out palette?!" );
+
+ return 255;
+ }
+
+ virtual ::sal_Bool SAL_CALL getIndex( uno::Sequence< double >& entry,
+ ::sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException,
+ uno::RuntimeException)
+ {
+ test( getPalette().is(),
+ "Got palette interface call without handing out palette?!" );
+ test( nIndex >= 0 && nIndex < 256,
+ "Index out of range" );
+ entry = colorToStdColorSpaceSequence(
+ Color(UINT8(nIndex),
+ UINT8(nIndex),
+ UINT8(nIndex)) );
+
+ return sal_True; // no palette transparency here.
+ }
+
+ virtual ::sal_Bool SAL_CALL setIndex( const uno::Sequence< double >&,
+ ::sal_Bool,
+ ::sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException,
+ lang::IllegalArgumentException,
+ uno::RuntimeException)
+ {
+ test( getPalette().is(),
+ "Got palette interface call without handing out palette?!" );
+ test( nIndex >= 0 && nIndex < 256,
+ "Index out of range" );
+ return sal_False;
+ }
+
+ struct PaletteColorSpaceHolder: public rtl::StaticWithInit<uno::Reference<rendering::XColorSpace>,
+ PaletteColorSpaceHolder>
+ {
+ uno::Reference<rendering::XColorSpace> operator()()
+ {
+ return vcl::unotools::createStandardColorSpace();
+ }
+ };
+
+ virtual uno::Reference< rendering::XColorSpace > SAL_CALL getColorSpace( ) throw (uno::RuntimeException)
+ {
+ // this is the method from XBitmapPalette. Return palette color
+ // space here
+ return PaletteColorSpaceHolder::get();
+ }
+
+ // XIntegerBitmapColorSpace
+ 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 maComponentTags;
+ }
+
+ virtual ::sal_Int8 SAL_CALL getRenderingIntent( ) throw (uno::RuntimeException)
+ {
+ return rendering::RenderingIntent::PERCEPTUAL;
+ }
+
+ virtual uno::Sequence< beans::PropertyValue > SAL_CALL getProperties( ) throw (uno::RuntimeException)
+ {
+ test(false, "Method not implemented");
+ return uno::Sequence< ::beans::PropertyValue >();
+ }
+
+ virtual uno::Sequence< double > SAL_CALL convertColorSpace( const uno::Sequence< double >&,
+ const uno::Reference< rendering::XColorSpace >& ) throw (uno::RuntimeException)
+ {
+ test(false, "Method not implemented");
+ return uno::Sequence< double >();
+ }
+
+ virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertToRGB( const uno::Sequence< double >& ) throw (lang::IllegalArgumentException,
+ uno::RuntimeException)
+ {
+ test(false, "Method not implemented");
+ return uno::Sequence< rendering::RGBColor >();
+ }
+
+ virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToARGB( const uno::Sequence< double >& ) throw (lang::IllegalArgumentException,
+ uno::RuntimeException)
+ {
+ test(false, "Method not implemented");
+ return uno::Sequence< rendering::ARGBColor >();
+ }
+
+ virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToPARGB( const uno::Sequence< double >& ) throw (lang::IllegalArgumentException,
+ uno::RuntimeException)
+ {
+ test(false, "Method not implemented");
+ return uno::Sequence< rendering::ARGBColor >();
+ }
+
+ virtual uno::Sequence< double > SAL_CALL convertFromRGB( const uno::Sequence< rendering::RGBColor >& ) throw (lang::IllegalArgumentException,
+ uno::RuntimeException)
+ {
+ test(false, "Method not implemented");
+ return uno::Sequence< double >();
+ }
+
+ virtual uno::Sequence< double > SAL_CALL convertFromARGB( const uno::Sequence< rendering::ARGBColor >& ) throw (lang::IllegalArgumentException,
+ uno::RuntimeException)
+ {
+ test(false, "This method is not expected to be called!");
+ return uno::Sequence< double >();
+ }
+
+ virtual uno::Sequence< double > SAL_CALL convertFromPARGB( const uno::Sequence< rendering::ARGBColor >& ) throw (lang::IllegalArgumentException,
+ uno::RuntimeException)
+ {
+ test(false, "This method is not expected to be called!");
+ return uno::Sequence< double >();
+ }
+
+ virtual ::sal_Int32 SAL_CALL getBitsPerPixel( ) throw (uno::RuntimeException)
+ {
+ return mnBitsPerPixel;
+ }
+
+ virtual uno::Sequence< ::sal_Int32 > SAL_CALL getComponentBitCounts( ) throw (uno::RuntimeException)
+ {
+ return maComponentBitCounts;
+ }
+
+ virtual ::sal_Int8 SAL_CALL getEndianness( ) throw (uno::RuntimeException)
+ {
+ return util::Endianness::LITTLE;
+ }
+
+ virtual uno::Sequence< double > SAL_CALL convertFromIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& ,
+ const uno::Reference< rendering::XColorSpace >& ) throw (lang::IllegalArgumentException,
+ uno::RuntimeException)
+ {
+ test(false, "Method not implemented");
+ return uno::Sequence< double >();
+ }
+
+ virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertToIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& ,
+ const uno::Reference< rendering::XIntegerBitmapColorSpace >& ) throw (lang::IllegalArgumentException,
+ uno::RuntimeException)
+ {
+ test(false, "Method not implemented");
+ return uno::Sequence< sal_Int8 >();
+ }
+
+ virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertIntegerToRGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) throw (lang::IllegalArgumentException,
+ uno::RuntimeException)
+ {
+ const uno::Sequence< rendering::ARGBColor > aTemp( convertIntegerToARGB(deviceColor) );
+ const sal_Size nLen(aTemp.getLength());
+ uno::Sequence< rendering::RGBColor > aRes( nLen );
+ rendering::RGBColor* pOut = aRes.getArray();
+ for( sal_Size i=0; i<nLen; ++i )
+ {
+ *pOut++ = rendering::RGBColor(aTemp[i].Red,
+ aTemp[i].Green,
+ aTemp[i].Blue);
+ }
+
+ return aRes;
+ }
+
+ virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) throw (lang::IllegalArgumentException,
+ uno::RuntimeException)
+ {
+ const sal_Size nLen( deviceColor.getLength() );
+ const sal_Int32 nBytesPerPixel(mnBitsPerPixel == 8 ? 1 : 4);
+ test(nLen%nBytesPerPixel==0,
+ "number of channels no multiple of pixel element count");
+
+ uno::Sequence< rendering::ARGBColor > aRes( nLen / nBytesPerPixel );
+ rendering::ARGBColor* pOut( aRes.getArray() );
+
+ if( getPalette().is() )
+ {
+ for( sal_Size i=0; i<nLen; ++i )
+ {
+ *pOut++ = rendering::ARGBColor(
+ 1.0,
+ vcl::unotools::toDoubleColor(deviceColor[i]),
+ vcl::unotools::toDoubleColor(deviceColor[i]),
+ vcl::unotools::toDoubleColor(deviceColor[i]));
+ }
+ }
+ else
+ {
+ for( sal_Size i=0; i<nLen; i+=4 )
+ {
+ *pOut++ = rendering::ARGBColor(
+ vcl::unotools::toDoubleColor(deviceColor[i+3]),
+ vcl::unotools::toDoubleColor(deviceColor[i+0]),
+ vcl::unotools::toDoubleColor(deviceColor[i+1]),
+ vcl::unotools::toDoubleColor(deviceColor[i+2]));
+ }
+ }
+
+ return aRes;
+ }
+
+ virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToPARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) throw (lang::IllegalArgumentException,
+ uno::RuntimeException)
+ {
+ const sal_Size nLen( deviceColor.getLength() );
+ const sal_Int32 nBytesPerPixel(mnBitsPerPixel == 8 ? 1 : 4);
+ test(nLen%nBytesPerPixel==0,
+ "number of channels no multiple of pixel element count");
+
+ uno::Sequence< rendering::ARGBColor > aRes( nLen / nBytesPerPixel );
+ rendering::ARGBColor* pOut( aRes.getArray() );
+
+ if( getPalette().is() )
+ {
+ for( sal_Size i=0; i<nLen; ++i )
+ {
+ *pOut++ = rendering::ARGBColor(
+ 1.0,
+ vcl::unotools::toDoubleColor(deviceColor[i]),
+ vcl::unotools::toDoubleColor(deviceColor[i]),
+ vcl::unotools::toDoubleColor(deviceColor[i]));
+ }
+ }
+ else
+ {
+ for( sal_Size i=0; i<nLen; i+=4 )
+ {
+ const double fAlpha=vcl::unotools::toDoubleColor(deviceColor[i+3]);
+ *pOut++ = rendering::ARGBColor(
+ fAlpha,
+ fAlpha*vcl::unotools::toDoubleColor(deviceColor[i+0]),
+ fAlpha*vcl::unotools::toDoubleColor(deviceColor[i+1]),
+ fAlpha*vcl::unotools::toDoubleColor(deviceColor[i+2]));
+ }
+ }
+
+ return aRes;
+ }
+
+ virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromRGB( const uno::Sequence< rendering::RGBColor >& ) throw (lang::IllegalArgumentException,
+ uno::RuntimeException)
+ {
+ test(false, "Method not implemented");
+ return uno::Sequence< sal_Int8 >();
+ }
+
+ virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromARGB( const uno::Sequence< rendering::ARGBColor >& ) throw (lang::IllegalArgumentException,
+ uno::RuntimeException)
+ {
+ test(false, "Method not implemented");
+ return uno::Sequence< sal_Int8 >();
+ }
+
+ virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromPARGB( const uno::Sequence< rendering::ARGBColor >& ) throw (lang::IllegalArgumentException,
+ uno::RuntimeException)
+ {
+ test(false, "Method not implemented");
+ return uno::Sequence< sal_Int8 >();
+ }
+
+public:
+ TestBitmap( const geometry::IntegerSize2D& rSize, bool bPalette ) :
+ maSize(rSize),
+ maComponentTags(),
+ maComponentBitCounts(),
+ maLayout(),
+ mnBitsPerPixel( bPalette ? 8 : 32 )
+ {
+ if( bPalette )
+ {
+ maComponentTags.realloc(1);
+ maComponentTags[0] = rendering::ColorComponentTag::INDEX;
+
+ maComponentBitCounts.realloc(1);
+ maComponentBitCounts[0] = 8;
+ }
+ else
+ {
+ maComponentTags.realloc(4);
+ sal_Int8* pTags = maComponentTags.getArray();
+ pTags[0] = rendering::ColorComponentTag::RGB_BLUE;
+ pTags[1] = rendering::ColorComponentTag::RGB_GREEN;
+ pTags[2] = rendering::ColorComponentTag::RGB_RED;
+ pTags[3] = rendering::ColorComponentTag::ALPHA;
+
+ maComponentBitCounts.realloc(4);
+ sal_Int32* pCounts = maComponentBitCounts.getArray();
+ pCounts[0] = 8;
+ pCounts[1] = 8;
+ pCounts[2] = 8;
+ pCounts[3] = 8;
+ }
+
+ maLayout.ScanLines = 0;
+ maLayout.ScanLineBytes = 0;
+ maLayout.ScanLineStride = 0;
+ maLayout.PlaneStride = 0;
+ maLayout.ColorSpace.clear();
+ maLayout.Palette.clear();
+ maLayout.IsMsbFirst = sal_False;
+ }
+};
+
+
+//----------------------------------------------------------------------------------
+
+void TestWindow::Paint( const Rectangle& )
+{
+ static sal_Int8 lcl_depths[]={1,4,8,16,24};
+
+ try
+ {
+ // Testing VclCanvasBitmap wrapper
+ // ===============================
+
+ for( unsigned int i=0; i<sizeof(lcl_depths)/sizeof(*lcl_depths); ++i )
+ {
+ const sal_Int8 nDepth( lcl_depths[i] );
+ Bitmap aBitmap(Size(200,200),nDepth);
+ aBitmap.Erase(COL_WHITE);
+ {
+ ScopedBitmapWriteAccess pAcc(aBitmap.AcquireWriteAccess(),
+ aBitmap);
+ if( pAcc.get() )
+ {
+ BitmapColor aBlack(0);
+ BitmapColor aWhite(0);
+ if( pAcc->HasPalette() )
+ {
+ aBlack.SetIndex( sal::static_int_cast<BYTE>(pAcc->GetBestPaletteIndex(BitmapColor(0,0,0))) );
+ aWhite.SetIndex( sal::static_int_cast<BYTE>(pAcc->GetBestPaletteIndex(BitmapColor(255,255,255))) );
+ }
+ else
+ {
+ aBlack = Color(COL_BLACK);
+ aWhite = Color(COL_WHITE);
+ }
+ pAcc->SetFillColor(COL_GREEN);
+ pAcc->FillRect(Rectangle(0,0,100,100));
+ pAcc->SetPixel(0,0,aWhite);
+ pAcc->SetPixel(0,1,aBlack);
+ pAcc->SetPixel(0,2,aWhite);
+ }
+ }
+
+ rtl::Reference<VclCanvasBitmap> xBmp( new VclCanvasBitmap(aBitmap) );
+
+ checkCanvasBitmap( xBmp, "single bitmap", nDepth );
+
+ Bitmap aMask(Size(200,200),1);
+ aMask.Erase(COL_WHITE);
+ {
+ ScopedBitmapWriteAccess pAcc(aMask.AcquireWriteAccess(),
+ aMask);
+ if( pAcc.get() )
+ {
+ pAcc->SetFillColor(COL_BLACK);
+ pAcc->FillRect(Rectangle(0,0,100,100));
+ pAcc->SetPixel(0,0,BitmapColor(1));
+ pAcc->SetPixel(0,1,BitmapColor(0));
+ pAcc->SetPixel(0,2,BitmapColor(1));
+ }
+ }
+
+ xBmp.set( new VclCanvasBitmap(BitmapEx(aBitmap,aMask)) );
+
+ checkCanvasBitmap( xBmp, "masked bitmap", nDepth );
+
+ AlphaMask aAlpha(Size(200,200));
+ aAlpha.Erase(255);
+ {
+ BitmapWriteAccess* pAcc = aAlpha.AcquireWriteAccess();
+ if( pAcc )
+ {
+ pAcc->SetFillColor(COL_BLACK);
+ pAcc->FillRect(Rectangle(0,0,100,100));
+ pAcc->SetPixel(0,0,BitmapColor(255));
+ pAcc->SetPixel(0,1,BitmapColor(0));
+ pAcc->SetPixel(0,2,BitmapColor(255));
+ aAlpha.ReleaseAccess(pAcc);
+ }
+ }
+
+ xBmp.set( new VclCanvasBitmap(BitmapEx(aBitmap,aAlpha)) );
+
+ checkCanvasBitmap( xBmp, "alpha bitmap", nDepth );
+ }
+
+ // Testing XBitmap import
+ // ======================
+ uno::Reference< rendering::XIntegerReadOnlyBitmap > xTestBmp(
+ new TestBitmap( geometry::IntegerSize2D(10,10), true ));
+
+ BitmapEx aBmp = vcl::unotools::bitmapExFromXBitmap(xTestBmp);
+ test( aBmp.IsTransparent() == false,
+ "Palette bitmap is not transparent" );
+ test( aBmp.GetSizePixel() == Size(10,10),
+ "Bitmap has size (10,10)" );
+ test( aBmp.GetBitCount() == 8,
+ "Bitmap has bitcount of 8" );
+ {
+ BitmapReadAccess* pBmpAcc = aBmp.GetBitmap().AcquireReadAccess();
+
+ test( pBmpAcc,
+ "Bitmap has valid BitmapReadAccess" );
+
+ test(pBmpAcc->GetPixel(0,0) == BitmapColor(0),
+ "(0,0) correct content");
+ test(pBmpAcc->GetPixel(2,2) == BitmapColor(2),
+ "(2,2) correct content");
+ test(pBmpAcc->GetPixel(2,9) == BitmapColor(9),
+ "(9,2) correct content");
+
+ aBmp.GetBitmap().ReleaseAccess(pBmpAcc);
+ }
+
+ xTestBmp.set( new TestBitmap( geometry::IntegerSize2D(10,10), false ));
+
+ aBmp = vcl::unotools::bitmapExFromXBitmap(xTestBmp);
+ test( aBmp.IsTransparent() == TRUE,
+ "Palette bitmap is transparent" );
+ test( aBmp.IsAlpha() == TRUE,
+ "Palette bitmap has alpha" );
+ test( aBmp.GetSizePixel() == Size(10,10),
+ "Bitmap has size (10,10)" );
+ test( aBmp.GetBitCount() == 24,
+ "Bitmap has bitcount of 24" );
+ {
+ BitmapReadAccess* pBmpAcc = aBmp.GetBitmap().AcquireReadAccess();
+ BitmapReadAccess* pAlphaAcc = aBmp.GetAlpha().AcquireReadAccess();
+
+ test( pBmpAcc,
+ "Bitmap has valid BitmapReadAccess" );
+ test( pAlphaAcc,
+ "Bitmap has valid alpha BitmapReadAccess" );
+
+ test(pBmpAcc->GetPixel(0,0) == BitmapColor(0,1,0),
+ "(0,0) correct content");
+ test(pAlphaAcc->GetPixel(0,0) == BitmapColor(255),
+ "(0,0) correct alpha content");
+ test(pBmpAcc->GetPixel(2,2) == BitmapColor(0,3,2),
+ "(2,2) correct content");
+ test(pAlphaAcc->GetPixel(2,2) == BitmapColor(253),
+ "(2,2) correct alpha content");
+ test(pBmpAcc->GetPixel(2,9) == BitmapColor(0,3,9),
+ "(9,2) correct content");
+ test(pAlphaAcc->GetPixel(2,9) == BitmapColor(253),
+ "(9,2) correct alpha content");
+
+ aBmp.GetAlpha().ReleaseAccess(pAlphaAcc);
+ aBmp.GetBitmap().ReleaseAccess(pBmpAcc);
+ }
+ }
+ catch( uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION();
+ exit(2);
+ }
+ catch( std::exception& )
+ {
+ OSL_TRACE( "Caught std exception!" );
+ }
+
+ if( g_failure )
+ exit(2);
+}
+
+} // namespace
+
+void Main()
+{
+ TestWindow aWindow;
+ aWindow.Execute();
+ aWindow.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "VCL - canvasbitmaptest" ) ) );
+
+ Application::Execute();
+}
+
diff --git a/vcl/test/dndtest.cxx b/vcl/test/dndtest.cxx
new file mode 100755
index 000000000000..c52d6d3e9589
--- /dev/null
+++ b/vcl/test/dndtest.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/event.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/wrkwin.hxx>
+#include <vcl/msgbox.hxx>
+#include <vcl/lstbox.hxx>
+#include <comphelper/processfactory.hxx>
+#include <cppuhelper/servicefactory.hxx>
+#include <cppuhelper/implbase1.hxx>
+#include <cppuhelper/implbase3.hxx>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
+#include <com/sun/star/datatransfer/dnd/XDropTarget.hpp>
+#include <com/sun/star/datatransfer/dnd/XDragSourceListener.hpp>
+#include <com/sun/star/datatransfer/dnd/XDropTargetListener.hpp>
+#include <com/sun/star/datatransfer/dnd/XDragGestureRecognizer.hpp>
+#include <com/sun/star/datatransfer/dnd/XDragGestureListener.hpp>
+#include <vos/process.hxx>
+
+#include <stdio.h>
+
+using namespace ::rtl;
+using namespace ::vos;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::datatransfer;
+using namespace ::com::sun::star::datatransfer::clipboard;
+using namespace ::com::sun::star::datatransfer::dnd;
+
+// -----------------------------------------------------------------------
+
+class MyApp : public Application
+{
+public:
+ void Main();
+};
+
+MyApp aMyApp;
+
+// -----------------------------------------------------------------------
+
+class MyWin : public WorkWindow
+{
+public:
+ MyWin( Window* pParent, WinBits nWinStyle );
+
+ void MouseMove( const MouseEvent& rMEvt );
+ void MouseButtonDown( const MouseEvent& rMEvt );
+ void MouseButtonUp( const MouseEvent& rMEvt );
+ void KeyInput( const KeyEvent& rKEvt );
+ void KeyUp( const KeyEvent& rKEvt );
+ void Paint( const Rectangle& rRect );
+ void Resize();
+};
+
+// -----------------------------------------------------------------------
+
+class MyDragAndDropListener: public ::cppu::WeakImplHelper3 < XDropTargetListener, XDragGestureListener, XDragSourceListener >
+{
+ Window * m_pWindow;
+
+public:
+
+ MyDragAndDropListener( Window * pWindow ) : m_pWindow( pWindow ) {};
+
+ virtual void SAL_CALL dragGestureRecognized( const DragGestureEvent& dge ) throw(RuntimeException);
+ virtual void SAL_CALL drop( const DropTargetDropEvent& dtde ) throw(RuntimeException);
+ virtual void SAL_CALL dragEnter( const DropTargetDragEnterEvent& dtde ) throw(RuntimeException);
+ virtual void SAL_CALL dragExit( const DropTargetEvent& dte ) throw(RuntimeException);
+ virtual void SAL_CALL dragOver( const DropTargetDragEvent& dtde ) throw(RuntimeException);
+ virtual void SAL_CALL dropActionChanged( const DropTargetDragEvent& dtde ) throw(RuntimeException);
+ virtual void SAL_CALL dragDropEnd( const DragSourceDropEvent& dsde ) throw(RuntimeException);
+ virtual void SAL_CALL dragEnter( const DragSourceDragEvent& dsdee ) throw(RuntimeException);
+ virtual void SAL_CALL dragExit( const DragSourceEvent& dse ) throw(RuntimeException);
+ virtual void SAL_CALL dragOver( const DragSourceDragEvent& dsde ) throw(RuntimeException);
+ virtual void SAL_CALL dropActionChanged( const DragSourceDragEvent& dsde ) throw(RuntimeException);
+ virtual void SAL_CALL disposing( const EventObject& eo ) throw(RuntimeException);
+};
+
+// -----------------------------------------------------------------------
+
+class MyInfoBox : public InfoBox
+{
+
+public:
+
+ MyInfoBox( Window* pParent );
+};
+
+// -----------------------------------------------------------------------
+
+class MyListBox : public ListBox
+{
+
+public:
+
+ MyListBox( Window* pParent );
+};
+
+// -----------------------------------------------------------------------
+
+class StringTransferable : public ::cppu::WeakImplHelper1< XTransferable >
+{
+ const OUString m_aData;
+ Sequence< DataFlavor > m_aFlavorList;
+
+public:
+ StringTransferable( const OUString& rString ) : m_aData( rString ), m_aFlavorList( 1 )
+ {
+ DataFlavor df;
+
+ df.MimeType = OUString::createFromAscii( "text/plain;charset=utf-16" );
+ df.DataType = getCppuType( static_cast < OUString * > ( 0 ) );
+
+ m_aFlavorList[0] = df;
+ };
+
+ virtual Any SAL_CALL getTransferData( const DataFlavor& aFlavor ) throw(UnsupportedFlavorException, IOException, RuntimeException);
+ virtual Sequence< DataFlavor > SAL_CALL getTransferDataFlavors( ) throw(RuntimeException);
+ virtual sal_Bool SAL_CALL isDataFlavorSupported( const DataFlavor& aFlavor ) throw(RuntimeException);
+};
+
+
+// -----------------------------------------------------------------------
+
+void MyApp::Main()
+{
+ OUString aRegistry;
+ OStartupInfo aInfo;
+
+ for( sal_Int32 n = 0, nmax = aInfo.getCommandArgCount(); n < nmax; n++ )
+ {
+ OUString aArg;
+
+ aInfo.getCommandArg( n, aArg );
+
+ if( aArg.compareTo( OUString::createFromAscii( "-r" ), 2 ) == 0 )
+ {
+ if ( n + 1 < nmax )
+ aInfo.getCommandArg( ++n, aRegistry );
+ }
+ }
+
+ Reference< XMultiServiceFactory > xServiceManager;
+
+ if( aRegistry.getLength() )
+ {
+ xServiceManager = ::cppu::createRegistryServiceFactory( aRegistry, sal_True );
+
+ if( xServiceManager.is() )
+ {
+ ::comphelper::setProcessServiceFactory( xServiceManager );
+ }
+
+ if( ! xServiceManager.is() )
+ printf( "No servicemanager available.\n" );
+ else
+ printf( "Ok\n" );
+
+ }
+ else
+ fprintf( stderr, "Usage: %s -r full-path-to-applicat.rdb\n", "dnddemo" );
+
+
+ MyWin aMainWin( NULL, WB_APP | WB_STDWORK );
+ aMainWin.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "Drag And Drop - Workbench" ) ) );
+ aMainWin.Show();
+
+ // test the clipboard code
+ Reference< XClipboard > xClipboard = aMainWin.GetClipboard();
+ if( xClipboard.is() )
+ {
+ printf( "System clipboard available.\n" );
+ xClipboard->getContents();
+ }
+ else
+ fprintf( stderr, "System clipboard not available.\n" );
+
+ MyInfoBox aInfoBox( &aMainWin );
+ aInfoBox.Execute();
+
+ MyListBox aListBox( &aMainWin );
+ aListBox.SetPosSizePixel( 10, 10, 100, 100 );
+ aListBox.InsertEntry( OUString::createFromAscii( "TestItem" ));
+ aListBox.Show();
+
+ Execute();
+
+ Reference< XComponent > xComponent( xServiceManager, UNO_QUERY );
+ if( xComponent.is() )
+ xComponent->dispose();
+
+}
+
+// -----------------------------------------------------------------------
+
+MyWin::MyWin( Window* pParent, WinBits nWinStyle ) :
+ WorkWindow( pParent, nWinStyle )
+{
+ Reference< XDropTargetListener > xListener = new MyDragAndDropListener( this );
+
+ Reference< XDropTarget > xDropTarget = GetDropTarget();
+ if( xDropTarget.is() )
+ {
+ xDropTarget->addDropTargetListener( xListener );
+ xDropTarget->setActive( sal_True );
+ }
+
+ Reference< XDragGestureRecognizer > xRecognizer = GetDragGestureRecognizer();
+ if( xRecognizer.is() )
+ xRecognizer->addDragGestureListener( Reference< XDragGestureListener > ( xListener, UNO_QUERY ) );
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::MouseMove( const MouseEvent& rMEvt )
+{
+ WorkWindow::MouseMove( rMEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ WorkWindow::MouseButtonDown( rMEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ WorkWindow::MouseButtonUp( rMEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::KeyInput( const KeyEvent& rKEvt )
+{
+ WorkWindow::KeyInput( rKEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::KeyUp( const KeyEvent& rKEvt )
+{
+ WorkWindow::KeyUp( rKEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::Paint( const Rectangle& rRect )
+{
+ WorkWindow::Paint( rRect );
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::Resize()
+{
+ WorkWindow::Resize();
+}
+
+// -----------------------------------------------------------------------
+
+void SAL_CALL MyDragAndDropListener::dragGestureRecognized( const DragGestureEvent& dge ) throw(RuntimeException)
+{
+ printf( "XDragGestureListener::dragGestureRecognized called ( Window: %p, %"SAL_PRIdINT32", %"SAL_PRIdINT32" ).\n", m_pWindow, dge.DragOriginX, dge.DragOriginY );
+
+ Reference< XDragSource > xDragSource( dge.DragSource, UNO_QUERY );
+ xDragSource->startDrag( dge, -1, 0, 0, new StringTransferable( OUString::createFromAscii( "TestString" ) ), this );
+ printf( "XDragSource::startDrag returned.\n" );
+}
+
+// -----------------------------------------------------------------------
+
+void SAL_CALL MyDragAndDropListener::drop( const DropTargetDropEvent& dtde ) throw(RuntimeException)
+{
+ printf( "XDropTargetListener::drop called ( Window: %p, %"SAL_PRIdINT32", %"SAL_PRIdINT32" ).\n", m_pWindow, dtde.LocationX, dtde.LocationY );
+
+ dtde.Context->dropComplete( sal_True );
+}
+
+// -----------------------------------------------------------------------
+
+void SAL_CALL MyDragAndDropListener::dragEnter( const DropTargetDragEnterEvent& dtdee ) throw(RuntimeException)
+{
+ printf( "XDropTargetListener::dragEnter called ( Window: %p, %"SAL_PRIdINT32", %"SAL_PRIdINT32" ).\n", m_pWindow, dtdee.LocationX, dtdee.LocationY );
+ dtdee.Context->acceptDrag( dtdee.DropAction );
+}
+
+// -----------------------------------------------------------------------
+
+void SAL_CALL MyDragAndDropListener::dragExit( const DropTargetEvent& ) throw(RuntimeException)
+{
+ printf( "XDropTargetListener::dragExit called ( Window: %p ).\n", m_pWindow );
+}
+
+// -----------------------------------------------------------------------
+
+void SAL_CALL MyDragAndDropListener::dragOver( const DropTargetDragEvent& dtde ) throw(RuntimeException)
+{
+ printf( "XDropTargetListener::dragOver called ( Window: %p, %"SAL_PRIdINT32", %"SAL_PRIdINT32" ).\n", m_pWindow, dtde.LocationX, dtde.LocationY );
+ dtde.Context->acceptDrag( dtde.DropAction );
+}
+
+// -----------------------------------------------------------------------
+
+void SAL_CALL MyDragAndDropListener::dropActionChanged( const DropTargetDragEvent& dtde ) throw(RuntimeException)
+{
+ printf( "XDropTargetListener::dropActionChanged called ( Window: %p, %"SAL_PRIdINT32", %"SAL_PRIdINT32" ).\n", m_pWindow, dtde.LocationX, dtde.LocationY );
+ dtde.Context->acceptDrag( dtde.DropAction );
+}
+
+// -----------------------------------------------------------------------
+
+void SAL_CALL MyDragAndDropListener::dragDropEnd( const DragSourceDropEvent& dsde ) throw(RuntimeException)
+{
+ printf( "XDragSourceListener::dropDropEnd called ( Window: %p, %s ).\n", m_pWindow, dsde.DropSuccess ? "sucess" : "failed" );
+}
+
+// -----------------------------------------------------------------------
+
+void SAL_CALL MyDragAndDropListener::dragEnter( const DragSourceDragEvent& ) throw(RuntimeException)
+{
+ printf( "XDragSourceListener::dragEnter called ( Window: %p ).\n", m_pWindow );
+}
+
+// -----------------------------------------------------------------------
+
+void SAL_CALL MyDragAndDropListener::dragExit( const DragSourceEvent& ) throw(RuntimeException)
+{
+ printf( "XDragSourceListener::dragExit called ( Window: %p ).\n", m_pWindow );
+}
+
+// -----------------------------------------------------------------------
+
+void SAL_CALL MyDragAndDropListener::dragOver( const DragSourceDragEvent& ) throw(RuntimeException)
+{
+ printf( "XDragSourceListener::dragOver called ( Window: %p ).\n", m_pWindow );
+}
+
+// -----------------------------------------------------------------------
+
+void SAL_CALL MyDragAndDropListener::dropActionChanged( const DragSourceDragEvent& ) throw(RuntimeException)
+{
+ printf( "XDragSourceListener::dropActionChanged called ( Window: %p ).\n", m_pWindow );
+}
+
+// -----------------------------------------------------------------------
+
+void SAL_CALL MyDragAndDropListener::disposing( const EventObject& ) throw(RuntimeException)
+{
+ printf( "XEventListener::disposing called ( Window: %p ).\n", m_pWindow );
+}
+
+// -----------------------------------------------------------------------
+
+MyInfoBox::MyInfoBox( Window* pParent ) : InfoBox( pParent,
+ OUString::createFromAscii( "dragging over this box should result in another window id in the drag log." ) )
+{
+ Reference< XDropTargetListener > xListener = new MyDragAndDropListener( this );
+
+ Reference< XDropTarget > xDropTarget = GetDropTarget();
+ if( xDropTarget.is() )
+ {
+ xDropTarget->addDropTargetListener( xListener );
+ xDropTarget->setActive( sal_True );
+ }
+
+ Reference< XDragGestureRecognizer > xRecognizer = GetDragGestureRecognizer();
+ if( xRecognizer.is() )
+ xRecognizer->addDragGestureListener( Reference< XDragGestureListener > ( xListener, UNO_QUERY ) );
+};
+
+// -----------------------------------------------------------------------
+
+MyListBox::MyListBox( Window* pParent ) : ListBox( pParent )
+{
+ Reference< XDropTargetListener > xListener = new MyDragAndDropListener( this );
+
+ Reference< XDropTarget > xDropTarget = GetDropTarget();
+ if( xDropTarget.is() )
+ {
+ xDropTarget->addDropTargetListener( xListener );
+ xDropTarget->setActive( sal_True );
+ }
+
+ Reference< XDragGestureRecognizer > xRecognizer = GetDragGestureRecognizer();
+ if( xRecognizer.is() )
+ xRecognizer->addDragGestureListener( Reference< XDragGestureListener > ( xListener, UNO_QUERY ) );
+};
+
+// -----------------------------------------------------------------------
+
+Any SAL_CALL StringTransferable::getTransferData( const DataFlavor& )
+ throw(UnsupportedFlavorException, IOException, RuntimeException)
+{
+ return makeAny( m_aData );
+}
+
+// -----------------------------------------------------------------------
+
+Sequence< DataFlavor > SAL_CALL StringTransferable::getTransferDataFlavors( )
+ throw(RuntimeException)
+{
+ return m_aFlavorList;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool SAL_CALL StringTransferable::isDataFlavorSupported( const DataFlavor& )
+ throw(RuntimeException)
+{
+ return sal_True;
+}
+
+
diff --git a/vcl/test/makefile.mk b/vcl/test/makefile.mk
new file mode 100644
index 000000000000..8691d0bcb626
--- /dev/null
+++ b/vcl/test/makefile.mk
@@ -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.
+#
+#*************************************************************************
+
+PRJ=..
+
+PRJNAME=vcl
+TARGET=dndtest
+LIBTARGET=NO
+ENABLE_EXCEPTIONS=TRUE
+
+.IF "$(GUI)" == "OS2"
+TARGETTYPE=GUI
+.ENDIF
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+
+# --- Files --------------------------------------------------------
+
+APP1OBJS= \
+ $(OBJ)$/dndtest.obj
+
+
+APP1NOSAL= TRUE
+APP1TARGET= $(TARGET)
+APP1STDLIBS= $(CPPULIB) \
+ $(CPPUHELPERLIB) \
+ $(TOOLSLIB) \
+ $(SALLIB) \
+ $(VOSLIB) \
+ $(SOTLIB) \
+ $(COMPHELPERLIB) \
+ $(VCLLIB)
+
+# --- Targets ------------------------------------------------------
+
+APP2TARGET= canvasbitmaptest
+APP2OBJS= \
+ $(OBJ)$/canvasbitmaptest.obj
+
+APP2NOSAL= TRUE
+APP2STDLIBS=$(TOOLSLIB) \
+ $(COMPHELPERLIB) \
+ $(CPPULIB) \
+ $(CPPUHELPERLIB) \
+ $(UCBHELPERLIB) \
+ $(SALLIB) \
+ $(VCLLIB)
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
diff --git a/vcl/unx/gtk/a11y/TODO b/vcl/unx/gtk/a11y/TODO
new file mode 100644
index 000000000000..1048bd96ef75
--- /dev/null
+++ b/vcl/unx/gtk/a11y/TODO
@@ -0,0 +1,49 @@
+cws 'atkbridge'
+#Issue number: i#47890#
+Submitted by: mmeeks
+
+Hacked up prototype of atk bridge
+
+
+Serious problems
+ + Threading/locking:
+ + incoming CORBA calls & the GDK lock
+ + how are these being processed & on what thread ?
+ + are we holding the GDK_THREADS lock ?
+ + can we even do that ?
+ + is it really necessary to be thread safe ?
+ + how does this work in combination with the (unsafe) GAIL code ?
+ + what should incoming CORBA calls be doing ?
+ + esp. since we can't tell if they're coming from
+ in-proc or not either [ though this is unlikely ]
+
+
+Test:
+ + in-line text editing, does the TEXT_CHANGED signal get it right,
+ + why not copy/paste/delete etc. ?
+ + check vs. writer & other bits ...
+ + AtkSelection
+ + AtkHyper*
+
+* At-poke
+ + implement non-gui mode - for to-console event logging
+ + logging
+ + more detail from remaining events
+ + add a Tree navigation thing instead (?)
+ + poke a sub-child (?)
+ + embed a tree widget inside the tree view ?
+ + AtkHyperText testing (?)
+
+
+Known bugs:
+ + AtkText
+ + selection interface - multiple selections ?
+ + word boundary issues
+ + copy AccessibleTextImpl.java's getAfterIndex eg.
+ + the 'getFoo' methods need to use UNO_QUERY_THROW &
+ throw an exception to avoid null pointer dereferences.
+ + AtkAttributeSet (etc.)
+ + AtkEditableText
+ + finish/test AtkTable
+ + HyperLink 'link_activated', HyperText 'link_selected' (?)
+ + tooltips create new toplevels with broken roles.
diff --git a/vcl/unx/gtk/a11y/atkaction.cxx b/vcl/unx/gtk/a11y/atkaction.cxx
new file mode 100644
index 000000000000..4329dd345d14
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkaction.cxx
@@ -0,0 +1,278 @@
+/*************************************************************************
+ *
+ * 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 "atkwrapper.hxx"
+
+#include <com/sun/star/accessibility/XAccessibleAction.hpp>
+#include <com/sun/star/accessibility/XAccessibleKeyBinding.hpp>
+
+#include <com/sun/star/awt/Key.hpp>
+#include <com/sun/star/awt/KeyModifier.hpp>
+
+#include <rtl/strbuf.hxx>
+#include <algorithm>
+#include <map>
+
+#include <stdio.h>
+
+using namespace ::com::sun::star;
+
+// FIXME
+static G_CONST_RETURN gchar *
+getAsConst( const rtl::OString& rString )
+{
+ static const int nMax = 10;
+ static rtl::OString aUgly[nMax];
+ static int nIdx = 0;
+ nIdx = (nIdx + 1) % nMax;
+ aUgly[nIdx] = rString;
+ return aUgly[ nIdx ];
+}
+
+static accessibility::XAccessibleAction*
+ getAction( AtkAction *action ) throw (uno::RuntimeException)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( action );
+
+ if( pWrap )
+ {
+ if( !pWrap->mpAction && pWrap->mpContext )
+ {
+ uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleAction::static_type(NULL) );
+ pWrap->mpAction = reinterpret_cast< accessibility::XAccessibleAction * > (any.pReserved);
+ pWrap->mpAction->acquire();
+ }
+
+ return pWrap->mpAction;
+ }
+
+ return NULL;
+}
+
+extern "C" {
+
+static gboolean
+action_wrapper_do_action (AtkAction *action,
+ gint i)
+{
+ try {
+ accessibility::XAccessibleAction* pAction = getAction( action );
+ if( pAction )
+ return pAction->doAccessibleAction( i );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in doAccessibleAction()" );
+ }
+
+ return FALSE;
+}
+
+static gint
+action_wrapper_get_n_actions (AtkAction *action)
+{
+ try {
+ accessibility::XAccessibleAction* pAction = getAction( action );
+ if( pAction )
+ return pAction->getAccessibleActionCount();
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleActionCount()" );
+ }
+
+ return 0;
+}
+
+static G_CONST_RETURN gchar *
+action_wrapper_get_description (AtkAction *, gint)
+{
+ // GAIL implement this only for cells
+ g_warning( "Not implemented: get_description()" );
+ return "";
+}
+
+static G_CONST_RETURN gchar *
+action_wrapper_get_localized_name (AtkAction *, gint)
+{
+ // GAIL doesn't implement this as well
+ g_warning( "Not implemented: get_localized_name()" );
+ return "";
+}
+
+#define ACTION_NAME_PAIR( OOoName, AtkName ) \
+ std::pair< const rtl::OUString, const gchar * > ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OOoName ) ), AtkName )
+
+static G_CONST_RETURN gchar *
+action_wrapper_get_name (AtkAction *action,
+ gint i)
+{
+ static std::map< rtl::OUString, const gchar * > aNameMap;
+
+ if( aNameMap.empty() )
+ {
+ aNameMap.insert( ACTION_NAME_PAIR( "click", "click" ) );
+ aNameMap.insert( ACTION_NAME_PAIR( "select", "click" ) );
+ aNameMap.insert( ACTION_NAME_PAIR( "togglePopup", "push" ) );
+ }
+
+ try {
+ accessibility::XAccessibleAction* pAction = getAction( action );
+ if( pAction )
+ {
+ std::map< rtl::OUString, const gchar * >::iterator iter;
+
+ rtl::OUString aDesc( pAction->getAccessibleActionDescription( i ) );
+
+ iter = aNameMap.find( aDesc );
+ if( iter != aNameMap.end() )
+ return iter->second;
+
+ std::pair< const rtl::OUString, const gchar * > aNewVal( aDesc,
+ g_strdup( OUStringToConstGChar(aDesc) ) );
+
+ if( aNameMap.insert( aNewVal ).second )
+ return aNewVal.second;
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleActionDescription()" );
+ }
+
+ return "";
+}
+
+/*
+* GNOME Expects a string in the format:
+*
+* <nmemonic>;<full-path>;<accelerator>
+*
+* The keybindings in <full-path> should be separated by ":"
+*/
+
+static inline void
+appendKeyStrokes(rtl::OStringBuffer& rBuffer, const uno::Sequence< awt::KeyStroke >& rKeyStrokes)
+{
+ for( sal_Int32 i = 0; i < rKeyStrokes.getLength(); i++ )
+ {
+ if( rKeyStrokes[i].Modifiers & awt::KeyModifier::SHIFT )
+ rBuffer.append("<Shift>");
+ if( rKeyStrokes[i].Modifiers & awt::KeyModifier::MOD1 )
+ rBuffer.append("<Control>");
+ if( rKeyStrokes[i].Modifiers & awt::KeyModifier::MOD2 )
+ rBuffer.append("<Alt>");
+
+ if( ( rKeyStrokes[i].KeyCode >= awt::Key::A ) && ( rKeyStrokes[i].KeyCode <= awt::Key::Z ) )
+ rBuffer.append( (sal_Char) ( 'a' + ( rKeyStrokes[i].KeyCode - awt::Key::A ) ) );
+ else
+ {
+ sal_Char c = '\0';
+
+ switch( rKeyStrokes[i].KeyCode )
+ {
+ case awt::Key::TAB: c = '\t'; break;
+ case awt::Key::SPACE: c = ' '; break;
+ case awt::Key::ADD: c = '+'; break;
+ case awt::Key::SUBTRACT: c = '-'; break;
+ case awt::Key::MULTIPLY: c = '*'; break;
+ case awt::Key::DIVIDE: c = '/'; break;
+ case awt::Key::POINT: c = '.'; break;
+ case awt::Key::COMMA: c = ','; break;
+ case awt::Key::LESS: c = '<'; break;
+ case awt::Key::GREATER: c = '>'; break;
+ case awt::Key::EQUAL: c = '='; break;
+ case 0:
+ break;
+ default:
+ g_warning( "Unmapped KeyCode: %d", rKeyStrokes[i].KeyCode );
+ break;
+ }
+
+ if( c != '\0' )
+ rBuffer.append( c );
+ }
+ }
+}
+
+
+static G_CONST_RETURN gchar *
+action_wrapper_get_keybinding (AtkAction *action,
+ gint i)
+{
+ try {
+ accessibility::XAccessibleAction* pAction = getAction( action );
+ if( pAction )
+ {
+ uno::Reference< accessibility::XAccessibleKeyBinding > xBinding( pAction->getAccessibleActionKeyBinding( i ));
+
+ if( xBinding.is() )
+ {
+ rtl::OStringBuffer aRet;
+
+ sal_Int32 nmax = std::min( xBinding->getAccessibleKeyBindingCount(), (sal_Int32) 3 );
+ for( sal_Int32 n = 0; n < nmax; n++ )
+ {
+ appendKeyStrokes( aRet, xBinding->getAccessibleKeyBinding( n ) );
+
+ if( n < 2 )
+ aRet.append( (sal_Char) ';' );
+ }
+
+ // !! FIXME !! remember keystroke in wrapper object ?
+ return getAsConst( aRet.makeStringAndClear() );
+ }
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in get_keybinding()" );
+ }
+
+ return "";
+}
+
+static gboolean
+action_wrapper_set_description (AtkAction *, gint, const gchar *)
+{
+ return FALSE;
+}
+
+} // extern "C"
+
+void
+actionIfaceInit (AtkActionIface *iface)
+{
+ g_return_if_fail (iface != NULL);
+
+ iface->do_action = action_wrapper_do_action;
+ iface->get_n_actions = action_wrapper_get_n_actions;
+ iface->get_description = action_wrapper_get_description;
+ iface->get_keybinding = action_wrapper_get_keybinding;
+ iface->get_name = action_wrapper_get_name;
+ iface->get_localized_name = action_wrapper_get_localized_name;
+ iface->set_description = action_wrapper_set_description;
+}
diff --git a/vcl/unx/gtk/a11y/atkbridge.cxx b/vcl/unx/gtk/a11y/atkbridge.cxx
new file mode 100644
index 000000000000..25add8e0dd18
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkbridge.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 <plugins/gtk/atkbridge.hxx>
+#include <plugins/gtk/gtkframe.hxx>
+
+#include "atkfactory.hxx"
+#include "atkutil.hxx"
+#include "atkwindow.hxx"
+#include <stdio.h>
+
+bool InitAtkBridge(void)
+{
+ const char* pVersion = atk_get_toolkit_version();
+ if( ! pVersion )
+ return false;
+
+ unsigned int major, minor, micro;
+
+ /* check gail minimum version requirements */
+ if( sscanf( pVersion, "%u.%u.%u", &major, &minor, &micro) < 3 )
+ {
+ // g_warning( "unable to parse gail version number" );
+ return false;
+ }
+
+ if( ( (major << 16) | (minor << 8) | micro ) < ( (1 << 16) | 8 << 8 | 6 ) )
+ {
+ g_warning( "libgail >= 1.8.6 required for accessibility support" );
+ return false;
+ }
+
+ /* Initialize the AtkUtilityWrapper class */
+ g_type_class_unref( g_type_class_ref( OOO_TYPE_ATK_UTIL ) );
+
+ /* Initialize the GailWindow wrapper class */
+ g_type_class_unref( g_type_class_ref( OOO_TYPE_WINDOW_WRAPPER ) );
+
+ /* Register AtkObject wrapper factory */
+ AtkRegistry * registry = atk_get_default_registry();
+ if( registry )
+ atk_registry_set_factory_type( registry, OOO_TYPE_FIXED, OOO_TYPE_WRAPPER_FACTORY );
+
+ return true;
+}
+
+void DeInitAtkBridge()
+{
+ restore_gail_window_vtable();
+}
+
diff --git a/vcl/unx/gtk/a11y/atkcomponent.cxx b/vcl/unx/gtk/a11y/atkcomponent.cxx
new file mode 100644
index 000000000000..24cf335ebeb0
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkcomponent.cxx
@@ -0,0 +1,382 @@
+/*************************************************************************
+ *
+ * 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 "atkwrapper.hxx"
+
+#include <com/sun/star/accessibility/XAccessibleComponent.hpp>
+
+#ifdef ENABLE_TRACING
+#include <stdio.h>
+#endif
+
+using namespace ::com::sun::star;
+
+static accessibility::XAccessibleComponent*
+ getComponent( AtkComponent *pComponent ) throw (uno::RuntimeException)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pComponent );
+ if( pWrap )
+ {
+ if( !pWrap->mpComponent && pWrap->mpContext )
+ {
+ uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleComponent::static_type(NULL) );
+ pWrap->mpComponent = reinterpret_cast< accessibility::XAccessibleComponent * > (any.pReserved);
+ pWrap->mpComponent->acquire();
+ }
+
+ return pWrap->mpComponent;
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+static awt::Point
+translatePoint( accessibility::XAccessibleComponent *pComponent,
+ gint x, gint y, AtkCoordType t)
+{
+ awt::Point aOrigin( 0, 0 );
+ if( t == ATK_XY_SCREEN )
+ aOrigin = pComponent->getLocationOnScreen();
+
+#ifdef ENABLE_TRACING
+ fprintf(stderr, "coordinates ( %u, %u ) translated to: ( %u, %u )\n",
+ x, y, x - aOrigin.X, y - aOrigin.Y);
+#endif
+
+ return awt::Point( x - aOrigin.X, y - aOrigin.Y );
+}
+
+/*****************************************************************************/
+
+extern "C" {
+
+static gboolean
+component_wrapper_grab_focus (AtkComponent *component)
+{
+ try
+ {
+ accessibility::XAccessibleComponent* pComponent = getComponent( component );
+ if( pComponent )
+ {
+ pComponent->grabFocus();
+ return TRUE;
+ }
+ }
+ catch( const uno::Exception &e )
+ {
+ g_warning( "Exception in grabFocus()" );
+ }
+
+ return FALSE;
+}
+
+/*****************************************************************************/
+
+static gboolean
+component_wrapper_contains (AtkComponent *component,
+ gint x,
+ gint y,
+ AtkCoordType coord_type)
+{
+ try
+ {
+ accessibility::XAccessibleComponent* pComponent = getComponent( component );
+ if( pComponent )
+ return pComponent->containsPoint( translatePoint( pComponent, x, y, coord_type ) );
+ }
+ catch( const uno::Exception &e )
+ {
+ g_warning( "Exception in containsPoint()" );
+ }
+
+ return FALSE;
+}
+
+/*****************************************************************************/
+
+static AtkObject *
+component_wrapper_ref_accessible_at_point (AtkComponent *component,
+ gint x,
+ gint y,
+ AtkCoordType coord_type)
+{
+ try
+ {
+ accessibility::XAccessibleComponent* pComponent = getComponent( component );
+
+ if( pComponent )
+ {
+ uno::Reference< accessibility::XAccessible > xAccessible;
+ xAccessible = pComponent->getAccessibleAtPoint(
+ translatePoint( pComponent, x, y, coord_type ) );
+
+#ifdef ENABLE_TRACING
+ fprintf(stderr, "getAccessibleAtPoint( %u, %u ) returned %p\n",
+ x, y, xAccessible.get());
+
+ uno::Reference< accessibility::XAccessibleComponent > xComponent(
+ xAccessible->getAccessibleContext(), uno::UNO_QUERY );
+
+ if( xComponent.is() )
+ {
+ awt::Rectangle rect = xComponent->getBounds();
+ fprintf(stderr, "%p->getBounds() returned: ( %u, %u, %u, %u )\n",
+ xAccessible.get(), rect.X, rect.Y, rect.Width, rect.Height );
+ }
+#endif
+
+ return atk_object_wrapper_ref( xAccessible );
+ }
+ }
+ catch( const uno::Exception &e )
+ {
+ g_warning( "Exception in getAccessibleAtPoint()" );
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+static void
+component_wrapper_get_position (AtkComponent *component,
+ gint *x,
+ gint *y,
+ AtkCoordType coord_type)
+{
+ try
+ {
+ accessibility::XAccessibleComponent* pComponent = getComponent( component );
+ if( pComponent )
+ {
+ awt::Point aPos;
+
+ if( coord_type == ATK_XY_SCREEN )
+ aPos = pComponent->getLocationOnScreen();
+ else
+ aPos = pComponent->getLocation();
+
+ *x = aPos.X;
+ *y = aPos.Y;
+
+#ifdef ENABLE_TRACING
+ fprintf(stderr, "getLocation[OnScreen]() returned: ( %u, %u )\n", *x, *y );
+#endif
+ }
+ }
+ catch( const uno::Exception &e )
+ {
+ g_warning( "Exception in getLocation[OnScreen]()" );
+ }
+}
+
+/*****************************************************************************/
+
+static void
+component_wrapper_get_size (AtkComponent *component,
+ gint *width,
+ gint *height)
+{
+ try
+ {
+ accessibility::XAccessibleComponent* pComponent = getComponent( component );
+ if( pComponent )
+ {
+ awt::Size aSize = pComponent->getSize();
+ *width = aSize.Width;
+ *height = aSize.Height;
+
+#ifdef ENABLE_TRACING
+ fprintf(stderr, "getSize() returned: ( %u, %u )\n", *width, *height );
+#endif
+ }
+ }
+ catch( const uno::Exception &e )
+ {
+ g_warning( "Exception in getSize()" );
+ }
+}
+
+/*****************************************************************************/
+
+static void
+component_wrapper_get_extents (AtkComponent *component,
+ gint *x,
+ gint *y,
+ gint *width,
+ gint *height,
+ AtkCoordType coord_type)
+{
+ component_wrapper_get_position( component, x, y, coord_type );
+ component_wrapper_get_size( component, width, height );
+}
+
+/*****************************************************************************/
+
+static gboolean
+component_wrapper_set_extents (AtkComponent *, gint, gint, gint, gint, AtkCoordType)
+{
+ g_warning( "AtkComponent::set_extents unimplementable" );
+ return FALSE;
+}
+
+/*****************************************************************************/
+
+static gboolean
+component_wrapper_set_position (AtkComponent *, gint, gint, AtkCoordType)
+{
+ g_warning( "AtkComponent::set_position unimplementable" );
+ return FALSE;
+}
+
+/*****************************************************************************/
+
+static gboolean
+component_wrapper_set_size (AtkComponent *, gint, gint)
+{
+ g_warning( "AtkComponent::set_size unimplementable" );
+ return FALSE;
+}
+
+/*****************************************************************************/
+
+static AtkLayer
+component_wrapper_get_layer (AtkComponent *component)
+{
+ AtkRole role = atk_object_get_role( ATK_OBJECT( component ) );
+ AtkLayer layer = ATK_LAYER_WIDGET;
+
+ switch (role)
+ {
+ case ATK_ROLE_POPUP_MENU:
+ case ATK_ROLE_MENU_ITEM:
+ case ATK_ROLE_CHECK_MENU_ITEM:
+ case ATK_ROLE_SEPARATOR:
+ case ATK_ROLE_LIST_ITEM:
+ layer = ATK_LAYER_POPUP;
+ break;
+ case ATK_ROLE_MENU:
+ {
+ AtkObject * parent = atk_object_get_parent( ATK_OBJECT( component ) );
+ if( atk_object_get_role( parent ) != ATK_ROLE_MENU_BAR )
+ layer = ATK_LAYER_POPUP;
+ }
+ break;
+
+ case ATK_ROLE_LIST:
+ {
+ AtkObject * parent = atk_object_get_parent( ATK_OBJECT( component ) );
+ if( atk_object_get_role( parent ) == ATK_ROLE_COMBO_BOX )
+ layer = ATK_LAYER_POPUP;
+ }
+ break;
+
+ default:
+ ;
+ }
+
+ return layer;
+}
+
+/*****************************************************************************/
+
+static gint
+component_wrapper_get_mdi_zorder (AtkComponent *)
+{
+ // only needed for ATK_LAYER_MDI (not used) or ATK_LAYER_WINDOW (inherited from GAIL)
+ return G_MININT;
+}
+
+/*****************************************************************************/
+
+// This code is mostly stolen from libgail ..
+
+static guint
+component_wrapper_add_focus_handler (AtkComponent *component,
+ AtkFocusHandler handler)
+{
+ GSignalMatchType match_type;
+ gulong ret;
+ guint signal_id;
+
+ match_type = (GSignalMatchType) (G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC);
+ signal_id = g_signal_lookup( "focus-event", ATK_TYPE_OBJECT );
+
+ ret = g_signal_handler_find( component, match_type, signal_id, 0, NULL,
+ (gpointer) &handler, NULL);
+ if (!ret)
+ {
+ return g_signal_connect_closure_by_id (component,
+ signal_id, 0,
+ g_cclosure_new (
+ G_CALLBACK (handler), NULL,
+ (GClosureNotify) NULL),
+ FALSE);
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/*****************************************************************************/
+
+static void
+component_wrapper_remove_focus_handler (AtkComponent *component,
+ guint handler_id)
+{
+ g_signal_handler_disconnect (component, handler_id);
+}
+
+/*****************************************************************************/
+
+} // extern "C"
+
+void
+componentIfaceInit (AtkComponentIface *iface)
+{
+ g_return_if_fail (iface != NULL);
+
+ iface->add_focus_handler = component_wrapper_add_focus_handler;
+ iface->contains = component_wrapper_contains;
+ iface->get_extents = component_wrapper_get_extents;
+ iface->get_layer = component_wrapper_get_layer;
+ iface->get_mdi_zorder = component_wrapper_get_mdi_zorder;
+ iface->get_position = component_wrapper_get_position;
+ iface->get_size = component_wrapper_get_size;
+ iface->grab_focus = component_wrapper_grab_focus;
+ iface->ref_accessible_at_point = component_wrapper_ref_accessible_at_point;
+ iface->remove_focus_handler = component_wrapper_remove_focus_handler;
+ iface->set_extents = component_wrapper_set_extents;
+ iface->set_position = component_wrapper_set_position;
+ iface->set_size = component_wrapper_set_size;
+}
diff --git a/vcl/unx/gtk/a11y/atkeditabletext.cxx b/vcl/unx/gtk/a11y/atkeditabletext.cxx
new file mode 100644
index 000000000000..c0399145b07c
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkeditabletext.cxx
@@ -0,0 +1,202 @@
+/*************************************************************************
+ *
+ * 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 "atkwrapper.hxx"
+#include "atktextattributes.hxx"
+
+#include <com/sun/star/accessibility/XAccessibleEditableText.hpp>
+#include <com/sun/star/accessibility/TextSegment.hpp>
+
+// #include <functional>
+// #include <hash_map>
+
+#include <stdio.h>
+#include <string.h>
+
+using namespace ::com::sun::star;
+
+static accessibility::XAccessibleEditableText*
+ getEditableText( AtkEditableText *pEditableText ) throw (uno::RuntimeException)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pEditableText );
+ if( pWrap )
+ {
+ if( !pWrap->mpEditableText && pWrap->mpContext )
+ {
+ uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleEditableText::static_type(NULL) );
+ pWrap->mpEditableText = reinterpret_cast< accessibility::XAccessibleEditableText * > (any.pReserved);
+ pWrap->mpEditableText->acquire();
+ }
+
+ return pWrap->mpEditableText;
+ }
+
+ return NULL;
+}
+
+
+/*****************************************************************************/
+
+extern "C" {
+
+static gboolean
+editable_text_wrapper_set_run_attributes( AtkEditableText *text,
+ AtkAttributeSet *attribute_set,
+ gint nStartOffset,
+ gint nEndOffset)
+{
+ try {
+ accessibility::XAccessibleEditableText* pEditableText = getEditableText( text );
+ if( pEditableText )
+ {
+ uno::Sequence< beans::PropertyValue > aAttributeList;
+
+ if( attribute_set_map_to_property_values( attribute_set, aAttributeList ) )
+ return pEditableText->setAttributes(nStartOffset, nEndOffset, aAttributeList);
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in setAttributes()" );
+ }
+
+ return FALSE;
+}
+
+static void
+editable_text_wrapper_set_text_contents( AtkEditableText *text,
+ const gchar *string )
+{
+ try {
+ accessibility::XAccessibleEditableText* pEditableText = getEditableText( text );
+ if( pEditableText )
+ {
+ rtl::OUString aString ( string, strlen(string), RTL_TEXTENCODING_UTF8 );
+ pEditableText->setText( aString );
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in setText()" );
+ }
+}
+
+static void
+editable_text_wrapper_insert_text( AtkEditableText *text,
+ const gchar *string,
+ gint length,
+ gint *pos )
+{
+ try {
+ accessibility::XAccessibleEditableText* pEditableText = getEditableText( text );
+ if( pEditableText )
+ {
+ rtl::OUString aString ( string, length, RTL_TEXTENCODING_UTF8 );
+ if( pEditableText->insertText( aString, *pos ) )
+ *pos += length;
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in insertText()" );
+ }
+}
+
+static void
+editable_text_wrapper_cut_text( AtkEditableText *text,
+ gint start,
+ gint end )
+{
+ try {
+ accessibility::XAccessibleEditableText* pEditableText = getEditableText( text );
+ if( pEditableText )
+ pEditableText->cutText( start, end );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in cutText()" );
+ }
+}
+
+static void
+editable_text_wrapper_delete_text( AtkEditableText *text,
+ gint start,
+ gint end )
+{
+ try {
+ accessibility::XAccessibleEditableText* pEditableText = getEditableText( text );
+ if( pEditableText )
+ pEditableText->deleteText( start, end );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in deleteText()" );
+ }
+}
+
+static void
+editable_text_wrapper_paste_text( AtkEditableText *text,
+ gint pos )
+{
+ try {
+ accessibility::XAccessibleEditableText* pEditableText = getEditableText( text );
+ if( pEditableText )
+ pEditableText->pasteText( pos );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in pasteText()" );
+ }
+}
+
+static void
+editable_text_wrapper_copy_text( AtkEditableText *text,
+ gint start,
+ gint end )
+{
+ try {
+ accessibility::XAccessibleEditableText* pEditableText = getEditableText( text );
+ if( pEditableText )
+ pEditableText->copyText( start, end );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in copyText()" );
+ }
+}
+
+} // extern "C"
+
+void
+editableTextIfaceInit (AtkEditableTextIface *iface)
+{
+ g_return_if_fail (iface != NULL);
+
+ iface->set_text_contents = editable_text_wrapper_set_text_contents;
+ iface->insert_text = editable_text_wrapper_insert_text;
+ iface->copy_text = editable_text_wrapper_copy_text;
+ iface->cut_text = editable_text_wrapper_cut_text;
+ iface->delete_text = editable_text_wrapper_delete_text;
+ iface->paste_text = editable_text_wrapper_paste_text;
+ iface->set_run_attributes = editable_text_wrapper_set_run_attributes;
+}
diff --git a/vcl/unx/gtk/a11y/atkfactory.cxx b/vcl/unx/gtk/a11y/atkfactory.cxx
new file mode 100644
index 000000000000..d2574f616539
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkfactory.cxx
@@ -0,0 +1,183 @@
+/*************************************************************************
+ *
+ * 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 <plugins/gtk/gtkframe.hxx>
+#include <vcl/window.hxx>
+#include "atkwrapper.hxx"
+#include "atkfactory.hxx"
+#include "atkregistry.hxx"
+
+using namespace ::com::sun::star;
+
+extern "C" {
+
+/*
+ * Instances of this dummy object class are returned whenever we have to
+ * create an AtkObject, but can't touch the OOo object anymore since it
+ * is already disposed.
+ */
+
+static AtkStateSet *
+noop_wrapper_ref_state_set( AtkObject * )
+{
+ AtkStateSet *state_set = atk_state_set_new();
+ atk_state_set_add_state( state_set, ATK_STATE_DEFUNCT );
+ return state_set;
+}
+
+static void
+atk_noop_object_wrapper_class_init(AtkNoOpObjectClass *klass)
+{
+ AtkObjectClass *atk_class = ATK_OBJECT_CLASS( klass );
+ atk_class->ref_state_set = noop_wrapper_ref_state_set;
+}
+
+static GType
+atk_noop_object_wrapper_get_type(void)
+{
+ static GType type = 0;
+
+ if (!type)
+ {
+ static const GTypeInfo typeInfo =
+ {
+ sizeof (AtkNoOpObjectClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) atk_noop_object_wrapper_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL,
+ sizeof (AtkObjectWrapper),
+ 0,
+ (GInstanceInitFunc) NULL,
+ NULL
+ } ;
+
+ type = g_type_register_static (ATK_TYPE_OBJECT, "OOoAtkNoOpObj", &typeInfo, (GTypeFlags)0) ;
+ }
+ return type;
+}
+
+AtkObject*
+atk_noop_object_wrapper_new()
+{
+ AtkObject *accessible;
+
+ accessible = (AtkObject *) g_object_new (atk_noop_object_wrapper_get_type(), NULL);
+ g_return_val_if_fail (accessible != NULL, NULL);
+
+ accessible->role = ATK_ROLE_INVALID;
+ accessible->layer = ATK_LAYER_INVALID;
+
+ return accessible;
+}
+
+/*
+ * The wrapper factory
+ */
+
+static GType
+wrapper_factory_get_accessible_type(void)
+{
+ return atk_object_wrapper_get_type();
+}
+
+static AtkObject*
+wrapper_factory_create_accessible( GObject *obj )
+{
+ GtkWidget* parent_widget = gtk_widget_get_parent( GTK_WIDGET( obj ) );
+
+ // gail_container_real_remove_gtk tries to re-instanciate an accessible
+ // for a widget that is about to vanish ..
+ if( ! parent_widget )
+ return atk_noop_object_wrapper_new();
+
+ GtkSalFrame* pFrame = GtkSalFrame::getFromWindow( GTK_WINDOW( parent_widget ) );
+ g_return_val_if_fail( pFrame != NULL, NULL );
+
+ Window* pFrameWindow = pFrame->GetWindow();
+ if( pFrameWindow )
+ {
+ Window* pWindow = pFrameWindow;
+
+ // skip accessible objects already exposed by the frame objects
+ if( WINDOW_BORDERWINDOW == pWindow->GetType() )
+ pWindow = pFrameWindow->GetAccessibleChildWindow(0);
+
+ if( pWindow )
+ {
+ uno::Reference< accessibility::XAccessible > xAccessible = pWindow->GetAccessible(true);
+ if( xAccessible.is() )
+ {
+ AtkObject *accessible = ooo_wrapper_registry_get( xAccessible );
+
+ if( accessible )
+ g_object_ref( G_OBJECT(accessible) );
+ else
+ accessible = atk_object_wrapper_new( xAccessible, gtk_widget_get_accessible(parent_widget) );
+
+ return accessible;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static void
+wrapper_factory_class_init( AtkObjectFactoryClass *klass )
+{
+ klass->create_accessible = wrapper_factory_create_accessible;
+ klass->get_accessible_type = wrapper_factory_get_accessible_type;
+}
+
+GType
+wrapper_factory_get_type (void)
+{
+ static GType t = 0;
+
+ if (!t) {
+ static const GTypeInfo tinfo =
+ {
+ sizeof (AtkObjectFactoryClass),
+ NULL, NULL, (GClassInitFunc) wrapper_factory_class_init,
+ NULL, NULL, sizeof (AtkObjectFactory), 0, NULL, NULL
+ };
+
+ t = g_type_register_static (
+ ATK_TYPE_OBJECT_FACTORY, "OOoAtkObjectWrapperFactory",
+ &tinfo, (GTypeFlags) 0);
+ }
+
+ return t;
+}
+
+} // extern C
+
diff --git a/vcl/unx/gtk/a11y/atkfactory.hxx b/vcl/unx/gtk/a11y/atkfactory.hxx
new file mode 100644
index 000000000000..82be08cfad1b
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkfactory.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef __ATK_FACTORY_HXX__
+#define __ATK_FACTORY_HXX__
+
+#include <atk/atk.h>
+
+#define OOO_TYPE_WRAPPER_FACTORY wrapper_factory_get_type()
+
+extern "C" {
+
+GType wrapper_factory_get_type (void);
+
+} // extern "C"
+
+#endif
diff --git a/vcl/unx/gtk/a11y/atkhypertext.cxx b/vcl/unx/gtk/a11y/atkhypertext.cxx
new file mode 100644
index 000000000000..90d735890655
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkhypertext.cxx
@@ -0,0 +1,291 @@
+/*************************************************************************
+ *
+ * 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 "atkwrapper.hxx"
+
+#include <com/sun/star/accessibility/XAccessibleHypertext.hpp>
+
+#include <stdio.h>
+
+using namespace ::com::sun::star;
+
+
+// ---------------------- AtkHyperlink ----------------------
+
+typedef struct {
+ AtkHyperlink atk_hyper_link;
+
+ uno::Reference< accessibility::XAccessibleHyperlink > xLink;
+} HyperLink;
+
+static uno::Reference< accessibility::XAccessibleHyperlink >
+ getHyperlink( AtkHyperlink *pHyperlink )
+{
+ HyperLink *pLink = (HyperLink *) pHyperlink;
+ return pLink->xLink;
+}
+
+static GObjectClass *hyper_parent_class = NULL;
+
+extern "C" {
+
+static void
+hyper_link_finalize (GObject *obj)
+{
+ HyperLink *hl = (HyperLink *) obj;
+ hl->xLink.clear();
+ hyper_parent_class->finalize (obj);
+}
+
+static gchar *
+hyper_link_get_uri( AtkHyperlink *pLink,
+ gint i )
+{
+ try {
+ uno::Any aAny = getHyperlink( pLink )->getAccessibleActionObject( i );
+ rtl::OUString aUri = aAny.get< rtl::OUString > ();
+ return OUStringToGChar(aUri);
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in hyper_link_get_uri" );
+ }
+ return NULL;
+}
+
+static AtkObject *
+hyper_link_get_object( AtkHyperlink *pLink,
+ gint i)
+{
+ try {
+ uno::Any aAny = getHyperlink( pLink )->getAccessibleActionObject( i );
+ uno::Reference< accessibility::XAccessible > xObj( aAny, uno::UNO_QUERY_THROW );
+ return atk_object_wrapper_ref( xObj );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in hyper_link_get_object" );
+ }
+ return NULL;
+}
+static gint
+hyper_link_get_end_index( AtkHyperlink *pLink )
+{
+ try {
+ return getHyperlink( pLink )->getEndIndex();
+ }
+ catch(const uno::Exception& e) {
+ }
+ return -1;
+}
+static gint
+hyper_link_get_start_index( AtkHyperlink *pLink )
+{
+ try {
+ return getHyperlink( pLink )->getStartIndex();
+ }
+ catch(const uno::Exception& e) {
+ }
+ return -1;
+}
+static gboolean
+hyper_link_is_valid( AtkHyperlink *pLink )
+{
+ try {
+ return getHyperlink( pLink )->isValid();
+ }
+ catch(const uno::Exception& e) {
+ }
+ return FALSE;
+}
+static gint
+hyper_link_get_n_anchors( AtkHyperlink *pLink )
+{
+ try {
+ return getHyperlink( pLink )->getAccessibleActionCount();
+ }
+ catch(const uno::Exception& e) {
+ }
+ return 0;
+}
+
+static guint
+hyper_link_link_state( AtkHyperlink * )
+{
+ g_warning( "FIXME: hyper_link_link_state unimplemented" );
+ return 0;
+}
+static gboolean
+hyper_link_is_selected_link( AtkHyperlink * )
+{
+ g_warning( "FIXME: hyper_link_is_selected_link unimplemented" );
+ return FALSE;
+}
+
+static void
+hyper_link_class_init (AtkHyperlinkClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = hyper_link_finalize;
+
+ hyper_parent_class = (GObjectClass *)g_type_class_peek_parent (klass);
+
+ klass->get_uri = hyper_link_get_uri;
+ klass->get_object = hyper_link_get_object;
+ klass->get_end_index = hyper_link_get_end_index;
+ klass->get_start_index = hyper_link_get_start_index;
+ klass->is_valid = hyper_link_is_valid;
+ klass->get_n_anchors = hyper_link_get_n_anchors;
+ klass->link_state = hyper_link_link_state;
+ klass->is_selected_link = hyper_link_is_selected_link;
+}
+
+static GType
+hyper_link_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ static const GTypeInfo tinfo = {
+ sizeof (AtkHyperlinkClass),
+ NULL, /* base init */
+ NULL, /* base finalize */
+ (GClassInitFunc) hyper_link_class_init,
+ NULL, /* class finalize */
+ NULL, /* class data */
+ sizeof (HyperLink), /* instance size */
+ 0, /* nb preallocs */
+ NULL, /* instance init */
+ NULL /* value table */
+ };
+
+ static const GInterfaceInfo atk_action_info = {
+ (GInterfaceInitFunc) actionIfaceInit,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL
+ };
+
+ type = g_type_register_static (ATK_TYPE_HYPERLINK,
+ "OOoAtkObjHyperLink", &tinfo,
+ (GTypeFlags)0);
+ g_type_add_interface_static (type, ATK_TYPE_ACTION,
+ &atk_action_info);
+ }
+
+ return type;
+}
+
+// ---------------------- AtkHyperText ----------------------
+
+static accessibility::XAccessibleHypertext*
+ getHypertext( AtkHypertext *pHypertext ) throw (uno::RuntimeException)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pHypertext );
+ if( pWrap )
+ {
+ if( !pWrap->mpHypertext && pWrap->mpContext )
+ {
+ uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleHypertext::static_type(NULL) );
+ pWrap->mpHypertext = reinterpret_cast< accessibility::XAccessibleHypertext * > (any.pReserved);
+ pWrap->mpHypertext->acquire();
+ }
+
+ return pWrap->mpHypertext;
+ }
+
+ return NULL;
+}
+
+
+static AtkHyperlink *
+hypertext_get_link( AtkHypertext *hypertext,
+ gint link_index)
+{
+ try {
+ accessibility::XAccessibleHypertext* pHypertext = getHypertext( hypertext );
+ if( pHypertext )
+ {
+ HyperLink *pLink = (HyperLink *)g_object_new( hyper_link_get_type(), NULL );
+ pLink->xLink = pHypertext->getHyperLink( link_index );
+ if( !pLink->xLink.is() ) {
+ g_object_unref( G_OBJECT( pLink ) );
+ pLink = NULL;
+ }
+ return ATK_HYPERLINK( pLink );
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getHyperLink()" );
+ }
+
+ return NULL;
+}
+
+static gint
+hypertext_get_n_links( AtkHypertext *hypertext )
+{
+ try {
+ accessibility::XAccessibleHypertext* pHypertext = getHypertext( hypertext );
+ if( pHypertext )
+ return pHypertext->getHyperLinkCount();
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getHyperLinkCount()" );
+ }
+
+ return 0;
+}
+
+static gint
+hypertext_get_link_index( AtkHypertext *hypertext,
+ gint index)
+{
+ try {
+ accessibility::XAccessibleHypertext* pHypertext = getHypertext( hypertext );
+ if( pHypertext )
+ return pHypertext->getHyperLinkIndex( index );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getHyperLinkIndex()" );
+ }
+
+ return 0;
+}
+
+} // extern "C"
+
+void
+hypertextIfaceInit (AtkHypertextIface *iface)
+{
+ g_return_if_fail (iface != NULL);
+
+ iface->get_link = hypertext_get_link;
+ iface->get_n_links = hypertext_get_n_links;
+ iface->get_link_index = hypertext_get_link_index;
+}
diff --git a/vcl/unx/gtk/a11y/atkimage.cxx b/vcl/unx/gtk/a11y/atkimage.cxx
new file mode 100644
index 000000000000..b48c59555a29
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkimage.cxx
@@ -0,0 +1,138 @@
+/*************************************************************************
+ *
+ * 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 "atkwrapper.hxx"
+
+#include <com/sun/star/accessibility/XAccessibleImage.hpp>
+
+#include <stdio.h>
+
+using namespace ::com::sun::star;
+
+// FIXME
+static G_CONST_RETURN gchar *
+getAsConst( rtl::OUString rString )
+{
+ static const int nMax = 10;
+ static rtl::OString aUgly[nMax];
+ static int nIdx = 0;
+ nIdx = (nIdx + 1) % nMax;
+ aUgly[nIdx] = rtl::OUStringToOString( rString, RTL_TEXTENCODING_UTF8 );
+ return aUgly[ nIdx ];
+}
+
+static accessibility::XAccessibleImage*
+ getImage( AtkImage *pImage ) throw (uno::RuntimeException)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pImage );
+ if( pWrap )
+ {
+ if( !pWrap->mpImage && pWrap->mpContext )
+ {
+ uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleImage::static_type(NULL) );
+ pWrap->mpImage = reinterpret_cast< accessibility::XAccessibleImage * > (any.pReserved);
+ pWrap->mpImage->acquire();
+ }
+
+ return pWrap->mpImage;
+ }
+
+ return NULL;
+}
+
+extern "C" {
+
+static G_CONST_RETURN gchar *
+image_get_image_description( AtkImage *image )
+{
+ try {
+ accessibility::XAccessibleImage* pImage = getImage( image );
+ if( pImage )
+ return getAsConst( pImage->getAccessibleImageDescription() );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleImageDescription()" );
+ }
+
+ return NULL;
+}
+
+static void
+image_get_image_position( AtkImage *image,
+ gint *x,
+ gint *y,
+ AtkCoordType coord_type )
+{
+ *x = *y = 0;
+ if( ATK_IS_COMPONENT( image ) )
+ atk_component_get_position( ATK_COMPONENT( image ), x, y, coord_type );
+ else
+ g_warning( "FIXME: no image position information" );
+}
+
+static void
+image_get_image_size( AtkImage *image,
+ gint *width,
+ gint *height )
+{
+ *width = 0;
+ *height = 0;
+ try {
+ accessibility::XAccessibleImage* pImage = getImage( image );
+ if( pImage )
+ {
+ *width = pImage->getAccessibleImageWidth();
+ *height = pImage->getAccessibleImageHeight();
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleImageHeight() or Width" );
+ }
+}
+
+static gboolean
+image_set_image_description( AtkImage *, const gchar * )
+{
+ g_warning ("FIXME: no set image description");
+ return FALSE;
+}
+
+} // extern "C"
+
+void
+imageIfaceInit (AtkImageIface *iface)
+{
+ g_return_if_fail (iface != NULL);
+
+ iface->set_image_description = image_set_image_description;
+ iface->get_image_description = image_get_image_description;
+ iface->get_image_position = image_get_image_position;
+ iface->get_image_size = image_get_image_size;
+}
diff --git a/vcl/unx/gtk/a11y/atklistener.cxx b/vcl/unx/gtk/a11y/atklistener.cxx
new file mode 100644
index 000000000000..e02478ac8ad8
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atklistener.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 <com/sun/star/accessibility/TextSegment.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/AccessibleTableModelChange.hpp>
+#include <com/sun/star/accessibility/AccessibleTableModelChangeType.hpp>
+#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
+
+#include "atklistener.hxx"
+#include "atkwrapper.hxx"
+
+#include <rtl/ref.hxx>
+#include <stdio.h>
+
+using namespace com::sun::star;
+
+
+#define CSTRING_FROM_ANY(i) rtl::OUStringToOString( i.get< rtl::OUString >(), RTL_TEXTENCODING_UTF8 ).getStr()
+
+AtkListener::AtkListener( AtkObjectWrapper* pWrapper ) : mpWrapper( pWrapper )
+{
+ if( mpWrapper )
+ {
+ g_object_ref( mpWrapper );
+ updateChildList( mpWrapper->mpContext );
+ }
+}
+
+AtkListener::~AtkListener()
+{
+ if( mpWrapper )
+ g_object_unref( mpWrapper );
+}
+
+/*****************************************************************************/
+
+AtkStateType mapState( const uno::Any &rAny )
+{
+ sal_Int16 nState = accessibility::AccessibleStateType::INVALID;
+ rAny >>= nState;
+ return mapAtkState( nState );
+}
+
+/*****************************************************************************/
+
+// XEventListener implementation
+void AtkListener::disposing( const lang::EventObject& ) throw (uno::RuntimeException)
+{
+ if( mpWrapper )
+ {
+ AtkObject *atk_obj = ATK_OBJECT( mpWrapper );
+
+ // Release all interface references to avoid shutdown problems with
+ // global mutex
+ atk_object_wrapper_dispose( mpWrapper );
+
+ // This is an equivalent to a state change to DEFUNC(T).
+ atk_object_notify_state_change( atk_obj, ATK_STATE_DEFUNCT, TRUE );
+
+ if( atk_get_focus_object() == atk_obj )
+ atk_focus_tracker_notify( NULL );
+
+ // Release the wrapper object so that it can vanish ..
+ g_object_unref( mpWrapper );
+ mpWrapper = NULL;
+ }
+}
+
+/*****************************************************************************/
+
+static AtkObject *getObjFromAny( const uno::Any &rAny )
+{
+ uno::Reference< accessibility::XAccessible > xAccessible;
+ rAny >>= xAccessible;
+ return xAccessible.is() ? atk_object_wrapper_ref( xAccessible ) : NULL;
+}
+
+/*****************************************************************************/
+
+// Updates the child list held to provide the old IndexInParent on children_changed::remove
+void AtkListener::updateChildList(accessibility::XAccessibleContext* pContext)
+{
+ m_aChildList.clear();
+
+ uno::Reference< accessibility::XAccessibleStateSet > xStateSet = pContext->getAccessibleStateSet();
+ if( xStateSet.is()
+ && !xStateSet->contains(accessibility::AccessibleStateType::DEFUNC)
+ && !xStateSet->contains(accessibility::AccessibleStateType::MANAGES_DESCENDANTS) )
+ {
+ sal_Int32 nChildren = pContext->getAccessibleChildCount();
+ m_aChildList.resize(nChildren);
+ for(sal_Int32 n = 0; n < nChildren; n++)
+ {
+ m_aChildList[n] = pContext->getAccessibleChild(n);
+ OSL_ASSERT(m_aChildList[n].is());
+ }
+ }
+}
+
+/*****************************************************************************/
+
+void AtkListener::handleChildAdded(
+ const uno::Reference< accessibility::XAccessibleContext >& rxParent,
+ const uno::Reference< accessibility::XAccessible>& rxAccessible)
+{
+ AtkObject * pChild = atk_object_wrapper_ref( rxAccessible );
+
+ if( pChild )
+ {
+ updateChildList(rxParent.get());
+
+ atk_object_wrapper_add_child( mpWrapper, pChild,
+ atk_object_get_index_in_parent( pChild ));
+
+ g_object_unref( pChild );
+ }
+}
+
+/*****************************************************************************/
+
+void AtkListener::handleChildRemoved(
+ const uno::Reference< accessibility::XAccessibleContext >& rxParent,
+ const uno::Reference< accessibility::XAccessible>& rxChild)
+{
+ sal_Int32 nIndex = -1;
+
+ // Locate the child in the children list
+ size_t n, nmax = m_aChildList.size();
+ for( n = 0; n < nmax; ++n )
+ {
+ if( rxChild == m_aChildList[n] )
+ {
+ nIndex = n;
+ break;
+ }
+ }
+
+ // FIXME: two problems here:
+ // a) we get child-removed events for objects that are no real childs
+ // in the accessibility hierarchy or have been removed before due to
+ // some child removing batch.
+ // b) spi_atk_bridge_signal_listener ignores the given parameters
+ // for children_changed events and always asks the parent for the
+ // 0. child, which breaks somehow on vanishing list boxes.
+ // Ignoring "remove" events for objects not in the m_aChildList
+ // for now.
+ if( nIndex >= 0 )
+ {
+ updateChildList(rxParent.get());
+
+ AtkObject * pChild = atk_object_wrapper_ref( rxChild, false );
+ if( pChild )
+ {
+ atk_object_wrapper_remove_child( mpWrapper, pChild, nIndex );
+ g_object_unref( pChild );
+ }
+ }
+}
+
+/*****************************************************************************/
+
+void AtkListener::handleInvalidateChildren(
+ const uno::Reference< accessibility::XAccessibleContext >& rxParent)
+{
+ // Send notifications for all previous children
+ size_t n = m_aChildList.size();
+ while( n-- > 0 )
+ {
+ if( m_aChildList[n].is() )
+ {
+ AtkObject * pChild = atk_object_wrapper_ref( m_aChildList[n], false );
+ if( pChild )
+ {
+ atk_object_wrapper_remove_child( mpWrapper, pChild, n );
+ g_object_unref( pChild );
+ }
+ }
+ }
+
+ updateChildList(rxParent.get());
+
+ // Send notifications for all new children
+ size_t nmax = m_aChildList.size();
+ for( n = 0; n < nmax; ++n )
+ {
+ if( m_aChildList[n].is() )
+ {
+ AtkObject * pChild = atk_object_wrapper_ref( m_aChildList[n] );
+
+ if( pChild )
+ {
+ atk_object_wrapper_add_child( mpWrapper, pChild, n );
+ g_object_unref( pChild );
+ }
+ }
+ }
+}
+
+/*****************************************************************************/
+
+static uno::Reference< accessibility::XAccessibleContext >
+getAccessibleContextFromSource( const uno::Reference< uno::XInterface >& rxSource )
+{
+ uno::Reference< accessibility::XAccessibleContext > xContext(rxSource, uno::UNO_QUERY);
+ if( ! xContext.is() )
+ {
+ g_warning( "ERROR: Event source does not implement XAccessibleContext" );
+
+ // Second try - query for XAccessible, which should give us access to
+ // XAccessibleContext.
+ uno::Reference< accessibility::XAccessible > xAccessible(rxSource, uno::UNO_QUERY);
+ if( xAccessible.is() )
+ xContext = xAccessible->getAccessibleContext();
+ }
+
+ return xContext;
+}
+
+/*****************************************************************************/
+
+// XAccessibleEventListener
+void AtkListener::notifyEvent( const accessibility::AccessibleEventObject& aEvent ) throw( uno::RuntimeException )
+{
+ if( !mpWrapper )
+ return;
+
+ AtkObject *atk_obj = ATK_OBJECT( mpWrapper );
+
+ switch( aEvent.EventId )
+ {
+ // AtkObject signals:
+ // Hierarchy signals
+ case accessibility::AccessibleEventId::CHILD:
+ {
+ uno::Reference< accessibility::XAccessibleContext > xParent;
+ uno::Reference< accessibility::XAccessible > xChild;
+
+ xParent = getAccessibleContextFromSource(aEvent.Source);
+ g_return_if_fail( xParent.is() );
+
+ if( aEvent.OldValue >>= xChild )
+ handleChildRemoved(xParent, xChild);
+
+ if( aEvent.NewValue >>= xChild )
+ handleChildAdded(xParent, xChild);
+ }
+ break;
+
+ case accessibility::AccessibleEventId::INVALIDATE_ALL_CHILDREN:
+ {
+ uno::Reference< accessibility::XAccessibleContext > xParent;
+
+ xParent = getAccessibleContextFromSource(aEvent.Source);
+ g_return_if_fail( xParent.is() );
+
+ handleInvalidateChildren(xParent);
+ }
+ break;
+
+ case accessibility::AccessibleEventId::NAME_CHANGED:
+ {
+ rtl::OUString aName;
+ if( aEvent.NewValue >>= aName )
+ {
+ atk_object_set_name(atk_obj,
+ rtl::OUStringToOString(aName, RTL_TEXTENCODING_UTF8).getStr());
+ }
+ }
+ break;
+
+ case accessibility::AccessibleEventId::DESCRIPTION_CHANGED:
+ {
+ rtl::OUString aDescription;
+ if( aEvent.NewValue >>= aDescription )
+ {
+ atk_object_set_description(atk_obj,
+ rtl::OUStringToOString(aDescription, RTL_TEXTENCODING_UTF8).getStr());
+ }
+ }
+ break;
+
+ case accessibility::AccessibleEventId::STATE_CHANGED:
+ {
+ AtkStateType eOldState = mapState( aEvent.OldValue );
+ AtkStateType eNewState = mapState( aEvent.NewValue );
+
+ gboolean bState = eNewState != ATK_STATE_INVALID;
+ AtkStateType eRealState = bState ? eNewState : eOldState;
+
+ atk_object_notify_state_change( atk_obj, eRealState, bState );
+ break;
+ }
+
+ case accessibility::AccessibleEventId::BOUNDRECT_CHANGED:
+
+#ifdef HAS_ATKRECTANGLE
+ if( ATK_IS_COMPONENT( atk_obj ) )
+ {
+ AtkRectangle rect;
+
+ atk_component_get_extents( ATK_COMPONENT( atk_obj ),
+ &rect.x,
+ &rect.y,
+ &rect.width,
+ &rect.height,
+ ATK_XY_SCREEN );
+
+ g_signal_emit_by_name( atk_obj, "bounds_changed", &rect );
+ }
+ else
+ g_warning( "bounds_changed event for object not implementing AtkComponent\n");
+#endif
+
+ break;
+
+ case accessibility::AccessibleEventId::VISIBLE_DATA_CHANGED:
+ g_signal_emit_by_name( atk_obj, "visible-data-changed" );
+ break;
+
+ case accessibility::AccessibleEventId::ACTIVE_DESCENDANT_CHANGED:
+ {
+ AtkObject *pChild = getObjFromAny( aEvent.NewValue );
+ if( pChild )
+ {
+ g_signal_emit_by_name( atk_obj, "active-descendant-changed", pChild );
+ g_object_unref( pChild );
+ }
+ break;
+ }
+
+ // --> OD 2009-05-26 #i92103#
+ case accessibility::AccessibleEventId::LISTBOX_ENTRY_EXPANDED:
+ {
+ AtkObject *pChild = getObjFromAny( aEvent.NewValue );
+ if( pChild )
+ {
+ AtkStateType eExpandedState = ATK_STATE_EXPANDED;
+ atk_object_notify_state_change( pChild, eExpandedState, true );
+ g_object_unref( pChild );
+ }
+ break;
+ }
+
+ case accessibility::AccessibleEventId::LISTBOX_ENTRY_COLLAPSED:
+ {
+ AtkObject *pChild = getObjFromAny( aEvent.NewValue );
+ if( pChild )
+ {
+ AtkStateType eExpandedState = ATK_STATE_EXPANDED;
+ atk_object_notify_state_change( pChild, eExpandedState, false );
+ g_object_unref( pChild );
+ }
+ break;
+ }
+ // <--
+
+ // AtkAction signals ...
+ case accessibility::AccessibleEventId::ACTION_CHANGED:
+ g_signal_emit_by_name( G_OBJECT( atk_obj ), "property_change::accessible-actions");
+ break;
+
+ // AtkText
+ case accessibility::AccessibleEventId::CARET_CHANGED:
+ {
+ sal_Int32 nPos=0;
+ aEvent.NewValue >>= nPos;
+ g_signal_emit_by_name( atk_obj, "text_caret_moved", nPos );
+ break;
+ }
+ case accessibility::AccessibleEventId::TEXT_CHANGED:
+ {
+ // TESTME: and remove this comment:
+ // cf. comphelper/source/misc/accessibletexthelper.cxx (implInitTextChangedEvent)
+ accessibility::TextSegment aDeletedText;
+ accessibility::TextSegment aInsertedText;
+
+ // TODO: when GNOME starts to send "update" kind of events, change
+ // we need to re-think this implementation as well
+ if( aEvent.OldValue >>= aDeletedText )
+ {
+ /* Remember the text segment here to be able to return removed text in get_text().
+ * This is clearly a hack to be used until appropriate API exists in atk to pass
+ * the string value directly or we find a compelling reason to start caching the
+ * UTF-8 converted strings in the atk wrapper object.
+ */
+
+ g_object_set_data( G_OBJECT(atk_obj), "ooo::text_changed::delete", &aDeletedText);
+
+ g_signal_emit_by_name( atk_obj, "text_changed::delete",
+ (gint) aDeletedText.SegmentStart,
+ (gint)( aDeletedText.SegmentEnd - aDeletedText.SegmentStart ) );
+
+ g_object_steal_data( G_OBJECT(atk_obj), "ooo::text_changed::delete" );
+ }
+
+ if( aEvent.NewValue >>= aInsertedText )
+ g_signal_emit_by_name( atk_obj, "text_changed::insert",
+ (gint) aInsertedText.SegmentStart,
+ (gint)( aInsertedText.SegmentEnd - aInsertedText.SegmentStart ) );
+ break;
+ }
+
+ case accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED:
+ {
+ g_signal_emit_by_name( atk_obj, "text-selection-changed" );
+ break;
+ }
+
+ case accessibility::AccessibleEventId::TEXT_ATTRIBUTE_CHANGED:
+ g_signal_emit_by_name( atk_obj, "text-attributes-changed" );
+ break;
+
+ // AtkValue
+ case accessibility::AccessibleEventId::VALUE_CHANGED:
+ g_object_notify( G_OBJECT( atk_obj ), "accessible-value" );
+ break;
+
+ case accessibility::AccessibleEventId::CONTENT_FLOWS_FROM_RELATION_CHANGED:
+ case accessibility::AccessibleEventId::CONTENT_FLOWS_TO_RELATION_CHANGED:
+ case accessibility::AccessibleEventId::CONTROLLED_BY_RELATION_CHANGED:
+ case accessibility::AccessibleEventId::CONTROLLER_FOR_RELATION_CHANGED:
+ case accessibility::AccessibleEventId::LABEL_FOR_RELATION_CHANGED:
+ case accessibility::AccessibleEventId::LABELED_BY_RELATION_CHANGED:
+ case accessibility::AccessibleEventId::MEMBER_OF_RELATION_CHANGED:
+ case accessibility::AccessibleEventId::SUB_WINDOW_OF_RELATION_CHANGED:
+ // FIXME: ask Bill how Atk copes with this little lot ...
+ break;
+
+ // AtkTable
+ case accessibility::AccessibleEventId::TABLE_MODEL_CHANGED:
+ {
+ accessibility::AccessibleTableModelChange aChange;
+ aEvent.NewValue >>= aChange;
+
+ sal_Int32 nRowsChanged = aChange.LastRow - aChange.FirstRow + 1;
+ sal_Int32 nColumnsChanged = aChange.LastColumn - aChange.FirstColumn + 1;
+
+ static const struct {
+ const char *row;
+ const char *col;
+ } aSignalNames[] =
+ {
+ { NULL, NULL }, // dummy
+ { "row_inserted", "column_inserted" }, // INSERT = 1
+ { "row_deleted", "column_deleted" } // DELETE = 2
+ };
+ switch( aChange.Type )
+ {
+ case accessibility::AccessibleTableModelChangeType::INSERT:
+ case accessibility::AccessibleTableModelChangeType::DELETE:
+ if( nRowsChanged > 0 )
+ g_signal_emit_by_name( G_OBJECT( atk_obj ),
+ aSignalNames[aChange.Type].row,
+ aChange.FirstRow, nRowsChanged );
+ if( nColumnsChanged > 0 )
+ g_signal_emit_by_name( G_OBJECT( atk_obj ),
+ aSignalNames[aChange.Type].col,
+ aChange.FirstColumn, nColumnsChanged );
+ break;
+
+ case accessibility::AccessibleTableModelChangeType::UPDATE:
+ // This is not really a model change, is it ?
+ break;
+ default:
+ g_warning( "TESTME: unusual table model change %d\n", aChange.Type );
+ break;
+ }
+ g_signal_emit_by_name( G_OBJECT( atk_obj ), "model-changed" );
+ break;
+ }
+
+ case accessibility::AccessibleEventId::TABLE_COLUMN_HEADER_CHANGED:
+ g_signal_emit_by_name( G_OBJECT( atk_obj ), "property_change::accessible-table-column-header");
+ break;
+
+ case accessibility::AccessibleEventId::TABLE_CAPTION_CHANGED:
+ g_signal_emit_by_name( G_OBJECT( atk_obj ), "property_change::accessible-table-caption");
+ break;
+
+ case accessibility::AccessibleEventId::TABLE_COLUMN_DESCRIPTION_CHANGED:
+ g_signal_emit_by_name( G_OBJECT( atk_obj ), "property_change::accessible-table-column-description");
+ break;
+
+ case accessibility::AccessibleEventId::TABLE_ROW_DESCRIPTION_CHANGED:
+ g_signal_emit_by_name( G_OBJECT( atk_obj ), "property_change::accessible-table-row-description");
+ break;
+
+ case accessibility::AccessibleEventId::TABLE_ROW_HEADER_CHANGED:
+ g_signal_emit_by_name( G_OBJECT( atk_obj ), "property_change::accessible-table-row-header");
+ break;
+
+ case accessibility::AccessibleEventId::TABLE_SUMMARY_CHANGED:
+ g_signal_emit_by_name( G_OBJECT( atk_obj ), "property_change::accessible-table-summary");
+ break;
+
+ case accessibility::AccessibleEventId::SELECTION_CHANGED:
+ g_signal_emit_by_name( G_OBJECT( atk_obj ), "selection_changed");
+ break;
+
+ case accessibility::AccessibleEventId::HYPERTEXT_CHANGED:
+ g_signal_emit_by_name( G_OBJECT( atk_obj ), "property_change::accessible-hypertext-offset");
+ break;
+
+ default:
+ g_warning( "Unknown event notification %d", aEvent.EventId );
+ break;
+ }
+}
diff --git a/vcl/unx/gtk/a11y/atklistener.hxx b/vcl/unx/gtk/a11y/atklistener.hxx
new file mode 100644
index 000000000000..d2889caa3e24
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atklistener.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _ATK_LISTENER_HXX_
+#define _ATK_LISTENER_HXX_
+
+#include <com/sun/star/accessibility/XAccessibleEventListener.hpp>
+#include <cppuhelper/implbase1.hxx>
+
+#include <vector>
+
+#include "atkwrapper.hxx"
+
+typedef std::vector< ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > > AccessibleVector;
+
+class AtkListener : public ::cppu::WeakImplHelper1< ::com::sun::star::accessibility::XAccessibleEventListener >
+{
+public:
+ AtkListener(AtkObjectWrapper * pWrapper);
+
+ // XEventListener
+ virtual void disposing( const ::com::sun::star::lang::EventObject& Source )
+ throw (::com::sun::star::uno::RuntimeException);
+
+ // XAccessibleEventListener
+ virtual void notifyEvent( const ::com::sun::star::accessibility::AccessibleEventObject& aEvent )
+ throw( ::com::sun::star::uno::RuntimeException );
+
+ AtkObjectWrapper *mpWrapper;
+ AccessibleVector m_aChildList;
+
+private:
+
+ virtual ~AtkListener();
+
+ // Updates the child list held to provide the old IndexInParent on children_changed::remove
+ void updateChildList(::com::sun::star::accessibility::XAccessibleContext* pContext);
+
+ // Process CHILD_EVENT notifications with a new child added
+ void handleChildAdded(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >& rxParent,
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible>& rxChild);
+
+ // Process CHILD_EVENT notifications with a child removed
+ void handleChildRemoved(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >& rxParent,
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible>& rxChild);
+
+ // Process INVALIDATE_ALL_CHILDREN notification
+ void handleInvalidateChildren(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >& rxParent);
+};
+
+#endif /* _ATK_LISTENER_HXX_ */
+
diff --git a/vcl/unx/gtk/a11y/atkregistry.cxx b/vcl/unx/gtk/a11y/atkregistry.cxx
new file mode 100644
index 000000000000..81ec22dc4ce1
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkregistry.cxx
@@ -0,0 +1,71 @@
+/*************************************************************************
+ *
+ * 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 "atkregistry.hxx"
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::uno;
+
+static GHashTable *uno_to_gobject = NULL;
+
+/*****************************************************************************/
+
+AtkObject *
+ooo_wrapper_registry_get(const Reference< XAccessible >& rxAccessible)
+{
+ if( uno_to_gobject )
+ {
+ gpointer cached =
+ g_hash_table_lookup(uno_to_gobject, (gpointer) rxAccessible.get());
+
+ if( cached )
+ return ATK_OBJECT( cached );
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+void
+ooo_wrapper_registry_add(const Reference< XAccessible >& rxAccessible, AtkObject *obj)
+{
+ if( !uno_to_gobject )
+ uno_to_gobject = g_hash_table_new (NULL, NULL);
+
+ g_hash_table_insert( uno_to_gobject, (gpointer) rxAccessible.get(), obj );
+}
+
+/*****************************************************************************/
+
+void
+ooo_wrapper_registry_remove(XAccessible *pAccessible)
+{
+ if( uno_to_gobject )
+ g_hash_table_remove( uno_to_gobject, (gpointer) pAccessible );
+}
+
diff --git a/vcl/unx/gtk/a11y/atkregistry.hxx b/vcl/unx/gtk/a11y/atkregistry.hxx
new file mode 100644
index 000000000000..f4de3b2e4c1e
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkregistry.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef __ATK_REGISTRY_HXX__
+#define __ATK_REGISTRY_HXX__
+
+#include <com/sun/star/accessibility/XAccessible.hpp>
+#include <atk/atk.h>
+
+AtkObject * ooo_wrapper_registry_get(const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& rxAccessible);
+
+void ooo_wrapper_registry_add(const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& rxAccessible, AtkObject *obj);
+
+void ooo_wrapper_registry_remove(::com::sun::star::accessibility::XAccessible *pAccessible);
+
+#endif // __ATK_REGISTRY_HXX_
diff --git a/vcl/unx/gtk/a11y/atkselection.cxx b/vcl/unx/gtk/a11y/atkselection.cxx
new file mode 100644
index 000000000000..172faac4c704
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkselection.cxx
@@ -0,0 +1,195 @@
+/*************************************************************************
+ *
+ * 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 "atkwrapper.hxx"
+
+#include <com/sun/star/accessibility/XAccessibleSelection.hpp>
+
+#include <stdio.h>
+
+using namespace ::com::sun::star;
+
+static accessibility::XAccessibleSelection*
+ getSelection( AtkSelection *pSelection ) throw (uno::RuntimeException)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pSelection );
+ if( pWrap )
+ {
+ if( !pWrap->mpSelection && pWrap->mpContext )
+ {
+ uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleSelection::static_type(NULL) );
+ pWrap->mpSelection = reinterpret_cast< accessibility::XAccessibleSelection * > (any.pReserved);
+ pWrap->mpSelection->acquire();
+ }
+
+ return pWrap->mpSelection;
+ }
+
+ return NULL;
+}
+
+extern "C" {
+
+static gboolean
+selection_add_selection( AtkSelection *selection,
+ gint i )
+{
+ try {
+ accessibility::XAccessibleSelection* pSelection = getSelection( selection );
+ if( pSelection )
+ {
+ pSelection->selectAccessibleChild( i );
+ return TRUE;
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in selectAccessibleChild()" );
+ }
+
+ return FALSE;
+}
+
+static gboolean
+selection_clear_selection( AtkSelection *selection )
+{
+ try {
+ accessibility::XAccessibleSelection* pSelection = getSelection( selection );
+ if( pSelection )
+ {
+ pSelection->clearAccessibleSelection();
+ return TRUE;
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in selectAccessibleChild()" );
+ }
+
+ return FALSE;
+}
+
+static AtkObject*
+selection_ref_selection( AtkSelection *selection,
+ gint i )
+{
+ try {
+ accessibility::XAccessibleSelection* pSelection = getSelection( selection );
+ if( pSelection )
+ return atk_object_wrapper_ref( pSelection->getSelectedAccessibleChild( i ) );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getSelectedAccessibleChild()" );
+ }
+
+ return NULL;
+}
+
+static gint
+selection_get_selection_count( AtkSelection *selection)
+{
+ try {
+ accessibility::XAccessibleSelection* pSelection = getSelection( selection );
+ if( pSelection )
+ return pSelection->getSelectedAccessibleChildCount();
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getSelectedAccessibleChildCount()" );
+ }
+
+ return -1;
+}
+
+static gboolean
+selection_is_child_selected( AtkSelection *selection,
+ gint i)
+{
+ try {
+ accessibility::XAccessibleSelection* pSelection = getSelection( selection );
+ if( pSelection )
+ return pSelection->isAccessibleChildSelected( i );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getSelectedAccessibleChildCount()" );
+ }
+
+ return FALSE;
+}
+
+static gboolean
+selection_remove_selection( AtkSelection *selection,
+ gint i )
+{
+ try {
+ accessibility::XAccessibleSelection* pSelection = getSelection( selection );
+ if( pSelection )
+ {
+ pSelection->deselectAccessibleChild( i );
+ return TRUE;
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getSelectedAccessibleChildCount()" );
+ }
+
+ return FALSE;
+}
+
+static gboolean
+selection_select_all_selection( AtkSelection *selection)
+{
+ try {
+ accessibility::XAccessibleSelection* pSelection = getSelection( selection );
+ if( pSelection )
+ {
+ pSelection->selectAllAccessibleChildren();
+ return TRUE;
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getSelectedAccessibleChildCount()" );
+ }
+
+ return FALSE;
+}
+
+} // extern "C"
+
+void
+selectionIfaceInit( AtkSelectionIface *iface)
+{
+ g_return_if_fail (iface != NULL);
+
+ iface->add_selection = selection_add_selection;
+ iface->clear_selection = selection_clear_selection;
+ iface->ref_selection = selection_ref_selection;
+ iface->get_selection_count = selection_get_selection_count;
+ iface->is_child_selected = selection_is_child_selected;
+ iface->remove_selection = selection_remove_selection;
+ iface->select_all_selection = selection_select_all_selection;
+}
diff --git a/vcl/unx/gtk/a11y/atktable.cxx b/vcl/unx/gtk/a11y/atktable.cxx
new file mode 100644
index 000000000000..78571ff11c34
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atktable.cxx
@@ -0,0 +1,721 @@
+/*************************************************************************
+ *
+ * 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 "atkwrapper.hxx"
+
+#include <com/sun/star/accessibility/XAccessibleTable.hpp>
+
+#ifdef ENABLE_TRACING
+#include <stdio.h>
+#endif
+
+using namespace ::com::sun::star;
+
+static inline AtkObject *
+atk_object_wrapper_conditional_ref( const uno::Reference< accessibility::XAccessible >& rxAccessible )
+{
+#ifdef ENABLE_TRACING
+ fprintf( stderr, ": %p\n", rxAccessible.get() );
+#endif
+
+ if( rxAccessible.is() )
+ return atk_object_wrapper_ref( rxAccessible );
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+// FIXME
+static G_CONST_RETURN gchar *
+getAsConst( rtl::OUString rString )
+{
+ static const int nMax = 10;
+ static rtl::OString aUgly[nMax];
+ static int nIdx = 0;
+ nIdx = (nIdx + 1) % nMax;
+ aUgly[nIdx] = rtl::OUStringToOString( rString, RTL_TEXTENCODING_UTF8 );
+ return aUgly[ nIdx ];
+}
+
+/*****************************************************************************/
+
+static accessibility::XAccessibleTable*
+ getTable( AtkTable *pTable ) throw (uno::RuntimeException)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pTable );
+ if( pWrap )
+ {
+ if( !pWrap->mpTable && pWrap->mpContext )
+ {
+ uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleTable::static_type(NULL) );
+ pWrap->mpTable = reinterpret_cast< accessibility::XAccessibleTable * > (any.pReserved);
+ pWrap->mpTable->acquire();
+ }
+
+ return pWrap->mpTable;
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+extern "C" {
+
+static AtkObject*
+table_wrapper_ref_at (AtkTable *table,
+ gint row,
+ gint column)
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "getAccessibleCellAt( %u, %u ) returns", row, column );
+
+ if( column >= 255 )
+ fprintf(stderr, "getAccessibleCellAt( %u, %u ) returns", row, column );
+
+#endif
+
+ if( pTable )
+ return atk_object_wrapper_conditional_ref( pTable->getAccessibleCellAt( row, column ) );
+ }
+
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleCellAt()" );
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+static gint
+table_wrapper_get_index_at (AtkTable *table,
+ gint row,
+ gint column)
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "getAccessibleIndex( %u, %u ) returns %u\n",
+ row, column, pTable->getAccessibleIndex( row, column ) );
+#endif
+
+ if( pTable )
+ return pTable->getAccessibleIndex( row, column );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleIndex()" );
+ }
+
+ return -1;
+}
+
+/*****************************************************************************/
+
+static gint
+table_wrapper_get_column_at_index (AtkTable *table,
+ gint nIndex)
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "getAccessibleColumn( %u ) returns %u\n",
+ nIndex, pTable->getAccessibleColumn( nIndex ) );
+#endif
+
+ if( pTable )
+ return pTable->getAccessibleColumn( nIndex );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleColumn()" );
+ }
+
+ return -1;
+}
+
+/*****************************************************************************/
+
+static gint
+table_wrapper_get_row_at_index( AtkTable *table,
+ gint nIndex )
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "getAccessibleRow( %u ) returns %u\n",
+ nIndex, pTable->getAccessibleRow( nIndex ) );
+#endif
+
+ if( pTable )
+ return pTable->getAccessibleRow( nIndex );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleRow()" );
+ }
+
+ return -1;
+}
+
+/*****************************************************************************/
+
+static gint
+table_wrapper_get_n_columns( AtkTable *table )
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "XAccessibleTable::getAccessibleColumnCount returns %u\n",
+ pTable->getAccessibleColumnCount() );
+#endif
+
+ if( pTable )
+ return pTable->getAccessibleColumnCount();
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleColumnCount()" );
+ }
+
+ return -1;
+}
+
+/*****************************************************************************/
+
+static gint
+table_wrapper_get_n_rows( AtkTable *table )
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "getAccessibleRowCount() returns %u\n",
+ pTable->getAccessibleRowCount() );
+#endif
+
+ if( pTable )
+ return pTable->getAccessibleRowCount();
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleRowCount()" );
+ }
+
+ return -1;
+}
+
+/*****************************************************************************/
+
+static gint
+table_wrapper_get_column_extent_at( AtkTable *table,
+ gint row,
+ gint column )
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "getAccessibleColumnExtentAt( %u, %u ) returns %u\n",
+ row, column, pTable->getAccessibleColumnExtentAt( row, column ) );
+#endif
+
+ if( pTable )
+ return pTable->getAccessibleColumnExtentAt( row, column );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleColumnExtentAt()" );
+ }
+
+ return -1;
+}
+
+/*****************************************************************************/
+
+static gint
+table_wrapper_get_row_extent_at( AtkTable *table,
+ gint row,
+ gint column )
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "getAccessibleRowExtentAt( %u, %u ) returns %u\n",
+ row, column, pTable->getAccessibleRowExtentAt( row, column ) );
+#endif
+
+ if( pTable )
+ return pTable->getAccessibleRowExtentAt( row, column );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleRowExtentAt()" );
+ }
+
+ return -1;
+}
+
+/*****************************************************************************/
+
+static AtkObject *
+table_wrapper_get_caption( AtkTable *table )
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "getAccessibleCaption() returns" );
+#endif
+
+ if( pTable )
+ return atk_object_wrapper_conditional_ref( pTable->getAccessibleCaption() );
+ }
+
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleCaption()" );
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+static G_CONST_RETURN gchar *
+table_wrapper_get_row_description( AtkTable *table,
+ gint row )
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "getAccessibleRowDescription( %u ) returns %s\n",
+ row, getAsConst( pTable->getAccessibleRowDescription( row ) ) );
+#endif
+
+ if( pTable )
+ return getAsConst( pTable->getAccessibleRowDescription( row ) );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleRowDescription()" );
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+static G_CONST_RETURN gchar *
+table_wrapper_get_column_description( AtkTable *table,
+ gint column )
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "getAccessibleColumnDescription( %u ) returns %s\n",
+ column, getAsConst( pTable->getAccessibleColumnDescription( column ) ) );
+#endif
+
+ if( pTable )
+ return getAsConst( pTable->getAccessibleColumnDescription( column ) );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleColumnDescription()" );
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+static AtkObject *
+table_wrapper_get_row_header( AtkTable *table,
+ gint row )
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+ if( pTable )
+ {
+ uno::Reference< accessibility::XAccessibleTable > xRowHeaders( pTable->getAccessibleRowHeaders() );
+
+#ifdef ENABLE_TRACING
+ if( xRowHeaders.is() )
+ fprintf(stderr, "getAccessibleRowHeader( %u )->getAccessibleCellAt( 0, %u ) returns",
+ row, row );
+ else
+ fprintf(stderr, "getAccessibleRowHeader( %u ) returns %p\n", row, xRowHeaders.get() );
+#endif
+
+ if( xRowHeaders.is() )
+ return atk_object_wrapper_conditional_ref( xRowHeaders->getAccessibleCellAt( row, 0 ) );
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleRowHeaders()" );
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+static AtkObject *
+table_wrapper_get_column_header( AtkTable *table,
+ gint column )
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+ if( pTable )
+ {
+ uno::Reference< accessibility::XAccessibleTable > xColumnHeaders( pTable->getAccessibleColumnHeaders() );
+
+#ifdef ENABLE_TRACING
+ if( xColumnHeaders.is() )
+ fprintf(stderr, "getAccessibleColumnHeader( %u )->getAccessibleCellAt( 0, %u ) returns",
+ column, column );
+ else
+ fprintf(stderr, "getAccessibleColumnHeader( %u ) returns %p\n", column, xColumnHeaders.get() );
+#endif
+
+ if( xColumnHeaders.is() )
+ return atk_object_wrapper_conditional_ref( xColumnHeaders->getAccessibleCellAt( 0, column ) );
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleColumnHeaders()" );
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+static AtkObject *
+table_wrapper_get_summary( AtkTable *table )
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "getAccessibleSummary() returns" );
+#endif
+
+ if( pTable )
+ {
+ // FIXME: Summary ??
+// AtkObject* summary;
+ return atk_object_wrapper_conditional_ref( pTable->getAccessibleSummary() );
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleSummary()" );
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+static gint
+convertToGIntArray( const uno::Sequence< ::sal_Int32 >& aSequence, gint **pSelected )
+{
+ if( aSequence.getLength() )
+ {
+ *pSelected = g_new( gint, aSequence.getLength() );
+
+ for( sal_Int32 i = 0; i < aSequence.getLength(); i++ )
+ (*pSelected) [i] = aSequence[i];
+ }
+
+ return aSequence.getLength();
+}
+
+/*****************************************************************************/
+
+static gint
+table_wrapper_get_selected_columns( AtkTable *table,
+ gint **pSelected )
+{
+ *pSelected = NULL;
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "getSelectedAccessibleColumns() \n" );
+#endif
+
+ if( pTable )
+ return convertToGIntArray( pTable->getSelectedAccessibleColumns(), pSelected );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getSelectedAccessibleColumns()" );
+ }
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+static gint
+table_wrapper_get_selected_rows( AtkTable *table,
+ gint **pSelected )
+{
+ *pSelected = NULL;
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "getSelectedAccessibleRows() \n" );
+#endif
+
+ if( pTable )
+ return convertToGIntArray( pTable->getSelectedAccessibleRows(), pSelected );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getSelectedAccessibleRows()" );
+ }
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+static gboolean
+table_wrapper_is_column_selected( AtkTable *table,
+ gint column )
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "isAccessibleColumnSelected( %u ) returns %s\n",
+ column, pTable->isAccessibleColumnSelected( column ) ? "true" : "false" );
+#endif
+
+ if( pTable )
+ return pTable->isAccessibleColumnSelected( column );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in isAccessibleColumnSelected()" );
+ }
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+static gboolean
+table_wrapper_is_row_selected( AtkTable *table,
+ gint row )
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "isAccessibleRowSelected( %u ) returns %s\n",
+ row, pTable->isAccessibleRowSelected( row ) ? "true" : "false" );
+#endif
+
+ if( pTable )
+ return pTable->isAccessibleRowSelected( row );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in isAccessibleRowSelected()" );
+ }
+
+ return FALSE;
+}
+
+/*****************************************************************************/
+
+static gboolean
+table_wrapper_is_selected( AtkTable *table,
+ gint row,
+ gint column )
+{
+ try {
+ accessibility::XAccessibleTable* pTable = getTable( table );
+
+#ifdef ENABLE_TRACING
+ if( pTable )
+ fprintf(stderr, "isAccessibleSelected( %u, %u ) returns %s\n",
+ row, column, pTable->isAccessibleSelected( row , column ) ? "true" : "false" );
+#endif
+
+ if( pTable )
+ return pTable->isAccessibleSelected( row, column );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in isAccessibleSelected()" );
+ }
+
+ return FALSE;
+}
+
+/*****************************************************************************/
+
+static gboolean
+table_wrapper_add_row_selection( AtkTable *, gint )
+{
+ g_warning( "FIXME: no simple analogue for add_row_selection" );
+ return 0;
+}
+
+/*****************************************************************************/
+
+static gboolean
+table_wrapper_remove_row_selection( AtkTable *, gint )
+{
+ g_warning( "FIXME: no simple analogue for remove_row_selection" );
+ return 0;
+}
+
+/*****************************************************************************/
+
+static gboolean
+table_wrapper_add_column_selection( AtkTable *, gint )
+{
+ g_warning( "FIXME: no simple analogue for add_column_selection" );
+ return 0;
+}
+
+/*****************************************************************************/
+
+static gboolean
+table_wrapper_remove_column_selection( AtkTable *, gint )
+{
+ g_warning( "FIXME: no simple analogue for remove_column_selection" );
+ return 0;
+}
+
+/*****************************************************************************/
+
+static void
+table_wrapper_set_caption( AtkTable *, AtkObject * )
+{ // meaningless helper
+}
+
+/*****************************************************************************/
+
+static void
+table_wrapper_set_column_description( AtkTable *, gint, const gchar * )
+{ // meaningless helper
+}
+
+
+/*****************************************************************************/
+
+static void
+table_wrapper_set_column_header( AtkTable *, gint, AtkObject * )
+{ // meaningless helper
+}
+
+
+/*****************************************************************************/
+
+static void
+table_wrapper_set_row_description( AtkTable *, gint, const gchar * )
+{ // meaningless helper
+}
+
+/*****************************************************************************/
+
+static void
+table_wrapper_set_row_header( AtkTable *, gint, AtkObject * )
+{ // meaningless helper
+}
+
+/*****************************************************************************/
+
+static void
+table_wrapper_set_summary( AtkTable *, AtkObject * )
+{ // meaningless helper
+}
+
+/*****************************************************************************/
+
+} // extern "C"
+
+void
+tableIfaceInit (AtkTableIface *iface)
+{
+ g_return_if_fail (iface != NULL);
+
+ iface->ref_at = table_wrapper_ref_at;
+ iface->get_n_rows = table_wrapper_get_n_rows;
+ iface->get_n_columns = table_wrapper_get_n_columns;
+ iface->get_index_at = table_wrapper_get_index_at;
+ iface->get_column_at_index = table_wrapper_get_column_at_index;
+ iface->get_row_at_index = table_wrapper_get_row_at_index;
+ iface->is_row_selected = table_wrapper_is_row_selected;
+ iface->is_selected = table_wrapper_is_selected;
+ iface->get_selected_rows = table_wrapper_get_selected_rows;
+ iface->add_row_selection = table_wrapper_add_row_selection;
+ iface->remove_row_selection = table_wrapper_remove_row_selection;
+ iface->add_column_selection = table_wrapper_add_column_selection;
+ iface->remove_column_selection = table_wrapper_remove_column_selection;
+ iface->get_selected_columns = table_wrapper_get_selected_columns;
+ iface->is_column_selected = table_wrapper_is_column_selected;
+ iface->get_column_extent_at = table_wrapper_get_column_extent_at;
+ iface->get_row_extent_at = table_wrapper_get_row_extent_at;
+ iface->get_row_header = table_wrapper_get_row_header;
+ iface->set_row_header = table_wrapper_set_row_header;
+ iface->get_column_header = table_wrapper_get_column_header;
+ iface->set_column_header = table_wrapper_set_column_header;
+ iface->get_caption = table_wrapper_get_caption;
+ iface->set_caption = table_wrapper_set_caption;
+ iface->get_summary = table_wrapper_get_summary;
+ iface->set_summary = table_wrapper_set_summary;
+ iface->get_row_description = table_wrapper_get_row_description;
+ iface->set_row_description = table_wrapper_set_row_description;
+ iface->get_column_description = table_wrapper_get_column_description;
+ iface->set_column_description = table_wrapper_set_column_description;
+}
diff --git a/vcl/unx/gtk/a11y/atktext.cxx b/vcl/unx/gtk/a11y/atktext.cxx
new file mode 100644
index 000000000000..e6d3276891de
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atktext.cxx
@@ -0,0 +1,876 @@
+/*************************************************************************
+ *
+ * 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 "atkwrapper.hxx"
+#include "atktextattributes.hxx"
+#include <algorithm>
+
+#include <com/sun/star/accessibility/AccessibleTextType.hpp>
+#include <com/sun/star/accessibility/TextSegment.hpp>
+#include <com/sun/star/accessibility/XAccessibleMultiLineText.hpp>
+#include <com/sun/star/accessibility/XAccessibleText.hpp>
+#include <com/sun/star/accessibility/XAccessibleTextAttributes.hpp>
+#include <com/sun/star/accessibility/XAccessibleTextMarkup.hpp>
+#include <com/sun/star/text/TextMarkupType.hpp>
+
+// #define ENABLE_TRACING
+
+#ifdef ENABLE_TRACING
+#include <stdio.h>
+#endif
+
+using namespace ::com::sun::star;
+
+static sal_Int16
+text_type_from_boundary(AtkTextBoundary boundary_type)
+{
+ switch(boundary_type)
+ {
+ case ATK_TEXT_BOUNDARY_CHAR:
+ return accessibility::AccessibleTextType::CHARACTER;
+ case ATK_TEXT_BOUNDARY_WORD_START:
+ case ATK_TEXT_BOUNDARY_WORD_END:
+ return accessibility::AccessibleTextType::WORD;
+ case ATK_TEXT_BOUNDARY_SENTENCE_START:
+ case ATK_TEXT_BOUNDARY_SENTENCE_END:
+ return accessibility::AccessibleTextType::SENTENCE;
+ case ATK_TEXT_BOUNDARY_LINE_START:
+ case ATK_TEXT_BOUNDARY_LINE_END:
+ return accessibility::AccessibleTextType::LINE;
+ default:
+ return -1;
+ }
+}
+
+/*****************************************************************************/
+
+static gchar *
+adjust_boundaries( accessibility::XAccessibleText* pText,
+ accessibility::TextSegment& rTextSegment,
+ AtkTextBoundary boundary_type,
+ gint * start_offset, gint * end_offset )
+{
+ accessibility::TextSegment aTextSegment;
+ rtl::OUString aString;
+ gint start = 0, end = 0;
+
+ if( rTextSegment.SegmentText.getLength() > 0 )
+ {
+ switch(boundary_type)
+ {
+ case ATK_TEXT_BOUNDARY_CHAR:
+ case ATK_TEXT_BOUNDARY_LINE_START:
+ case ATK_TEXT_BOUNDARY_LINE_END:
+ case ATK_TEXT_BOUNDARY_SENTENCE_START:
+ start = rTextSegment.SegmentStart;
+ end = rTextSegment.SegmentEnd;
+ aString = rTextSegment.SegmentText;
+ break;
+
+ // the OOo break iterator behaves as SENTENCE_START
+ case ATK_TEXT_BOUNDARY_SENTENCE_END:
+ start = rTextSegment.SegmentStart;
+ end = rTextSegment.SegmentEnd;
+
+ if( start > 0 )
+ --start;
+ if( end > 0 && end < pText->getCharacterCount() - 1 )
+ --end;
+
+ aString = pText->getTextRange(start, end);
+ break;
+
+ case ATK_TEXT_BOUNDARY_WORD_START:
+ start = rTextSegment.SegmentStart;
+
+ // Determine the start index of the next segment
+ aTextSegment = pText->getTextBehindIndex(rTextSegment.SegmentEnd,
+ text_type_from_boundary(boundary_type));
+ if( aTextSegment.SegmentText.getLength() > 0 )
+ end = aTextSegment.SegmentStart;
+ else
+ end = pText->getCharacterCount();
+
+ aString = pText->getTextRange(start, end);
+ break;
+
+ case ATK_TEXT_BOUNDARY_WORD_END:
+ end = rTextSegment.SegmentEnd;
+
+ // Determine the end index of the previous segment
+ aTextSegment = pText->getTextBeforeIndex(rTextSegment.SegmentStart,
+ text_type_from_boundary(boundary_type));
+ if( aTextSegment.SegmentText.getLength() > 0 )
+ start = aTextSegment.SegmentEnd;
+ else
+ start = 0;
+
+ aString = pText->getTextRange(start, end);
+ break;
+
+ default:
+ return NULL;
+ }
+ }
+
+ *start_offset = start;
+ *end_offset = end;
+
+#ifdef ENABLE_TRACING
+ fprintf(stderr, "adjust_boundaries( %d, %d, %d ) returns %d, %d\n",
+ rTextSegment.SegmentStart, rTextSegment.SegmentEnd, boundary_type,
+ start, end);
+#endif
+
+ return OUStringToGChar(aString);
+}
+
+/*****************************************************************************/
+
+static accessibility::XAccessibleText*
+ getText( AtkText *pText ) throw (uno::RuntimeException)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pText );
+ if( pWrap )
+ {
+ if( !pWrap->mpText && pWrap->mpContext )
+ {
+ uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleText::static_type(NULL) );
+ pWrap->mpText = reinterpret_cast< accessibility::XAccessibleText * > (any.pReserved);
+ pWrap->mpText->acquire();
+ }
+
+ return pWrap->mpText;
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+static accessibility::XAccessibleTextMarkup*
+ getTextMarkup( AtkText *pText ) throw (uno::RuntimeException)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pText );
+ if( pWrap )
+ {
+ if( !pWrap->mpTextMarkup && pWrap->mpContext )
+ {
+ uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleTextMarkup::static_type(NULL) );
+ /* Since this not a dedicated interface in Atk and thus has not
+ * been queried during wrapper initialization, we need to check
+ * the return value here.
+ */
+ if( typelib_TypeClass_INTERFACE == any.pType->eTypeClass )
+ {
+ pWrap->mpTextMarkup = reinterpret_cast< accessibility::XAccessibleTextMarkup * > (any.pReserved);
+ if( pWrap->mpTextMarkup )
+ pWrap->mpTextMarkup->acquire();
+ }
+ }
+
+ return pWrap->mpTextMarkup;
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+static accessibility::XAccessibleTextAttributes*
+ getTextAttributes( AtkText *pText ) throw (uno::RuntimeException)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pText );
+ if( pWrap )
+ {
+ if( !pWrap->mpTextAttributes && pWrap->mpContext )
+ {
+ uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleTextAttributes::static_type(NULL) );
+ /* Since this not a dedicated interface in Atk and thus has not
+ * been queried during wrapper initialization, we need to check
+ * the return value here.
+ */
+ if( typelib_TypeClass_INTERFACE == any.pType->eTypeClass )
+ {
+ pWrap->mpTextAttributes = reinterpret_cast< accessibility::XAccessibleTextAttributes * > (any.pReserved);
+ pWrap->mpTextAttributes->acquire();
+ }
+ }
+
+ return pWrap->mpTextAttributes;
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+static accessibility::XAccessibleMultiLineText*
+ getMultiLineText( AtkText *pText ) throw (uno::RuntimeException)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pText );
+ if( pWrap )
+ {
+ if( !pWrap->mpMultiLineText && pWrap->mpContext )
+ {
+ uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleMultiLineText::static_type(NULL) );
+ /* Since this not a dedicated interface in Atk and thus has not
+ * been queried during wrapper initialization, we need to check
+ * the return value here.
+ */
+ if( typelib_TypeClass_INTERFACE == any.pType->eTypeClass )
+ {
+ pWrap->mpMultiLineText = reinterpret_cast< accessibility::XAccessibleMultiLineText * > (any.pReserved);
+ pWrap->mpMultiLineText->acquire();
+ }
+ }
+
+ return pWrap->mpMultiLineText;
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+extern "C" {
+
+static gchar *
+text_wrapper_get_text (AtkText *text,
+ gint start_offset,
+ gint end_offset)
+{
+ gchar * ret = NULL;
+
+ g_return_val_if_fail( (end_offset == -1) || (end_offset >= start_offset), NULL );
+
+ /* at-spi expects the delete event to be send before the deletion happened
+ * so we save the deleted string object in the UNO event notification and
+ * fool libatk-bridge.so here ..
+ */
+ void * pData = g_object_get_data( G_OBJECT(text), "ooo::text_changed::delete" );
+ if( pData != NULL )
+ {
+ accessibility::TextSegment * pTextSegment =
+ reinterpret_cast <accessibility::TextSegment *> (pData);
+
+ if( pTextSegment->SegmentStart == start_offset &&
+ pTextSegment->SegmentEnd == end_offset )
+ {
+ rtl::OString aUtf8 = rtl::OUStringToOString( pTextSegment->SegmentText, RTL_TEXTENCODING_UTF8 );
+ return g_strdup( aUtf8.getStr() );
+ }
+ }
+
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ {
+ rtl::OUString aText;
+ sal_Int32 n = pText->getCharacterCount();
+
+ if( -1 == end_offset )
+ aText = pText->getText();
+ else if( start_offset < n )
+ aText = pText->getTextRange(start_offset, end_offset);
+
+ ret = g_strdup( rtl::OUStringToOString(aText, RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getText()" );
+ }
+
+#ifdef ENABLE_TRACING
+ fprintf(stderr, "text_wrapper_get_text( %d,%d ) returns %s\n", start_offset, end_offset, ret ? ret : "null" );
+#endif
+ return ret;
+}
+
+static gchar *
+text_wrapper_get_text_after_offset (AtkText *text,
+ gint offset,
+ AtkTextBoundary boundary_type,
+ gint *start_offset,
+ gint *end_offset)
+{
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ {
+ accessibility::TextSegment aTextSegment = pText->getTextBehindIndex(offset, text_type_from_boundary(boundary_type));
+ return adjust_boundaries(pText, aTextSegment, boundary_type, start_offset, end_offset);
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in get_text_after_offset()" );
+ }
+
+ return NULL;
+}
+
+static gchar *
+text_wrapper_get_text_at_offset (AtkText *text,
+ gint offset,
+ AtkTextBoundary boundary_type,
+ gint *start_offset,
+ gint *end_offset)
+{
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ {
+ /* If the user presses the 'End' key, the caret will be placed behind the last character,
+ * which is the same index as the first character of the next line. In atk the magic offset
+ * '-2' is used to cover this special case.
+ */
+ if (
+ -2 == offset &&
+ (ATK_TEXT_BOUNDARY_LINE_START == boundary_type ||
+ ATK_TEXT_BOUNDARY_LINE_END == boundary_type)
+ )
+ {
+ accessibility::XAccessibleMultiLineText* pMultiLineText = getMultiLineText( text );
+ if( pMultiLineText )
+ {
+ accessibility::TextSegment aTextSegment = pMultiLineText->getTextAtLineWithCaret();
+ return adjust_boundaries(pText, aTextSegment, boundary_type, start_offset, end_offset);
+ }
+ }
+
+ accessibility::TextSegment aTextSegment = pText->getTextAtIndex(offset, text_type_from_boundary(boundary_type));
+ return adjust_boundaries(pText, aTextSegment, boundary_type, start_offset, end_offset);
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in get_text_at_offset()" );
+ }
+
+ return NULL;
+}
+
+static gunichar
+text_wrapper_get_character_at_offset (AtkText *text,
+ gint offset)
+{
+ gint start, end;
+ gunichar uc = 0;
+
+ gchar * char_as_string =
+ text_wrapper_get_text_at_offset(text, offset, ATK_TEXT_BOUNDARY_CHAR,
+ &start, &end);
+ if( char_as_string )
+ {
+ uc = g_utf8_get_char( char_as_string );
+ g_free( char_as_string );
+ }
+
+ return uc;
+}
+
+static gchar *
+text_wrapper_get_text_before_offset (AtkText *text,
+ gint offset,
+ AtkTextBoundary boundary_type,
+ gint *start_offset,
+ gint *end_offset)
+{
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ {
+ accessibility::TextSegment aTextSegment = pText->getTextBeforeIndex(offset, text_type_from_boundary(boundary_type));
+ return adjust_boundaries(pText, aTextSegment, boundary_type, start_offset, end_offset);
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in text_before_offset()" );
+ }
+
+ return NULL;
+}
+
+static gint
+text_wrapper_get_caret_offset (AtkText *text)
+{
+ gint offset = -1;
+
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ offset = pText->getCaretPosition();
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getCaretPosition()" );
+ }
+
+#ifdef ENABLE_TRACING
+ fprintf(stderr, "get_caret_offset(%p) returns %d\n", text, offset);
+#endif
+
+ return offset;
+}
+
+static gboolean
+text_wrapper_set_caret_offset (AtkText *text,
+ gint offset)
+{
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ return pText->setCaretPosition( offset );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in setCaretPosition()" );
+ }
+
+ return FALSE;
+}
+
+// --> OD 2010-03-04 #i92232#
+AtkAttributeSet*
+handle_text_markup_as_run_attribute( accessibility::XAccessibleTextMarkup* pTextMarkup,
+ const gint nTextMarkupType,
+ const gint offset,
+ AtkAttributeSet* pSet,
+ gint *start_offset,
+ gint *end_offset )
+{
+ const gint nTextMarkupCount( pTextMarkup->getTextMarkupCount( nTextMarkupType ) );
+ if ( nTextMarkupCount > 0 )
+ {
+ for ( gint nTextMarkupIndex = 0;
+ nTextMarkupIndex < nTextMarkupCount;
+ ++nTextMarkupIndex )
+ {
+ accessibility::TextSegment aTextSegment =
+ pTextMarkup->getTextMarkup( nTextMarkupIndex, nTextMarkupType );
+ const gint nStartOffsetTextMarkup = aTextSegment.SegmentStart;
+ const gint nEndOffsetTextMarkup = aTextSegment.SegmentEnd;
+ if ( nStartOffsetTextMarkup <= offset )
+ {
+ if ( offset < nEndOffsetTextMarkup )
+ {
+ // text markup at <offset>
+ *start_offset = ::std::max( *start_offset,
+ nStartOffsetTextMarkup );
+ *end_offset = ::std::min( *end_offset,
+ nEndOffsetTextMarkup );
+ switch ( nTextMarkupType )
+ {
+ case com::sun::star::text::TextMarkupType::SPELLCHECK:
+ {
+ pSet = attribute_set_prepend_misspelled( pSet );
+ }
+ break;
+ case com::sun::star::text::TextMarkupType::TRACK_CHANGE_INSERTION:
+ {
+ pSet = attribute_set_prepend_tracked_change_insertion( pSet );
+ }
+ break;
+ case com::sun::star::text::TextMarkupType::TRACK_CHANGE_DELETION:
+ {
+ pSet = attribute_set_prepend_tracked_change_deletion( pSet );
+ }
+ break;
+ case com::sun::star::text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE:
+ {
+ pSet = attribute_set_prepend_tracked_change_formatchange( pSet );
+ }
+ break;
+ default:
+ {
+ OSL_ASSERT( false );
+ }
+ }
+ break; // no further iteration needed.
+ }
+ else
+ {
+ *start_offset = ::std::max( *start_offset,
+ nEndOffsetTextMarkup );
+ // continue iteration.
+ }
+ }
+ else
+ {
+ *end_offset = ::std::min( *end_offset,
+ nStartOffsetTextMarkup );
+ break; // no further iteration.
+ }
+ } // eof iteration over text markups
+ }
+
+ return pSet;
+}
+// <--
+
+static AtkAttributeSet *
+text_wrapper_get_run_attributes( AtkText *text,
+ gint offset,
+ gint *start_offset,
+ gint *end_offset)
+{
+ AtkAttributeSet *pSet = NULL;
+
+ try {
+ bool bOffsetsAreValid = false;
+
+ accessibility::XAccessibleText* pText = getText( text );
+ accessibility::XAccessibleTextAttributes* pTextAttributes = getTextAttributes( text );
+ if( pText && pTextAttributes )
+ {
+ uno::Sequence< beans::PropertyValue > aAttributeList =
+ pTextAttributes->getRunAttributes( offset, uno::Sequence< rtl::OUString > () );
+
+ pSet = attribute_set_new_from_property_values( aAttributeList, true, text );
+ // --> OD 2009-06-22 #i100938#
+ // - always provide start_offset and end_offset
+// if( pSet )
+ // <--
+ {
+ accessibility::TextSegment aTextSegment =
+ pText->getTextAtIndex(offset, accessibility::AccessibleTextType::ATTRIBUTE_RUN);
+
+ *start_offset = aTextSegment.SegmentStart;
+ // --> OD 2009-06-22 #i100938#
+ // Do _not_ increment the end_offset provide by <accessibility::TextSegment> instance
+// *end_offset = aTextSegment.SegmentEnd + 1; // FIXME: TESTME
+ *end_offset = aTextSegment.SegmentEnd;
+ // <--
+ bOffsetsAreValid = true;
+ }
+ }
+
+ // Special handling for misspelled text
+ // --> OD 2010-03-01 #i92232#
+ // - add special handling for tracked changes and refactor the
+ // corresponding code for handling misspelled text.
+ accessibility::XAccessibleTextMarkup* pTextMarkup = getTextMarkup( text );
+ if( pTextMarkup )
+ {
+ // Get attribute run here if it hasn't been done before
+ if( !bOffsetsAreValid )
+ {
+ accessibility::TextSegment aAttributeTextSegment =
+ pText->getTextAtIndex(offset, accessibility::AccessibleTextType::ATTRIBUTE_RUN);
+ *start_offset = aAttributeTextSegment.SegmentStart;
+ *end_offset = aAttributeTextSegment.SegmentEnd;
+ }
+ // handle misspelled text
+ pSet = handle_text_markup_as_run_attribute(
+ pTextMarkup,
+ com::sun::star::text::TextMarkupType::SPELLCHECK,
+ offset, pSet, start_offset, end_offset );
+ // handle tracked changes
+ pSet = handle_text_markup_as_run_attribute(
+ pTextMarkup,
+ com::sun::star::text::TextMarkupType::TRACK_CHANGE_INSERTION,
+ offset, pSet, start_offset, end_offset );
+ pSet = handle_text_markup_as_run_attribute(
+ pTextMarkup,
+ com::sun::star::text::TextMarkupType::TRACK_CHANGE_DELETION,
+ offset, pSet, start_offset, end_offset );
+ pSet = handle_text_markup_as_run_attribute(
+ pTextMarkup,
+ com::sun::star::text::TextMarkupType::TRACK_CHANGE_FORMATCHANGE,
+ offset, pSet, start_offset, end_offset );
+ }
+ // <--
+ }
+ catch(const uno::Exception& e){
+
+ g_warning( "Exception in get_run_attributes()" );
+
+ if( pSet )
+ {
+ atk_attribute_set_free( pSet );
+ pSet = NULL;
+ }
+ }
+
+ return pSet;
+}
+
+/*****************************************************************************/
+
+static AtkAttributeSet *
+text_wrapper_get_default_attributes( AtkText *text )
+{
+ AtkAttributeSet *pSet = NULL;
+
+ try {
+ accessibility::XAccessibleTextAttributes* pTextAttributes = getTextAttributes( text );
+ if( pTextAttributes )
+ {
+ uno::Sequence< beans::PropertyValue > aAttributeList =
+ pTextAttributes->getDefaultAttributes( uno::Sequence< rtl::OUString > () );
+
+ pSet = attribute_set_new_from_property_values( aAttributeList, false, text );
+ }
+ }
+ catch(const uno::Exception& e) {
+
+ g_warning( "Exception in get_default_attributes()" );
+
+ if( pSet )
+ {
+ atk_attribute_set_free( pSet );
+ pSet = NULL;
+ }
+ }
+
+ return pSet;
+}
+
+/*****************************************************************************/
+
+static void
+text_wrapper_get_character_extents( AtkText *text,
+ gint offset,
+ gint *x,
+ gint *y,
+ gint *width,
+ gint *height,
+ AtkCoordType coords )
+{
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ {
+ *x = *y = *width = *height = 0;
+ awt::Rectangle aRect = pText->getCharacterBounds( offset );
+
+ gint origin_x = 0;
+ gint origin_y = 0;
+
+ if( coords == ATK_XY_SCREEN )
+ {
+ g_return_if_fail( ATK_IS_COMPONENT( text ) );
+ atk_component_get_position( ATK_COMPONENT( text ), &origin_x, &origin_y, coords);
+ }
+
+ *x = aRect.X + origin_x;
+ *y = aRect.Y + origin_y;
+ *width = aRect.Width;
+ *height = aRect.Height;
+
+#ifdef ENABLE_TRACING
+ fprintf(stderr, "get_character_extents(%d, %d) returns: %d,%d,%d,%d ",
+ offset, coords, *x, *y, *width, *height);
+#endif
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getCharacterBounds" );
+ }
+}
+
+static gint
+text_wrapper_get_character_count (AtkText *text)
+{
+ gint rv = 0;
+
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ rv = pText->getCharacterCount();
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getCharacterCount" );
+ }
+
+#ifdef ENABLE_TRACING
+ fprintf(stderr, "get_character_count(%p) returns: %d\n", text, rv);
+#endif
+
+ return rv;
+}
+
+static gint
+text_wrapper_get_offset_at_point (AtkText *text,
+ gint x,
+ gint y,
+ AtkCoordType coords)
+{
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ {
+ gint origin_x = 0;
+ gint origin_y = 0;
+
+ if( coords == ATK_XY_SCREEN )
+ {
+ g_return_val_if_fail( ATK_IS_COMPONENT( text ), -1 );
+ atk_component_get_position( ATK_COMPONENT( text ), &origin_x, &origin_y, coords);
+ }
+
+ return pText->getIndexAtPoint( awt::Point(x - origin_x, y - origin_y) );
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getIndexAtPoint" );
+ }
+
+ return -1;
+}
+
+// FIXME: the whole series of selections API is problematic ...
+
+static gint
+text_wrapper_get_n_selections (AtkText *text)
+{
+ gint rv = 0;
+
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ rv = ( pText->getSelectionEnd() > pText->getSelectionStart() ) ? 1 : 0;
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getSelectionEnd() or getSelectionStart()" );
+ }
+
+#ifdef ENABLE_TRACING
+ fprintf(stderr, "get_n_selections(%p) returns %d\n", text, rv);
+#endif
+
+ return rv;
+}
+
+static gchar *
+text_wrapper_get_selection (AtkText *text,
+ gint selection_num,
+ gint *start_offset,
+ gint *end_offset)
+{
+ g_return_val_if_fail( selection_num == 0, FALSE );
+
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ {
+ *start_offset = pText->getSelectionStart();
+ *end_offset = pText->getSelectionEnd();
+
+ return OUStringToGChar( pText->getSelectedText() );
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getSelectionEnd(), getSelectionStart() or getSelectedText()" );
+ }
+
+ return NULL;
+}
+
+static gboolean
+text_wrapper_add_selection (AtkText *text,
+ gint start_offset,
+ gint end_offset)
+{
+ // FIXME: can we try to be more compatible by expanding an
+ // existing adjacent selection ?
+
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ return pText->setSelection( start_offset, end_offset ); // ?
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in setSelection()" );
+ }
+
+ return FALSE;
+}
+
+static gboolean
+text_wrapper_remove_selection (AtkText *text,
+ gint selection_num)
+{
+ g_return_val_if_fail( selection_num == 0, FALSE );
+
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ return pText->setSelection( 0, 0 ); // ?
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in setSelection()" );
+ }
+
+ return FALSE;
+}
+
+static gboolean
+text_wrapper_set_selection (AtkText *text,
+ gint selection_num,
+ gint start_offset,
+ gint end_offset)
+{
+ g_return_val_if_fail( selection_num == 0, FALSE );
+
+ try {
+ accessibility::XAccessibleText* pText = getText( text );
+ if( pText )
+ return pText->setSelection( start_offset, end_offset );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in setSelection()" );
+ }
+
+ return FALSE;
+}
+
+} // extern "C"
+
+void
+textIfaceInit (AtkTextIface *iface)
+{
+ g_return_if_fail (iface != NULL);
+
+ iface->get_text = text_wrapper_get_text;
+ iface->get_character_at_offset = text_wrapper_get_character_at_offset;
+ iface->get_text_before_offset = text_wrapper_get_text_before_offset;
+ iface->get_text_at_offset = text_wrapper_get_text_at_offset;
+ iface->get_text_after_offset = text_wrapper_get_text_after_offset;
+ iface->get_caret_offset = text_wrapper_get_caret_offset;
+ iface->set_caret_offset = text_wrapper_set_caret_offset;
+ iface->get_character_count = text_wrapper_get_character_count;
+ iface->get_n_selections = text_wrapper_get_n_selections;
+ iface->get_selection = text_wrapper_get_selection;
+ iface->add_selection = text_wrapper_add_selection;
+ iface->remove_selection = text_wrapper_remove_selection;
+ iface->set_selection = text_wrapper_set_selection;
+ iface->get_run_attributes = text_wrapper_get_run_attributes;
+ iface->get_default_attributes = text_wrapper_get_default_attributes;
+ iface->get_character_extents = text_wrapper_get_character_extents;
+ iface->get_offset_at_point = text_wrapper_get_offset_at_point;
+}
diff --git a/vcl/unx/gtk/a11y/atktextattributes.cxx b/vcl/unx/gtk/a11y/atktextattributes.cxx
new file mode 100644
index 000000000000..04498810597f
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atktextattributes.cxx
@@ -0,0 +1,1456 @@
+/*************************************************************************
+ *
+ * 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 "atktextattributes.hxx"
+
+#include <com/sun/star/awt/FontSlant.hpp>
+#include <com/sun/star/awt/FontStrikeout.hpp>
+#include <com/sun/star/awt/FontUnderline.hpp>
+
+#include <com/sun/star/style/CaseMap.hpp>
+#include <com/sun/star/style/LineSpacing.hpp>
+#include <com/sun/star/style/LineSpacingMode.hpp>
+#include <com/sun/star/style/ParagraphAdjust.hpp>
+#include <com/sun/star/style/TabAlign.hpp>
+#include <com/sun/star/style/TabStop.hpp>
+
+#include <com/sun/star/text/WritingMode2.hpp>
+
+#include "atkwrapper.hxx"
+
+#include <com/sun/star/accessibility/XAccessibleComponent.hpp>
+
+#include <vcl/svapp.hxx>
+#include <vcl/outdev.hxx>
+
+#include <stdio.h>
+#include <string.h>
+
+using namespace ::com::sun::star;
+
+typedef gchar* (* AtkTextAttrFunc) ( const uno::Any& rAny );
+typedef bool (* TextPropertyValueFunc) ( uno::Any& rAny, const gchar * value );
+
+#define STRNCMP_PARAM( s ) s,sizeof( s )-1
+
+
+/*****************************************************************************/
+
+static AtkTextAttribute atk_text_attribute_paragraph_style = ATK_TEXT_ATTR_INVALID;
+static AtkTextAttribute atk_text_attribute_font_effect = ATK_TEXT_ATTR_INVALID;
+static AtkTextAttribute atk_text_attribute_decoration = ATK_TEXT_ATTR_INVALID;
+static AtkTextAttribute atk_text_attribute_line_height = ATK_TEXT_ATTR_INVALID;
+static AtkTextAttribute atk_text_attribute_rotation = ATK_TEXT_ATTR_INVALID;
+static AtkTextAttribute atk_text_attribute_shadow = ATK_TEXT_ATTR_INVALID;
+static AtkTextAttribute atk_text_attribute_tab_interval = ATK_TEXT_ATTR_INVALID;
+static AtkTextAttribute atk_text_attribute_tab_stops = ATK_TEXT_ATTR_INVALID;
+static AtkTextAttribute atk_text_attribute_writing_mode = ATK_TEXT_ATTR_INVALID;
+static AtkTextAttribute atk_text_attribute_vertical_align = ATK_TEXT_ATTR_INVALID;
+static AtkTextAttribute atk_text_attribute_misspelled = ATK_TEXT_ATTR_INVALID;
+// --> OD 2010-03-01 #i92232#
+static AtkTextAttribute atk_text_attribute_tracked_change = ATK_TEXT_ATTR_INVALID;
+// <--
+// --> OD 2010-03-05 #i92233#
+static AtkTextAttribute atk_text_attribute_mm_to_pixel_ratio = ATK_TEXT_ATTR_INVALID;
+// <--
+
+/*****************************************************************************/
+
+/**
+ * !! IMPORTANT NOTE !! : when adding items to this list, KEEP THE LIST SORTED
+ * and re-arrange the enum values accordingly.
+ */
+
+enum ExportedAttribute
+{
+ TEXT_ATTRIBUTE_BACKGROUND_COLOR = 0,
+ TEXT_ATTRIBUTE_CASEMAP,
+ TEXT_ATTRIBUTE_FOREGROUND_COLOR,
+ TEXT_ATTRIBUTE_CONTOURED,
+ TEXT_ATTRIBUTE_CHAR_ESCAPEMENT,
+ TEXT_ATTRIBUTE_BLINKING,
+ TEXT_ATTRIBUTE_FONT_NAME,
+ TEXT_ATTRIBUTE_HEIGHT,
+ TEXT_ATTRIBUTE_HIDDEN,
+ TEXT_ATTRIBUTE_KERNING,
+ TEXT_ATTRIBUTE_LOCALE,
+ TEXT_ATTRIBUTE_POSTURE,
+ TEXT_ATTRIBUTE_RELIEF,
+ TEXT_ATTRIBUTE_ROTATION,
+ TEXT_ATTRIBUTE_SCALE,
+ TEXT_ATTRIBUTE_SHADOWED,
+ TEXT_ATTRIBUTE_STRIKETHROUGH,
+ TEXT_ATTRIBUTE_UNDERLINE,
+ TEXT_ATTRIBUTE_WEIGHT,
+ // --> OD 2010-03-05 #i92233#
+ TEXT_ATTRIBUTE_MM_TO_PIXEL_RATIO,
+ // <--
+ TEXT_ATTRIBUTE_JUSTIFICATION,
+ TEXT_ATTRIBUTE_BOTTOM_MARGIN,
+ TEXT_ATTRIBUTE_FIRST_LINE_INDENT,
+ TEXT_ATTRIBUTE_LEFT_MARGIN,
+ TEXT_ATTRIBUTE_LINE_SPACING,
+ TEXT_ATTRIBUTE_RIGHT_MARGIN,
+ TEXT_ATTRIBUTE_STYLE_NAME,
+ TEXT_ATTRIBUTE_TAB_STOPS,
+ TEXT_ATTRIBUTE_TOP_MARGIN,
+ TEXT_ATTRIBUTE_WRITING_MODE,
+ TEXT_ATTRIBUTE_LAST
+};
+
+static const char * ExportedTextAttributes[TEXT_ATTRIBUTE_LAST] =
+{
+ "CharBackColor", // TEXT_ATTRIBUTE_BACKGROUND_COLOR
+ "CharCaseMap", // TEXT_ATTRIBUTE_CASEMAP
+ "CharColor", // TEXT_ATTRIBUTE_FOREGROUND_COLOR
+ "CharContoured", // TEXT_ATTRIBUTE_CONTOURED
+ "CharEscapement", // TEXT_ATTRIBUTE_CHAR_ESCAPEMENT
+ "CharFlash", // TEXT_ATTRIBUTE_BLINKING
+ "CharFontName", // TEXT_ATTRIBUTE_FONT_NAME
+ "CharHeight", // TEXT_ATTRIBUTE_HEIGHT
+ "CharHidden", // TEXT_ATTRIBUTE_HIDDEN
+ "CharKerning", // TEXT_ATTRIBUTE_KERNING
+ "CharLocale", // TEXT_ATTRIBUTE_LOCALE
+ "CharPosture", // TEXT_ATTRIBUTE_POSTURE
+ "CharRelief", // TEXT_ATTRIBUTE_RELIEF
+ "CharRotation", // TEXT_ATTRIBUTE_ROTATION
+ "CharScaleWidth", // TEXT_ATTRIBUTE_SCALE
+ "CharShadowed", // TEXT_ATTRIBUTE_SHADOWED
+ "CharStrikeout", // TEXT_ATTRIBUTE_STRIKETHROUGH
+ "CharUnderline", // TEXT_ATTRIBUTE_UNDERLINE
+ "CharWeight", // TEXT_ATTRIBUTE_WEIGHT
+ // --> OD 2010-03-05 #i92233#
+ "MMToPixelRatio", // TEXT_ATTRIBUTE_MM_TO_PIXEL_RATIO
+ // <--
+ "ParaAdjust", // TEXT_ATTRIBUTE_JUSTIFICATION
+ "ParaBottomMargin", // TEXT_ATTRIBUTE_BOTTOM_MARGIN
+ "ParaFirstLineIndent", // TEXT_ATTRIBUTE_FIRST_LINE_INDENT
+ "ParaLeftMargin", // TEXT_ATTRIBUTE_LEFT_MARGIN
+ "ParaLineSpacing", // TEXT_ATTRIBUTE_LINE_SPACING
+ "ParaRightMargin", // TEXT_ATTRIBUTE_RIGHT_MARGIN
+ "ParaStyleName", // TEXT_ATTRIBUTE_STYLE_NAME
+ "ParaTabStops", // TEXT_ATTRIBUTE_TAB_STOPS
+ "ParaTopMargin", // TEXT_ATTRIBUTE_TOP_MARGIN
+ "WritingMode" // TEXT_ATTRIBUTE_WRITING_MODE
+};
+
+
+/*****************************************************************************/
+
+static gchar*
+get_value( const uno::Sequence< beans::PropertyValue >& rAttributeList,
+ sal_Int32 nIndex, AtkTextAttrFunc func )
+{
+ if( nIndex != -1 )
+ return func(rAttributeList[nIndex].Value);
+
+ return NULL;
+}
+
+#define get_bool_value( list, index ) get_value( list, index, Bool2String )
+#define get_short_value( list, index ) get_value( list, index, Short2String )
+//#define get_long_value( list, index ) get_value( list, index, Long2String ) pb: not used (warning on linux)
+#define get_height_value( list, index ) get_value( list, index, Float2String )
+#define get_justification_value( list, index ) get_value( list, index, Adjust2Justification )
+#define get_cmm_value( list, index ) get_value( list, index, CMM2UnitString )
+#define get_scale_width( list, index ) get_value( list, index, Scale2String )
+#define get_strikethrough_value( list, index ) get_value( list, index, Strikeout2String )
+#define get_string_value( list, index ) get_value( list, index, GetString )
+#define get_style_value( list, index ) get_value( list, index, FontSlant2Style )
+#define get_underline_value( list, index ) get_value( list, index, Underline2String )
+#define get_variant_value( list, index ) get_value( list, index, CaseMap2String )
+#define get_weight_value( list, index ) get_value( list, index, Weight2String )
+#define get_language_string( list, index ) get_value( list, index, Locale2String )
+
+/*
+static gchar*
+dump_value( const uno::Sequence< beans::PropertyValue >& rAttributeList, sal_Int32 nIndex )
+{
+ if( nIndex != -1 )
+ {
+ rtl::OString aName = rtl::OUStringToOString(rAttributeList[nIndex].Name, RTL_TEXTENCODING_UTF8);
+
+ if( rAttributeList[nIndex].Value.has<sal_Int16> () )
+ OSL_TRACE( "%s = %d (short value)", aName.getStr(),
+ rAttributeList[nIndex].Value.get<sal_Int16> () );
+
+ else if( rAttributeList[nIndex].Value.has<sal_Int8> () )
+ OSL_TRACE( "%s = %d (byte value)", aName.getStr(),
+ rAttributeList[nIndex].Value.get<sal_Int8> () );
+
+ else if( rAttributeList[nIndex].Value.has<sal_Bool> () )
+ OSL_TRACE( "%s = %s (bool value)", aName.getStr(),
+ rAttributeList[nIndex].Value.get<sal_Bool> () ? "true" : "false" );
+
+ else if( rAttributeList[nIndex].Value.has<rtl::OUString> () )
+ OSL_TRACE( "%s = %s", aName.getStr(),
+ rtl::OUStringToOString(rAttributeList[nIndex].Value.get<rtl::OUString> (),
+ RTL_TEXTENCODING_UTF8).getStr() );
+ }
+
+ return NULL;
+}
+*/
+
+static inline
+double toPoint(sal_Int16 n)
+{
+ // 100th mm -> pt
+ return (double) (n * 72) / 2540;
+}
+
+
+/*****************************************************************************/
+
+/*
+static gchar*
+NullString(const uno::Any&)
+{
+ return NULL;
+}
+*/
+
+static bool
+InvalidValue( uno::Any&, const gchar * )
+{
+ return false;
+}
+
+/*****************************************************************************/
+
+static gchar*
+Float2String(const uno::Any& rAny)
+{
+ return g_strdup_printf( "%g", rAny.get<float>() );
+}
+
+static bool
+String2Float( uno::Any& rAny, const gchar * value )
+{
+ float fval;
+
+ if( 1 != sscanf( value, "%g", &fval ) )
+ return false;
+
+ rAny = uno::makeAny( fval );
+ return true;
+}
+
+/*****************************************************************************/
+
+/*
+static gchar*
+Short2String(const uno::Any& rAny)
+{
+ return g_strdup_printf( "%d", rAny.get<sal_Int16>() );
+}
+
+static bool
+String2Short( uno::Any& rAny, const gchar * value )
+{
+ sal_Int32 lval;
+
+ if( 1 != sscanf( value, "%d", &lval ) )
+ return false;
+
+ rAny = uno::makeAny( (sal_Int16) lval );
+ return true;
+}
+*/
+
+/*****************************************************************************/
+/* pb: not used (warning on linux)
+static gchar*
+Long2String(const uno::Any& rAny)
+{
+ return g_strdup_printf( "%ld", rAny.get<sal_Int32>() );
+}
+
+static bool
+String2Long( uno::Any& rAny, const gchar * value )
+{
+ sal_Int32 lval;
+
+ if( 1 != sscanf( value, "%ld", &lval ) )
+ return false;
+
+ rAny = uno::makeAny( lval );
+ return true;
+}
+*/
+/*****************************************************************************/
+
+static accessibility::XAccessibleComponent*
+ getComponent( AtkText *pText ) throw (uno::RuntimeException)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pText );
+ if( pWrap )
+ {
+ if( !pWrap->mpComponent && pWrap->mpContext )
+ {
+ uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleComponent::static_type(NULL) );
+ pWrap->mpComponent = reinterpret_cast< accessibility::XAccessibleComponent * > (any.pReserved);
+ pWrap->mpComponent->acquire();
+ }
+
+ return pWrap->mpComponent;
+ }
+
+ return NULL;
+}
+
+static gchar*
+get_color_value(const uno::Sequence< beans::PropertyValue >& rAttributeList,
+ const sal_Int32 * pIndexArray,
+ ExportedAttribute attr,
+ AtkText * text)
+{
+ sal_Int32 nColor = -1; // AUTOMATIC
+ sal_Int32 nIndex = pIndexArray[attr];
+
+ if( nIndex != -1 )
+ nColor = rAttributeList[nIndex].Value.get<sal_Int32>();
+
+ /*
+ * Check for color value for 100% alpha white, which means
+ * "automatic". Grab the RGB value from XAccessibleComponent
+ * in this case.
+ */
+
+ if( (nColor == -1) && text )
+ {
+ try
+ {
+ accessibility::XAccessibleComponent *pComponent = getComponent( text );
+ if( pComponent )
+ {
+ switch( attr )
+ {
+ case TEXT_ATTRIBUTE_BACKGROUND_COLOR:
+ nColor = pComponent->getBackground();
+ break;
+ case TEXT_ATTRIBUTE_FOREGROUND_COLOR:
+ nColor = pComponent->getForeground();
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in get[Fore|Back]groundColor()" );
+ }
+ }
+
+ if( nColor != -1 )
+ {
+ sal_uInt8 blue = nColor & 0xFF;
+ sal_uInt8 green = (nColor >> 8) & 0xFF;
+ sal_uInt8 red = (nColor >> 16) & 0xFF;
+
+ return g_strdup_printf( "%u,%u,%u", red, green, blue );
+ }
+
+ return NULL;
+}
+
+static bool
+String2Color( uno::Any& rAny, const gchar * value )
+{
+ int red, green, blue;
+
+ if( 3 != sscanf( value, "%d,%d,%d", &red, &green, &blue ) )
+ return false;
+
+ sal_Int32 nColor = (sal_Int32) blue | ( (sal_Int32) green << 8 ) | ( ( sal_Int32 ) red << 16 );
+ rAny = uno::makeAny( nColor );
+ return true;
+}
+
+/*****************************************************************************/
+
+static gchar*
+FontSlant2Style(const uno::Any& rAny)
+{
+ const gchar * value = NULL;
+
+ switch( rAny.get<awt::FontSlant>() )
+ {
+ case awt::FontSlant_NONE:
+ value = "normal";
+ break;
+
+ case awt::FontSlant_OBLIQUE:
+ value = "oblique";
+ break;
+
+ case awt::FontSlant_ITALIC:
+ value = "italic";
+ break;
+
+ case awt::FontSlant_REVERSE_OBLIQUE:
+ value = "reverse oblique";
+ break;
+
+ case awt::FontSlant_REVERSE_ITALIC:
+ value = "reverse italic";
+ break;
+
+ default:
+ break;
+ }
+
+ if( value )
+ return g_strdup( value );
+
+ return NULL;
+}
+
+static bool
+Style2FontSlant( uno::Any& rAny, const gchar * value )
+{
+ awt::FontSlant aFontSlant;
+
+ if( strncmp( value, STRNCMP_PARAM( "normal" ) ) )
+ aFontSlant = awt::FontSlant_NONE;
+ else if( strncmp( value, STRNCMP_PARAM( "oblique" ) ) )
+ aFontSlant = awt::FontSlant_OBLIQUE;
+ else if( strncmp( value, STRNCMP_PARAM( "italic" ) ) )
+ aFontSlant = awt::FontSlant_ITALIC;
+ else if( strncmp( value, STRNCMP_PARAM( "reverse oblique" ) ) )
+ aFontSlant = awt::FontSlant_REVERSE_OBLIQUE;
+ else if( strncmp( value, STRNCMP_PARAM( "reverse italic" ) ) )
+ aFontSlant = awt::FontSlant_REVERSE_ITALIC;
+ else
+ return false;
+
+ rAny = uno::makeAny( aFontSlant );
+ return true;
+}
+
+/*****************************************************************************/
+
+static gchar*
+Weight2String(const uno::Any& rAny)
+{
+ return g_strdup_printf( "%g", rAny.get<float>() * 4 );
+}
+
+static bool
+String2Weight( uno::Any& rAny, const gchar * value )
+{
+ float weight;
+
+ if( 1 != sscanf( value, "%g", &weight ) )
+ return false;
+
+ rAny = uno::makeAny( weight / 4 );
+ return true;
+}
+
+
+/*****************************************************************************/
+
+static gchar*
+Adjust2Justification(const uno::Any& rAny)
+{
+ const gchar * value = NULL;
+
+ switch( rAny.get<short>() )
+ {
+ case style::ParagraphAdjust_LEFT:
+ value = "left";
+ break;
+
+ case style::ParagraphAdjust_RIGHT:
+ value = "right";
+ break;
+
+ case style::ParagraphAdjust_BLOCK:
+ case style::ParagraphAdjust_STRETCH:
+ value = "fill";
+ break;
+
+ case style::ParagraphAdjust_CENTER:
+ value = "center";
+ break;
+
+ default:
+ break;
+ }
+
+ if( value )
+ return g_strdup( value );
+
+ return NULL;
+}
+
+static bool
+Justification2Adjust( uno::Any& rAny, const gchar * value )
+{
+ short nParagraphAdjust;
+
+ if( strncmp( value, STRNCMP_PARAM( "left" ) ) )
+ nParagraphAdjust = style::ParagraphAdjust_LEFT;
+ else if( strncmp( value, STRNCMP_PARAM( "right" ) ) )
+ nParagraphAdjust = style::ParagraphAdjust_RIGHT;
+ else if( strncmp( value, STRNCMP_PARAM( "fill" ) ) )
+ nParagraphAdjust = style::ParagraphAdjust_BLOCK;
+ else if( strncmp( value, STRNCMP_PARAM( "center" ) ) )
+ nParagraphAdjust = style::ParagraphAdjust_CENTER;
+ else
+ return false;
+
+ rAny = uno::makeAny( nParagraphAdjust );
+ return true;
+}
+
+/*****************************************************************************/
+
+const gchar * font_strikethrough[] = {
+ "none", // FontStrikeout::NONE
+ "single", // FontStrikeout::SINGLE
+ "double", // FontStrikeout::DOUBLE
+ NULL, // FontStrikeout::DONTKNOW
+ "bold", // FontStrikeout::BOLD
+ "with /", // FontStrikeout::SLASH
+ "with X" // FontStrikeout::X
+};
+
+const sal_Int16 n_strikeout_constants = sizeof(font_strikethrough) / sizeof(gchar*);
+
+static gchar*
+Strikeout2String(const uno::Any& rAny)
+{
+ sal_Int16 n = rAny.get<sal_Int16>();
+
+ if( n >= 0 && n < n_strikeout_constants )
+ return g_strdup( font_strikethrough[n] );
+
+ return NULL;
+}
+
+static bool
+String2Strikeout( uno::Any& rAny, const gchar * value )
+{
+ for( sal_Int16 n=0; n < n_strikeout_constants; ++n )
+ {
+ if( ( NULL != font_strikethrough[n] ) &&
+ 0 == strncmp( value, font_strikethrough[n], strlen( font_strikethrough[n] ) ) )
+ {
+ rAny = uno::makeAny( n );
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/*****************************************************************************/
+
+static gchar*
+Underline2String(const uno::Any& rAny)
+{
+ const gchar * value = NULL;
+
+ switch( rAny.get<sal_Int16>() )
+ {
+ case awt::FontUnderline::NONE:
+ value = "none";
+ break;
+
+ case awt::FontUnderline::SINGLE:
+ value = "single";
+ break;
+
+ case awt::FontUnderline::DOUBLE:
+ value = "double";
+ break;
+
+ default:
+ break;
+ }
+
+ if( value )
+ return g_strdup( value );
+
+ return NULL;
+}
+
+static bool
+String2Underline( uno::Any& rAny, const gchar * value )
+{
+ short nUnderline;
+
+ if( strncmp( value, STRNCMP_PARAM( "none" ) ) )
+ nUnderline = awt::FontUnderline::NONE;
+ else if( strncmp( value, STRNCMP_PARAM( "single" ) ) )
+ nUnderline = awt::FontUnderline::SINGLE;
+ else if( strncmp( value, STRNCMP_PARAM( "double" ) ) )
+ nUnderline = awt::FontUnderline::DOUBLE;
+ else
+ return false;
+
+ rAny = uno::makeAny( nUnderline );
+ return true;
+}
+
+/*****************************************************************************/
+
+static gchar*
+GetString(const uno::Any& rAny)
+{
+ rtl::OString aFontName = rtl::OUStringToOString( rAny.get< rtl::OUString > (), RTL_TEXTENCODING_UTF8 );
+
+ if( aFontName.getLength() )
+ return g_strdup( aFontName.getStr() );
+
+ return NULL;
+}
+
+static bool
+SetString( uno::Any& rAny, const gchar * value )
+{
+ rtl::OString aFontName( value );
+
+ if( aFontName.getLength() )
+ {
+ rAny = uno::makeAny( rtl::OStringToOUString( aFontName, RTL_TEXTENCODING_UTF8 ) );
+ return true;
+ }
+
+ return false;
+}
+
+/*****************************************************************************/
+
+// @see http://developer.gnome.org/doc/API/2.0/atk/AtkText.html#AtkTextAttribute
+
+// CMM = 100th of mm
+static gchar*
+CMM2UnitString(const uno::Any& rAny)
+{
+ double fValue = rAny.get<sal_Int32>();
+ fValue = fValue * 0.01;
+
+ return g_strdup_printf( "%gmm", fValue );
+}
+
+static bool
+UnitString2CMM( uno::Any& rAny, const gchar * value )
+{
+ float fValue = 0.0; // pb: dont use double here because of warning on linux
+
+ if( 1 != sscanf( value, "%gmm", &fValue ) )
+ return false;
+
+ fValue = fValue * 100;
+
+ rAny = uno::makeAny( (sal_Int32) fValue);
+ return true;
+}
+
+/*****************************************************************************/
+
+static const gchar * bool_values[] = { "true", "false" };
+
+static gchar *
+Bool2String( const uno::Any& rAny )
+{
+ int n = 1;
+
+ if( rAny.get<sal_Bool>() )
+ n = 0;
+
+ return g_strdup( bool_values[n] );
+}
+
+static bool
+String2Bool( uno::Any& rAny, const gchar * value )
+{
+ sal_Bool bValue;
+
+ if( strncmp( value, STRNCMP_PARAM( "true" ) ) )
+ bValue = sal_True;
+ else if( strncmp( value, STRNCMP_PARAM( "false" ) ) )
+ bValue = sal_False;
+ else
+ return false;
+
+ rAny = uno::makeAny(bValue);
+ return true;
+}
+
+/*****************************************************************************/
+
+static gchar*
+Scale2String( const uno::Any& rAny )
+{
+ return g_strdup_printf( "%g", (double) (rAny.get< sal_Int16 > ()) / 100 );
+}
+
+static bool
+String2Scale( uno::Any& rAny, const gchar * value )
+{
+ double dval;
+
+ if( 1 != sscanf( value, "%lg", &dval ) )
+ return false;
+
+ rAny = uno::makeAny((sal_Int16) (dval * 100));
+ return true;
+}
+
+/*****************************************************************************/
+
+static gchar *
+CaseMap2String( const uno::Any& rAny )
+{
+ const gchar * value = NULL;
+
+ switch( rAny.get<short>() )
+ {
+ case style::CaseMap::SMALLCAPS:
+ value = "small_caps";
+ break;
+
+ default:
+ value = "normal";
+ break;
+ }
+
+ if( value )
+ return g_strdup( value );
+
+ return NULL;
+}
+
+static bool
+String2CaseMap( uno::Any& rAny, const gchar * value )
+{
+ short nCaseMap;
+
+ if( strncmp( value, STRNCMP_PARAM( "normal" ) ) )
+ nCaseMap = style::CaseMap::NONE;
+ else if( strncmp( value, STRNCMP_PARAM( "small_caps" ) ) )
+ nCaseMap = style::CaseMap::SMALLCAPS;
+ else
+ return false;
+
+ rAny = uno::makeAny( nCaseMap );
+ return true;
+}
+
+/*****************************************************************************/
+
+const gchar * font_stretch[] = {
+ "ultra_condensed",
+ "extra_condensed",
+ "condensed",
+ "semi_condensed",
+ "normal",
+ "semi_expanded",
+ "expanded",
+ "extra_expanded",
+ "ultra_expanded"
+};
+
+static gchar*
+Kerning2Stretch(const uno::Any& rAny)
+{
+ sal_Int16 n = rAny.get<sal_Int16>();
+ int i = 4;
+
+ // No good idea for a mapping - just return the basic info
+ if( n < 0 )
+ i=2;
+ else if( n > 0 )
+ i=6;
+
+ return g_strdup(font_stretch[i]);
+}
+
+/*****************************************************************************/
+
+static gchar*
+Locale2String(const uno::Any& rAny)
+{
+ lang::Locale aLocale = rAny.get<lang::Locale> ();
+ return g_strdup_printf( "%s-%s",
+ rtl::OUStringToOString( aLocale.Language, RTL_TEXTENCODING_ASCII_US).getStr(),
+ rtl::OUStringToOString( aLocale.Country, RTL_TEXTENCODING_ASCII_US).toAsciiLowerCase().getStr() );
+}
+
+static bool
+String2Locale( uno::Any& rAny, const gchar * value )
+{
+ bool ret = false;
+
+ gchar ** str_array = g_strsplit_set( value, "-.@", -1 );
+ if( str_array[0] != NULL )
+ {
+ ret = true;
+
+ lang::Locale aLocale;
+
+ aLocale.Language = rtl::OUString::createFromAscii(str_array[0]);
+ if( str_array[1] != NULL )
+ {
+ gchar * country = g_ascii_strup(str_array[1], -1);
+ aLocale.Country = rtl::OUString::createFromAscii(country);
+ g_free(country);
+ }
+
+ rAny = uno::makeAny(aLocale);
+ }
+
+ g_strfreev(str_array);
+ return ret;
+}
+
+/*****************************************************************************/
+
+// @see http://www.w3.org/TR/2002/WD-css3-fonts-20020802/#font-effect-prop
+static const gchar * relief[] = { "none", "emboss", "engrave" };
+static const gchar * outline = "outline";
+
+static gchar *
+get_font_effect(const uno::Sequence< beans::PropertyValue >& rAttributeList,
+ sal_Int32 nContourIndex, sal_Int32 nReliefIndex)
+{
+ if( nContourIndex != -1 )
+ {
+ if( rAttributeList[nContourIndex].Value.get<sal_Bool>() )
+ return g_strdup(outline);
+ }
+
+ if( nReliefIndex != -1 )
+ {
+ sal_Int16 n = rAttributeList[nReliefIndex].Value.get<sal_Int16>();
+ if( n < 3)
+ return g_strdup(relief[n]);
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+// @see http://www.w3.org/TR/REC-CSS2/text.html#lining-striking-props
+
+
+enum
+{
+ DECORATION_NONE = 0,
+ DECORATION_BLINK,
+ DECORATION_UNDERLINE,
+ DECORATION_LINE_THROUGH
+};
+
+
+static const gchar * decorations[] = { "none", "blink", "underline", "line-through" };
+
+static gchar *
+get_text_decoration(const uno::Sequence< beans::PropertyValue >& rAttributeList,
+ sal_Int32 nBlinkIndex, sal_Int32 nUnderlineIndex,
+ sal_Int16 nStrikeoutIndex)
+{
+ gchar * value_list[4] = { NULL, NULL, NULL, NULL };
+ gint count = 0;
+
+ // no property value found
+ if( ( nBlinkIndex == -1 ) && (nUnderlineIndex == -1 ) && (nStrikeoutIndex == -1))
+ return NULL;
+
+ if( nBlinkIndex != -1 )
+ {
+ if( rAttributeList[nBlinkIndex].Value.get<sal_Bool>() )
+ value_list[count++] = const_cast <gchar *> (decorations[DECORATION_BLINK]);
+ }
+ if( nUnderlineIndex != -1 )
+ {
+ sal_Int16 n = rAttributeList[nUnderlineIndex].Value.get<sal_Int16> ();
+ if( n != awt::FontUnderline::NONE )
+ value_list[count++] = const_cast <gchar *> (decorations[DECORATION_UNDERLINE]);
+ }
+ if( nStrikeoutIndex != -1 )
+ {
+ sal_Int16 n = rAttributeList[nStrikeoutIndex].Value.get<sal_Int16> ();
+ if( n != awt::FontStrikeout::NONE && n != awt::FontStrikeout::DONTKNOW )
+ value_list[count++] = const_cast <gchar *> (decorations[DECORATION_LINE_THROUGH]);
+ }
+
+ if( count == 0 )
+ value_list[count++] = const_cast <gchar *> (decorations[DECORATION_NONE]);
+
+ return g_strjoinv(" ", value_list);
+}
+
+
+/*****************************************************************************/
+
+// @see http://www.w3.org/TR/REC-CSS2/text.html#propdef-text-shadow
+
+static const gchar * shadow_values[] = { "none", "black" };
+
+static gchar *
+Bool2Shadow( const uno::Any& rAny )
+{
+ int n = 0;
+
+ if( rAny.get<sal_Bool>() )
+ n = 1;
+
+ return g_strdup( shadow_values[n] );
+}
+
+/*****************************************************************************/
+
+static gchar *
+Short2Degree( const uno::Any& rAny )
+{
+ float f = rAny.get<sal_Int16>() / 10;
+ return g_strdup_printf( "%g", f );
+}
+
+/*****************************************************************************/
+
+const gchar * directions[] = { "ltr", "rtl", "rtl", "ltr", "none" };
+
+static gchar *
+WritingMode2Direction( const uno::Any& rAny )
+{
+ sal_Int16 n = rAny.get<sal_Int16>();
+
+ if( 0 <= n && n <= text::WritingMode2::PAGE )
+ return g_strdup(directions[n]);
+
+ return NULL;
+}
+
+// @see http://www.w3.org/TR/2001/WD-css3-text-20010517/#PrimaryTextAdvanceDirection
+
+const gchar * writing_modes[] = { "lr-tb", "rl-tb", "tb-rl", "tb-lr", "none" };
+static gchar *
+WritingMode2String( const uno::Any& rAny )
+{
+ sal_Int16 n = rAny.get<sal_Int16>();
+
+ if( 0 <= n && n <= text::WritingMode2::PAGE )
+ return g_strdup(writing_modes[n]);
+
+ return NULL;
+}
+
+/*****************************************************************************/
+
+const char * baseline_values[] = { "baseline", "sub", "super" };
+
+// @see http://www.w3.org/TR/REC-CSS2/visudet.html#propdef-vertical-align
+static gchar *
+Escapement2VerticalAlign( const uno::Any& rAny )
+{
+ sal_Int16 n = rAny.get<sal_Int16>();
+ gchar * ret = NULL;
+
+ // Values are in %, 101% means "automatic"
+ if( n == 0 )
+ ret = g_strdup(baseline_values[0]);
+ else if( n == 101 )
+ ret = g_strdup(baseline_values[2]);
+ else if( n == -101 )
+ ret = g_strdup(baseline_values[1]);
+ else
+ ret = g_strdup_printf( "%d%%", n );
+
+ return ret;
+}
+
+/*****************************************************************************/
+
+// @see http://www.w3.org/TR/REC-CSS2/visudet.html#propdef-line-height
+static gchar *
+LineSpacing2LineHeight( const uno::Any& rAny )
+{
+ style::LineSpacing ls;
+ gchar * ret = NULL;
+
+ if( rAny >>= ls )
+ {
+ if( ls.Mode == style::LineSpacingMode::PROP )
+ ret = g_strdup_printf( "%d%%", ls.Height );
+ else if( ls.Mode == style::LineSpacingMode::FIX )
+ ret = g_strdup_printf( "%.3gpt", toPoint(ls.Height) );
+ }
+
+ return ret;
+}
+
+/*****************************************************************************/
+
+// @see http://www.w3.org/People/howcome/t/970224HTMLERB-CSS/WD-tabs-970117.html
+static gchar *
+TabStopList2String( const uno::Any& rAny, bool default_tabs )
+{
+ uno::Sequence< style::TabStop > theTabStops;
+ gchar * ret = NULL;
+
+ if( rAny >>= theTabStops)
+ {
+ sal_Int32 indexOfTab = 0;
+ sal_Int32 numberOfTabs = theTabStops.getLength();
+ sal_Unicode lastFillChar = (sal_Unicode) ' ';
+
+ for( ; indexOfTab < numberOfTabs; ++indexOfTab )
+ {
+ bool is_default_tab = (style::TabAlign_DEFAULT == theTabStops[indexOfTab].Alignment);
+
+ if( is_default_tab != default_tabs )
+ continue;
+
+ double fValue = theTabStops[indexOfTab].Position;
+ fValue = fValue * 0.01;
+
+ const gchar * tab_align = "";
+ switch( theTabStops[indexOfTab].Alignment )
+ {
+ case style::TabAlign_LEFT :
+ tab_align = "left ";
+ break;
+ case style::TabAlign_CENTER :
+ tab_align = "center ";
+ break;
+ case style::TabAlign_RIGHT :
+ tab_align = "right ";
+ break;
+ case style::TabAlign_DECIMAL :
+ tab_align = "decimal ";
+ break;
+ default:
+ break;
+ }
+
+ const gchar * lead_char = "";
+
+ if( theTabStops[indexOfTab].FillChar != lastFillChar )
+ {
+ lastFillChar = theTabStops[indexOfTab].FillChar;
+ switch (lastFillChar)
+ {
+ case (sal_Unicode) ' ':
+ lead_char = "blank ";
+ break;
+
+ case (sal_Unicode) '.':
+ lead_char = "dotted ";
+ break;
+
+ case (sal_Unicode) '-':
+ lead_char = "dashed ";
+ break;
+
+ case (sal_Unicode) '_':
+ lead_char = "lined ";
+ break;
+
+ default:
+ lead_char = "custom ";
+ break;
+ }
+ }
+
+ gchar * tab_str = g_strdup_printf( "%s%s%gmm", lead_char, tab_align, fValue );
+
+ if( ret )
+ {
+ gchar * old_tab_str = ret;
+ ret = g_strconcat(old_tab_str, " ", tab_str, NULL /* terminated */);
+ g_free( old_tab_str );
+ }
+ else
+ ret = tab_str;
+ }
+ }
+
+ return ret;
+}
+
+static gchar *
+TabStops2String( const uno::Any& rAny )
+{
+ return TabStopList2String(rAny, false);
+}
+
+static gchar *
+DefaultTabStops2String( const uno::Any& rAny )
+{
+ return TabStopList2String(rAny, true);
+}
+
+/*****************************************************************************/
+
+extern "C" int
+attr_compare(const void *p1,const void *p2)
+{
+ const rtl_uString * pustr = (const rtl_uString *) p1;
+ const char * pc = *((const char **) p2);
+
+ return rtl_ustr_ascii_compare_WithLength(pustr->buffer, pustr->length, pc);
+}
+
+static void
+find_exported_attributes( sal_Int32 *pArray,
+ const com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >& rAttributeList )
+{
+ for( sal_Int32 i = 0; i < rAttributeList.getLength(); i++ )
+ {
+ const char ** pAttr = (const char **) bsearch(rAttributeList[i].Name.pData,
+ ExportedTextAttributes, TEXT_ATTRIBUTE_LAST, sizeof(const char *),
+ attr_compare);
+
+ if( pAttr )
+ {
+ sal_Int32 nIndex = pAttr - ExportedTextAttributes;
+ pArray[nIndex] = i;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+static AtkAttributeSet*
+attribute_set_prepend( AtkAttributeSet* attribute_set,
+ AtkTextAttribute attribute,
+ gchar * value )
+{
+ if( value )
+ {
+ AtkAttribute *at = (AtkAttribute *) g_malloc( sizeof (AtkAttribute) );
+ at->name = g_strdup( atk_text_attribute_get_name( attribute ) );
+ at->value = value;
+
+ return g_slist_prepend(attribute_set, at);
+ }
+
+ return attribute_set;
+}
+
+/*****************************************************************************/
+
+AtkAttributeSet*
+attribute_set_new_from_property_values(
+ const uno::Sequence< beans::PropertyValue >& rAttributeList,
+ bool run_attributes_only,
+ AtkText *text)
+{
+ AtkAttributeSet* attribute_set = NULL;
+
+ sal_Int32 aIndexList[TEXT_ATTRIBUTE_LAST] = { -1 };
+
+ // Initialize index array with -1
+ for( sal_Int32 attr = 0; attr < TEXT_ATTRIBUTE_LAST; ++attr )
+ aIndexList[attr] = -1;
+
+ find_exported_attributes(aIndexList, rAttributeList);
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_BG_COLOR,
+ get_color_value(rAttributeList, aIndexList, TEXT_ATTRIBUTE_BACKGROUND_COLOR, run_attributes_only ? NULL : text ) );
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_FG_COLOR,
+ get_color_value(rAttributeList, aIndexList, TEXT_ATTRIBUTE_FOREGROUND_COLOR, run_attributes_only ? NULL : text) );
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_INVISIBLE,
+ get_bool_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_HIDDEN]));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_UNDERLINE,
+ get_underline_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_UNDERLINE]));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_STRIKETHROUGH,
+ get_strikethrough_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_STRIKETHROUGH]));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_SIZE,
+ get_height_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_HEIGHT]));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_WEIGHT,
+ get_weight_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_WEIGHT]));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_FAMILY_NAME,
+ get_string_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_FONT_NAME]));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_VARIANT,
+ get_variant_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_CASEMAP]));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_STYLE,
+ get_style_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_POSTURE]));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_SCALE,
+ get_scale_width(rAttributeList, aIndexList[TEXT_ATTRIBUTE_SCALE]));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_LANGUAGE,
+ get_language_string(rAttributeList, aIndexList[TEXT_ATTRIBUTE_LOCALE]));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_DIRECTION,
+ get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_WRITING_MODE], WritingMode2Direction));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_STRETCH,
+ get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_KERNING], Kerning2Stretch));
+
+ if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_font_effect )
+ atk_text_attribute_font_effect = atk_text_attribute_register("font-effect");
+
+ attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_font_effect,
+ get_font_effect(rAttributeList, aIndexList[TEXT_ATTRIBUTE_CONTOURED], aIndexList[TEXT_ATTRIBUTE_RELIEF]));
+
+ if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_decoration )
+ atk_text_attribute_decoration = atk_text_attribute_register("text-decoration");
+
+ attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_decoration,
+ get_text_decoration(rAttributeList, aIndexList[TEXT_ATTRIBUTE_BLINKING],
+ aIndexList[TEXT_ATTRIBUTE_UNDERLINE], aIndexList[TEXT_ATTRIBUTE_STRIKETHROUGH]));
+
+ if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_rotation )
+ atk_text_attribute_rotation = atk_text_attribute_register("text-rotation");
+
+ attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_rotation,
+ get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_ROTATION], Short2Degree));
+
+ if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_shadow )
+ atk_text_attribute_shadow = atk_text_attribute_register("text-shadow");
+
+ attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_shadow,
+ get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_SHADOWED], Bool2Shadow));
+
+ if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_writing_mode )
+ atk_text_attribute_writing_mode = atk_text_attribute_register("writing-mode");
+
+ attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_writing_mode,
+ get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_WRITING_MODE], WritingMode2String));
+
+ if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_vertical_align )
+ atk_text_attribute_vertical_align = atk_text_attribute_register("vertical-align");
+
+ attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_vertical_align,
+ get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_CHAR_ESCAPEMENT], Escapement2VerticalAlign));
+
+ if( run_attributes_only )
+ return attribute_set;
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_LEFT_MARGIN,
+ get_cmm_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_LEFT_MARGIN]));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_RIGHT_MARGIN,
+ get_cmm_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_RIGHT_MARGIN]));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_INDENT,
+ get_cmm_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_FIRST_LINE_INDENT]));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_PIXELS_ABOVE_LINES,
+ get_cmm_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_TOP_MARGIN]));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_PIXELS_BELOW_LINES,
+ get_cmm_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_BOTTOM_MARGIN]));
+
+ attribute_set = attribute_set_prepend(attribute_set, ATK_TEXT_ATTR_JUSTIFICATION,
+ get_justification_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_JUSTIFICATION]));
+
+ if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_paragraph_style )
+ atk_text_attribute_paragraph_style = atk_text_attribute_register("paragraph-style");
+
+ attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_paragraph_style,
+ get_string_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_STYLE_NAME]));
+
+ if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_line_height )
+ atk_text_attribute_line_height = atk_text_attribute_register("line-height");
+
+ attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_line_height,
+ get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_LINE_SPACING], LineSpacing2LineHeight));
+
+ if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_tab_interval )
+ atk_text_attribute_tab_interval = atk_text_attribute_register("tab-interval");
+
+ attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_tab_interval,
+ get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_TAB_STOPS], DefaultTabStops2String));
+
+ if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_tab_stops )
+ atk_text_attribute_tab_stops = atk_text_attribute_register("tab-stops");
+
+ attribute_set = attribute_set_prepend(attribute_set, atk_text_attribute_tab_stops,
+ get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_TAB_STOPS], TabStops2String));
+
+ // --> OD 2010-03-05 #i92233#
+ if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_mm_to_pixel_ratio )
+ atk_text_attribute_mm_to_pixel_ratio = atk_text_attribute_register("mm-to-pixel-ratio");
+
+ attribute_set = attribute_set_prepend( attribute_set, atk_text_attribute_mm_to_pixel_ratio,
+ get_value(rAttributeList, aIndexList[TEXT_ATTRIBUTE_MM_TO_PIXEL_RATIO], Float2String));
+ // <--
+
+ return attribute_set;
+}
+
+
+AtkAttributeSet* attribute_set_prepend_misspelled( AtkAttributeSet* attribute_set )
+{
+ if( ATK_TEXT_ATTR_INVALID == atk_text_attribute_misspelled )
+ atk_text_attribute_misspelled = atk_text_attribute_register( "text-spelling" );
+
+ attribute_set = attribute_set_prepend( attribute_set, atk_text_attribute_misspelled,
+ g_strdup_printf( "misspelled" ) );
+
+ return attribute_set;
+}
+
+// --> OD 2010-03-01 #i92232#
+AtkAttributeSet* attribute_set_prepend_tracked_change_insertion( AtkAttributeSet* attribute_set )
+{
+ if ( ATK_TEXT_ATTR_INVALID == atk_text_attribute_tracked_change )
+ {
+ atk_text_attribute_tracked_change = atk_text_attribute_register( "text-tracked-change" );
+ }
+
+ attribute_set = attribute_set_prepend( attribute_set,
+ atk_text_attribute_tracked_change,
+ g_strdup_printf( "insertion" ) );
+
+ return attribute_set;
+}
+
+AtkAttributeSet* attribute_set_prepend_tracked_change_deletion( AtkAttributeSet* attribute_set )
+{
+ if ( ATK_TEXT_ATTR_INVALID == atk_text_attribute_tracked_change )
+ {
+ atk_text_attribute_tracked_change = atk_text_attribute_register( "text-tracked-change" );
+ }
+
+ attribute_set = attribute_set_prepend( attribute_set,
+ atk_text_attribute_tracked_change,
+ g_strdup_printf( "deletion" ) );
+
+ return attribute_set;
+}
+
+AtkAttributeSet* attribute_set_prepend_tracked_change_formatchange( AtkAttributeSet* attribute_set )
+{
+ if ( ATK_TEXT_ATTR_INVALID == atk_text_attribute_tracked_change )
+ {
+ atk_text_attribute_tracked_change = atk_text_attribute_register( "text-tracked-change" );
+ }
+
+ attribute_set = attribute_set_prepend( attribute_set,
+ atk_text_attribute_tracked_change,
+ g_strdup_printf( "attribute-change" ) );
+
+ return attribute_set;
+}
+// <--
+
+/*****************************************************************************/
+
+struct AtkTextAttrMapping
+{
+ const char * name;
+ TextPropertyValueFunc toPropertyValue;
+};
+
+const AtkTextAttrMapping g_TextAttrMap[] =
+{
+ { "", InvalidValue }, // ATK_TEXT_ATTR_INVALID = 0
+ { "ParaLeftMargin", UnitString2CMM }, // ATK_TEXT_ATTR_LEFT_MARGIN
+ { "ParaRightMargin", UnitString2CMM }, // ATK_TEXT_ATTR_RIGHT_MARGIN
+ { "ParaFirstLineIndent", UnitString2CMM }, // ATK_TEXT_ATTR_INDENT
+ { "CharHidden", String2Bool }, // ATK_TEXT_ATTR_INVISIBLE
+ { "", InvalidValue }, // ATK_TEXT_ATTR_EDITABLE
+ { "ParaTopMargin", UnitString2CMM }, // ATK_TEXT_ATTR_PIXELS_ABOVE_LINES
+ { "ParaBottomMargin", UnitString2CMM }, // ATK_TEXT_ATTR_PIXELS_BELOW_LINES
+ { "", InvalidValue }, // ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP
+ { "", InvalidValue }, // ATK_TEXT_ATTR_BG_FULL_HEIGHT
+ { "", InvalidValue }, // ATK_TEXT_ATTR_RISE
+ { "CharUnderline", String2Underline }, // ATK_TEXT_ATTR_UNDERLINE
+ { "CharStrikeout", String2Strikeout }, // ATK_TEXT_ATTR_STRIKETHROUGH
+ { "CharHeight", String2Float }, // ATK_TEXT_ATTR_SIZE
+ { "CharScaleWidth", String2Scale }, // ATK_TEXT_ATTR_SCALE
+ { "CharWeight", String2Weight }, // ATK_TEXT_ATTR_WEIGHT
+ { "CharLocale", String2Locale }, // ATK_TEXT_ATTR_LANGUAGE
+ { "CharFontName", SetString }, // ATK_TEXT_ATTR_FAMILY_NAME
+ { "CharBackColor", String2Color }, // ATK_TEXT_ATTR_BG_COLOR
+ { "CharColor", String2Color }, // ATK_TEXT_ATTR_FG_COLOR
+ { "", InvalidValue }, // ATK_TEXT_ATTR_BG_STIPPLE
+ { "", InvalidValue }, // ATK_TEXT_ATTR_FG_STIPPLE
+ { "", InvalidValue }, // ATK_TEXT_ATTR_WRAP_MODE
+ { "", InvalidValue }, // ATK_TEXT_ATTR_DIRECTION
+ { "ParaAdjust", Justification2Adjust }, // ATK_TEXT_ATTR_JUSTIFICATION
+ { "", InvalidValue }, // ATK_TEXT_ATTR_STRETCH
+ { "CharCaseMap", String2CaseMap }, // ATK_TEXT_ATTR_VARIANT
+ { "CharPosture", Style2FontSlant } // ATK_TEXT_ATTR_STYLE
+};
+
+static const sal_Int32 g_TextAttrMapSize = sizeof( g_TextAttrMap ) / sizeof( AtkTextAttrMapping );
+
+/*****************************************************************************/
+
+bool
+attribute_set_map_to_property_values(
+ AtkAttributeSet* attribute_set,
+ uno::Sequence< beans::PropertyValue >& rValueList )
+{
+ // Ensure enough space ..
+ uno::Sequence< beans::PropertyValue > aAttributeList (g_TextAttrMapSize);
+
+ sal_Int32 nIndex = 0;
+ for( GSList * item = attribute_set; item != NULL; item = g_slist_next( item ) )
+ {
+ AtkAttribute* attribute = (AtkAttribute *) item;
+
+ AtkTextAttribute text_attr = atk_text_attribute_for_name( attribute->name );
+ if( text_attr < g_TextAttrMapSize )
+ {
+ if( g_TextAttrMap[text_attr].name[0] != '\0' )
+ {
+ if( ! g_TextAttrMap[text_attr].toPropertyValue( aAttributeList[nIndex].Value, attribute->value) )
+ return false;
+
+ aAttributeList[nIndex].Name = rtl::OUString::createFromAscii( g_TextAttrMap[text_attr].name );
+ aAttributeList[nIndex].State = beans::PropertyState_DIRECT_VALUE;
+ ++nIndex;
+ }
+ }
+ else
+ {
+ // Unsupported text attribute
+ return false;
+ }
+ }
+
+ aAttributeList.realloc( nIndex );
+ rValueList = aAttributeList;
+ return true;
+}
+
diff --git a/vcl/unx/gtk/a11y/atktextattributes.hxx b/vcl/unx/gtk/a11y/atktextattributes.hxx
new file mode 100644
index 000000000000..9c7628bf927e
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atktextattributes.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.
+ *
+ ************************************************************************/
+
+#ifndef __ATK_ATKTEXTATTRIBUTES_HXX__
+#define __ATK_ATKTEXTATTRIBUTES_HXX__
+
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+#include <atk/atk.h>
+
+AtkAttributeSet*
+attribute_set_new_from_property_values(
+ const com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >& rAttributeList,
+ bool run_attributes_only,
+ AtkText *text);
+
+bool
+attribute_set_map_to_property_values(
+ AtkAttributeSet* attribute_set,
+ com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >& rValueList );
+
+AtkAttributeSet* attribute_set_prepend_misspelled( AtkAttributeSet* attribute_set );
+// --> OD 2010-03-01 #i92232#
+AtkAttributeSet* attribute_set_prepend_tracked_change_insertion( AtkAttributeSet* attribute_set );
+AtkAttributeSet* attribute_set_prepend_tracked_change_deletion( AtkAttributeSet* attribute_set );
+AtkAttributeSet* attribute_set_prepend_tracked_change_formatchange( AtkAttributeSet* attribute_set );
+// <--
+
+#endif
diff --git a/vcl/unx/gtk/a11y/atkutil.cxx b/vcl/unx/gtk/a11y/atkutil.cxx
new file mode 100644
index 000000000000..13492f3d4a5c
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkutil.cxx
@@ -0,0 +1,802 @@
+/*************************************************************************
+ *
+ * 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/accessibility/XAccessibleContext.hpp>
+#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
+#include <com/sun/star/accessibility/XAccessibleSelection.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+// --> OD 2009-04-14 #i93269#
+#include <com/sun/star/accessibility/XAccessibleText.hpp>
+// <--
+#include <cppuhelper/implbase1.hxx>
+#include <vos/mutex.hxx>
+#include <rtl/ref.hxx>
+
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+#include <vcl/menu.hxx>
+#include <vcl/toolbox.hxx>
+
+#include "atkwrapper.hxx"
+#include "atkutil.hxx"
+
+#include <gtk/gtk.h>
+
+#include <set>
+
+// #define ENABLE_TRACING
+
+#ifdef ENABLE_TRACING
+#include <stdio.h>
+#endif
+
+using namespace ::com::sun::star;
+
+static uno::WeakReference< accessibility::XAccessible > xNextFocusObject;
+static guint focus_notify_handler = 0;
+
+/*****************************************************************************/
+
+extern "C" {
+
+static gint
+atk_wrapper_focus_idle_handler (gpointer data)
+{
+ vos::OGuard aGuard( Application::GetSolarMutex() );
+
+ focus_notify_handler = 0;
+
+ uno::Reference< accessibility::XAccessible > xAccessible = xNextFocusObject;
+ if( xAccessible.get() == reinterpret_cast < accessibility::XAccessible * > (data) )
+ {
+ // Gail does not notify focus changes to NULL, so do we ..
+ if( xAccessible.is() )
+ {
+ AtkObject *atk_obj = atk_object_wrapper_ref( xAccessible );
+
+#ifdef ENABLE_TRACING
+ fprintf(stderr, "notifying focus event for %p\n", atk_obj);
+#endif
+ atk_focus_tracker_notify(atk_obj);
+ // --> OD 2009-04-14 #i93269#
+ // emit text_caret_moved event for <XAccessibleText> object,
+ // if cursor is inside the <XAccessibleText> object.
+ // also emit state-changed:focused event under the same condition.
+ {
+ AtkObjectWrapper* wrapper_obj = ATK_OBJECT_WRAPPER (atk_obj);
+ if( !wrapper_obj->mpText && wrapper_obj->mpContext )
+ {
+ uno::Any any = wrapper_obj->mpContext->queryInterface( accessibility::XAccessibleText::static_type(NULL) );
+ if ( typelib_TypeClass_INTERFACE == any.pType->eTypeClass &&
+ any.pReserved != 0 )
+ {
+ wrapper_obj->mpText = reinterpret_cast< accessibility::XAccessibleText * > (any.pReserved);
+ if ( wrapper_obj->mpText != 0 )
+ {
+ wrapper_obj->mpText->acquire();
+ gint caretPos = wrapper_obj->mpText->getCaretPosition();
+
+ if ( caretPos != -1 )
+ {
+ atk_object_notify_state_change( atk_obj, ATK_STATE_FOCUSED, TRUE );
+ g_signal_emit_by_name( atk_obj, "text_caret_moved", caretPos );
+ }
+ }
+ }
+ }
+ }
+ // <--
+ g_object_unref(atk_obj);
+ }
+ }
+
+ return FALSE;
+}
+
+} // extern "C"
+
+/*****************************************************************************/
+
+static void
+atk_wrapper_focus_tracker_notify_when_idle( const uno::Reference< accessibility::XAccessible > &xAccessible )
+{
+ if( focus_notify_handler )
+ g_source_remove(focus_notify_handler);
+
+ xNextFocusObject = xAccessible;
+
+ focus_notify_handler = g_idle_add (atk_wrapper_focus_idle_handler, xAccessible.get());
+}
+
+/*****************************************************************************/
+
+class DocumentFocusListener :
+ public ::cppu::WeakImplHelper1< accessibility::XAccessibleEventListener >
+{
+
+ std::set< uno::Reference< uno::XInterface > > m_aRefList;
+
+public:
+ void attachRecursive(
+ const uno::Reference< accessibility::XAccessible >& xAccessible
+ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException);
+
+ void attachRecursive(
+ const uno::Reference< accessibility::XAccessible >& xAccessible,
+ const uno::Reference< accessibility::XAccessibleContext >& xContext
+ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException);
+
+ void attachRecursive(
+ const uno::Reference< accessibility::XAccessible >& xAccessible,
+ const uno::Reference< accessibility::XAccessibleContext >& xContext,
+ const uno::Reference< accessibility::XAccessibleStateSet >& xStateSet
+ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException);
+
+ void detachRecursive(
+ const uno::Reference< accessibility::XAccessible >& xAccessible
+ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException);
+
+ void detachRecursive(
+ const uno::Reference< accessibility::XAccessible >& xAccessible,
+ const uno::Reference< accessibility::XAccessibleContext >& xContext
+ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException);
+
+ void detachRecursive(
+ const uno::Reference< accessibility::XAccessible >& xAccessible,
+ const uno::Reference< accessibility::XAccessibleContext >& xContext,
+ const uno::Reference< accessibility::XAccessibleStateSet >& xStateSet
+ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException);
+
+ static uno::Reference< accessibility::XAccessible > getAccessible(const lang::EventObject& aEvent )
+ throw (lang::IndexOutOfBoundsException, uno::RuntimeException);
+
+ // XEventListener
+ virtual void disposing( const lang::EventObject& Source ) throw (uno::RuntimeException);
+
+ // XAccessibleEventListener
+ virtual void notifyEvent( const accessibility::AccessibleEventObject& aEvent ) throw( uno::RuntimeException );
+};
+
+/*****************************************************************************/
+
+void DocumentFocusListener::disposing( const lang::EventObject& aEvent )
+ throw (uno::RuntimeException)
+{
+// fprintf(stderr, "In DocumentFocusListener::disposing (%p)\n", this);
+// fprintf(stderr, "m_aRefList has %d entries\n", m_aRefList.size());
+
+ // Unref the object here, but do not remove as listener since the object
+ // might no longer be in a state that safely allows this.
+ if( aEvent.Source.is() )
+ m_aRefList.erase(aEvent.Source);
+
+// fprintf(stderr, "m_aRefList has %d entries\n", m_aRefList.size());
+
+}
+
+/*****************************************************************************/
+
+void DocumentFocusListener::notifyEvent( const accessibility::AccessibleEventObject& aEvent )
+ throw( uno::RuntimeException )
+{
+ switch( aEvent.EventId )
+ {
+ case accessibility::AccessibleEventId::STATE_CHANGED:
+ try
+ {
+ sal_Int16 nState = accessibility::AccessibleStateType::INVALID;
+ aEvent.NewValue >>= nState;
+
+ if( accessibility::AccessibleStateType::FOCUSED == nState )
+ atk_wrapper_focus_tracker_notify_when_idle( getAccessible(aEvent) );
+ }
+ catch(const lang::IndexOutOfBoundsException &e)
+ {
+ g_warning("Focused object has invalid index in parent");
+ }
+ break;
+
+ case accessibility::AccessibleEventId::CHILD:
+ {
+ uno::Reference< accessibility::XAccessible > xChild;
+ if( (aEvent.OldValue >>= xChild) && xChild.is() )
+ detachRecursive(xChild);
+
+ if( (aEvent.NewValue >>= xChild) && xChild.is() )
+ attachRecursive(xChild);
+ }
+ break;
+
+ case accessibility::AccessibleEventId::INVALIDATE_ALL_CHILDREN:
+/* {
+ uno::Reference< accessibility::XAccessible > xAccessible( getAccessible(aEvent) );
+ detachRecursive(xAccessible);
+ attachRecursive(xAccessible);
+ }
+*/
+ g_warning( "Invalidate all children called\n" );
+ break;
+ default:
+ break;
+ }
+}
+
+/*****************************************************************************/
+
+uno::Reference< accessibility::XAccessible > DocumentFocusListener::getAccessible(const lang::EventObject& aEvent )
+ throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
+{
+ uno::Reference< accessibility::XAccessible > xAccessible(aEvent.Source, uno::UNO_QUERY);
+
+ if( xAccessible.is() )
+ return xAccessible;
+
+ uno::Reference< accessibility::XAccessibleContext > xContext(aEvent.Source, uno::UNO_QUERY);
+
+ if( xContext.is() )
+ {
+ uno::Reference< accessibility::XAccessible > xParent( xContext->getAccessibleParent() );
+ if( xParent.is() )
+ {
+ uno::Reference< accessibility::XAccessibleContext > xParentContext( xParent->getAccessibleContext() );
+ if( xParentContext.is() )
+ {
+ return xParentContext->getAccessibleChild( xContext->getAccessibleIndexInParent() );
+ }
+ }
+ }
+
+ return uno::Reference< accessibility::XAccessible >();
+}
+
+/*****************************************************************************/
+
+void DocumentFocusListener::attachRecursive(
+ const uno::Reference< accessibility::XAccessible >& xAccessible
+) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
+{
+ uno::Reference< accessibility::XAccessibleContext > xContext =
+ xAccessible->getAccessibleContext();
+
+ if( xContext.is() )
+ attachRecursive(xAccessible, xContext);
+}
+
+/*****************************************************************************/
+
+void DocumentFocusListener::attachRecursive(
+ const uno::Reference< accessibility::XAccessible >& xAccessible,
+ const uno::Reference< accessibility::XAccessibleContext >& xContext
+) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
+{
+ uno::Reference< accessibility::XAccessibleStateSet > xStateSet =
+ xContext->getAccessibleStateSet();
+
+ if( xStateSet.is() )
+ attachRecursive(xAccessible, xContext, xStateSet);
+}
+
+/*****************************************************************************/
+
+void DocumentFocusListener::attachRecursive(
+ const uno::Reference< accessibility::XAccessible >& xAccessible,
+ const uno::Reference< accessibility::XAccessibleContext >& xContext,
+ const uno::Reference< accessibility::XAccessibleStateSet >& xStateSet
+) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
+{
+ if( xStateSet->contains(accessibility::AccessibleStateType::FOCUSED ) )
+ atk_wrapper_focus_tracker_notify_when_idle( xAccessible );
+
+ uno::Reference< accessibility::XAccessibleEventBroadcaster > xBroadcaster =
+ uno::Reference< accessibility::XAccessibleEventBroadcaster >(xContext, uno::UNO_QUERY);
+
+ // If not already done, add the broadcaster to the list and attach as listener.
+ if( xBroadcaster.is() && m_aRefList.insert(xBroadcaster).second )
+ {
+ xBroadcaster->addEventListener(static_cast< accessibility::XAccessibleEventListener *>(this));
+
+ if( ! xStateSet->contains(accessibility::AccessibleStateType::MANAGES_DESCENDANTS ) )
+ {
+ sal_Int32 n, nmax = xContext->getAccessibleChildCount();
+ for( n = 0; n < nmax; n++ )
+ {
+ uno::Reference< accessibility::XAccessible > xChild( xContext->getAccessibleChild( n ) );
+
+ if( xChild.is() )
+ attachRecursive(xChild);
+ }
+ }
+ }
+}
+
+/*****************************************************************************/
+
+void DocumentFocusListener::detachRecursive(
+ const uno::Reference< accessibility::XAccessible >& xAccessible
+) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
+{
+ uno::Reference< accessibility::XAccessibleContext > xContext =
+ xAccessible->getAccessibleContext();
+
+ if( xContext.is() )
+ detachRecursive(xAccessible, xContext);
+}
+
+/*****************************************************************************/
+
+void DocumentFocusListener::detachRecursive(
+ const uno::Reference< accessibility::XAccessible >& xAccessible,
+ const uno::Reference< accessibility::XAccessibleContext >& xContext
+) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
+{
+ uno::Reference< accessibility::XAccessibleStateSet > xStateSet =
+ xContext->getAccessibleStateSet();
+
+ if( xStateSet.is() )
+ detachRecursive(xAccessible, xContext, xStateSet);
+}
+
+/*****************************************************************************/
+
+void DocumentFocusListener::detachRecursive(
+ const uno::Reference< accessibility::XAccessible >&,
+ const uno::Reference< accessibility::XAccessibleContext >& xContext,
+ const uno::Reference< accessibility::XAccessibleStateSet >& xStateSet
+) throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
+{
+ uno::Reference< accessibility::XAccessibleEventBroadcaster > xBroadcaster =
+ uno::Reference< accessibility::XAccessibleEventBroadcaster >(xContext, uno::UNO_QUERY);
+
+ if( xBroadcaster.is() && 0 < m_aRefList.erase(xBroadcaster) )
+ {
+ xBroadcaster->removeEventListener(static_cast< accessibility::XAccessibleEventListener *>(this));
+
+ if( ! xStateSet->contains(accessibility::AccessibleStateType::MANAGES_DESCENDANTS ) )
+ {
+ sal_Int32 n, nmax = xContext->getAccessibleChildCount();
+ for( n = 0; n < nmax; n++ )
+ {
+ uno::Reference< accessibility::XAccessible > xChild( xContext->getAccessibleChild( n ) );
+
+ if( xChild.is() )
+ detachRecursive(xChild);
+ }
+ }
+ }
+}
+
+/*****************************************************************************/
+
+/*
+ * page tabs in gtk are widgets, so we need to simulate focus events for those
+ */
+
+static void handle_tabpage_activated(Window *pWindow)
+{
+ uno::Reference< accessibility::XAccessible > xAccessible =
+ pWindow->GetAccessible();
+
+ if( ! xAccessible.is() )
+ return;
+
+ uno::Reference< accessibility::XAccessibleSelection > xSelection(
+ xAccessible->getAccessibleContext(), uno::UNO_QUERY);
+
+ if( xSelection.is() )
+ atk_wrapper_focus_tracker_notify_when_idle( xSelection->getSelectedAccessibleChild(0) );
+}
+
+/*****************************************************************************/
+
+/*
+ * toolbar items in gtk are widgets, so we need to simulate focus events for those
+ */
+
+static void notify_toolbox_item_focus(ToolBox *pToolBox)
+{
+ uno::Reference< accessibility::XAccessible > xAccessible =
+ pToolBox->GetAccessible();
+
+ if( ! xAccessible.is() )
+ return;
+
+ uno::Reference< accessibility::XAccessibleContext > xContext =
+ xAccessible->getAccessibleContext();
+
+ if( ! xContext.is() )
+ return;
+
+ sal_Int32 nPos = pToolBox->GetItemPos( pToolBox->GetHighlightItemId() );
+ if( nPos != TOOLBOX_ITEM_NOTFOUND )
+ atk_wrapper_focus_tracker_notify_when_idle( xContext->getAccessibleChild( nPos ) );
+}
+
+static void handle_toolbox_highlight(Window *pWindow)
+{
+ ToolBox *pToolBox = static_cast <ToolBox *> (pWindow);
+
+ // Make sure either the toolbox or its parent toolbox has the focus
+ if ( ! pToolBox->HasFocus() )
+ {
+ ToolBox* pToolBoxParent = dynamic_cast< ToolBox* >( pToolBox->GetParent() );
+ if ( ! pToolBoxParent || ! pToolBoxParent->HasFocus() )
+ return;
+ }
+
+ notify_toolbox_item_focus(pToolBox);
+}
+
+static void handle_toolbox_highlightoff(Window *pWindow)
+{
+ ToolBox *pToolBox = static_cast <ToolBox *> (pWindow);
+ ToolBox* pToolBoxParent = dynamic_cast< ToolBox* >( pToolBox->GetParent() );
+
+ // Notify when leaving sub toolboxes
+ if( pToolBoxParent && pToolBoxParent->HasFocus() )
+ notify_toolbox_item_focus( pToolBoxParent );
+}
+
+/*****************************************************************************/
+
+static void create_wrapper_for_child(
+ const uno::Reference< accessibility::XAccessibleContext >& xContext,
+ sal_Int32 index)
+{
+ if( xContext.is() )
+ {
+ uno::Reference< accessibility::XAccessible > xChild(xContext->getAccessibleChild(index));
+ if( xChild.is() )
+ {
+ // create the wrapper object - it will survive the unref unless it is a transient object
+ g_object_unref( atk_object_wrapper_ref( xChild ) );
+ }
+ }
+}
+
+/*****************************************************************************/
+
+static void handle_toolbox_buttonchange(VclWindowEvent const *pEvent)
+{
+ Window* pWindow = pEvent->GetWindow();
+ sal_Int32 index = (sal_Int32)(sal_IntPtr) pEvent->GetData();
+
+ if( pWindow && pWindow->IsReallyVisible() )
+ {
+ uno::Reference< accessibility::XAccessible > xAccessible(pWindow->GetAccessible());
+ if( xAccessible.is() )
+ {
+ create_wrapper_for_child(xAccessible->getAccessibleContext(), index);
+ }
+ }
+}
+
+/*****************************************************************************/
+
+/* currently not needed anymore...
+static void create_wrapper_for_children(Window *pWindow)
+{
+ if( pWindow && pWindow->IsReallyVisible() )
+ {
+ uno::Reference< accessibility::XAccessible > xAccessible(pWindow->GetAccessible());
+ if( xAccessible.is() )
+ {
+ uno::Reference< accessibility::XAccessibleContext > xContext(xAccessible->getAccessibleContext());
+ if( xContext.is() )
+ {
+ sal_Int32 nChildren = xContext->getAccessibleChildCount();
+ for( sal_Int32 i = 0; i < nChildren; ++i )
+ create_wrapper_for_child(xContext, i);
+ }
+ }
+ }
+}
+*/
+
+/*****************************************************************************/
+
+static std::set< Window * > g_aWindowList;
+
+static void handle_get_focus(::VclWindowEvent const * pEvent)
+{
+ static rtl::Reference< DocumentFocusListener > aDocumentFocusListener =
+ new DocumentFocusListener();
+
+ Window *pWindow = pEvent->GetWindow();
+
+ // The menu bar is handled through VCLEVENT_MENU_HIGHLIGHTED
+ if( ! pWindow || !pWindow->IsReallyVisible() || pWindow->GetType() == WINDOW_MENUBARWINDOW )
+ return;
+
+ // ToolBoxes are handled through VCLEVENT_TOOLBOX_HIGHLIGHT
+ if( pWindow->GetType() == WINDOW_TOOLBOX )
+ return;
+
+ if( pWindow->GetType() == WINDOW_TABCONTROL )
+ {
+ handle_tabpage_activated( pWindow );
+ return;
+ }
+
+ uno::Reference< accessibility::XAccessible > xAccessible =
+ pWindow->GetAccessible();
+
+ if( ! xAccessible.is() )
+ return;
+
+ uno::Reference< accessibility::XAccessibleContext > xContext =
+ xAccessible->getAccessibleContext();
+
+ if( ! xContext.is() )
+ return;
+
+ uno::Reference< accessibility::XAccessibleStateSet > xStateSet =
+ xContext->getAccessibleStateSet();
+
+ if( ! xStateSet.is() )
+ return;
+
+/* the UNO ToolBox wrapper does not (yet?) support XAccessibleSelection, so we
+ * need to add listeners to the children instead of re-using the tabpage stuff
+ */
+ if( xStateSet->contains(accessibility::AccessibleStateType::FOCUSED) &&
+ ( pWindow->GetType() != WINDOW_TREELISTBOX ) )
+ {
+ atk_wrapper_focus_tracker_notify_when_idle( xAccessible );
+ }
+ else
+ {
+ if( g_aWindowList.find(pWindow) == g_aWindowList.end() )
+ {
+ g_aWindowList.insert(pWindow);
+ try
+ {
+ aDocumentFocusListener->attachRecursive(xAccessible, xContext, xStateSet);
+ }
+ catch( const uno::Exception &e )
+ {
+ g_warning( "Exception caught processing focus events" );
+ }
+ }
+#ifdef ENABLE_TRACING
+ else
+ fprintf(stderr, "Window %p already in the list\n", pWindow );
+#endif
+ }
+}
+
+/*****************************************************************************/
+
+static void handle_menu_highlighted(::VclMenuEvent const * pEvent)
+{
+ try
+ {
+ Menu* pMenu = pEvent->GetMenu();
+ USHORT nPos = pEvent->GetItemPos();
+
+ if( pMenu && nPos != 0xFFFF)
+ {
+ uno::Reference< accessibility::XAccessible > xAccessible ( pMenu->GetAccessible() );
+
+ if( xAccessible.is() )
+ {
+ uno::Reference< accessibility::XAccessibleContext > xContext ( xAccessible->getAccessibleContext() );
+
+ if( xContext.is() )
+ atk_wrapper_focus_tracker_notify_when_idle( xContext->getAccessibleChild( nPos ) );
+ }
+ }
+ }
+ catch( const uno::Exception& e )
+ {
+ g_warning( "Exception caught processing menu highlight events" );
+ }
+}
+
+/*****************************************************************************/
+
+long WindowEventHandler(void *, ::VclSimpleEvent const * pEvent)
+{
+ switch (pEvent->GetId())
+ {
+ case VCLEVENT_WINDOW_SHOW:
+// fprintf(stderr, "got VCLEVENT_WINDOW_SHOW for %p\n",
+// static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
+ break;
+ case VCLEVENT_WINDOW_HIDE:
+// fprintf(stderr, "got VCLEVENT_WINDOW_HIDE for %p\n",
+// static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
+ break;
+ case VCLEVENT_WINDOW_CLOSE:
+// fprintf(stderr, "got VCLEVENT_WINDOW_CLOSE for %p\n",
+// static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
+ break;
+ case VCLEVENT_WINDOW_GETFOCUS:
+ handle_get_focus(static_cast< ::VclWindowEvent const * >(pEvent));
+ break;
+ case VCLEVENT_WINDOW_LOSEFOCUS:
+// fprintf(stderr, "got VCLEVENT_WINDOW_LOSEFOCUS for %p\n",
+// static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
+ break;
+ case VCLEVENT_WINDOW_MINIMIZE:
+// fprintf(stderr, "got VCLEVENT_WINDOW_MINIMIZE for %p\n",
+// static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
+ break;
+ case VCLEVENT_WINDOW_NORMALIZE:
+// fprintf(stderr, "got VCLEVENT_WINDOW_NORMALIZE for %p\n",
+// static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
+ break;
+ case VCLEVENT_WINDOW_KEYINPUT:
+ case VCLEVENT_WINDOW_KEYUP:
+ case VCLEVENT_WINDOW_COMMAND:
+ case VCLEVENT_WINDOW_MOUSEMOVE:
+ break;
+ /*
+ fprintf(stderr, "got VCLEVENT_WINDOW_COMMAND (%d) for %p\n",
+ static_cast< ::CommandEvent const * > (
+ static_cast< ::VclWindowEvent const * >(pEvent)->GetData())->GetCommand(),
+ static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
+ */
+ case VCLEVENT_MENU_HIGHLIGHT:
+ if (const VclMenuEvent* pMenuEvent = dynamic_cast<const VclMenuEvent*>(pEvent))
+ {
+ handle_menu_highlighted(pMenuEvent);
+ }
+ else if (const VclAccessibleEvent* pAccEvent = dynamic_cast<const VclAccessibleEvent*>(pEvent))
+ {
+ uno::Reference< accessibility::XAccessible > xAccessible = pAccEvent->GetAccessible();
+ if (xAccessible.is())
+ atk_wrapper_focus_tracker_notify_when_idle(xAccessible);
+ }
+ break;
+
+ case VCLEVENT_TOOLBOX_HIGHLIGHT:
+ handle_toolbox_highlight(static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
+ break;
+
+ case VCLEVENT_TOOLBOX_BUTTONSTATECHANGED:
+ handle_toolbox_buttonchange(static_cast< ::VclWindowEvent const * >(pEvent));
+ break;
+
+ case VCLEVENT_OBJECT_DYING:
+ g_aWindowList.erase( static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow() );
+ // fallthrough intentional !
+ case VCLEVENT_TOOLBOX_HIGHLIGHTOFF:
+ handle_toolbox_highlightoff(static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
+ break;
+
+ case VCLEVENT_TABPAGE_ACTIVATE:
+ handle_tabpage_activated(static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
+ break;
+
+ case VCLEVENT_COMBOBOX_SETTEXT:
+ // MT 2010/02: This looks quite strange to me. Stumbled over this when fixing #i104290#.
+ // This kicked in when leaving the combobox in the toolbar, after that the events worked.
+ // I guess this was a try to work around missing combobox events, which didn't do the full job, and shouldn't be necessary anymore.
+ // Fix for #i104290# was done in toolkit/source/awt/vclxaccessiblecomponent, FOCUSED state for compound controls in general.
+ // create_wrapper_for_children(static_cast< ::VclWindowEvent const * >(pEvent)->GetWindow());
+ break;
+
+ default:
+// OSL_TRACE("got event %d \n", pEvent->GetId());
+ break;
+ }
+ return 0;
+}
+
+static Link g_aEventListenerLink( NULL, (PSTUB) WindowEventHandler );
+
+/*****************************************************************************/
+
+extern "C" {
+
+static G_CONST_RETURN gchar *
+ooo_atk_util_get_toolkit_name (void)
+{
+ return "VCL";
+}
+
+/*****************************************************************************/
+
+static G_CONST_RETURN gchar *
+ooo_atk_util_get_toolkit_version (void)
+{
+ /*
+ * Version is passed in as a -D flag when this file is
+ * compiled.
+ */
+
+ return VERSION;
+}
+
+/*****************************************************************************/
+
+/*
+ * GObject inheritance
+ */
+
+static void
+ooo_atk_util_class_init (AtkUtilClass *)
+{
+ AtkUtilClass *atk_class;
+ gpointer data;
+
+ data = g_type_class_peek (ATK_TYPE_UTIL);
+ atk_class = ATK_UTIL_CLASS (data);
+
+ atk_class->get_toolkit_name = ooo_atk_util_get_toolkit_name;
+ atk_class->get_toolkit_version = ooo_atk_util_get_toolkit_version;
+
+ Application::AddEventListener( g_aEventListenerLink );
+}
+
+} // extern "C"
+
+/*****************************************************************************/
+
+GType
+ooo_atk_util_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type)
+ {
+ GType parent_type = g_type_from_name( "GailUtil" );
+
+ if( ! parent_type )
+ {
+ g_warning( "Unknown type: GailUtil" );
+ parent_type = ATK_TYPE_UTIL;
+ }
+
+ GTypeQuery type_query;
+ g_type_query( parent_type, &type_query );
+
+ static const GTypeInfo typeInfo =
+ {
+ type_query.class_size,
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) ooo_atk_util_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL,
+ type_query.instance_size,
+ 0,
+ (GInstanceInitFunc) NULL,
+ NULL
+ } ;
+
+ type = g_type_register_static (parent_type, "OOoUtil", &typeInfo, (GTypeFlags)0) ;
+ }
+
+ return type;
+}
+
+
diff --git a/vcl/unx/gtk/a11y/atkutil.hxx b/vcl/unx/gtk/a11y/atkutil.hxx
new file mode 100644
index 000000000000..8c8ddf59c65f
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkutil.hxx
@@ -0,0 +1,37 @@
+/*************************************************************************
+ *
+ * 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 __ATK_UTIL_HXX__
+#define __ATK_UTIL_HXX__
+
+#include <atk/atk.h>
+
+#define OOO_TYPE_ATK_UTIL ooo_atk_util_get_type()
+
+GType ooo_atk_util_get_type (void);
+
+#endif
diff --git a/vcl/unx/gtk/a11y/atkvalue.cxx b/vcl/unx/gtk/a11y/atkvalue.cxx
new file mode 100644
index 000000000000..9b8e9743eb18
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkvalue.cxx
@@ -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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "atkwrapper.hxx"
+
+#include <com/sun/star/accessibility/XAccessibleValue.hpp>
+
+#include <stdio.h>
+#include <string.h>
+
+using namespace ::com::sun::star;
+
+static accessibility::XAccessibleValue*
+ getValue( AtkValue *pValue ) throw (uno::RuntimeException)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( pValue );
+ if( pWrap )
+ {
+ if( !pWrap->mpValue && pWrap->mpContext )
+ {
+ uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleValue::static_type(NULL) );
+ pWrap->mpValue = reinterpret_cast< accessibility::XAccessibleValue * > (any.pReserved);
+ pWrap->mpValue->acquire();
+ }
+
+ return pWrap->mpValue;
+ }
+
+ return NULL;
+}
+
+static void anyToGValue( uno::Any aAny, GValue *pValue )
+{
+ // FIXME: expand to lots of types etc.
+ double aDouble=0;
+ aAny >>= aDouble;
+
+ memset( pValue, 0, sizeof( GValue ) );
+ g_value_init( pValue, G_TYPE_DOUBLE );
+ g_value_set_double( pValue, aDouble );
+}
+
+extern "C" {
+
+static void
+value_wrapper_get_current_value( AtkValue *value,
+ GValue *gval )
+{
+ try {
+ accessibility::XAccessibleValue* pValue = getValue( value );
+ if( pValue )
+ anyToGValue( pValue->getCurrentValue(), gval );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getCurrentValue()" );
+ }
+}
+
+static void
+value_wrapper_get_maximum_value( AtkValue *value,
+ GValue *gval )
+{
+ try {
+ accessibility::XAccessibleValue* pValue = getValue( value );
+ if( pValue )
+ anyToGValue( pValue->getMaximumValue(), gval );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getCurrentValue()" );
+ }
+}
+
+static void
+value_wrapper_get_minimum_value( AtkValue *value,
+ GValue *gval )
+{
+ try {
+ accessibility::XAccessibleValue* pValue = getValue( value );
+ if( pValue )
+ anyToGValue( pValue->getMinimumValue(), gval );
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getCurrentValue()" );
+ }
+}
+
+static gboolean
+value_wrapper_set_current_value( AtkValue *value,
+ const GValue *gval )
+{
+ try {
+ accessibility::XAccessibleValue* pValue = getValue( value );
+ if( pValue )
+ {
+ // FIXME - this needs expanding
+ double aDouble = g_value_get_double( gval );
+ uno::Any aAny;
+ aAny <<= aDouble;
+ return pValue->setCurrentValue( aAny );
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getCurrentValue()" );
+ }
+
+ return FALSE;
+}
+
+} // extern "C"
+
+void
+valueIfaceInit (AtkValueIface *iface)
+{
+ g_return_if_fail (iface != NULL);
+
+ iface->get_current_value = value_wrapper_get_current_value;
+ iface->get_maximum_value = value_wrapper_get_maximum_value;
+ iface->get_minimum_value = value_wrapper_get_minimum_value;
+ iface->set_current_value = value_wrapper_set_current_value;
+}
diff --git a/vcl/unx/gtk/a11y/atkwindow.cxx b/vcl/unx/gtk/a11y/atkwindow.cxx
new file mode 100644
index 000000000000..5448235998e8
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkwindow.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 <plugins/gtk/gtkframe.hxx>
+#include <vcl/window.hxx>
+#include "vcl/popupmenuwindow.hxx"
+
+#include "atkwindow.hxx"
+#include "atkwrapper.hxx"
+#include "atkregistry.hxx"
+
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::uno;
+
+extern "C" {
+
+static void (* window_real_initialize) (AtkObject *obj, gpointer data) = NULL;
+static void (* window_real_finalize) (GObject *obj) = NULL;
+
+static void
+init_from_window( AtkObject *accessible, Window *pWindow )
+{
+ static AtkRole aDefaultRole = ATK_ROLE_INVALID;
+
+ // Special role for sub-menu and combo-box popups that are exposed directly
+ // by their parents already.
+ if( aDefaultRole == ATK_ROLE_INVALID )
+ aDefaultRole = atk_role_register( "redundant object" );
+
+ AtkRole role = aDefaultRole;
+
+ // Determine the appropriate role for the GtkWindow
+ switch( pWindow->GetAccessibleRole() )
+ {
+ case AccessibleRole::ALERT:
+ role = ATK_ROLE_ALERT;
+ break;
+
+ case AccessibleRole::DIALOG:
+ role = ATK_ROLE_DIALOG;
+ break;
+
+ case AccessibleRole::FRAME:
+ role = ATK_ROLE_FRAME;
+ break;
+
+ /* Ignore window objects for sub-menus, combo- and list boxes,
+ * which are exposed as children of their parents.
+ */
+ case AccessibleRole::WINDOW:
+ {
+ USHORT type = WINDOW_WINDOW;
+ bool parentIsMenuFloatingWindow = false;
+
+ Window *pParent = pWindow->GetParent();
+ if( pParent ) {
+ type = pParent->GetType();
+ parentIsMenuFloatingWindow = ( TRUE == pParent->IsMenuFloatingWindow() );
+ }
+
+ if( (WINDOW_LISTBOX != type) && (WINDOW_COMBOBOX != type) &&
+ (WINDOW_MENUBARWINDOW != type) && ! parentIsMenuFloatingWindow )
+ {
+ role = ATK_ROLE_WINDOW;
+ }
+ }
+ break;
+
+ default:
+ {
+ Window *pChild = pWindow->GetChild( 0 );
+ if( pChild )
+ {
+ if( WINDOW_HELPTEXTWINDOW == pChild->GetType() )
+ {
+ role = ATK_ROLE_TOOL_TIP;
+ pChild->SetAccessibleRole( AccessibleRole::LABEL );
+ accessible->name = g_strdup( rtl::OUStringToOString( pChild->GetText(), RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ else if ( pWindow->GetType() == WINDOW_BORDERWINDOW && pChild->GetType() == WINDOW_FLOATINGWINDOW )
+ {
+ PopupMenuFloatingWindow* p = dynamic_cast<PopupMenuFloatingWindow*>(pChild);
+ if (p && p->IsPopupMenu() && p->GetMenuStackLevel() == 0)
+ {
+ // This is a top-level menu popup. Register it.
+ role = ATK_ROLE_POPUP_MENU;
+ pChild->SetAccessibleRole( AccessibleRole::POPUP_MENU );
+ accessible->name = g_strdup( rtl::OUStringToOString( pChild->GetText(), RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ accessible->role = role;
+}
+
+/*****************************************************************************/
+
+static gint
+ooo_window_wrapper_clear_focus(gpointer)
+{
+ atk_focus_tracker_notify( NULL );
+ return FALSE;
+}
+
+/*****************************************************************************/
+
+static gboolean
+ooo_window_wrapper_real_focus_gtk (GtkWidget *, GdkEventFocus *)
+{
+ g_idle_add( ooo_window_wrapper_clear_focus, NULL );
+ return FALSE;
+}
+
+static gboolean ooo_tooltip_map( GtkWidget* pToolTip, gpointer )
+{
+ AtkObject* pAccessible = gtk_widget_get_accessible( pToolTip );
+ if( pAccessible )
+ atk_object_notify_state_change( pAccessible, ATK_STATE_SHOWING, TRUE );
+ return FALSE;
+}
+
+static gboolean ooo_tooltip_unmap( GtkWidget* pToolTip, gpointer )
+{
+ AtkObject* pAccessible = gtk_widget_get_accessible( pToolTip );
+ if( pAccessible )
+ atk_object_notify_state_change( pAccessible, ATK_STATE_SHOWING, FALSE );
+ return FALSE;
+}
+
+/*****************************************************************************/
+
+static bool
+isChildPopupMenu(Window* pWindow)
+{
+ Window* pChild = pWindow->GetAccessibleChildWindow(0);
+ if (!pChild)
+ return false;
+
+ if (WINDOW_FLOATINGWINDOW != pChild->GetType())
+ return false;
+
+ PopupMenuFloatingWindow* p = dynamic_cast<PopupMenuFloatingWindow*>(pChild);
+ if (!p)
+ return false;
+
+ return p->IsPopupMenu();
+}
+
+static void
+ooo_window_wrapper_real_initialize(AtkObject *obj, gpointer data)
+{
+ window_real_initialize(obj, data);
+
+ GtkSalFrame *pFrame = GtkSalFrame::getFromWindow( GTK_WINDOW( data ) );
+ if( pFrame )
+ {
+ Window *pWindow = pFrame->GetWindow();
+ if( pWindow )
+ {
+ init_from_window( obj, pWindow );
+
+ Reference< XAccessible > xAccessible( pWindow->GetAccessible(true) );
+
+ /* We need the wrapper object for the top-level XAccessible to be
+ * in the wrapper registry when atk traverses the hierachy up on
+ * focus events
+ */
+ if( WINDOW_BORDERWINDOW == pWindow->GetType() )
+ {
+ if ( isChildPopupMenu(pWindow) )
+ {
+ AtkObject *child = atk_object_wrapper_new( xAccessible, obj );
+ ooo_wrapper_registry_add( xAccessible, child );
+ }
+ else
+ {
+ ooo_wrapper_registry_add( xAccessible, obj );
+ g_object_set_data( G_OBJECT(obj), "ooo:atk-wrapper-key", xAccessible.get() );
+ }
+ }
+ else
+ {
+ AtkObject *child = atk_object_wrapper_new( xAccessible, obj );
+ child->role = ATK_ROLE_FILLER;
+ if( (ATK_ROLE_DIALOG == obj->role) || (ATK_ROLE_ALERT == obj->role) )
+ child->role = ATK_ROLE_OPTION_PANE;
+ ooo_wrapper_registry_add( xAccessible, child );
+ }
+ }
+ }
+
+ g_signal_connect_after( GTK_WIDGET( data ), "focus-out-event",
+ G_CALLBACK (ooo_window_wrapper_real_focus_gtk),
+ NULL);
+
+ if( obj->role == ATK_ROLE_TOOL_TIP )
+ {
+ g_signal_connect_after( GTK_WIDGET( data ), "map-event",
+ G_CALLBACK (ooo_tooltip_map),
+ NULL);
+ g_signal_connect_after( GTK_WIDGET( data ), "unmap-event",
+ G_CALLBACK (ooo_tooltip_unmap),
+ NULL);
+ }
+}
+
+/*****************************************************************************/
+
+static void
+ooo_window_wrapper_real_finalize (GObject *obj)
+{
+ ooo_wrapper_registry_remove( (XAccessible *) g_object_get_data( obj, "ooo:atk-wrapper-key" ));
+ window_real_finalize( obj );
+}
+
+/*****************************************************************************/
+
+static void
+ooo_window_wrapper_class_init (AtkObjectClass *klass, gpointer)
+{
+ AtkObjectClass *atk_class;
+ GObjectClass *gobject_class;
+ gpointer data;
+
+ /*
+ * Patch the gobject vtable of GailWindow to refer to our instance of
+ * "initialize".
+ */
+
+ data = g_type_class_peek_parent( klass );
+ atk_class = ATK_OBJECT_CLASS (data);
+
+ window_real_initialize = atk_class->initialize;
+ atk_class->initialize = ooo_window_wrapper_real_initialize;
+
+ gobject_class = G_OBJECT_CLASS (data);
+
+ window_real_finalize = gobject_class->finalize;
+ gobject_class->finalize = ooo_window_wrapper_real_finalize;
+}
+
+} // extern "C"
+
+/*****************************************************************************/
+
+GType
+ooo_window_wrapper_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type)
+ {
+ GType parent_type = g_type_from_name( "GailWindow" );
+
+ if( ! parent_type )
+ {
+ g_warning( "Unknown type: GailWindow" );
+ parent_type = ATK_TYPE_OBJECT;
+ }
+
+ GTypeQuery type_query;
+ g_type_query( parent_type, &type_query );
+
+ static const GTypeInfo typeInfo =
+ {
+ type_query.class_size,
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) ooo_window_wrapper_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL,
+ type_query.instance_size,
+ 0,
+ (GInstanceInitFunc) NULL,
+ NULL
+ } ;
+
+ type = g_type_register_static (parent_type, "OOoWindowAtkObject", &typeInfo, (GTypeFlags)0) ;
+ }
+
+ return type;
+}
+
+void restore_gail_window_vtable (void)
+{
+ AtkObjectClass *atk_class;
+ gpointer data;
+
+ GType type = g_type_from_name( "GailWindow" );
+
+ if( type == G_TYPE_INVALID )
+ return;
+
+ data = g_type_class_peek( type );
+ atk_class = ATK_OBJECT_CLASS (data);
+
+ atk_class->initialize = window_real_initialize;
+}
+
diff --git a/vcl/unx/gtk/a11y/atkwindow.hxx b/vcl/unx/gtk/a11y/atkwindow.hxx
new file mode 100644
index 000000000000..6a9862256999
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkwindow.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef __ATK_WINDOW_HXX__
+#define __ATK_WINDOW_HXX__
+
+#include <atk/atk.h>
+
+#define OOO_TYPE_WINDOW_WRAPPER ooo_window_wrapper_get_type()
+
+GType ooo_window_wrapper_get_type (void);
+void restore_gail_window_vtable (void);
+
+#endif
diff --git a/vcl/unx/gtk/a11y/atkwrapper.cxx b/vcl/unx/gtk/a11y/atkwrapper.cxx
new file mode 100644
index 000000000000..10f75309708d
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkwrapper.cxx
@@ -0,0 +1,953 @@
+/*************************************************************************
+ *
+ * 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/uno/Any.hxx>
+#include <com/sun/star/uno/Type.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleRelation.hpp>
+#include <com/sun/star/accessibility/AccessibleRelationType.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/XAccessible.hpp>
+#include <com/sun/star/accessibility/XAccessibleText.hpp>
+#include <com/sun/star/accessibility/XAccessibleTextMarkup.hpp>
+#include <com/sun/star/accessibility/XAccessibleTextAttributes.hpp>
+#include <com/sun/star/accessibility/XAccessibleValue.hpp>
+#include <com/sun/star/accessibility/XAccessibleAction.hpp>
+#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+#include <com/sun/star/accessibility/XAccessibleComponent.hpp>
+#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
+#include <com/sun/star/accessibility/XAccessibleMultiLineText.hpp>
+#include <com/sun/star/accessibility/XAccessibleStateSet.hpp>
+#include <com/sun/star/accessibility/XAccessibleRelationSet.hpp>
+#include <com/sun/star/accessibility/XAccessibleTable.hpp>
+#include <com/sun/star/accessibility/XAccessibleEditableText.hpp>
+#include <com/sun/star/accessibility/XAccessibleImage.hpp>
+#include <com/sun/star/accessibility/XAccessibleHyperlink.hpp>
+#include <com/sun/star/accessibility/XAccessibleHypertext.hpp>
+#include <com/sun/star/accessibility/XAccessibleSelection.hpp>
+#include <com/sun/star/awt/XExtendedToolkit.hpp>
+#include <com/sun/star/awt/XTopWindow.hpp>
+#include <com/sun/star/awt/XTopWindowListener.hpp>
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/beans/Property.hpp>
+
+#include <rtl/ref.hxx>
+#include <cppuhelper/factory.hxx>
+#include <cppuhelper/queryinterface.hxx>
+
+#include "atkwrapper.hxx"
+#include "atkregistry.hxx"
+#include "atklistener.hxx"
+
+#ifdef ENABLE_TRACING
+#include <stdio.h>
+#endif
+
+#include <string.h>
+
+using namespace ::com::sun::star;
+
+static GObjectClass *parent_class = NULL;
+
+static AtkRelationType mapRelationType( sal_Int16 nRelation )
+{
+ AtkRelationType type = ATK_RELATION_NULL;
+
+ switch( nRelation )
+ {
+ case accessibility::AccessibleRelationType::CONTENT_FLOWS_FROM:
+ type = ATK_RELATION_FLOWS_FROM;
+ break;
+
+ case accessibility::AccessibleRelationType::CONTENT_FLOWS_TO:
+ type = ATK_RELATION_FLOWS_TO;
+ break;
+
+ case accessibility::AccessibleRelationType::CONTROLLED_BY:
+ type = ATK_RELATION_CONTROLLED_BY;
+ break;
+
+ case accessibility::AccessibleRelationType::CONTROLLER_FOR:
+ type = ATK_RELATION_CONTROLLER_FOR;
+ break;
+
+ case accessibility::AccessibleRelationType::LABEL_FOR:
+ type = ATK_RELATION_LABEL_FOR;
+ break;
+
+ case accessibility::AccessibleRelationType::LABELED_BY:
+ type = ATK_RELATION_LABELLED_BY;
+ break;
+
+ case accessibility::AccessibleRelationType::MEMBER_OF:
+ type = ATK_RELATION_MEMBER_OF;
+ break;
+
+ case accessibility::AccessibleRelationType::SUB_WINDOW_OF:
+ type = ATK_RELATION_SUBWINDOW_OF;
+ break;
+
+ case accessibility::AccessibleRelationType::NODE_CHILD_OF:
+ type = ATK_RELATION_NODE_CHILD_OF;
+ break;
+
+ default:
+ break;
+ }
+#if 0
+ ATK_RELATION_NODE_CHILD_OF,
+ ATK_RELATION_EMBEDS,
+ ATK_RELATION_EMBEDDED_BY,
+ ATK_RELATION_POPUP_FOR,
+#endif
+ return type;
+}
+
+
+AtkStateType mapAtkState( sal_Int16 nState )
+{
+ AtkStateType type = ATK_STATE_INVALID;
+
+ // A perfect / complete mapping ...
+ switch( nState )
+ {
+#define MAP_DIRECT( a ) \
+ case accessibility::AccessibleStateType::a: \
+ type = ATK_STATE_##a; break
+
+ MAP_DIRECT( INVALID );
+ MAP_DIRECT( ACTIVE );
+ MAP_DIRECT( ARMED );
+ MAP_DIRECT( BUSY );
+ MAP_DIRECT( CHECKED );
+ MAP_DIRECT( EDITABLE );
+ MAP_DIRECT( ENABLED );
+ MAP_DIRECT( EXPANDABLE );
+ MAP_DIRECT( EXPANDED );
+ MAP_DIRECT( FOCUSABLE );
+ MAP_DIRECT( FOCUSED );
+ MAP_DIRECT( HORIZONTAL );
+ MAP_DIRECT( ICONIFIED );
+ MAP_DIRECT( INDETERMINATE );
+ MAP_DIRECT( MANAGES_DESCENDANTS );
+ MAP_DIRECT( MODAL );
+ MAP_DIRECT( MULTI_LINE );
+ MAP_DIRECT( OPAQUE );
+ MAP_DIRECT( PRESSED );
+ MAP_DIRECT( RESIZABLE );
+ MAP_DIRECT( SELECTABLE );
+ MAP_DIRECT( SELECTED );
+ MAP_DIRECT( SENSITIVE );
+ MAP_DIRECT( SHOWING );
+ MAP_DIRECT( SINGLE_LINE );
+ MAP_DIRECT( STALE );
+ MAP_DIRECT( TRANSIENT );
+ MAP_DIRECT( VERTICAL );
+ MAP_DIRECT( VISIBLE );
+ // a spelling error ...
+ case accessibility::AccessibleStateType::DEFUNC:
+ type = ATK_STATE_DEFUNCT; break;
+ case accessibility::AccessibleStateType::MULTI_SELECTABLE:
+ type = ATK_STATE_MULTISELECTABLE; break;
+ default:
+ break;
+ }
+
+ return type;
+}
+
+static inline AtkRole registerRole( const gchar * name )
+{
+ AtkRole ret = atk_role_for_name( name );
+ if( ATK_ROLE_INVALID == ret )
+ ret = atk_role_register( name );
+
+ return ret;
+}
+
+static AtkRole mapToAtkRole( sal_Int16 nRole )
+{
+ AtkRole role = ATK_ROLE_UNKNOWN;
+
+ static AtkRole roleMap[] = {
+ ATK_ROLE_UNKNOWN,
+ ATK_ROLE_ALERT,
+ ATK_ROLE_COLUMN_HEADER,
+ ATK_ROLE_CANVAS,
+ ATK_ROLE_CHECK_BOX,
+ ATK_ROLE_CHECK_MENU_ITEM,
+ ATK_ROLE_COLOR_CHOOSER,
+ ATK_ROLE_COMBO_BOX,
+ ATK_ROLE_DATE_EDITOR,
+ ATK_ROLE_DESKTOP_ICON,
+ ATK_ROLE_DESKTOP_FRAME, // ? pane
+ ATK_ROLE_DIRECTORY_PANE,
+ ATK_ROLE_DIALOG,
+ ATK_ROLE_UNKNOWN, // DOCUMENT - registered below
+ ATK_ROLE_UNKNOWN, // EMBEDDED_OBJECT - registered below
+ ATK_ROLE_UNKNOWN, // END_NOTE - registered below
+ ATK_ROLE_FILE_CHOOSER,
+ ATK_ROLE_FILLER,
+ ATK_ROLE_FONT_CHOOSER,
+ ATK_ROLE_FOOTER,
+ ATK_ROLE_TEXT, // FOOTNOTE - registered below
+ ATK_ROLE_FRAME,
+ ATK_ROLE_GLASS_PANE,
+ ATK_ROLE_IMAGE, // GRAPHIC
+ ATK_ROLE_UNKNOWN, // GROUP_BOX - registered below
+ ATK_ROLE_HEADER,
+ ATK_ROLE_PARAGRAPH, // HEADING - registered below
+ ATK_ROLE_TEXT, // HYPER_LINK - registered below
+ ATK_ROLE_ICON,
+ ATK_ROLE_INTERNAL_FRAME,
+ ATK_ROLE_LABEL,
+ ATK_ROLE_LAYERED_PANE,
+ ATK_ROLE_LIST,
+ ATK_ROLE_LIST_ITEM,
+ ATK_ROLE_MENU,
+ ATK_ROLE_MENU_BAR,
+ ATK_ROLE_MENU_ITEM,
+ ATK_ROLE_OPTION_PANE,
+ ATK_ROLE_PAGE_TAB,
+ ATK_ROLE_PAGE_TAB_LIST,
+ ATK_ROLE_PANEL,
+ ATK_ROLE_PARAGRAPH,
+ ATK_ROLE_PASSWORD_TEXT,
+ ATK_ROLE_POPUP_MENU,
+ ATK_ROLE_PUSH_BUTTON,
+ ATK_ROLE_PROGRESS_BAR,
+ ATK_ROLE_RADIO_BUTTON,
+ ATK_ROLE_RADIO_MENU_ITEM,
+ ATK_ROLE_ROW_HEADER,
+ ATK_ROLE_ROOT_PANE,
+ ATK_ROLE_SCROLL_BAR,
+ ATK_ROLE_SCROLL_PANE,
+ ATK_ROLE_UNKNOWN, // SHAPE - registered below
+ ATK_ROLE_SEPARATOR,
+ ATK_ROLE_SLIDER,
+ ATK_ROLE_SPIN_BUTTON, // SPIN_BOX ?
+ ATK_ROLE_SPLIT_PANE,
+ ATK_ROLE_STATUSBAR,
+ ATK_ROLE_TABLE,
+ ATK_ROLE_TABLE_CELL,
+ ATK_ROLE_TEXT,
+ ATK_ROLE_INTERNAL_FRAME, // TEXT_FRAME - registered below
+ ATK_ROLE_TOGGLE_BUTTON,
+ ATK_ROLE_TOOL_BAR,
+ ATK_ROLE_TOOL_TIP,
+ ATK_ROLE_TREE,
+ ATK_ROLE_VIEWPORT,
+ ATK_ROLE_WINDOW,
+ ATK_ROLE_PUSH_BUTTON, // BUTTON_DROPDOWN
+ ATK_ROLE_PUSH_BUTTON, // BUTTON_MENU
+ ATK_ROLE_UNKNOWN, // CAPTION - registered below
+ ATK_ROLE_UNKNOWN, // CHART - registered below
+ ATK_ROLE_UNKNOWN, // EDIT_BAR - registered below
+ ATK_ROLE_UNKNOWN, // FORM - registered below
+ ATK_ROLE_UNKNOWN, // IMAGE_MAP - registered below
+ ATK_ROLE_UNKNOWN, // NOTE - registered below
+ ATK_ROLE_UNKNOWN, // PAGE - registered below
+ ATK_ROLE_RULER,
+ ATK_ROLE_UNKNOWN, // SECTION - registered below
+ ATK_ROLE_UNKNOWN, // TREE_ITEM - registered below
+ ATK_ROLE_TREE_TABLE,
+ ATK_ROLE_SCROLL_PANE, // COMMENT - mapped to atk_role_scroll_pane
+ ATK_ROLE_UNKNOWN // COMMENT_END - mapped to atk_role_unknown
+ };
+
+ static bool initialized = false;
+
+ if( ! initialized )
+ {
+ // re-use strings from ATK library
+ roleMap[accessibility::AccessibleRole::EDIT_BAR] = registerRole("edit bar");
+ roleMap[accessibility::AccessibleRole::EMBEDDED_OBJECT] = registerRole("embedded component");
+ roleMap[accessibility::AccessibleRole::CHART] = registerRole("chart");
+ roleMap[accessibility::AccessibleRole::CAPTION] = registerRole("caption");
+ roleMap[accessibility::AccessibleRole::DOCUMENT] = registerRole("document frame");
+ roleMap[accessibility::AccessibleRole::HEADING] = registerRole("heading");
+ roleMap[accessibility::AccessibleRole::PAGE] = registerRole("page");
+ roleMap[accessibility::AccessibleRole::SECTION] = registerRole("section");
+ roleMap[accessibility::AccessibleRole::FORM] = registerRole("form");
+
+ // these don't exist in ATK yet
+ roleMap[accessibility::AccessibleRole::END_NOTE] = registerRole("end note");
+ roleMap[accessibility::AccessibleRole::FOOTNOTE] = registerRole("foot note");
+ roleMap[accessibility::AccessibleRole::GROUP_BOX] = registerRole("group box");
+ roleMap[accessibility::AccessibleRole::HYPER_LINK] = registerRole("hyper link");
+ roleMap[accessibility::AccessibleRole::SHAPE] = registerRole("shape");
+ roleMap[accessibility::AccessibleRole::TEXT_FRAME] = registerRole("text frame");
+ roleMap[accessibility::AccessibleRole::IMAGE_MAP] = registerRole("image map");
+ roleMap[accessibility::AccessibleRole::NOTE] = registerRole("note");
+ roleMap[accessibility::AccessibleRole::TREE_ITEM] = registerRole("tree item");
+
+ initialized = true;
+ }
+
+ static const sal_Int32 nMapSize = sizeof(roleMap)/sizeof(sal_Int16);
+ if( 0 <= nRole && nMapSize > nRole )
+ role = roleMap[nRole];
+
+ return role;
+}
+
+
+/*****************************************************************************/
+
+extern "C" {
+
+/*****************************************************************************/
+
+static G_CONST_RETURN gchar*
+wrapper_get_name( AtkObject *atk_obj )
+{
+ AtkObjectWrapper *obj = ATK_OBJECT_WRAPPER (atk_obj);
+
+ if( obj->mpContext )
+ {
+ try {
+ rtl::OString aName =
+ rtl::OUStringToOString(
+ obj->mpContext->getAccessibleName(),
+ RTL_TEXTENCODING_UTF8);
+
+ int nCmp = atk_obj->name ? rtl_str_compare( atk_obj->name, aName.getStr() ) : -1;
+ if( nCmp != 0 )
+ {
+ if( atk_obj->name )
+ g_free(atk_obj->name);
+ atk_obj->name = g_strdup(aName.getStr());
+ }
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleName()" );
+ }
+ }
+
+ return ATK_OBJECT_CLASS (parent_class)->get_name(atk_obj);
+}
+
+/*****************************************************************************/
+
+static G_CONST_RETURN gchar*
+wrapper_get_description( AtkObject *atk_obj )
+{
+ AtkObjectWrapper *obj = ATK_OBJECT_WRAPPER (atk_obj);
+
+ if( obj->mpContext )
+ {
+ try {
+ rtl::OString aDescription =
+ rtl::OUStringToOString(
+ obj->mpContext->getAccessibleDescription(),
+ RTL_TEXTENCODING_UTF8);
+
+ g_free(atk_obj->description);
+ atk_obj->description = g_strdup(aDescription.getStr());
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleDescription()" );
+ }
+ }
+
+ return ATK_OBJECT_CLASS (parent_class)->get_description(atk_obj);
+
+}
+
+/*****************************************************************************/
+
+static gint
+wrapper_get_n_children( AtkObject *atk_obj )
+{
+ AtkObjectWrapper *obj = ATK_OBJECT_WRAPPER (atk_obj);
+ gint n = 0;
+
+ if( obj->mpContext )
+ {
+ try {
+ n = obj->mpContext->getAccessibleChildCount();
+ }
+ catch(const uno::Exception& e) {
+ OSL_ENSURE(0, "Exception in getAccessibleChildCount()" );
+ }
+ }
+
+ return n;
+}
+
+/*****************************************************************************/
+
+static AtkObject *
+wrapper_ref_child( AtkObject *atk_obj,
+ gint i )
+{
+ AtkObjectWrapper *obj = ATK_OBJECT_WRAPPER (atk_obj);
+ AtkObject* child = NULL;
+
+ // see comments above atk_object_wrapper_remove_child
+ if( -1 < i && obj->index_of_child_about_to_be_removed == i )
+ {
+ g_object_ref( obj->child_about_to_be_removed );
+ return obj->child_about_to_be_removed;
+ }
+
+ if( obj->mpContext )
+ {
+ try {
+ uno::Reference< accessibility::XAccessible > xAccessible =
+ obj->mpContext->getAccessibleChild( i );
+
+ child = atk_object_wrapper_ref( xAccessible );
+ }
+ catch(const uno::Exception& e) {
+ OSL_ENSURE(0, "Exception in getAccessibleChild");
+ }
+ }
+
+ return child;
+}
+
+/*****************************************************************************/
+
+static gint
+wrapper_get_index_in_parent( AtkObject *atk_obj )
+{
+ AtkObjectWrapper *obj = ATK_OBJECT_WRAPPER (atk_obj);
+ gint i = -1;
+
+ if( obj->mpContext )
+ {
+ try {
+ i = obj->mpContext->getAccessibleIndexInParent();
+
+#ifdef ENABLE_TRACING
+ fprintf(stderr, "%p->getAccessibleIndexInParent() returned: %u\n",
+ obj->mpAccessible, i);
+#endif
+ }
+ catch(const uno::Exception& e) {
+ g_warning( "Exception in getAccessibleIndexInParent()" );
+ }
+ }
+ return i;
+}
+
+/*****************************************************************************/
+
+static AtkRelationSet *
+wrapper_ref_relation_set( AtkObject *atk_obj )
+{
+ AtkObjectWrapper *obj = ATK_OBJECT_WRAPPER (atk_obj);
+ AtkRelationSet *pSet = atk_relation_set_new();
+
+ if( obj->mpContext )
+ {
+ try {
+ uno::Reference< accessibility::XAccessibleRelationSet > xRelationSet(
+ obj->mpContext->getAccessibleRelationSet()
+ );
+
+ sal_Int32 nRelations = xRelationSet.is() ? xRelationSet->getRelationCount() : 0;
+ for( sal_Int32 n = 0; n < nRelations; n++ )
+ {
+ accessibility::AccessibleRelation aRelation = xRelationSet->getRelation( n );
+ sal_uInt32 nTargetCount = aRelation.TargetSet.getLength();
+ AtkObject **pTargets = (AtkObject **) alloca( nTargetCount * sizeof(AtkObject *) );
+
+ for( sal_uInt32 i = 0; i < nTargetCount; i++ )
+ {
+ uno::Reference< accessibility::XAccessible > xAccessible(
+ aRelation.TargetSet[i], uno::UNO_QUERY );
+ pTargets[i] = atk_object_wrapper_ref( xAccessible );
+ }
+
+ AtkRelation *pRel =
+ atk_relation_new(
+ pTargets, nTargetCount,
+ mapRelationType( aRelation.RelationType )
+ );
+ atk_relation_set_add( pSet, pRel );
+ g_object_unref( G_OBJECT( pRel ) );
+ }
+ }
+ catch(const uno::Exception &e) {
+ g_object_unref( G_OBJECT( pSet ) );
+ pSet = NULL;
+ }
+ }
+
+ return pSet;
+}
+
+/*****************************************************************************/
+
+#if 0
+struct {
+ sal_Int16 value;
+ const sal_Char* name;
+} aStateTypeTable[] = {
+ { accessibility::AccessibleStateType::INVALID, "INVALID" },
+ { accessibility::AccessibleStateType::ACTIVE, "ACTIVE" },
+ { accessibility::AccessibleStateType::ARMED, "ARMED" },
+ { accessibility::AccessibleStateType::BUSY, "BUSY" },
+ { accessibility::AccessibleStateType::CHECKED, "CHECKED" },
+ { accessibility::AccessibleStateType::DEFUNC, "DEFUNC" },
+ { accessibility::AccessibleStateType::EDITABLE, "EDITABLE" },
+ { accessibility::AccessibleStateType::ENABLED, "ENABLED" },
+ { accessibility::AccessibleStateType::EXPANDABLE, "EXPANDABLE" },
+ { accessibility::AccessibleStateType::EXPANDED, "EXPANDED" },
+ { accessibility::AccessibleStateType::FOCUSABLE, "FOCUSABLE" },
+ { accessibility::AccessibleStateType::FOCUSED, "FOCUSED" },
+ { accessibility::AccessibleStateType::HORIZONTAL, "HORIZONTAL" },
+ { accessibility::AccessibleStateType::ICONIFIED, "ICONIFIED" },
+ { accessibility::AccessibleStateType::INDETERMINATE, "INDETERMINATE" },
+ { accessibility::AccessibleStateType::MANAGES_DESCENDANTS, "MANAGES_DESCENDANTS" },
+ { accessibility::AccessibleStateType::MODAL, "MODAL" },
+ { accessibility::AccessibleStateType::MULTI_LINE, "MULTI_LINE" },
+ { accessibility::AccessibleStateType::MULTI_SELECTABLE, "MULTI_SELECTABLE" },
+ { accessibility::AccessibleStateType::OPAQUE, "OPAQUE" },
+ { accessibility::AccessibleStateType::PRESSED, "PRESSED" },
+ { accessibility::AccessibleStateType::RESIZABLE, "RESIZABLE" },
+ { accessibility::AccessibleStateType::SELECTABLE, "SELECTABLE" },
+ { accessibility::AccessibleStateType::SELECTED, "SELECTED" },
+ { accessibility::AccessibleStateType::SENSITIVE, "SENSITIVE" },
+ { accessibility::AccessibleStateType::SHOWING, "SHOWING" },
+ { accessibility::AccessibleStateType::SINGLE_LINE, "SINGLE_LINE" },
+ { accessibility::AccessibleStateType::STALE, "STALE" },
+ { accessibility::AccessibleStateType::TRANSIENT, "TRANSIENT" },
+ { accessibility::AccessibleStateType::VERTICAL, "VERTICAL" },
+ { accessibility::AccessibleStateType::VISIBLE, "VISIBLE" }
+};
+
+static void printStates(const uno::Sequence<sal_Int16>& rStates)
+{
+ sal_Int32 n = rStates.getLength();
+ size_t nTypes = sizeof(aStateTypeTable)/sizeof(aStateTypeTable[0]);
+ for (sal_Int32 i = 0; i < n; ++i)
+ {
+ for (size_t j = 0; j < nTypes; ++j)
+ {
+ if (aStateTypeTable[j].value == rStates[i])
+ printf("%s ", aStateTypeTable[j].name);
+ }
+ }
+ printf("\n");
+}
+#endif
+
+static AtkStateSet *
+wrapper_ref_state_set( AtkObject *atk_obj )
+{
+ AtkObjectWrapper *obj = ATK_OBJECT_WRAPPER (atk_obj);
+ AtkStateSet *pSet = atk_state_set_new();
+
+ if( obj->mpContext )
+ {
+ try {
+ uno::Reference< accessibility::XAccessibleStateSet > xStateSet(
+ obj->mpContext->getAccessibleStateSet());
+
+ if( xStateSet.is() )
+ {
+ uno::Sequence< sal_Int16 > aStates = xStateSet->getStates();
+
+ for( sal_Int32 n = 0; n < aStates.getLength(); n++ )
+ atk_state_set_add_state( pSet, mapAtkState( aStates[n] ) );
+
+ // We need to emulate FOCUS state for menus, menu-items etc.
+ if( atk_obj == atk_get_focus_object() )
+ atk_state_set_add_state( pSet, ATK_STATE_FOCUSED );
+/* FIXME - should we do this ?
+ else
+ atk_state_set_remove_state( pSet, ATK_STATE_FOCUSED );
+*/
+ }
+ }
+
+ catch(const uno::Exception &e) {
+ g_warning( "Exception in wrapper_ref_state_set" );
+ atk_state_set_add_state( pSet, ATK_STATE_DEFUNCT );
+ }
+ }
+ else
+ atk_state_set_add_state( pSet, ATK_STATE_DEFUNCT );
+
+ return pSet;
+}
+
+/*****************************************************************************/
+
+
+static void
+atk_object_wrapper_finalize (GObject *obj)
+{
+ AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER (obj);
+
+ if( pWrap->mpAccessible )
+ {
+ ooo_wrapper_registry_remove( pWrap->mpAccessible );
+ pWrap->mpAccessible->release();
+ pWrap->mpAccessible = NULL;
+ }
+
+ atk_object_wrapper_dispose( pWrap );
+
+ parent_class->finalize( obj );
+}
+
+static void
+atk_object_wrapper_class_init (AtkObjectWrapperClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS( klass );
+ AtkObjectClass *atk_class = ATK_OBJECT_CLASS( klass );
+
+ parent_class = (GObjectClass *) g_type_class_peek_parent (klass);
+
+ // GObject methods
+ gobject_class->finalize = atk_object_wrapper_finalize;
+
+ // AtkObject methods
+ atk_class->get_name = wrapper_get_name;
+ atk_class->get_description = wrapper_get_description;
+ atk_class->get_n_children = wrapper_get_n_children;
+ atk_class->ref_child = wrapper_ref_child;
+ atk_class->get_index_in_parent = wrapper_get_index_in_parent;
+ atk_class->ref_relation_set = wrapper_ref_relation_set;
+ atk_class->ref_state_set = wrapper_ref_state_set;
+}
+
+static void
+atk_object_wrapper_init (AtkObjectWrapper *wrapper,
+ AtkObjectWrapperClass)
+{
+ wrapper->mpAction = NULL;
+ wrapper->mpComponent = NULL;
+ wrapper->mpEditableText = NULL;
+ wrapper->mpHypertext = NULL;
+ wrapper->mpImage = NULL;
+ wrapper->mpSelection = NULL;
+ wrapper->mpTable = NULL;
+ wrapper->mpText = NULL;
+ wrapper->mpValue = NULL;
+}
+
+} // extern "C"
+
+GType
+atk_object_wrapper_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type)
+ {
+ static const GTypeInfo typeInfo =
+ {
+ sizeof (AtkObjectWrapperClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) atk_object_wrapper_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL,
+ sizeof (AtkObjectWrapper),
+ 0,
+ (GInstanceInitFunc) atk_object_wrapper_init,
+ NULL
+ } ;
+ type = g_type_register_static (ATK_TYPE_OBJECT,
+ "OOoAtkObj",
+ &typeInfo, (GTypeFlags)0) ;
+ }
+ return type;
+}
+
+static bool
+isOfType( uno::XInterface *pInterface, const uno::Type & rType )
+{
+ g_return_val_if_fail( pInterface != NULL, false );
+
+ bool bIs = false;
+ try {
+ uno::Any aRet = pInterface->queryInterface( rType );
+
+ bIs = ( ( typelib_TypeClass_INTERFACE == aRet.pType->eTypeClass ) &&
+ ( aRet.pReserved != NULL ) );
+ } catch( const uno::Exception &e) { }
+
+ return bIs;
+}
+
+extern "C" {
+typedef GType (* GetGIfaceType ) (void);
+}
+const struct {
+ const char *name;
+ GInterfaceInitFunc aInit;
+ GetGIfaceType aGetGIfaceType;
+ const uno::Type & (*aGetUnoType) (void *);
+} aTypeTable[] = {
+// re-location heaven:
+ {
+ "Comp", (GInterfaceInitFunc) componentIfaceInit,
+ atk_component_get_type,
+ accessibility::XAccessibleComponent::static_type
+ },
+ {
+ "Act", (GInterfaceInitFunc) actionIfaceInit,
+ atk_action_get_type,
+ accessibility::XAccessibleAction::static_type
+ },
+ {
+ "Txt", (GInterfaceInitFunc) textIfaceInit,
+ atk_text_get_type,
+ accessibility::XAccessibleText::static_type
+ },
+ {
+ "Val", (GInterfaceInitFunc) valueIfaceInit,
+ atk_value_get_type,
+ accessibility::XAccessibleValue::static_type
+ },
+ {
+ "Tab", (GInterfaceInitFunc) tableIfaceInit,
+ atk_table_get_type,
+ accessibility::XAccessibleTable::static_type
+ },
+ {
+ "Edt", (GInterfaceInitFunc) editableTextIfaceInit,
+ atk_editable_text_get_type,
+ accessibility::XAccessibleEditableText::static_type
+ },
+ {
+ "Img", (GInterfaceInitFunc) imageIfaceInit,
+ atk_image_get_type,
+ accessibility::XAccessibleImage::static_type
+ },
+ {
+ "Hyp", (GInterfaceInitFunc) hypertextIfaceInit,
+ atk_hypertext_get_type,
+ accessibility::XAccessibleHypertext::static_type
+ },
+ {
+ "Sel", (GInterfaceInitFunc) selectionIfaceInit,
+ atk_selection_get_type,
+ accessibility::XAccessibleSelection::static_type
+ }
+ // AtkDocument is a nastily broken interface (so far)
+ // we could impl. get_document_type perhaps though.
+};
+
+const int aTypeTableSize = G_N_ELEMENTS( aTypeTable );
+
+static GType
+ensureTypeFor( uno::XInterface *pAccessible )
+{
+ int i;
+ int bTypes[ aTypeTableSize ] = { 0, };
+ rtl::OString aTypeName( "OOoAtkObj" );
+
+ for( i = 0; i < aTypeTableSize; i++ )
+ {
+ if( isOfType( pAccessible, aTypeTable[i].aGetUnoType(0) ) )
+ {
+ aTypeName += aTypeTable[i].name;
+ bTypes[i] = TRUE;
+ }
+// g_message( "Accessible %p has type '%s' (%d)",
+// pAccessible, aTypeTable[i].name, bTypes[i] );
+ }
+
+ GType nType = g_type_from_name( aTypeName );
+ if( nType == G_TYPE_INVALID )
+ {
+ GTypeInfo aTypeInfo = {
+ sizeof( AtkObjectWrapperClass ),
+ NULL, NULL, NULL, NULL, NULL,
+ sizeof( AtkObjectWrapper ),
+ 0, NULL, NULL
+ } ;
+ nType = g_type_register_static( ATK_TYPE_OBJECT_WRAPPER,
+ aTypeName, &aTypeInfo, (GTypeFlags)0 ) ;
+
+ for( int j = 0; j < aTypeTableSize; j++ )
+ if( bTypes[j] )
+ {
+ GInterfaceInfo aIfaceInfo = { NULL, NULL, NULL };
+ aIfaceInfo.interface_init = aTypeTable[j].aInit;
+ g_type_add_interface_static (nType, aTypeTable[j].aGetGIfaceType(),
+ &aIfaceInfo);
+ }
+ }
+ return nType;
+}
+
+AtkObject *
+atk_object_wrapper_ref( const uno::Reference< accessibility::XAccessible > &rxAccessible, bool create )
+{
+ g_return_val_if_fail( rxAccessible.get() != NULL, NULL );
+
+ AtkObject *obj = ooo_wrapper_registry_get(rxAccessible);
+ if( obj )
+ {
+ g_object_ref( obj );
+ return obj;
+ }
+
+ if( create )
+ return atk_object_wrapper_new( rxAccessible );
+
+ return NULL;
+}
+
+
+AtkObject *
+atk_object_wrapper_new( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& rxAccessible,
+ AtkObject* parent )
+{
+ g_return_val_if_fail( rxAccessible.get() != NULL, NULL );
+
+ AtkObjectWrapper *pWrap = NULL;
+
+ try {
+ uno::Reference< accessibility::XAccessibleContext > xContext(rxAccessible->getAccessibleContext());
+
+ g_return_val_if_fail( xContext.get() != NULL, NULL );
+
+ GType nType = ensureTypeFor( xContext.get() );
+ gpointer obj = g_object_new( nType, NULL);
+
+ pWrap = ATK_OBJECT_WRAPPER( obj );
+ pWrap->mpAccessible = rxAccessible.get();
+ rxAccessible->acquire();
+
+ pWrap->index_of_child_about_to_be_removed = -1;
+ pWrap->child_about_to_be_removed = NULL;
+
+ xContext->acquire();
+ pWrap->mpContext = xContext.get();
+
+ AtkObject* atk_obj = ATK_OBJECT(pWrap);
+ atk_obj->role = mapToAtkRole( xContext->getAccessibleRole() );
+ atk_obj->accessible_parent = parent;
+
+ ooo_wrapper_registry_add( rxAccessible, atk_obj );
+
+ if( parent )
+ g_object_ref( atk_obj->accessible_parent );
+ else
+ {
+ /* gail_focus_tracker remembers the focused object at the first
+ * parent in the hierachy that is a Gtk+ widget, but at the time the
+ * event gets processed (at idle), it may be too late to create the
+ * hierachy, so doing it now ..
+ */
+ uno::Reference< accessibility::XAccessible > xParent( xContext->getAccessibleParent() );
+
+ /* The top-level objects should never be of this class */
+ OSL_ASSERT( xParent.is() );
+
+ if( xParent.is() )
+ atk_obj->accessible_parent = atk_object_wrapper_ref( xParent );
+ }
+
+ // Attach a listener to the UNO object if it's not TRANSIENT
+ uno::Reference< accessibility::XAccessibleStateSet > xStateSet( xContext->getAccessibleStateSet() );
+ if( xStateSet.is() && ! xStateSet->contains( accessibility::AccessibleStateType::TRANSIENT ) )
+ {
+ uno::Reference< accessibility::XAccessibleEventBroadcaster > xBroadcaster(xContext, uno::UNO_QUERY);
+ if( xBroadcaster.is() )
+ xBroadcaster->addEventListener( static_cast< accessibility::XAccessibleEventListener * > ( new AtkListener(pWrap) ) );
+ else
+ OSL_ASSERT( false );
+ }
+
+ return ATK_OBJECT( pWrap );
+ }
+ catch (const uno::Exception &e)
+ {
+ if( pWrap )
+ g_object_unref( pWrap );
+
+ return NULL;
+ }
+}
+
+
+/*****************************************************************************/
+
+void atk_object_wrapper_add_child(AtkObjectWrapper* wrapper, AtkObject *child, gint index)
+{
+ AtkObject *atk_obj = ATK_OBJECT( wrapper );
+
+ atk_object_set_parent( child, atk_obj );
+ g_signal_emit_by_name( atk_obj, "children_changed::add", index, child, NULL );
+}
+
+/*****************************************************************************/
+
+void atk_object_wrapper_remove_child(AtkObjectWrapper* wrapper, AtkObject *child, gint index)
+{
+ /*
+ * the atk-bridge GTK+ module get's back to the event source to ref the child just
+ * vanishing, so we keep this reference because the semantic on OOo side is different.
+ */
+ wrapper->child_about_to_be_removed = child;
+ wrapper->index_of_child_about_to_be_removed = index;
+
+ g_signal_emit_by_name( ATK_OBJECT( wrapper ), "children_changed::remove", index, child, NULL );
+
+ wrapper->index_of_child_about_to_be_removed = -1;
+ wrapper->child_about_to_be_removed = NULL;
+}
+
+/*****************************************************************************/
+
+#define RELEASE(i) if( i ) { i->release(); i = NULL; }
+
+void atk_object_wrapper_dispose(AtkObjectWrapper* wrapper)
+{
+ RELEASE( wrapper->mpContext )
+ RELEASE( wrapper->mpAction )
+ RELEASE( wrapper->mpComponent )
+ RELEASE( wrapper->mpEditableText )
+ RELEASE( wrapper->mpHypertext )
+ RELEASE( wrapper->mpImage )
+ RELEASE( wrapper->mpSelection )
+ RELEASE( wrapper->mpMultiLineText )
+ RELEASE( wrapper->mpTable )
+ RELEASE( wrapper->mpText )
+ RELEASE( wrapper->mpTextMarkup )
+ RELEASE( wrapper->mpTextAttributes )
+ RELEASE( wrapper->mpValue )
+}
diff --git a/vcl/unx/gtk/a11y/atkwrapper.hxx b/vcl/unx/gtk/a11y/atkwrapper.hxx
new file mode 100644
index 000000000000..4252c0404833
--- /dev/null
+++ b/vcl/unx/gtk/a11y/atkwrapper.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef __ATK_WRAPPER_HXX__
+#define __ATK_WRAPPER_HXX__
+
+#include <atk/atk.h>
+#include <com/sun/star/accessibility/XAccessible.hpp>
+
+extern "C" {
+
+typedef struct _AtkObjectWrapper AtkObjectWrapper;
+typedef struct _AtkObjectWrapperClass AtkObjectWrapperClass;
+
+namespace com { namespace sun { namespace star { namespace accessibility {
+ class XAccessibleAction;
+ class XAccessibleComponent;
+ class XAccessibleEditableText;
+ class XAccessibleHypertext;
+ class XAccessibleImage;
+ class XAccessibleMultiLineText;
+ class XAccessibleSelection;
+ class XAccessibleTable;
+ class XAccessibleText;
+ class XAccessibleTextMarkup;
+ class XAccessibleTextAttributes;
+ class XAccessibleValue;
+} } } }
+
+
+struct _AtkObjectWrapper
+{
+ AtkObject aParent;
+
+ ::com::sun::star::accessibility::XAccessible *mpAccessible;
+ ::com::sun::star::accessibility::XAccessibleContext *mpContext;
+ ::com::sun::star::accessibility::XAccessibleAction *mpAction;
+ ::com::sun::star::accessibility::XAccessibleComponent *mpComponent;
+ ::com::sun::star::accessibility::XAccessibleEditableText *mpEditableText;
+ ::com::sun::star::accessibility::XAccessibleHypertext *mpHypertext;
+ ::com::sun::star::accessibility::XAccessibleImage *mpImage;
+ ::com::sun::star::accessibility::XAccessibleMultiLineText *mpMultiLineText;
+ ::com::sun::star::accessibility::XAccessibleSelection *mpSelection;
+ ::com::sun::star::accessibility::XAccessibleTable *mpTable;
+ ::com::sun::star::accessibility::XAccessibleText *mpText;
+ ::com::sun::star::accessibility::XAccessibleTextMarkup *mpTextMarkup;
+ ::com::sun::star::accessibility::XAccessibleTextAttributes *mpTextAttributes;
+ ::com::sun::star::accessibility::XAccessibleValue *mpValue;
+
+ AtkObject *child_about_to_be_removed;
+ gint index_of_child_about_to_be_removed;
+// ::rtl::OString * m_pKeyBindings
+};
+
+struct _AtkObjectWrapperClass
+{
+ AtkObjectClass aParentClass;
+};
+
+GType atk_object_wrapper_get_type (void) G_GNUC_CONST;
+AtkObject * atk_object_wrapper_ref(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& rxAccessible,
+ bool create = true );
+
+AtkObject * atk_object_wrapper_new(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& rxAccessible,
+ AtkObject* parent = NULL );
+
+void atk_object_wrapper_add_child(AtkObjectWrapper* wrapper, AtkObject *child, gint index);
+void atk_object_wrapper_remove_child(AtkObjectWrapper* wrapper, AtkObject *child, gint index);
+
+void atk_object_wrapper_dispose(AtkObjectWrapper* wrapper);
+
+AtkStateType mapAtkState( sal_Int16 nState );
+
+void actionIfaceInit(AtkActionIface *iface);
+void componentIfaceInit(AtkComponentIface *iface);
+void editableTextIfaceInit(AtkEditableTextIface *iface);
+void hypertextIfaceInit(AtkHypertextIface *iface);
+void imageIfaceInit(AtkImageIface *iface);
+void selectionIfaceInit(AtkSelectionIface *iface);
+void tableIfaceInit(AtkTableIface *iface);
+void textIfaceInit(AtkTextIface *iface);
+void valueIfaceInit(AtkValueIface *iface);
+
+} // extern "C"
+
+#define ATK_TYPE_OBJECT_WRAPPER atk_object_wrapper_get_type()
+#define ATK_OBJECT_WRAPPER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), ATK_TYPE_OBJECT_WRAPPER, AtkObjectWrapper))
+
+static inline gchar *
+OUStringToGChar(const rtl::OUString& rString )
+{
+ rtl::OString aUtf8 = rtl::OUStringToOString( rString, RTL_TEXTENCODING_UTF8 );
+ return g_strdup( aUtf8 );
+}
+
+#define OUStringToConstGChar( string ) rtl::OUStringToOString( string, RTL_TEXTENCODING_UTF8 ).getStr()
+
+#endif /* __ATK_WRAPPER_HXX__ */
diff --git a/vcl/unx/gtk/a11y/makefile.mk b/vcl/unx/gtk/a11y/makefile.mk
new file mode 100644
index 000000000000..14d3014ddf11
--- /dev/null
+++ b/vcl/unx/gtk/a11y/makefile.mk
@@ -0,0 +1,93 @@
+#*************************************************************************
+#
+# 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=gtka11y
+ENABLE_EXCEPTIONS=TRUE
+
+# workaround for makedepend hang
+MKDEPENDSOLVER=
+NO_DEFAULT_STL=YES
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)"!="unx"
+
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+
+.ELSE # "$(GUIBASE)"!="unx"
+
+.IF "$(ENABLE_GTK)" != ""
+
+PKGCONFIG_MODULES=gtk+-2.0
+.INCLUDE : pkg_config.mk
+
+CFLAGS+=-DVERSION=$(EMQ)"$(UPD)$(LAST_MINOR)$(EMQ)"
+
+ATKVERSION:=$(shell @$(PKG_CONFIG) --modversion atk | $(AWK) -v num=true -f $(SOLARENV)$/bin$/getcompver.awk)
+
+.IF "$(ATKVERSION)" >= "000100070000"
+CFLAGS+=-DHAS_ATKRECTANGLE
+.ENDIF
+
+SLOFILES=\
+ $(SLO)$/atkaction.obj \
+ $(SLO)$/atkbridge.obj \
+ $(SLO)$/atkcomponent.obj \
+ $(SLO)$/atkeditabletext.obj \
+ $(SLO)$/atkfactory.obj \
+ $(SLO)$/atkhypertext.obj \
+ $(SLO)$/atkimage.obj \
+ $(SLO)$/atklistener.obj \
+ $(SLO)$/atkregistry.obj \
+ $(SLO)$/atkselection.obj \
+ $(SLO)$/atktable.obj \
+ $(SLO)$/atktext.obj \
+ $(SLO)$/atktextattributes.obj \
+ $(SLO)$/atkutil.obj \
+ $(SLO)$/atkvalue.obj \
+ $(SLO)$/atkwindow.obj \
+ $(SLO)$/atkwrapper.obj
+
+.ELSE # "$(ENABLE_GTK)" != ""
+
+dummy:
+ @echo GTK disabled - nothing to build
+.ENDIF
+.ENDIF # "$(GUIBASE)"!="unx"
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
diff --git a/vcl/unx/gtk/app/gtkdata.cxx b/vcl/unx/gtk/app/gtkdata.cxx
new file mode 100644
index 000000000000..2679f4a29c02
--- /dev/null
+++ b/vcl/unx/gtk/app/gtkdata.cxx
@@ -0,0 +1,988 @@
+/*************************************************************************
+ *
+ * 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 _SV_SALDATA_CXX
+
+// -=-= #includes =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <errno.h>
+#include <poll.h>
+#ifdef FREEBSD
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#endif
+#include <plugins/gtk/gtkdata.hxx>
+#include <plugins/gtk/gtkinst.hxx>
+#include <plugins/gtk/gtkframe.hxx>
+#include <salobj.h>
+#include <osl/thread.h>
+#include <osl/process.h>
+
+#include <tools/debug.hxx>
+#include "i18n_im.hxx"
+#include "i18n_xkb.hxx"
+#include <wmadaptor.hxx>
+
+#include "../../unx/source/inc/salcursors.h"
+
+#include <vcl/svapp.hxx>
+
+using namespace rtl;
+using namespace vcl_sal;
+
+/***************************************************************************
+ * class GtkDisplay *
+ ***************************************************************************/
+
+GtkSalDisplay::GtkSalDisplay( GdkDisplay* pDisplay )
+ : SalDisplay( gdk_x11_display_get_xdisplay( pDisplay ) ),
+ m_pGdkDisplay( pDisplay ),
+ m_bStartupCompleted( false )
+{
+ m_bUseRandRWrapper = false; // use gdk signal instead
+ for(int i = 0; i < POINTER_COUNT; i++)
+ m_aCursors[ i ] = NULL;
+ Init ();
+}
+
+GtkSalDisplay::~GtkSalDisplay()
+{
+ if( !m_bStartupCompleted )
+ gdk_notify_startup_complete();
+ doDestruct();
+
+ for(int i = 0; i < POINTER_COUNT; i++)
+ if( m_aCursors[ i ] )
+ gdk_cursor_unref( m_aCursors[ i ] );
+
+ pDisp_ = NULL;
+}
+
+void GtkSalDisplay::deregisterFrame( SalFrame* pFrame )
+{
+ if( m_pCapture == pFrame )
+ {
+ static_cast<GtkSalFrame*>(m_pCapture)->grabPointer( FALSE );
+ m_pCapture = NULL;
+ }
+ SalDisplay::deregisterFrame( pFrame );
+}
+
+extern "C" {
+GdkFilterReturn call_filterGdkEvent( GdkXEvent* sys_event,
+ GdkEvent* event,
+ gpointer data )
+{
+ return GtkSalDisplay::filterGdkEvent( sys_event, event, data );
+}
+
+void signalKeysChanged( GdkKeymap*, gpointer data )
+{
+ GtkSalDisplay* pDisp = (GtkSalDisplay*)data;
+ pDisp->GetKeyboardName(TRUE);
+}
+
+void signalScreenSizeChanged( GdkScreen* pScreen, gpointer data )
+{
+ GtkSalDisplay* pDisp = (GtkSalDisplay*)data;
+ pDisp->screenSizeChanged( pScreen );
+}
+
+void signalMonitorsChanged( GdkScreen* pScreen, gpointer data )
+{
+ GtkSalDisplay* pDisp = (GtkSalDisplay*)data;
+ pDisp->monitorsChanged( pScreen );
+}
+
+}
+
+GdkFilterReturn GtkSalDisplay::filterGdkEvent( GdkXEvent* sys_event,
+ GdkEvent*,
+ gpointer data )
+{
+ GdkFilterReturn aFilterReturn = GDK_FILTER_CONTINUE;
+
+ XEvent *pEvent = (XEvent *)sys_event;
+ GtkSalDisplay *pDisplay = (GtkSalDisplay *)data;
+
+ // dispatch all XEvents to event callback
+ if( GetSalData()->m_pInstance->
+ CallEventCallback( pEvent, sizeof( XEvent ) ) )
+ aFilterReturn = GDK_FILTER_REMOVE;
+
+ GTK_YIELD_GRAB();
+
+ if (pDisplay->GetDisplay() == pEvent->xany.display )
+ {
+ // #i53471# gtk has no callback mechanism that lets us be notified
+ // when settings (as in XSETTING and opposed to styles) are changed.
+ // so we need to listen for corresponding property notifications here
+ // these should be rare enough so that we can assume that the settings
+ // actually change when a corresponding PropertyNotify occurs
+ if( pEvent->type == PropertyNotify &&
+ pEvent->xproperty.atom == pDisplay->getWMAdaptor()->getAtom( WMAdaptor::XSETTINGS ) &&
+ ! pDisplay->m_aFrames.empty()
+ )
+ {
+ pDisplay->SendInternalEvent( pDisplay->m_aFrames.front(), NULL, SALEVENT_SETTINGSCHANGED );
+ }
+ // let's see if one of our frames wants to swallow these events
+ // get the frame
+ for( std::list< SalFrame* >::const_iterator it = pDisplay->m_aFrames.begin();
+ it != pDisplay->m_aFrames.end(); ++it )
+ {
+ GtkSalFrame* pFrame = static_cast<GtkSalFrame*>(*it);
+ if( (GdkNativeWindow)pFrame->GetSystemData()->aWindow == pEvent->xany.window ||
+ ( pFrame->getForeignParent() && pFrame->getForeignParentWindow() == pEvent->xany.window ) ||
+ ( pFrame->getForeignTopLevel() && pFrame->getForeignTopLevelWindow() == pEvent->xany.window )
+ )
+ {
+ if( ! pFrame->Dispatch( pEvent ) )
+ aFilterReturn = GDK_FILTER_REMOVE;
+ break;
+ }
+ }
+ X11SalObject::Dispatch( pEvent );
+ }
+
+ return aFilterReturn;
+}
+
+void GtkSalDisplay::screenSizeChanged( GdkScreen* pScreen )
+{
+ if( pScreen )
+ {
+ int nScreen = gdk_screen_get_number( pScreen );
+ if( nScreen < static_cast<int>(m_aScreens.size()) )
+ {
+ ScreenData& rSD = const_cast<ScreenData&>(m_aScreens[nScreen]);
+ if( rSD.m_bInit )
+ {
+ rSD.m_aSize = Size( gdk_screen_get_width( pScreen ),
+ gdk_screen_get_height( pScreen ) );
+ if( ! m_aFrames.empty() )
+ m_aFrames.front()->CallCallback( SALEVENT_DISPLAYCHANGED, 0 );
+ }
+ }
+ else
+ {
+ DBG_ERROR( "unknown screen changed size" );
+ }
+ }
+}
+
+void GtkSalDisplay::monitorsChanged( GdkScreen* pScreen )
+{
+ if( pScreen )
+ {
+ if( gdk_display_get_n_screens(m_pGdkDisplay) == 1 )
+ {
+ int nScreen = gdk_screen_get_number( pScreen );
+ if( nScreen == m_nDefaultScreen ) //To-Do, make m_aXineramaScreens a per-screen thing ?
+ {
+ gint nMonitors = gdk_screen_get_n_monitors(pScreen);
+ m_aXineramaScreens = std::vector<Rectangle>();
+ for (gint i = 0; i < nMonitors; ++i)
+ {
+ GdkRectangle dest;
+ gdk_screen_get_monitor_geometry(pScreen, i, &dest);
+ addXineramaScreenUnique( dest.x, dest.y, dest.width, dest.height );
+ }
+ m_bXinerama = m_aXineramaScreens.size() > 1;
+ if( ! m_aFrames.empty() )
+ m_aFrames.front()->CallCallback( SALEVENT_DISPLAYCHANGED, 0 );
+ }
+ else
+ {
+ DBG_ERROR( "monitors for non-default screen changed, extend-me" );
+ }
+ }
+ }
+}
+
+void GtkSalDisplay::initScreen( int nScreen ) const
+{
+ if( nScreen < 0 || nScreen >= static_cast<int>(m_aScreens.size()) )
+ nScreen = m_nDefaultScreen;
+ ScreenData& rSD = const_cast<ScreenData&>(m_aScreens[nScreen]);
+ if( rSD.m_bInit )
+ return;
+
+ // choose visual for screen
+ SalDisplay::initScreen( nScreen );
+ // now set a gdk default colormap matching the chosen visual to the screen
+ GdkVisual* pVis = gdkx_visual_get( rSD.m_aVisual.visualid );
+ GdkScreen* pScreen = gdk_display_get_screen( m_pGdkDisplay, nScreen );
+ if( pVis )
+ {
+ GdkColormap* pDefCol = gdk_screen_get_default_colormap( pScreen );
+ GdkVisual* pDefVis = gdk_colormap_get_visual( pDefCol );
+ if( pDefVis != pVis )
+ {
+ pDefCol = gdk_x11_colormap_foreign_new( pVis, rSD.m_aColormap.GetXColormap() );
+ gdk_screen_set_default_colormap( pScreen, pDefCol );
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "set new gdk color map for screen %d\n", nScreen );
+ #endif
+ }
+ }
+ #if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "not GdkVisual for visual id %d\n", (int)rSD.m_aVisual.visualid );
+ #endif
+}
+
+long GtkSalDisplay::Dispatch( XEvent* pEvent )
+{
+ if( GetDisplay() == pEvent->xany.display )
+ {
+ // let's see if one of our frames wants to swallow these events
+ // get the child frame
+ for( std::list< SalFrame* >::const_iterator it = m_aFrames.begin();
+ it != m_aFrames.end(); ++it )
+ {
+ if( (GdkNativeWindow)(*it)->GetSystemData()->aWindow == pEvent->xany.window )
+ return static_cast<GtkSalFrame*>(*it)->Dispatch( pEvent );
+ }
+ }
+
+ return GDK_FILTER_CONTINUE;
+}
+
+GdkCursor* GtkSalDisplay::getFromXPM( const char *pBitmap,
+ const char *pMask,
+ int nWidth, int nHeight,
+ int nXHot, int nYHot )
+{
+ GdkScreen *pScreen = gdk_display_get_default_screen( m_pGdkDisplay );
+ GdkDrawable *pDrawable = GDK_DRAWABLE( gdk_screen_get_root_window (pScreen) );
+ GdkBitmap *pBitmapPix = gdk_bitmap_create_from_data
+ ( pDrawable, pBitmap, nWidth, nHeight );
+ GdkBitmap *pMaskPix = gdk_bitmap_create_from_data
+ ( pDrawable, pMask, nWidth, nHeight );
+ GdkColormap *pColormap = gdk_drawable_get_colormap( pDrawable );
+
+ GdkColor aWhite = { 0, 0xffff, 0xffff, 0xffff };
+ GdkColor aBlack = { 0, 0, 0, 0 };
+
+ gdk_colormap_alloc_color( pColormap, &aBlack, FALSE, TRUE);
+ gdk_colormap_alloc_color( pColormap, &aWhite, FALSE, TRUE);
+
+ return gdk_cursor_new_from_pixmap
+ ( pBitmapPix, pMaskPix,
+ &aBlack, &aWhite, nXHot, nYHot);
+}
+
+#define MAKE_CURSOR( vcl_name, name ) \
+ case vcl_name: \
+ pCursor = getFromXPM( name##curs##_bits, name##mask##_bits, \
+ name##curs_width, name##curs_height, \
+ name##curs_x_hot, name##curs_y_hot ); \
+ break
+#define MAP_BUILTIN( vcl_name, gdk_name ) \
+ case vcl_name: \
+ pCursor = gdk_cursor_new_for_display( m_pGdkDisplay, gdk_name ); \
+ break
+
+GdkCursor *GtkSalDisplay::getCursor( PointerStyle ePointerStyle )
+{
+ if( ePointerStyle > POINTER_COUNT )
+ return NULL;
+
+ if ( !m_aCursors[ ePointerStyle ] )
+ {
+ GdkCursor *pCursor = NULL;
+
+ switch( ePointerStyle )
+ {
+ MAP_BUILTIN( POINTER_ARROW, GDK_LEFT_PTR );
+ MAP_BUILTIN( POINTER_TEXT, GDK_XTERM );
+ MAP_BUILTIN( POINTER_HELP, GDK_QUESTION_ARROW );
+ MAP_BUILTIN( POINTER_CROSS, GDK_CROSSHAIR );
+ MAP_BUILTIN( POINTER_WAIT, GDK_WATCH );
+
+ MAP_BUILTIN( POINTER_NSIZE, GDK_SB_V_DOUBLE_ARROW );
+ MAP_BUILTIN( POINTER_SSIZE, GDK_SB_V_DOUBLE_ARROW );
+ MAP_BUILTIN( POINTER_WSIZE, GDK_SB_H_DOUBLE_ARROW );
+ MAP_BUILTIN( POINTER_ESIZE, GDK_SB_H_DOUBLE_ARROW );
+
+ MAP_BUILTIN( POINTER_NWSIZE, GDK_TOP_LEFT_CORNER );
+ MAP_BUILTIN( POINTER_NESIZE, GDK_TOP_RIGHT_CORNER );
+ MAP_BUILTIN( POINTER_SWSIZE, GDK_BOTTOM_LEFT_CORNER );
+ MAP_BUILTIN( POINTER_SESIZE, GDK_BOTTOM_RIGHT_CORNER );
+
+ MAP_BUILTIN( POINTER_WINDOW_NSIZE, GDK_TOP_SIDE );
+ MAP_BUILTIN( POINTER_WINDOW_SSIZE, GDK_BOTTOM_SIDE );
+ MAP_BUILTIN( POINTER_WINDOW_WSIZE, GDK_LEFT_SIDE );
+ MAP_BUILTIN( POINTER_WINDOW_ESIZE, GDK_RIGHT_SIDE );
+
+ MAP_BUILTIN( POINTER_WINDOW_NWSIZE, GDK_TOP_LEFT_CORNER );
+ MAP_BUILTIN( POINTER_WINDOW_NESIZE, GDK_TOP_RIGHT_CORNER );
+ MAP_BUILTIN( POINTER_WINDOW_SWSIZE, GDK_BOTTOM_LEFT_CORNER );
+ MAP_BUILTIN( POINTER_WINDOW_SESIZE, GDK_BOTTOM_RIGHT_CORNER );
+
+ MAP_BUILTIN( POINTER_HSIZEBAR, GDK_SB_H_DOUBLE_ARROW );
+ MAP_BUILTIN( POINTER_VSIZEBAR, GDK_SB_V_DOUBLE_ARROW );
+
+ MAP_BUILTIN( POINTER_REFHAND, GDK_HAND1 );
+ MAP_BUILTIN( POINTER_HAND, GDK_HAND2 );
+ MAP_BUILTIN( POINTER_PEN, GDK_PENCIL );
+
+ MAP_BUILTIN( POINTER_HSPLIT, GDK_SB_H_DOUBLE_ARROW );
+ MAP_BUILTIN( POINTER_VSPLIT, GDK_SB_V_DOUBLE_ARROW );
+
+ MAP_BUILTIN( POINTER_MOVE, GDK_FLEUR );
+
+ MAKE_CURSOR( POINTER_NULL, null );
+ MAKE_CURSOR( POINTER_MAGNIFY, magnify_ );
+ MAKE_CURSOR( POINTER_FILL, fill_ );
+ MAKE_CURSOR( POINTER_MOVEDATA, movedata_ );
+ MAKE_CURSOR( POINTER_COPYDATA, copydata_ );
+ MAKE_CURSOR( POINTER_MOVEFILE, movefile_ );
+ MAKE_CURSOR( POINTER_COPYFILE, copyfile_ );
+ MAKE_CURSOR( POINTER_MOVEFILES, movefiles_ );
+ MAKE_CURSOR( POINTER_COPYFILES, copyfiles_ );
+ MAKE_CURSOR( POINTER_NOTALLOWED, nodrop_ );
+ MAKE_CURSOR( POINTER_ROTATE, rotate_ );
+ MAKE_CURSOR( POINTER_HSHEAR, hshear_ );
+ MAKE_CURSOR( POINTER_VSHEAR, vshear_ );
+ MAKE_CURSOR( POINTER_DRAW_LINE, drawline_ );
+ MAKE_CURSOR( POINTER_DRAW_RECT, drawrect_ );
+ MAKE_CURSOR( POINTER_DRAW_POLYGON, drawpolygon_ );
+ MAKE_CURSOR( POINTER_DRAW_BEZIER, drawbezier_ );
+ MAKE_CURSOR( POINTER_DRAW_ARC, drawarc_ );
+ MAKE_CURSOR( POINTER_DRAW_PIE, drawpie_ );
+ MAKE_CURSOR( POINTER_DRAW_CIRCLECUT, drawcirclecut_ );
+ MAKE_CURSOR( POINTER_DRAW_ELLIPSE, drawellipse_ );
+ MAKE_CURSOR( POINTER_DRAW_CONNECT, drawconnect_ );
+ MAKE_CURSOR( POINTER_DRAW_TEXT, drawtext_ );
+ MAKE_CURSOR( POINTER_MIRROR, mirror_ );
+ MAKE_CURSOR( POINTER_CROOK, crook_ );
+ MAKE_CURSOR( POINTER_CROP, crop_ );
+ MAKE_CURSOR( POINTER_MOVEPOINT, movepoint_ );
+ MAKE_CURSOR( POINTER_MOVEBEZIERWEIGHT, movebezierweight_ );
+ MAKE_CURSOR( POINTER_DRAW_FREEHAND, drawfreehand_ );
+ MAKE_CURSOR( POINTER_DRAW_CAPTION, drawcaption_ );
+ MAKE_CURSOR( POINTER_LINKDATA, linkdata_ );
+ MAKE_CURSOR( POINTER_MOVEDATALINK, movedlnk_ );
+ MAKE_CURSOR( POINTER_COPYDATALINK, copydlnk_ );
+ MAKE_CURSOR( POINTER_LINKFILE, linkfile_ );
+ MAKE_CURSOR( POINTER_MOVEFILELINK, moveflnk_ );
+ MAKE_CURSOR( POINTER_COPYFILELINK, copyflnk_ );
+ MAKE_CURSOR( POINTER_CHART, chart_ );
+ MAKE_CURSOR( POINTER_DETECTIVE, detective_ );
+ MAKE_CURSOR( POINTER_PIVOT_COL, pivotcol_ );
+ MAKE_CURSOR( POINTER_PIVOT_ROW, pivotrow_ );
+ MAKE_CURSOR( POINTER_PIVOT_FIELD, pivotfld_ );
+ MAKE_CURSOR( POINTER_PIVOT_DELETE, pivotdel_ );
+ MAKE_CURSOR( POINTER_CHAIN, chain_ );
+ MAKE_CURSOR( POINTER_CHAIN_NOTALLOWED, chainnot_ );
+ MAKE_CURSOR( POINTER_TIMEEVENT_MOVE, timemove_ );
+ MAKE_CURSOR( POINTER_TIMEEVENT_SIZE, timesize_ );
+ MAKE_CURSOR( POINTER_AUTOSCROLL_N, asn_ );
+ MAKE_CURSOR( POINTER_AUTOSCROLL_S, ass_ );
+ MAKE_CURSOR( POINTER_AUTOSCROLL_W, asw_ );
+ MAKE_CURSOR( POINTER_AUTOSCROLL_E, ase_ );
+ MAKE_CURSOR( POINTER_AUTOSCROLL_NW, asnw_ );
+ MAKE_CURSOR( POINTER_AUTOSCROLL_NE, asne_ );
+ MAKE_CURSOR( POINTER_AUTOSCROLL_SW, assw_ );
+ MAKE_CURSOR( POINTER_AUTOSCROLL_SE, asse_ );
+ MAKE_CURSOR( POINTER_AUTOSCROLL_NS, asns_ );
+ MAKE_CURSOR( POINTER_AUTOSCROLL_WE, aswe_ );
+ MAKE_CURSOR( POINTER_AUTOSCROLL_NSWE, asnswe_ );
+ MAKE_CURSOR( POINTER_AIRBRUSH, airbrush_ );
+ MAKE_CURSOR( POINTER_TEXT_VERTICAL, vertcurs_ );
+
+ // --> FME 2004-07-30 #i32329# Enhanced table selection
+ MAKE_CURSOR( POINTER_TAB_SELECT_S, tblsels_ );
+ MAKE_CURSOR( POINTER_TAB_SELECT_E, tblsele_ );
+ MAKE_CURSOR( POINTER_TAB_SELECT_SE, tblselse_ );
+ MAKE_CURSOR( POINTER_TAB_SELECT_W, tblselw_ );
+ MAKE_CURSOR( POINTER_TAB_SELECT_SW, tblselsw_ );
+ // <--
+
+ // --> FME 2004-08-16 #i20119# Paintbrush tool
+ MAKE_CURSOR( POINTER_PAINTBRUSH, paintbrush_ );
+ // <--
+
+ default:
+ fprintf( stderr, "pointer %d not implemented", ePointerStyle );
+ break;
+ }
+ if( !pCursor )
+ pCursor = gdk_cursor_new_for_display( m_pGdkDisplay, GDK_LEFT_PTR );
+
+ m_aCursors[ ePointerStyle ] = pCursor;
+ }
+
+ return m_aCursors[ ePointerStyle ];
+}
+
+int GtkSalDisplay::CaptureMouse( SalFrame* pSFrame )
+{
+ GtkSalFrame* pFrame = static_cast<GtkSalFrame*>(pSFrame);
+
+ if( !pFrame )
+ {
+ if( m_pCapture )
+ static_cast<GtkSalFrame*>(m_pCapture)->grabPointer( FALSE );
+ m_pCapture = NULL;
+ return 0;
+ }
+
+ if( m_pCapture )
+ {
+ if( pFrame == m_pCapture )
+ return 1;
+ static_cast<GtkSalFrame*>(m_pCapture)->grabPointer( FALSE );
+ }
+
+ m_pCapture = pFrame;
+ static_cast<GtkSalFrame*>(pFrame)->grabPointer( TRUE );
+ return 1;
+}
+
+/***************************************************************************
+ * class GtkXLib *
+ ***************************************************************************/
+
+class GtkXLib : public SalXLib
+{
+ GtkSalDisplay *m_pGtkSalDisplay;
+ std::list<GSource *> m_aSources;
+ GSource *m_pTimeout;
+ GSource *m_pUserEvent;
+ oslMutex m_aDispatchMutex;
+ oslCondition m_aDispatchCondition;
+
+public:
+ static gboolean timeoutFn(gpointer data);
+ static gboolean userEventFn(gpointer data);
+
+ GtkXLib();
+ virtual ~GtkXLib();
+
+ virtual void Init();
+ virtual void Yield( bool bWait, bool bHandleAllCurrentEvents );
+ virtual void Insert( int fd, void* data,
+ YieldFunc pending,
+ YieldFunc queued,
+ YieldFunc handle );
+ virtual void Remove( int fd );
+
+ virtual void StartTimer( ULONG nMS );
+ virtual void StopTimer();
+ virtual void Wakeup();
+ virtual void PostUserEvent();
+};
+
+GtkXLib::GtkXLib()
+{
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "GtkXLib::GtkXLib()\n" );
+#endif
+ m_pGtkSalDisplay = NULL;
+ m_pTimeout = NULL;
+ m_nTimeoutMS = 0;
+ m_pUserEvent = NULL;
+ m_aDispatchCondition = osl_createCondition();
+ m_aDispatchMutex = osl_createMutex();
+}
+
+GtkXLib::~GtkXLib()
+{
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "GtkXLib::~GtkXLib()\n" );
+#endif
+ StopTimer();
+ // sanity check: at this point nobody should be yielding, but wake them
+ // up anyway before the condition they're waiting on gets destroyed.
+ osl_setCondition( m_aDispatchCondition );
+ osl_destroyCondition( m_aDispatchCondition );
+ osl_destroyMutex( m_aDispatchMutex );
+}
+
+void GtkXLib::Init()
+{
+ int i;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "GtkXLib::Init()\n" );
+#endif
+ XrmInitialize();
+
+ gtk_set_locale();
+
+ /*
+ * open connection to X11 Display
+ * try in this order:
+ * o -display command line parameter,
+ * o $DISPLAY environment variable
+ * o default display
+ */
+
+ GdkDisplay *pGdkDisp = NULL;
+
+ // is there a -display command line parameter?
+ rtl_TextEncoding aEnc = osl_getThreadTextEncoding();
+ int nParams = osl_getCommandArgCount();
+ rtl::OString aDisplay;
+ rtl::OUString aParam, aBin;
+ char** pCmdLineAry = new char*[ nParams+1 ];
+ osl_getExecutableFile( &aParam.pData );
+ osl_getSystemPathFromFileURL( aParam.pData, &aBin.pData );
+ pCmdLineAry[0] = g_strdup( OUStringToOString( aBin, aEnc ).getStr() );
+ for (i=0; i<nParams; i++)
+ {
+ osl_getCommandArg(i, &aParam.pData );
+ OString aBParam( OUStringToOString( aParam, aEnc ) );
+
+ if( aParam.equalsAscii( "-display" ) || aParam.equalsAscii( "--display" ) )
+ {
+ pCmdLineAry[i+1] = g_strdup( "--display" );
+ osl_getCommandArg(i+1, &aParam.pData );
+ aDisplay = rtl::OUStringToOString( aParam, aEnc );
+ }
+ else
+ pCmdLineAry[i+1] = g_strdup( aBParam.getStr() );
+ }
+ // add executable
+ nParams++;
+
+ g_set_application_name(X11SalData::getFrameClassName());
+
+ // Set consistant name of the root accessible
+ rtl::OUString aAppName = Application::GetAppName();
+ if( aAppName.getLength() > 0 )
+ {
+ rtl::OString aPrgName = rtl::OUStringToOString(aAppName, aEnc);
+ g_set_prgname(aPrgName);
+ }
+
+ // init gtk/gdk
+ gtk_init_check( &nParams, &pCmdLineAry );
+
+ for (i = 0; i < nParams; i++ )
+ g_free( pCmdLineAry[i] );
+ delete [] pCmdLineAry;
+
+#if OSL_DEBUG_LEVEL > 1
+ if (g_getenv ("SAL_DEBUG_UPDATES"))
+ gdk_window_set_debug_updates (TRUE);
+#endif
+
+ pGdkDisp = gdk_display_get_default();
+ if ( !pGdkDisp )
+ {
+ rtl::OUString aProgramFileURL;
+ osl_getExecutableFile( &aProgramFileURL.pData );
+ rtl::OUString aProgramSystemPath;
+ osl_getSystemPathFromFileURL (aProgramFileURL.pData, &aProgramSystemPath.pData);
+ rtl::OString aProgramName = rtl::OUStringToOString(
+ aProgramSystemPath,
+ osl_getThreadTextEncoding() );
+ fprintf( stderr, "%s X11 error: Can't open display: %s\n",
+ aProgramName.getStr(), aDisplay.getStr());
+ fprintf( stderr, " Set DISPLAY environment variable, use -display option\n");
+ fprintf( stderr, " or check permissions of your X-Server\n");
+ fprintf( stderr, " (See \"man X\" resp. \"man xhost\" for details)\n");
+ fflush( stderr );
+ exit(0);
+ }
+
+ /*
+ * if a -display switch was used, we need
+ * to set the environment accoringly since
+ * the clipboard build another connection
+ * to the xserver using $DISPLAY
+ */
+ char *pPutEnvIsBroken = g_strdup_printf( "DISPLAY=%s",
+ gdk_display_get_name( pGdkDisp ) );
+ putenv( pPutEnvIsBroken );
+
+ Display *pDisp = gdk_x11_display_get_xdisplay( pGdkDisp );
+
+ m_pGtkSalDisplay = new GtkSalDisplay( pGdkDisp );
+
+ gdk_window_add_filter( NULL, call_filterGdkEvent, m_pGtkSalDisplay );
+
+ PushXErrorLevel( true );
+ SalI18N_KeyboardExtension *pKbdExtension = new SalI18N_KeyboardExtension( pDisp );
+ XSync( pDisp, False );
+
+ pKbdExtension->UseExtension( ! HasXErrorOccured() );
+ PopXErrorLevel();
+
+ m_pGtkSalDisplay->SetKbdExtension( pKbdExtension );
+
+ g_signal_connect( G_OBJECT(gdk_keymap_get_default()), "keys_changed", G_CALLBACK(signalKeysChanged), m_pGtkSalDisplay );
+
+ // add signal handler to notify screen size changes
+ int nScreens = gdk_display_get_n_screens( pGdkDisp );
+ for( int n = 0; n < nScreens; n++ )
+ {
+ GdkScreen *pScreen = gdk_display_get_screen( pGdkDisp, n );
+ if( pScreen )
+ {
+ g_signal_connect( G_OBJECT(pScreen), "size-changed", G_CALLBACK(signalScreenSizeChanged), m_pGtkSalDisplay );
+ if( ! gtk_check_version( 2, 14, 0 ) ) // monitors-changed came in with 2.14, avoid an assertion
+ g_signal_connect( G_OBJECT(pScreen), "monitors-changed", G_CALLBACK(signalMonitorsChanged), m_pGtkSalDisplay );
+ }
+ }
+}
+
+extern "C"
+{
+ gboolean call_timeoutFn(gpointer data)
+ {
+ return GtkXLib::timeoutFn(data);
+ }
+}
+
+gboolean GtkXLib::timeoutFn(gpointer data)
+{
+ SalData *pSalData = GetSalData();
+ GtkXLib *pThis = (GtkXLib *) data;
+
+ pSalData->m_pInstance->GetYieldMutex()->acquire();
+
+ if( pThis->m_pTimeout )
+ {
+ g_source_unref (pThis->m_pTimeout);
+ pThis->m_pTimeout = NULL;
+ }
+
+ // Auto-restart immediately
+ pThis->StartTimer( pThis->m_nTimeoutMS );
+
+ GetX11SalData()->Timeout();
+
+ pSalData->m_pInstance->GetYieldMutex()->release();
+
+ return FALSE;
+}
+
+void GtkXLib::StartTimer( ULONG nMS )
+{
+ m_nTimeoutMS = nMS; // for restarting
+
+ if (m_pTimeout)
+ {
+ g_source_destroy (m_pTimeout);
+ g_source_unref (m_pTimeout);
+ }
+
+ m_pTimeout = g_timeout_source_new (m_nTimeoutMS);
+ // #i36226# timers should be executed with lower priority
+ // than XEvents like in generic plugin
+ g_source_set_priority( m_pTimeout, G_PRIORITY_LOW );
+ g_source_set_can_recurse (m_pTimeout, TRUE);
+ g_source_set_callback (m_pTimeout, call_timeoutFn,
+ (gpointer) this, NULL);
+ g_source_attach (m_pTimeout, g_main_context_default ());
+
+ SalXLib::StartTimer( nMS );
+}
+
+void GtkXLib::StopTimer()
+{
+ SalXLib::StopTimer();
+
+ if (m_pTimeout)
+ {
+ g_source_destroy (m_pTimeout);
+ g_source_unref (m_pTimeout);
+ m_pTimeout = NULL;
+ }
+}
+
+extern "C"
+{
+ gboolean call_userEventFn( gpointer data )
+ {
+ return GtkXLib::userEventFn( data );
+ }
+}
+
+gboolean GtkXLib::userEventFn(gpointer data)
+{
+ gboolean bContinue;
+ GtkXLib *pThis = (GtkXLib *) data;
+ SalData *pSalData = GetSalData();
+
+ pSalData->m_pInstance->GetYieldMutex()->acquire();
+ pThis->m_pGtkSalDisplay->EventGuardAcquire();
+
+ if( !pThis->m_pGtkSalDisplay->HasMoreEvents() )
+ {
+ if( pThis->m_pUserEvent )
+ {
+ g_source_unref (pThis->m_pUserEvent);
+ pThis->m_pUserEvent = NULL;
+ }
+ bContinue = FALSE;
+ }
+ else
+ bContinue = TRUE;
+
+ pThis->m_pGtkSalDisplay->EventGuardRelease();
+
+ pThis->m_pGtkSalDisplay->DispatchInternalEvent();
+
+ pSalData->m_pInstance->GetYieldMutex()->release();
+
+ return bContinue;
+}
+
+// hEventGuard_ held during this invocation
+void GtkXLib::PostUserEvent()
+{
+ if( !m_pUserEvent ) // not pending anyway
+ {
+ m_pUserEvent = g_idle_source_new();
+ g_source_set_priority( m_pUserEvent, G_PRIORITY_HIGH );
+ g_source_set_can_recurse (m_pUserEvent, TRUE);
+ g_source_set_callback (m_pUserEvent, call_userEventFn,
+ (gpointer) this, NULL);
+ g_source_attach (m_pUserEvent, g_main_context_default ());
+ }
+ Wakeup();
+}
+
+void GtkXLib::Wakeup()
+{
+ g_main_context_wakeup( g_main_context_default () );
+}
+
+void GtkXLib::Yield( bool bWait, bool bHandleAllCurrentEvents )
+{
+ /* #i33212# only enter g_main_context_iteration in one thread at any one
+ * time, else one of them potentially will never end as long as there is
+ * another thread in in there. Having only one yieldin thread actually dispatch
+ * fits the vcl event model (see e.g. the generic plugin).
+ */
+
+ bool bDispatchThread = false;
+ gboolean wasEvent = FALSE;
+ {
+ // release YieldMutex (and re-acquire at block end)
+ YieldMutexReleaser aReleaser;
+ if( osl_tryToAcquireMutex( m_aDispatchMutex ) )
+ bDispatchThread = true;
+ else if( ! bWait )
+ return; // someone else is waiting already, return
+
+
+ if( bDispatchThread )
+ {
+ int nMaxEvents = bHandleAllCurrentEvents ? 100 : 1;
+ gboolean wasOneEvent = TRUE;
+ while( nMaxEvents-- && wasOneEvent )
+ {
+ wasOneEvent = g_main_context_iteration( NULL, FALSE );
+ if( wasOneEvent )
+ wasEvent = TRUE;
+ }
+ if( bWait && ! wasEvent )
+ wasEvent = g_main_context_iteration( NULL, TRUE );
+ }
+ else if( bWait )
+ {
+ /* #i41693# in case the dispatch thread hangs in join
+ * for this thread the condition will never be set
+ * workaround: timeout of 1 second a emergency exit
+ */
+ // we are the dispatch thread
+ osl_resetCondition( m_aDispatchCondition );
+ TimeValue aValue = { 1, 0 };
+ osl_waitCondition( m_aDispatchCondition, &aValue );
+ }
+ }
+
+ if( bDispatchThread )
+ {
+ osl_releaseMutex( m_aDispatchMutex );
+ if( wasEvent )
+ osl_setCondition( m_aDispatchCondition ); // trigger non dispatch thread yields
+ }
+}
+
+extern "C" {
+
+typedef struct {
+ GSource source;
+
+ GPollFD pollfd;
+ GIOCondition condition;
+
+ YieldFunc pending;
+ YieldFunc handle;
+ gpointer user_data;
+} SalWatch;
+
+static gboolean
+sal_source_prepare (GSource *source,
+ gint *timeout)
+{
+ SalWatch *watch = (SalWatch *)source;
+
+ *timeout = -1;
+
+ if (watch->pending &&
+ watch->pending (watch->pollfd.fd, watch->user_data)) {
+ watch->pollfd.revents |= watch->condition;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+sal_source_check (GSource *source)
+{
+ SalWatch *watch = (SalWatch *)source;
+
+ return watch->pollfd.revents & watch->condition;
+}
+
+static gboolean
+sal_source_dispatch (GSource *source,
+ GSourceFunc,
+ gpointer)
+{
+ SalData *pSalData = GetSalData();
+ SalWatch *watch = (SalWatch *) source;
+
+ pSalData->m_pInstance->GetYieldMutex()->acquire();
+
+ watch->handle (watch->pollfd.fd, watch->user_data);
+
+ pSalData->m_pInstance->GetYieldMutex()->release();
+
+ return TRUE;
+}
+
+static void
+sal_source_finalize (GSource*)
+{
+}
+
+static GSourceFuncs sal_source_watch_funcs = {
+ sal_source_prepare,
+ sal_source_check,
+ sal_source_dispatch,
+ sal_source_finalize,
+ NULL,
+ NULL
+};
+
+static GSource *
+sal_source_create_watch (int fd,
+ GIOCondition condition,
+ YieldFunc pending,
+ YieldFunc handle,
+ gpointer user_data)
+{
+ GSource *source;
+ SalWatch *watch;
+ GMainContext *context = g_main_context_default ();
+
+ source = g_source_new (&sal_source_watch_funcs,
+ sizeof (SalWatch));
+ watch = (SalWatch *) source;
+
+ watch->pollfd.fd = fd;
+ watch->pollfd.events = condition;
+ watch->condition = condition;
+ watch->pending = pending;
+ watch->handle = handle;
+ watch->user_data = user_data;
+
+ g_source_set_can_recurse (source, TRUE);
+ g_source_add_poll (source, &watch->pollfd);
+ g_source_attach (source, context);
+
+ return source;
+}
+
+} // extern "C"
+
+void GtkXLib::Insert( int nFD,
+ void *data,
+ YieldFunc pending,
+ YieldFunc,
+ YieldFunc handle )
+{
+ GSource *source = sal_source_create_watch
+ ( nFD, (GIOCondition) ((G_IO_IN|G_IO_PRI) |
+ (G_IO_ERR|G_IO_HUP|G_IO_NVAL)),
+ pending, handle, data );
+ m_aSources.push_back( source );
+}
+
+void GtkXLib::Remove( int nFD )
+{
+ ::std::list< GSource * >::iterator it;
+
+ for (it = m_aSources.begin(); it != m_aSources.end(); ++it)
+ {
+ SalWatch *watch = (SalWatch *) *it;
+
+ if (watch->pollfd.fd == nFD)
+ {
+ m_aSources.erase( it );
+
+ g_source_destroy ((GSource *)watch);
+ g_source_unref ((GSource *)watch);
+ return;
+ }
+ }
+}
+
+/**********************************************************************
+ * class GtkData *
+ **********************************************************************/
+
+GtkData::~GtkData()
+{
+}
+
+void GtkData::Init()
+{
+ pXLib_ = new GtkXLib();
+ pXLib_->Init();
+}
diff --git a/vcl/unx/gtk/app/gtkinst.cxx b/vcl/unx/gtk/app/gtkinst.cxx
new file mode 100644
index 000000000000..68617c8c16be
--- /dev/null
+++ b/vcl/unx/gtk/app/gtkinst.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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <osl/module.h>
+#include <plugins/gtk/gtkdata.hxx>
+#include <plugins/gtk/gtkinst.hxx>
+#include <salframe.h>
+#include <salobj.h>
+#include <plugins/gtk/gtkframe.hxx>
+#include <plugins/gtk/gtkobject.hxx>
+#include <plugins/gtk/atkbridge.hxx>
+
+#include <rtl/strbuf.hxx>
+
+#if OSL_DEBUG_LEVEL > 1
+#include <stdio.h>
+#endif
+
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+GtkHookedYieldMutex::GtkHookedYieldMutex()
+{
+}
+
+/*
+ * These methods always occur in pairs
+ * A ThreadsEnter is followed by a ThreadsLeave
+ * We need to queue up the recursive lock count
+ * for each pair, so we can accurately restore
+ * it later.
+ */
+void GtkHookedYieldMutex::ThreadsEnter()
+{
+ acquire();
+ if( !aYieldStack.empty() )
+ { /* Previously called ThreadsLeave() */
+ ULONG nCount = aYieldStack.front();
+ aYieldStack.pop_front();
+ while( nCount-- > 1 )
+ acquire();
+ }
+}
+
+void GtkHookedYieldMutex::ThreadsLeave()
+{
+ aYieldStack.push_front( mnCount );
+
+#if OSL_DEBUG_LEVEL > 1
+ if( mnThreadId &&
+ mnThreadId != NAMESPACE_VOS(OThread)::getCurrentIdentifier())
+ fprintf( stderr, "\n\n--- A different thread owns the mutex ...---\n\n\n");
+#endif
+
+ while( mnCount > 1 )
+ release();
+ release();
+}
+
+void GtkHookedYieldMutex::acquire()
+{
+ SalYieldMutex::acquire();
+}
+
+void GtkHookedYieldMutex::release()
+{
+ SalYieldMutex::release();
+}
+
+extern "C"
+{
+ #define GET_YIELD_MUTEX() static_cast<GtkHookedYieldMutex*>(GetSalData()->m_pInstance->GetYieldMutex())
+ static void GdkThreadsEnter( void )
+ {
+ GtkHookedYieldMutex *pYieldMutex = GET_YIELD_MUTEX();
+ pYieldMutex->ThreadsEnter();
+ }
+ static void GdkThreadsLeave( void )
+ {
+ GtkHookedYieldMutex *pYieldMutex = GET_YIELD_MUTEX();
+ pYieldMutex->ThreadsLeave();
+ }
+ static bool hookLocks( oslModule pModule )
+ {
+ typedef void (*GdkLockFn) (GCallback enter_fn, GCallback leave_fn);
+
+ GdkLockFn gdk_threads_set_lock_functions =
+ (GdkLockFn) osl_getAsciiFunctionSymbol( pModule, "gdk_threads_set_lock_functions" );
+ if ( !gdk_threads_set_lock_functions )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "Failed to hook gdk threads locks\n" );
+#endif
+ return false;
+ }
+
+ gdk_threads_set_lock_functions (GdkThreadsEnter, GdkThreadsLeave);
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "Hooked gdk threads locks\n" );
+#endif
+ return true;
+ }
+
+ VCL_DLLPUBLIC SalInstance* create_SalInstance( oslModule pModule )
+ {
+ /* #i92121# workaround deadlocks in the X11 implementation
+ */
+ static const char* pNoXInitThreads = getenv( "SAL_NO_XINITTHREADS" );
+ /* #i90094#
+ from now on we know that an X connection will be
+ established, so protect X against itself
+ */
+ if( ! ( pNoXInitThreads && *pNoXInitThreads ) )
+ XInitThreads();
+
+ const gchar* pVersion = gtk_check_version( 2, 2, 0 );
+ if( pVersion )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "gtk version conflict: %s\n", pVersion );
+#endif
+ return NULL;
+ }
+
+ GtkYieldMutex *pYieldMutex;
+
+ // init gdk thread protection
+ if ( !g_thread_supported() )
+ g_thread_init( NULL );
+
+ if ( hookLocks( pModule ) )
+ pYieldMutex = new GtkHookedYieldMutex();
+ else
+ pYieldMutex = new GtkYieldMutex();
+
+ gdk_threads_init();
+
+ GtkInstance* pInstance = new GtkInstance( pYieldMutex );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "creating GtkSalInstance 0x%p\n", pInstance );
+#endif
+
+ // initialize SalData
+ GtkData *pSalData = new GtkData();
+ SetSalData( pSalData );
+ pSalData->m_pInstance = pInstance;
+ pSalData->Init();
+ pSalData->initNWF();
+
+ InitAtkBridge();
+
+ return pInstance;
+ }
+}
+
+GtkInstance::~GtkInstance()
+{
+ DeInitAtkBridge();
+}
+
+SalFrame* GtkInstance::CreateFrame( SalFrame* pParent, ULONG nStyle )
+{
+ return new GtkSalFrame( pParent, nStyle );
+}
+
+SalFrame* GtkInstance::CreateChildFrame( SystemParentData* pParentData, ULONG )
+{
+ SalFrame* pFrame = new GtkSalFrame( pParentData );
+
+ return pFrame;
+}
+
+SalObject* GtkInstance::CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, BOOL bShow )
+{
+ // there is no method to set a visual for a GtkWidget
+ // so we need the X11SalObject in that case
+ if( pWindowData )
+ return X11SalObject::CreateObject( pParent, pWindowData, bShow );
+
+ return new GtkSalObject( static_cast<GtkSalFrame*>(pParent), bShow );
+}
+
+extern "C"
+{
+ typedef void*(* getDefaultFnc)();
+ typedef void(* addItemFnc)(void *, const char *);
+}
+
+void GtkInstance::AddToRecentDocumentList(const rtl::OUString& rFileUrl, const rtl::OUString& rMimeType)
+{
+#if GTK_CHECK_VERSION(2,10,0)
+ GtkRecentManager *manager = gtk_recent_manager_get_default ();
+ gtk_recent_manager_add_item (manager, rtl::OUStringToOString(rFileUrl, RTL_TEXTENCODING_UTF8).getStr());
+ (void)rMimeType;
+#else
+ static getDefaultFnc sym_gtk_recent_manager_get_default =
+ (getDefaultFnc)osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "gtk_recent_manager_get_default" );
+
+ static addItemFnc sym_gtk_recent_manager_add_item =
+ (addItemFnc)osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "gtk_recent_manager_add_item");
+ if (sym_gtk_recent_manager_get_default && sym_gtk_recent_manager_add_item)
+ {
+ sym_gtk_recent_manager_add_item(sym_gtk_recent_manager_get_default(),
+ rtl::OUStringToOString(rFileUrl, RTL_TEXTENCODING_UTF8).getStr());
+ }
+ else
+ X11SalInstance::AddToRecentDocumentList(rFileUrl, rMimeType);
+#endif
+}
+
+GtkYieldMutex::GtkYieldMutex()
+{
+}
+
+void GtkYieldMutex::acquire()
+{
+ vos::OThread::TThreadIdentifier aCurrentThread = vos::OThread::getCurrentIdentifier();
+ // protect member manipulation
+ OMutex::acquire();
+ if( mnCount > 0 && mnThreadId == aCurrentThread )
+ {
+ mnCount++;
+ OMutex::release();
+ return;
+ }
+ OMutex::release();
+
+ // obtain gdk mutex
+ gdk_threads_enter();
+
+ // obtained gdk mutex, now lock count is one by definition
+ OMutex::acquire();
+ mnCount = 1;
+ mnThreadId = aCurrentThread;
+ OMutex::release();
+}
+
+void GtkYieldMutex::release()
+{
+ vos::OThread::TThreadIdentifier aCurrentThread = vos::OThread::getCurrentIdentifier();
+ // protect member manipulation
+ OMutex::acquire();
+ // strange things happen, do nothing if we don't own the mutex
+ if( mnThreadId == aCurrentThread )
+ {
+ mnCount--;
+ if( mnCount == 0 )
+ {
+ gdk_threads_leave();
+ mnThreadId = 0;
+ }
+ }
+ OMutex::release();
+}
+
+sal_Bool GtkYieldMutex::tryToAcquire()
+{
+ vos::OThread::TThreadIdentifier aCurrentThread = vos::OThread::getCurrentIdentifier();
+ // protect member manipulation
+ OMutex::acquire();
+ if( mnCount > 0 )
+ {
+ if( mnThreadId == aCurrentThread )
+ {
+ mnCount++;
+ OMutex::release();
+ return sal_True;
+ }
+ else
+ {
+ OMutex::release();
+ return sal_False;
+ }
+ }
+ OMutex::release();
+
+ // HACK: gdk_threads_mutex is private, we shouldn't use it.
+ // how to we do a try_lock without having a gdk_threads_try_enter ?
+ if( ! g_mutex_trylock( gdk_threads_mutex ) )
+ return sal_False;
+
+ // obtained gdk mutex, now lock count is one by definition
+ OMutex::acquire();
+ mnCount = 1;
+ mnThreadId = aCurrentThread;
+ OMutex::release();
+
+ return sal_True;
+}
+
+int GtkYieldMutex::Grab()
+{
+ // this MUST only be called by gdk/gtk callbacks:
+ // they are entered with gdk mutex locked; the mutex
+ // was unlocked by GtkYieldMutex befor yielding which
+ // is now locked again by gtk implicitly
+
+ // obtained gdk mutex, now lock count is one by definition
+ OMutex::acquire();
+ int nRet = mnCount;
+ if( mnCount == 0 ) // recursive else
+ mnThreadId = vos::OThread::getCurrentIdentifier();
+#if OSL_DEBUG_LEVEL > 1
+ else if( mnThreadId != vos::OThread::getCurrentIdentifier() )
+ {
+ fprintf( stderr, "Yield mutex grabbed in different thread !\n" );
+ abort();
+ }
+#endif
+ mnCount = 1;
+ OMutex::release();
+ return nRet;
+}
+
+void GtkYieldMutex::Ungrab( int nGrabs )
+{
+ // this MUST only be called when leaving the callback
+ // that locked the mutex with Grab()
+ OMutex::acquire();
+ mnCount = nGrabs;
+ if( mnCount == 0 )
+ mnThreadId = 0;
+ OMutex::release();
+}
diff --git a/vcl/unx/gtk/app/gtksys.cxx b/vcl/unx/gtk/app/gtksys.cxx
new file mode 100644
index 000000000000..272af20d0886
--- /dev/null
+++ b/vcl/unx/gtk/app/gtksys.cxx
@@ -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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <svunx.h>
+#include <vcl/svdata.hxx>
+#include <vcl/window.hxx>
+#include <plugins/gtk/gtkinst.hxx>
+#include <cstdio>
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+#include <X11/Xlib.h>
+
+SalSystem *GtkInstance::CreateSalSystem()
+{
+ return new GtkSalSystem();
+}
+
+GtkSalSystem::~GtkSalSystem()
+{
+}
+
+int GtkSalSystem::ShowNativeDialog( const String& rTitle,
+ const String& rMessage,
+ const std::list< String >& rButtons,
+ int nDefButton )
+{
+
+ ImplSVData* pSVData = ImplGetSVData();
+ if( pSVData->mpIntroWindow )
+ pSVData->mpIntroWindow->Hide();
+
+#if OSL_DEBUG_LEVEL > 1
+ std::fprintf( stderr, "GtkSalSystem::ShowNativeDialog\n");
+#endif
+
+ ByteString aTitle( rTitle, RTL_TEXTENCODING_UTF8 );
+ ByteString aMessage( rMessage, RTL_TEXTENCODING_UTF8 );
+
+ /* Create the dialogue */
+ GtkWidget* mainwin = gtk_message_dialog_new
+ ( NULL, (GtkDialogFlags)0, GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_NONE, aMessage.GetBuffer(), NULL );
+ gtk_window_set_title( GTK_WINDOW( mainwin ), aTitle.GetBuffer() );
+
+ gint nButtons = 0, nResponse;
+
+ int nButton = 0;
+ for( std::list< String >::const_iterator it = rButtons.begin(); it != rButtons.end(); ++it )
+ {
+ ByteString aLabel( *it, RTL_TEXTENCODING_UTF8 );
+
+ if( nButton == nDefButton )
+ {
+ gtk_dialog_add_button( GTK_DIALOG( mainwin ), aLabel.GetBuffer(), nButtons );
+ gtk_dialog_set_default_response( GTK_DIALOG( mainwin ), nButtons );
+ }
+ else
+ gtk_dialog_add_button( GTK_DIALOG( mainwin ), aLabel.GetBuffer(), nButtons );
+ nButtons++;
+ }
+
+ nResponse = gtk_dialog_run( GTK_DIALOG(mainwin) );
+ if( nResponse == GTK_RESPONSE_NONE || nResponse == GTK_RESPONSE_DELETE_EVENT )
+ nResponse = -1;
+
+ gtk_widget_destroy( GTK_WIDGET(mainwin) );
+
+ return nResponse;
+}
diff --git a/vcl/unx/gtk/app/makefile.mk b/vcl/unx/gtk/app/makefile.mk
new file mode 100644
index 000000000000..3e8cd750bf7a
--- /dev/null
+++ b/vcl/unx/gtk/app/makefile.mk
@@ -0,0 +1,76 @@
+#*************************************************************************
+#
+# 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=gtkapp
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# workaround for makedepend hang
+MKDEPENDSOLVER=
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)"!="unx"
+
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+
+.ELSE # "$(GUIBASE)"!="unx"
+
+.IF "$(ENABLE_GTK)" != ""
+
+PKGCONFIG_MODULES=gtk+-2.0
+.INCLUDE : pkg_config.mk
+
+SLOFILES=\
+ $(SLO)$/gtkdata.obj \
+ $(SLO)$/gtkinst.obj \
+ $(SLO)$/gtksys.obj
+
+EXCEPTIONSFILES=\
+ $(SLO)$/gtkdata.obj\
+ $(SLO)$/gtkinst.obj
+
+.ELSE # "$(ENABLE_GTK)" != ""
+
+dummy:
+ @echo GTK disabled - nothing to build
+.ENDIF
+.ENDIF # "$(GUIBASE)"!="unx"
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
+.INCLUDE : $(PRJ)$/util$/target.pmk
diff --git a/vcl/unx/gtk/gdi/makefile.mk b/vcl/unx/gtk/gdi/makefile.mk
new file mode 100644
index 000000000000..ec6b4e1d205e
--- /dev/null
+++ b/vcl/unx/gtk/gdi/makefile.mk
@@ -0,0 +1,67 @@
+#*************************************************************************
+#
+# 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=gtkgdi
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)"!="unx"
+
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+
+.ELSE # "$(GUIBASE)"!="unx"
+
+.IF "$(ENABLE_GTK)" != ""
+
+PKGCONFIG_MODULES=gtk+-2.0
+.INCLUDE : pkg_config.mk
+
+SLOFILES=$(SLO)$/salnativewidgets-gtk.obj
+EXCEPTIONSFILES=$(SLO)$/salnativewidgets-gtk.obj
+
+.ELSE # "$(ENABLE_GTK)" != ""
+dummy:
+ @echo GTK disabled - nothing to build
+.ENDIF
+
+.ENDIF # "$(GUIBASE)"!="unx"
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
+.INCLUDE : $(PRJ)$/util$/target.pmk
diff --git a/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx b/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx
new file mode 100644
index 000000000000..cdc72485ae6c
--- /dev/null
+++ b/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx
@@ -0,0 +1,4129 @@
+/*************************************************************************
+ *
+ * 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 "plugins/gtk/gtkframe.hxx"
+#include "plugins/gtk/gtkdata.hxx"
+#include "plugins/gtk/gtkinst.hxx"
+#include "plugins/gtk/gtkgdi.hxx"
+
+#include "pspgraphics.h"
+
+#include <cstdio>
+#include <cmath>
+#include <vector>
+#include <algorithm>
+#include <hash_map>
+
+#include "saldata.hxx"
+#include "saldisp.hxx"
+#include "vcl/svapp.hxx"
+
+typedef struct _cairo_font_options cairo_font_options_t;
+
+// initialize statics
+BOOL GtkSalGraphics::bThemeChanged = TRUE;
+BOOL GtkSalGraphics::bNeedPixmapPaint = FALSE;
+BOOL GtkSalGraphics::bGlobalNeedPixmapPaint = FALSE;
+BOOL GtkSalGraphics::bToolbarGripWorkaround = FALSE;
+BOOL GtkSalGraphics::bNeedButtonStyleAsEditBackgroundWorkaround = FALSE;
+
+GtkSalGraphics::~GtkSalGraphics()
+{
+}
+
+
+using namespace rtl;
+
+/*************************************
+ * Cached native widget objects
+ *************************************/
+class NWPixmapCacheList;
+class NWPixmapCache;
+struct NWFWidgetData
+{
+ GtkWidget * gCacheWindow;
+ GtkWidget * gDumbContainer;
+
+ GtkWidget * gBtnWidget;
+ GtkWidget * gRadioWidget;
+ GtkWidget * gRadioWidgetSibling;
+ GtkWidget * gCheckWidget;
+ GtkWidget * gScrollHorizWidget;
+ GtkWidget * gScrollVertWidget;
+ GtkWidget * gArrowWidget;
+ GtkWidget * gDropdownWidget;
+ GtkWidget * gEditBoxWidget;
+ GtkWidget * gSpinButtonWidget;
+ GtkWidget * gNotebookWidget;
+ GtkWidget * gOptionMenuWidget;
+ GtkWidget * gComboWidget;
+ GtkWidget * gScrolledWindowWidget;
+ GtkWidget * gToolbarWidget;
+ GtkWidget * gToolbarButtonWidget;
+ GtkWidget * gToolbarToggleWidget;
+ GtkWidget * gHandleBoxWidget;
+ GtkWidget * gMenubarWidget;
+ GtkWidget * gMenuItemMenubarWidget;
+ GtkWidget * gMenuWidget;
+ GtkWidget * gMenuItemMenuWidget;
+ GtkWidget * gMenuItemCheckMenuWidget;
+ GtkWidget * gMenuItemRadioMenuWidget;
+ GtkWidget * gImageMenuItem;
+ GtkWidget * gTooltipPopup;
+ GtkWidget * gProgressBar;
+ GtkWidget * gTreeView;
+ GtkWidget * gHScale;
+ GtkWidget * gVScale;
+
+ NWPixmapCacheList* gNWPixmapCacheList;
+ NWPixmapCache* gCacheTabItems;
+ NWPixmapCache* gCacheTabPages;
+
+ NWFWidgetData() :
+ gCacheWindow( NULL ),
+ gDumbContainer( NULL ),
+ gBtnWidget( NULL ),
+ gRadioWidget( NULL ),
+ gRadioWidgetSibling( NULL ),
+ gCheckWidget( NULL ),
+ gScrollHorizWidget( NULL ),
+ gScrollVertWidget( NULL ),
+ gArrowWidget( NULL ),
+ gDropdownWidget( NULL ),
+ gEditBoxWidget( NULL ),
+ gSpinButtonWidget( NULL ),
+ gNotebookWidget( NULL ),
+ gOptionMenuWidget( NULL ),
+ gComboWidget( NULL ),
+ gScrolledWindowWidget( NULL ),
+ gToolbarWidget( NULL ),
+ gToolbarButtonWidget( NULL ),
+ gToolbarToggleWidget( NULL ),
+ gHandleBoxWidget( NULL ),
+ gMenubarWidget( NULL ),
+ gMenuItemMenubarWidget( NULL ),
+ gMenuWidget( NULL ),
+ gMenuItemMenuWidget( NULL ),
+ gMenuItemCheckMenuWidget( NULL ),
+ gMenuItemRadioMenuWidget( NULL ),
+ gImageMenuItem( NULL ),
+ gTooltipPopup( NULL ),
+ gProgressBar( NULL ),
+ gTreeView( NULL ),
+ gHScale( NULL ),
+ gVScale( NULL ),
+ gNWPixmapCacheList( NULL ),
+ gCacheTabItems( NULL ),
+ gCacheTabPages( NULL )
+ {}
+};
+
+// Keep a hash table of Widgets->default flags so that we can
+// easily and quickly reset each to a default state before using
+// them
+static std::hash_map<long, guint> gWidgetDefaultFlags;
+static std::vector<NWFWidgetData> gWidgetData;
+
+static const GtkBorder aDefDefBorder = { 1, 1, 1, 1 };
+
+// Some GTK defaults
+#define MIN_ARROW_SIZE 11
+#define BTN_CHILD_SPACING 1
+#define MIN_SPIN_ARROW_WIDTH 6
+
+
+static void NWEnsureGTKRadio ( int nScreen );
+static void NWEnsureGTKButton ( int nScreen );
+static void NWEnsureGTKCheck ( int nScreen );
+static void NWEnsureGTKScrollbars ( int nScreen );
+static void NWEnsureGTKArrow ( int nScreen );
+static void NWEnsureGTKEditBox ( int nScreen );
+static void NWEnsureGTKSpinButton ( int nScreen );
+static void NWEnsureGTKNotebook ( int nScreen );
+static void NWEnsureGTKOptionMenu ( int nScreen );
+static void NWEnsureGTKCombo ( int nScreen );
+static void NWEnsureGTKScrolledWindow ( int nScreen );
+static void NWEnsureGTKToolbar ( int nScreen );
+static void NWEnsureGTKMenubar ( int nScreen );
+static void NWEnsureGTKMenu ( int nScreen );
+static void NWEnsureGTKTooltip ( int nScreen );
+static void NWEnsureGTKProgressBar ( int nScreen );
+static void NWEnsureGTKTreeView ( int nScreen );
+static void NWEnsureGTKSlider ( int nScreen );
+
+static void NWConvertVCLStateToGTKState( ControlState nVCLState, GtkStateType* nGTKState, GtkShadowType* nGTKShadow );
+static void NWAddWidgetToCacheWindow( GtkWidget* widget, int nScreen );
+static void NWSetWidgetState( GtkWidget* widget, ControlState nState, GtkStateType nGtkState );
+
+static void NWCalcArrowRect( const Rectangle& rButton, Rectangle& rArrow );
+
+/*
+ * Individual helper functions
+ *
+ */
+
+//---
+static Rectangle NWGetButtonArea( int nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
+ const ImplControlValue& aValue, const OUString& rCaption );
+
+//---
+static Rectangle NWGetEditBoxPixmapRect( int nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
+ const ImplControlValue& aValue, const OUString& rCaption );
+
+static void NWPaintOneEditBox( int nScreen, GdkDrawable * gdkDrawable, GdkRectangle *gdkRect,
+ ControlType nType, ControlPart nPart, Rectangle aEditBoxRect,
+ ControlState nState, const ImplControlValue& aValue,
+ const OUString& rCaption );
+
+//---
+static Rectangle NWGetSpinButtonRect( int nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
+ const ImplControlValue& aValue, const OUString& rCaption );
+
+static void NWPaintOneSpinButton( int nScreen, GdkPixmap * pixmap, ControlType nType, ControlPart nPart, Rectangle aAreaRect,
+ ControlState nState, const ImplControlValue& aValue,
+ const OUString& rCaption );
+//---
+static Rectangle NWGetComboBoxButtonRect( int nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
+ const ImplControlValue& aValue, const OUString& rCaption );
+
+//---
+static Rectangle NWGetListBoxButtonRect( int nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
+ const ImplControlValue& aValue, const OUString& rCaption );
+
+static Rectangle NWGetListBoxIndicatorRect( int nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
+ const ImplControlValue& aValue, const OUString& rCaption );
+
+static Rectangle NWGetToolbarRect( int nScreen,
+ ControlType nType,
+ ControlPart nPart,
+ Rectangle aAreaRect,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const OUString& rCaption );
+//---
+
+static Rectangle NWGetScrollButtonRect( int nScreen, ControlPart nPart, Rectangle aAreaRect );
+//---
+
+/*********************************************************
+ * PixmapCache
+ *********************************************************/
+
+// as some native widget drawing operations are pretty slow
+// with certain themes (eg tabpages)
+// this cache can be used to cache the corresponding pixmap
+// see NWPaintGTKTabItem
+
+class NWPixmapCacheData
+{
+public:
+ ControlType m_nType;
+ ControlState m_nState;
+ Rectangle m_pixmapRect;
+ GdkPixmap* m_pixmap;
+
+ NWPixmapCacheData() : m_nType(0), m_nState(0), m_pixmap(0) {}
+ ~NWPixmapCacheData()
+ { SetPixmap( NULL ); };
+ void SetPixmap( GdkPixmap* pPixmap );
+};
+
+class NWPixmapCache
+{
+ int m_size;
+ int m_idx;
+ int m_screen;
+ NWPixmapCacheData* pData;
+public:
+ NWPixmapCache( int nScreen );
+ ~NWPixmapCache();
+
+ void SetSize( int n)
+ { delete [] pData; m_idx = 0; m_size = n; pData = new NWPixmapCacheData[m_size]; }
+ int GetSize() { return m_size; }
+
+ BOOL Find( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkPixmap** pPixmap );
+ void Fill( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkPixmap* pPixmap );
+
+ void ThemeChanged();
+};
+
+class NWPixmapCacheList
+{
+public:
+ ::std::vector< NWPixmapCache* > mCaches;
+
+ void AddCache( NWPixmapCache *pCache );
+ void RemoveCache( NWPixmapCache *pCache );
+ void ThemeChanged();
+};
+
+// --- implementation ---
+
+void NWPixmapCacheData::SetPixmap( GdkPixmap* pPixmap )
+{
+ if( m_pixmap )
+ g_object_unref( m_pixmap );
+
+ m_pixmap = pPixmap;
+
+ if( m_pixmap )
+ g_object_ref( m_pixmap );
+}
+
+
+NWPixmapCache::NWPixmapCache( int nScreen )
+{
+ m_idx = 0;
+ m_size = 0;
+ m_screen = nScreen;
+ pData = NULL;
+ if( gWidgetData[m_screen].gNWPixmapCacheList )
+ gWidgetData[m_screen].gNWPixmapCacheList->AddCache(this);
+}
+NWPixmapCache::~NWPixmapCache()
+{
+ if( gWidgetData[m_screen].gNWPixmapCacheList )
+ gWidgetData[m_screen].gNWPixmapCacheList->RemoveCache(this);
+ delete[] pData;
+}
+void NWPixmapCache::ThemeChanged()
+{
+ // throw away cached pixmaps
+ int i;
+ for(i=0; i<m_size; i++)
+ pData[i].SetPixmap( NULL );
+}
+
+BOOL NWPixmapCache::Find( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkPixmap** pPixmap )
+{
+ aState &= ~CTRL_CACHING_ALLOWED; // mask clipping flag
+ int i;
+ for(i=0; i<m_size; i++)
+ {
+ if( pData[i].m_nType == aType &&
+ pData[i].m_nState == aState &&
+ pData[i].m_pixmapRect.GetWidth() == r_pixmapRect.GetWidth() &&
+ pData[i].m_pixmapRect.GetHeight() == r_pixmapRect.GetHeight() &&
+ pData[i].m_pixmap != NULL )
+ {
+ *pPixmap = pData[i].m_pixmap;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+void NWPixmapCache::Fill( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkPixmap* pPixmap )
+{
+ if( !(aState & CTRL_CACHING_ALLOWED) )
+ return;
+
+ aState &= ~CTRL_CACHING_ALLOWED; // mask clipping flag
+ m_idx = (m_idx+1) % m_size; // just wrap
+ pData[m_idx].m_nType = aType;
+ pData[m_idx].m_nState = aState;
+ pData[m_idx].m_pixmapRect = r_pixmapRect;
+ pData[m_idx].SetPixmap( pPixmap );
+}
+
+
+void NWPixmapCacheList::AddCache( NWPixmapCache* pCache )
+{
+ mCaches.push_back( pCache );
+}
+void NWPixmapCacheList::RemoveCache( NWPixmapCache* pCache )
+{
+ ::std::vector< NWPixmapCache* >::iterator p;
+ p = ::std::find( mCaches.begin(), mCaches.end(), pCache );
+ if( p != mCaches.end() )
+ mCaches.erase( p );
+}
+void NWPixmapCacheList::ThemeChanged( )
+{
+ ::std::vector< NWPixmapCache* >::iterator p = mCaches.begin();
+ while( p != mCaches.end() )
+ {
+ (*p)->ThemeChanged();
+ p++;
+ }
+}
+
+
+/*********************************************************
+ * Make border manipulation easier
+ *********************************************************/
+inline void NW_gtk_border_set_from_border( GtkBorder& aDst, const GtkBorder * pSrc )
+{
+ aDst.left = pSrc->left;
+ aDst.top = pSrc->top;
+ aDst.right = pSrc->right;
+ aDst.bottom = pSrc->bottom;
+}
+
+
+/*********************************************************
+ * Initialize GTK and local stuff
+ *********************************************************/
+void GtkData::initNWF( void )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ // draw no border for popup menus (NWF draws its own)
+ pSVData->maNWFData.mbFlatMenu = true;
+
+ // draw separate buttons for toolbox dropdown items
+ pSVData->maNWFData.mbToolboxDropDownSeparate = true;
+
+ // small extra border around menu items
+ pSVData->maNWFData.mnMenuFormatExtraBorder = 1;
+
+ // draw toolbars in separate lines
+ pSVData->maNWFData.mbDockingAreaSeparateTB = true;
+
+ // open first menu on F10
+ pSVData->maNWFData.mbOpenMenuOnF10 = true;
+
+ int nScreens = GetX11SalData()->GetDisplay()->GetScreenCount();
+ gWidgetData = std::vector<NWFWidgetData>( nScreens );
+ for( int i = 0; i < nScreens; i++ )
+ gWidgetData[i].gNWPixmapCacheList = new NWPixmapCacheList;
+
+
+ if( SalGetDesktopEnvironment().equalsAscii( "KDE" ) )
+ {
+ // #i97196# ensure a widget exists and the style engine was loaded
+ NWEnsureGTKButton( 0 );
+ if( g_type_from_name( "QtEngineStyle" ) )
+ {
+ // KDE 3.3 invented a bug in the qt<->gtk theme engine
+ // that makes direct rendering impossible: they totally
+ // ignore the clip rectangle passed to the paint methods
+ GtkSalGraphics::bNeedPixmapPaint = GtkSalGraphics::bGlobalNeedPixmapPaint = true;
+ }
+ }
+ static const char* pEnv = getenv( "SAL_GTK_USE_PIXMAPPAINT" );
+ if( pEnv && *pEnv )
+ GtkSalGraphics::bNeedPixmapPaint = GtkSalGraphics::bGlobalNeedPixmapPaint = true;
+
+ #if OSL_DEBUG_LEVEL > 1
+ std::fprintf( stderr, "GtkPlugin: using %s NWF\n",
+ GtkSalGraphics::bNeedPixmapPaint ? "offscreen" : "direct" );
+ #endif
+}
+
+
+/*********************************************************
+ * Release GTK and local stuff
+ *********************************************************/
+void GtkData::deInitNWF( void )
+{
+
+ for( unsigned int i = 0; i < gWidgetData.size(); i++ )
+ {
+ // free up global widgets
+ // gtk_widget_destroy will in turn destroy the child hierarchy
+ // so only destroy disjunct hierachies
+ if( gWidgetData[i].gCacheWindow )
+ gtk_widget_destroy( gWidgetData[i].gCacheWindow );
+ if( gWidgetData[i].gMenuWidget )
+ gtk_widget_destroy( gWidgetData[i].gMenuWidget );
+ if( gWidgetData[i].gTooltipPopup )
+ gtk_widget_destroy( gWidgetData[i].gTooltipPopup );
+ delete gWidgetData[i].gCacheTabPages;
+ gWidgetData[i].gCacheTabPages = NULL;
+ delete gWidgetData[i].gCacheTabItems;
+ gWidgetData[i].gCacheTabItems = NULL;
+ delete gWidgetData[i].gNWPixmapCacheList;
+ gWidgetData[i].gNWPixmapCacheList = NULL;
+ }
+}
+
+
+/**********************************************************
+ * track clip region
+ **********************************************************/
+void GtkSalGraphics::ResetClipRegion()
+{
+ m_aClipRegion.SetNull();
+ X11SalGraphics::ResetClipRegion();
+}
+
+void GtkSalGraphics::BeginSetClipRegion( ULONG nCount )
+{
+ m_aClipRegion.SetNull();
+ X11SalGraphics::BeginSetClipRegion( nCount );
+}
+
+BOOL GtkSalGraphics::unionClipRegion( long nX, long nY, long nWidth, long nHeight )
+{
+ Rectangle aRect( Point( nX, nY ), Size( nWidth, nHeight ) );
+ m_aClipRegion.Union( aRect );
+ return X11SalGraphics::unionClipRegion( nX, nY, nWidth, nHeight );
+}
+
+bool GtkSalGraphics::unionClipRegion( const ::basegfx::B2DPolyPolygon& )
+{
+ // TODO: implement and advertise OutDevSupport_B2DClip support
+ return false;
+}
+
+void GtkSalGraphics::EndSetClipRegion()
+{
+ if( m_aClipRegion.IsEmpty() )
+ m_aClipRegion.SetNull();
+ X11SalGraphics::EndSetClipRegion();
+}
+
+void GtkSalGraphics::copyBits( const SalTwoRect* pPosAry,
+ SalGraphics* pSrcGraphics )
+{
+ GtkSalFrame* pFrame = GetGtkFrame();
+ XLIB_Window aWin = None;
+ if( pFrame && m_pWindow )
+ {
+ /* #i64117# some themes set the background pixmap VERY frequently */
+ GdkWindow* pWin = GTK_WIDGET(m_pWindow)->window;
+ if( pWin )
+ {
+ aWin = GDK_WINDOW_XWINDOW(pWin);
+ if( aWin != None )
+ XSetWindowBackgroundPixmap( pFrame->getDisplay()->GetDisplay(),
+ aWin,
+ None );
+ }
+ }
+ X11SalGraphics::copyBits( pPosAry, pSrcGraphics );
+ if( pFrame && pFrame->getBackgroundPixmap() != None )
+ XSetWindowBackgroundPixmap( pFrame->getDisplay()->GetDisplay(),
+ aWin,
+ pFrame->getBackgroundPixmap() );
+}
+
+/*
+ * IsNativeControlSupported()
+ *
+ * Returns TRUE if the platform supports native
+ * drawing of the control defined by nPart
+ */
+BOOL GtkSalGraphics::IsNativeControlSupported( ControlType nType, ControlPart nPart )
+{
+ if (
+ ((nType==CTRL_PUSHBUTTON) && (nPart==PART_ENTIRE_CONTROL)) ||
+ ((nType==CTRL_RADIOBUTTON) && (nPart==PART_ENTIRE_CONTROL)) ||
+ ((nType==CTRL_CHECKBOX) && (nPart==PART_ENTIRE_CONTROL)) ||
+ ((nType==CTRL_SCROLLBAR) &&
+ ( (nPart==PART_DRAW_BACKGROUND_HORZ)
+ || (nPart==PART_DRAW_BACKGROUND_VERT)
+ || (nPart==PART_ENTIRE_CONTROL)
+ || (nPart==HAS_THREE_BUTTONS) ) ) ||
+ ((nType==CTRL_EDITBOX) &&
+ ( (nPart==PART_ENTIRE_CONTROL)
+ || (nPart==HAS_BACKGROUND_TEXTURE) ) ) ||
+ ((nType==CTRL_MULTILINE_EDITBOX) &&
+ ( (nPart==PART_ENTIRE_CONTROL)
+ || (nPart==HAS_BACKGROUND_TEXTURE) ) ) ||
+ ((nType==CTRL_SPINBOX) &&
+ ( (nPart==PART_ENTIRE_CONTROL)
+ || (nPart==PART_ALL_BUTTONS)
+ || (nPart==HAS_BACKGROUND_TEXTURE) ) ) ||
+ ((nType==CTRL_SPINBUTTONS) &&
+ ( (nPart==PART_ENTIRE_CONTROL)
+ || (nPart==PART_ALL_BUTTONS) ) ) ||
+ ((nType==CTRL_COMBOBOX) &&
+ ( (nPart==PART_ENTIRE_CONTROL)
+ || (nPart==HAS_BACKGROUND_TEXTURE) ) ) ||
+ (((nType==CTRL_TAB_ITEM) || (nType==CTRL_TAB_PANE) ||
+ (nType==CTRL_TAB_BODY) || (nType==CTRL_FIXEDBORDER)) &&
+ ( (nPart==PART_ENTIRE_CONTROL)
+ || (nPart==PART_TABS_DRAW_RTL) ) ) ||
+ ((nType==CTRL_LISTBOX) &&
+ ( (nPart==PART_ENTIRE_CONTROL)
+ || (nPart==PART_WINDOW)
+ || (nPart==HAS_BACKGROUND_TEXTURE) ) ) ||
+ ((nType == CTRL_TOOLBAR) &&
+ ( (nPart==PART_ENTIRE_CONTROL)
+ || (nPart==PART_DRAW_BACKGROUND_HORZ)
+ || (nPart==PART_DRAW_BACKGROUND_VERT)
+ || (nPart==PART_THUMB_HORZ)
+ || (nPart==PART_THUMB_VERT)
+ || (nPart==PART_BUTTON)
+ )
+ ) ||
+ ((nType == CTRL_MENUBAR) &&
+ ( (nPart==PART_ENTIRE_CONTROL) ) ) ||
+ ((nType == CTRL_TOOLTIP) &&
+ ( (nPart==PART_ENTIRE_CONTROL) ) ) ||
+ ((nType == CTRL_MENU_POPUP) &&
+ ( (nPart==PART_ENTIRE_CONTROL)
+ || (nPart==PART_MENU_ITEM)
+ || (nPart==PART_MENU_ITEM_CHECK_MARK)
+ || (nPart==PART_MENU_ITEM_RADIO_MARK)
+ )
+ ) ||
+ ((nType == CTRL_PROGRESS) &&
+ ( (nPart == PART_ENTIRE_CONTROL) )
+ ) ||
+ ((nType == CTRL_LISTNODE || nType == CTRL_LISTNET) &&
+ ( (nPart == PART_ENTIRE_CONTROL) )
+ ) ||
+ ((nType == CTRL_SLIDER) &&
+ ( (nPart == PART_TRACK_HORZ_AREA)
+ || (nPart == PART_TRACK_VERT_AREA)
+ )
+ )
+ )
+ return( TRUE );
+
+ return( FALSE );
+}
+
+
+/*
+ * HitTestNativeControl()
+ *
+ * bIsInside is set to TRUE if aPos is contained within the
+ * given part of the control, whose bounding region is
+ * given by rControlRegion (in VCL frame coordinates).
+ *
+ * returns whether bIsInside was really set.
+ */
+BOOL GtkSalGraphics::hitTestNativeControl( ControlType nType,
+ ControlPart nPart,
+ const Region& rControlRegion,
+ const Point& aPos,
+ BOOL& rIsInside )
+{
+ if ( ( nType == CTRL_SCROLLBAR ) &&
+ ( ( nPart == PART_BUTTON_UP ) ||
+ ( nPart == PART_BUTTON_DOWN ) ||
+ ( nPart == PART_BUTTON_LEFT ) ||
+ ( nPart == PART_BUTTON_RIGHT ) ) )
+ {
+ NWEnsureGTKScrollbars( m_nScreen );
+
+ // Grab some button style attributes
+ gboolean has_forward;
+ gboolean has_forward2;
+ gboolean has_backward;
+ gboolean has_backward2;
+
+ gtk_widget_style_get( gWidgetData[m_nScreen].gScrollHorizWidget, "has-forward-stepper", &has_forward,
+ "has-secondary-forward-stepper", &has_forward2,
+ "has-backward-stepper", &has_backward,
+ "has-secondary-backward-stepper", &has_backward2, (char *)NULL );
+ Rectangle aForward;
+ Rectangle aBackward;
+
+ rIsInside = FALSE;
+
+ ControlPart nCounterPart = 0;
+ if ( nPart == PART_BUTTON_UP )
+ nCounterPart = PART_BUTTON_DOWN;
+ else if ( nPart == PART_BUTTON_DOWN )
+ nCounterPart = PART_BUTTON_UP;
+ else if ( nPart == PART_BUTTON_LEFT )
+ nCounterPart = PART_BUTTON_RIGHT;
+ else if ( nPart == PART_BUTTON_RIGHT )
+ nCounterPart = PART_BUTTON_LEFT;
+
+ aBackward = NWGetScrollButtonRect( m_nScreen, nPart, rControlRegion.GetBoundRect() );
+ aForward = NWGetScrollButtonRect( m_nScreen, nCounterPart, rControlRegion.GetBoundRect() );
+
+ if ( has_backward && has_forward2 )
+ {
+ Size aSize( aBackward.GetSize() );
+ if ( ( nPart == PART_BUTTON_UP ) || ( nPart == PART_BUTTON_DOWN ) )
+ aSize.setHeight( aBackward.GetHeight() / 2 );
+ else
+ aSize.setWidth( aBackward.GetWidth() / 2 );
+ aBackward.SetSize( aSize );
+
+ if ( nPart == PART_BUTTON_DOWN )
+ aBackward.Move( 0, aBackward.GetHeight() / 2 );
+ else if ( nPart == PART_BUTTON_RIGHT )
+ aBackward.Move( aBackward.GetWidth() / 2, 0 );
+ }
+
+ if ( has_backward2 && has_forward )
+ {
+ Size aSize( aForward.GetSize() );
+ if ( ( nPart == PART_BUTTON_UP ) || ( nPart == PART_BUTTON_DOWN ) )
+ aSize.setHeight( aForward.GetHeight() / 2 );
+ else
+ aSize.setWidth( aForward.GetWidth() / 2 );
+ aForward.SetSize( aSize );
+
+ if ( nPart == PART_BUTTON_DOWN )
+ aForward.Move( 0, aForward.GetHeight() / 2 );
+ else if ( nPart == PART_BUTTON_RIGHT )
+ aForward.Move( aForward.GetWidth() / 2, 0 );
+ }
+
+ if ( ( nPart == PART_BUTTON_UP ) || ( nPart == PART_BUTTON_LEFT ) )
+ {
+ if ( has_backward )
+ rIsInside |= aBackward.IsInside( aPos );
+ if ( has_backward2 )
+ rIsInside |= aForward.IsInside( aPos );
+ }
+ else
+ {
+ if ( has_forward )
+ rIsInside |= aBackward.IsInside( aPos );
+ if ( has_forward2 )
+ rIsInside |= aForward.IsInside( aPos );
+ }
+ return ( TRUE );
+ }
+
+ if( IsNativeControlSupported(nType, nPart) )
+ {
+ rIsInside = rControlRegion.IsInside( aPos );
+ return( TRUE );
+ }
+ else
+ {
+ 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)
+ * rCaption: A caption or title string (like button text etc)
+ */
+BOOL GtkSalGraphics::drawNativeControl( ControlType nType,
+ ControlPart nPart,
+ const Region& rControlRegion,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const OUString& rCaption )
+{
+ if( (nType==CTRL_CHECKBOX) && (nPart==PART_ENTIRE_CONTROL) &&
+ aValue.getTristateVal() == BUTTONVALUE_MIXED )
+ {
+ return drawNativeMixedStateCheck( nType, nPart, rControlRegion, nState, aValue, rCaption );
+ }
+
+ BOOL returnVal = FALSE;
+ // get a GC with current clipping region set
+ SelectFont();
+
+
+ // theme changed ?
+ if( GtkSalGraphics::bThemeChanged )
+ {
+ // invalidate caches
+ for( unsigned int i = 0; i < gWidgetData.size(); i++ )
+ if( gWidgetData[i].gNWPixmapCacheList )
+ gWidgetData[i].gNWPixmapCacheList->ThemeChanged();
+ GtkSalGraphics::bThemeChanged = FALSE;
+ }
+
+ Rectangle aCtrlRect = rControlRegion.GetBoundRect();
+ Region aClipRegion( m_aClipRegion );
+ if( aClipRegion.IsNull() )
+ aClipRegion = aCtrlRect;
+
+ clipList aClip;
+ GdkDrawable* gdkDrawable = GDK_DRAWABLE( GetGdkWindow() );
+ GdkPixmap* pixmap = NULL;
+ Rectangle aPixmapRect;
+ if( ( bNeedPixmapPaint )
+ && nType != CTRL_SCROLLBAR
+ && nType != CTRL_SPINBOX
+ && nType != CTRL_TAB_ITEM
+ && nType != CTRL_TAB_PANE
+ && nType != CTRL_PROGRESS
+ && ! (bToolbarGripWorkaround && nType == CTRL_TOOLBAR && (nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT) )
+ )
+ {
+ // make pixmap a little larger since some themes draw decoration
+ // outside the rectangle, see e.g. checkbox
+ aPixmapRect = Rectangle( Point( aCtrlRect.Left()-1, aCtrlRect.Top()-1 ),
+ Size( aCtrlRect.GetWidth()+2, aCtrlRect.GetHeight()+2) );
+ pixmap = NWGetPixmapFromScreen( aPixmapRect );
+ if( ! pixmap )
+ return FALSE;
+ gdkDrawable = GDK_DRAWABLE( pixmap );
+ aCtrlRect = Rectangle( Point(1,1), aCtrlRect.GetSize() );
+ aClip.push_back( aCtrlRect );
+ }
+ else
+ {
+ RegionHandle aHdl = aClipRegion.BeginEnumRects();
+ Rectangle aPaintRect;
+ while( aClipRegion.GetNextEnumRect( aHdl, aPaintRect ) )
+ {
+ aPaintRect = aCtrlRect.GetIntersection( aPaintRect );
+ if( aPaintRect.IsEmpty() )
+ continue;
+ aClip.push_back( aPaintRect );
+ }
+ aClipRegion.EndEnumRects( aHdl );
+ }
+
+ if ( (nType==CTRL_PUSHBUTTON) && (nPart==PART_ENTIRE_CONTROL) )
+ {
+ returnVal = NWPaintGTKButton( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+ else if ( (nType==CTRL_RADIOBUTTON) && (nPart==PART_ENTIRE_CONTROL) )
+ {
+ returnVal = NWPaintGTKRadio( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+ else if ( (nType==CTRL_CHECKBOX) && (nPart==PART_ENTIRE_CONTROL) )
+ {
+ returnVal = NWPaintGTKCheck( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+ else if ( (nType==CTRL_SCROLLBAR) && ((nPart==PART_DRAW_BACKGROUND_HORZ) || (nPart==PART_DRAW_BACKGROUND_VERT)) )
+ {
+ returnVal = NWPaintGTKScrollbar( nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+ else if ( ((nType==CTRL_EDITBOX) && ((nPart==PART_ENTIRE_CONTROL) || (nPart==HAS_BACKGROUND_TEXTURE)) )
+ || ((nType==CTRL_SPINBOX) && (nPart==HAS_BACKGROUND_TEXTURE))
+ || ((nType==CTRL_COMBOBOX) && (nPart==HAS_BACKGROUND_TEXTURE))
+ || ((nType==CTRL_LISTBOX) && (nPart==HAS_BACKGROUND_TEXTURE)) )
+ {
+ returnVal = NWPaintGTKEditBox( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+ else if ( ((nType==CTRL_MULTILINE_EDITBOX) && ((nPart==PART_ENTIRE_CONTROL) || (nPart==HAS_BACKGROUND_TEXTURE)) ) )
+ {
+ returnVal = NWPaintGTKEditBox( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+ else if ( ((nType==CTRL_SPINBOX) || (nType==CTRL_SPINBUTTONS))
+ && ((nPart==PART_ENTIRE_CONTROL) || (nPart==PART_ALL_BUTTONS)) )
+ {
+ returnVal = NWPaintGTKSpinBox( nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+ else if ( (nType == CTRL_COMBOBOX) &&
+ ( (nPart==PART_ENTIRE_CONTROL)
+ ||(nPart==PART_BUTTON_DOWN)
+ ) )
+ {
+ returnVal = NWPaintGTKComboBox( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+ else if ( (nType==CTRL_TAB_ITEM) || (nType==CTRL_TAB_PANE) || (nType==CTRL_TAB_BODY) || (nType==CTRL_FIXEDBORDER) )
+ {
+ if ( nType == CTRL_TAB_BODY )
+ returnVal = TRUE;
+ else
+ returnVal = NWPaintGTKTabItem( nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption);
+ }
+ else if ( (nType==CTRL_LISTBOX) && ((nPart==PART_ENTIRE_CONTROL) || (nPart==PART_WINDOW)) )
+ {
+ returnVal = NWPaintGTKListBox( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+ else if ( (nType== CTRL_TOOLBAR) )
+ {
+ returnVal = NWPaintGTKToolbar( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+ else if ( (nType== CTRL_MENUBAR) )
+ {
+ returnVal = NWPaintGTKMenubar( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+ else if( (nType == CTRL_MENU_POPUP)
+ && ( (nPart == PART_ENTIRE_CONTROL)
+ || (nPart == PART_MENU_ITEM)
+ || (nPart == PART_MENU_ITEM_CHECK_MARK)
+ || (nPart == PART_MENU_ITEM_RADIO_MARK)
+ )
+ )
+ {
+ returnVal = NWPaintGTKPopupMenu( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+ else if( (nType == CTRL_TOOLTIP) && (nPart == PART_ENTIRE_CONTROL) )
+ {
+ returnVal = NWPaintGTKTooltip( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+ else if( (nType == CTRL_PROGRESS) && (nPart == PART_ENTIRE_CONTROL) )
+ {
+ returnVal = NWPaintGTKProgress( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+ else if( (nType == CTRL_LISTNODE) && (nPart == PART_ENTIRE_CONTROL) )
+ {
+ returnVal = NWPaintGTKListNode( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+ else if( (nType == CTRL_LISTNET) && (nPart == PART_ENTIRE_CONTROL) )
+ {
+ // don't actually draw anything; gtk treeviews do not draw lines
+ returnVal = true;
+ }
+ else if( (nType == CTRL_SLIDER) )
+ {
+ returnVal = NWPaintGTKSlider( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
+ }
+
+ if( pixmap )
+ {
+ returnVal = NWRenderPixmapToScreen( pixmap, aPixmapRect ) && returnVal;
+ g_object_unref( pixmap );
+ }
+
+ return( returnVal );
+}
+
+BOOL GtkSalGraphics::drawNativeMixedStateCheck( ControlType nType,
+ ControlPart nPart,
+ const Region& rControlRegion,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const OUString& rCaption )
+{
+ // need to emulate something for mixed state
+
+ // do this via pixmap since some themes don't care for regions
+ bool bOldNeedPixmapPaint = bNeedPixmapPaint;
+ bNeedPixmapPaint = true;
+
+ Rectangle aCtrlRect = rControlRegion.GetBoundRect();
+ BOOL returnVal = FALSE;
+ SelectFont();
+
+ // draw upper half in off state
+ const_cast<ImplControlValue&>(aValue).setTristateVal( BUTTONVALUE_OFF );
+ XLIB_Region aRegion = XCreateRegion();
+ XRectangle aXRect = { aCtrlRect.Left(), aCtrlRect.Top(), aCtrlRect.GetWidth(), aCtrlRect.GetHeight() };
+ const unsigned short nH = aXRect.height/2;
+ aXRect.height -= nH;
+ XUnionRectWithRegion( &aXRect, aRegion, aRegion );
+ SetClipRegion( pFontGC_, aRegion );
+ XDestroyRegion( aRegion );
+
+ returnVal = drawNativeControl( nType, nPart, rControlRegion, nState, aValue, rCaption );
+
+ if( returnVal )
+ {
+ // draw lower half in on state
+ const_cast<ImplControlValue&>(aValue).setTristateVal( BUTTONVALUE_ON );
+ aXRect.y += nH;
+ aRegion = XCreateRegion();
+ XUnionRectWithRegion( &aXRect, aRegion, aRegion );
+ SetClipRegion( pFontGC_, aRegion );
+ XDestroyRegion( aRegion );
+ returnVal = drawNativeControl( nType, nPart, rControlRegion, nState, aValue, rCaption );
+ }
+
+ // clean up
+ bNeedPixmapPaint = bOldNeedPixmapPaint;
+ const_cast<ImplControlValue&>(aValue).setTristateVal( BUTTONVALUE_MIXED );
+ SetClipRegion( pFontGC_ );
+ return returnVal;
+}
+
+
+/*
+ * 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)
+ * rCaption: A caption or title string (like button text etc)
+ */
+BOOL GtkSalGraphics::drawNativeControlText( ControlType,
+ ControlPart,
+ const Region&,
+ 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)
+ * rCaption: A caption or title string (like button text etc)
+ */
+BOOL GtkSalGraphics::getNativeControlRegion( ControlType nType,
+ ControlPart nPart,
+ const Region& rControlRegion,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const OUString& rCaption,
+ Region &rNativeBoundingRegion,
+ Region &rNativeContentRegion )
+{
+ BOOL returnVal = FALSE;
+
+ if ( (nType==CTRL_PUSHBUTTON) && (nPart==PART_ENTIRE_CONTROL)
+ && (rControlRegion.GetBoundRect().GetWidth() > 16)
+ && (rControlRegion.GetBoundRect().GetHeight() > 16) )
+ {
+ rNativeBoundingRegion = NWGetButtonArea( m_nScreen, nType, nPart, rControlRegion.GetBoundRect(),
+ nState, aValue, rCaption );
+ rNativeContentRegion = rControlRegion;
+
+ returnVal = TRUE;
+ }
+ if ( (nType==CTRL_COMBOBOX) && ((nPart==PART_BUTTON_DOWN) || (nPart==PART_SUB_EDIT)) )
+ {
+ rNativeBoundingRegion = NWGetComboBoxButtonRect( m_nScreen, nType, nPart, rControlRegion.GetBoundRect(), nState,
+ aValue, rCaption );
+ rNativeContentRegion = rNativeBoundingRegion;
+
+ returnVal = TRUE;
+ }
+ if ( (nType==CTRL_SPINBOX) && ((nPart==PART_BUTTON_UP) || (nPart==PART_BUTTON_DOWN) || (nPart==PART_SUB_EDIT)) )
+ {
+
+ rNativeBoundingRegion = NWGetSpinButtonRect( m_nScreen, nType, nPart, rControlRegion.GetBoundRect(), nState,
+ aValue, rCaption );
+ rNativeContentRegion = rNativeBoundingRegion;
+
+ returnVal = TRUE;
+ }
+ if ( (nType==CTRL_LISTBOX) && ((nPart==PART_BUTTON_DOWN) || (nPart==PART_SUB_EDIT)) )
+ {
+ rNativeBoundingRegion = NWGetListBoxButtonRect( m_nScreen, nType, nPart, rControlRegion.GetBoundRect(), nState,
+ aValue, rCaption );
+ rNativeContentRegion = rNativeBoundingRegion;
+
+ returnVal = TRUE;
+ }
+ if ( (nType==CTRL_TOOLBAR) &&
+ ((nPart==PART_DRAW_BACKGROUND_HORZ) ||
+ (nPart==PART_DRAW_BACKGROUND_VERT) ||
+ (nPart==PART_THUMB_HORZ) ||
+ (nPart==PART_THUMB_VERT) ||
+ (nPart==PART_BUTTON)
+ ))
+ {
+ rNativeBoundingRegion = NWGetToolbarRect( m_nScreen, nType, nPart, rControlRegion.GetBoundRect(), nState, aValue, rCaption );
+ rNativeContentRegion = rNativeBoundingRegion;
+ returnVal = TRUE;
+ }
+ if ( (nType==CTRL_SCROLLBAR) && ((nPart==PART_BUTTON_LEFT) || (nPart==PART_BUTTON_RIGHT) ||
+ (nPart==PART_BUTTON_UP) || (nPart==PART_BUTTON_DOWN) ) )
+ {
+ rNativeBoundingRegion = NWGetScrollButtonRect( m_nScreen, nPart, rControlRegion.GetBoundRect() );
+ rNativeContentRegion = rNativeBoundingRegion;
+
+ returnVal = TRUE;
+ }
+ if( (nType == CTRL_MENUBAR) && (nPart == PART_ENTIRE_CONTROL) )
+ {
+ NWEnsureGTKMenubar( m_nScreen );
+ GtkRequisition aReq;
+ gtk_widget_size_request( gWidgetData[m_nScreen].gMenubarWidget, &aReq );
+ Rectangle aMenuBarRect = rControlRegion.GetBoundRect();
+ aMenuBarRect = Rectangle( aMenuBarRect.TopLeft(),
+ Size( aMenuBarRect.GetWidth(), aReq.height+1 ) );
+ rNativeBoundingRegion = Region( aMenuBarRect );
+ rNativeContentRegion = rNativeBoundingRegion;
+ returnVal = TRUE;
+ }
+ if( (nType == CTRL_MENU_POPUP) )
+ {
+ if( (nPart == PART_MENU_ITEM_CHECK_MARK) ||
+ (nPart == PART_MENU_ITEM_RADIO_MARK) )
+ {
+ NWEnsureGTKMenu( m_nScreen );
+
+ gint indicator_size = 0;
+ GtkWidget* pWidget = (nPart == PART_MENU_ITEM_CHECK_MARK) ?
+ gWidgetData[m_nScreen].gMenuItemCheckMenuWidget : gWidgetData[m_nScreen].gMenuItemRadioMenuWidget;
+ gtk_widget_style_get( pWidget,
+ "indicator_size", &indicator_size,
+ (char *)NULL );
+ rNativeBoundingRegion = rControlRegion;
+ Rectangle aIndicatorRect( Point( 0,
+ (rControlRegion.GetBoundRect().GetHeight()-indicator_size)/2),
+ Size( indicator_size, indicator_size ) );
+ rNativeContentRegion = Region( aIndicatorRect );
+ returnVal = TRUE;
+ }
+ }
+ if( (nType == CTRL_RADIOBUTTON || nType == CTRL_CHECKBOX) )
+ {
+ NWEnsureGTKRadio( m_nScreen );
+ NWEnsureGTKCheck( m_nScreen );
+ GtkWidget* widget = (nType == CTRL_RADIOBUTTON) ? gWidgetData[m_nScreen].gRadioWidget : gWidgetData[m_nScreen].gCheckWidget;
+ gint indicator_size, indicator_spacing;
+ gtk_widget_style_get( widget,
+ "indicator_size", &indicator_size,
+ "indicator_spacing", &indicator_spacing,
+ (char *)NULL);
+ indicator_size += 2*indicator_spacing; // guess overpaint of theme
+ rNativeBoundingRegion = rControlRegion;
+ Rectangle aIndicatorRect( Point( 0,
+ (rControlRegion.GetBoundRect().GetHeight()-indicator_size)/2),
+ Size( indicator_size, indicator_size ) );
+ rNativeContentRegion = Region( aIndicatorRect );
+ returnVal = TRUE;
+ }
+ if( (nType == CTRL_EDITBOX || nType == CTRL_SPINBOX) && nPart == PART_ENTIRE_CONTROL )
+ {
+ NWEnsureGTKEditBox( m_nScreen );
+ GtkWidget* widget = gWidgetData[m_nScreen].gEditBoxWidget;
+ GtkRequisition aReq;
+ gtk_widget_size_request( widget, &aReq );
+ Rectangle aEditRect = rControlRegion.GetBoundRect();
+ aEditRect = Rectangle( aEditRect.TopLeft(),
+ Size( aEditRect.GetWidth(), aReq.height+1 ) );
+ rNativeBoundingRegion = Region( aEditRect );
+ rNativeContentRegion = rNativeBoundingRegion;
+ returnVal = TRUE;
+ }
+ if( (nType == CTRL_SLIDER) && (nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT) )
+ {
+ NWEnsureGTKSlider( m_nScreen );
+ GtkWidget* widget = (nPart == PART_THUMB_HORZ) ? gWidgetData[m_nScreen].gHScale : gWidgetData[m_nScreen].gVScale;
+ gint slider_length = 10;
+ gint slider_width = 10;
+ gtk_widget_style_get( widget,
+ "slider-width", &slider_width,
+ "slider-length", &slider_length,
+ (char *)NULL);
+ Rectangle aRect( rControlRegion.GetBoundRect() );
+ if( nPart == PART_THUMB_HORZ )
+ {
+ aRect.Right() = aRect.Left() + slider_length - 1;
+ aRect.Bottom() = aRect.Top() + slider_width - 1;
+ }
+ else
+ {
+ aRect.Bottom() = aRect.Top() + slider_length - 1;
+ aRect.Right() = aRect.Left() + slider_width - 1;
+ }
+ rNativeBoundingRegion = rNativeContentRegion = Region( aRect );
+ returnVal = TRUE;
+ }
+
+ return( returnVal );
+}
+
+
+/************************************************************************
+ * Individual control drawing functions
+ ************************************************************************/
+BOOL GtkSalGraphics::NWPaintGTKButton(
+ GdkDrawable* gdkDrawable,
+ ControlType, ControlPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState, const ImplControlValue&,
+ const OUString& )
+{
+ GtkStateType stateType;
+ GtkShadowType shadowType;
+ gboolean interiorFocus;
+ gint focusWidth;
+ gint focusPad;
+ BOOL bDrawFocus = TRUE;
+ gint x, y, w, h;
+ GtkBorder aDefBorder;
+ GtkBorder* pBorder;
+ GdkRectangle clipRect;
+
+ NWEnsureGTKButton( m_nScreen );
+ NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
+
+ x = rControlRectangle.Left();
+ y = rControlRectangle.Top();
+ w = rControlRectangle.GetWidth();
+ h = rControlRectangle.GetHeight();
+
+ // Grab some button style attributes
+ gtk_widget_style_get( gWidgetData[m_nScreen].gBtnWidget, "focus-line-width", &focusWidth,
+ "focus-padding", &focusPad,
+ "interior_focus", &interiorFocus,
+ "default_border", &pBorder,
+ (char *)NULL );
+
+ // Make sure the border values exist, otherwise use some defaults
+ if ( pBorder )
+ {
+ NW_gtk_border_set_from_border( aDefBorder, pBorder );
+ gtk_border_free( pBorder );
+ }
+ else NW_gtk_border_set_from_border( aDefBorder, &aDefDefBorder );
+
+ // If the button is too small, don't ever draw focus or grab more space
+ if ( (w < 16) || (h < 16) )
+ bDrawFocus = FALSE;
+
+ NWSetWidgetState( gWidgetData[m_nScreen].gBtnWidget, nState, stateType );
+
+ gint xi = x, yi = y, wi = w, hi = h;
+ if ( (nState & CTRL_STATE_DEFAULT) && bDrawFocus )
+ {
+ xi += aDefBorder.left;
+ yi += aDefBorder.top;
+ wi -= aDefBorder.left + aDefBorder.right;
+ hi -= aDefBorder.top + aDefBorder.bottom;
+ }
+
+ if ( !interiorFocus && bDrawFocus )
+ {
+ xi += focusWidth + focusPad;
+ yi += focusWidth + focusPad;
+ wi -= 2 * (focusWidth + focusPad);
+ hi -= 2 * (focusWidth + focusPad);
+ }
+
+ for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it)
+ {
+ clipRect.x = it->Left();
+ clipRect.y = it->Top();
+ clipRect.width = it->GetWidth();
+ clipRect.height = it->GetHeight();
+
+ // Buttons must paint opaque since some themes have alpha-channel enabled buttons
+ gtk_paint_flat_box( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable, GTK_STATE_NORMAL, GTK_SHADOW_NONE,
+ &clipRect, m_pWindow, "base", x, y, w, h );
+
+ if ( (nState & CTRL_STATE_DEFAULT) && (GTK_BUTTON(gWidgetData[m_nScreen].gBtnWidget)->relief == GTK_RELIEF_NORMAL) )
+ {
+ gtk_paint_box( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable, GTK_STATE_NORMAL, GTK_SHADOW_IN,
+ &clipRect, gWidgetData[m_nScreen].gBtnWidget, "buttondefault", x, y, w, h );
+ }
+
+ if ( (GTK_BUTTON(gWidgetData[m_nScreen].gBtnWidget)->relief != GTK_RELIEF_NONE)
+ || (nState & CTRL_STATE_PRESSED)
+ || (nState & CTRL_STATE_ROLLOVER) )
+ {
+ gtk_paint_box( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable, stateType, shadowType,
+ &clipRect, gWidgetData[m_nScreen].gBtnWidget, "button", xi, yi, wi, hi );
+ }
+ }
+#if 0 // VCL draws focus rects
+ // Draw focus rect
+ if ( (nState & CTRL_STATE_FOCUSED) && (nState & CTRL_STATE_ENABLED) && bDrawFocus )
+ {
+ if (interiorFocus)
+ {
+ x += gWidgetData[m_nScreen].gBtnWidget->style->xthickness + focusPad;
+ y += gWidgetData[m_nScreen].gBtnWidget->style->ythickness + focusPad;
+ w -= 2 * (gWidgetData[m_nScreen].gBtnWidget->style->xthickness + focusPad);
+ h -= 2 * (gWidgetData[m_nScreen].gBtnWidget->style->xthickness + focusPad);
+ }
+ else
+ {
+ x -= focusWidth + focusPad;
+ y -= focusWidth + focusPad;
+ w += 2 * (focusWidth + focusPad);
+ h += 2 * (focusWidth + focusPad);
+ }
+ if ( !interiorFocus )
+ gtk_paint_focus( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable, stateType, &clipRect,
+ gWidgetData[m_nScreen].gBtnWidget, "button", x, y, w, h );
+ }
+#endif
+
+ return( TRUE );
+}
+
+static Rectangle NWGetButtonArea( int nScreen,
+ ControlType, ControlPart, Rectangle aAreaRect, ControlState nState,
+ const ImplControlValue&, const OUString& )
+{
+ gboolean interiorFocus;
+ gint focusWidth;
+ gint focusPad;
+ GtkBorder aDefBorder;
+ GtkBorder * pBorder;
+ BOOL bDrawFocus = TRUE;
+ Rectangle aRect;
+ gint x, y, w, h;
+
+ NWEnsureGTKButton( nScreen );
+ gtk_widget_style_get( gWidgetData[nScreen].gBtnWidget,
+ "focus-line-width", &focusWidth,
+ "focus-padding", &focusPad,
+ "interior_focus", &interiorFocus,
+ "default_border", &pBorder,
+ (char *)NULL );
+
+ // Make sure the border values exist, otherwise use some defaults
+ if ( pBorder )
+ {
+ NW_gtk_border_set_from_border( aDefBorder, pBorder );
+ gtk_border_free( pBorder );
+ }
+ else NW_gtk_border_set_from_border( aDefBorder, &aDefDefBorder );
+
+ x = aAreaRect.Left();
+ y = aAreaRect.Top();
+ w = aAreaRect.GetWidth();
+ h = aAreaRect.GetHeight();
+
+ // If the button is too small, don't ever draw focus or grab more space
+ if ( (w < 16) || (h < 16) )
+ bDrawFocus = FALSE;
+
+ if ( (nState & CTRL_STATE_DEFAULT) && bDrawFocus )
+ {
+ x -= aDefBorder.left;
+ y -= aDefBorder.top;
+ w += aDefBorder.left + aDefBorder.right;
+ h += aDefBorder.top + aDefBorder.bottom;
+ }
+
+ aRect = Rectangle( Point( x, y ), Size( w, h ) );
+
+ return( aRect );
+}
+
+//-------------------------------------
+
+BOOL GtkSalGraphics::NWPaintGTKRadio( GdkDrawable* gdkDrawable,
+ ControlType, ControlPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const OUString& )
+{
+ GtkStateType stateType;
+ GtkShadowType shadowType;
+ BOOL isChecked = (aValue.getTristateVal()==BUTTONVALUE_ON);
+ gint x, y;
+ GdkRectangle clipRect;
+
+ NWEnsureGTKButton( m_nScreen );
+ NWEnsureGTKRadio( m_nScreen );
+ NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
+
+ gint indicator_size;
+ gtk_widget_style_get( gWidgetData[m_nScreen].gRadioWidget, "indicator_size", &indicator_size, (char *)NULL);
+
+ x = rControlRectangle.Left() + (rControlRectangle.GetWidth()-indicator_size)/2;
+ y = rControlRectangle.Top() + (rControlRectangle.GetHeight()-indicator_size)/2;
+
+ // Set the shadow based on if checked or not so we get a freakin checkmark.
+ shadowType = isChecked ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
+ NWSetWidgetState( gWidgetData[m_nScreen].gRadioWidget, nState, stateType );
+ NWSetWidgetState( gWidgetData[m_nScreen].gRadioWidgetSibling, nState, stateType );
+
+ // GTK enforces radio groups, so that if we don't have 2 buttons in the group,
+ // the single button will always be active. So we have to have 2 buttons.
+
+ // #i59666# set the members directly where we should use
+ // gtk_toggle_button_set_active. reason: there are animated themes
+ // which are in active state only after a while leading to painting
+ // intermediate states between active/inactive. Let's hope that
+ // GtkToggleButtone stays binary compatible.
+ if (!isChecked)
+ GTK_TOGGLE_BUTTON(gWidgetData[m_nScreen].gRadioWidgetSibling)->active = TRUE;
+ GTK_TOGGLE_BUTTON(gWidgetData[m_nScreen].gRadioWidget)->active = isChecked;
+
+ for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
+ {
+ clipRect.x = it->Left();
+ clipRect.y = it->Top();
+ clipRect.width = it->GetWidth();
+ clipRect.height = it->GetHeight();
+
+ gtk_paint_option( gWidgetData[m_nScreen].gRadioWidget->style, gdkDrawable, stateType, shadowType,
+ &clipRect, gWidgetData[m_nScreen].gRadioWidget, "radiobutton",
+ x, y, indicator_size, indicator_size );
+ }
+
+ return( TRUE );
+}
+
+//-------------------------------------
+
+BOOL GtkSalGraphics::NWPaintGTKCheck( GdkDrawable* gdkDrawable,
+ ControlType, ControlPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const OUString& )
+{
+ GtkStateType stateType;
+ GtkShadowType shadowType;
+ BOOL isChecked = (aValue.getTristateVal()==BUTTONVALUE_ON) ? TRUE : FALSE;
+ GdkRectangle clipRect;
+ gint x,y;
+
+ NWEnsureGTKButton( m_nScreen );
+ NWEnsureGTKCheck( m_nScreen );
+ NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
+
+ gint indicator_size;
+ gtk_widget_style_get( gWidgetData[m_nScreen].gCheckWidget, "indicator_size", &indicator_size, (char *)NULL);
+
+ x = rControlRectangle.Left() + (rControlRectangle.GetWidth()-indicator_size)/2;
+ y = rControlRectangle.Top() + (rControlRectangle.GetHeight()-indicator_size)/2;
+
+ // Set the shadow based on if checked or not so we get a checkmark.
+ shadowType = isChecked ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
+ NWSetWidgetState( gWidgetData[m_nScreen].gCheckWidget, nState, stateType );
+ GTK_TOGGLE_BUTTON(gWidgetData[m_nScreen].gCheckWidget)->active = isChecked;
+
+ for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
+ {
+ clipRect.x = it->Left();
+ clipRect.y = it->Top();
+ clipRect.width = it->GetWidth();
+ clipRect.height = it->GetHeight();
+
+ gtk_paint_check( gWidgetData[m_nScreen].gCheckWidget->style, gdkDrawable, stateType, shadowType,
+ &clipRect, gWidgetData[m_nScreen].gCheckWidget, "checkbutton",
+ x, y, indicator_size, indicator_size );
+ }
+
+ return( TRUE );
+}
+
+//-------------------------------------
+static void NWCalcArrowRect( const Rectangle& rButton, Rectangle& rArrow )
+{
+ // Size the arrow appropriately
+ Size aSize( rButton.GetWidth()/2, rButton.GetHeight()/2 );
+ rArrow.SetSize( aSize );
+
+ rArrow.SetPos( Point(
+ rButton.Left() + ( rButton.GetWidth() - rArrow.GetWidth() ) / 2,
+ rButton.Top() + ( rButton.GetHeight() - rArrow.GetHeight() ) / 2
+ ) );
+}
+
+BOOL GtkSalGraphics::NWPaintGTKScrollbar( ControlType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList&,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const OUString& )
+{
+ ScrollbarValue* pScrollbarVal = (ScrollbarValue *)(aValue.getOptionalVal());
+ GdkPixmap* pixmap = NULL;
+ Rectangle pixmapRect, scrollbarRect;
+ GtkStateType stateType;
+ GtkShadowType shadowType;
+ GtkScrollbar * scrollbarWidget;
+ GtkStyle * style;
+ GtkAdjustment* scrollbarValues = NULL;
+ GtkOrientation scrollbarOrientation;
+ Rectangle thumbRect = pScrollbarVal->maThumbRect;
+ Rectangle button11BoundRect = pScrollbarVal->maButton1Rect; // backward
+ Rectangle button22BoundRect = pScrollbarVal->maButton2Rect; // forward
+ Rectangle button12BoundRect = pScrollbarVal->maButton1Rect; // secondary forward
+ Rectangle button21BoundRect = pScrollbarVal->maButton2Rect; // secondary backward
+ GtkArrowType button1Type; // backward
+ GtkArrowType button2Type; // forward
+ gchar * scrollbarTagH = (gchar *) "hscrollbar";
+ gchar * scrollbarTagV = (gchar *) "vscrollbar";
+ gchar * scrollbarTag = NULL;
+ Rectangle arrowRect;
+ gint slider_width = 0;
+ gint stepper_size = 0;
+ gint stepper_spacing = 0;
+ gint trough_border = 0;
+ gint min_slider_length = 0;
+ gint vShim = 0;
+ gint hShim = 0;
+ gint x,y,w,h;
+
+ // make controlvalue rectangles relative to area
+ thumbRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() );
+ button11BoundRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() );
+ button22BoundRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() );
+ button12BoundRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() );
+ button21BoundRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() );
+
+ NWEnsureGTKButton( m_nScreen );
+ NWEnsureGTKScrollbars( m_nScreen );
+ NWEnsureGTKArrow( m_nScreen );
+
+ // Find the overall bounding rect of the control
+ pixmapRect = rControlRectangle;
+ pixmapRect.SetSize( Size( pixmapRect.GetWidth() + 1,
+ pixmapRect.GetHeight() + 1 ) );
+ scrollbarRect = pixmapRect;
+
+ if ( (scrollbarRect.GetWidth() <= 1) || (scrollbarRect.GetHeight() <= 1) )
+ return( TRUE );
+
+ // Grab some button style attributes
+ gtk_widget_style_get( gWidgetData[m_nScreen].gScrollHorizWidget,
+ "slider_width", &slider_width,
+ "stepper_size", &stepper_size,
+ "trough_border", &trough_border,
+ "stepper_spacing", &stepper_spacing,
+ "min_slider_length", &min_slider_length, (char *)NULL );
+ gboolean has_forward;
+ gboolean has_forward2;
+ gboolean has_backward;
+ gboolean has_backward2;
+
+ gtk_widget_style_get( gWidgetData[m_nScreen].gScrollHorizWidget, "has-forward-stepper", &has_forward,
+ "has-secondary-forward-stepper", &has_forward2,
+ "has-backward-stepper", &has_backward,
+ "has-secondary-backward-stepper", &has_backward2, (char *)NULL );
+ gint magic = trough_border ? 1 : 0;
+ gint nFirst = 0;
+
+ if ( has_backward ) nFirst += 1;
+ if ( has_forward2 ) nFirst += 1;
+
+ if ( nPart == PART_DRAW_BACKGROUND_HORZ )
+ {
+ unsigned int sliderHeight = slider_width + (trough_border * 2);
+ vShim = (pixmapRect.GetHeight() - sliderHeight) / 2;
+
+ scrollbarRect.Move( 0, vShim );
+ scrollbarRect.SetSize( Size( scrollbarRect.GetWidth(), sliderHeight ) );
+
+ scrollbarWidget = GTK_SCROLLBAR( gWidgetData[m_nScreen].gScrollHorizWidget );
+ scrollbarOrientation = GTK_ORIENTATION_HORIZONTAL;
+ scrollbarTag = scrollbarTagH;
+ button1Type = GTK_ARROW_LEFT;
+ button2Type = GTK_ARROW_RIGHT;
+
+ if ( has_backward )
+ {
+ button12BoundRect.Move( stepper_size - trough_border,
+ (scrollbarRect.GetHeight() - slider_width) / 2 );
+ }
+
+ button11BoundRect.Move( trough_border, (scrollbarRect.GetHeight() - slider_width) / 2 );
+ button11BoundRect.SetSize( Size( stepper_size, slider_width ) );
+ button12BoundRect.SetSize( Size( stepper_size, slider_width ) );
+
+ if ( has_backward2 )
+ {
+ button22BoundRect.Move( stepper_size+(trough_border+1)/2, (scrollbarRect.GetHeight() - slider_width) / 2 );
+ button21BoundRect.Move( (trough_border+1)/2, (scrollbarRect.GetHeight() - slider_width) / 2 );
+ }
+ else
+ {
+ button22BoundRect.Move( (trough_border+1)/2, (scrollbarRect.GetHeight() - slider_width) / 2 );
+ }
+
+ button21BoundRect.SetSize( Size( stepper_size, slider_width ) );
+ button22BoundRect.SetSize( Size( stepper_size, slider_width ) );
+
+ thumbRect.Bottom() = thumbRect.Top() + slider_width - 1;
+ // Make sure the thumb is at least the default width (so we don't get tiny thumbs),
+ // but if the VCL gives us a size smaller than the theme's default thumb size,
+ // honor the VCL size
+#if 0
+ if ( (thumbRect.GetWidth() < min_slider_length)
+ && ((scrollbarRect.GetWidth()-button1BoundRect.GetWidth()-button2BoundRect.GetWidth()) > min_slider_length) )
+ thumbRect.SetSize( Size( min_slider_length, thumbRect.GetHeight() ) );
+#endif
+
+ thumbRect.Right() += magic;
+ // Center vertically in the track
+ thumbRect.Move( 0, (scrollbarRect.GetHeight() - slider_width) / 2 );
+ }
+ else
+ {
+ unsigned int sliderWidth = slider_width + (trough_border * 2);
+ hShim = (pixmapRect.GetWidth() - sliderWidth) / 2;
+
+ scrollbarRect.Move( hShim, 0 );
+ scrollbarRect.SetSize( Size( sliderWidth, scrollbarRect.GetHeight() ) );
+
+ scrollbarWidget = GTK_SCROLLBAR( gWidgetData[m_nScreen].gScrollVertWidget );
+ scrollbarOrientation = GTK_ORIENTATION_VERTICAL;
+ scrollbarTag = scrollbarTagV;
+ button1Type = GTK_ARROW_UP;
+ button2Type = GTK_ARROW_DOWN;
+
+ if ( has_backward )
+ {
+ button12BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2,
+ stepper_size + trough_border );
+ }
+ button11BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, trough_border );
+ button11BoundRect.SetSize( Size( slider_width, stepper_size ) );
+ button12BoundRect.SetSize( Size( slider_width, stepper_size ) );
+
+ if ( has_backward2 )
+ {
+ button22BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, stepper_size+(trough_border+1)/2 );
+ button21BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, (trough_border+1)/2 );
+ }
+ else
+ {
+ button22BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, (trough_border+1)/2 );
+ }
+
+ button21BoundRect.SetSize( Size( slider_width, stepper_size ) );
+ button22BoundRect.SetSize( Size( slider_width, stepper_size ) );
+
+ thumbRect.Right() = thumbRect.Left() + slider_width - 1;
+#if 0
+ // Make sure the thumb is at least the default width (so we don't get tiny thumbs),
+ // but if the VCL gives us a size smaller than the theme's default thumb size,
+ // honor the VCL size
+ if ( (thumbRect.GetHeight() < min_slider_length)
+ && ((scrollbarRect.GetHeight()-button1BoundRect.GetHeight()-button2BoundRect.GetHeight()) > min_slider_length) )
+ thumbRect.SetSize( Size( thumbRect.GetWidth(), min_slider_length ) );
+#endif
+
+ thumbRect.Bottom() += magic;
+ // Center horizontally in the track
+ thumbRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, 0 );
+ }
+
+ BOOL has_slider = ( thumbRect.GetWidth() > 0 && thumbRect.GetHeight() > 0 );
+
+ scrollbarValues = gtk_range_get_adjustment( GTK_RANGE(scrollbarWidget) );
+ if ( scrollbarValues == NULL )
+ scrollbarValues = GTK_ADJUSTMENT( gtk_adjustment_new(0, 0, 0, 0, 0, 0) );
+ if ( nPart == PART_DRAW_BACKGROUND_HORZ )
+ {
+ scrollbarValues->lower = pScrollbarVal->mnMin;
+ scrollbarValues->upper = pScrollbarVal->mnMax;
+ scrollbarValues->value = pScrollbarVal->mnCur;
+ scrollbarValues->page_size = scrollbarRect.GetWidth() / 2;
+ }
+ else
+ {
+ scrollbarValues->lower = pScrollbarVal->mnMin;
+ scrollbarValues->upper = pScrollbarVal->mnMax;
+ scrollbarValues->value = pScrollbarVal->mnCur;
+ scrollbarValues->page_size = scrollbarRect.GetHeight() / 2;
+ }
+ gtk_adjustment_changed( scrollbarValues );
+
+ // as multiple paints are required for the scrollbar
+ // painting them directly to the window flickers
+ pixmap = NWGetPixmapFromScreen( pixmapRect );
+ if( ! pixmap )
+ return FALSE;
+ x = y = 0;
+
+ w = pixmapRect.GetWidth();
+ h = pixmapRect.GetHeight();
+
+ GdkDrawable* const &gdkDrawable = GDK_DRAWABLE( pixmap );
+ GdkRectangle* gdkRect = NULL;
+
+ NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
+ NWSetWidgetState( GTK_WIDGET(scrollbarWidget), nState, stateType );
+ NWSetWidgetState( gWidgetData[m_nScreen].gBtnWidget, nState, stateType );
+ style = GTK_WIDGET( scrollbarWidget )->style;
+
+ // ----------------- TROUGH
+ gtk_paint_flat_box( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable,
+ GTK_STATE_NORMAL, GTK_SHADOW_NONE, gdkRect,
+ m_pWindow, "base", x, y,
+ w, h );
+ gtk_paint_box( style, gdkDrawable, GTK_STATE_ACTIVE, GTK_SHADOW_IN,
+ gdkRect, GTK_WIDGET(scrollbarWidget), "trough",
+ x, y,
+ scrollbarRect.GetWidth(), scrollbarRect.GetHeight() );
+
+ if ( nState & CTRL_STATE_FOCUSED )
+ {
+ gtk_paint_focus( style, gdkDrawable, GTK_STATE_ACTIVE,
+ gdkRect, GTK_WIDGET(scrollbarWidget), "trough",
+ x, y,
+ scrollbarRect.GetWidth(), scrollbarRect.GetHeight() );
+ }
+
+ // ----------------- THUMB
+ if ( has_slider )
+ {
+ NWConvertVCLStateToGTKState( pScrollbarVal->mnThumbState, &stateType, &shadowType );
+ if ( pScrollbarVal->mnThumbState & CTRL_STATE_PRESSED ) stateType = GTK_STATE_PRELIGHT;
+ gtk_paint_slider( style, gdkDrawable, stateType, GTK_SHADOW_OUT,
+ gdkRect, GTK_WIDGET(scrollbarWidget), "slider",
+ x+hShim+thumbRect.Left(), y+vShim+thumbRect.Top(),
+ thumbRect.GetWidth(), thumbRect.GetHeight(), scrollbarOrientation );
+ }
+ // ----------------- BUTTON 1 //
+ if ( has_backward )
+ {
+ NWConvertVCLStateToGTKState( pScrollbarVal->mnButton1State, &stateType, &shadowType );
+ if ( stateType == GTK_STATE_INSENSITIVE ) stateType = GTK_STATE_NORMAL;
+ gtk_paint_box( style, gdkDrawable, stateType, shadowType,
+ gdkRect, GTK_WIDGET(scrollbarWidget), "stepper",
+ x+hShim+button11BoundRect.Left(), y+vShim+button11BoundRect.Top(),
+ button11BoundRect.GetWidth(), button11BoundRect.GetHeight() );
+ // ----------------- ARROW 1
+ NWCalcArrowRect( button11BoundRect, arrowRect );
+ gtk_paint_arrow( style, gdkDrawable, stateType, shadowType,
+ gdkRect, GTK_WIDGET(scrollbarWidget), scrollbarTag, button1Type, TRUE,
+ x+hShim+arrowRect.Left(), y+vShim+arrowRect.Top(),
+ arrowRect.GetWidth(), arrowRect.GetHeight() );
+ }
+ if ( has_forward2 )
+ {
+ NWConvertVCLStateToGTKState( pScrollbarVal->mnButton2State, &stateType, &shadowType );
+ if ( stateType == GTK_STATE_INSENSITIVE ) stateType = GTK_STATE_NORMAL;
+ gtk_paint_box( style, gdkDrawable, stateType, shadowType,
+ gdkRect, GTK_WIDGET(scrollbarWidget), "stepper",
+ x+hShim+button12BoundRect.Left(), y+vShim+button12BoundRect.Top(),
+ button12BoundRect.GetWidth(), button12BoundRect.GetHeight() );
+ // ----------------- ARROW 1
+ NWCalcArrowRect( button12BoundRect, arrowRect );
+ gtk_paint_arrow( style, gdkDrawable, stateType, shadowType,
+ gdkRect, GTK_WIDGET(scrollbarWidget), scrollbarTag, button2Type, TRUE,
+ x+hShim+arrowRect.Left(), y+vShim+arrowRect.Top(),
+ arrowRect.GetWidth(), arrowRect.GetHeight() );
+ }
+ // ----------------- BUTTON 2
+ if ( has_backward2 )
+ {
+ NWConvertVCLStateToGTKState( pScrollbarVal->mnButton1State, &stateType, &shadowType );
+ if ( stateType == GTK_STATE_INSENSITIVE ) stateType = GTK_STATE_NORMAL;
+ gtk_paint_box( style, gdkDrawable, stateType, shadowType, gdkRect,
+ GTK_WIDGET(scrollbarWidget), "stepper",
+ x+hShim+button21BoundRect.Left(), y+vShim+button21BoundRect.Top(),
+ button21BoundRect.GetWidth(), button21BoundRect.GetHeight() );
+ // ----------------- ARROW 2
+ NWCalcArrowRect( button21BoundRect, arrowRect );
+ gtk_paint_arrow( style, gdkDrawable, stateType, shadowType,
+ gdkRect, GTK_WIDGET(scrollbarWidget), scrollbarTag, button1Type, TRUE,
+ x+hShim+arrowRect.Left(), y+vShim+arrowRect.Top(),
+ arrowRect.GetWidth(), arrowRect.GetHeight() );
+ }
+ if ( has_forward )
+ {
+ NWConvertVCLStateToGTKState( pScrollbarVal->mnButton2State, &stateType, &shadowType );
+ if ( stateType == GTK_STATE_INSENSITIVE ) stateType = GTK_STATE_NORMAL;
+ gtk_paint_box( style, gdkDrawable, stateType, shadowType, gdkRect,
+ GTK_WIDGET(scrollbarWidget), "stepper",
+ x+hShim+button22BoundRect.Left(), y+vShim+button22BoundRect.Top(),
+ button22BoundRect.GetWidth(), button22BoundRect.GetHeight() );
+ // ----------------- ARROW 2
+ NWCalcArrowRect( button22BoundRect, arrowRect );
+ gtk_paint_arrow( style, gdkDrawable, stateType, shadowType,
+ gdkRect, GTK_WIDGET(scrollbarWidget), scrollbarTag, button2Type, TRUE,
+ x+hShim+arrowRect.Left(), y+vShim+arrowRect.Top(),
+ arrowRect.GetWidth(), arrowRect.GetHeight() );
+ }
+
+ if( !NWRenderPixmapToScreen(pixmap, pixmapRect) )
+ {
+ g_object_unref( pixmap );
+ return( FALSE );
+ }
+ g_object_unref( pixmap );
+
+ return( TRUE );
+}
+
+//---
+
+static Rectangle NWGetScrollButtonRect( int nScreen, ControlPart nPart, Rectangle aAreaRect )
+{
+ gint slider_width;
+ gint stepper_size;
+ gint stepper_spacing;
+ gint trough_border;
+
+ NWEnsureGTKScrollbars( nScreen );
+
+ // Grab some button style attributes
+ gtk_widget_style_get( gWidgetData[nScreen].gScrollHorizWidget,
+ "slider-width", &slider_width,
+ "stepper-size", &stepper_size,
+ "trough-border", &trough_border,
+ "stepper-spacing", &stepper_spacing, (char *)NULL );
+
+ gboolean has_forward;
+ gboolean has_forward2;
+ gboolean has_backward;
+ gboolean has_backward2;
+
+ gtk_widget_style_get( gWidgetData[nScreen].gScrollHorizWidget,
+ "has-forward-stepper", &has_forward,
+ "has-secondary-forward-stepper", &has_forward2,
+ "has-backward-stepper", &has_backward,
+ "has-secondary-backward-stepper", &has_backward2, (char *)NULL );
+ gint buttonWidth;
+ gint buttonHeight;
+ Rectangle buttonRect;
+
+ gint nFirst = 0;
+ gint nSecond = 0;
+
+ if ( has_forward ) nSecond += 1;
+ if ( has_forward2 ) nFirst += 1;
+ if ( has_backward ) nFirst += 1;
+ if ( has_backward2 ) nSecond += 1;
+
+ if ( ( nPart == PART_BUTTON_UP ) || ( nPart == PART_BUTTON_DOWN ) )
+ {
+ buttonWidth = slider_width + 2 * trough_border;
+ buttonHeight = stepper_size + trough_border + stepper_spacing;
+ }
+ else
+ {
+ buttonWidth = stepper_size + trough_border + stepper_spacing;
+ buttonHeight = slider_width + 2 * trough_border;
+ }
+
+ if ( nPart == PART_BUTTON_UP )
+ {
+ buttonHeight *= nFirst;
+ buttonHeight -= 1;
+ buttonRect.setX( aAreaRect.Left() );
+ buttonRect.setY( aAreaRect.Top() );
+ }
+ else if ( nPart == PART_BUTTON_LEFT )
+ {
+ buttonWidth *= nFirst;
+ buttonWidth -= 1;
+ buttonRect.setX( aAreaRect.Left() );
+ buttonRect.setY( aAreaRect.Top() );
+ }
+ else if ( nPart == PART_BUTTON_DOWN )
+ {
+ buttonHeight *= nSecond;
+ buttonRect.setX( aAreaRect.Left() );
+ buttonRect.setY( aAreaRect.Top() + aAreaRect.GetHeight() - buttonHeight );
+ }
+ else if ( nPart == PART_BUTTON_RIGHT )
+ {
+ buttonWidth *= nSecond;
+ buttonRect.setX( aAreaRect.Left() + aAreaRect.GetWidth() - buttonWidth );
+ buttonRect.setY( aAreaRect.Top() );
+ }
+
+ buttonRect.SetSize( Size( buttonWidth, buttonHeight ) );
+
+ return( buttonRect );
+}
+
+//-------------------------------------
+
+BOOL GtkSalGraphics::NWPaintGTKEditBox( GdkDrawable* gdkDrawable,
+ ControlType nType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const OUString& rCaption )
+{
+ Rectangle pixmapRect;
+ GdkRectangle clipRect;
+
+ // Find the overall bounding rect of the buttons's drawing area,
+ // plus its actual draw rect excluding adornment
+ pixmapRect = NWGetEditBoxPixmapRect( m_nScreen, nType, nPart, rControlRectangle,
+ nState, aValue, rCaption );
+ for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
+ {
+ clipRect.x = it->Left();
+ clipRect.y = it->Top();
+ clipRect.width = it->GetWidth();
+ clipRect.height = it->GetHeight();
+
+ NWPaintOneEditBox( m_nScreen, gdkDrawable, &clipRect, nType, nPart, pixmapRect, nState, aValue, rCaption );
+ }
+
+ return( TRUE );
+}
+
+
+/* Take interior/exterior focus into account and return
+ * the bounding rectangle of the edit box including
+ * any focus requirements.
+ */
+static Rectangle NWGetEditBoxPixmapRect(int nScreen,
+ ControlType,
+ ControlPart,
+ Rectangle aAreaRect,
+ ControlState,
+ const ImplControlValue&,
+ const OUString& )
+{
+ Rectangle pixmapRect = aAreaRect;
+ gboolean interiorFocus;
+ gint focusWidth;
+
+ NWEnsureGTKEditBox( nScreen );
+
+ // Grab some entry style attributes
+ gtk_widget_style_get( gWidgetData[nScreen].gEditBoxWidget,
+ "focus-line-width", &focusWidth,
+ "interior-focus", &interiorFocus, (char *)NULL );
+
+ if ( !interiorFocus )
+ {
+ pixmapRect.Move( -(focusWidth), -(focusWidth) );
+ pixmapRect.SetSize( Size( pixmapRect.GetWidth() + (2*(focusWidth)),
+ pixmapRect.GetHeight() + (2*(focusWidth)) ) );
+ }
+
+ return( pixmapRect );
+}
+
+
+/* Paint a GTK Entry widget into the specified GdkPixmap.
+ * All coordinates should be local to the Pixmap, NOT
+ * screen/window coordinates.
+ */
+static void NWPaintOneEditBox( int nScreen,
+ GdkDrawable * gdkDrawable,
+ GdkRectangle * gdkRect,
+ ControlType nType,
+ ControlPart,
+ Rectangle aEditBoxRect,
+ ControlState nState,
+ const ImplControlValue&,
+ const OUString& )
+{
+ GtkStateType stateType;
+ GtkShadowType shadowType;
+ GtkWidget *widget;
+
+ NWEnsureGTKButton( nScreen );
+ NWEnsureGTKEditBox( nScreen );
+ NWEnsureGTKSpinButton( nScreen );
+ NWEnsureGTKCombo( nScreen );
+ NWEnsureGTKScrolledWindow( nScreen );
+ NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
+
+ /* border's shadowType for gtk entries is always GTK_SHADOW_IN (see gtkentry.c)
+ shadowType = GTK_SHADOW_IN;
+ */
+
+ switch ( nType )
+ {
+ case CTRL_SPINBOX:
+ widget = gWidgetData[nScreen].gSpinButtonWidget;
+ break;
+
+ case CTRL_MULTILINE_EDITBOX:
+ widget = gWidgetData[nScreen].gScrolledWindowWidget;
+ break;
+ case CTRL_COMBOBOX:
+ widget = GTK_COMBO(gWidgetData[nScreen].gComboWidget)->entry;
+ break;
+
+ default:
+ widget = gWidgetData[nScreen].gEditBoxWidget;
+ break;
+ }
+
+ if ( stateType == GTK_STATE_PRELIGHT )
+ stateType = GTK_STATE_NORMAL;
+
+ // Blueprint needs to paint entry_bg with a Button widget, not an Entry widget to get
+ // a nice white (or whatever default color) background
+ GtkWidget* pBGWidget = widget;
+ if( GtkSalGraphics::bNeedButtonStyleAsEditBackgroundWorkaround )
+ {
+ NWSetWidgetState( gWidgetData[nScreen].gBtnWidget, nState, stateType );
+ pBGWidget = gWidgetData[nScreen].gBtnWidget;
+ }
+ NWSetWidgetState( widget, nState, stateType );
+
+ gtk_paint_flat_box( pBGWidget->style, gdkDrawable, stateType, GTK_SHADOW_NONE,
+ gdkRect, pBGWidget, "entry_bg",
+ aEditBoxRect.Left(), aEditBoxRect.Top(),
+ aEditBoxRect.GetWidth(), aEditBoxRect.GetHeight() );
+ gtk_paint_shadow( widget->style, gdkDrawable, GTK_STATE_NORMAL, GTK_SHADOW_IN,
+ gdkRect, widget, "entry",
+ aEditBoxRect.Left(), aEditBoxRect.Top(),
+ aEditBoxRect.GetWidth(), aEditBoxRect.GetHeight() );
+
+}
+
+
+
+//-------------------------------------
+
+BOOL GtkSalGraphics::NWPaintGTKSpinBox( ControlType nType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList&,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const OUString& rCaption )
+{
+ GdkPixmap * pixmap;
+ Rectangle pixmapRect;
+ GtkStateType stateType;
+ GtkShadowType shadowType;
+ SpinbuttonValue * pSpinVal = (SpinbuttonValue *)(aValue.getOptionalVal());
+ Rectangle upBtnRect;
+ ControlPart upBtnPart = PART_BUTTON_UP;
+ ControlState upBtnState = CTRL_STATE_ENABLED;
+ Rectangle downBtnRect;
+ ControlPart downBtnPart = PART_BUTTON_DOWN;
+ ControlState downBtnState = CTRL_STATE_ENABLED;
+
+ NWEnsureGTKButton( m_nScreen );
+ NWEnsureGTKSpinButton( m_nScreen );
+ NWEnsureGTKArrow( m_nScreen );
+
+ NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
+
+ if ( pSpinVal )
+ {
+ upBtnPart = pSpinVal->mnUpperPart;
+ upBtnState = pSpinVal->mnUpperState;
+
+ downBtnPart = pSpinVal->mnLowerPart;
+ downBtnState = pSpinVal->mnLowerState;
+ }
+
+ // CTRL_SPINBUTTONS pass their area in pSpinVal, not in rControlRectangle
+ if ( nType == CTRL_SPINBUTTONS )
+ {
+ if ( !pSpinVal )
+ {
+ std::fprintf( stderr, "Tried to draw CTRL_SPINBUTTONS, but the SpinButtons data structure didn't exist!\n" );
+ return( false );
+ }
+ pixmapRect = pSpinVal->maUpperRect;
+ pixmapRect.Union( pSpinVal->maLowerRect );
+ }
+ else
+ pixmapRect = rControlRectangle;
+
+
+ pixmap = NWGetPixmapFromScreen( pixmapRect );
+ if ( !pixmap )
+ return( FALSE );
+
+ upBtnRect = NWGetSpinButtonRect( m_nScreen, nType, upBtnPart, pixmapRect, upBtnState, aValue, rCaption );
+ downBtnRect = NWGetSpinButtonRect( m_nScreen, nType, downBtnPart, pixmapRect, downBtnState, aValue, rCaption );
+
+ if ( (nType==CTRL_SPINBOX) && (nPart!=PART_ALL_BUTTONS) )
+ {
+ // Draw an edit field for SpinBoxes and ComboBoxes
+ Rectangle aEditBoxRect( pixmapRect );
+ aEditBoxRect.SetSize( Size( upBtnRect.Left() - pixmapRect.Left(), aEditBoxRect.GetHeight() ) );
+ aEditBoxRect.setX( 0 );
+ aEditBoxRect.setY( 0 );
+
+ NWPaintOneEditBox( m_nScreen, pixmap, NULL, nType, nPart, aEditBoxRect, nState, aValue, rCaption );
+ }
+
+ NWSetWidgetState( gWidgetData[m_nScreen].gSpinButtonWidget, nState, stateType );
+ gtk_widget_style_get( gWidgetData[m_nScreen].gSpinButtonWidget, "shadow_type", &shadowType, (char *)NULL );
+
+ if ( shadowType != GTK_SHADOW_NONE )
+ {
+ Rectangle shadowRect( upBtnRect );
+
+ shadowRect.Union( downBtnRect );
+ gtk_paint_box( gWidgetData[m_nScreen].gSpinButtonWidget->style, pixmap, GTK_STATE_NORMAL, shadowType, NULL,
+ gWidgetData[m_nScreen].gSpinButtonWidget, "spinbutton",
+ (shadowRect.Left() - pixmapRect.Left()), (shadowRect.Top() - pixmapRect.Top()),
+ shadowRect.GetWidth(), shadowRect.GetHeight() );
+ }
+
+ NWPaintOneSpinButton( m_nScreen, pixmap, nType, upBtnPart, pixmapRect, upBtnState, aValue, rCaption );
+ NWPaintOneSpinButton( m_nScreen, pixmap, nType, downBtnPart, pixmapRect, downBtnState, aValue, rCaption );
+
+ if( !NWRenderPixmapToScreen(pixmap, pixmapRect) )
+ {
+ g_object_unref( pixmap );
+ return( FALSE );
+ }
+
+ g_object_unref( pixmap );
+ return( TRUE );
+}
+
+//---
+
+static Rectangle NWGetSpinButtonRect( int nScreen,
+ ControlType,
+ ControlPart nPart,
+ Rectangle aAreaRect,
+ ControlState,
+ const ImplControlValue&,
+ const OUString& )
+{
+ gint buttonSize;
+ Rectangle buttonRect;
+
+ NWEnsureGTKSpinButton( nScreen );
+
+ buttonSize = MAX( PANGO_PIXELS( pango_font_description_get_size(GTK_WIDGET(gWidgetData[nScreen].gSpinButtonWidget)->style->font_desc) ),
+ MIN_SPIN_ARROW_WIDTH );
+ buttonSize -= buttonSize % 2 - 1; /* force odd */
+ buttonRect.SetSize( Size( buttonSize + 2 * gWidgetData[nScreen].gSpinButtonWidget->style->xthickness,
+ buttonRect.GetHeight() ) );
+ buttonRect.setX( aAreaRect.Left() + (aAreaRect.GetWidth() - buttonRect.GetWidth()) );
+ if ( nPart == PART_BUTTON_UP )
+ {
+ buttonRect.setY( aAreaRect.Top() );
+ buttonRect.Bottom() = buttonRect.Top() + (aAreaRect.GetHeight() / 2);
+ }
+ else if( nPart == PART_BUTTON_DOWN )
+ {
+ buttonRect.setY( aAreaRect.Top() + (aAreaRect.GetHeight() / 2) );
+ buttonRect.Bottom() = aAreaRect.Bottom(); // cover area completely
+ }
+ else
+ {
+ buttonRect.Right() = buttonRect.Left()-1;
+ buttonRect.Left() = aAreaRect.Left();
+ buttonRect.Top() = aAreaRect.Top();
+ buttonRect.Bottom() = aAreaRect.Bottom();
+ }
+
+ return( buttonRect );
+}
+
+//---
+
+static void NWPaintOneSpinButton( int nScreen,
+ GdkPixmap* pixmap,
+ ControlType nType,
+ ControlPart nPart,
+ Rectangle aAreaRect,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const OUString& rCaption )
+{
+ Rectangle buttonRect;
+ GtkStateType stateType;
+ GtkShadowType shadowType;
+ Rectangle arrowRect;
+ gint arrowSize;
+
+ NWEnsureGTKSpinButton( nScreen );
+ NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
+
+ buttonRect = NWGetSpinButtonRect( nScreen, nType, nPart, aAreaRect, nState, aValue, rCaption );
+
+ NWSetWidgetState( gWidgetData[nScreen].gSpinButtonWidget, nState, stateType );
+ gtk_paint_box( gWidgetData[nScreen].gSpinButtonWidget->style, pixmap, stateType, shadowType, NULL, gWidgetData[nScreen].gSpinButtonWidget,
+ (nPart == PART_BUTTON_UP) ? "spinbutton_up" : "spinbutton_down",
+ (buttonRect.Left() - aAreaRect.Left()), (buttonRect.Top() - aAreaRect.Top()),
+ buttonRect.GetWidth(), buttonRect.GetHeight() );
+
+ arrowSize = (buttonRect.GetWidth() - (2 * gWidgetData[nScreen].gSpinButtonWidget->style->xthickness)) - 4;
+ arrowSize -= arrowSize % 2 - 1; /* force odd */
+ arrowRect.SetSize( Size( arrowSize, arrowSize ) );
+ arrowRect.setX( buttonRect.Left() + (buttonRect.GetWidth() - arrowRect.GetWidth()) / 2 );
+ if ( nPart == PART_BUTTON_UP )
+ arrowRect.setY( buttonRect.Top() + (buttonRect.GetHeight() - arrowRect.GetHeight()) / 2 + 1);
+ else
+ arrowRect.setY( buttonRect.Top() + (buttonRect.GetHeight() - arrowRect.GetHeight()) / 2 - 1);
+
+ gtk_paint_arrow( gWidgetData[nScreen].gSpinButtonWidget->style, pixmap, stateType, GTK_SHADOW_OUT, NULL, gWidgetData[nScreen].gSpinButtonWidget,
+ "spinbutton", (nPart == PART_BUTTON_UP) ? GTK_ARROW_UP : GTK_ARROW_DOWN, TRUE,
+ (arrowRect.Left() - aAreaRect.Left()), (arrowRect.Top() - aAreaRect.Top()),
+ arrowRect.GetWidth(), arrowRect.GetHeight() );
+}
+
+
+//-------------------------------------
+
+BOOL GtkSalGraphics::NWPaintGTKComboBox( GdkDrawable* gdkDrawable,
+ ControlType nType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const OUString& rCaption )
+{
+ Rectangle pixmapRect;
+ Rectangle buttonRect;
+ GtkStateType stateType;
+ GtkShadowType shadowType;
+ Rectangle arrowRect;
+ gint x,y;
+ GdkRectangle clipRect;
+
+ NWEnsureGTKButton( m_nScreen );
+ NWEnsureGTKArrow( m_nScreen );
+ NWEnsureGTKCombo( m_nScreen );
+ NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
+
+ // Find the overall bounding rect of the buttons's drawing area,
+ // plus its actual draw rect excluding adornment
+ pixmapRect = rControlRectangle;
+ x = rControlRectangle.Left();
+ y = rControlRectangle.Top();
+
+ NWSetWidgetState( gWidgetData[m_nScreen].gBtnWidget, nState, stateType );
+ NWSetWidgetState( gWidgetData[m_nScreen].gComboWidget, nState, stateType );
+ NWSetWidgetState( gWidgetData[m_nScreen].gArrowWidget, nState, stateType );
+
+ buttonRect = NWGetComboBoxButtonRect( m_nScreen, nType, PART_BUTTON_DOWN, pixmapRect, nState, aValue, rCaption );
+ if( nPart == PART_BUTTON_DOWN )
+ buttonRect.Left() += 1;
+
+ Rectangle aEditBoxRect( pixmapRect );
+ aEditBoxRect.SetSize( Size( pixmapRect.GetWidth() - buttonRect.GetWidth(), aEditBoxRect.GetHeight() ) );
+
+ #define ARROW_EXTENT 0.7
+ arrowRect.SetSize( Size( (gint)(MIN_ARROW_SIZE * ARROW_EXTENT),
+ (gint)(MIN_ARROW_SIZE * ARROW_EXTENT) ) );
+ arrowRect.SetPos( Point( buttonRect.Left() + (gint)((buttonRect.GetWidth() - arrowRect.GetWidth()) / 2),
+ buttonRect.Top() + (gint)((buttonRect.GetHeight() - arrowRect.GetHeight()) / 2) ) );
+
+ for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
+ {
+ clipRect.x = it->Left();
+ clipRect.y = it->Top();
+ clipRect.width = it->GetWidth();
+ clipRect.height = it->GetHeight();
+
+ if( nPart == PART_ENTIRE_CONTROL )
+ NWPaintOneEditBox( m_nScreen, gdkDrawable, &clipRect, nType, nPart, aEditBoxRect,
+ nState, aValue, rCaption );
+
+ // Buttons must paint opaque since some themes have alpha-channel enabled buttons
+ gtk_paint_flat_box( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable, GTK_STATE_NORMAL, GTK_SHADOW_NONE,
+ &clipRect, m_pWindow, "base",
+ x+(buttonRect.Left() - pixmapRect.Left()),
+ y+(buttonRect.Top() - pixmapRect.Top()),
+ buttonRect.GetWidth(), buttonRect.GetHeight() );
+ gtk_paint_box( GTK_COMBO(gWidgetData[m_nScreen].gComboWidget)->button->style, gdkDrawable, stateType, shadowType,
+ &clipRect, GTK_COMBO(gWidgetData[m_nScreen].gComboWidget)->button, "button",
+ x+(buttonRect.Left() - pixmapRect.Left()),
+ y+(buttonRect.Top() - pixmapRect.Top()),
+ buttonRect.GetWidth(), buttonRect.GetHeight() );
+
+ gtk_paint_arrow( gWidgetData[m_nScreen].gArrowWidget->style, gdkDrawable, stateType, shadowType,
+ &clipRect, gWidgetData[m_nScreen].gArrowWidget, "arrow", GTK_ARROW_DOWN, TRUE,
+ x+(arrowRect.Left() - pixmapRect.Left()), y+(arrowRect.Top() - pixmapRect.Top()),
+ arrowRect.GetWidth(), arrowRect.GetHeight() );
+ }
+
+ return( TRUE );
+}
+
+//----
+
+static Rectangle NWGetComboBoxButtonRect( int nScreen,
+ ControlType,
+ ControlPart nPart,
+ Rectangle aAreaRect,
+ ControlState,
+ const ImplControlValue&,
+ const OUString& )
+{
+ Rectangle aButtonRect;
+ gint nArrowWidth;
+ gint nButtonWidth;
+ gint nFocusWidth;
+ gint nFocusPad;
+
+ NWEnsureGTKArrow( nScreen );
+
+ // Grab some button style attributes
+ gtk_widget_style_get( gWidgetData[nScreen].gDropdownWidget,
+ "focus-line-width", &nFocusWidth,
+ "focus-padding", &nFocusPad, (char *)NULL );
+
+ nArrowWidth = MIN_ARROW_SIZE + (GTK_MISC(gWidgetData[nScreen].gArrowWidget)->xpad * 2);
+ nButtonWidth = nArrowWidth +
+ ((BTN_CHILD_SPACING + gWidgetData[nScreen].gDropdownWidget->style->xthickness) * 2)
+ + (2 * (nFocusWidth+nFocusPad));
+ if( nPart == PART_BUTTON_DOWN )
+ {
+ aButtonRect.SetSize( Size( nButtonWidth, aAreaRect.GetHeight() ) );
+ aButtonRect.SetPos( Point( aAreaRect.Left() + aAreaRect.GetWidth() - nButtonWidth,
+ aAreaRect.Top() ) );
+ }
+ else if( nPart == PART_SUB_EDIT )
+ {
+ NWEnsureGTKCombo( nScreen );
+
+ gint adjust_x = GTK_CONTAINER(gWidgetData[nScreen].gComboWidget)->border_width +
+ nFocusWidth +
+ nFocusPad;
+ gint adjust_y = adjust_x + gWidgetData[nScreen].gComboWidget->style->ythickness;
+ adjust_x += gWidgetData[nScreen].gComboWidget->style->xthickness;
+ aButtonRect.SetSize( Size( aAreaRect.GetWidth() - nButtonWidth - 2 * adjust_x,
+ aAreaRect.GetHeight() - 2 * adjust_y ) );
+ Point aEditPos = aAreaRect.TopLeft();
+ aEditPos.X() += adjust_x;
+ aEditPos.Y() += adjust_y;
+ aButtonRect.SetPos( aEditPos );
+ }
+
+ return( aButtonRect );
+}
+
+//-------------------------------------
+
+
+
+BOOL GtkSalGraphics::NWPaintGTKTabItem( ControlType nType, ControlPart,
+ const Rectangle& rControlRectangle,
+ const clipList&,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const OUString& )
+{
+ GdkPixmap * pixmap;
+ Rectangle pixmapRect;
+ Rectangle tabRect;
+ TabitemValue * pTabitemValue = (TabitemValue *)(aValue.getOptionalVal());
+ GtkStateType stateType;
+ GtkShadowType shadowType;
+ if( ! gWidgetData[ m_nScreen ].gCacheTabItems )
+ {
+ gWidgetData[ m_nScreen ].gCacheTabItems = new NWPixmapCache( m_nScreen );
+ gWidgetData[ m_nScreen ].gCacheTabPages = new NWPixmapCache( m_nScreen );
+ }
+ NWPixmapCache& aCacheItems = *gWidgetData[ m_nScreen ].gCacheTabItems;
+ NWPixmapCache& aCachePage = *gWidgetData[ m_nScreen ].gCacheTabPages;
+
+ if( !aCacheItems.GetSize() )
+ aCacheItems.SetSize( 20 );
+ if( !aCachePage.GetSize() )
+ aCachePage.SetSize( 1 );
+
+ if ( !pTabitemValue && (nType==CTRL_TAB_ITEM) )
+ {
+ std::fprintf( stderr, "NWPaintGTKTabItem() received a NULL TabitemValue. Cannot draw native tab\n" );
+ return( false );
+ }
+
+ NWEnsureGTKButton( m_nScreen );
+ NWEnsureGTKNotebook( m_nScreen );
+ NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
+
+ // Find the overall bounding rect of the buttons's drawing area,
+ // plus its actual draw rect excluding adornment
+ pixmapRect = rControlRectangle;
+ if ( nType == CTRL_TAB_ITEM )
+ {
+ if ( !pTabitemValue->isFirst() )
+ {
+ // GTK+ tabs overlap on the right edge (the top tab obscures the
+ // left edge of the tab right "below" it, so adjust the rectangle
+ // to draw tabs slightly large so the overlap happens
+ pixmapRect.Move( -2, 0 );
+ pixmapRect.SetSize( Size( pixmapRect.GetWidth() + 2, pixmapRect.GetHeight() ) );
+ }
+ if ( nState & CTRL_STATE_SELECTED )
+ {
+ // In GTK+, the selected tab is 2px taller than all other tabs
+ pixmapRect.Move( 0, -2 );
+ pixmapRect.Bottom() += 2;
+ tabRect = pixmapRect;
+ // Only draw over 1 pixel of the tab pane that this tab is drawn on top of.
+ tabRect.Bottom() -= 1;
+ }
+ else
+ tabRect = pixmapRect;
+
+ // Allow the tab to draw a right border if needed
+ tabRect.Right() -= 1;
+
+ // #129732# avoid degenerate cases which might lead to crashes
+ if( tabRect.GetWidth() <= 1 || tabRect.GetHeight() <= 1 )
+ return false;
+ }
+
+ if( nType == CTRL_TAB_ITEM )
+ {
+ if( aCacheItems.Find( nType, nState, pixmapRect, &pixmap ) )
+ return NWRenderPixmapToScreen( pixmap, pixmapRect );
+ }
+ else
+ {
+ if( aCachePage.Find( nType, nState, pixmapRect, &pixmap ) )
+ return NWRenderPixmapToScreen( pixmap, pixmapRect );
+ }
+
+
+// gtk_widget_set_state( gWidgetData[m_nScreen].gNotebookWidget, stateType );
+
+ pixmap = gdk_pixmap_new( NULL, pixmapRect.GetWidth(), pixmapRect.GetHeight(),
+ GetX11SalData()->GetDisplay()->GetVisual( m_nScreen ).GetDepth() );
+ GdkRectangle paintRect;
+ paintRect.x = paintRect.y = 0;
+ paintRect.width = pixmapRect.GetWidth();
+ paintRect.height = pixmapRect.GetHeight();
+
+ gtk_paint_flat_box( m_pWindow->style, pixmap, GTK_STATE_NORMAL,
+ GTK_SHADOW_NONE, &paintRect, m_pWindow, "base", 0, 0, -1, -1);
+
+ NWSetWidgetState( gWidgetData[m_nScreen].gNotebookWidget, nState, stateType );
+
+ switch( nType )
+ {
+ case CTRL_TAB_BODY:
+ break;
+
+ case CTRL_FIXEDBORDER:
+ case CTRL_TAB_PANE:
+ gtk_paint_box_gap( gWidgetData[m_nScreen].gNotebookWidget->style, pixmap, GTK_STATE_NORMAL, GTK_SHADOW_OUT, NULL, gWidgetData[m_nScreen].gNotebookWidget,
+ (char *)"notebook", 0, 0, pixmapRect.GetWidth(), pixmapRect.GetHeight(), GTK_POS_TOP, 0, 0 );
+ break;
+
+ case CTRL_TAB_ITEM:
+ stateType = ( nState & CTRL_STATE_SELECTED ) ? GTK_STATE_NORMAL : GTK_STATE_ACTIVE;
+
+ gtk_paint_extension( gWidgetData[m_nScreen].gNotebookWidget->style, pixmap, stateType, GTK_SHADOW_OUT, NULL, gWidgetData[m_nScreen].gNotebookWidget,
+ (char *)"tab", (tabRect.Left() - pixmapRect.Left()), (tabRect.Top() - pixmapRect.Top()),
+ tabRect.GetWidth(), tabRect.GetHeight(), GTK_POS_BOTTOM );
+
+ if ( nState & CTRL_STATE_SELECTED )
+ {
+ gtk_paint_flat_box( gWidgetData[m_nScreen].gNotebookWidget->style, pixmap, stateType, GTK_SHADOW_NONE, NULL, m_pWindow,
+ (char *)"base", 0, (pixmapRect.GetHeight() - 1), pixmapRect.GetWidth(), 1 );
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // Crux seems to think it can make the pane without a left edge
+ if ( nType == CTRL_FIXEDBORDER )
+ pixmapRect.Move( 1, 0 );
+
+ // cache data
+ if( nType == CTRL_TAB_ITEM )
+ aCacheItems.Fill( nType, nState, pixmapRect, pixmap );
+ else
+ aCachePage.Fill( nType, nState, pixmapRect, pixmap );
+
+ BOOL bSuccess = NWRenderPixmapToScreen(pixmap, pixmapRect);
+ g_object_unref( pixmap );
+ return bSuccess;
+}
+
+//-------------------------------------
+
+BOOL GtkSalGraphics::NWPaintGTKListBox( GdkDrawable* gdkDrawable,
+ ControlType nType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const OUString& rCaption )
+{
+ Rectangle pixmapRect;
+ Rectangle widgetRect;
+ Rectangle aIndicatorRect;
+ GtkStateType stateType;
+ GtkShadowType shadowType;
+ gint bInteriorFocus;
+ gint nFocusLineWidth;
+ gint nFocusPadding;
+ gint x,y;
+ GdkRectangle clipRect;
+
+ NWEnsureGTKButton( m_nScreen );
+ NWEnsureGTKOptionMenu( m_nScreen );
+ NWEnsureGTKScrolledWindow( m_nScreen );
+ NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
+
+ // Find the overall bounding rect of the buttons's drawing area,
+ // plus its actual draw rect excluding adornment
+ pixmapRect = rControlRectangle;
+ if ( nPart == PART_WINDOW )
+ {
+ // Make the widget a _bit_ bigger
+ pixmapRect.SetPos( Point( pixmapRect.Left() - 1,
+ pixmapRect.Top() - 1 ) );
+ pixmapRect.SetSize( Size( pixmapRect.GetWidth() + 2,
+ pixmapRect.GetHeight() + 2 ) );
+ }
+
+ widgetRect = pixmapRect;
+ x = pixmapRect.Left();
+ y = pixmapRect.Top();
+
+ // set up references to correct drawable and cliprect
+ NWSetWidgetState( gWidgetData[m_nScreen].gBtnWidget, nState, stateType );
+ NWSetWidgetState( gWidgetData[m_nScreen].gOptionMenuWidget, nState, stateType );
+ NWSetWidgetState( gWidgetData[m_nScreen].gScrolledWindowWidget, nState, stateType );
+
+ if ( nPart != PART_WINDOW )
+ {
+ gtk_widget_style_get( gWidgetData[m_nScreen].gOptionMenuWidget,
+ "interior_focus", &bInteriorFocus,
+ "focus_line_width", &nFocusLineWidth,
+ "focus_padding", &nFocusPadding,
+ (char *)NULL);
+ }
+
+ for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
+ {
+ clipRect.x = it->Left();
+ clipRect.y = it->Top();
+ clipRect.width = it->GetWidth();
+ clipRect.height = it->GetHeight();
+
+ if ( nPart != PART_WINDOW )
+ {
+ // Listboxes must paint opaque since some themes have alpha-channel enabled bodies
+ gtk_paint_flat_box( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable, GTK_STATE_NORMAL, GTK_SHADOW_NONE,
+ &clipRect, m_pWindow, "base", x, y,
+ pixmapRect.GetWidth(), pixmapRect.GetHeight() );
+ gtk_paint_box( gWidgetData[m_nScreen].gOptionMenuWidget->style, gdkDrawable, stateType, shadowType, &clipRect,
+ gWidgetData[m_nScreen].gOptionMenuWidget, "optionmenu",
+ x+(widgetRect.Left() - pixmapRect.Left()),
+ y+(widgetRect.Top() - pixmapRect.Top()),
+ widgetRect.GetWidth(), widgetRect.GetHeight() );
+ aIndicatorRect = NWGetListBoxIndicatorRect( m_nScreen, nType, nPart, widgetRect, nState,
+ aValue, rCaption );
+ gtk_paint_tab( gWidgetData[m_nScreen].gOptionMenuWidget->style, gdkDrawable, stateType, shadowType, &clipRect,
+ gWidgetData[m_nScreen].gOptionMenuWidget, "optionmenutab",
+ x+(aIndicatorRect.Left() - pixmapRect.Left()),
+ y+(aIndicatorRect.Top() - pixmapRect.Top()),
+ aIndicatorRect.GetWidth(), aIndicatorRect.GetHeight() );
+ }
+ else
+ {
+ shadowType = GTK_SHADOW_IN;
+
+ gtk_paint_shadow( gWidgetData[m_nScreen].gScrolledWindowWidget->style, gdkDrawable, GTK_STATE_NORMAL, shadowType,
+ &clipRect, gWidgetData[m_nScreen].gScrolledWindowWidget, "scrolled_window",
+ x+(widgetRect.Left() - pixmapRect.Left()), y+(widgetRect.Top() - pixmapRect.Top()),
+ widgetRect.GetWidth(), widgetRect.GetHeight() );
+ }
+ }
+
+ return( TRUE );
+}
+
+BOOL GtkSalGraphics::NWPaintGTKToolbar(
+ GdkDrawable* gdkDrawable,
+ ControlType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState, const ImplControlValue& aValue,
+ const OUString& )
+{
+ GtkStateType stateType;
+ GtkShadowType shadowType;
+ gint x, y, w, h;
+ gint g_x=0, g_y=0, g_w=10, g_h=10;
+ bool bPaintButton = true;
+ GtkWidget* pButtonWidget = gWidgetData[m_nScreen].gToolbarButtonWidget;
+ const gchar* pButtonDetail = "button";
+ GdkRectangle clipRect;
+
+ NWEnsureGTKToolbar( m_nScreen );
+ if( nPart == PART_BUTTON ) // toolbar buttons cannot focus in gtk
+ nState &= ~CTRL_STATE_FOCUSED;
+ NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
+
+ x = rControlRectangle.Left();
+ y = rControlRectangle.Top();
+ w = rControlRectangle.GetWidth();
+ h = rControlRectangle.GetHeight();
+
+ // handle toolbar
+ if( nPart == PART_DRAW_BACKGROUND_HORZ || nPart == PART_DRAW_BACKGROUND_VERT )
+ {
+ NWSetWidgetState( gWidgetData[m_nScreen].gToolbarWidget, nState, stateType );
+
+ GTK_WIDGET_UNSET_FLAGS( gWidgetData[m_nScreen].gToolbarWidget, GTK_SENSITIVE );
+ if ( nState & CTRL_STATE_ENABLED )
+ GTK_WIDGET_SET_FLAGS( gWidgetData[m_nScreen].gToolbarWidget, GTK_SENSITIVE );
+
+ if( nPart == PART_DRAW_BACKGROUND_HORZ )
+ gtk_toolbar_set_orientation( GTK_TOOLBAR(gWidgetData[m_nScreen].gToolbarWidget), GTK_ORIENTATION_HORIZONTAL );
+ else
+ gtk_toolbar_set_orientation( GTK_TOOLBAR(gWidgetData[m_nScreen].gToolbarWidget), GTK_ORIENTATION_VERTICAL );
+ }
+ // handle grip
+ else if( nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT )
+ {
+ NWSetWidgetState( gWidgetData[m_nScreen].gHandleBoxWidget, nState, stateType );
+
+ GTK_WIDGET_UNSET_FLAGS( gWidgetData[m_nScreen].gHandleBoxWidget, GTK_SENSITIVE );
+ if ( nState & CTRL_STATE_ENABLED )
+ GTK_WIDGET_SET_FLAGS( gWidgetData[m_nScreen].gHandleBoxWidget, GTK_SENSITIVE );
+
+ gtk_handle_box_set_shadow_type( GTK_HANDLE_BOX(gWidgetData[m_nScreen].gHandleBoxWidget), shadowType );
+
+ // evaluate grip rect
+ ToolbarValue* pVal = (ToolbarValue*)aValue.getOptionalVal();
+ if( pVal )
+ {
+ g_x = pVal->maGripRect.Left();
+ g_y = pVal->maGripRect.Top();
+ g_w = pVal->maGripRect.GetWidth();
+ g_h = pVal->maGripRect.GetHeight();
+ }
+ }
+ // handle button
+ else if( nPart == PART_BUTTON )
+ {
+ bPaintButton =
+ (GTK_BUTTON(pButtonWidget)->relief != GTK_RELIEF_NONE)
+ || (nState & CTRL_STATE_PRESSED)
+ || (nState & CTRL_STATE_ROLLOVER);
+ if( aValue.getTristateVal() == BUTTONVALUE_ON )
+ {
+ pButtonWidget = gWidgetData[m_nScreen].gToolbarToggleWidget;
+ shadowType = GTK_SHADOW_IN;
+ // special case stateType value for depressed toggle buttons
+ // cf. gtk+/gtk/gtktogglebutton.c (gtk_toggle_button_update_state)
+ if( ! (nState & (CTRL_STATE_PRESSED|CTRL_STATE_ROLLOVER)) )
+ stateType = GTK_STATE_ACTIVE;
+ pButtonDetail = "togglebutton";
+ bPaintButton = true;
+ }
+
+ NWSetWidgetState( pButtonWidget, nState, stateType );
+ gtk_widget_ensure_style( pButtonWidget );
+ }
+
+ for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
+ {
+ clipRect.x = it->Left();
+ clipRect.y = it->Top();
+ clipRect.width = it->GetWidth();
+ clipRect.height = it->GetHeight();
+
+ // draw toolbar
+ if( nPart == PART_DRAW_BACKGROUND_HORZ || nPart == PART_DRAW_BACKGROUND_VERT )
+ {
+ gtk_paint_flat_box( gWidgetData[m_nScreen].gToolbarWidget->style,
+ gdkDrawable,
+ (GtkStateType)GTK_STATE_NORMAL,
+ GTK_SHADOW_NONE,
+ &clipRect,
+ gWidgetData[m_nScreen].gToolbarWidget,
+ "base",
+ x, y, w, h );
+ gtk_paint_box( gWidgetData[m_nScreen].gToolbarWidget->style,
+ gdkDrawable,
+ stateType,
+ shadowType,
+ &clipRect,
+ gWidgetData[m_nScreen].gToolbarWidget,
+ "toolbar",
+ x, y, w, h );
+ }
+ // draw grip
+ else if( nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT )
+ {
+ gtk_paint_handle( gWidgetData[m_nScreen].gHandleBoxWidget->style,
+ gdkDrawable,
+ GTK_STATE_NORMAL,
+ GTK_SHADOW_OUT,
+ &clipRect,
+ gWidgetData[m_nScreen].gHandleBoxWidget,
+ "handlebox",
+ g_x, g_y, g_w, g_h,
+ nPart == PART_THUMB_HORZ ?
+ GTK_ORIENTATION_HORIZONTAL :
+ GTK_ORIENTATION_VERTICAL
+ );
+ }
+ // draw button
+ else if( nPart == PART_BUTTON )
+ {
+ if( bPaintButton )
+ {
+ gtk_paint_box( pButtonWidget->style, gdkDrawable,
+ stateType,
+ shadowType,
+ &clipRect,
+ pButtonWidget, pButtonDetail, x, y, w, h );
+ }
+ }
+ }
+
+ return( TRUE );
+}
+
+//----
+
+BOOL GtkSalGraphics::NWPaintGTKMenubar(
+ GdkDrawable* gdkDrawable,
+ ControlType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState, const ImplControlValue&,
+ const OUString& )
+{
+ GtkStateType stateType;
+ GtkShadowType shadowType;
+ GtkShadowType selected_shadow_type = GTK_SHADOW_OUT;
+ gint x, y, w, h;
+ GdkRectangle clipRect;
+
+ NWEnsureGTKMenubar( m_nScreen );
+ NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
+
+ x = rControlRectangle.Left();
+ y = rControlRectangle.Top();
+ w = rControlRectangle.GetWidth();
+ h = rControlRectangle.GetHeight();
+
+ if( nPart == PART_MENU_ITEM )
+ {
+ if( nState & (CTRL_STATE_SELECTED|CTRL_STATE_ROLLOVER) )
+ {
+ gtk_widget_style_get( gWidgetData[m_nScreen].gMenuItemMenubarWidget,
+ "selected_shadow_type", &selected_shadow_type,
+ (char *)NULL);
+ }
+ }
+
+ for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
+ {
+ clipRect.x = it->Left();
+ clipRect.y = it->Top();
+ clipRect.width = it->GetWidth();
+ clipRect.height = it->GetHeight();
+
+ // handle Menubar
+ if( nPart == PART_ENTIRE_CONTROL )
+ {
+ NWSetWidgetState( gWidgetData[m_nScreen].gMenubarWidget, nState, stateType );
+
+ GTK_WIDGET_UNSET_FLAGS( gWidgetData[m_nScreen].gMenubarWidget, GTK_SENSITIVE );
+ if ( nState & CTRL_STATE_ENABLED )
+ GTK_WIDGET_SET_FLAGS( gWidgetData[m_nScreen].gMenubarWidget, GTK_SENSITIVE );
+
+ // #118704# for translucent menubar styles paint background first
+ gtk_paint_flat_box( gWidgetData[m_nScreen].gMenubarWidget->style,
+ gdkDrawable,
+ GTK_STATE_NORMAL,
+ GTK_SHADOW_NONE,
+ &clipRect,
+ GTK_WIDGET(m_pWindow),
+ "base",
+ x, y, w, h );
+ gtk_paint_box( gWidgetData[m_nScreen].gMenubarWidget->style,
+ gdkDrawable,
+ stateType,
+ shadowType,
+ &clipRect,
+ gWidgetData[m_nScreen].gMenubarWidget,
+ "menubar",
+ x, y, w, h );
+ }
+ else if( nPart == PART_MENU_ITEM )
+ {
+ if( nState & (CTRL_STATE_SELECTED|CTRL_STATE_ROLLOVER) )
+ {
+ gtk_paint_box( gWidgetData[m_nScreen].gMenuItemMenubarWidget->style,
+ gdkDrawable,
+ GTK_STATE_PRELIGHT,
+ selected_shadow_type,
+ &clipRect,
+ gWidgetData[m_nScreen].gMenuItemMenubarWidget,
+ "menuitem",
+ x, y, w, h);
+ }
+ }
+ }
+
+ return( TRUE );
+}
+
+BOOL GtkSalGraphics::NWPaintGTKPopupMenu(
+ GdkDrawable* gdkDrawable,
+ ControlType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState, const ImplControlValue&,
+ const OUString& )
+{
+ // #i50745# gtk does not draw disabled menu entries (and crux theme
+ // even crashes), draw them using vcl functionality.
+ if( nPart == PART_MENU_ITEM && ! (nState & CTRL_STATE_ENABLED) )
+ return FALSE;
+
+ GtkStateType stateType;
+ GtkShadowType shadowType;
+ GtkShadowType selected_shadow_type = GTK_SHADOW_OUT;
+ gint x, y, w, h;
+ GdkRectangle clipRect;
+
+ NWEnsureGTKMenu( m_nScreen );
+ NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
+
+ x = rControlRectangle.Left();
+ y = rControlRectangle.Top();
+ w = rControlRectangle.GetWidth();
+ h = rControlRectangle.GetHeight();
+
+ if( nPart == PART_MENU_ITEM &&
+ ( nState & (CTRL_STATE_SELECTED|CTRL_STATE_ROLLOVER) ) )
+ {
+ gtk_widget_style_get( gWidgetData[m_nScreen].gMenuItemMenuWidget,
+ "selected_shadow_type", &selected_shadow_type,
+ (char *)NULL);
+ }
+
+ NWSetWidgetState( gWidgetData[m_nScreen].gMenuWidget, nState, stateType );
+
+ GTK_WIDGET_UNSET_FLAGS( gWidgetData[m_nScreen].gMenuWidget, GTK_SENSITIVE );
+ if ( nState & CTRL_STATE_ENABLED )
+ GTK_WIDGET_SET_FLAGS( gWidgetData[m_nScreen].gMenuWidget, GTK_SENSITIVE );
+
+ for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
+ {
+ clipRect.x = it->Left();
+ clipRect.y = it->Top();
+ clipRect.width = it->GetWidth();
+ clipRect.height = it->GetHeight();
+
+ if( nPart == PART_ENTIRE_CONTROL )
+ {
+ // #118704# for translucent menubar styles paint background first
+ gtk_paint_flat_box( gWidgetData[m_nScreen].gMenuWidget->style,
+ gdkDrawable,
+ GTK_STATE_NORMAL,
+ GTK_SHADOW_NONE,
+ &clipRect,
+ GTK_WIDGET(m_pWindow),
+ "base",
+ x, y, w, h );
+ gtk_paint_box( gWidgetData[m_nScreen].gMenuWidget->style,
+ gdkDrawable,
+ GTK_STATE_NORMAL,
+ GTK_SHADOW_OUT,
+ &clipRect,
+ gWidgetData[m_nScreen].gMenuWidget,
+ "menu",
+ x, y, w, h );
+ }
+ else if( nPart == PART_MENU_ITEM )
+ {
+ if( nState & (CTRL_STATE_SELECTED|CTRL_STATE_ROLLOVER) )
+ {
+ if( nState & CTRL_STATE_ENABLED )
+ gtk_paint_box( gWidgetData[m_nScreen].gMenuItemMenuWidget->style,
+ gdkDrawable,
+ GTK_STATE_PRELIGHT,
+ selected_shadow_type,
+ &clipRect,
+ gWidgetData[m_nScreen].gMenuItemMenuWidget,
+ "menuitem",
+ x, y, w, h);
+ }
+ }
+ else if( nPart == PART_MENU_ITEM_CHECK_MARK || nPart == PART_MENU_ITEM_RADIO_MARK )
+ {
+ GtkWidget* pWidget = (nPart == PART_MENU_ITEM_CHECK_MARK) ?
+ gWidgetData[m_nScreen].gMenuItemCheckMenuWidget :
+ gWidgetData[m_nScreen].gMenuItemRadioMenuWidget;
+
+ GtkStateType nStateType = GTK_STATE_NORMAL;
+ GtkShadowType nShadowType;
+
+ if ( nState & CTRL_STATE_SELECTED )
+ nStateType = GTK_STATE_PRELIGHT;
+
+ NWSetWidgetState( pWidget, nState, nStateType );
+
+ if ( nState & CTRL_STATE_PRESSED )
+ nShadowType = GTK_SHADOW_IN;
+ else
+ nShadowType = GTK_SHADOW_OUT;
+
+ if ( nPart == PART_MENU_ITEM_CHECK_MARK )
+ {
+ gtk_paint_check( pWidget->style,
+ gdkDrawable,
+ nStateType,
+ nShadowType,
+ &clipRect,
+ gWidgetData[m_nScreen].gMenuItemMenuWidget,
+ "check",
+ x, y, w, h );
+ }
+ else
+ {
+ gtk_paint_option( pWidget->style,
+ gdkDrawable,
+ nStateType,
+ nShadowType,
+ &clipRect,
+ gWidgetData[m_nScreen].gMenuItemMenuWidget,
+ "option",
+ x, y, w, h );
+ }
+ }
+ }
+
+ return( TRUE );
+}
+
+BOOL GtkSalGraphics::NWPaintGTKTooltip(
+ GdkDrawable* gdkDrawable,
+ ControlType, ControlPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState, const ImplControlValue&,
+ const OUString& )
+{
+ NWEnsureGTKTooltip( m_nScreen );
+
+ gint x, y, w, h;
+ GdkRectangle clipRect;
+
+ x = rControlRectangle.Left();
+ y = rControlRectangle.Top();
+ w = rControlRectangle.GetWidth();
+ h = rControlRectangle.GetHeight();
+
+ for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
+ {
+ clipRect.x = it->Left();
+ clipRect.y = it->Top();
+ clipRect.width = it->GetWidth();
+ clipRect.height = it->GetHeight();
+
+ gtk_paint_flat_box( gWidgetData[m_nScreen].gTooltipPopup->style,
+ gdkDrawable,
+ GTK_STATE_NORMAL,
+ GTK_SHADOW_OUT,
+ &clipRect,
+ gWidgetData[m_nScreen].gTooltipPopup,
+ "tooltip",
+ x, y, w, h );
+ }
+
+ return( TRUE );
+}
+
+BOOL GtkSalGraphics::NWPaintGTKListNode(
+ GdkDrawable*,
+ ControlType, ControlPart,
+ const Rectangle& rControlRectangle,
+ const clipList&,
+ ControlState nState, const ImplControlValue& rValue,
+ const OUString& )
+{
+ NWEnsureGTKTreeView( m_nScreen );
+
+ Rectangle aRect( rControlRectangle );
+ aRect.Left() -= 2;
+ aRect.Right() += 2;
+ aRect.Top() -= 2;
+ aRect.Bottom() += 2;
+ gint w, h;
+ w = aRect.GetWidth();
+ h = aRect.GetHeight();
+
+ GtkStateType stateType;
+ GtkShadowType shadowType;
+ NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
+
+ ButtonValue aButtonValue = rValue.getTristateVal();
+ GtkExpanderStyle eStyle = GTK_EXPANDER_EXPANDED;
+
+ switch( aButtonValue )
+ {
+ case BUTTONVALUE_ON: eStyle = GTK_EXPANDER_EXPANDED;break;
+ case BUTTONVALUE_OFF: eStyle = GTK_EXPANDER_COLLAPSED; break;
+ default:
+ break;
+ }
+
+ GdkPixmap* pixmap = NWGetPixmapFromScreen( aRect );
+ if( ! pixmap )
+ return FALSE;
+
+ GdkDrawable* const &pixDrawable = GDK_DRAWABLE( pixmap );
+ gtk_paint_expander( gWidgetData[m_nScreen].gTreeView->style,
+ pixDrawable,
+ stateType,
+ NULL,
+ gWidgetData[m_nScreen].gTreeView,
+ "treeview",
+ w/2, h/2,
+ eStyle );
+
+ BOOL bRet = NWRenderPixmapToScreen( pixmap, aRect );
+ g_object_unref( pixmap );
+
+ return bRet;
+}
+
+BOOL GtkSalGraphics::NWPaintGTKProgress(
+ GdkDrawable*,
+ ControlType, ControlPart,
+ const Rectangle& rControlRectangle,
+ const clipList&,
+ ControlState, const ImplControlValue& rValue,
+ const OUString& )
+{
+ NWEnsureGTKProgressBar( m_nScreen );
+
+ gint w, h;
+ w = rControlRectangle.GetWidth();
+ h = rControlRectangle.GetHeight();
+
+ long nProgressWidth = rValue.getNumericVal();
+
+ GdkPixmap* pixmap = NWGetPixmapFromScreen( Rectangle( Point( 0, 0 ), Size( w, h ) ) );
+ if( ! pixmap )
+ return FALSE;
+
+ GdkDrawable* const &pixDrawable = GDK_DRAWABLE( pixmap );
+
+ // paint background
+ gtk_paint_flat_box( gWidgetData[m_nScreen].gProgressBar->style,
+ pixDrawable,
+ GTK_STATE_NORMAL,
+ GTK_SHADOW_NONE,
+ NULL,
+ gWidgetData[m_nScreen].gProgressBar,
+ "trough",
+ 0, 0, w, h );
+ if( nProgressWidth > 0 )
+ {
+ // paint progress
+ if( Application::GetSettings().GetLayoutRTL() )
+ {
+ gtk_paint_box( gWidgetData[m_nScreen].gProgressBar->style,
+ pixDrawable,
+ GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
+ NULL,
+ gWidgetData[m_nScreen].gProgressBar,
+ "bar",
+ w-nProgressWidth, 0, nProgressWidth, h
+ );
+ }
+ else
+ {
+ gtk_paint_box( gWidgetData[m_nScreen].gProgressBar->style,
+ pixDrawable,
+ GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
+ NULL,
+ gWidgetData[m_nScreen].gProgressBar,
+ "bar",
+ 0, 0, nProgressWidth, h
+ );
+ }
+ }
+
+ BOOL bRet = NWRenderPixmapToScreen( pixmap, rControlRectangle );
+ g_object_unref( pixmap );
+
+ return bRet;
+}
+
+BOOL GtkSalGraphics::NWPaintGTKSlider(
+ GdkDrawable*,
+ ControlType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList&,
+ ControlState nState, const ImplControlValue& rValue,
+ const OUString& )
+{
+ NWEnsureGTKSlider( m_nScreen );
+
+ gint w, h;
+ w = rControlRectangle.GetWidth();
+ h = rControlRectangle.GetHeight();
+
+ SliderValue* pVal = (SliderValue*)rValue.getOptionalVal();
+
+ GdkPixmap* pixmap = NWGetPixmapFromScreen( rControlRectangle );
+ if( ! pixmap )
+ return FALSE;
+
+ (void)pVal;
+
+ GdkDrawable* const &pixDrawable = GDK_DRAWABLE( pixmap );
+ GtkWidget* pWidget = (nPart == PART_TRACK_HORZ_AREA)
+ ? GTK_WIDGET(gWidgetData[m_nScreen].gHScale)
+ : GTK_WIDGET(gWidgetData[m_nScreen].gVScale);
+ const gchar* pDetail = (nPart == PART_TRACK_HORZ_AREA) ? "hscale" : "vscale";
+ GtkOrientation eOri = (nPart == PART_TRACK_HORZ_AREA) ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
+ GtkStateType eState = (nState & CTRL_STATE_ENABLED) ? GTK_STATE_ACTIVE : GTK_STATE_INSENSITIVE;
+ gint slider_width = 10;
+ gint slider_length = 10;
+ gint trough_border = 0;
+ gtk_widget_style_get( pWidget,
+ "slider-width", &slider_width,
+ "slider-length", &slider_length,
+ "trough-border", &trough_border,
+ NULL);
+
+ eState = (nState & CTRL_STATE_ENABLED) ? GTK_STATE_NORMAL : GTK_STATE_INSENSITIVE;
+ if( nPart == PART_TRACK_HORZ_AREA )
+ {
+ gtk_paint_box( pWidget->style,
+ pixDrawable,
+ eState,
+ GTK_SHADOW_IN,
+ NULL,
+ pWidget,
+ "trough",
+ 0, (h-slider_width-2*trough_border)/2, w, slider_width + 2*trough_border);
+ gint x = (w - slider_length + 1) * (pVal->mnCur - pVal->mnMin) / (pVal->mnMax - pVal->mnMin);
+ gtk_paint_slider( pWidget->style,
+ pixDrawable,
+ eState,
+ GTK_SHADOW_OUT,
+ NULL,
+ pWidget,
+ pDetail,
+ x, (h-slider_width)/2,
+ slider_length, slider_width,
+ eOri );
+ }
+ else
+ {
+ gtk_paint_box( pWidget->style,
+ pixDrawable,
+ eState,
+ GTK_SHADOW_IN,
+ NULL,
+ pWidget,
+ "trough",
+ (w-slider_width-2*trough_border)/2, 0, slider_width + 2*trough_border, h);
+ gint y = (h - slider_length + 1) * (pVal->mnCur - pVal->mnMin) / (pVal->mnMax - pVal->mnMin);
+ gtk_paint_slider( pWidget->style,
+ pixDrawable,
+ eState,
+ GTK_SHADOW_OUT,
+ NULL,
+ pWidget,
+ pDetail,
+ (w-slider_width)/2, y,
+ slider_width, slider_length,
+ eOri );
+ }
+ #if 0
+ // paint background
+ gtk_paint_flat_box( gWidgetData[m_nScreen].gProgressBar->style,
+ pixDrawable,
+ GTK_STATE_NORMAL,
+ GTK_SHADOW_NONE,
+ NULL,
+ gWidgetData[m_nScreen].gProgressBar,
+ "trough",
+ 0, 0, w, h );
+ if( nProgressWidth > 0 )
+ {
+ // paint progress
+ if( Application::GetSettings().GetLayoutRTL() )
+ {
+ gtk_paint_box( gWidgetData[m_nScreen].gProgressBar->style,
+ pixDrawable,
+ GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
+ NULL,
+ gWidgetData[m_nScreen].gProgressBar,
+ "bar",
+ w-nProgressWidth, 0, nProgressWidth, h
+ );
+ }
+ else
+ {
+ gtk_paint_box( gWidgetData[m_nScreen].gProgressBar->style,
+ pixDrawable,
+ GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
+ NULL,
+ gWidgetData[m_nScreen].gProgressBar,
+ "bar",
+ 0, 0, nProgressWidth, h
+ );
+ }
+ }
+ #endif
+
+ BOOL bRet = NWRenderPixmapToScreen( pixmap, rControlRectangle );
+ g_object_unref( pixmap );
+
+ return bRet;
+}
+
+//----
+
+static Rectangle NWGetListBoxButtonRect( int nScreen,
+ ControlType,
+ ControlPart nPart,
+ Rectangle aAreaRect,
+ ControlState,
+ const ImplControlValue&,
+ const OUString& )
+{
+ Rectangle aPartRect;
+ GtkRequisition *pIndicatorSize = NULL;
+ GtkBorder *pIndicatorSpacing = NULL;
+ gint width = 13; // GTK+ default
+ gint right = 5; // GTK+ default
+ gint nButtonAreaWidth = 0;
+ gint xthickness = 0;
+
+ NWEnsureGTKOptionMenu( nScreen );
+
+ gtk_widget_style_get( gWidgetData[nScreen].gOptionMenuWidget,
+ "indicator_size", &pIndicatorSize,
+ "indicator_spacing",&pIndicatorSpacing, (char *)NULL);
+
+ if ( pIndicatorSize )
+ width = pIndicatorSize->width;
+
+ if ( pIndicatorSpacing )
+ right = pIndicatorSpacing->right;
+
+ Size aPartSize( 0, aAreaRect.GetHeight() );
+ Point aPartPos ( 0, aAreaRect.Top() );
+
+ xthickness = gWidgetData[nScreen].gOptionMenuWidget->style->xthickness;
+ nButtonAreaWidth = width + right + (xthickness * 2);
+ switch( nPart )
+ {
+ case PART_BUTTON_DOWN:
+ aPartSize.Width() = nButtonAreaWidth;
+ aPartPos.X() = aAreaRect.Left() + aAreaRect.GetWidth() - aPartSize.Width();
+ break;
+
+ case PART_SUB_EDIT:
+ aPartSize.Width() = aAreaRect.GetWidth() - nButtonAreaWidth - xthickness;
+ aPartPos.X() = aAreaRect.Left() + xthickness;
+ break;
+
+ default:
+ aPartSize.Width() = aAreaRect.GetWidth();
+ aPartPos.X() = aAreaRect.Left();
+ break;
+ }
+ aPartRect = Rectangle( aPartPos, aPartSize );
+
+ if ( pIndicatorSize )
+ gtk_requisition_free( pIndicatorSize );
+ if ( pIndicatorSpacing )
+ gtk_border_free( pIndicatorSpacing );
+
+ return( aPartRect );
+}
+
+//----
+
+static Rectangle NWGetListBoxIndicatorRect( int nScreen,
+ ControlType,
+ ControlPart,
+ Rectangle aAreaRect,
+ ControlState,
+ const ImplControlValue&,
+ const OUString& )
+{
+ Rectangle aIndicatorRect;
+ GtkRequisition *pIndicatorSize = NULL;
+ GtkBorder *pIndicatorSpacing = NULL;
+ gint width = 13; // GTK+ default
+ gint height = 13; // GTK+ default
+ gint right = 5; // GTK+ default
+
+ NWEnsureGTKOptionMenu( nScreen );
+
+ gtk_widget_style_get( gWidgetData[nScreen].gOptionMenuWidget,
+ "indicator_size", &pIndicatorSize,
+ "indicator_spacing",&pIndicatorSpacing, (char *)NULL);
+
+ if ( pIndicatorSize )
+ {
+ width = pIndicatorSize->width;
+ height = pIndicatorSize->height;
+ }
+
+ if ( pIndicatorSpacing )
+ right = pIndicatorSpacing->right;
+
+ aIndicatorRect.SetSize( Size( width, height ) );
+ aIndicatorRect.SetPos( Point( aAreaRect.Left() + aAreaRect.GetWidth() - width - right - gWidgetData[nScreen].gOptionMenuWidget->style->xthickness,
+ aAreaRect.Top() + ((aAreaRect.GetHeight() - height) / 2) ) );
+
+ // If height is odd, move the indicator down 1 pixel
+ if ( aIndicatorRect.GetHeight() % 2 )
+ aIndicatorRect.Move( 0, 1 );
+
+ if ( pIndicatorSize )
+ gtk_requisition_free( pIndicatorSize );
+ if ( pIndicatorSpacing )
+ gtk_border_free( pIndicatorSpacing );
+
+ return( aIndicatorRect );
+}
+
+static Rectangle NWGetToolbarRect( int nScreen,
+ ControlType,
+ ControlPart nPart,
+ Rectangle aAreaRect,
+ ControlState,
+ const ImplControlValue&,
+ const OUString& )
+{
+ Rectangle aRet;
+
+ if( nPart == PART_DRAW_BACKGROUND_HORZ ||
+ nPart == PART_DRAW_BACKGROUND_VERT )
+ aRet = aAreaRect;
+ else if( nPart == PART_THUMB_HORZ )
+ aRet = Rectangle( Point( 0, 0 ), Size( aAreaRect.GetWidth(), 10 ) );
+ else if( nPart == PART_THUMB_VERT )
+ aRet = Rectangle( Point( 0, 0 ), Size( 10, aAreaRect.GetHeight() ) );
+ else if( nPart == PART_BUTTON )
+ {
+ aRet = aAreaRect;
+
+ NWEnsureGTKToolbar( nScreen );
+
+ gint nMinWidth =
+ 2*gWidgetData[nScreen].gToolbarButtonWidget->style->xthickness
+ + 1 // CHILD_SPACING constant, found in gtk_button.c
+ + 3*gWidgetData[nScreen].gToolbarButtonWidget->style->xthickness; // Murphy factor
+ gint nMinHeight =
+ 2*gWidgetData[nScreen].gToolbarButtonWidget->style->ythickness
+ + 1 // CHILD_SPACING constant, found in gtk_button.c
+ + 3*gWidgetData[nScreen].gToolbarButtonWidget->style->ythickness; // Murphy factor
+
+ gtk_widget_ensure_style( gWidgetData[nScreen].gToolbarButtonWidget );
+ if( aAreaRect.GetWidth() < nMinWidth )
+ aRet.Right() = aRet.Left() + nMinWidth;
+ if( aAreaRect.GetHeight() < nMinHeight )
+ aRet.Bottom() = aRet.Top() + nMinHeight;
+ }
+
+ return aRet;
+}
+
+/************************************************************************
+ * helper for GtkSalFrame
+ ************************************************************************/
+static inline Color getColor( const GdkColor& rCol )
+{
+ return Color( rCol.red >> 8, rCol.green >> 8, rCol.blue >> 8 );
+}
+
+#if OSL_DEBUG_LEVEL > 1
+
+void printColor( const char* name, const GdkColor& rCol )
+{
+ std::fprintf( stderr, " %s = 0x%2x 0x%2x 0x%2x\n",
+ name,
+ rCol.red >> 8, rCol.green >> 8, rCol.blue >> 8 );
+}
+
+void printStyleColors( GtkStyle* pStyle )
+{
+ static const char* pStates[] = { "NORMAL", "ACTIVE", "PRELIGHT", "SELECTED", "INSENSITIVE" };
+
+ for( int i = 0; i < 5; i++ )
+ {
+ std::fprintf( stderr, "state %s colors:\n", pStates[i] );
+ printColor( "bg ", pStyle->bg[i] );
+ printColor( "fg ", pStyle->fg[i] );
+ printColor( "light ", pStyle->light[i] );
+ printColor( "dark ", pStyle->dark[i] );
+ printColor( "mid ", pStyle->mid[i] );
+ printColor( "text ", pStyle->text[i] );
+ printColor( "base ", pStyle->base[i] );
+ printColor( "text_aa", pStyle->text_aa[i] );
+ }
+}
+#endif
+
+void GtkSalGraphics::updateSettings( AllSettings& rSettings )
+{
+ // get the widgets in place
+ NWEnsureGTKMenu( m_nScreen );
+ NWEnsureGTKMenubar( m_nScreen );
+ NWEnsureGTKScrollbars( m_nScreen );
+ NWEnsureGTKEditBox( m_nScreen );
+ NWEnsureGTKTooltip( m_nScreen );
+
+ gtk_widget_ensure_style( m_pWindow );
+ GtkStyle* pStyle = gtk_widget_get_style( m_pWindow );
+
+ StyleSettings aStyleSet = rSettings.GetStyleSettings();
+
+#if OSL_DEBUG_LEVEL > 2
+ printStyleColors( pStyle );
+#endif
+
+ // text colors
+ Color aTextColor = getColor( pStyle->text[GTK_STATE_NORMAL] );
+ aStyleSet.SetDialogTextColor( aTextColor );
+ aStyleSet.SetButtonTextColor( aTextColor );
+ aStyleSet.SetRadioCheckTextColor( aTextColor );
+ aStyleSet.SetGroupTextColor( aTextColor );
+ aStyleSet.SetLabelTextColor( aTextColor );
+ aStyleSet.SetInfoTextColor( aTextColor );
+ aStyleSet.SetWindowTextColor( aTextColor );
+ aStyleSet.SetFieldTextColor( aTextColor );
+
+ // Tooltip colors
+ GtkStyle* pTooltipStyle = gtk_widget_get_style( gWidgetData[m_nScreen].gTooltipPopup );
+ aTextColor = getColor( pTooltipStyle->fg[ GTK_STATE_NORMAL ] );
+ aStyleSet.SetHelpTextColor( aTextColor );
+
+ // mouse over text colors
+ aTextColor = getColor( pStyle->fg[ GTK_STATE_PRELIGHT ] );
+ aStyleSet.SetButtonRolloverTextColor( aTextColor );
+ aStyleSet.SetFieldRolloverTextColor( aTextColor );
+
+ // background colors
+ Color aBackColor = getColor( pStyle->bg[GTK_STATE_NORMAL] );
+ Color aBackFieldColor = getColor( pStyle->base[ GTK_STATE_NORMAL ] );
+ aStyleSet.Set3DColors( aBackColor );
+ aStyleSet.SetFaceColor( aBackColor );
+ aStyleSet.SetDialogColor( aBackColor );
+ aStyleSet.SetWorkspaceColor( aBackColor );
+ aStyleSet.SetFieldColor( aBackFieldColor );
+ aStyleSet.SetWindowColor( aBackFieldColor );
+// aStyleSet.SetHelpColor( aBackColor );
+ // ancient wisdom tells us a mystic algorithm how to set checked color
+ if( aBackColor == COL_LIGHTGRAY )
+ aStyleSet.SetCheckedColor( Color( 0xCC, 0xCC, 0xCC ) );
+ else
+ {
+ Color aColor2 = aStyleSet.GetLightColor();
+ Color aCheck( (BYTE)(((USHORT)aBackColor.GetRed()+(USHORT)aColor2.GetRed())/2),
+ (BYTE)(((USHORT)aBackColor.GetGreen()+(USHORT)aColor2.GetGreen())/2),
+ (BYTE)(((USHORT)aBackColor.GetBlue()+(USHORT)aColor2.GetBlue())/2)
+ );
+ aStyleSet.SetCheckedColor( aCheck );
+ }
+
+ // highlighting colors
+ Color aHighlightColor = getColor( pStyle->base[GTK_STATE_SELECTED] );
+ Color aHighlightTextColor = getColor( pStyle->text[GTK_STATE_SELECTED] );
+ aStyleSet.SetHighlightColor( aHighlightColor );
+ aStyleSet.SetHighlightTextColor( aHighlightTextColor );
+
+ if( ! gtk_check_version( 2, 10, 0 ) ) // link colors came in with 2.10, avoid an assertion
+ {
+ // hyperlink colors
+ GdkColor *link_color = NULL;
+ gtk_widget_style_get (m_pWindow, "link-color", &link_color, NULL);
+ if (link_color)
+ {
+ aStyleSet.SetLinkColor(getColor(*link_color));
+ gdk_color_free (link_color);
+ link_color = NULL;
+ }
+ gtk_widget_style_get (m_pWindow, "visited-link-color", &link_color, NULL);
+ if (link_color)
+ {
+ aStyleSet.SetVisitedLinkColor(getColor(*link_color));
+ gdk_color_free (link_color);
+ }
+ }
+
+ // Tab colors
+ aStyleSet.SetActiveTabColor( aBackFieldColor ); // same as the window color.
+ Color aSelectedBackColor = getColor( pStyle->bg[GTK_STATE_ACTIVE] );
+ aStyleSet.SetInactiveTabColor( aSelectedBackColor );
+
+ // menu disabled entries handling
+ aStyleSet.SetSkipDisabledInMenus( TRUE );
+ // menu colors
+ GtkStyle* pMenuStyle = gtk_widget_get_style( gWidgetData[m_nScreen].gMenuWidget );
+ GtkStyle* pMenuItemStyle = gtk_rc_get_style( gWidgetData[m_nScreen].gMenuItemMenuWidget );
+ GtkStyle* pMenubarStyle = gtk_rc_get_style( gWidgetData[m_nScreen].gMenubarWidget );
+ GtkStyle* pMenuTextStyle = gtk_rc_get_style( gtk_bin_get_child( GTK_BIN(gWidgetData[m_nScreen].gMenuItemMenuWidget) ) );
+
+ aBackColor = getColor( pMenubarStyle->bg[GTK_STATE_NORMAL] );
+ aStyleSet.SetMenuBarColor( aBackColor );
+ aBackColor = getColor( pMenuStyle->bg[GTK_STATE_NORMAL] );
+ aTextColor = getColor( pMenuTextStyle->fg[GTK_STATE_NORMAL] );
+ aStyleSet.SetMenuColor( aBackColor );
+ aStyleSet.SetMenuTextColor( aTextColor );
+
+ aTextColor = getColor( pMenubarStyle->fg[GTK_STATE_NORMAL] );
+ aStyleSet.SetMenuBarTextColor( aTextColor );
+
+#if OSL_DEBUG_LEVEL > 1
+ std::fprintf( stderr, "==\n" );
+ std::fprintf( stderr, "MenuColor = %x (%d)\n", (int)aStyleSet.GetMenuColor().GetColor(), aStyleSet.GetMenuColor().GetLuminance() );
+ std::fprintf( stderr, "MenuTextColor = %x (%d)\n", (int)aStyleSet.GetMenuTextColor().GetColor(), aStyleSet.GetMenuTextColor().GetLuminance() );
+ std::fprintf( stderr, "MenuBarColor = %x (%d)\n", (int)aStyleSet.GetMenuBarColor().GetColor(), aStyleSet.GetMenuBarColor().GetLuminance() );
+ std::fprintf( stderr, "MenuBarTextColor = %x (%d)\n", (int)aStyleSet.GetMenuBarTextColor().GetColor(), aStyleSet.GetMenuBarTextColor().GetLuminance() );
+ std::fprintf( stderr, "LightColor = %x (%d)\n", (int)aStyleSet.GetLightColor().GetColor(), aStyleSet.GetLightColor().GetLuminance() );
+ std::fprintf( stderr, "ShadowColor = %x (%d)\n", (int)aStyleSet.GetShadowColor().GetColor(), aStyleSet.GetShadowColor().GetLuminance() );
+#endif
+
+ // Awful hack for menu separators in the Sonar and similar themes.
+ // If the menu color is not too dark, and the menu text color is lighter,
+ // make the "light" color lighter than the menu color and the "shadow"
+ // color darker than it.
+ if ( aStyleSet.GetMenuColor().GetLuminance() >= 32 &&
+ aStyleSet.GetMenuColor().GetLuminance() <= aStyleSet.GetMenuTextColor().GetLuminance() )
+ {
+ Color temp = aStyleSet.GetMenuColor();
+ temp.IncreaseLuminance( 8 );
+ aStyleSet.SetLightColor( temp );
+ temp = aStyleSet.GetMenuColor();
+ temp.DecreaseLuminance( 16 );
+ aStyleSet.SetShadowColor( temp );
+ }
+
+ aHighlightColor = getColor( pMenuItemStyle->bg[ GTK_STATE_SELECTED ] );
+ aHighlightTextColor = getColor( pMenuTextStyle->fg[ GTK_STATE_PRELIGHT ] );
+ if( aHighlightColor == aHighlightTextColor )
+ aHighlightTextColor = (aHighlightColor.GetLuminance() < 128) ? Color( COL_WHITE ) : Color( COL_BLACK );
+ aStyleSet.SetMenuHighlightColor( aHighlightColor );
+ aStyleSet.SetMenuHighlightTextColor( aHighlightTextColor );
+
+ // UI font
+ OString aFamily = pango_font_description_get_family( pStyle->font_desc );
+ int nPangoHeight = pango_font_description_get_size( pStyle->font_desc );
+ PangoStyle eStyle = pango_font_description_get_style( pStyle->font_desc );
+ PangoWeight eWeight = pango_font_description_get_weight( pStyle->font_desc );
+ PangoStretch eStretch = pango_font_description_get_stretch( pStyle->font_desc );
+
+ psp::FastPrintFontInfo aInfo;
+ // set family name
+ aInfo.m_aFamilyName = OStringToOUString( aFamily, RTL_TEXTENCODING_UTF8 );
+ // set italic
+ switch( eStyle )
+ {
+ case PANGO_STYLE_NORMAL: aInfo.m_eItalic = psp::italic::Upright;break;
+ case PANGO_STYLE_ITALIC: aInfo.m_eItalic = psp::italic::Italic;break;
+ case PANGO_STYLE_OBLIQUE: aInfo.m_eItalic = psp::italic::Oblique;break;
+ }
+ // set weight
+ if( eWeight <= PANGO_WEIGHT_ULTRALIGHT )
+ aInfo.m_eWeight = psp::weight::UltraLight;
+ else if( eWeight <= PANGO_WEIGHT_LIGHT )
+ aInfo.m_eWeight = psp::weight::Light;
+ else if( eWeight <= PANGO_WEIGHT_NORMAL )
+ aInfo.m_eWeight = psp::weight::Normal;
+ else if( eWeight <= PANGO_WEIGHT_BOLD )
+ aInfo.m_eWeight = psp::weight::Bold;
+ else
+ aInfo.m_eWeight = psp::weight::UltraBold;
+ // set width
+ switch( eStretch )
+ {
+ case PANGO_STRETCH_ULTRA_CONDENSED: aInfo.m_eWidth = psp::width::UltraCondensed;break;
+ case PANGO_STRETCH_EXTRA_CONDENSED: aInfo.m_eWidth = psp::width::ExtraCondensed;break;
+ case PANGO_STRETCH_CONDENSED: aInfo.m_eWidth = psp::width::Condensed;break;
+ case PANGO_STRETCH_SEMI_CONDENSED: aInfo.m_eWidth = psp::width::SemiCondensed;break;
+ case PANGO_STRETCH_NORMAL: aInfo.m_eWidth = psp::width::Normal;break;
+ case PANGO_STRETCH_SEMI_EXPANDED: aInfo.m_eWidth = psp::width::SemiExpanded;break;
+ case PANGO_STRETCH_EXPANDED: aInfo.m_eWidth = psp::width::Expanded;break;
+ case PANGO_STRETCH_EXTRA_EXPANDED: aInfo.m_eWidth = psp::width::ExtraExpanded;break;
+ case PANGO_STRETCH_ULTRA_EXPANDED: aInfo.m_eWidth = psp::width::UltraExpanded;break;
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ std::fprintf( stderr, "font name BEFORE system match: \"%s\"\n", aFamily.getStr() );
+#endif
+
+ // match font to e.g. resolve "Sans"
+ psp::PrintFontManager::get().matchFont( aInfo, rSettings.GetUILocale() );
+
+#if OSL_DEBUG_LEVEL > 1
+ std::fprintf( stderr, "font match %s, name AFTER: \"%s\"\n",
+ aInfo.m_nID != 0 ? "succeeded" : "failed",
+ OUStringToOString( aInfo.m_aFamilyName, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+
+ sal_Int32 nDispDPIY = GetDisplay()->GetResolution().B();
+ int nPointHeight = 0;
+ static gboolean(*pAbso)(const PangoFontDescription*) =
+ (gboolean(*)(const PangoFontDescription*))osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "pango_font_description_get_size_is_absolute" );
+
+ if( pAbso && pAbso( pStyle->font_desc ) )
+ nPointHeight = (nPangoHeight * 72 + nDispDPIY*PANGO_SCALE/2) / (nDispDPIY * PANGO_SCALE);
+ else
+ nPointHeight = nPangoHeight/PANGO_SCALE;
+
+ Font aFont( aInfo.m_aFamilyName, Size( 0, nPointHeight ) );
+ if( aInfo.m_eWeight != psp::weight::Unknown )
+ aFont.SetWeight( PspGraphics::ToFontWeight( aInfo.m_eWeight ) );
+ if( aInfo.m_eWidth != psp::width::Unknown )
+ aFont.SetWidthType( PspGraphics::ToFontWidth( aInfo.m_eWidth ) );
+ if( aInfo.m_eItalic != psp::italic::Unknown )
+ aFont.SetItalic( PspGraphics::ToFontItalic( aInfo.m_eItalic ) );
+ if( aInfo.m_ePitch != psp::pitch::Unknown )
+ aFont.SetPitch( PspGraphics::ToFontPitch( aInfo.m_ePitch ) );
+
+ aStyleSet.SetAppFont( aFont );
+ aStyleSet.SetHelpFont( aFont );
+ aStyleSet.SetTitleFont( aFont );
+ aStyleSet.SetFloatTitleFont( aFont );
+ aStyleSet.SetMenuFont( aFont );
+ aStyleSet.SetToolFont( aFont );
+ aStyleSet.SetLabelFont( aFont );
+ aStyleSet.SetInfoFont( aFont );
+ aStyleSet.SetRadioCheckFont( aFont );
+ aStyleSet.SetPushButtonFont( aFont );
+ aStyleSet.SetFieldFont( aFont );
+ aStyleSet.SetIconFont( aFont );
+ aStyleSet.SetGroupFont( aFont );
+
+ // get cursor blink time
+ GtkSettings *pSettings = gtk_widget_get_settings( gWidgetData[m_nScreen].gEditBoxWidget );
+ gboolean blink = false;
+
+ g_object_get( pSettings, "gtk-cursor-blink", &blink, (char *)NULL );
+ if( blink )
+ {
+ gint blink_time = STYLE_CURSOR_NOBLINKTIME;
+ g_object_get( pSettings, "gtk-cursor-blink-time", &blink_time, (char *)NULL );
+ // set the blink_time if there is a setting and it is reasonable
+ // else leave the default value
+ if( blink_time > 100 && blink_time != gint(STYLE_CURSOR_NOBLINKTIME) )
+ aStyleSet.SetCursorBlinkTime( blink_time/2 );
+ }
+ else
+ aStyleSet.SetCursorBlinkTime( STYLE_CURSOR_NOBLINKTIME );
+
+ gboolean showmenuicons = true;
+ pSettings = gtk_widget_get_settings( gWidgetData[m_nScreen].gImageMenuItem );
+ g_object_get( pSettings, "gtk-menu-images", &showmenuicons, (char *)NULL );
+ aStyleSet.SetUseImagesInMenus( showmenuicons );
+
+ // set scrollbar settings
+ gint slider_width = 14;
+ gint trough_border = 1;
+ gint min_slider_length = 21;
+
+ // Grab some button style attributes
+ gtk_widget_style_get( gWidgetData[m_nScreen].gScrollHorizWidget,
+ "slider-width", &slider_width,
+ "trough-border", &trough_border,
+ "min-slider-length", &min_slider_length,
+ (char *)NULL );
+ gint magic = trough_border ? 1 : 0;
+ aStyleSet.SetScrollBarSize( slider_width + 2*trough_border );
+ aStyleSet.SetMinThumbSize( min_slider_length - magic );
+
+ // preferred icon style
+ gchar* pIconThemeName = NULL;
+ g_object_get( gtk_settings_get_default(), "gtk-icon-theme-name", &pIconThemeName, (char *)NULL );
+ aStyleSet.SetPreferredSymbolsStyleName( OUString::createFromAscii( pIconThemeName ) );
+ g_free( pIconThemeName );
+
+ // FIXME: need some way of fetching toolbar icon size.
+// aStyleSet.SetToolbarIconSize( STYLE_TOOLBAR_ICONSIZE_SMALL );
+
+ const cairo_font_options_t* pNewOptions = NULL;
+ if( GdkScreen* pScreen = gdk_display_get_screen( gdk_display_get_default(), m_nScreen ) )
+ {
+//#if !GTK_CHECK_VERSION(2,8,1)
+#if !GTK_CHECK_VERSION(2,9,0)
+ static cairo_font_options_t* (*gdk_screen_get_font_options)(GdkScreen*) =
+ (cairo_font_options_t*(*)(GdkScreen*))osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "gdk_screen_get_font_options" );
+ if( gdk_screen_get_font_options != NULL )
+#endif
+ pNewOptions = gdk_screen_get_font_options( pScreen );
+ }
+ aStyleSet.SetCairoFontOptions( pNewOptions );
+
+ // finally update the collected settings
+ rSettings.SetStyleSettings( aStyleSet );
+
+ #if OSL_DEBUG_LEVEL > 1
+ {
+ GtkSettings* pGtkSettings = gtk_settings_get_default();
+ GValue aValue;
+ memset( &aValue, 0, sizeof(GValue) );
+ g_value_init( &aValue, G_TYPE_STRING );
+ g_object_get_property( G_OBJECT(pGtkSettings), "gtk-theme-name", &aValue );
+ const gchar* pThemeName = g_value_get_string( &aValue );
+ std::fprintf( stderr, "Theme name is \"%s\"\n", pThemeName );
+ g_value_unset( &aValue );
+ }
+ #endif
+ GtkSettings* pGtkSettings = gtk_settings_get_default();
+ GValue aValue;
+ memset( &aValue, 0, sizeof(GValue) );
+ g_value_init( &aValue, G_TYPE_STRING );
+ g_object_get_property( G_OBJECT(pGtkSettings), "gtk-theme-name", &aValue );
+ const gchar* pThemeName = g_value_get_string( &aValue );
+
+ // default behaviour
+ bNeedPixmapPaint = bGlobalNeedPixmapPaint;
+ bToolbarGripWorkaround = false;
+ bNeedButtonStyleAsEditBackgroundWorkaround = false;
+
+ // setup some workarounds for "blueprint" theme
+ if( pThemeName && strncasecmp( pThemeName, "blueprint", 9 ) == 0 )
+ {
+ bNeedButtonStyleAsEditBackgroundWorkaround = true;
+ if( GetX11SalData()->GetDisplay()->GetServerVendor() == vendor_sun )
+ {
+ // #i52570#, #i61532# workaround a weird paint issue;
+ // on a Sunray Xserver sometimes painting buttons and edits
+ // won't work when using the blueprint theme
+ // not reproducible with simpler programs or other themes
+ if( pThemeName && strncasecmp( pThemeName, "blueprint", 9 ) == 0 )
+ {
+ bNeedPixmapPaint = true;
+ bToolbarGripWorkaround = true;
+ }
+ }
+ }
+ // clean up
+ g_value_unset( &aValue );
+}
+
+
+/************************************************************************
+ * Create a GdkPixmap filled with the contents of an area of an Xlib window
+ ************************************************************************/
+
+GdkPixmap* GtkSalGraphics::NWGetPixmapFromScreen( Rectangle srcRect )
+{
+ // Create a new pixmap to hold the composite of the window background and the control
+ GdkPixmap * pPixmap = gdk_pixmap_new( GDK_DRAWABLE(GetGdkWindow()), srcRect.GetWidth(), srcRect.GetHeight(), -1 );
+ GdkGC * pPixmapGC = gdk_gc_new( pPixmap );
+
+ if( !pPixmap || !pPixmapGC )
+ {
+ if ( pPixmap )
+ g_object_unref( pPixmap );
+ if ( pPixmapGC )
+ g_object_unref( pPixmapGC );
+ std::fprintf( stderr, "salnativewidgets-gtk.cxx: could not get valid pixmap from screen\n" );
+ return( NULL );
+ }
+
+ // Copy the background of the screen into a composite pixmap
+ CopyScreenArea( GetXDisplay(),
+ GetDrawable(), GetScreenNumber(), GetVisual().GetDepth(),
+ gdk_x11_drawable_get_xid(pPixmap),
+ gdk_screen_get_number( gdk_drawable_get_screen( GDK_DRAWABLE(pPixmap) ) ),
+ gdk_drawable_get_depth( GDK_DRAWABLE( pPixmap ) ),
+ gdk_x11_gc_get_xgc(pPixmapGC),
+ srcRect.Left(), srcRect.Top(), srcRect.GetWidth(), srcRect.GetHeight(), 0, 0 );
+
+ g_object_unref( pPixmapGC );
+ return( pPixmap );
+}
+
+
+
+
+/************************************************************************
+ * Copy an alpha pixmap to screen using a gc with clipping
+ ************************************************************************/
+
+BOOL GtkSalGraphics::NWRenderPixmapToScreen( GdkPixmap* pPixmap, Rectangle dstRect )
+{
+ // The GC can't be null, otherwise we'd have no clip region
+ if( SelectFont() == NULL )
+ {
+ std::fprintf(stderr, "salnativewidgets.cxx: no valid GC\n" );
+ return( FALSE );
+ }
+
+ if ( !pPixmap )
+ return( FALSE );
+
+ // Copy the background of the screen into a composite pixmap
+ CopyScreenArea( GetXDisplay(),
+ GDK_DRAWABLE_XID(pPixmap),
+ gdk_screen_get_number( gdk_drawable_get_screen( GDK_DRAWABLE(pPixmap) ) ),
+ gdk_drawable_get_depth( GDK_DRAWABLE(pPixmap) ),
+ GetDrawable(), m_nScreen, GetVisual().GetDepth(),
+ SelectFont(),
+ 0, 0, dstRect.GetWidth(), dstRect.GetHeight(), dstRect.Left(), dstRect.Top() );
+
+ return( TRUE );
+}
+
+
+/************************************************************************
+ * State conversion
+ ************************************************************************/
+static void NWConvertVCLStateToGTKState( ControlState nVCLState,
+ GtkStateType* nGTKState, GtkShadowType* nGTKShadow )
+{
+ *nGTKShadow = GTK_SHADOW_OUT;
+ *nGTKState = GTK_STATE_INSENSITIVE;
+
+ if ( nVCLState & CTRL_STATE_ENABLED )
+ {
+ if ( nVCLState & CTRL_STATE_PRESSED )
+ {
+ *nGTKState = GTK_STATE_ACTIVE;
+ *nGTKShadow = GTK_SHADOW_IN;
+ }
+ else if ( nVCLState & CTRL_STATE_ROLLOVER )
+ {
+ *nGTKState = GTK_STATE_PRELIGHT;
+ *nGTKShadow = GTK_SHADOW_OUT;
+ }
+ else
+ {
+ *nGTKState = GTK_STATE_NORMAL;
+ *nGTKShadow = GTK_SHADOW_OUT;
+ }
+ }
+}
+
+/************************************************************************
+ * Set widget flags
+ ************************************************************************/
+static void NWSetWidgetState( GtkWidget* widget, ControlState nState, GtkStateType nGtkState )
+{
+ // Set to default state, then build up from there
+ GTK_WIDGET_UNSET_FLAGS( widget, GTK_HAS_DEFAULT );
+ GTK_WIDGET_UNSET_FLAGS( widget, GTK_HAS_FOCUS );
+ GTK_WIDGET_UNSET_FLAGS( widget, GTK_SENSITIVE );
+ GTK_WIDGET_SET_FLAGS( widget, gWidgetDefaultFlags[(long)widget] );
+
+ if ( nState & CTRL_STATE_DEFAULT )
+ GTK_WIDGET_SET_FLAGS( widget, GTK_HAS_DEFAULT );
+ if ( !GTK_IS_TOGGLE_BUTTON(widget) && (nState & CTRL_STATE_FOCUSED) )
+ GTK_WIDGET_SET_FLAGS( widget, GTK_HAS_FOCUS );
+ if ( nState & CTRL_STATE_ENABLED )
+ GTK_WIDGET_SET_FLAGS( widget, GTK_SENSITIVE );
+ gtk_widget_set_state( widget, nGtkState );
+}
+
+/************************************************************************
+ * Widget ensure functions - make sure cached objects are valid
+ ************************************************************************/
+
+//-------------------------------------
+
+static void NWAddWidgetToCacheWindow( GtkWidget* widget, int nScreen )
+{
+ NWFWidgetData& rData = gWidgetData[nScreen];
+ if ( !rData.gCacheWindow || !rData.gDumbContainer )
+ {
+ if ( !rData.gCacheWindow )
+ {
+ rData.gCacheWindow = gtk_window_new( GTK_WINDOW_TOPLEVEL );
+ GdkScreen* pScreen = gdk_display_get_screen( gdk_display_get_default(), nScreen );
+ if( pScreen )
+ gtk_window_set_screen( GTK_WINDOW(rData.gCacheWindow), pScreen );
+ }
+ if ( !rData.gDumbContainer )
+ rData.gDumbContainer = gtk_fixed_new();
+ gtk_container_add( GTK_CONTAINER(rData.gCacheWindow), rData.gDumbContainer );
+ gtk_widget_realize( rData.gDumbContainer );
+ gtk_widget_realize( rData.gCacheWindow );
+ }
+
+ gtk_container_add( GTK_CONTAINER(rData.gDumbContainer), widget );
+ gtk_widget_realize( widget );
+ gtk_widget_ensure_style( widget );
+
+ // Store widget's default flags
+ gWidgetDefaultFlags[ (long)widget ] = GTK_WIDGET_FLAGS( widget );
+}
+
+//-------------------------------------
+
+static void NWEnsureGTKButton( int nScreen )
+{
+ if ( !gWidgetData[nScreen].gBtnWidget )
+ {
+ gWidgetData[nScreen].gBtnWidget = gtk_button_new_with_label( "" );
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gBtnWidget, nScreen );
+ }
+}
+
+//-------------------------------------
+
+static void NWEnsureGTKRadio( int nScreen )
+{
+ if ( !gWidgetData[nScreen].gRadioWidget || !gWidgetData[nScreen].gRadioWidgetSibling )
+ {
+ gWidgetData[nScreen].gRadioWidget = gtk_radio_button_new( NULL );
+ gWidgetData[nScreen].gRadioWidgetSibling = gtk_radio_button_new_from_widget( GTK_RADIO_BUTTON(gWidgetData[nScreen].gRadioWidget) );
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gRadioWidget, nScreen );
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gRadioWidgetSibling, nScreen );
+ }
+}
+
+//-------------------------------------
+
+static void NWEnsureGTKCheck( int nScreen )
+{
+ if ( !gWidgetData[nScreen].gCheckWidget )
+ {
+ gWidgetData[nScreen].gCheckWidget = gtk_check_button_new();
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gCheckWidget, nScreen );
+ }
+}
+
+//-------------------------------------
+
+static void NWEnsureGTKScrollbars( int nScreen )
+{
+ if ( !gWidgetData[nScreen].gScrollHorizWidget )
+ {
+ gWidgetData[nScreen].gScrollHorizWidget = gtk_hscrollbar_new( NULL );
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gScrollHorizWidget, nScreen );
+ }
+
+ if ( !gWidgetData[nScreen].gScrollVertWidget )
+ {
+ gWidgetData[nScreen].gScrollVertWidget = gtk_vscrollbar_new( NULL );
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gScrollVertWidget, nScreen );
+ }
+}
+
+//-------------------------------------
+
+static void NWEnsureGTKArrow( int nScreen )
+{
+ if ( !gWidgetData[nScreen].gArrowWidget || !gWidgetData[nScreen].gDropdownWidget )
+ {
+ gWidgetData[nScreen].gDropdownWidget = gtk_toggle_button_new();
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gDropdownWidget, nScreen );
+ gWidgetData[nScreen].gArrowWidget = gtk_arrow_new( GTK_ARROW_DOWN, GTK_SHADOW_OUT );
+ gtk_container_add( GTK_CONTAINER(gWidgetData[nScreen].gDropdownWidget), gWidgetData[nScreen].gArrowWidget );
+ gtk_widget_set_rc_style( gWidgetData[nScreen].gArrowWidget );
+ gtk_widget_realize( gWidgetData[nScreen].gArrowWidget );
+ }
+}
+
+//-------------------------------------
+
+static void NWEnsureGTKEditBox( int nScreen )
+{
+ if ( !gWidgetData[nScreen].gEditBoxWidget )
+ {
+ gWidgetData[nScreen].gEditBoxWidget = gtk_entry_new();
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gEditBoxWidget, nScreen );
+ }
+}
+
+//-------------------------------------
+
+static void NWEnsureGTKSpinButton( int nScreen )
+{
+ if ( !gWidgetData[nScreen].gSpinButtonWidget )
+ {
+ GtkAdjustment *adj = GTK_ADJUSTMENT( gtk_adjustment_new(0, 0, 1, 1, 1, 0) );
+ gWidgetData[nScreen].gSpinButtonWidget = gtk_spin_button_new( adj, 1, 2 );
+
+ //Setting non-editable means it doesn't blink, so there's no timeouts
+ //running around to nobble us
+ gtk_editable_set_editable(GTK_EDITABLE(gWidgetData[nScreen].gSpinButtonWidget), false);
+
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gSpinButtonWidget, nScreen );
+ }
+}
+
+//-------------------------------------
+
+static void NWEnsureGTKNotebook( int nScreen )
+{
+ if ( !gWidgetData[nScreen].gNotebookWidget )
+ {
+ gWidgetData[nScreen].gNotebookWidget = gtk_notebook_new();
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gNotebookWidget, nScreen );
+ }
+}
+
+//-------------------------------------
+
+static void NWEnsureGTKOptionMenu( int nScreen )
+{
+ if ( !gWidgetData[nScreen].gOptionMenuWidget )
+ {
+ gWidgetData[nScreen].gOptionMenuWidget = gtk_option_menu_new();
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gOptionMenuWidget, nScreen );
+ }
+}
+
+//-------------------------------------
+
+static void NWEnsureGTKCombo( int nScreen )
+{
+ if ( !gWidgetData[nScreen].gComboWidget )
+ {
+ gWidgetData[nScreen].gComboWidget = gtk_combo_new();
+
+ // #i59129# Setting non-editable means it doesn't blink, so
+ // there are no timeouts running around to nobble us
+ gtk_editable_set_editable(GTK_EDITABLE(GTK_COMBO(gWidgetData[nScreen].gComboWidget)->entry), false);
+
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gComboWidget, nScreen );
+ // Must realize the ComboBox's children, since GTK
+ // does not do this for us in GtkCombo::gtk_widget_realize()
+ gtk_widget_realize( GTK_COMBO(gWidgetData[nScreen].gComboWidget)->button );
+ gtk_widget_realize( GTK_COMBO(gWidgetData[nScreen].gComboWidget)->entry );
+ }
+}
+
+//-------------------------------------
+
+static void NWEnsureGTKScrolledWindow( int nScreen )
+{
+ if ( !gWidgetData[nScreen].gScrolledWindowWidget )
+ {
+ GtkAdjustment *hadj = GTK_ADJUSTMENT( gtk_adjustment_new(0, 0, 0, 0, 0, 0) );
+ GtkAdjustment *vadj = GTK_ADJUSTMENT( gtk_adjustment_new(0, 0, 0, 0, 0, 0) );
+
+ gWidgetData[nScreen].gScrolledWindowWidget = gtk_scrolled_window_new( hadj, vadj );
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gScrolledWindowWidget, nScreen );
+ }
+}
+
+//-------------------------------------
+
+static void NWEnsureGTKToolbar( int nScreen )
+{
+ if( !gWidgetData[nScreen].gToolbarWidget )
+ {
+ gWidgetData[nScreen].gToolbarWidget = gtk_toolbar_new();
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gToolbarWidget, nScreen );
+ gWidgetData[nScreen].gToolbarButtonWidget = gtk_button_new();
+ gWidgetData[nScreen].gToolbarToggleWidget = gtk_toggle_button_new();
+
+ GtkReliefStyle aRelief = GTK_RELIEF_NORMAL;
+ gtk_widget_ensure_style( gWidgetData[nScreen].gToolbarWidget );
+ gtk_widget_style_get( gWidgetData[nScreen].gToolbarWidget,
+ "button_relief", &aRelief,
+ (char *)NULL);
+
+ gtk_button_set_relief( GTK_BUTTON(gWidgetData[nScreen].gToolbarButtonWidget), aRelief );
+ GTK_WIDGET_UNSET_FLAGS( gWidgetData[nScreen].gToolbarButtonWidget, GTK_CAN_FOCUS );
+ GTK_WIDGET_UNSET_FLAGS( gWidgetData[nScreen].gToolbarButtonWidget, GTK_CAN_DEFAULT );
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gToolbarButtonWidget, nScreen );
+
+ gtk_button_set_relief( GTK_BUTTON(gWidgetData[nScreen].gToolbarToggleWidget), aRelief );
+ GTK_WIDGET_UNSET_FLAGS( gWidgetData[nScreen].gToolbarToggleWidget, GTK_CAN_FOCUS );
+ GTK_WIDGET_UNSET_FLAGS( gWidgetData[nScreen].gToolbarToggleWidget, GTK_CAN_DEFAULT );
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gToolbarToggleWidget, nScreen );
+ }
+ if( ! gWidgetData[nScreen].gHandleBoxWidget )
+ {
+ gWidgetData[nScreen].gHandleBoxWidget = gtk_handle_box_new();
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gHandleBoxWidget, nScreen );
+ }
+}
+
+//-------------------------------------
+
+static void NWEnsureGTKMenubar( int nScreen )
+{
+ if( !gWidgetData[nScreen].gMenubarWidget )
+ {
+ gWidgetData[nScreen].gMenubarWidget = gtk_menu_bar_new();
+ gWidgetData[nScreen].gMenuItemMenubarWidget = gtk_menu_item_new_with_label( "b" );
+ gtk_menu_shell_append( GTK_MENU_SHELL( gWidgetData[nScreen].gMenubarWidget ), gWidgetData[nScreen].gMenuItemMenubarWidget );
+ gtk_widget_show( gWidgetData[nScreen].gMenuItemMenubarWidget );
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gMenubarWidget, nScreen );
+ gtk_widget_show( gWidgetData[nScreen].gMenubarWidget );
+
+ // do what NWAddWidgetToCacheWindow does except adding to def container
+ gtk_widget_realize( gWidgetData[nScreen].gMenuItemMenubarWidget );
+ gtk_widget_ensure_style( gWidgetData[nScreen].gMenuItemMenubarWidget );
+
+ gWidgetDefaultFlags[ (long)gWidgetData[nScreen].gMenuItemMenubarWidget ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gMenuItemMenubarWidget );
+ }
+}
+
+static void NWEnsureGTKMenu( int nScreen )
+{
+ if( !gWidgetData[nScreen].gMenuWidget )
+ {
+ gWidgetData[nScreen].gMenuWidget = gtk_menu_new();
+ gWidgetData[nScreen].gMenuItemMenuWidget = gtk_menu_item_new_with_label( "b" );
+ gWidgetData[nScreen].gMenuItemCheckMenuWidget = gtk_check_menu_item_new_with_label( "b" );
+ gWidgetData[nScreen].gMenuItemRadioMenuWidget = gtk_radio_menu_item_new_with_label( NULL, "b" );
+ gWidgetData[nScreen].gImageMenuItem = gtk_image_menu_item_new();
+
+ gtk_menu_shell_append( GTK_MENU_SHELL( gWidgetData[nScreen].gMenuWidget ), gWidgetData[nScreen].gMenuItemMenuWidget );
+ gtk_menu_shell_append( GTK_MENU_SHELL( gWidgetData[nScreen].gMenuWidget ), gWidgetData[nScreen].gMenuItemCheckMenuWidget );
+ gtk_menu_shell_append( GTK_MENU_SHELL( gWidgetData[nScreen].gMenuWidget ), gWidgetData[nScreen].gMenuItemRadioMenuWidget );
+ gtk_menu_shell_append( GTK_MENU_SHELL( gWidgetData[nScreen].gMenuWidget ), gWidgetData[nScreen].gImageMenuItem );
+
+ // do what NWAddWidgetToCacheWindow does except adding to def container
+ gtk_widget_realize( gWidgetData[nScreen].gMenuWidget );
+ gtk_widget_ensure_style( gWidgetData[nScreen].gMenuWidget );
+
+ gtk_widget_realize( gWidgetData[nScreen].gMenuItemMenuWidget );
+ gtk_widget_ensure_style( gWidgetData[nScreen].gMenuItemMenuWidget );
+
+ gtk_widget_realize( gWidgetData[nScreen].gMenuItemCheckMenuWidget );
+ gtk_widget_ensure_style( gWidgetData[nScreen].gMenuItemCheckMenuWidget );
+
+ gtk_widget_realize( gWidgetData[nScreen].gMenuItemRadioMenuWidget );
+ gtk_widget_ensure_style( gWidgetData[nScreen].gMenuItemRadioMenuWidget );
+
+ gtk_widget_realize( gWidgetData[nScreen].gImageMenuItem );
+ gtk_widget_ensure_style( gWidgetData[nScreen].gImageMenuItem );
+
+ gWidgetDefaultFlags[ (long)gWidgetData[nScreen].gMenuWidget ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gMenuWidget );
+ gWidgetDefaultFlags[ (long)gWidgetData[nScreen].gMenuItemMenuWidget ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gMenuItemMenuWidget );
+ gWidgetDefaultFlags[ (long)gWidgetData[nScreen].gMenuItemCheckMenuWidget ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gMenuItemCheckMenuWidget );
+ gWidgetDefaultFlags[ (long)gWidgetData[nScreen].gMenuItemRadioMenuWidget ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gMenuItemRadioMenuWidget );
+ gWidgetDefaultFlags[ (long)gWidgetData[nScreen].gImageMenuItem ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gImageMenuItem );
+ }
+}
+
+static void NWEnsureGTKTooltip( int nScreen )
+{
+ if( !gWidgetData[nScreen].gTooltipPopup )
+ {
+ gWidgetData[nScreen].gTooltipPopup = gtk_window_new (GTK_WINDOW_POPUP);
+ GdkScreen* pScreen = gdk_display_get_screen( gdk_display_get_default(), nScreen );
+ if( pScreen )
+ gtk_window_set_screen( GTK_WINDOW(gWidgetData[nScreen].gTooltipPopup), pScreen );
+ gtk_widget_set_name( gWidgetData[nScreen].gTooltipPopup, "gtk-tooltips");
+ gtk_widget_realize( gWidgetData[nScreen].gTooltipPopup );
+ gtk_widget_ensure_style( gWidgetData[nScreen].gTooltipPopup );
+ }
+}
+
+static void NWEnsureGTKProgressBar( int nScreen )
+{
+ if( !gWidgetData[nScreen].gProgressBar )
+ {
+ gWidgetData[nScreen].gProgressBar = gtk_progress_bar_new ();
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gProgressBar, nScreen );
+ }
+}
+
+static void NWEnsureGTKTreeView( int nScreen )
+{
+ if( !gWidgetData[nScreen].gTreeView )
+ {
+ gWidgetData[nScreen].gTreeView = gtk_tree_view_new ();
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gTreeView, nScreen );
+ }
+}
+
+static void NWEnsureGTKSlider( int nScreen )
+{
+ if( !gWidgetData[nScreen].gHScale )
+ {
+ gWidgetData[nScreen].gHScale = gtk_hscale_new_with_range(0, 10, 1);
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gHScale, nScreen );
+ }
+ if( !gWidgetData[nScreen].gVScale )
+ {
+ gWidgetData[nScreen].gVScale = gtk_vscale_new_with_range(0, 10, 1);
+ NWAddWidgetToCacheWindow( gWidgetData[nScreen].gVScale, nScreen );
+ }
+}
diff --git a/vcl/unx/gtk/window/gtkframe.cxx b/vcl/unx/gtk/window/gtkframe.cxx
new file mode 100644
index 000000000000..c6ff16f8395b
--- /dev/null
+++ b/vcl/unx/gtk/window/gtkframe.cxx
@@ -0,0 +1,3778 @@
+/*************************************************************************
+ *
+ * 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 <plugins/gtk/gtkframe.hxx>
+#include <plugins/gtk/gtkdata.hxx>
+#include <plugins/gtk/gtkinst.hxx>
+#include <plugins/gtk/gtkgdi.hxx>
+#include <vcl/keycodes.hxx>
+#include <wmadaptor.hxx>
+#include <sm.hxx>
+#include <salbmp.h>
+#include <salprn.h>
+#include <vcl/floatwin.hxx>
+#include <salprn.h>
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+
+#include <tools/prex.h>
+#include <X11/Xatom.h>
+#include <tools/postx.h>
+
+#include <dlfcn.h>
+#include <vcl/salbtype.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/impbmp.hxx>
+#include <vcl/svids.hrc>
+
+#include <algorithm>
+
+#if OSL_DEBUG_LEVEL > 1
+#include <cstdio>
+#endif
+
+#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/XAccessibleStateSet.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/XAccessibleEditableText.hpp>
+
+#ifdef ENABLE_DBUS
+#include <dbus/dbus-glib.h>
+
+#define GSM_DBUS_SERVICE "org.gnome.SessionManager"
+#define GSM_DBUS_PATH "/org/gnome/SessionManager"
+#define GSM_DBUS_INTERFACE "org.gnome.SessionManager"
+#endif
+
+// make compile on gtk older than 2.10
+#if GTK_MINOR_VERSION < 10
+#define GDK_SUPER_MASK (1 << 26)
+#define GDK_HYPER_MASK (1 << 27)
+#define GDK_META_MASK (1 << 28)
+#endif
+
+using namespace com::sun::star;
+
+int GtkSalFrame::m_nFloats = 0;
+
+static USHORT GetKeyModCode( guint state )
+{
+ USHORT nCode = 0;
+ if( (state & GDK_SHIFT_MASK) )
+ nCode |= KEY_SHIFT;
+ if( (state & GDK_CONTROL_MASK) )
+ nCode |= KEY_MOD1;
+ if( (state & GDK_MOD1_MASK) )
+ nCode |= KEY_MOD2;
+
+ // Map Meta/Super keys to MOD3 modifier on all Unix systems
+ // except Mac OS X
+ if ( (state & GDK_META_MASK ) || ( state & GDK_SUPER_MASK ) )
+ nCode |= KEY_MOD3;
+ return nCode;
+}
+
+static USHORT GetMouseModCode( guint state )
+{
+ USHORT nCode = GetKeyModCode( state );
+ if( (state & GDK_BUTTON1_MASK) )
+ nCode |= MOUSE_LEFT;
+ if( (state & GDK_BUTTON2_MASK) )
+ nCode |= MOUSE_MIDDLE;
+ if( (state & GDK_BUTTON3_MASK) )
+ nCode |= MOUSE_RIGHT;
+
+ return nCode;
+}
+
+static USHORT GetKeyCode( guint keyval )
+{
+ USHORT nCode = 0;
+ if( keyval >= GDK_0 && keyval <= GDK_9 )
+ nCode = KEY_0 + (keyval-GDK_0);
+ else if( keyval >= GDK_KP_0 && keyval <= GDK_KP_9 )
+ nCode = KEY_0 + (keyval-GDK_KP_0);
+ else if( keyval >= GDK_A && keyval <= GDK_Z )
+ nCode = KEY_A + (keyval-GDK_A );
+ else if( keyval >= GDK_a && keyval <= GDK_z )
+ nCode = KEY_A + (keyval-GDK_a );
+ else if( keyval >= GDK_F1 && keyval <= GDK_F26 )
+ {
+ if( GetX11SalData()->GetDisplay()->IsNumLockFromXS() )
+ {
+ nCode = KEY_F1 + (keyval-GDK_F1);
+ }
+ else
+ {
+ switch( keyval )
+ {
+ // - - - - - Sun keyboard, see vcl/unx/source/app/saldisp.cxx
+ case GDK_L2:
+ if( GetX11SalData()->GetDisplay()->GetServerVendor() == vendor_sun )
+ nCode = KEY_REPEAT;
+ else
+ nCode = KEY_F12;
+ break;
+ case GDK_L3: nCode = KEY_PROPERTIES; break;
+ case GDK_L4: nCode = KEY_UNDO; break;
+ case GDK_L6: nCode = KEY_COPY; break; // KEY_F16
+ case GDK_L8: nCode = KEY_PASTE; break; // KEY_F18
+ case GDK_L10: nCode = KEY_CUT; break; // KEY_F20
+ default:
+ nCode = KEY_F1 + (keyval-GDK_F1); break;
+ }
+ }
+ }
+ else
+ {
+ switch( keyval )
+ {
+ case GDK_KP_Down:
+ case GDK_Down: nCode = KEY_DOWN; break;
+ case GDK_KP_Up:
+ case GDK_Up: nCode = KEY_UP; break;
+ case GDK_KP_Left:
+ case GDK_Left: nCode = KEY_LEFT; break;
+ case GDK_KP_Right:
+ case GDK_Right: nCode = KEY_RIGHT; break;
+ case GDK_KP_Begin:
+ case GDK_KP_Home:
+ case GDK_Begin:
+ case GDK_Home: nCode = KEY_HOME; break;
+ case GDK_KP_End:
+ case GDK_End: nCode = KEY_END; break;
+ case GDK_KP_Page_Up:
+ case GDK_Page_Up: nCode = KEY_PAGEUP; break;
+ case GDK_KP_Page_Down:
+ case GDK_Page_Down: nCode = KEY_PAGEDOWN; break;
+ case GDK_KP_Enter:
+ case GDK_Return: nCode = KEY_RETURN; break;
+ case GDK_Escape: nCode = KEY_ESCAPE; break;
+ case GDK_ISO_Left_Tab:
+ case GDK_KP_Tab:
+ case GDK_Tab: nCode = KEY_TAB; break;
+ case GDK_BackSpace: nCode = KEY_BACKSPACE; break;
+ case GDK_KP_Space:
+ case GDK_space: nCode = KEY_SPACE; break;
+ case GDK_KP_Insert:
+ case GDK_Insert: nCode = KEY_INSERT; break;
+ case GDK_KP_Delete:
+ case GDK_Delete: nCode = KEY_DELETE; break;
+ case GDK_plus:
+ case GDK_KP_Add: nCode = KEY_ADD; break;
+ case GDK_minus:
+ case GDK_KP_Subtract: nCode = KEY_SUBTRACT; break;
+ case GDK_asterisk:
+ case GDK_KP_Multiply: nCode = KEY_MULTIPLY; break;
+ case GDK_slash:
+ case GDK_KP_Divide: nCode = KEY_DIVIDE; break;
+ case GDK_period:
+ case GDK_decimalpoint: nCode = KEY_POINT; break;
+ case GDK_comma: nCode = KEY_COMMA; break;
+ case GDK_less: nCode = KEY_LESS; break;
+ case GDK_greater: nCode = KEY_GREATER; break;
+ case GDK_KP_Equal:
+ case GDK_equal: nCode = KEY_EQUAL; break;
+ case GDK_Find: nCode = KEY_FIND; break;
+ case GDK_Menu: nCode = KEY_CONTEXTMENU;break;
+ case GDK_Help: nCode = KEY_HELP; break;
+ case GDK_Undo: nCode = KEY_UNDO; break;
+ case GDK_Redo: nCode = KEY_REPEAT; break;
+ case GDK_KP_Decimal:
+ case GDK_KP_Separator: nCode = KEY_DECIMAL; break;
+ case GDK_asciitilde: nCode = KEY_TILDE; break;
+ case GDK_leftsinglequotemark:
+ case GDK_quoteleft: nCode = KEY_QUOTELEFT; break;
+ // some special cases, also see saldisp.cxx
+ // - - - - - - - - - - - - - Apollo - - - - - - - - - - - - - 0x1000
+ case 0x1000FF02: // apXK_Copy
+ nCode = KEY_COPY;
+ break;
+ case 0x1000FF03: // apXK_Cut
+ nCode = KEY_CUT;
+ break;
+ case 0x1000FF04: // apXK_Paste
+ nCode = KEY_PASTE;
+ break;
+ case 0x1000FF14: // apXK_Repeat
+ nCode = KEY_REPEAT;
+ break;
+ // Exit, Save
+ // - - - - - - - - - - - - - - D E C - - - - - - - - - - - - - 0x1000
+ case 0x1000FF00:
+ nCode = KEY_DELETE;
+ break;
+ // - - - - - - - - - - - - - - H P - - - - - - - - - - - - - 0x1000
+ case 0x1000FF73: // hpXK_DeleteChar
+ nCode = KEY_DELETE;
+ break;
+ case 0x1000FF74: // hpXK_BackTab
+ case 0x1000FF75: // hpXK_KP_BackTab
+ nCode = KEY_TAB;
+ break;
+ // - - - - - - - - - - - - - - I B M - - - - - - - - - - - - -
+ // - - - - - - - - - - - - - - O S F - - - - - - - - - - - - - 0x1004
+ case 0x1004FF02: // osfXK_Copy
+ nCode = KEY_COPY;
+ break;
+ case 0x1004FF03: // osfXK_Cut
+ nCode = KEY_CUT;
+ break;
+ case 0x1004FF04: // osfXK_Paste
+ nCode = KEY_PASTE;
+ break;
+ case 0x1004FF07: // osfXK_BackTab
+ nCode = KEY_TAB;
+ break;
+ case 0x1004FF08: // osfXK_BackSpace
+ nCode = KEY_BACKSPACE;
+ break;
+ case 0x1004FF1B: // osfXK_Escape
+ nCode = KEY_ESCAPE;
+ break;
+ // Up, Down, Left, Right, PageUp, PageDown
+ // - - - - - - - - - - - - - - S C O - - - - - - - - - - - - -
+ // - - - - - - - - - - - - - - S G I - - - - - - - - - - - - - 0x1007
+ // - - - - - - - - - - - - - - S N I - - - - - - - - - - - - -
+ // - - - - - - - - - - - - - - S U N - - - - - - - - - - - - - 0x1005
+ case 0x1005FF10: // SunXK_F36
+ nCode = KEY_F11;
+ break;
+ case 0x1005FF11: // SunXK_F37
+ nCode = KEY_F12;
+ break;
+ case 0x1005FF70: // SunXK_Props
+ nCode = KEY_PROPERTIES;
+ break;
+ case 0x1005FF71: // SunXK_Front
+ nCode = KEY_FRONT;
+ break;
+ case 0x1005FF72: // SunXK_Copy
+ nCode = KEY_COPY;
+ break;
+ case 0x1005FF73: // SunXK_Open
+ nCode = KEY_OPEN;
+ break;
+ case 0x1005FF74: // SunXK_Paste
+ nCode = KEY_PASTE;
+ break;
+ case 0x1005FF75: // SunXK_Cut
+ nCode = KEY_CUT;
+ break;
+ }
+ }
+
+ return nCode;
+}
+
+// F10 means either KEY_F10 or KEY_MENU, which has to be decided
+// in the independent part.
+struct KeyAlternate
+{
+ USHORT nKeyCode;
+ sal_Unicode nCharCode;
+ KeyAlternate() : nKeyCode( 0 ), nCharCode( 0 ) {}
+ KeyAlternate( USHORT nKey, sal_Unicode nChar = 0 ) : nKeyCode( nKey ), nCharCode( nChar ) {}
+};
+
+inline KeyAlternate
+GetAlternateKeyCode( const USHORT nKeyCode )
+{
+ KeyAlternate aAlternate;
+
+ switch( nKeyCode )
+ {
+ case KEY_F10: aAlternate = KeyAlternate( KEY_MENU );break;
+ case KEY_F24: aAlternate = KeyAlternate( KEY_SUBTRACT, '-' );break;
+ }
+
+ return aAlternate;
+}
+
+void GtkSalFrame::doKeyCallback( guint state,
+ guint keyval,
+ guint16 hardware_keycode,
+ guint8 /*group*/,
+ guint32 time,
+ sal_Unicode aOrigCode,
+ bool bDown,
+ bool bSendRelease
+ )
+{
+ SalKeyEvent aEvent;
+
+ aEvent.mnTime = time;
+ aEvent.mnCharCode = aOrigCode;
+ aEvent.mnRepeat = 0;
+
+ vcl::DeletionListener aDel( this );
+ /* #i42122# translate all keys with Ctrl and/or Alt to group 0
+ * else shortcuts (e.g. Ctrl-o) will not work but be inserted by
+ * the application
+ */
+ /* #i52338# do this for all keys that the independent part has no key code for
+ */
+ aEvent.mnCode = GetKeyCode( keyval );
+ if( aEvent.mnCode == 0 )
+ {
+ // check other mapping
+ gint eff_group, level;
+ GdkModifierType consumed;
+ guint updated_keyval = 0;
+ // use gdk_keymap_get_default instead of NULL;
+ // workaround a crahs fixed in gtk 2.4
+ if( gdk_keymap_translate_keyboard_state( gdk_keymap_get_default(),
+ hardware_keycode,
+ (GdkModifierType)0,
+ 0,
+ &updated_keyval,
+ &eff_group,
+ &level,
+ &consumed ) )
+ {
+ aEvent.mnCode = GetKeyCode( updated_keyval );
+ }
+ }
+ aEvent.mnCode |= GetKeyModCode( state );
+
+ if( bDown )
+ {
+ bool bHandled = CallCallback( SALEVENT_KEYINPUT, &aEvent );
+ // #i46889# copy AlternatKeyCode handling from generic plugin
+ if( ! bHandled )
+ {
+ KeyAlternate aAlternate = GetAlternateKeyCode( aEvent.mnCode );
+ if( aAlternate.nKeyCode )
+ {
+ aEvent.mnCode = aAlternate.nKeyCode;
+ if( aAlternate.nCharCode )
+ aEvent.mnCharCode = aAlternate.nCharCode;
+ bHandled = CallCallback( SALEVENT_KEYINPUT, &aEvent );
+ }
+ }
+ if( bSendRelease && ! aDel.isDeleted() )
+ {
+ CallCallback( SALEVENT_KEYUP, &aEvent );
+ }
+ }
+ else
+ CallCallback( SALEVENT_KEYUP, &aEvent );
+}
+
+GtkSalFrame::GraphicsHolder::~GraphicsHolder()
+{
+ delete pGraphics;
+}
+
+GtkSalFrame::GtkSalFrame( SalFrame* pParent, ULONG nStyle )
+{
+ m_nScreen = getDisplay()->GetDefaultScreenNumber();
+ getDisplay()->registerFrame( this );
+ m_bDefaultPos = true;
+ m_bDefaultSize = ( (nStyle & SAL_FRAME_STYLE_SIZEABLE) && ! pParent );
+ m_bWindowIsGtkPlug = false;
+ Init( pParent, nStyle );
+}
+
+GtkSalFrame::GtkSalFrame( SystemParentData* pSysData )
+{
+ m_nScreen = getDisplay()->GetDefaultScreenNumber();
+ getDisplay()->registerFrame( this );
+ getDisplay()->setHaveSystemChildFrame();
+ m_bDefaultPos = true;
+ m_bDefaultSize = true;
+ Init( pSysData );
+}
+
+GtkSalFrame::~GtkSalFrame()
+{
+ for( unsigned int i = 0; i < sizeof(m_aGraphics)/sizeof(m_aGraphics[0]); ++i )
+ {
+ if( !m_aGraphics[i].pGraphics )
+ continue;
+ m_aGraphics[i].pGraphics->SetDrawable( None, m_nScreen );
+ m_aGraphics[i].bInUse = false;
+ }
+
+ if( m_pParent )
+ m_pParent->m_aChildren.remove( this );
+
+ getDisplay()->deregisterFrame( this );
+
+ if( m_pRegion )
+ gdk_region_destroy( m_pRegion );
+
+ if( m_hBackgroundPixmap )
+ {
+ XSetWindowBackgroundPixmap( getDisplay()->GetDisplay(),
+ GDK_WINDOW_XWINDOW(m_pWindow->window),
+ None );
+ XFreePixmap( getDisplay()->GetDisplay(), m_hBackgroundPixmap );
+ }
+
+ if( m_pIMHandler )
+ delete m_pIMHandler;
+
+ if( m_pFixedContainer )
+ gtk_widget_destroy( GTK_WIDGET(m_pFixedContainer) );
+ if( m_pWindow )
+ {
+ g_object_set_data( G_OBJECT( m_pWindow ), "SalFrame", NULL );
+ gtk_widget_destroy( m_pWindow );
+ }
+ if( m_pForeignParent )
+ g_object_unref( G_OBJECT(m_pForeignParent) );
+ if( m_pForeignTopLevel )
+ g_object_unref(G_OBJECT( m_pForeignTopLevel) );
+}
+
+void GtkSalFrame::moveWindow( long nX, long nY )
+{
+ if( isChild( false, true ) )
+ {
+ if( m_pParent )
+ gtk_fixed_move( m_pParent->getFixedContainer(),
+ m_pWindow,
+ nX - m_pParent->maGeometry.nX, nY - m_pParent->maGeometry.nY );
+ }
+ else
+ gtk_window_move( GTK_WINDOW(m_pWindow), nX, nY );
+}
+
+void GtkSalFrame::resizeWindow( long nWidth, long nHeight )
+{
+ if( isChild( false, true ) )
+ gtk_widget_set_size_request( m_pWindow, nWidth, nHeight );
+ else if( ! isChild( true, false ) )
+ gtk_window_resize( GTK_WINDOW(m_pWindow), nWidth, nHeight );
+}
+
+/*
+ * Always use a sub-class of GtkFixed we can tag for a11y. This allows us to
+ * utilize GAIL for the toplevel window and toolkit implementation incl.
+ * key event listener support ..
+ */
+
+GType
+ooo_fixed_get_type()
+{
+ static GType type = 0;
+
+ if (!type) {
+ static const GTypeInfo tinfo =
+ {
+ sizeof (GtkFixedClass),
+ (GBaseInitFunc) NULL, /* base init */
+ (GBaseFinalizeFunc) NULL, /* base finalize */
+ (GClassInitFunc) NULL, /* class init */
+ (GClassFinalizeFunc) NULL, /* class finalize */
+ NULL, /* class data */
+ sizeof (GtkFixed), /* instance size */
+ 0, /* nb preallocs */
+ (GInstanceInitFunc) NULL, /* instance init */
+ NULL /* value table */
+ };
+
+ type = g_type_register_static( GTK_TYPE_FIXED, "OOoFixed",
+ &tinfo, (GTypeFlags) 0);
+ }
+
+ return type;
+}
+
+void GtkSalFrame::updateScreenNumber()
+{
+ if( getDisplay()->IsXinerama() && getDisplay()->GetXineramaScreens().size() > 1 )
+ {
+ Point aPoint( maGeometry.nX, maGeometry.nY );
+ const std::vector<Rectangle>& rScreenRects( getDisplay()->GetXineramaScreens() );
+ size_t nScreens = rScreenRects.size();
+ for( size_t i = 0; i < nScreens; i++ )
+ {
+ if( rScreenRects[i].IsInside( aPoint ) )
+ {
+ maGeometry.nScreenNumber = static_cast<unsigned int>(i);
+ break;
+ }
+ }
+ }
+ else
+ maGeometry.nScreenNumber = static_cast<unsigned int>(m_nScreen);
+}
+
+void GtkSalFrame::InitCommon()
+{
+ // connect signals
+ g_signal_connect( G_OBJECT(m_pWindow), "style-set", G_CALLBACK(signalStyleSet), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "button-press-event", G_CALLBACK(signalButton), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "button-release-event", G_CALLBACK(signalButton), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "expose-event", G_CALLBACK(signalExpose), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "focus-in-event", G_CALLBACK(signalFocus), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "focus-out-event", G_CALLBACK(signalFocus), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "map-event", G_CALLBACK(signalMap), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "unmap-event", G_CALLBACK(signalUnmap), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "configure-event", G_CALLBACK(signalConfigure), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "motion-notify-event", G_CALLBACK(signalMotion), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "key-press-event", G_CALLBACK(signalKey), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "key-release-event", G_CALLBACK(signalKey), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "delete-event", G_CALLBACK(signalDelete), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "window-state-event", G_CALLBACK(signalState), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "scroll-event", G_CALLBACK(signalScroll), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "leave-notify-event", G_CALLBACK(signalCrossing), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "enter-notify-event", G_CALLBACK(signalCrossing), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "visibility-notify-event", G_CALLBACK(signalVisibility), this );
+ g_signal_connect( G_OBJECT(m_pWindow), "destroy", G_CALLBACK(signalDestroy), this );
+
+ // init members
+ m_pCurrentCursor = NULL;
+ m_nKeyModifiers = 0;
+ m_bSingleAltPress = false;
+ m_bFullscreen = false;
+ m_nState = GDK_WINDOW_STATE_WITHDRAWN;
+ m_nVisibility = GDK_VISIBILITY_FULLY_OBSCURED;
+ m_bSendModChangeOnRelease = false;
+ m_pIMHandler = NULL;
+ m_hBackgroundPixmap = None;
+ m_nSavedScreenSaverTimeout = 0;
+ m_nGSMCookie = 0;
+ m_nExtStyle = 0;
+ m_pRegion = NULL;
+ m_ePointerStyle = 0xffff;
+ m_bSetFocusOnMap = false;
+
+ gtk_widget_set_app_paintable( m_pWindow, TRUE );
+ gtk_widget_set_double_buffered( m_pWindow, FALSE );
+ gtk_widget_set_redraw_on_allocate( m_pWindow, FALSE );
+ gtk_widget_add_events( m_pWindow,
+ GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
+ GDK_VISIBILITY_NOTIFY_MASK
+ );
+
+ // add the fixed container child,
+ // fixed is needed since we have to position plugin windows
+ m_pFixedContainer = GTK_FIXED(g_object_new( ooo_fixed_get_type(), NULL ));
+ gtk_container_add( GTK_CONTAINER(m_pWindow), GTK_WIDGET(m_pFixedContainer) );
+
+ // show the widgets
+ gtk_widget_show( GTK_WIDGET(m_pFixedContainer) );
+
+ // realize the window, we need an XWindow id
+ gtk_widget_realize( m_pWindow );
+
+ //system data
+ SalDisplay* pDisp = GetX11SalData()->GetDisplay();
+ m_aSystemData.nSize = sizeof( SystemChildData );
+ m_aSystemData.pDisplay = pDisp->GetDisplay();
+ m_aSystemData.aWindow = GDK_WINDOW_XWINDOW(m_pWindow->window);
+ m_aSystemData.pSalFrame = this;
+ m_aSystemData.pWidget = m_pWindow;
+ m_aSystemData.pVisual = pDisp->GetVisual( m_nScreen ).GetVisual();
+ m_aSystemData.nScreen = m_nScreen;
+ m_aSystemData.nDepth = pDisp->GetVisual( m_nScreen ).GetDepth();
+ m_aSystemData.aColormap = pDisp->GetColormap( m_nScreen ).GetXColormap();
+ m_aSystemData.pAppContext = NULL;
+ m_aSystemData.aShellWindow = m_aSystemData.aWindow;
+ m_aSystemData.pShellWidget = m_aSystemData.pWidget;
+
+
+ // fake an initial geometry, gets updated via configure event or SetPosSize
+ if( m_bDefaultPos || m_bDefaultSize )
+ {
+ Size aDefSize = calcDefaultSize();
+ maGeometry.nX = -1;
+ maGeometry.nY = -1;
+ maGeometry.nWidth = aDefSize.Width();
+ maGeometry.nHeight = aDefSize.Height();
+ if( m_pParent )
+ {
+ // approximation
+ maGeometry.nTopDecoration = m_pParent->maGeometry.nTopDecoration;
+ maGeometry.nBottomDecoration = m_pParent->maGeometry.nBottomDecoration;
+ maGeometry.nLeftDecoration = m_pParent->maGeometry.nLeftDecoration;
+ maGeometry.nRightDecoration = m_pParent->maGeometry.nRightDecoration;
+ }
+ else
+ {
+ maGeometry.nTopDecoration = 0;
+ maGeometry.nBottomDecoration = 0;
+ maGeometry.nLeftDecoration = 0;
+ maGeometry.nRightDecoration = 0;
+ }
+ }
+ else
+ {
+ resizeWindow( maGeometry.nWidth, maGeometry.nHeight );
+ moveWindow( maGeometry.nX, maGeometry.nY );
+ }
+ updateScreenNumber();
+
+ SetIcon(1);
+ m_nWorkArea = pDisp->getWMAdaptor()->getCurrentWorkArea();
+
+ /* #i64117# gtk sets a nice background pixmap
+ * but we actually don't really want that, so save
+ * some time on the Xserver as well as prevent
+ * some paint issues
+ */
+ XSetWindowBackgroundPixmap( getDisplay()->GetDisplay(),
+ GDK_WINDOW_XWINDOW(m_pWindow->window),
+ m_hBackgroundPixmap );
+}
+
+/* Sadly gtk_window_set_accept_focus exists only since gtk 2.4
+ * for achieving the same effect we will remove the WM_TAKE_FOCUS
+ * protocol from the window and set the input hint to false.
+ * But gtk_window_set_accept_focus needs to be called before
+ * window realization whereas the removal obviously can only happen
+ * after realization.
+ */
+
+extern "C" {
+ typedef void(*setAcceptFn)( GtkWindow*, gboolean );
+ static setAcceptFn p_gtk_window_set_accept_focus = NULL;
+ static bool bGetAcceptFocusFn = true;
+
+ typedef void(*setUserTimeFn)( GdkWindow*, guint32 );
+ static setUserTimeFn p_gdk_x11_window_set_user_time = NULL;
+ static bool bGetSetUserTimeFn = true;
+}
+
+static void lcl_set_accept_focus( GtkWindow* pWindow, gboolean bAccept, bool bBeforeRealize )
+{
+ if( bGetAcceptFocusFn )
+ {
+ bGetAcceptFocusFn = false;
+ p_gtk_window_set_accept_focus = (setAcceptFn)osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "gtk_window_set_accept_focus" );
+ }
+ if( p_gtk_window_set_accept_focus && bBeforeRealize )
+ p_gtk_window_set_accept_focus( pWindow, bAccept );
+ else if( ! bBeforeRealize )
+ {
+ Display* pDisplay = GetX11SalData()->GetDisplay()->GetDisplay();
+ XLIB_Window aWindow = GDK_WINDOW_XWINDOW( GTK_WIDGET(pWindow)->window );
+ XWMHints* pHints = XGetWMHints( pDisplay, aWindow );
+ if( ! pHints )
+ {
+ pHints = XAllocWMHints();
+ pHints->flags = 0;
+ }
+ pHints->flags |= InputHint;
+ pHints->input = bAccept ? True : False;
+ XSetWMHints( pDisplay, aWindow, pHints );
+ XFree( pHints );
+
+ if (GetX11SalData()->GetDisplay()->getWMAdaptor()->getWindowManagerName().EqualsAscii("compiz"))
+ return;
+
+ /* remove WM_TAKE_FOCUS protocol; this would usually be the
+ * right thing, but gtk handles it internally whereas we
+ * want to handle it ourselves (as to sometimes not get
+ * the focus)
+ */
+ Atom* pProtocols = NULL;
+ int nProtocols = 0;
+ XGetWMProtocols( pDisplay,
+ aWindow,
+ &pProtocols, &nProtocols );
+ if( pProtocols )
+ {
+ bool bSet = false;
+ Atom nTakeFocus = XInternAtom( pDisplay, "WM_TAKE_FOCUS", True );
+ if( nTakeFocus )
+ {
+ for( int i = 0; i < nProtocols; i++ )
+ {
+ if( pProtocols[i] == nTakeFocus )
+ {
+ for( int n = i; n < nProtocols-1; n++ )
+ pProtocols[n] = pProtocols[n+1];
+ nProtocols--;
+ i--;
+ bSet = true;
+ }
+ }
+ }
+ if( bSet )
+ XSetWMProtocols( pDisplay, aWindow, pProtocols, nProtocols );
+ XFree( pProtocols );
+ }
+ }
+}
+static void lcl_set_user_time( GdkWindow* i_pWindow, guint32 i_nTime )
+{
+ if( bGetSetUserTimeFn )
+ {
+ bGetSetUserTimeFn = false;
+ p_gdk_x11_window_set_user_time = (setUserTimeFn)osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "gdk_x11_window_set_user_time" );
+ }
+ if( p_gdk_x11_window_set_user_time )
+ p_gdk_x11_window_set_user_time( i_pWindow, i_nTime );
+ else
+ {
+ Display* pDisplay = GetX11SalData()->GetDisplay()->GetDisplay();
+ XLIB_Window aWindow = GDK_WINDOW_XWINDOW( i_pWindow );
+ Atom nUserTime = XInternAtom( pDisplay, "_NET_WM_USER_TIME", True );
+ if( nUserTime )
+ {
+ XChangeProperty( pDisplay, aWindow,
+ nUserTime, XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char*)&i_nTime, 1 );
+ }
+ }
+};
+
+GtkSalFrame *GtkSalFrame::getFromWindow( GtkWindow *pWindow )
+{
+ return (GtkSalFrame *) g_object_get_data( G_OBJECT( pWindow ), "SalFrame" );
+}
+
+void GtkSalFrame::Init( SalFrame* pParent, ULONG nStyle )
+{
+ if( nStyle & SAL_FRAME_STYLE_DEFAULT ) // ensure default style
+ {
+ nStyle |= SAL_FRAME_STYLE_MOVEABLE | SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_CLOSEABLE;
+ nStyle &= ~SAL_FRAME_STYLE_FLOAT;
+ }
+
+ m_pParent = static_cast<GtkSalFrame*>(pParent);
+ m_pForeignParent = NULL;
+ m_aForeignParentWindow = None;
+ m_pForeignTopLevel = NULL;
+ m_aForeignTopLevelWindow = None;
+ m_nStyle = nStyle;
+
+ GtkWindowType eWinType = ( (nStyle & SAL_FRAME_STYLE_FLOAT) &&
+ ! (nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|
+ SAL_FRAME_STYLE_FLOAT_FOCUSABLE))
+ )
+ ? GTK_WINDOW_POPUP : GTK_WINDOW_TOPLEVEL;
+
+ if( nStyle & SAL_FRAME_STYLE_SYSTEMCHILD )
+ {
+ m_pWindow = gtk_event_box_new();
+ if( m_pParent )
+ {
+ // insert into container
+ gtk_fixed_put( m_pParent->getFixedContainer(),
+ m_pWindow, 0, 0 );
+
+ }
+ }
+ else
+ m_pWindow = gtk_widget_new( GTK_TYPE_WINDOW, "type", eWinType, "visible", FALSE, NULL );
+ g_object_set_data( G_OBJECT( m_pWindow ), "SalFrame", this );
+
+ // force wm class hint
+ m_nExtStyle = ~0;
+ SetExtendedFrameStyle( 0 );
+
+ if( m_pParent && m_pParent->m_pWindow && ! isChild() )
+ gtk_window_set_screen( GTK_WINDOW(m_pWindow), gtk_window_get_screen( GTK_WINDOW(m_pParent->m_pWindow) ) );
+
+ // set window type
+ bool bDecoHandling =
+ ! isChild() &&
+ ( ! (nStyle & SAL_FRAME_STYLE_FLOAT) ||
+ (nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_FLOAT_FOCUSABLE) ) );
+
+ if( bDecoHandling )
+ {
+ bool bNoDecor = ! (nStyle & (SAL_FRAME_STYLE_MOVEABLE | SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_CLOSEABLE ) );
+ GdkWindowTypeHint eType = GDK_WINDOW_TYPE_HINT_NORMAL;
+ if( (nStyle & SAL_FRAME_STYLE_DIALOG) && m_pParent != 0 )
+ eType = GDK_WINDOW_TYPE_HINT_DIALOG;
+ if( (nStyle & SAL_FRAME_STYLE_INTRO) )
+ {
+ gtk_window_set_role( GTK_WINDOW(m_pWindow), "splashscreen" );
+ eType = GDK_WINDOW_TYPE_HINT_SPLASHSCREEN;
+ }
+ else if( (nStyle & SAL_FRAME_STYLE_TOOLWINDOW ) )
+ {
+ eType = GDK_WINDOW_TYPE_HINT_UTILITY;
+ gtk_window_set_skip_taskbar_hint( GTK_WINDOW(m_pWindow), true );
+ }
+ else if( (nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) )
+ {
+ eType = GDK_WINDOW_TYPE_HINT_TOOLBAR;
+ lcl_set_accept_focus( GTK_WINDOW(m_pWindow), FALSE, true );
+ bNoDecor = true;
+ }
+ else if( (nStyle & SAL_FRAME_STYLE_FLOAT_FOCUSABLE) )
+ {
+ eType = GDK_WINDOW_TYPE_HINT_UTILITY;
+ }
+
+ if( (nStyle & SAL_FRAME_STYLE_PARTIAL_FULLSCREEN )
+ && getDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() )
+ {
+ eType = GDK_WINDOW_TYPE_HINT_TOOLBAR;
+ gtk_window_set_keep_above( GTK_WINDOW(m_pWindow), true );
+ }
+
+ gtk_window_set_type_hint( GTK_WINDOW(m_pWindow), eType );
+ if( bNoDecor )
+ gtk_window_set_decorated( GTK_WINDOW(m_pWindow), FALSE );
+ gtk_window_set_gravity( GTK_WINDOW(m_pWindow), GDK_GRAVITY_STATIC );
+ if( m_pParent && ! (m_pParent->m_nStyle & SAL_FRAME_STYLE_PLUG) )
+ gtk_window_set_transient_for( GTK_WINDOW(m_pWindow), GTK_WINDOW(m_pParent->m_pWindow) );
+ }
+ else if( (nStyle & SAL_FRAME_STYLE_FLOAT) )
+ {
+ gtk_window_set_type_hint( GTK_WINDOW(m_pWindow), GDK_WINDOW_TYPE_HINT_UTILITY );
+ }
+ if( m_pParent )
+ m_pParent->m_aChildren.push_back( this );
+
+ InitCommon();
+
+ if( eWinType == GTK_WINDOW_TOPLEVEL )
+ {
+ guint32 nUserTime = 0;
+ if( (nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_TOOLWINDOW)) == 0 )
+ {
+ /* #i99360# ugly workaround an X11 library bug */
+ nUserTime= getDisplay()->GetLastUserEventTime( true );
+ // nUserTime = gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window);
+ }
+ lcl_set_user_time(GTK_WIDGET(m_pWindow)->window, nUserTime);
+ }
+
+ if( bDecoHandling )
+ {
+ gtk_window_set_resizable( GTK_WINDOW(m_pWindow), (nStyle & SAL_FRAME_STYLE_SIZEABLE) ? TRUE : FALSE );
+ if( ( (nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION)) ) )
+ lcl_set_accept_focus( GTK_WINDOW(m_pWindow), FALSE, false );
+ }
+
+}
+
+GdkNativeWindow GtkSalFrame::findTopLevelSystemWindow( GdkNativeWindow aWindow )
+{
+ XLIB_Window aRoot, aParent;
+ XLIB_Window* pChildren;
+ unsigned int nChildren;
+ bool bBreak = false;
+ do
+ {
+ pChildren = NULL;
+ nChildren = 0;
+ aParent = aRoot = None;
+ XQueryTree( getDisplay()->GetDisplay(), aWindow,
+ &aRoot, &aParent, &pChildren, &nChildren );
+ XFree( pChildren );
+ if( aParent != aRoot )
+ aWindow = aParent;
+ int nCount = 0;
+ Atom* pProps = XListProperties( getDisplay()->GetDisplay(),
+ aWindow,
+ &nCount );
+ for( int i = 0; i < nCount && ! bBreak; ++i )
+ bBreak = (pProps[i] == XA_WM_HINTS);
+ if( pProps )
+ XFree( pProps );
+ } while( aParent != aRoot && ! bBreak );
+
+ return aWindow;
+}
+
+void GtkSalFrame::Init( SystemParentData* pSysData )
+{
+ m_pParent = NULL;
+ m_aForeignParentWindow = (GdkNativeWindow)pSysData->aWindow;
+ m_pForeignParent = NULL;
+ m_aForeignTopLevelWindow = findTopLevelSystemWindow( (GdkNativeWindow)pSysData->aWindow );
+ m_pForeignTopLevel = gdk_window_foreign_new_for_display( getGdkDisplay(), m_aForeignTopLevelWindow );
+ gdk_window_set_events( m_pForeignTopLevel, GDK_STRUCTURE_MASK );
+
+ if( pSysData->nSize > sizeof(pSysData->nSize)+sizeof(pSysData->aWindow) && pSysData->bXEmbedSupport )
+ {
+ m_pWindow = gtk_plug_new( pSysData->aWindow );
+ m_bWindowIsGtkPlug = true;
+ GTK_WIDGET_SET_FLAGS( m_pWindow, GTK_CAN_FOCUS | GTK_SENSITIVE | GTK_CAN_DEFAULT );
+ gtk_widget_set_sensitive( m_pWindow, true );
+ }
+ else
+ {
+ m_pWindow = gtk_window_new( GTK_WINDOW_POPUP );
+ m_bWindowIsGtkPlug = false;
+ }
+ m_nStyle = SAL_FRAME_STYLE_PLUG;
+ InitCommon();
+
+ m_pForeignParent = gdk_window_foreign_new_for_display( getGdkDisplay(), m_aForeignParentWindow );
+ gdk_window_set_events( m_pForeignParent, GDK_STRUCTURE_MASK );
+ int x_ret, y_ret;
+ unsigned int w, h, bw, d;
+ XLIB_Window aRoot;
+ XGetGeometry( getDisplay()->GetDisplay(), pSysData->aWindow,
+ &aRoot, &x_ret, &y_ret, &w, &h, &bw, &d );
+ maGeometry.nWidth = w;
+ maGeometry.nHeight = h;
+ gtk_window_resize( GTK_WINDOW(m_pWindow), w, h );
+ gtk_window_move( GTK_WINDOW(m_pWindow), 0, 0 );
+ if( ! m_bWindowIsGtkPlug )
+ {
+ XReparentWindow( getDisplay()->GetDisplay(),
+ GDK_WINDOW_XWINDOW(m_pWindow->window),
+ (XLIB_Window)pSysData->aWindow,
+ 0, 0 );
+ }
+}
+
+void GtkSalFrame::askForXEmbedFocus( sal_Int32 i_nTimeCode )
+{
+ XEvent aEvent;
+
+ rtl_zeroMemory( &aEvent, sizeof(aEvent) );
+ aEvent.xclient.window = m_aForeignParentWindow;
+ aEvent.xclient.type = ClientMessage;
+ aEvent.xclient.message_type = getDisplay()->getWMAdaptor()->getAtom( vcl_sal::WMAdaptor::XEMBED );
+ aEvent.xclient.format = 32;
+ aEvent.xclient.data.l[0] = i_nTimeCode ? i_nTimeCode : CurrentTime;
+ aEvent.xclient.data.l[1] = 3; // XEMBED_REQUEST_FOCUS
+ aEvent.xclient.data.l[2] = 0;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = 0;
+
+ getDisplay()->GetXLib()->PushXErrorLevel( true );
+ XSendEvent( getDisplay()->GetDisplay(),
+ m_aForeignParentWindow,
+ False, NoEventMask, &aEvent );
+ XSync( getDisplay()->GetDisplay(), False );
+ getDisplay()->GetXLib()->PopXErrorLevel();
+}
+
+void GtkSalFrame::SetExtendedFrameStyle( SalExtStyle nStyle )
+{
+ if( nStyle != m_nExtStyle && ! isChild() )
+ {
+ m_nExtStyle = nStyle;
+ if( GTK_WIDGET_REALIZED( m_pWindow ) )
+ {
+ XClassHint* pClass = XAllocClassHint();
+ rtl::OString aResHint = X11SalData::getFrameResName( m_nExtStyle );
+ pClass->res_name = const_cast<char*>(aResHint.getStr());
+ pClass->res_class = const_cast<char*>(X11SalData::getFrameClassName());
+ XSetClassHint( getDisplay()->GetDisplay(),
+ GDK_WINDOW_XWINDOW(m_pWindow->window),
+ pClass );
+ XFree( pClass );
+ }
+ else
+ gtk_window_set_wmclass( GTK_WINDOW(m_pWindow),
+ X11SalData::getFrameResName( m_nExtStyle ),
+ X11SalData::getFrameClassName() );
+ }
+}
+
+
+SalGraphics* GtkSalFrame::GetGraphics()
+{
+ if( m_pWindow )
+ {
+ for( int i = 0; i < nMaxGraphics; i++ )
+ {
+ if( ! m_aGraphics[i].bInUse )
+ {
+ m_aGraphics[i].bInUse = true;
+ if( ! m_aGraphics[i].pGraphics )
+ {
+ m_aGraphics[i].pGraphics = new GtkSalGraphics( m_pWindow );
+ m_aGraphics[i].pGraphics->Init( this, GDK_WINDOW_XWINDOW(m_pWindow->window), m_nScreen );
+ }
+ return m_aGraphics[i].pGraphics;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+void GtkSalFrame::ReleaseGraphics( SalGraphics* pGraphics )
+{
+ for( int i = 0; i < nMaxGraphics; i++ )
+ {
+ if( m_aGraphics[i].pGraphics == pGraphics )
+ {
+ m_aGraphics[i].bInUse = false;
+ break;
+ }
+ }
+}
+
+BOOL GtkSalFrame::PostEvent( void* pData )
+{
+ getDisplay()->SendInternalEvent( this, pData );
+ return TRUE;
+}
+
+void GtkSalFrame::SetTitle( const String& rTitle )
+{
+ m_aTitle = rTitle;
+ if( m_pWindow && ! isChild() )
+ gtk_window_set_title( GTK_WINDOW(m_pWindow), rtl::OUStringToOString( rTitle, RTL_TEXTENCODING_UTF8 ).getStr() );
+}
+
+static inline BYTE *
+getRow( BitmapBuffer *pBuffer, ULONG nRow )
+{
+ if( BMP_SCANLINE_ADJUSTMENT( pBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN )
+ return pBuffer->mpBits + nRow * pBuffer->mnScanlineSize;
+ else
+ return pBuffer->mpBits + ( pBuffer->mnHeight - nRow - 1 ) * pBuffer->mnScanlineSize;
+}
+
+static GdkPixbuf *
+bitmapToPixbuf( SalBitmap *pSalBitmap, SalBitmap *pSalAlpha )
+{
+ g_return_val_if_fail( pSalBitmap != NULL, NULL );
+ g_return_val_if_fail( pSalAlpha != NULL, NULL );
+
+ BitmapBuffer *pBitmap = pSalBitmap->AcquireBuffer( TRUE );
+ g_return_val_if_fail( pBitmap != NULL, NULL );
+ g_return_val_if_fail( pBitmap->mnBitCount == 24, NULL );
+
+ BitmapBuffer *pAlpha = pSalAlpha->AcquireBuffer( TRUE );
+ g_return_val_if_fail( pAlpha != NULL, NULL );
+ g_return_val_if_fail( pAlpha->mnBitCount == 8, NULL );
+
+ Size aSize = pSalBitmap->GetSize();
+ g_return_val_if_fail( pSalAlpha->GetSize() == aSize, NULL );
+
+ int nX, nY;
+ guchar *pPixbufData = (guchar *)g_malloc (4 * aSize.Width() * aSize.Height() );
+ guchar *pDestData = pPixbufData;
+
+ for( nY = 0; nY < pBitmap->mnHeight; nY++ )
+ {
+ BYTE *pData = getRow( pBitmap, nY );
+ BYTE *pAlphaData = getRow( pAlpha, nY );
+
+ for( nX = 0; nX < pBitmap->mnWidth; nX++ )
+ {
+ if( pBitmap->mnFormat == BMP_FORMAT_24BIT_TC_BGR )
+ {
+ pDestData[2] = *pData++;
+ pDestData[1] = *pData++;
+ pDestData[0] = *pData++;
+ }
+ else // BMP_FORMAT_24BIT_TC_RGB
+ {
+ pDestData[0] = *pData++;
+ pDestData[1] = *pData++;
+ pDestData[2] = *pData++;
+ }
+ pDestData += 3;
+ *pDestData++ = 255 - *pAlphaData++;
+ }
+ }
+
+ pSalBitmap->ReleaseBuffer( pBitmap, TRUE );
+ pSalAlpha->ReleaseBuffer( pAlpha, TRUE );
+
+ return gdk_pixbuf_new_from_data( pPixbufData,
+ GDK_COLORSPACE_RGB, TRUE, 8,
+ aSize.Width(), aSize.Height(),
+ aSize.Width() * 4,
+ (GdkPixbufDestroyNotify) g_free,
+ NULL );
+}
+
+void GtkSalFrame::SetIcon( USHORT nIcon )
+{
+ if( (m_nStyle & (SAL_FRAME_STYLE_PLUG|SAL_FRAME_STYLE_SYSTEMCHILD|SAL_FRAME_STYLE_FLOAT|SAL_FRAME_STYLE_INTRO|SAL_FRAME_STYLE_OWNERDRAWDECORATION))
+ || ! m_pWindow )
+ return;
+
+ if( !ImplGetResMgr() )
+ return;
+
+ GdkPixbuf *pBuf;
+ GList *pIcons = NULL;
+
+ USHORT nOffsets[2] = { SV_ICON_SMALL_START, SV_ICON_LARGE_START };
+ USHORT nIndex;
+
+ // Use high contrast icons where appropriate
+ if( Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
+ {
+ nOffsets[0] = SV_ICON_LARGE_HC_START;
+ nOffsets[1] = SV_ICON_SMALL_HC_START;
+ }
+
+ for( nIndex = 0; nIndex < sizeof(nOffsets)/ sizeof(USHORT); nIndex++ )
+ {
+ // #i44723# workaround gcc temporary problem
+ ResId aResId( nOffsets[nIndex] + nIcon, *ImplGetResMgr() );
+ BitmapEx aIcon( aResId );
+
+ // #i81083# convert to 24bit/8bit alpha bitmap
+ Bitmap aBmp = aIcon.GetBitmap();
+ if( aBmp.GetBitCount() != 24 || ! aIcon.IsAlpha() )
+ {
+ if( aBmp.GetBitCount() != 24 )
+ aBmp.Convert( BMP_CONVERSION_24BIT );
+ AlphaMask aMask;
+ if( ! aIcon.IsAlpha() )
+ {
+ switch( aIcon.GetTransparentType() )
+ {
+ case TRANSPARENT_NONE:
+ {
+ BYTE nTrans = 0;
+ aMask = AlphaMask( aBmp.GetSizePixel(), &nTrans );
+ }
+ break;
+ case TRANSPARENT_COLOR:
+ aMask = AlphaMask( aBmp.CreateMask( aIcon.GetTransparentColor() ) );
+ break;
+ case TRANSPARENT_BITMAP:
+ aMask = AlphaMask( aIcon.GetMask() );
+ break;
+ default:
+ DBG_ERROR( "unhandled transparent type" );
+ break;
+ }
+ }
+ else
+ aMask = aIcon.GetAlpha();
+ aIcon = BitmapEx( aBmp, aMask );
+ }
+
+ ImpBitmap *pIconImpBitmap = aIcon.ImplGetBitmapImpBitmap();
+ ImpBitmap *pIconImpMask = aIcon.ImplGetMaskImpBitmap();
+
+
+ if( pIconImpBitmap && pIconImpMask )
+ {
+ SalBitmap *pIconBitmap =
+ pIconImpBitmap->ImplGetSalBitmap();
+ SalBitmap *pIconMask =
+ pIconImpMask->ImplGetSalBitmap();
+
+ if( ( pBuf = bitmapToPixbuf( pIconBitmap, pIconMask ) ) )
+ pIcons = g_list_prepend( pIcons, pBuf );
+ }
+ }
+
+ gtk_window_set_icon_list( GTK_WINDOW(m_pWindow), pIcons );
+
+ g_list_foreach( pIcons, (GFunc) g_object_unref, NULL );
+ g_list_free( pIcons );
+}
+
+void GtkSalFrame::SetMenu( SalMenu* )
+{
+}
+
+void GtkSalFrame::DrawMenuBar()
+{
+}
+
+void GtkSalFrame::Center()
+{
+ long nX, nY;
+
+ if( m_pParent )
+ {
+ nX = ((long)m_pParent->maGeometry.nWidth - (long)maGeometry.nWidth)/2;
+ nY = ((long)m_pParent->maGeometry.nHeight - (long)maGeometry.nHeight)/2;
+
+ }
+ else
+ {
+ long nScreenWidth, nScreenHeight;
+ long nScreenX = 0, nScreenY = 0;
+
+ Size aScreenSize = GetX11SalData()->GetDisplay()->GetScreenSize( m_nScreen );
+ nScreenWidth = aScreenSize.Width();
+ nScreenHeight = aScreenSize.Height();
+ if( GetX11SalData()->GetDisplay()->IsXinerama() )
+ {
+ // get xinerama screen we are on
+ // if there is a parent, use its center for screen determination
+ // else use the pointer
+ GdkScreen* pScreen;
+ gint x, y;
+ GdkModifierType aMask;
+ gdk_display_get_pointer( getGdkDisplay(), &pScreen, &x, &y, &aMask );
+
+ const std::vector< Rectangle >& rScreens = GetX11SalData()->GetDisplay()->GetXineramaScreens();
+ for( unsigned int i = 0; i < rScreens.size(); i++ )
+ if( rScreens[i].IsInside( Point( x, y ) ) )
+ {
+ nScreenX = rScreens[i].Left();
+ nScreenY = rScreens[i].Top();
+ nScreenWidth = rScreens[i].GetWidth();
+ nScreenHeight = rScreens[i].GetHeight();
+ break;
+ }
+ }
+ nX = nScreenX + (nScreenWidth - (long)maGeometry.nWidth)/2;
+ nY = nScreenY + (nScreenHeight - (long)maGeometry.nHeight)/2;
+ }
+ SetPosSize( nX, nY, 0, 0, SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y );
+}
+
+Size GtkSalFrame::calcDefaultSize()
+{
+ Size aScreenSize = GetX11SalData()->GetDisplay()->GetScreenSize( m_nScreen );
+ long w = aScreenSize.Width();
+ long h = aScreenSize.Height();
+
+ // fill in holy default values brought to us by product management
+ if( aScreenSize.Width() >= 800 )
+ w = 785;
+ if( aScreenSize.Width() >= 1024 )
+ w = 920;
+
+ if( aScreenSize.Height() >= 600 )
+ h = 550;
+ if( aScreenSize.Height() >= 768 )
+ h = 630;
+ if( aScreenSize.Height() >= 1024 )
+ h = 875;
+
+ return Size( w, h );
+}
+
+void GtkSalFrame::SetDefaultSize()
+{
+ Size aDefSize = calcDefaultSize();
+
+ SetPosSize( 0, 0, aDefSize.Width(), aDefSize.Height(),
+ SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT );
+
+ if( (m_nStyle & SAL_FRAME_STYLE_DEFAULT) && m_pWindow )
+ gtk_window_maximize( GTK_WINDOW(m_pWindow) );
+}
+
+static void initClientId()
+{
+ static bool bOnce = false;
+ if( ! bOnce )
+ {
+ bOnce = true;
+ const ByteString& rID = SessionManagerClient::getSessionID();
+ if( rID.Len() > 0 )
+ gdk_set_sm_client_id(rID.GetBuffer());
+ }
+}
+
+void GtkSalFrame::Show( BOOL bVisible, BOOL bNoActivate )
+{
+ if( m_pWindow )
+ {
+ if( m_pParent && (m_pParent->m_nStyle & SAL_FRAME_STYLE_PARTIAL_FULLSCREEN)
+ && getDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() )
+ gtk_window_set_keep_above( GTK_WINDOW(m_pWindow), bVisible );
+ if( bVisible )
+ {
+ SessionManagerClient::open(); // will simply return after the first time
+ initClientId();
+ getDisplay()->startupNotificationCompleted();
+
+ if( m_bDefaultPos )
+ Center();
+ if( m_bDefaultSize )
+ SetDefaultSize();
+ setMinMaxSize();
+
+ // #i45160# switch to desktop where a dialog with parent will appear
+ if( m_pParent && m_pParent->m_nWorkArea != m_nWorkArea && GTK_WIDGET_MAPPED(m_pParent->m_pWindow) )
+ getDisplay()->getWMAdaptor()->switchToWorkArea( m_pParent->m_nWorkArea );
+
+ if( isFloatGrabWindow() &&
+ m_pParent &&
+ m_nFloats == 0 &&
+ ! getDisplay()->GetCaptureFrame() )
+ {
+ /* #i63086#
+ * outsmart Metacity's "focus:mouse" mode
+ * which insists on taking the focus from the document
+ * to the new float. Grab focus to parent frame BEFORE
+ * showing the float (cannot grab it to the float
+ * before show).
+ */
+ m_pParent->grabPointer( TRUE, TRUE );
+ }
+
+ guint32 nUserTime = 0;
+ if( ! bNoActivate && (m_nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_TOOLWINDOW)) == 0 )
+ /* #i99360# ugly workaround an X11 library bug */
+ nUserTime= getDisplay()->GetLastUserEventTime( true );
+ //nUserTime = gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window);
+
+ //For these floating windows we don't want the main window to lose focus, and metacity has...
+ // metacity-2.24.0/src/core/window.c
+ //
+ // if ((focus_window != NULL) && XSERVER_TIME_IS_BEFORE (compare, focus_window->net_wm_user_time))
+ // "compare" window focus prevented by other activity
+ //
+ // where "compare" is this window
+
+ // which leads to...
+
+ // /* This happens for error dialogs or alerts; these need to remain on
+ // * top, but it would be confusing to have its ancestor remain
+ // * focused.
+ // */
+ // if (meta_window_is_ancestor_of_transient (focus_window, window))
+ // "The focus window %s is an ancestor of the newly mapped "
+ // "window %s which isn't being focused. Unfocusing the "
+ // "ancestor.\n",
+ //
+ // i.e. having a time < that of the toplevel frame means that the toplevel frame gets unfocused.
+ // awesome.
+ bool bHack =
+ getDisplay()->getWMAdaptor()->getWindowManagerName().EqualsAscii("Metacity") ||
+ getDisplay()->getWMAdaptor()->getWindowManagerName().EqualsAscii("compiz")
+ ;
+ if( nUserTime == 0 && bHack )
+ {
+ /* #i99360# ugly workaround an X11 library bug */
+ nUserTime= getDisplay()->GetLastUserEventTime( true );
+ //nUserTime = gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window);
+ }
+ lcl_set_user_time( GTK_WIDGET(m_pWindow)->window, nUserTime );
+
+ if( bHack && ! bNoActivate && (m_nStyle & SAL_FRAME_STYLE_TOOLWINDOW) )
+ m_bSetFocusOnMap = true;
+
+ gtk_widget_show( m_pWindow );
+
+ if( isFloatGrabWindow() )
+ {
+ m_nFloats++;
+ if( ! getDisplay()->GetCaptureFrame() && m_nFloats == 1 )
+ grabPointer( TRUE, TRUE );
+ // #i44068# reset parent's IM context
+ if( m_pParent )
+ m_pParent->EndExtTextInput(0);
+ }
+ if( m_bWindowIsGtkPlug )
+ askForXEmbedFocus( 0 );
+ }
+ else
+ {
+ if( isFloatGrabWindow() )
+ {
+ m_nFloats--;
+ if( ! getDisplay()->GetCaptureFrame() && m_nFloats == 0)
+ grabPointer( FALSE );
+ }
+ gtk_widget_hide( m_pWindow );
+ if( m_pIMHandler )
+ m_pIMHandler->focusChanged( false );
+ // flush here; there may be a very seldom race between
+ // the display connection used for clipboard and our connection
+ Flush();
+ }
+ CallCallback( SALEVENT_RESIZE, NULL );
+ }
+}
+
+void GtkSalFrame::Enable( BOOL /*bEnable*/ )
+{
+ // Not implemented by X11SalFrame either
+}
+
+void GtkSalFrame::setMinMaxSize()
+{
+/* FIXME: for yet unknown reasons the reported size is a little smaller
+ * than the max size hint; one would guess that this was due to the border
+ * sizes of the widgets involved (GtkWindow and GtkFixed), but setting the
+ * their border to 0 (which is the default anyway) does not change the
+ * behaviour. Until the reason is known we'll add some pixels here.
+ */
+#define CONTAINER_ADJUSTMENT 6
+
+ /* #i34504# metacity (and possibly others) do not treat
+ * _NET_WM_STATE_FULLSCREEN and max_width/heigth independently;
+ * whether they should is undefined. So don't set the max size hint
+ * for a full screen window.
+ */
+ if( m_pWindow && ! isChild() )
+ {
+ GdkGeometry aGeo;
+ int aHints = 0;
+ if( m_nStyle & SAL_FRAME_STYLE_SIZEABLE )
+ {
+ if( m_aMinSize.Width() && m_aMinSize.Height() )
+ {
+ aGeo.min_width = m_aMinSize.Width()+CONTAINER_ADJUSTMENT;
+ aGeo.min_height = m_aMinSize.Height()+CONTAINER_ADJUSTMENT;
+ aHints |= GDK_HINT_MIN_SIZE;
+ }
+ if( m_aMaxSize.Width() && m_aMaxSize.Height() && ! m_bFullscreen )
+ {
+ aGeo.max_width = m_aMaxSize.Width()+CONTAINER_ADJUSTMENT;
+ aGeo.max_height = m_aMaxSize.Height()+CONTAINER_ADJUSTMENT;
+ aHints |= GDK_HINT_MAX_SIZE;
+ }
+ }
+ else
+ {
+ aGeo.min_width = maGeometry.nWidth;
+ aGeo.min_height = maGeometry.nHeight;
+ aHints |= GDK_HINT_MIN_SIZE;
+ if( ! m_bFullscreen )
+ {
+ aGeo.max_width = maGeometry.nWidth;
+ aGeo.max_height = maGeometry.nHeight;
+ aHints |= GDK_HINT_MAX_SIZE;
+ }
+ }
+ if( m_bFullscreen )
+ {
+ aGeo.max_width = m_aMaxSize.Width();
+ aGeo.max_height = m_aMaxSize.Height();
+ aHints |= GDK_HINT_MAX_SIZE;
+ }
+ if( aHints )
+ gtk_window_set_geometry_hints( GTK_WINDOW(m_pWindow),
+ NULL,
+ &aGeo,
+ GdkWindowHints( aHints ) );
+ }
+}
+
+void GtkSalFrame::SetMaxClientSize( long nWidth, long nHeight )
+{
+ if( ! isChild() )
+ {
+ m_aMaxSize = Size( nWidth, nHeight );
+ // Show does a setMinMaxSize
+ if( GTK_WIDGET_MAPPED( m_pWindow ) )
+ setMinMaxSize();
+ }
+}
+void GtkSalFrame::SetMinClientSize( long nWidth, long nHeight )
+{
+ if( ! isChild() )
+ {
+ m_aMinSize = Size( nWidth, nHeight );
+ if( m_pWindow )
+ {
+ gtk_widget_set_size_request( m_pWindow, nWidth, nHeight );
+ // Show does a setMinMaxSize
+ if( GTK_WIDGET_MAPPED( m_pWindow ) )
+ setMinMaxSize();
+ }
+ }
+}
+
+void GtkSalFrame::SetPosSize( long nX, long nY, long nWidth, long nHeight, USHORT nFlags )
+{
+ if( !m_pWindow || isChild( true, false ) )
+ return;
+
+ bool bSized = false, bMoved = false;
+
+ if( (nFlags & ( SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT )) &&
+ (nWidth > 0 && nHeight > 0 ) // sometimes stupid things happen
+ )
+ {
+ m_bDefaultSize = false;
+
+ if( (unsigned long)nWidth != maGeometry.nWidth || (unsigned long)nHeight != maGeometry.nHeight )
+ bSized = true;
+ maGeometry.nWidth = nWidth;
+ maGeometry.nHeight = nHeight;
+
+ if( isChild( false, true ) )
+ gtk_widget_set_size_request( m_pWindow, nWidth, nHeight );
+ else if( ! ( m_nState & GDK_WINDOW_STATE_MAXIMIZED ) )
+ gtk_window_resize( GTK_WINDOW(m_pWindow), nWidth, nHeight );
+ setMinMaxSize();
+ }
+ else if( m_bDefaultSize )
+ SetDefaultSize();
+
+ m_bDefaultSize = false;
+
+ if( nFlags & ( SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y ) )
+ {
+ if( m_pParent )
+ {
+ if( Application::GetSettings().GetLayoutRTL() )
+ nX = m_pParent->maGeometry.nWidth-maGeometry.nWidth-1-nX;
+ nX += m_pParent->maGeometry.nX;
+ nY += m_pParent->maGeometry.nY;
+ }
+
+ // adjust position to avoid off screen windows
+ // but allow toolbars to be positioned partly off screen by the user
+ Size aScreenSize = GetX11SalData()->GetDisplay()->GetScreenSize( m_nScreen );
+ if( ! (m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) )
+ {
+ if( nX < (long)maGeometry.nLeftDecoration )
+ nX = maGeometry.nLeftDecoration;
+ if( nY < (long)maGeometry.nTopDecoration )
+ nY = maGeometry.nTopDecoration;
+ if( (nX + (long)maGeometry.nWidth + (long)maGeometry.nRightDecoration) > (long)aScreenSize.Width() )
+ nX = aScreenSize.Width() - maGeometry.nWidth - maGeometry.nRightDecoration;
+ if( (nY + (long)maGeometry.nHeight + (long)maGeometry.nBottomDecoration) > (long)aScreenSize.Height() )
+ nY = aScreenSize.Height() - maGeometry.nHeight - maGeometry.nBottomDecoration;
+ }
+ else
+ {
+ if( nX + (long)maGeometry.nWidth < 10 )
+ nX = 10 - (long)maGeometry.nWidth;
+ if( nY + (long)maGeometry.nHeight < 10 )
+ nY = 10 - (long)maGeometry.nHeight;
+ if( nX > (long)aScreenSize.Width() - 10 )
+ nX = (long)aScreenSize.Width() - 10;
+ if( nY > (long)aScreenSize.Height() - 10 )
+ nY = (long)aScreenSize.Height() - 10;
+ }
+
+ if( nX != maGeometry.nX || nY != maGeometry.nY )
+ bMoved = true;
+ maGeometry.nX = nX;
+ maGeometry.nY = nY;
+
+ m_bDefaultPos = false;
+
+ moveWindow( maGeometry.nX, maGeometry.nY );
+
+ updateScreenNumber();
+ }
+ else if( m_bDefaultPos )
+ Center();
+
+ m_bDefaultPos = false;
+
+ if( bSized && ! bMoved )
+ CallCallback( SALEVENT_RESIZE, NULL );
+ else if( bMoved && ! bSized )
+ CallCallback( SALEVENT_MOVE, NULL );
+ else if( bMoved && bSized )
+ CallCallback( SALEVENT_MOVERESIZE, NULL );
+}
+
+void GtkSalFrame::GetClientSize( long& rWidth, long& rHeight )
+{
+ if( m_pWindow && !(m_nState & GDK_WINDOW_STATE_ICONIFIED) )
+ {
+ rWidth = maGeometry.nWidth;
+ rHeight = maGeometry.nHeight;
+ }
+ else
+ rWidth = rHeight = 0;
+}
+
+void GtkSalFrame::GetWorkArea( Rectangle& rRect )
+{
+ rRect = GetX11SalData()->GetDisplay()->getWMAdaptor()->getWorkArea( 0 );
+}
+
+SalFrame* GtkSalFrame::GetParent() const
+{
+ return m_pParent;
+}
+
+void GtkSalFrame::SetWindowState( const SalFrameState* pState )
+{
+ if( ! m_pWindow || ! pState || isChild( true, false ) )
+ return;
+
+ const ULONG nMaxGeometryMask =
+ SAL_FRAMESTATE_MASK_X | SAL_FRAMESTATE_MASK_Y |
+ SAL_FRAMESTATE_MASK_WIDTH | SAL_FRAMESTATE_MASK_HEIGHT |
+ SAL_FRAMESTATE_MASK_MAXIMIZED_X | SAL_FRAMESTATE_MASK_MAXIMIZED_Y |
+ SAL_FRAMESTATE_MASK_MAXIMIZED_WIDTH | SAL_FRAMESTATE_MASK_MAXIMIZED_HEIGHT;
+
+ if( (pState->mnMask & SAL_FRAMESTATE_MASK_STATE) &&
+ ! ( m_nState & GDK_WINDOW_STATE_MAXIMIZED ) &&
+ (pState->mnState & SAL_FRAMESTATE_MAXIMIZED) &&
+ (pState->mnMask & nMaxGeometryMask) == nMaxGeometryMask )
+ {
+ resizeWindow( pState->mnWidth, pState->mnHeight );
+ moveWindow( pState->mnX, pState->mnY );
+ m_bDefaultPos = m_bDefaultSize = false;
+
+ maGeometry.nX = pState->mnMaximizedX;
+ maGeometry.nY = pState->mnMaximizedY;
+ maGeometry.nWidth = pState->mnMaximizedWidth;
+ maGeometry.nHeight = pState->mnMaximizedHeight;
+ updateScreenNumber();
+
+ m_nState = GdkWindowState( m_nState | GDK_WINDOW_STATE_MAXIMIZED );
+ m_aRestorePosSize = Rectangle( Point( pState->mnX, pState->mnY ),
+ Size( pState->mnWidth, pState->mnHeight ) );
+ }
+ else if( pState->mnMask & (SAL_FRAMESTATE_MASK_X | SAL_FRAMESTATE_MASK_Y |
+ SAL_FRAMESTATE_MASK_WIDTH | SAL_FRAMESTATE_MASK_HEIGHT ) )
+ {
+ USHORT nPosSizeFlags = 0;
+ long nX = pState->mnX - (m_pParent ? m_pParent->maGeometry.nX : 0);
+ long nY = pState->mnY - (m_pParent ? m_pParent->maGeometry.nY : 0);
+ long nWidth = pState->mnWidth;
+ long nHeight = pState->mnHeight;
+ if( pState->mnMask & SAL_FRAMESTATE_MASK_X )
+ nPosSizeFlags |= SAL_FRAME_POSSIZE_X;
+ else
+ nX = maGeometry.nX - (m_pParent ? m_pParent->maGeometry.nX : 0);
+ if( pState->mnMask & SAL_FRAMESTATE_MASK_Y )
+ nPosSizeFlags |= SAL_FRAME_POSSIZE_Y;
+ else
+ nY = maGeometry.nY - (m_pParent ? m_pParent->maGeometry.nY : 0);
+ if( pState->mnMask & SAL_FRAMESTATE_MASK_WIDTH )
+ nPosSizeFlags |= SAL_FRAME_POSSIZE_WIDTH;
+ else
+ nWidth = maGeometry.nWidth;
+ if( pState->mnMask & SAL_FRAMESTATE_MASK_HEIGHT )
+ nPosSizeFlags |= SAL_FRAME_POSSIZE_HEIGHT;
+ else
+ nHeight = maGeometry.nHeight;
+ SetPosSize( nX, nY, pState->mnWidth, pState->mnHeight, nPosSizeFlags );
+ }
+ if( pState->mnMask & SAL_FRAMESTATE_MASK_STATE && ! isChild() )
+ {
+ if( pState->mnState & SAL_FRAMESTATE_MAXIMIZED )
+ gtk_window_maximize( GTK_WINDOW(m_pWindow) );
+ else
+ gtk_window_unmaximize( GTK_WINDOW(m_pWindow) );
+ /* #i42379# there is no rollup state in GDK; and rolled up windows are
+ * (probably depending on the WM) reported as iconified. If we iconify a
+ * window here that was e.g. a dialog, then it will be unmapped but still
+ * not be displayed in the task list, so it's an iconified window that
+ * the user cannot get out of this state. So do not set the iconified state
+ * on windows with a parent (that is transient frames) since these tend
+ * to not be represented in an icon task list.
+ */
+ if( (pState->mnState & SAL_FRAMESTATE_MINIMIZED)
+ && ! m_pParent )
+ gtk_window_iconify( GTK_WINDOW(m_pWindow) );
+ else
+ gtk_window_deiconify( GTK_WINDOW(m_pWindow) );
+ }
+}
+
+BOOL GtkSalFrame::GetWindowState( SalFrameState* pState )
+{
+ pState->mnState = SAL_FRAMESTATE_NORMAL;
+ pState->mnMask = SAL_FRAMESTATE_MASK_STATE;
+ // rollup ? gtk 2.2 does not seem to support the shaded state
+ if( (m_nState & GDK_WINDOW_STATE_ICONIFIED) )
+ pState->mnState |= SAL_FRAMESTATE_MINIMIZED;
+ if( m_nState & GDK_WINDOW_STATE_MAXIMIZED )
+ {
+ pState->mnState |= SAL_FRAMESTATE_MAXIMIZED;
+ pState->mnX = m_aRestorePosSize.Left();
+ pState->mnY = m_aRestorePosSize.Top();
+ pState->mnWidth = m_aRestorePosSize.GetWidth();
+ pState->mnHeight = m_aRestorePosSize.GetHeight();
+ pState->mnMaximizedX = maGeometry.nX;
+ pState->mnMaximizedY = maGeometry.nY;
+ pState->mnMaximizedWidth = maGeometry.nWidth;
+ pState->mnMaximizedHeight = maGeometry.nHeight;
+ pState->mnMask |= SAL_FRAMESTATE_MASK_MAXIMIZED_X |
+ SAL_FRAMESTATE_MASK_MAXIMIZED_Y |
+ SAL_FRAMESTATE_MASK_MAXIMIZED_WIDTH |
+ SAL_FRAMESTATE_MASK_MAXIMIZED_HEIGHT;
+ }
+ else
+ {
+
+ pState->mnX = maGeometry.nX;
+ pState->mnY = maGeometry.nY;
+ pState->mnWidth = maGeometry.nWidth;
+ pState->mnHeight = maGeometry.nHeight;
+ }
+ pState->mnMask |= SAL_FRAMESTATE_MASK_X |
+ SAL_FRAMESTATE_MASK_Y |
+ SAL_FRAMESTATE_MASK_WIDTH |
+ SAL_FRAMESTATE_MASK_HEIGHT;
+
+ return TRUE;
+}
+
+void GtkSalFrame::moveToScreen( int nScreen )
+{
+ if( isChild() )
+ return;
+
+ if( nScreen < 0 || nScreen >= gdk_display_get_n_screens( getGdkDisplay() ) )
+ nScreen = m_nScreen;
+ if( nScreen == m_nScreen )
+ return;
+
+ GdkScreen* pScreen = gdk_display_get_screen( getGdkDisplay(), nScreen );
+ if( pScreen )
+ {
+ m_nScreen = nScreen;
+ gtk_window_set_screen( GTK_WINDOW(m_pWindow), pScreen );
+ // realize the window, we need an XWindow id
+ gtk_widget_realize( m_pWindow );
+ // update system data
+ GtkSalDisplay* pDisp = getDisplay();
+ m_aSystemData.aWindow = GDK_WINDOW_XWINDOW(m_pWindow->window);
+ m_aSystemData.pVisual = pDisp->GetVisual( m_nScreen ).GetVisual();
+ m_aSystemData.nScreen = nScreen;
+ m_aSystemData.nDepth = pDisp->GetVisual( m_nScreen ).GetDepth();
+ m_aSystemData.aColormap = pDisp->GetColormap( m_nScreen ).GetXColormap();
+ m_aSystemData.pAppContext = NULL;
+ m_aSystemData.aShellWindow = m_aSystemData.aWindow;
+ // update graphics if necessary
+ for( unsigned int i = 0; i < sizeof(m_aGraphics)/sizeof(m_aGraphics[0]); i++ )
+ {
+ if( m_aGraphics[i].bInUse )
+ m_aGraphics[i].pGraphics->SetDrawable( GDK_WINDOW_XWINDOW(m_pWindow->window), m_nScreen );
+ }
+ updateScreenNumber();
+ }
+
+ if( m_pParent && m_pParent->m_nScreen != m_nScreen )
+ SetParent( NULL );
+ std::list< GtkSalFrame* > aChildren = m_aChildren;
+ for( std::list< GtkSalFrame* >::iterator it = aChildren.begin(); it != aChildren.end(); ++it )
+ (*it)->moveToScreen( m_nScreen );
+
+ // FIXME: SalObjects
+}
+
+void GtkSalFrame::SetScreenNumber( unsigned int nNewScreen )
+{
+ if( nNewScreen == maGeometry.nScreenNumber )
+ return;
+
+ if( m_pWindow && ! isChild() )
+ {
+ GtkSalDisplay* pDisp = getDisplay();
+ if( pDisp->IsXinerama() && pDisp->GetXineramaScreens().size() > 1 )
+ {
+ if( nNewScreen >= pDisp->GetXineramaScreens().size() )
+ return;
+
+ Rectangle aOldScreenRect( pDisp->GetXineramaScreens()[maGeometry.nScreenNumber] );
+ Rectangle aNewScreenRect( pDisp->GetXineramaScreens()[nNewScreen] );
+ bool bVisible = GTK_WIDGET_MAPPED(m_pWindow);
+ if( bVisible )
+ Show( FALSE );
+ maGeometry.nX = aNewScreenRect.Left() + (maGeometry.nX - aOldScreenRect.Left());
+ maGeometry.nY = aNewScreenRect.Top() + (maGeometry.nY - aOldScreenRect.Top());
+ createNewWindow( None, false, m_nScreen );
+ gtk_window_move( GTK_WINDOW(m_pWindow), maGeometry.nX, maGeometry.nY );
+ if( bVisible )
+ Show( TRUE );
+ maGeometry.nScreenNumber = nNewScreen;
+ }
+ else if( sal_Int32(nNewScreen) < pDisp->GetScreenCount() )
+ {
+ moveToScreen( (int)nNewScreen );
+ maGeometry.nScreenNumber = nNewScreen;
+ gtk_window_move( GTK_WINDOW(m_pWindow), maGeometry.nX, maGeometry.nY );
+ }
+ }
+}
+
+void GtkSalFrame::ShowFullScreen( BOOL bFullScreen, sal_Int32 nScreen )
+{
+ if( m_pWindow && ! isChild() )
+ {
+ GtkSalDisplay* pDisp = getDisplay();
+ // xinerama ?
+ if( pDisp->IsXinerama() && pDisp->GetXineramaScreens().size() > 1 )
+ {
+ if( bFullScreen )
+ {
+ m_aRestorePosSize = Rectangle( Point( maGeometry.nX, maGeometry.nY ),
+ Size( maGeometry.nWidth, maGeometry.nHeight ) );
+ bool bVisible = GTK_WIDGET_MAPPED(m_pWindow);
+ if( bVisible )
+ Show( FALSE );
+ m_nStyle |= SAL_FRAME_STYLE_PARTIAL_FULLSCREEN;
+ createNewWindow( None, false, m_nScreen );
+ Rectangle aNewPosSize;
+ if( nScreen < 0 || nScreen >= static_cast<int>(pDisp->GetXineramaScreens().size()) )
+ aNewPosSize = Rectangle( Point( 0, 0 ), pDisp->GetScreenSize(m_nScreen) );
+ else
+ aNewPosSize = pDisp->GetXineramaScreens()[ nScreen ];
+ gtk_window_resize( GTK_WINDOW(m_pWindow),
+ maGeometry.nWidth = aNewPosSize.GetWidth(),
+ maGeometry.nHeight = aNewPosSize.GetHeight() );
+ gtk_window_move( GTK_WINDOW(m_pWindow),
+ maGeometry.nX = aNewPosSize.Left(),
+ maGeometry.nY = aNewPosSize.Top() );
+ // #i110881# for the benefit of compiz set a max size here
+ // else setting to fullscreen fails for unknown reasons
+ m_aMaxSize.Width() = aNewPosSize.GetWidth()+100;
+ m_aMaxSize.Height() = aNewPosSize.GetHeight()+100;
+ // workaround different legacy version window managers have different opinions about
+ // _NET_WM_STATE_FULLSCREEN (Metacity <-> KWin)
+ if( ! getDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() )
+ gtk_window_fullscreen( GTK_WINDOW( m_pWindow ) );
+ if( bVisible )
+ Show( TRUE );
+ }
+ else
+ {
+ bool bVisible = GTK_WIDGET_MAPPED(m_pWindow);
+ if( ! getDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() )
+ gtk_window_unfullscreen( GTK_WINDOW(m_pWindow) );
+ if( bVisible )
+ Show( FALSE );
+ m_nStyle &= ~SAL_FRAME_STYLE_PARTIAL_FULLSCREEN;
+ createNewWindow( None, false, m_nScreen );
+ if( ! m_aRestorePosSize.IsEmpty() )
+ {
+ gtk_window_resize( GTK_WINDOW(m_pWindow),
+ maGeometry.nWidth = m_aRestorePosSize.GetWidth(),
+ maGeometry.nHeight = m_aRestorePosSize.GetHeight() );
+ gtk_window_move( GTK_WINDOW(m_pWindow),
+ maGeometry.nX = m_aRestorePosSize.Left(),
+ maGeometry.nY = m_aRestorePosSize.Top() );
+ m_aRestorePosSize = Rectangle();
+ }
+ if( bVisible )
+ Show( TRUE );
+ }
+ }
+ else
+ {
+ if( bFullScreen )
+ {
+ if( getDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() )
+ {
+ if( !(m_nStyle & SAL_FRAME_STYLE_SIZEABLE) )
+ gtk_window_set_resizable( GTK_WINDOW(m_pWindow), TRUE );
+ }
+ gtk_window_fullscreen( GTK_WINDOW(m_pWindow) );
+ moveToScreen( nScreen );
+ Size aScreenSize = pDisp->GetScreenSize( m_nScreen );
+ maGeometry.nX = 0;
+ maGeometry.nY = 0;
+ maGeometry.nWidth = aScreenSize.Width();
+ maGeometry.nHeight = aScreenSize.Height();
+ }
+ else
+ {
+ gtk_window_unfullscreen( GTK_WINDOW(m_pWindow) );
+ if( getDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() )
+ {
+ if( !(m_nStyle & SAL_FRAME_STYLE_SIZEABLE) )
+ gtk_window_set_resizable( GTK_WINDOW(m_pWindow), FALSE );
+ }
+ moveToScreen( nScreen );
+ }
+ }
+ m_bDefaultPos = m_bDefaultSize = false;
+ updateScreenNumber();
+ CallCallback( SALEVENT_MOVERESIZE, NULL );
+ }
+ m_bFullscreen = bFullScreen;
+}
+
+/* definitions from xautolock.c (pl15) */
+#define XAUTOLOCK_DISABLE 1
+#define XAUTOLOCK_ENABLE 2
+
+void GtkSalFrame::setAutoLock( bool bLock )
+{
+ if( isChild() )
+ return;
+
+ GdkScreen *pScreen = gtk_window_get_screen( GTK_WINDOW(m_pWindow) );
+ GdkDisplay *pDisplay = gdk_screen_get_display( pScreen );
+ GdkWindow *pRootWin = gdk_screen_get_root_window( pScreen );
+
+ Atom nAtom = XInternAtom( GDK_DISPLAY_XDISPLAY( pDisplay ),
+ "XAUTOLOCK_MESSAGE", False );
+
+ int nMessage = bLock ? XAUTOLOCK_ENABLE : XAUTOLOCK_DISABLE;
+
+ XChangeProperty( GDK_DISPLAY_XDISPLAY( pDisplay ),
+ GDK_WINDOW_XID( pRootWin ),
+ nAtom, XA_INTEGER,
+ 8, PropModeReplace,
+ (unsigned char*)&nMessage,
+ sizeof( nMessage ) );
+}
+
+#ifdef ENABLE_DBUS
+/** cookie is returned as an unsigned integer */
+static guint
+dbus_inhibit_gsm (const gchar *appname,
+ const gchar *reason,
+ guint xid)
+{
+ gboolean res;
+ guint cookie;
+ GError *error = NULL;
+ DBusGProxy *proxy = NULL;
+ DBusGConnection *session_connection = NULL;
+
+ /* get the DBUS session connection */
+ session_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+ if (error != NULL) {
+ g_warning ("DBUS cannot connect : %s", error->message);
+ g_error_free (error);
+ return -1;
+ }
+
+ /* get the proxy with gnome-session-manager */
+ proxy = dbus_g_proxy_new_for_name (session_connection,
+ GSM_DBUS_SERVICE,
+ GSM_DBUS_PATH,
+ GSM_DBUS_INTERFACE);
+ if (proxy == NULL) {
+ g_warning ("Could not get DBUS proxy: %s", GSM_DBUS_SERVICE);
+ return -1;
+ }
+
+ res = dbus_g_proxy_call (proxy,
+ "Inhibit", &error,
+ G_TYPE_STRING, appname,
+ G_TYPE_UINT, xid,
+ G_TYPE_STRING, reason,
+ G_TYPE_UINT, 8, //Inhibit the session being marked as idle
+ G_TYPE_INVALID,
+ G_TYPE_UINT, &cookie,
+ G_TYPE_INVALID);
+
+ /* check the return value */
+ if (! res) {
+ cookie = -1;
+ g_warning ("Inhibit method failed");
+ }
+
+ /* check the error value */
+ if (error != NULL) {
+ g_warning ("Inhibit problem : %s", error->message);
+ g_error_free (error);
+ cookie = -1;
+ }
+
+ g_object_unref (G_OBJECT (proxy));
+ return cookie;
+}
+
+static void
+dbus_uninhibit_gsm (guint cookie)
+{
+ gboolean res;
+ GError *error = NULL;
+ DBusGProxy *proxy = NULL;
+ DBusGConnection *session_connection = NULL;
+
+ if (cookie == guint(-1)) {
+ g_warning ("Invalid cookie");
+ return;
+ }
+
+ /* get the DBUS session connection */
+ session_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+ if (error) {
+ g_warning ("DBUS cannot connect : %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ /* get the proxy with gnome-session-manager */
+ proxy = dbus_g_proxy_new_for_name (session_connection,
+ GSM_DBUS_SERVICE,
+ GSM_DBUS_PATH,
+ GSM_DBUS_INTERFACE);
+ if (proxy == NULL) {
+ g_warning ("Could not get DBUS proxy: %s", GSM_DBUS_SERVICE);
+ return;
+ }
+
+ res = dbus_g_proxy_call (proxy,
+ "Uninhibit",
+ &error,
+ G_TYPE_UINT, cookie,
+ G_TYPE_INVALID,
+ G_TYPE_INVALID);
+
+ /* check the return value */
+ if (! res) {
+ g_warning ("Uninhibit method failed");
+ }
+
+ /* check the error value */
+ if (error != NULL) {
+ g_warning ("Uninhibit problem : %s", error->message);
+ g_error_free (error);
+ cookie = -1;
+ }
+ g_object_unref (G_OBJECT (proxy));
+}
+#endif
+
+void GtkSalFrame::StartPresentation( BOOL bStart )
+{
+ Display *pDisplay = GDK_DISPLAY_XDISPLAY( getGdkDisplay() );
+
+ setAutoLock( !bStart );
+
+ int nTimeout, nInterval, bPreferBlanking, bAllowExposures;
+
+ XGetScreenSaver( pDisplay, &nTimeout, &nInterval,
+ &bPreferBlanking, &bAllowExposures );
+ if( bStart )
+ {
+ if ( nTimeout )
+ {
+ m_nSavedScreenSaverTimeout = nTimeout;
+ XResetScreenSaver( pDisplay );
+ XSetScreenSaver( pDisplay, 0, nInterval,
+ bPreferBlanking, bAllowExposures );
+ }
+#ifdef ENABLE_DBUS
+ m_nGSMCookie = dbus_inhibit_gsm(g_get_application_name(), "presentation",
+ GDK_WINDOW_XID(m_pWindow->window));
+#endif
+ }
+ else
+ {
+ if( m_nSavedScreenSaverTimeout )
+ XSetScreenSaver( pDisplay, m_nSavedScreenSaverTimeout,
+ nInterval, bPreferBlanking,
+ bAllowExposures );
+ m_nSavedScreenSaverTimeout = 0;
+#ifdef ENABLE_DBUS
+ dbus_uninhibit_gsm(m_nGSMCookie);
+#endif
+ }
+}
+
+void GtkSalFrame::SetAlwaysOnTop( BOOL /*bOnTop*/ )
+{
+}
+
+void GtkSalFrame::ToTop( USHORT nFlags )
+{
+ if( m_pWindow )
+ {
+ if( isChild( false, true ) )
+ gtk_widget_grab_focus( m_pWindow );
+ else if( GTK_WIDGET_MAPPED( m_pWindow ) )
+ {
+ if( ! (nFlags & SAL_FRAME_TOTOP_GRABFOCUS_ONLY) )
+ gtk_window_present( GTK_WINDOW(m_pWindow) );
+ else
+ {
+ // gdk_window_focus( m_pWindow->window, gdk_x11_get_server_time(GTK_WIDGET (m_pWindow)->window) );
+ /* #i99360# ugly workaround an X11 library bug */
+ guint32 nUserTime= getDisplay()->GetLastUserEventTime( true );
+ gdk_window_focus( m_pWindow->window, nUserTime );
+ }
+ /* need to do an XSetInputFocus here because
+ * gdk_window_focus will ask a EWMH compliant WM to put the focus
+ * to our window - which it of course won't since our input hint
+ * is set to false.
+ */
+ if( (m_nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_FLOAT_FOCUSABLE)) )
+ {
+ // sad but true: this can cause an XError, we need to catch that
+ // to do this we need to synchronize with the XServer
+ getDisplay()->GetXLib()->PushXErrorLevel( true );
+ XSetInputFocus( getDisplay()->GetDisplay(), GDK_WINDOW_XWINDOW( m_pWindow->window ), RevertToParent, CurrentTime );
+ XSync( getDisplay()->GetDisplay(), False );
+ getDisplay()->GetXLib()->PopXErrorLevel();
+ }
+ }
+ else
+ {
+ if( nFlags & SAL_FRAME_TOTOP_RESTOREWHENMIN )
+ gtk_window_present( GTK_WINDOW(m_pWindow) );
+ }
+ }
+}
+
+void GtkSalFrame::SetPointer( PointerStyle ePointerStyle )
+{
+ if( m_pWindow && ePointerStyle != m_ePointerStyle )
+ {
+ m_ePointerStyle = ePointerStyle;
+ GdkCursor *pCursor = getDisplay()->getCursor( ePointerStyle );
+ gdk_window_set_cursor( m_pWindow->window, pCursor );
+ m_pCurrentCursor = pCursor;
+
+ // #i80791# use grabPointer the same way as CaptureMouse, respective float grab
+ if( getDisplay()->MouseCaptured( this ) )
+ grabPointer( TRUE, FALSE );
+ else if( m_nFloats > 0 )
+ grabPointer( TRUE, TRUE );
+ }
+}
+
+void GtkSalFrame::grabPointer( BOOL bGrab, BOOL bOwnerEvents )
+{
+ if( m_pWindow )
+ {
+ if( bGrab )
+ {
+ bool bUseGdkGrab = true;
+ if( getDisplay()->getHaveSystemChildFrame() )
+ {
+ const std::list< SalFrame* >& rFrames = getDisplay()->getFrames();
+ for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it )
+ {
+ const GtkSalFrame* pFrame = static_cast< const GtkSalFrame* >(*it);
+ if( pFrame->m_bWindowIsGtkPlug )
+ {
+ bUseGdkGrab = false;
+ break;
+ }
+ }
+ }
+ if( bUseGdkGrab )
+ {
+ const int nMask = ( GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK );
+
+ gdk_pointer_grab( m_pWindow->window, bOwnerEvents,
+ (GdkEventMask) nMask, NULL, m_pCurrentCursor,
+ GDK_CURRENT_TIME );
+ }
+ else
+ {
+ // FIXME: for some unknown reason gdk_pointer_grab does not
+ // really produce owner events for GtkPlug windows
+ // the cause is yet unknown
+ //
+ // this is of course a bad hack, especially as we cannot
+ // set the right cursor this way
+ XGrabPointer( getDisplay()->GetDisplay(),
+ GDK_WINDOW_XWINDOW( m_pWindow->window),
+ bOwnerEvents,
+ PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
+ GrabModeAsync,
+ GrabModeAsync,
+ None,
+ None,
+ CurrentTime
+ );
+
+ }
+ }
+ else
+ {
+ // Two GdkDisplays may be open
+ gdk_display_pointer_ungrab( getGdkDisplay(), GDK_CURRENT_TIME);
+ }
+ }
+}
+
+void GtkSalFrame::CaptureMouse( BOOL bCapture )
+{
+ getDisplay()->CaptureMouse( bCapture ? this : NULL );
+}
+
+void GtkSalFrame::SetPointerPos( long nX, long nY )
+{
+ GtkSalFrame* pFrame = this;
+ while( pFrame && pFrame->isChild( false, true ) )
+ pFrame = pFrame->m_pParent;
+ if( ! pFrame )
+ return;
+
+ GdkScreen *pScreen = gtk_window_get_screen( GTK_WINDOW(pFrame->m_pWindow) );
+ GdkDisplay *pDisplay = gdk_screen_get_display( pScreen );
+
+ /* #87921# when the application tries to center the mouse in the dialog the
+ * window isn't mapped already. So use coordinates relative to the root window.
+ */
+ unsigned int nWindowLeft = maGeometry.nX + nX;
+ unsigned int nWindowTop = maGeometry.nY + nY;
+
+ XWarpPointer( GDK_DISPLAY_XDISPLAY (pDisplay), None,
+ GDK_WINDOW_XID (gdk_screen_get_root_window( pScreen ) ),
+ 0, 0, 0, 0, nWindowLeft, nWindowTop);
+ // #i38648# ask for the next motion hint
+ gint x, y;
+ GdkModifierType mask;
+ gdk_window_get_pointer( pFrame->m_pWindow->window, &x, &y, &mask );
+}
+
+void GtkSalFrame::Flush()
+{
+#ifdef HAVE_A_RECENT_GTK
+ gdk_display_flush( getGdkDisplay() );
+#else
+ XFlush (GDK_DISPLAY_XDISPLAY (getGdkDisplay()));
+#endif
+}
+
+void GtkSalFrame::Sync()
+{
+ gdk_display_sync( getGdkDisplay() );
+}
+
+String GtkSalFrame::GetSymbolKeyName( const String&, USHORT nKeyCode )
+{
+ return getDisplay()->GetKeyName( nKeyCode );
+}
+
+String GtkSalFrame::GetKeyName( USHORT nKeyCode )
+{
+ return getDisplay()->GetKeyName( nKeyCode );
+}
+
+GdkDisplay *GtkSalFrame::getGdkDisplay()
+{
+ return static_cast<GtkSalDisplay*>(GetX11SalData()->GetDisplay())->GetGdkDisplay();
+}
+
+GtkSalDisplay *GtkSalFrame::getDisplay()
+{
+ return static_cast<GtkSalDisplay*>(GetX11SalData()->GetDisplay());
+}
+
+SalFrame::SalPointerState GtkSalFrame::GetPointerState()
+{
+ SalPointerState aState;
+ GdkScreen* pScreen;
+ gint x, y;
+ GdkModifierType aMask;
+ gdk_display_get_pointer( getGdkDisplay(), &pScreen, &x, &y, &aMask );
+ aState.maPos = Point( x - maGeometry.nX, y - maGeometry.nY );
+ aState.mnState = GetMouseModCode( aMask );
+ return aState;
+}
+
+void GtkSalFrame::SetInputContext( SalInputContext* pContext )
+{
+ if( ! pContext )
+ return;
+
+ if( ! (pContext->mnOptions & SAL_INPUTCONTEXT_TEXT) )
+ return;
+
+ // create a new im context
+ if( ! m_pIMHandler )
+ m_pIMHandler = new IMHandler( this );
+ m_pIMHandler->setInputContext( pContext );
+}
+
+void GtkSalFrame::EndExtTextInput( USHORT nFlags )
+{
+ if( m_pIMHandler )
+ m_pIMHandler->endExtTextInput( nFlags );
+}
+
+BOOL GtkSalFrame::MapUnicodeToKeyCode( sal_Unicode , LanguageType , KeyCode& )
+{
+ // not supported yet
+ return FALSE;
+}
+
+LanguageType GtkSalFrame::GetInputLanguage()
+{
+ return LANGUAGE_DONTKNOW;
+}
+
+SalBitmap* GtkSalFrame::SnapShot()
+{
+ if( !m_pWindow )
+ return NULL;
+
+ X11SalBitmap *pBmp = new X11SalBitmap;
+ GdkWindow *pWin = m_pWindow->window;
+ if( pBmp->SnapShot( GDK_DISPLAY_XDISPLAY( getGdkDisplay() ),
+ GDK_WINDOW_XID( pWin ) ) )
+ return pBmp;
+ else
+ delete pBmp;
+
+ return NULL;
+}
+
+void GtkSalFrame::UpdateSettings( AllSettings& rSettings )
+{
+ if( ! m_pWindow )
+ return;
+
+ GtkSalGraphics* pGraphics = static_cast<GtkSalGraphics*>(m_aGraphics[0].pGraphics);
+ bool bFreeGraphics = false;
+ if( ! pGraphics )
+ {
+ pGraphics = static_cast<GtkSalGraphics*>(GetGraphics());
+ bFreeGraphics = true;
+ }
+
+ pGraphics->updateSettings( rSettings );
+
+ if( bFreeGraphics )
+ ReleaseGraphics( pGraphics );
+}
+
+void GtkSalFrame::Beep( SoundType eType )
+{
+ switch( eType )
+ {
+ case SOUND_DEFAULT:
+ case SOUND_ERROR:
+ gdk_display_beep( getGdkDisplay() );
+ break;
+ default:
+ break;
+ }
+}
+
+const SystemEnvData* GtkSalFrame::GetSystemData() const
+{
+ return &m_aSystemData;
+}
+
+void GtkSalFrame::SetParent( SalFrame* pNewParent )
+{
+ if( m_pParent )
+ m_pParent->m_aChildren.remove( this );
+ m_pParent = static_cast<GtkSalFrame*>(pNewParent);
+ if( m_pParent )
+ m_pParent->m_aChildren.push_back( this );
+ if( ! isChild() )
+ gtk_window_set_transient_for( GTK_WINDOW(m_pWindow),
+ (m_pParent && ! m_pParent->isChild(true,false)) ? GTK_WINDOW(m_pParent->m_pWindow) : NULL
+ );
+}
+
+void GtkSalFrame::createNewWindow( XLIB_Window aNewParent, bool bXEmbed, int nScreen )
+{
+ bool bWasVisible = GTK_WIDGET_MAPPED(m_pWindow);
+ if( bWasVisible )
+ Show( FALSE );
+
+ if( nScreen < 0 || nScreen >= getDisplay()->GetScreenCount() )
+ nScreen = m_nScreen;
+
+ SystemParentData aParentData;
+ aParentData.aWindow = aNewParent;
+ aParentData.bXEmbedSupport = bXEmbed;
+ if( aNewParent == None )
+ {
+ aNewParent = getDisplay()->GetRootWindow(nScreen);
+ aParentData.aWindow = None;
+ aParentData.bXEmbedSupport = false;
+ }
+ else
+ {
+ // is new parent a root window ?
+ Display* pDisp = getDisplay()->GetDisplay();
+ int nScreens = getDisplay()->GetScreenCount();
+ for( int i = 0; i < nScreens; i++ )
+ {
+ if( aNewParent == RootWindow( pDisp, i ) )
+ {
+ nScreen = i;
+ aParentData.aWindow = None;
+ aParentData.bXEmbedSupport = false;
+ break;
+ }
+ }
+ }
+
+ // free xrender resources
+ for( unsigned int i = 0; i < sizeof(m_aGraphics)/sizeof(m_aGraphics[0]); i++ )
+ if( m_aGraphics[i].bInUse )
+ m_aGraphics[i].pGraphics->SetDrawable( None, m_nScreen );
+
+ // first deinit frame
+ if( m_pIMHandler )
+ {
+ delete m_pIMHandler;
+ m_pIMHandler = NULL;
+ }
+ if( m_pRegion )
+ gdk_region_destroy( m_pRegion );
+ if( m_pFixedContainer )
+ gtk_widget_destroy( GTK_WIDGET(m_pFixedContainer) );
+ if( m_pWindow )
+ gtk_widget_destroy( m_pWindow );
+ if( m_pForeignParent )
+ g_object_unref( G_OBJECT(m_pForeignParent) );
+ if( m_pForeignTopLevel )
+ g_object_unref( G_OBJECT(m_pForeignTopLevel) );
+
+ // init new window
+ m_bDefaultPos = m_bDefaultSize = false;
+ if( aParentData.aWindow != None )
+ {
+ m_nStyle |= SAL_FRAME_STYLE_PLUG;
+ Init( &aParentData );
+ }
+ else
+ {
+ m_nStyle &= ~SAL_FRAME_STYLE_PLUG;
+ Init( (m_pParent && m_pParent->m_nScreen == m_nScreen) ? m_pParent : NULL, m_nStyle );
+ }
+
+ // update graphics
+ for( unsigned int i = 0; i < sizeof(m_aGraphics)/sizeof(m_aGraphics[0]); i++ )
+ {
+ if( m_aGraphics[i].bInUse )
+ {
+ m_aGraphics[i].pGraphics->SetDrawable( GDK_WINDOW_XWINDOW(m_pWindow->window), m_nScreen );
+ m_aGraphics[i].pGraphics->SetWindow( m_pWindow );
+ }
+ }
+
+ if( m_aTitle.Len() )
+ SetTitle( m_aTitle );
+
+ if( bWasVisible )
+ Show( TRUE );
+
+ std::list< GtkSalFrame* > aChildren = m_aChildren;
+ m_aChildren.clear();
+ for( std::list< GtkSalFrame* >::iterator it = aChildren.begin(); it != aChildren.end(); ++it )
+ (*it)->createNewWindow( None, false, m_nScreen );
+
+ // FIXME: SalObjects
+}
+
+bool GtkSalFrame::SetPluginParent( SystemParentData* pSysParent )
+{
+ if( pSysParent ) // this may be the first system child frame now
+ getDisplay()->setHaveSystemChildFrame();
+ createNewWindow( pSysParent->aWindow, (pSysParent->nSize > sizeof(long)) ? pSysParent->bXEmbedSupport : false, m_nScreen );
+ return true;
+}
+
+void GtkSalFrame::ResetClipRegion()
+{
+ if( m_pWindow )
+ gdk_window_shape_combine_region( m_pWindow->window, NULL, 0, 0 );
+}
+
+void GtkSalFrame::BeginSetClipRegion( ULONG )
+{
+ if( m_pRegion )
+ gdk_region_destroy( m_pRegion );
+ m_pRegion = gdk_region_new();
+}
+
+void GtkSalFrame::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
+{
+ if( m_pRegion )
+ {
+ GdkRectangle aRect;
+ aRect.x = nX;
+ aRect.y = nY;
+ aRect.width = nWidth;
+ aRect.height = nHeight;
+
+ gdk_region_union_with_rect( m_pRegion, &aRect );
+ }
+}
+
+void GtkSalFrame::EndSetClipRegion()
+{
+ if( m_pWindow && m_pRegion )
+ gdk_window_shape_combine_region( m_pWindow->window, m_pRegion, 0, 0 );
+}
+
+bool GtkSalFrame::Dispatch( const XEvent* pEvent )
+{
+ bool bContinueDispatch = true;
+
+ if( pEvent->type == PropertyNotify )
+ {
+ vcl_sal::WMAdaptor* pAdaptor = getDisplay()->getWMAdaptor();
+ Atom nDesktopAtom = pAdaptor->getAtom( vcl_sal::WMAdaptor::NET_WM_DESKTOP );
+ if( pEvent->xproperty.atom == nDesktopAtom &&
+ pEvent->xproperty.state == PropertyNewValue )
+ {
+ m_nWorkArea = pAdaptor->getWindowWorkArea( GDK_WINDOW_XWINDOW( m_pWindow->window) );
+ }
+ }
+ else if( pEvent->type == ConfigureNotify )
+ {
+ if( m_pForeignParent && pEvent->xconfigure.window == m_aForeignParentWindow )
+ {
+ bContinueDispatch = false;
+ gtk_window_resize( GTK_WINDOW(m_pWindow), pEvent->xconfigure.width, pEvent->xconfigure.height );
+ if( ( sal::static_int_cast< int >(maGeometry.nWidth) !=
+ pEvent->xconfigure.width ) ||
+ ( sal::static_int_cast< int >(maGeometry.nHeight) !=
+ pEvent->xconfigure.height ) )
+ {
+ maGeometry.nWidth = pEvent->xconfigure.width;
+ maGeometry.nHeight = pEvent->xconfigure.height;
+ setMinMaxSize();
+ getDisplay()->SendInternalEvent( this, NULL, SALEVENT_RESIZE );
+ }
+ }
+ else if( m_pForeignTopLevel && pEvent->xconfigure.window == m_aForeignTopLevelWindow )
+ {
+ bContinueDispatch = false;
+ // update position
+ int x = 0, y = 0;
+ XLIB_Window aChild;
+ XTranslateCoordinates( getDisplay()->GetDisplay(),
+ GDK_WINDOW_XWINDOW( m_pWindow->window),
+ getDisplay()->GetRootWindow( getDisplay()->GetDefaultScreenNumber() ),
+ 0, 0,
+ &x, &y,
+ &aChild );
+ if( x != maGeometry.nX || y != maGeometry.nY )
+ {
+ maGeometry.nX = x;
+ maGeometry.nY = y;
+ getDisplay()->SendInternalEvent( this, NULL, SALEVENT_MOVE );
+ }
+ }
+ }
+ else if( pEvent->type == ClientMessage &&
+ pEvent->xclient.message_type == getDisplay()->getWMAdaptor()->getAtom( vcl_sal::WMAdaptor::XEMBED ) &&
+ pEvent->xclient.window == GDK_WINDOW_XWINDOW(m_pWindow->window) &&
+ m_bWindowIsGtkPlug
+ )
+ {
+ // FIXME: this should not be necessary, GtkPlug should do this
+ // transparently for us
+ if( pEvent->xclient.data.l[1] == 1 || // XEMBED_WINDOW_ACTIVATE
+ pEvent->xclient.data.l[1] == 2 // XEMBED_WINDOW_DEACTIVATE
+ )
+ {
+ GdkEventFocus aEvent;
+ aEvent.type = GDK_FOCUS_CHANGE;
+ aEvent.window = m_pWindow->window;
+ aEvent.send_event = TRUE;
+ aEvent.in = (pEvent->xclient.data.l[1] == 1);
+ signalFocus( m_pWindow, &aEvent, this );
+ }
+ }
+
+ return bContinueDispatch;
+}
+
+void GtkSalFrame::SetBackgroundBitmap( SalBitmap* pBitmap )
+{
+ if( m_hBackgroundPixmap )
+ {
+ XSetWindowBackgroundPixmap( getDisplay()->GetDisplay(),
+ GDK_WINDOW_XWINDOW(m_pWindow->window),
+ None );
+ XFreePixmap( getDisplay()->GetDisplay(), m_hBackgroundPixmap );
+ m_hBackgroundPixmap = None;
+ }
+ if( pBitmap )
+ {
+ X11SalBitmap* pBM = static_cast<X11SalBitmap*>(pBitmap);
+ Size aSize = pBM->GetSize();
+ if( aSize.Width() && aSize.Height() )
+ {
+ m_hBackgroundPixmap =
+ XCreatePixmap( getDisplay()->GetDisplay(),
+ GDK_WINDOW_XWINDOW(m_pWindow->window),
+ aSize.Width(),
+ aSize.Height(),
+ getDisplay()->GetVisual(m_nScreen).GetDepth() );
+ if( m_hBackgroundPixmap )
+ {
+ SalTwoRect aTwoRect;
+ aTwoRect.mnSrcX = aTwoRect.mnSrcY = aTwoRect.mnDestX = aTwoRect.mnDestY = 0;
+ aTwoRect.mnSrcWidth = aTwoRect.mnDestWidth = aSize.Width();
+ aTwoRect.mnSrcHeight = aTwoRect.mnDestHeight = aSize.Height();
+ pBM->ImplDraw( m_hBackgroundPixmap,
+ m_nScreen,
+ getDisplay()->GetVisual(m_nScreen).GetDepth(),
+ aTwoRect,
+ getDisplay()->GetCopyGC(m_nScreen) );
+ XSetWindowBackgroundPixmap( getDisplay()->GetDisplay(),
+ GDK_WINDOW_XWINDOW(m_pWindow->window),
+ m_hBackgroundPixmap );
+ }
+ }
+ }
+}
+
+gboolean GtkSalFrame::signalButton( GtkWidget*, GdkEventButton* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = (GtkSalFrame*)frame;
+ SalMouseEvent aEvent;
+ USHORT nEventType = 0;
+ switch( pEvent->type )
+ {
+ case GDK_BUTTON_PRESS:
+ nEventType = SALEVENT_MOUSEBUTTONDOWN;
+ break;
+ case GDK_BUTTON_RELEASE:
+ nEventType = SALEVENT_MOUSEBUTTONUP;
+ break;
+ default:
+ return FALSE;
+ }
+ switch( pEvent->button )
+ {
+ case 1: aEvent.mnButton = MOUSE_LEFT; break;
+ case 2: aEvent.mnButton = MOUSE_MIDDLE; break;
+ case 3: aEvent.mnButton = MOUSE_RIGHT; break;
+ default: return FALSE;
+ }
+ aEvent.mnTime = pEvent->time;
+ aEvent.mnX = (long)pEvent->x_root - pThis->maGeometry.nX;
+ aEvent.mnY = (long)pEvent->y_root - pThis->maGeometry.nY;
+ aEvent.mnCode = GetMouseModCode( pEvent->state );
+
+ bool bClosePopups = false;
+ if( pEvent->type == GDK_BUTTON_PRESS &&
+ (pThis->m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) == 0
+ )
+ {
+ if( m_nFloats > 0 )
+ {
+ // close popups if user clicks outside our application
+ gint x, y;
+ bClosePopups = (gdk_display_get_window_at_pointer( pThis->getGdkDisplay(), &x, &y ) == NULL);
+ }
+ /* #i30306# release implicit pointer grab if no popups are open; else
+ * Drag cannot grab the pointer and will fail.
+ */
+ if( m_nFloats < 1 || bClosePopups )
+ gdk_display_pointer_ungrab( pThis->getGdkDisplay(), GDK_CURRENT_TIME );
+ }
+
+ GTK_YIELD_GRAB();
+
+ if( pThis->m_bWindowIsGtkPlug &&
+ pEvent->type == GDK_BUTTON_PRESS &&
+ pEvent->button == 1 )
+ {
+ pThis->askForXEmbedFocus( pEvent->time );
+ }
+
+ // --- RTL --- (mirror mouse pos)
+ if( Application::GetSettings().GetLayoutRTL() )
+ aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
+
+ vcl::DeletionListener aDel( pThis );
+
+ pThis->CallCallback( nEventType, &aEvent );
+
+ if( ! aDel.isDeleted() )
+ {
+ if( bClosePopups )
+ {
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( pSVData->maWinData.mpFirstFloat )
+ {
+ static const char* pEnv = getenv( "SAL_FLOATWIN_NOAPPFOCUSCLOSE" );
+ if ( !(pSVData->maWinData.mpFirstFloat->GetPopupModeFlags() & FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE) && !(pEnv && *pEnv) )
+ pSVData->maWinData.mpFirstFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL );
+ }
+ }
+
+ if( ! aDel.isDeleted() )
+ {
+ int frame_x = (int)(pEvent->x_root - pEvent->x);
+ int frame_y = (int)(pEvent->y_root - pEvent->y);
+ if( frame_x != pThis->maGeometry.nX || frame_y != pThis->maGeometry.nY )
+ {
+ pThis->maGeometry.nX = frame_x;
+ pThis->maGeometry.nY = frame_y;
+ pThis->CallCallback( SALEVENT_MOVE, NULL );
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+gboolean GtkSalFrame::signalScroll( GtkWidget*, GdkEvent* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = (GtkSalFrame*)frame;
+ GdkEventScroll* pSEvent = (GdkEventScroll*)pEvent;
+
+ static ULONG nLines = 0;
+ if( ! nLines )
+ {
+ char* pEnv = getenv( "SAL_WHEELLINES" );
+ nLines = pEnv ? atoi( pEnv ) : 3;
+ if( nLines > 10 )
+ nLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
+ }
+
+ bool bNeg = (pSEvent->direction == GDK_SCROLL_DOWN || pSEvent->direction == GDK_SCROLL_RIGHT );
+ SalWheelMouseEvent aEvent;
+ aEvent.mnTime = pSEvent->time;
+ aEvent.mnX = (ULONG)pSEvent->x;
+ aEvent.mnY = (ULONG)pSEvent->y;
+ aEvent.mnDelta = bNeg ? -120 : 120;
+ aEvent.mnNotchDelta = bNeg ? -1 : 1;
+ aEvent.mnScrollLines = nLines;
+ aEvent.mnCode = GetMouseModCode( pSEvent->state );
+ aEvent.mbHorz = (pSEvent->direction == GDK_SCROLL_LEFT || pSEvent->direction == GDK_SCROLL_RIGHT);
+
+ GTK_YIELD_GRAB();
+
+ // --- RTL --- (mirror mouse pos)
+ if( Application::GetSettings().GetLayoutRTL() )
+ aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
+
+ pThis->CallCallback( SALEVENT_WHEELMOUSE, &aEvent );
+
+ return FALSE;
+}
+
+gboolean GtkSalFrame::signalMotion( GtkWidget*, GdkEventMotion* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = (GtkSalFrame*)frame;
+
+ SalMouseEvent aEvent;
+ aEvent.mnTime = pEvent->time;
+ aEvent.mnX = (long)pEvent->x_root - pThis->maGeometry.nX;
+ aEvent.mnY = (long)pEvent->y_root - pThis->maGeometry.nY;
+ aEvent.mnCode = GetMouseModCode( pEvent->state );
+ aEvent.mnButton = 0;
+
+
+ GTK_YIELD_GRAB();
+
+ // --- RTL --- (mirror mouse pos)
+ if( Application::GetSettings().GetLayoutRTL() )
+ aEvent.mnX = pThis->maGeometry.nWidth-1-aEvent.mnX;
+
+ vcl::DeletionListener aDel( pThis );
+
+ pThis->CallCallback( SALEVENT_MOUSEMOVE, &aEvent );
+
+ if( ! aDel.isDeleted() )
+ {
+ int frame_x = (int)(pEvent->x_root - pEvent->x);
+ int frame_y = (int)(pEvent->y_root - pEvent->y);
+ if( frame_x != pThis->maGeometry.nX || frame_y != pThis->maGeometry.nY )
+ {
+ pThis->maGeometry.nX = frame_x;
+ pThis->maGeometry.nY = frame_y;
+ pThis->CallCallback( SALEVENT_MOVE, NULL );
+ }
+
+ if( ! aDel.isDeleted() )
+ {
+ // ask for the next hint
+ gint x, y;
+ GdkModifierType mask;
+ gdk_window_get_pointer( GTK_WIDGET(pThis->m_pWindow)->window, &x, &y, &mask );
+ }
+ }
+
+ return TRUE;
+}
+
+gboolean GtkSalFrame::signalCrossing( GtkWidget*, GdkEventCrossing* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = (GtkSalFrame*)frame;
+ SalMouseEvent aEvent;
+ aEvent.mnTime = pEvent->time;
+ aEvent.mnX = (long)pEvent->x_root - pThis->maGeometry.nX;
+ aEvent.mnY = (long)pEvent->y_root - pThis->maGeometry.nY;
+ aEvent.mnCode = GetMouseModCode( pEvent->state );
+ aEvent.mnButton = 0;
+
+ GTK_YIELD_GRAB();
+ pThis->CallCallback( (pEvent->type == GDK_ENTER_NOTIFY) ? SALEVENT_MOUSEMOVE : SALEVENT_MOUSELEAVE, &aEvent );
+
+ return TRUE;
+}
+
+
+gboolean GtkSalFrame::signalExpose( GtkWidget*, GdkEventExpose* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = (GtkSalFrame*)frame;
+
+ struct SalPaintEvent aEvent( pEvent->area.x, pEvent->area.y, pEvent->area.width, pEvent->area.height );
+
+ GTK_YIELD_GRAB();
+ pThis->CallCallback( SALEVENT_PAINT, &aEvent );
+
+ return FALSE;
+}
+
+gboolean GtkSalFrame::signalFocus( GtkWidget*, GdkEventFocus* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = (GtkSalFrame*)frame;
+
+ GTK_YIELD_GRAB();
+
+ // check if printers have changed (analogous to salframe focus handler)
+ vcl_sal::PrinterUpdate::update();
+
+ if( !pEvent->in )
+ {
+ pThis->m_nKeyModifiers = 0;
+ pThis->m_bSingleAltPress = false;
+ pThis->m_bSendModChangeOnRelease = false;
+ }
+
+ if( pThis->m_pIMHandler )
+ pThis->m_pIMHandler->focusChanged( pEvent->in );
+
+ // ask for changed printers like generic implementation
+ if( pEvent->in )
+ if( static_cast< X11SalInstance* >(GetSalData()->m_pInstance)->isPrinterInit() )
+ vcl_sal::PrinterUpdate::update();
+
+ // FIXME: find out who the hell steals the focus from our frame
+ // while we have the pointer grabbed, this should not come from
+ // the window manager. Is this an event that was still queued ?
+ // The focus does not seem to get set inside our process
+ //
+ // in the meantime do not propagate focus get/lose if floats are open
+ if( m_nFloats == 0 )
+ pThis->CallCallback( pEvent->in ? SALEVENT_GETFOCUS : SALEVENT_LOSEFOCUS, NULL );
+
+ return FALSE;
+}
+
+gboolean GtkSalFrame::signalMap( GtkWidget*, GdkEvent*, gpointer frame )
+{
+ GtkSalFrame* pThis = (GtkSalFrame*)frame;
+
+ GTK_YIELD_GRAB();
+
+ bool bSetFocus = pThis->m_bSetFocusOnMap;
+ pThis->m_bSetFocusOnMap = false;
+ if( ImplGetSVData()->mbIsTestTool )
+ {
+ /* #i76541# testtool needs the focus to be in a new document
+ * however e.g. metacity does not necessarily put the focus into
+ * a newly shown window. An extra little hint seems to help here.
+ * however we don't want to interfere with the normal user experience
+ * so this is done when running in testtool only
+ */
+ if( ! pThis->m_pParent && (pThis->m_nStyle & SAL_FRAME_STYLE_MOVEABLE) != 0 )
+ bSetFocus = true;
+ }
+
+ if( bSetFocus )
+ {
+ XSetInputFocus( pThis->getDisplay()->GetDisplay(),
+ GDK_WINDOW_XWINDOW( GTK_WIDGET(pThis->m_pWindow)->window),
+ RevertToParent, CurrentTime );
+ }
+
+ pThis->CallCallback( SALEVENT_RESIZE, NULL );
+
+ return FALSE;
+}
+
+gboolean GtkSalFrame::signalUnmap( GtkWidget*, GdkEvent*, gpointer frame )
+{
+ GtkSalFrame* pThis = (GtkSalFrame*)frame;
+
+ GTK_YIELD_GRAB();
+ pThis->CallCallback( SALEVENT_RESIZE, NULL );
+
+ return FALSE;
+}
+
+gboolean GtkSalFrame::signalConfigure( GtkWidget*, GdkEventConfigure* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = (GtkSalFrame*)frame;
+
+ bool bMoved = false, bSized = false;
+ int x = pEvent->x, y = pEvent->y;
+
+ /* HACK: during sizing/moving a toolbar pThis->maGeometry is actually
+ * already exact; even worse: due to the asynchronicity of configure
+ * events the borderwindow which would evaluate this event
+ * would size/move based on wrong data if we would actually evaluate
+ * this event. So let's swallow it; this is also a performance
+ * improvement as one can omit the synchronous XTranslateCoordinates
+ * call below.
+ */
+ if( (pThis->m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) &&
+ pThis->getDisplay()->GetCaptureFrame() == pThis )
+ return FALSE;
+
+
+ // in child case the coordinates are not root coordinates,
+ // need to transform
+
+ /* #i31785# sadly one cannot really trust the x,y members of the event;
+ * they are e.g. not set correctly on maximize/demaximize; this rather
+ * sounds like a bug in gtk we have to workaround.
+ */
+ XLIB_Window aChild;
+ XTranslateCoordinates( pThis->getDisplay()->GetDisplay(),
+ GDK_WINDOW_XWINDOW(GTK_WIDGET(pThis->m_pWindow)->window),
+ pThis->getDisplay()->GetRootWindow( pThis->getDisplay()->GetDefaultScreenNumber() ),
+ 0, 0,
+ &x, &y,
+ &aChild );
+
+ if( x != pThis->maGeometry.nX || y != pThis->maGeometry.nY )
+ {
+ bMoved = true;
+ pThis->maGeometry.nX = x;
+ pThis->maGeometry.nY = y;
+ }
+ /* #i86302#
+ * for non sizeable windows we set the min and max hint for the window manager to
+ * achieve correct sizing. However this is asynchronous and e.g. on Compiz
+ * it sometimes happens that the window gets resized to another size (some default)
+ * if we update the size here, subsequent setMinMaxSize will use this wrong size
+ * - which is not good since the window manager will now size the window back to this
+ * wrong size at some point.
+ */
+ if( (pThis->m_nStyle & (SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_PLUG)) == SAL_FRAME_STYLE_SIZEABLE )
+ {
+ if( pEvent->width != (int)pThis->maGeometry.nWidth || pEvent->height != (int)pThis->maGeometry.nHeight )
+ {
+ bSized = true;
+ pThis->maGeometry.nWidth = pEvent->width;
+ pThis->maGeometry.nHeight = pEvent->height;
+ }
+ }
+
+ // update decoration hints
+ if( ! (pThis->m_nStyle & SAL_FRAME_STYLE_PLUG) )
+ {
+ GdkRectangle aRect;
+ gdk_window_get_frame_extents( GTK_WIDGET(pThis->m_pWindow)->window, &aRect );
+ pThis->maGeometry.nTopDecoration = y - aRect.y;
+ pThis->maGeometry.nBottomDecoration = aRect.y + aRect.height - y - pEvent->height;
+ pThis->maGeometry.nLeftDecoration = x - aRect.x;
+ pThis->maGeometry.nRightDecoration = aRect.x + aRect.width - x - pEvent->width;
+ }
+ else
+ {
+ pThis->maGeometry.nTopDecoration =
+ pThis->maGeometry.nBottomDecoration =
+ pThis->maGeometry.nLeftDecoration =
+ pThis->maGeometry.nRightDecoration = 0;
+ }
+
+ GTK_YIELD_GRAB();
+ pThis->updateScreenNumber();
+ if( bMoved && bSized )
+ pThis->CallCallback( SALEVENT_MOVERESIZE, NULL );
+ else if( bMoved )
+ pThis->CallCallback( SALEVENT_MOVE, NULL );
+ else if( bSized )
+ pThis->CallCallback( SALEVENT_RESIZE, NULL );
+
+ return FALSE;
+}
+
+gboolean GtkSalFrame::signalKey( GtkWidget*, GdkEventKey* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = (GtkSalFrame*)frame;
+
+ vcl::DeletionListener aDel( pThis );
+
+ if( pThis->m_pIMHandler )
+ {
+ if( pThis->m_pIMHandler->handleKeyEvent( pEvent ) )
+ {
+ pThis->m_bSingleAltPress = false;
+ return TRUE;
+ }
+ }
+ GTK_YIELD_GRAB();
+
+ // handle modifiers
+ if( pEvent->keyval == GDK_Shift_L || pEvent->keyval == GDK_Shift_R ||
+ pEvent->keyval == GDK_Control_L || pEvent->keyval == GDK_Control_R ||
+ pEvent->keyval == GDK_Alt_L || pEvent->keyval == GDK_Alt_R ||
+ pEvent->keyval == GDK_Meta_L || pEvent->keyval == GDK_Meta_R ||
+ pEvent->keyval == GDK_Super_L || pEvent->keyval == GDK_Super_R )
+ {
+ SalKeyModEvent aModEvt;
+
+ USHORT nModCode = GetKeyModCode( pEvent->state );
+
+ aModEvt.mnModKeyCode = 0; // emit no MODKEYCHANGE events
+ if( pEvent->type == GDK_KEY_PRESS && !pThis->m_nKeyModifiers )
+ pThis->m_bSendModChangeOnRelease = true;
+
+ else if( pEvent->type == GDK_KEY_RELEASE &&
+ pThis->m_bSendModChangeOnRelease )
+ {
+ aModEvt.mnModKeyCode = pThis->m_nKeyModifiers;
+ pThis->m_nKeyModifiers = 0;
+ }
+
+ USHORT nExtModMask = 0;
+ USHORT nModMask = 0;
+ // pressing just the ctrl key leads to a keysym of XK_Control but
+ // the event state does not contain ControlMask. In the release
+ // event its the other way round: it does contain the Control mask.
+ // The modifier mode therefore has to be adapted manually.
+ switch( pEvent->keyval )
+ {
+ case GDK_Control_L:
+ nExtModMask = MODKEY_LMOD1;
+ nModMask = KEY_MOD1;
+ break;
+ case GDK_Control_R:
+ nExtModMask = MODKEY_RMOD1;
+ nModMask = KEY_MOD1;
+ break;
+ case GDK_Alt_L:
+ nExtModMask = MODKEY_LMOD2;
+ nModMask = KEY_MOD2;
+ break;
+ case GDK_Alt_R:
+ nExtModMask = MODKEY_RMOD2;
+ nModMask = KEY_MOD2;
+ break;
+ case GDK_Shift_L:
+ nExtModMask = MODKEY_LSHIFT;
+ nModMask = KEY_SHIFT;
+ break;
+ case GDK_Shift_R:
+ nExtModMask = MODKEY_RSHIFT;
+ nModMask = KEY_SHIFT;
+ break;
+ // Map Meta/Super to MOD3 modifier on all Unix systems
+ // except Mac OS X
+ case GDK_Meta_L:
+ case GDK_Super_L:
+ nExtModMask = MODKEY_LMOD3;
+ nModMask = KEY_MOD3;
+ break;
+ case GDK_Meta_R:
+ case GDK_Super_R:
+ nExtModMask = MODKEY_RMOD3;
+ nModMask = KEY_MOD3;
+ break;
+ }
+ if( pEvent->type == GDK_KEY_RELEASE )
+ {
+ nModCode &= ~nModMask;
+ pThis->m_nKeyModifiers &= ~nExtModMask;
+ }
+ else
+ {
+ nModCode |= nModMask;
+ pThis->m_nKeyModifiers |= nExtModMask;
+ }
+
+ aModEvt.mnCode = nModCode;
+ aModEvt.mnTime = pEvent->time;
+
+ pThis->CallCallback( SALEVENT_KEYMODCHANGE, &aModEvt );
+
+ if( ! aDel.isDeleted() )
+ {
+ // emulate KEY_MENU
+ if( ( pEvent->keyval == GDK_Alt_L || pEvent->keyval == GDK_Alt_R ) &&
+ ( nModCode & ~(KEY_MOD3|KEY_MOD2)) == 0 )
+ {
+ if( pEvent->type == GDK_KEY_PRESS )
+ pThis->m_bSingleAltPress = true;
+
+ else if( pThis->m_bSingleAltPress )
+ {
+ SalKeyEvent aKeyEvt;
+
+ aKeyEvt.mnCode = KEY_MENU | nModCode;
+ aKeyEvt.mnRepeat = 0;
+ aKeyEvt.mnTime = pEvent->time;
+ aKeyEvt.mnCharCode = 0;
+
+ // simulate KEY_MENU
+ pThis->CallCallback( SALEVENT_KEYINPUT, &aKeyEvt );
+ if( ! aDel.isDeleted() )
+ {
+ pThis->CallCallback( SALEVENT_KEYUP, &aKeyEvt );
+ pThis->m_bSingleAltPress = false;
+ }
+ }
+ }
+ else
+ pThis->m_bSingleAltPress = false;
+ }
+ }
+ else
+ {
+ pThis->doKeyCallback( pEvent->state,
+ pEvent->keyval,
+ pEvent->hardware_keycode,
+ pEvent->group,
+ pEvent->time,
+ sal_Unicode(gdk_keyval_to_unicode( pEvent->keyval )),
+ (pEvent->type == GDK_KEY_PRESS),
+ false );
+ if( ! aDel.isDeleted() )
+ {
+ pThis->m_bSendModChangeOnRelease = false;
+ pThis->m_bSingleAltPress = false;
+ }
+ }
+
+ if( !aDel.isDeleted() && pThis->m_pIMHandler )
+ pThis->m_pIMHandler->updateIMSpotLocation();
+
+ return TRUE;
+}
+
+gboolean GtkSalFrame::signalDelete( GtkWidget*, GdkEvent*, gpointer frame )
+{
+ GtkSalFrame* pThis = (GtkSalFrame*)frame;
+
+ GTK_YIELD_GRAB();
+ pThis->CallCallback( SALEVENT_CLOSE, NULL );
+
+ return TRUE;
+}
+
+void GtkSalFrame::signalStyleSet( GtkWidget*, GtkStyle* pPrevious, gpointer frame )
+{
+ GtkSalFrame* pThis = (GtkSalFrame*)frame;
+
+ // every frame gets an initial style set on creation
+ // do not post these as the whole application tends to
+ // redraw itself to adjust to the new style
+ // where there IS no new style resulting in tremendous unnecessary flickering
+ if( pPrevious != NULL )
+ {
+ // signalStyleSet does NOT usually have the gdk lock
+ // so post user event to safely dispatch the SALEVENT_SETTINGSCHANGED
+ // note: settings changed for multiple frames is avoided in winproc.cxx ImplHandleSettings
+ pThis->getDisplay()->SendInternalEvent( pThis, NULL, SALEVENT_SETTINGSCHANGED );
+ pThis->getDisplay()->SendInternalEvent( pThis, NULL, SALEVENT_FONTCHANGED );
+ }
+
+ /* #i64117# gtk sets a nice background pixmap
+ * but we actually don't really want that, so save
+ * some time on the Xserver as well as prevent
+ * some paint issues
+ */
+ GdkWindow* pWin = GTK_WIDGET(pThis->getWindow())->window;
+ if( pWin )
+ {
+ XLIB_Window aWin = GDK_WINDOW_XWINDOW(pWin);
+ if( aWin != None )
+ XSetWindowBackgroundPixmap( pThis->getDisplay()->GetDisplay(),
+ aWin,
+ pThis->m_hBackgroundPixmap );
+ }
+
+ if( ! pThis->m_pParent )
+ {
+ // signalize theme changed for NWF caches
+ // FIXME: should be called only once for a style change
+ GtkSalGraphics::bThemeChanged = TRUE;
+ }
+}
+
+gboolean GtkSalFrame::signalState( GtkWidget*, GdkEvent* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = (GtkSalFrame*)frame;
+ if( (pThis->m_nState & GDK_WINDOW_STATE_ICONIFIED) != (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_ICONIFIED ) )
+ pThis->getDisplay()->SendInternalEvent( pThis, NULL, SALEVENT_RESIZE );
+
+ if( (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_MAXIMIZED) &&
+ ! (pThis->m_nState & GDK_WINDOW_STATE_MAXIMIZED) )
+ {
+ pThis->m_aRestorePosSize =
+ Rectangle( Point( pThis->maGeometry.nX, pThis->maGeometry.nY ),
+ Size( pThis->maGeometry.nWidth, pThis->maGeometry.nHeight ) );
+ }
+ pThis->m_nState = pEvent->window_state.new_window_state;
+
+ #if OSL_DEBUG_LEVEL > 1
+ if( (pEvent->window_state.changed_mask & GDK_WINDOW_STATE_FULLSCREEN) )
+ {
+ fprintf( stderr, "window %p %s full screen state\n",
+ pThis,
+ (pEvent->window_state.new_window_state & GDK_WINDOW_STATE_FULLSCREEN) ? "enters" : "leaves");
+ }
+ #endif
+
+ return FALSE;
+}
+
+gboolean GtkSalFrame::signalVisibility( GtkWidget*, GdkEventVisibility* pEvent, gpointer frame )
+{
+ GtkSalFrame* pThis = (GtkSalFrame*)frame;
+ pThis->m_nVisibility = pEvent->state;
+
+ return FALSE;
+}
+
+void GtkSalFrame::signalDestroy( GtkObject* pObj, gpointer frame )
+{
+ GtkSalFrame* pThis = (GtkSalFrame*)frame;
+ if( GTK_WIDGET( pObj ) == pThis->m_pWindow )
+ {
+ pThis->m_pFixedContainer = NULL;
+ pThis->m_pWindow = NULL;
+ }
+}
+
+// ----------------------------------------------------------------------
+// GtkSalFrame::IMHandler
+// ----------------------------------------------------------------------
+
+GtkSalFrame::IMHandler::IMHandler( GtkSalFrame* pFrame )
+: m_pFrame(pFrame),
+ m_nPrevKeyPresses( 0 ),
+ m_pIMContext( NULL ),
+ m_bFocused( true ),
+ m_bPreeditJustChanged( false )
+{
+ m_aInputEvent.mpTextAttr = NULL;
+ createIMContext();
+}
+
+GtkSalFrame::IMHandler::~IMHandler()
+{
+ // cancel an eventual event posted to begin preedit again
+ m_pFrame->getDisplay()->CancelInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
+ deleteIMContext();
+}
+
+void GtkSalFrame::IMHandler::createIMContext()
+{
+ if( ! m_pIMContext )
+ {
+ m_pIMContext = gtk_im_multicontext_new ();
+ g_signal_connect( m_pIMContext, "commit",
+ G_CALLBACK (signalIMCommit), this );
+ g_signal_connect( m_pIMContext, "preedit_changed",
+ G_CALLBACK (signalIMPreeditChanged), this );
+ g_signal_connect( m_pIMContext, "retrieve_surrounding",
+ G_CALLBACK (signalIMRetrieveSurrounding), this );
+ g_signal_connect( m_pIMContext, "delete_surrounding",
+ G_CALLBACK (signalIMDeleteSurrounding), this );
+ g_signal_connect( m_pIMContext, "preedit_start",
+ G_CALLBACK (signalIMPreeditStart), this );
+ g_signal_connect( m_pIMContext, "preedit_end",
+ G_CALLBACK (signalIMPreeditEnd), this );
+
+ m_pFrame->getDisplay()->GetXLib()->PushXErrorLevel( true );
+ gtk_im_context_set_client_window( m_pIMContext, GTK_WIDGET(m_pFrame->m_pWindow)->window );
+ gtk_im_context_focus_in( m_pIMContext );
+ m_pFrame->getDisplay()->GetXLib()->PopXErrorLevel();
+ m_bFocused = true;
+ }
+}
+
+void GtkSalFrame::IMHandler::deleteIMContext()
+{
+ if( m_pIMContext )
+ {
+ // first give IC a chance to deinitialize
+ m_pFrame->getDisplay()->GetXLib()->PushXErrorLevel( true );
+ gtk_im_context_set_client_window( m_pIMContext, NULL );
+ m_pFrame->getDisplay()->GetXLib()->PopXErrorLevel();
+ // destroy old IC
+ g_object_unref( m_pIMContext );
+ m_pIMContext = NULL;
+ }
+}
+
+void GtkSalFrame::IMHandler::doCallEndExtTextInput()
+{
+ m_aInputEvent.mpTextAttr = NULL;
+ m_pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, NULL );
+}
+
+void GtkSalFrame::IMHandler::updateIMSpotLocation()
+{
+ SalExtTextInputPosEvent aPosEvent;
+ m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUTPOS, (void*)&aPosEvent );
+ GdkRectangle aArea;
+ aArea.x = aPosEvent.mnX;
+ aArea.y = aPosEvent.mnY;
+ aArea.width = aPosEvent.mnWidth;
+ aArea.height = aPosEvent.mnHeight;
+ gtk_im_context_set_cursor_location( m_pIMContext, &aArea );
+}
+
+void GtkSalFrame::IMHandler::setInputContext( SalInputContext* )
+{
+}
+
+void GtkSalFrame::IMHandler::sendEmptyCommit()
+{
+ vcl::DeletionListener aDel( m_pFrame );
+
+ SalExtTextInputEvent aEmptyEv;
+ aEmptyEv.mnTime = 0;
+ aEmptyEv.mpTextAttr = 0;
+ aEmptyEv.maText = String();
+ aEmptyEv.mnCursorPos = 0;
+ aEmptyEv.mnCursorFlags = 0;
+ aEmptyEv.mnDeltaStart = 0;
+ aEmptyEv.mbOnlyCursor = False;
+ m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&aEmptyEv );
+ if( ! aDel.isDeleted() )
+ m_pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, NULL );
+}
+
+void GtkSalFrame::IMHandler::endExtTextInput( USHORT /*nFlags*/ )
+{
+ gtk_im_context_reset ( m_pIMContext );
+
+ if( m_aInputEvent.mpTextAttr )
+ {
+ vcl::DeletionListener aDel( m_pFrame );
+ // delete preedit in sal (commit an empty string)
+ sendEmptyCommit();
+ if( ! aDel.isDeleted() )
+ {
+ // mark previous preedit state again (will e.g. be sent at focus gain)
+ m_aInputEvent.mpTextAttr = &m_aInputFlags[0];
+ if( m_bFocused )
+ {
+ // begin preedit again
+ m_pFrame->getDisplay()->SendInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
+ }
+ }
+ }
+}
+
+void GtkSalFrame::IMHandler::focusChanged( bool bFocusIn )
+{
+ m_bFocused = bFocusIn;
+ if( bFocusIn )
+ {
+ m_pFrame->getDisplay()->GetXLib()->PushXErrorLevel( true );
+ gtk_im_context_focus_in( m_pIMContext );
+ m_pFrame->getDisplay()->GetXLib()->PopXErrorLevel();
+ if( m_aInputEvent.mpTextAttr )
+ {
+ sendEmptyCommit();
+ // begin preedit again
+ m_pFrame->getDisplay()->SendInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
+ }
+ }
+ else
+ {
+ m_pFrame->getDisplay()->GetXLib()->PushXErrorLevel( true );
+ gtk_im_context_focus_out( m_pIMContext );
+ m_pFrame->getDisplay()->GetXLib()->PopXErrorLevel();
+ // cancel an eventual event posted to begin preedit again
+ m_pFrame->getDisplay()->CancelInternalEvent( m_pFrame, &m_aInputEvent, SALEVENT_EXTTEXTINPUT );
+ }
+}
+
+bool GtkSalFrame::IMHandler::handleKeyEvent( GdkEventKey* pEvent )
+{
+ vcl::DeletionListener aDel( m_pFrame );
+
+ if( pEvent->type == GDK_KEY_PRESS )
+ {
+ // Add this key press event to the list of previous key presses
+ // to which we compare key release events. If a later key release
+ // event has a matching key press event in this list, we swallow
+ // the key release because some GTK Input Methods don't swallow it
+ // for us.
+ m_aPrevKeyPresses.push_back( PreviousKeyPress(pEvent) );
+ m_nPrevKeyPresses++;
+
+ // Also pop off the earliest key press event if there are more than 10
+ // already.
+ while (m_nPrevKeyPresses > 10)
+ {
+ m_aPrevKeyPresses.pop_front();
+ m_nPrevKeyPresses--;
+ }
+
+ GObject* pRef = G_OBJECT( g_object_ref( G_OBJECT( m_pIMContext ) ) );
+
+ // #i51353# update spot location on every key input since we cannot
+ // know which key may activate a preedit choice window
+ updateIMSpotLocation();
+ if( aDel.isDeleted() )
+ return true;
+
+ gboolean bResult = gtk_im_context_filter_keypress( m_pIMContext, pEvent );
+ g_object_unref( pRef );
+
+ if( aDel.isDeleted() )
+ return true;
+
+ m_bPreeditJustChanged = false;
+
+ if( bResult )
+ return true;
+ else
+ {
+ DBG_ASSERT( m_nPrevKeyPresses > 0, "key press has vanished !" );
+ if( ! m_aPrevKeyPresses.empty() ) // sanity check
+ {
+ // event was not swallowed, do not filter a following
+ // key release event
+ // note: this relies on gtk_im_context_filter_keypress
+ // returning without calling a handler (in the "not swallowed"
+ // case ) which might change the previous key press list so
+ // we would pop the wrong event here
+ m_aPrevKeyPresses.pop_back();
+ m_nPrevKeyPresses--;
+ }
+ }
+ }
+
+ // Determine if we got an earlier key press event corresponding to this key release
+ if (pEvent->type == GDK_KEY_RELEASE)
+ {
+ GObject* pRef = G_OBJECT( g_object_ref( G_OBJECT( m_pIMContext ) ) );
+ gboolean bResult = gtk_im_context_filter_keypress( m_pIMContext, pEvent );
+ g_object_unref( pRef );
+
+ if( aDel.isDeleted() )
+ return true;
+
+ m_bPreeditJustChanged = false;
+
+ std::list<PreviousKeyPress>::iterator iter = m_aPrevKeyPresses.begin();
+ std::list<PreviousKeyPress>::iterator iter_end = m_aPrevKeyPresses.end();
+ while (iter != iter_end)
+ {
+ // If we found a corresponding previous key press event, swallow the release
+ // and remove the earlier key press from our list
+ if (*iter == pEvent)
+ {
+ m_aPrevKeyPresses.erase(iter);
+ m_nPrevKeyPresses--;
+ return true;
+ }
+ ++iter;
+ }
+
+ if( bResult )
+ return true;
+ }
+
+ return false;
+}
+
+/* FIXME:
+* #122282# still more hacking: some IMEs never start a preedit but simply commit
+* in this case we cannot commit a single character. Workaround: do not do the
+* single key hack for enter or space if the unicode commited does not match
+*/
+
+static bool checkSingleKeyCommitHack( guint keyval, sal_Unicode cCode )
+{
+ bool bRet = true;
+ switch( keyval )
+ {
+ case GDK_KP_Enter:
+ case GDK_Return:
+ if( cCode != '\n' && cCode != '\r' )
+ bRet = false;
+ break;
+ case GDK_space:
+ case GDK_KP_Space:
+ if( cCode != ' ' )
+ bRet = false;
+ break;
+ default:
+ break;
+ }
+ return bRet;
+}
+
+#ifdef SOLARIS
+#define CONTEXT_ARG pContext
+#else
+#define CONTEXT_ARG EMPTYARG
+#endif
+void GtkSalFrame::IMHandler::signalIMCommit( GtkIMContext* CONTEXT_ARG, gchar* pText, gpointer im_handler )
+{
+ GtkSalFrame::IMHandler* pThis = (GtkSalFrame::IMHandler*)im_handler;
+
+ vcl::DeletionListener aDel( pThis->m_pFrame );
+ // open a block that will end the GTK_YIELD_GRAB before calling preedit changed again
+ {
+ GTK_YIELD_GRAB();
+
+ pThis->m_aInputEvent.mnTime = 0;
+ pThis->m_aInputEvent.mpTextAttr = 0;
+ pThis->m_aInputEvent.maText = String( pText, RTL_TEXTENCODING_UTF8 );
+ pThis->m_aInputEvent.mnCursorPos = pThis->m_aInputEvent.maText.Len();
+ pThis->m_aInputEvent.mnCursorFlags = 0;
+ pThis->m_aInputEvent.mnDeltaStart = 0;
+ pThis->m_aInputEvent.mbOnlyCursor = False;
+
+ pThis->m_aInputFlags.clear();
+
+ /* necessary HACK: all keyboard input comes in here as soon as a IMContext is set
+ * which is logical and consequent. But since even simple input like
+ * <space> comes through the commit signal instead of signalKey
+ * and all kinds of windows only implement KeyInput (e.g. PushButtons,
+ * RadioButtons and a lot of other Controls), will send a single
+ * KeyInput/KeyUp sequence instead of an ExtText event if there
+ * never was a preedit and the text is only one character.
+ *
+ * In this case there the last ExtText event must have been
+ * SALEVENT_ENDEXTTEXTINPUT, either because of a regular commit
+ * or because there never was a preedit.
+ */
+ bool bSingleCommit = false;
+ bool bWasPreedit =
+ (pThis->m_aInputEvent.mpTextAttr != 0) ||
+ pThis->m_bPreeditJustChanged;
+ if( ! bWasPreedit
+ && pThis->m_aInputEvent.maText.Len() == 1
+ && ! pThis->m_aPrevKeyPresses.empty()
+ )
+ {
+ const PreviousKeyPress& rKP = pThis->m_aPrevKeyPresses.back();
+ sal_Unicode aOrigCode = pThis->m_aInputEvent.maText.GetChar(0);
+
+ if( checkSingleKeyCommitHack( rKP.keyval, aOrigCode ) )
+ {
+ pThis->m_pFrame->doKeyCallback( rKP.state, rKP.keyval, rKP.hardware_keycode, rKP.group, rKP.time, aOrigCode, true, true );
+ bSingleCommit = true;
+ }
+ }
+ if( ! bSingleCommit )
+ {
+ pThis->m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&pThis->m_aInputEvent);
+ if( ! aDel.isDeleted() )
+ pThis->doCallEndExtTextInput();
+ }
+ if( ! aDel.isDeleted() )
+ {
+ // reset input event
+ pThis->m_aInputEvent.maText = String();
+ pThis->m_aInputEvent.mnCursorPos = 0;
+ pThis->updateIMSpotLocation();
+ }
+ }
+ #ifdef SOLARIS
+ // #i51356# workaround a solaris IIIMP bug
+ // in case of partial commits the preedit changed signal
+ // and commit signal come in wrong order
+ if( ! aDel.isDeleted() )
+ signalIMPreeditChanged( pContext, im_handler );
+ #endif
+}
+
+void GtkSalFrame::IMHandler::signalIMPreeditChanged( GtkIMContext*, gpointer im_handler )
+{
+ GtkSalFrame::IMHandler* pThis = (GtkSalFrame::IMHandler*)im_handler;
+
+ char* pText = NULL;
+ PangoAttrList* pAttrs = NULL;
+ gint nCursorPos = 0;
+
+ gtk_im_context_get_preedit_string( pThis->m_pIMContext,
+ &pText,
+ &pAttrs,
+ &nCursorPos );
+ if( pText && ! *pText ) // empty string
+ {
+ // change from nothing to nothing -> do not start preedit
+ // e.g. this will activate input into a calc cell without
+ // user input
+ if( pThis->m_aInputEvent.maText.Len() == 0 )
+ {
+ g_free( pText );
+ return;
+ }
+ }
+
+ pThis->m_bPreeditJustChanged = true;
+
+ bool bEndPreedit = (!pText || !*pText) && pThis->m_aInputEvent.mpTextAttr != NULL;
+ pThis->m_aInputEvent.mnTime = 0;
+ pThis->m_aInputEvent.maText = String( pText, RTL_TEXTENCODING_UTF8 );
+ pThis->m_aInputEvent.mnCursorPos = nCursorPos;
+ pThis->m_aInputEvent.mnCursorFlags = 0;
+ pThis->m_aInputEvent.mnDeltaStart = 0;
+ pThis->m_aInputEvent.mbOnlyCursor = False;
+
+ pThis->m_aInputFlags = std::vector<USHORT>( std::max( 1, (int)pThis->m_aInputEvent.maText.Len() ), 0 );
+
+ PangoAttrIterator *iter = pango_attr_list_get_iterator (pAttrs);
+ do
+ {
+ GSList *attr_list = NULL;
+ GSList *tmp_list = NULL;
+ gint start, end;
+ guint sal_attr = 0;
+
+ pango_attr_iterator_range (iter, &start, &end);
+ if (end == G_MAXINT)
+ end = pText ? strlen (pText) : 0;
+ if (end == start)
+ continue;
+
+ start = g_utf8_pointer_to_offset (pText, pText + start);
+ end = g_utf8_pointer_to_offset (pText, pText + end);
+
+ tmp_list = attr_list = pango_attr_iterator_get_attrs (iter);
+ while (tmp_list)
+ {
+ PangoAttribute *pango_attr = (PangoAttribute *)(tmp_list->data);
+
+ switch (pango_attr->klass->type)
+ {
+ case PANGO_ATTR_BACKGROUND:
+ sal_attr |= (SAL_EXTTEXTINPUT_ATTR_HIGHLIGHT | SAL_EXTTEXTINPUT_CURSOR_INVISIBLE);
+ break;
+ case PANGO_ATTR_UNDERLINE:
+ sal_attr |= SAL_EXTTEXTINPUT_ATTR_UNDERLINE;
+ break;
+ case PANGO_ATTR_STRIKETHROUGH:
+ sal_attr |= SAL_EXTTEXTINPUT_ATTR_REDTEXT;
+ break;
+ default:
+ break;
+ }
+ pango_attribute_destroy (pango_attr);
+ tmp_list = tmp_list->next;
+ }
+ if (sal_attr == 0)
+ sal_attr |= SAL_EXTTEXTINPUT_ATTR_UNDERLINE;
+ g_slist_free (attr_list);
+
+ // Set the sal attributes on our text
+ for (int i = start; i < end; i++)
+ pThis->m_aInputFlags[i] |= sal_attr;
+ } while (pango_attr_iterator_next (iter));
+
+ pThis->m_aInputEvent.mpTextAttr = &pThis->m_aInputFlags[0];
+
+ g_free( pText );
+ pango_attr_list_unref( pAttrs );
+
+ GTK_YIELD_GRAB();
+
+ vcl::DeletionListener aDel( pThis->m_pFrame );
+
+ pThis->m_pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&pThis->m_aInputEvent);
+ if( bEndPreedit && ! aDel.isDeleted() )
+ pThis->doCallEndExtTextInput();
+ if( ! aDel.isDeleted() )
+ pThis->updateIMSpotLocation();
+}
+
+void GtkSalFrame::IMHandler::signalIMPreeditStart( GtkIMContext*, gpointer /*im_handler*/ )
+{
+}
+
+void GtkSalFrame::IMHandler::signalIMPreeditEnd( GtkIMContext*, gpointer im_handler )
+{
+ GtkSalFrame::IMHandler* pThis = (GtkSalFrame::IMHandler*)im_handler;
+ GTK_YIELD_GRAB();
+
+ pThis->m_bPreeditJustChanged = true;
+
+ vcl::DeletionListener aDel( pThis->m_pFrame );
+ pThis->doCallEndExtTextInput();
+ if( ! aDel.isDeleted() )
+ pThis->updateIMSpotLocation();
+}
+
+uno::Reference<accessibility::XAccessibleEditableText>
+ FindFocus(uno::Reference< accessibility::XAccessibleContext > xContext)
+{
+ if (!xContext.is())
+ uno::Reference< accessibility::XAccessibleEditableText >();
+
+ uno::Reference<accessibility::XAccessibleStateSet> xState = xContext->getAccessibleStateSet();
+ if (xState.is())
+ {
+ if (xState->contains(accessibility::AccessibleStateType::FOCUSED))
+ return uno::Reference<accessibility::XAccessibleEditableText>(xContext, uno::UNO_QUERY);
+ }
+
+ for (sal_Int32 i = 0; i < xContext->getAccessibleChildCount(); ++i)
+ {
+ uno::Reference< accessibility::XAccessible > xChild = xContext->getAccessibleChild(i);
+ if (!xChild.is())
+ continue;
+ uno::Reference< accessibility::XAccessibleContext > xChildContext = xChild->getAccessibleContext();
+ if (!xChildContext.is())
+ continue;
+ uno::Reference< accessibility::XAccessibleEditableText > xText = FindFocus(xChildContext);
+ if (xText.is())
+ return xText;
+ }
+ return uno::Reference< accessibility::XAccessibleEditableText >();
+}
+
+uno::Reference<accessibility::XAccessibleEditableText> lcl_GetxText()
+{
+ uno::Reference<accessibility::XAccessibleEditableText> xText;
+ Window* pFocusWin = ImplGetSVData()->maWinData.mpFocusWin;
+ if (!pFocusWin)
+ return xText;
+
+ uno::Reference< accessibility::XAccessible > xAccessible( pFocusWin->GetAccessible( true ) );
+ if (xAccessible.is())
+ xText = FindFocus(xAccessible->getAccessibleContext());
+ return xText;
+}
+
+gboolean GtkSalFrame::IMHandler::signalIMRetrieveSurrounding( GtkIMContext* pContext, gpointer /*im_handler*/ )
+{
+ uno::Reference<accessibility::XAccessibleEditableText> xText = lcl_GetxText();
+
+ if (xText.is())
+ {
+ sal_uInt32 nPosition = xText->getCaretPosition();
+ rtl::OUString sAllText = xText->getText();
+ if (!sAllText.getLength())
+ return FALSE;
+ rtl::OString sUTF = rtl::OUStringToOString(sAllText, RTL_TEXTENCODING_UTF8);
+ rtl::OUString sCursorText(sAllText, nPosition);
+ gtk_im_context_set_surrounding(pContext, sUTF.getStr(), sUTF.getLength(),
+ rtl::OUStringToOString(sCursorText, RTL_TEXTENCODING_UTF8).getLength());
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+gboolean GtkSalFrame::IMHandler::signalIMDeleteSurrounding( GtkIMContext*, gint offset, gint nchars,
+ gpointer /*im_handler*/ )
+{
+ uno::Reference<accessibility::XAccessibleEditableText> xText = lcl_GetxText();
+
+ if (xText.is())
+ {
+ sal_uInt32 nPosition = xText->getCaretPosition();
+ // --> OD 2010-06-04 #i111768# - apply patch from kstribley:
+ // range checking
+// xText->deleteText(nPosition + offset, nPosition + offset + nchars);
+ sal_Int32 nDeletePos = nPosition + offset;
+ sal_Int32 nDeleteEnd = nDeletePos + nchars;
+ if (nDeletePos < 0)
+ nDeletePos = 0;
+ if (nDeleteEnd < 0)
+ nDeleteEnd = 0;
+ if (nDeleteEnd > xText->getCharacterCount())
+ nDeleteEnd = xText->getCharacterCount();
+
+ xText->deleteText(nDeletePos, nDeleteEnd);
+ // <--
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/vcl/unx/gtk/window/gtkobject.cxx b/vcl/unx/gtk/window/gtkobject.cxx
new file mode 100644
index 000000000000..2a2bbe78078a
--- /dev/null
+++ b/vcl/unx/gtk/window/gtkobject.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 <plugins/gtk/gtkobject.hxx>
+#include <plugins/gtk/gtkframe.hxx>
+#include <plugins/gtk/gtkdata.hxx>
+#include <plugins/gtk/gtkinst.hxx>
+
+GtkSalObject::GtkSalObject( GtkSalFrame* pParent, BOOL bShow )
+ : m_pSocket( NULL ),
+ m_pRegion( NULL )
+{
+ if( pParent )
+ {
+ // our plug window
+ m_pSocket = gtk_drawing_area_new();
+ Show( bShow );
+ // insert into container
+ gtk_fixed_put( pParent->getFixedContainer(),
+ m_pSocket,
+ 0, 0 );
+ // realize so we can get a window id
+ gtk_widget_realize( m_pSocket );
+
+
+ // make it transparent; some plugins may not insert
+ // their own window here but use the socket window itself
+ gtk_widget_set_app_paintable( m_pSocket, TRUE );
+
+ //system data
+ SalDisplay* pDisp = GetX11SalData()->GetDisplay();
+ m_aSystemData.nSize = sizeof( SystemChildData );
+ m_aSystemData.pDisplay = pDisp->GetDisplay();
+ m_aSystemData.aWindow = GDK_WINDOW_XWINDOW(m_pSocket->window);
+ m_aSystemData.pSalFrame = NULL;
+ m_aSystemData.pWidget = m_pSocket;
+ m_aSystemData.pVisual = pDisp->GetVisual(pParent->getScreenNumber()).GetVisual();
+ m_aSystemData.nScreen = pParent->getScreenNumber();
+ m_aSystemData.nDepth = pDisp->GetVisual(pParent->getScreenNumber()).GetDepth();
+ m_aSystemData.aColormap = pDisp->GetColormap(pParent->getScreenNumber()).GetXColormap();
+ m_aSystemData.pAppContext = NULL;
+ m_aSystemData.aShellWindow = GDK_WINDOW_XWINDOW(GTK_WIDGET(pParent->getWindow())->window);
+ m_aSystemData.pShellWidget = GTK_WIDGET(pParent->getWindow());
+
+ g_signal_connect( G_OBJECT(m_pSocket), "button-press-event", G_CALLBACK(signalButton), this );
+ g_signal_connect( G_OBJECT(m_pSocket), "button-release-event", G_CALLBACK(signalButton), this );
+ g_signal_connect( G_OBJECT(m_pSocket), "focus-in-event", G_CALLBACK(signalFocus), this );
+ g_signal_connect( G_OBJECT(m_pSocket), "focus-out-event", G_CALLBACK(signalFocus), this );
+ g_signal_connect( G_OBJECT(m_pSocket), "destroy", G_CALLBACK(signalDestroy), this );
+
+ // #i59255# necessary due to sync effects with java child windows
+ pParent->Sync();
+ }
+}
+
+GtkSalObject::~GtkSalObject()
+{
+ if( m_pRegion )
+ gdk_region_destroy( m_pRegion );
+ if( m_pSocket )
+ {
+ // remove socket from parent frame's fixed container
+ gtk_container_remove( GTK_CONTAINER(gtk_widget_get_parent(m_pSocket)),
+ m_pSocket );
+ // get rid of the socket
+ // actually the gtk_container_remove should let the ref count
+ // of the socket sink to 0 and destroy it (see signalDestroy)
+ // this is just a sanity check
+ if( m_pSocket )
+ gtk_widget_destroy( m_pSocket );
+ }
+}
+
+void GtkSalObject::ResetClipRegion()
+{
+ if( m_pSocket )
+ gdk_window_shape_combine_region( m_pSocket->window, NULL, 0, 0 );
+}
+
+USHORT GtkSalObject::GetClipRegionType()
+{
+ return SAL_OBJECT_CLIP_INCLUDERECTS;
+}
+
+void GtkSalObject::BeginSetClipRegion( ULONG )
+{
+ if( m_pRegion )
+ gdk_region_destroy( m_pRegion );
+ m_pRegion = gdk_region_new();
+}
+
+void GtkSalObject::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
+{
+ GdkRectangle aRect;
+ aRect.x = nX;
+ aRect.y = nY;
+ aRect.width = nWidth;
+ aRect.height = nHeight;
+
+ gdk_region_union_with_rect( m_pRegion, &aRect );
+}
+
+void GtkSalObject::EndSetClipRegion()
+{
+ if( m_pSocket )
+ gdk_window_shape_combine_region( m_pSocket->window, m_pRegion, 0, 0 );
+}
+
+void GtkSalObject::SetPosSize( long nX, long nY, long nWidth, long nHeight )
+{
+ if( m_pSocket )
+ {
+ GtkFixed* pContainer = GTK_FIXED(gtk_widget_get_parent(m_pSocket));
+ gtk_fixed_move( pContainer, m_pSocket, nX, nY );
+ gtk_widget_set_size_request( m_pSocket, nWidth, nHeight );
+ gtk_container_resize_children( GTK_CONTAINER(pContainer) );
+ }
+}
+
+void GtkSalObject::Show( BOOL bVisible )
+{
+ if( m_pSocket )
+ {
+ if( bVisible )
+ gtk_widget_show( m_pSocket );
+ else
+ gtk_widget_hide( m_pSocket );
+ }
+}
+
+void GtkSalObject::Enable( BOOL )
+{
+}
+
+void GtkSalObject::GrabFocus()
+{
+}
+
+void GtkSalObject::SetBackground()
+{
+}
+
+void GtkSalObject::SetBackground( SalColor )
+{
+}
+
+const SystemEnvData* GtkSalObject::GetSystemData() const
+{
+ return &m_aSystemData;
+}
+
+
+gboolean GtkSalObject::signalButton( GtkWidget*, GdkEventButton* pEvent, gpointer object )
+{
+ GtkSalObject* pThis = (GtkSalObject*)object;
+
+ if( pEvent->type == GDK_BUTTON_PRESS )
+ {
+ GTK_YIELD_GRAB();
+ pThis->CallCallback( SALOBJ_EVENT_TOTOP, NULL );
+ }
+
+ return FALSE;
+}
+
+gboolean GtkSalObject::signalFocus( GtkWidget*, GdkEventFocus* pEvent, gpointer object )
+{
+ GtkSalObject* pThis = (GtkSalObject*)object;
+
+ GTK_YIELD_GRAB();
+
+ pThis->CallCallback( pEvent->in ? SALOBJ_EVENT_GETFOCUS : SALOBJ_EVENT_LOSEFOCUS, NULL );
+
+ return FALSE;
+}
+
+void GtkSalObject::signalDestroy( GtkObject* pObj, gpointer object )
+{
+ GtkSalObject* pThis = (GtkSalObject*)object;
+ if( GTK_WIDGET(pObj) == pThis->m_pSocket )
+ {
+ pThis->m_pSocket = NULL;
+ }
+}
diff --git a/vcl/unx/gtk/window/makefile.mk b/vcl/unx/gtk/window/makefile.mk
new file mode 100644
index 000000000000..ac23e9363eef
--- /dev/null
+++ b/vcl/unx/gtk/window/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=gtkwin
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# workaround for makedepend hang
+MKDEPENDSOLVER=
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)"!="unx"
+
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+
+.ELSE # "$(GUIBASE)"!="unx"
+
+.IF "$(ENABLE_GTK)" != ""
+
+PKGCONFIG_MODULES=gtk+-2.0
+.IF "$(ENABLE_DBUS)" != ""
+CDEFS+=-DENABLE_DBUS
+PKGCONFIG_MODULES+= dbus-glib-1
+.ENDIF
+.INCLUDE : pkg_config.mk
+
+.IF "$(COM)" == "C52"
+NOOPTFILES=$(SLO)$/gtkframe.obj
+.ENDIF
+
+SLOFILES=\
+ $(SLO)$/gtkframe.obj \
+ $(SLO)$/gtkobject.obj
+EXCEPTIONSFILES=$(SLO)$/gtkframe.obj
+.ELSE # "$(ENABLE_GTK)" != ""
+
+dummy:
+ @echo GTK disabled - nothing to build
+.ENDIF
+.ENDIF # "$(GUIBASE)"!="unx"
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
+.INCLUDE : $(PRJ)$/util$/target.pmk
diff --git a/vcl/unx/headless/makefile.mk b/vcl/unx/headless/makefile.mk
new file mode 100644
index 000000000000..a32f02838080
--- /dev/null
+++ b/vcl/unx/headless/makefile.mk
@@ -0,0 +1,66 @@
+#*************************************************************************
+#
+# 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=svpplug
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+
+.IF "$(listening)"!="" || "$(LISTENING)"!=""
+CDEFS+= -DWITH_SVP_LISTENING
+.ENDIF
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)" == "unx"
+
+SLOFILES=\
+ $(SLO)$/svpinst.obj\
+ $(SLO)$/svpdummies.obj\
+ $(SLO)$/svpframe.obj\
+ $(SLO)$/svpgdi.obj\
+ $(SLO)$/svptext.obj\
+ $(SLO)$/svpprn.obj\
+ $(SLO)$/svppspgraphics.obj\
+ $(SLO)$/svpvd.obj\
+ $(SLO)$/svpbmp.obj\
+ $(SLO)$/svpelement.obj
+
+.ENDIF
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
+
diff --git a/vcl/unx/headless/svpbmp.cxx b/vcl/unx/headless/svpbmp.cxx
new file mode 100644
index 000000000000..7c84c4a7a579
--- /dev/null
+++ b/vcl/unx/headless/svpbmp.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.
+ *
+ ************************************************************************/
+
+#include "svpbmp.hxx"
+
+#include <basegfx/vector/b2ivector.hxx>
+#include <basegfx/range/b2irange.hxx>
+#include <basebmp/scanlineformats.hxx>
+#include <basebmp/color.hxx>
+
+#include <vcl/salbtype.hxx>
+#include <vcl/bitmap.hxx>
+
+using namespace basebmp;
+using namespace basegfx;
+
+SvpSalBitmap::~SvpSalBitmap()
+{
+}
+
+bool SvpSalBitmap::Create( const Size& rSize,
+ USHORT nBitCount,
+ const BitmapPalette& rPalette )
+{
+ sal_uInt32 nFormat = SVP_DEFAULT_BITMAP_FORMAT;
+ switch( nBitCount )
+ {
+ case 1: nFormat = Format::ONE_BIT_MSB_PAL; break;
+ case 4: nFormat = Format::FOUR_BIT_MSB_PAL; break;
+ case 8: nFormat = Format::EIGHT_BIT_PAL; break;
+#ifdef OSL_BIGENDIAN
+ case 16: nFormat = Format::SIXTEEN_BIT_MSB_TC_MASK; break;
+#else
+ case 16: nFormat = Format::SIXTEEN_BIT_LSB_TC_MASK; break;
+#endif
+ case 24: nFormat = Format::TWENTYFOUR_BIT_TC_MASK; break;
+ case 32: nFormat = Format::THIRTYTWO_BIT_TC_MASK; break;
+ }
+ B2IVector aSize( rSize.Width(), rSize.Height() );
+ if( aSize.getX() == 0 )
+ aSize.setX( 1 );
+ if( aSize.getY() == 0 )
+ aSize.setY( 1 );
+ if( nBitCount > 8 )
+ m_aBitmap = createBitmapDevice( aSize, false, nFormat );
+ else
+ {
+ // prepare palette
+ unsigned int nEntries = 1U << nBitCount;
+ std::vector<basebmp::Color>* pPalette =
+ new std::vector<basebmp::Color>( nEntries, basebmp::Color(COL_WHITE) );
+ unsigned int nColors = rPalette.GetEntryCount();
+ for( unsigned int i = 0; i < nColors; i++ )
+ {
+ const BitmapColor& rCol = rPalette[i];
+ (*pPalette)[i] = basebmp::Color( rCol.GetRed(), rCol.GetGreen(), rCol.GetBlue() );
+ }
+ m_aBitmap = createBitmapDevice( aSize, false, nFormat,
+ basebmp::RawMemorySharedArray(),
+ basebmp::PaletteMemorySharedVector( pPalette )
+ );
+ }
+ return true;
+}
+
+bool SvpSalBitmap::Create( const SalBitmap& rSalBmp )
+{
+ const SvpSalBitmap& rSrc = static_cast<const SvpSalBitmap&>(rSalBmp);
+ const BitmapDeviceSharedPtr& rSrcBmp = rSrc.getBitmap();
+ if( rSrcBmp.get() )
+ {
+ B2IVector aSize = rSrcBmp->getSize();
+ m_aBitmap = cloneBitmapDevice( aSize, rSrcBmp );
+ B2IRange aRect( 0, 0, aSize.getX(), aSize.getY() );
+ m_aBitmap->drawBitmap( rSrcBmp, aRect, aRect, DrawMode_PAINT );
+ }
+ else
+ m_aBitmap.reset();
+
+ return true;
+}
+
+bool SvpSalBitmap::Create( const SalBitmap& /*rSalBmp*/,
+ SalGraphics* /*pGraphics*/ )
+{
+ return false;
+}
+
+bool SvpSalBitmap::Create( const SalBitmap& /*rSalBmp*/,
+ USHORT /*nNewBitCount*/ )
+{
+ return false;
+}
+
+void SvpSalBitmap::Destroy()
+{
+ m_aBitmap.reset();
+}
+
+Size SvpSalBitmap::GetSize() const
+{
+ Size aSize;
+ if( m_aBitmap.get() )
+ {
+ B2IVector aVec( m_aBitmap->getSize() );
+ aSize = Size( aVec.getX(), aVec.getY() );
+ }
+
+ return aSize;
+}
+
+USHORT SvpSalBitmap::GetBitCount() const
+{
+ USHORT nDepth = 0;
+ if( m_aBitmap.get() )
+ nDepth = getBitCountFromScanlineFormat( m_aBitmap->getScanlineFormat() );
+ return nDepth;
+}
+
+BitmapBuffer* SvpSalBitmap::AcquireBuffer( bool )
+{
+ BitmapBuffer* pBuf = NULL;
+ if( m_aBitmap.get() )
+ {
+ pBuf = new BitmapBuffer();
+ USHORT nBitCount = 1;
+ switch( m_aBitmap->getScanlineFormat() )
+ {
+ case Format::ONE_BIT_MSB_GREY:
+ case Format::ONE_BIT_MSB_PAL:
+ nBitCount = 1;
+ pBuf->mnFormat = BMP_FORMAT_1BIT_MSB_PAL;
+ break;
+ case Format::ONE_BIT_LSB_GREY:
+ case Format::ONE_BIT_LSB_PAL:
+ nBitCount = 1;
+ pBuf->mnFormat = BMP_FORMAT_1BIT_LSB_PAL;
+ break;
+ case Format::FOUR_BIT_MSB_GREY:
+ case Format::FOUR_BIT_MSB_PAL:
+ nBitCount = 4;
+ pBuf->mnFormat = BMP_FORMAT_4BIT_MSN_PAL;
+ break;
+ case Format::FOUR_BIT_LSB_GREY:
+ case Format::FOUR_BIT_LSB_PAL:
+ nBitCount = 4;
+ pBuf->mnFormat = BMP_FORMAT_4BIT_LSN_PAL;
+ break;
+ case Format::EIGHT_BIT_PAL:
+ nBitCount = 8;
+ pBuf->mnFormat = BMP_FORMAT_8BIT_PAL;
+ break;
+ case Format::EIGHT_BIT_GREY:
+ nBitCount = 8;
+ pBuf->mnFormat = BMP_FORMAT_8BIT_PAL;
+ break;
+ case Format::SIXTEEN_BIT_LSB_TC_MASK:
+ nBitCount = 16;
+ pBuf->mnFormat = BMP_FORMAT_16BIT_TC_LSB_MASK;
+ pBuf->maColorMask = ColorMask( 0xf800, 0x07e0, 0x001f );
+ break;
+ case Format::SIXTEEN_BIT_MSB_TC_MASK:
+ nBitCount = 16;
+ pBuf->mnFormat = BMP_FORMAT_16BIT_TC_MSB_MASK;
+ pBuf->maColorMask = ColorMask( 0xf800, 0x07e0, 0x001f );
+ break;
+ case Format::TWENTYFOUR_BIT_TC_MASK:
+ nBitCount = 24;
+ pBuf->mnFormat = BMP_FORMAT_24BIT_TC_BGR;
+ break;
+ case Format::THIRTYTWO_BIT_TC_MASK:
+ nBitCount = 32;
+ pBuf->mnFormat = BMP_FORMAT_32BIT_TC_MASK;
+#ifdef OSL_BIGENDIAN
+ pBuf->maColorMask = ColorMask( 0x0000ff, 0x00ff00, 0xff0000 );
+#else
+ pBuf->maColorMask = ColorMask( 0xff0000, 0x00ff00, 0x0000ff );
+#endif
+ break;
+
+ default:
+ // this is an error case !!!!!
+ nBitCount = 1;
+ pBuf->mnFormat = BMP_FORMAT_1BIT_MSB_PAL;
+ break;
+ }
+ if( m_aBitmap->isTopDown() )
+ pBuf->mnFormat |= BMP_FORMAT_TOP_DOWN;
+
+ B2IVector aSize = m_aBitmap->getSize();
+ pBuf->mnWidth = aSize.getX();
+ pBuf->mnHeight = aSize.getY();
+ pBuf->mnScanlineSize = m_aBitmap->getScanlineStride();
+ pBuf->mnBitCount = nBitCount;
+ pBuf->mpBits = (BYTE*)m_aBitmap->getBuffer().get();
+ if( nBitCount <= 8 )
+ {
+ if( m_aBitmap->getScanlineFormat() == Format::EIGHT_BIT_GREY ||
+ m_aBitmap->getScanlineFormat() == Format::FOUR_BIT_LSB_GREY ||
+ m_aBitmap->getScanlineFormat() == Format::FOUR_BIT_MSB_GREY ||
+ m_aBitmap->getScanlineFormat() == Format::ONE_BIT_LSB_GREY ||
+ m_aBitmap->getScanlineFormat() == Format::ONE_BIT_MSB_GREY
+ )
+ pBuf->maPalette = Bitmap::GetGreyPalette( 1U << nBitCount );
+ else
+ {
+ basebmp::PaletteMemorySharedVector aPalette = m_aBitmap->getPalette();
+ if( aPalette.get() )
+ {
+ unsigned int nColors = aPalette->size();
+ if( nColors > 0 )
+ {
+ pBuf->maPalette.SetEntryCount( nColors );
+ for( unsigned int i = 0; i < nColors; i++ )
+ {
+ const basebmp::Color& rCol = (*aPalette)[i];
+ pBuf->maPalette[i] = BitmapColor( rCol.getRed(), rCol.getGreen(), rCol.getBlue() );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return pBuf;
+}
+
+void SvpSalBitmap::ReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly )
+{
+ if( !bReadOnly && pBuffer->maPalette.GetEntryCount() )
+ {
+ // palette might have changed, clone device (but recycle
+ // memory)
+ USHORT nBitCount = 0;
+ switch( m_aBitmap->getScanlineFormat() )
+ {
+ case Format::ONE_BIT_MSB_GREY:
+ // FALLTHROUGH intended
+ case Format::ONE_BIT_MSB_PAL:
+ // FALLTHROUGH intended
+ case Format::ONE_BIT_LSB_GREY:
+ // FALLTHROUGH intended
+ case Format::ONE_BIT_LSB_PAL:
+ nBitCount = 1;
+ break;
+
+ case Format::FOUR_BIT_MSB_GREY:
+ // FALLTHROUGH intended
+ case Format::FOUR_BIT_MSB_PAL:
+ // FALLTHROUGH intended
+ case Format::FOUR_BIT_LSB_GREY:
+ // FALLTHROUGH intended
+ case Format::FOUR_BIT_LSB_PAL:
+ nBitCount = 4;
+ break;
+
+ case Format::EIGHT_BIT_PAL:
+ // FALLTHROUGH intended
+ case Format::EIGHT_BIT_GREY:
+ nBitCount = 8;
+ break;
+
+ default:
+ break;
+ }
+
+ if( nBitCount )
+ {
+ sal_uInt32 nEntries = 1U << nBitCount;
+
+ boost::shared_ptr< std::vector<basebmp::Color> > pPal(
+ new std::vector<basebmp::Color>( nEntries,
+ basebmp::Color(COL_WHITE)));
+ const sal_uInt32 nColors = std::min(
+ (sal_uInt32)pBuffer->maPalette.GetEntryCount(),
+ nEntries);
+ for( sal_uInt32 i = 0; i < nColors; i++ )
+ {
+ const BitmapColor& rCol = pBuffer->maPalette[i];
+ (*pPal)[i] = basebmp::Color( rCol.GetRed(), rCol.GetGreen(), rCol.GetBlue() );
+ }
+
+ m_aBitmap = basebmp::createBitmapDevice( m_aBitmap->getSize(),
+ m_aBitmap->isTopDown(),
+ m_aBitmap->getScanlineFormat(),
+ m_aBitmap->getBuffer(),
+ pPal );
+ }
+ }
+
+ delete pBuffer;
+}
+
+bool SvpSalBitmap::GetSystemData( BitmapSystemData& )
+{
+ return false;
+}
+
+
diff --git a/vcl/unx/headless/svpbmp.hxx b/vcl/unx/headless/svpbmp.hxx
new file mode 100644
index 000000000000..dc775e66aaf1
--- /dev/null
+++ b/vcl/unx/headless/svpbmp.hxx
@@ -0,0 +1,66 @@
+/*************************************************************************
+ *
+ * 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 SVP_SVBMP_HXX
+#define SVP_SVBMP_HXX
+
+#include <vcl/salbmp.hxx>
+#include "svpelement.hxx"
+
+class SvpSalBitmap : public SalBitmap, public SvpElement
+{
+ basebmp::BitmapDeviceSharedPtr m_aBitmap;
+public:
+ SvpSalBitmap() {}
+ virtual ~SvpSalBitmap();
+
+ const basebmp::BitmapDeviceSharedPtr& getBitmap() const { return m_aBitmap; }
+ void setBitmap( const basebmp::BitmapDeviceSharedPtr& rSrc ) { m_aBitmap = rSrc; }
+
+ // SvpElement
+ virtual const basebmp::BitmapDeviceSharedPtr& getDevice() const { return m_aBitmap; }
+
+ // SalBitmap
+ virtual bool Create( const Size& rSize,
+ USHORT nBitCount,
+ const BitmapPalette& rPal );
+ virtual bool Create( const SalBitmap& rSalBmp );
+ virtual bool Create( const SalBitmap& rSalBmp,
+ SalGraphics* pGraphics );
+ virtual bool Create( const SalBitmap& rSalBmp,
+ USHORT nNewBitCount );
+ virtual void Destroy();
+ virtual Size GetSize() const;
+ virtual USHORT GetBitCount() const;
+
+ virtual BitmapBuffer* AcquireBuffer( bool bReadOnly );
+ virtual void ReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly );
+ virtual bool GetSystemData( BitmapSystemData& rData );
+
+};
+
+#endif
diff --git a/vcl/unx/headless/svpdummies.cxx b/vcl/unx/headless/svpdummies.cxx
new file mode 100644
index 000000000000..5983ff18c34f
--- /dev/null
+++ b/vcl/unx/headless/svpdummies.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.
+ *
+ ************************************************************************/
+
+#include "svpdummies.hxx"
+#include "svpinst.hxx"
+#include <rtl/ustrbuf.hxx>
+
+// SalObject
+SvpSalObject::SvpSalObject()
+{
+ m_aSystemChildData.nSize = sizeof( SystemChildData );
+ m_aSystemChildData.pDisplay = NULL;
+ m_aSystemChildData.aWindow = 0;
+ m_aSystemChildData.pSalFrame = 0;
+ m_aSystemChildData.pWidget = 0;
+ m_aSystemChildData.pVisual = 0;
+ m_aSystemChildData.nDepth = 0;
+ m_aSystemChildData.aColormap = 0;
+ m_aSystemChildData.pAppContext = NULL;
+ m_aSystemChildData.aShellWindow = 0;
+ m_aSystemChildData.pShellWidget = NULL;
+}
+
+SvpSalObject::~SvpSalObject()
+{
+}
+
+void SvpSalObject::ResetClipRegion() {}
+USHORT SvpSalObject::GetClipRegionType() { return 0; }
+void SvpSalObject::BeginSetClipRegion( ULONG ) {}
+void SvpSalObject::UnionClipRegion( long, long, long, long ) {}
+void SvpSalObject::EndSetClipRegion() {}
+void SvpSalObject::SetPosSize( long, long, long, long ) {}
+void SvpSalObject::Show( BOOL ) {}
+void SvpSalObject::Enable( BOOL ) {}
+void SvpSalObject::GrabFocus() {}
+void SvpSalObject::SetBackground() {}
+void SvpSalObject::SetBackground( SalColor ) {}
+const SystemEnvData* SvpSalObject::GetSystemData() const { return &m_aSystemChildData; }
+
+// SalI18NImeStatus
+SvpImeStatus::~SvpImeStatus() {}
+bool SvpImeStatus::canToggle() { return false; }
+void SvpImeStatus::toggle() {}
+
+// SalSystem
+SvpSalSystem::~SvpSalSystem() {}
+
+unsigned int SvpSalSystem::GetDisplayScreenCount()
+{
+ return 1;
+}
+
+unsigned int SvpSalSystem::GetDefaultDisplayNumber()
+{
+ return 0;
+}
+
+bool SvpSalSystem::IsMultiDisplay()
+{
+ return false;
+}
+
+Rectangle SvpSalSystem::GetDisplayScreenPosSizePixel( unsigned int nScreen )
+{
+ Rectangle aRect;
+ if( nScreen == 0 )
+ aRect = Rectangle( Point(0,0), Size(VIRTUAL_DESKTOP_WIDTH,VIRTUAL_DESKTOP_HEIGHT) );
+ return aRect;
+}
+
+Rectangle SvpSalSystem::GetDisplayWorkAreaPosSizePixel( unsigned int nScreen )
+{
+ return GetDisplayScreenPosSizePixel( nScreen );
+}
+
+rtl::OUString SvpSalSystem::GetScreenName( unsigned int nScreen )
+{
+ rtl::OUStringBuffer aBuf( 32 );
+ aBuf.appendAscii( "VirtualScreen " );
+ aBuf.append( sal_Int32(nScreen) );
+ return aBuf.makeStringAndClear();
+}
+
+int SvpSalSystem::ShowNativeMessageBox( const String&,
+ const String&,
+ int,
+ int )
+{
+ return 0;
+}
+
diff --git a/vcl/unx/headless/svpdummies.hxx b/vcl/unx/headless/svpdummies.hxx
new file mode 100644
index 000000000000..febf7eef6bbe
--- /dev/null
+++ b/vcl/unx/headless/svpdummies.hxx
@@ -0,0 +1,94 @@
+/*************************************************************************
+ *
+ * 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 _SVP_SVPDUMMIES_HXX
+
+#include <vcl/salobj.hxx>
+#include <vcl/sysdata.hxx>
+#include <vcl/salimestatus.hxx>
+#include <vcl/salsys.hxx>
+
+class SalGraphics;
+
+class SvpSalObject : public SalObject
+{
+public:
+ SystemChildData m_aSystemChildData;
+
+ SvpSalObject();
+ virtual ~SvpSalObject();
+
+ // overload all pure virtual methods
+ virtual void ResetClipRegion();
+ virtual USHORT GetClipRegionType();
+ virtual void BeginSetClipRegion( ULONG nRects );
+ virtual void UnionClipRegion( long nX, long nY, long nWidth, long nHeight );
+ virtual void EndSetClipRegion();
+
+ virtual void SetPosSize( long nX, long nY, long nWidth, long nHeight );
+ virtual void Show( BOOL bVisible );
+ virtual void Enable( BOOL nEnable );
+ virtual void GrabFocus();
+
+ virtual void SetBackground();
+ virtual void SetBackground( SalColor nSalColor );
+
+ virtual const SystemEnvData* GetSystemData() const;
+};
+
+class SvpImeStatus : public SalI18NImeStatus
+{
+ public:
+ SvpImeStatus() {}
+ virtual ~SvpImeStatus();
+
+ virtual bool canToggle();
+ virtual void toggle();
+};
+
+class SvpSalSystem : public SalSystem
+{
+ public:
+ SvpSalSystem() {}
+ virtual ~SvpSalSystem();
+ // get info about the display
+ virtual unsigned int GetDisplayScreenCount();
+ virtual bool IsMultiDisplay();
+ virtual unsigned int GetDefaultDisplayNumber();
+ virtual Rectangle GetDisplayScreenPosSizePixel( unsigned int nScreen );
+ virtual Rectangle GetDisplayWorkAreaPosSizePixel( unsigned int nScreen );
+ virtual rtl::OUString GetScreenName( unsigned int nScreen );
+
+
+ virtual int ShowNativeMessageBox( const String& rTitle,
+ const String& rMessage,
+ int nButtonCombination,
+ int nDefaultButton);
+};
+
+
+#endif // _SVP_SVPDUMMIES_H
diff --git a/vcl/unx/headless/svpelement.cxx b/vcl/unx/headless/svpelement.cxx
new file mode 100644
index 000000000000..4041e2f7739a
--- /dev/null
+++ b/vcl/unx/headless/svpelement.cxx
@@ -0,0 +1,291 @@
+/*************************************************************************
+ *
+ * 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 "svpelement.hxx"
+
+#include <basebmp/scanlineformats.hxx>
+#include <tools/debug.hxx>
+
+#if defined WITH_SVP_LISTENING
+#include <osl/thread.h>
+#include <vcl/svapp.hxx>
+#include <rtl/strbuf.hxx>
+#include <vcl/bitmap.hxx>
+#include <tools/stream.hxx>
+
+#include "svpvd.hxx"
+#include "svpbmp.hxx"
+#include "svpframe.hxx"
+
+#include <list>
+#include <hash_map>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/ip.h>
+#include <stdio.h>
+#include <errno.h>
+
+using namespace basegfx;
+
+class SvpElementContainer
+{
+ std::list< SvpElement* > m_aElements;
+ int m_nSocket;
+ oslThread m_aThread;
+
+ SvpElementContainer();
+ ~SvpElementContainer();
+ public:
+ void registerElement( SvpElement* pElement ) { m_aElements.push_back(pElement); }
+ void deregisterElement( SvpElement* pElement ) { m_aElements.remove(pElement); }
+
+ void run();
+ DECL_LINK(processRequest,void*);
+
+ static SvpElementContainer& get();
+};
+
+extern "C" void SAL_CALL SvpContainerThread( void* );
+
+SvpElementContainer& SvpElementContainer::get()
+{
+ static SvpElementContainer* pInstance = new SvpElementContainer();
+ return *pInstance;
+}
+
+SvpElementContainer::SvpElementContainer()
+{
+ static const char* pEnv = getenv("SVP_LISTENER_PORT");
+ int nPort = (pEnv && *pEnv) ? atoi(pEnv) : 8000;
+ m_nSocket = socket( PF_INET, SOCK_STREAM, 0 );
+ if( m_nSocket >= 0)
+ {
+ int nOn = 1;
+ if( setsockopt(m_nSocket, SOL_SOCKET, SO_REUSEADDR,
+ (char*)&nOn, sizeof(nOn)) )
+ {
+ perror( "SvpElementContainer: changing socket options failed" );
+ close( m_nSocket );
+ }
+ else
+ {
+ struct sockaddr_in addr;
+ memset(&addr, 0, sizeof(struct sockaddr_in));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(nPort);
+ addr.sin_addr.s_addr = INADDR_ANY;
+ if( bind(m_nSocket,(struct sockaddr*)&addr,sizeof(addr)) )
+ {
+ perror( "SvpElementContainer: bind() failed" );
+ close( m_nSocket );
+ }
+ else
+ {
+ if( listen( m_nSocket, 0 ) )
+ {
+ perror( "SvpElementContainer: listen() failed" );
+ close(m_nSocket);
+ }
+ else
+ {
+ m_aThread = osl_createThread( SvpContainerThread, this );
+ }
+ }
+ }
+ }
+ else
+ perror( "SvpElementContainer: socket() failed\n" );
+}
+
+SvpElementContainer::~SvpElementContainer()
+{
+}
+
+void SAL_CALL SvpContainerThread(void* pSvpContainer)
+{
+ ((SvpElementContainer*)pSvpContainer)->run();
+}
+
+void SvpElementContainer::run()
+{
+ bool bRun = m_nSocket != 0;
+ while( bRun )
+ {
+ int nLocalSocket = accept( m_nSocket, NULL, NULL );
+ if( nLocalSocket < 0 )
+ {
+ bRun = false;
+ perror( "accept() failed" );
+ }
+ else
+ {
+ Application::PostUserEvent( LINK( this, SvpElementContainer, processRequest ), (void*)nLocalSocket );
+ }
+ }
+ if( m_nSocket )
+ close( m_nSocket );
+}
+
+static const char* matchType( SvpElement* pEle )
+{
+ if( dynamic_cast<SvpSalBitmap*>(pEle) )
+ return "Bitmap";
+ else if( dynamic_cast<SvpSalFrame*>(pEle) )
+ return "Frame";
+ else if( dynamic_cast<SvpSalVirtualDevice*>(pEle) )
+ return "VirtualDevice";
+ return typeid(*pEle).name();
+}
+
+IMPL_LINK( SvpElementContainer, processRequest, void*, pSocket )
+{
+ int nFile = (int)pSocket;
+
+ rtl::OStringBuffer aBuf( 256 ), aAnswer( 256 );
+ char c;
+ while( read( nFile, &c, 1 ) && c != '\n' )
+ aBuf.append( sal_Char(c) );
+ rtl::OString aCommand( aBuf.makeStringAndClear() );
+ if( aCommand.compareTo( "list", 4 ) == 0 )
+ {
+ std::hash_map< rtl::OString, std::list<SvpElement*>, rtl::OStringHash > aMap;
+ for( std::list< SvpElement* >::const_iterator it = m_aElements.begin();
+ it != m_aElements.end(); ++it )
+ {
+ std::list<SvpElement*>& rList = aMap[matchType(*it)];
+ rList.push_back( *it );
+ }
+ for( std::hash_map< rtl::OString, std::list<SvpElement*>, rtl::OStringHash>::const_iterator hash_it = aMap.begin();
+ hash_it != aMap.end(); ++hash_it )
+ {
+ aAnswer.append( "ElementType: " );
+ aAnswer.append( hash_it->first );
+ aAnswer.append( '\n' );
+ for( std::list<SvpElement*>::const_iterator it = hash_it->second.begin();
+ it != hash_it->second.end(); ++it )
+ {
+ aAnswer.append( sal_Int64(reinterpret_cast<sal_uInt32>(*it)), 16 );
+ aAnswer.append( '\n' );
+ }
+ }
+ }
+ else if( aCommand.compareTo( "get", 3 ) == 0 )
+ {
+ sal_IntPtr aId = aCommand.copy( 3 ).toInt64( 16 );
+ SvpElement* pElement = reinterpret_cast<SvpElement*>(aId);
+ for( std::list< SvpElement* >::const_iterator it = m_aElements.begin();
+ it != m_aElements.end(); ++it )
+ {
+ if( *it == pElement )
+ {
+ const basebmp::BitmapDeviceSharedPtr& rDevice = pElement->getDevice();
+ if( rDevice.get() )
+ {
+ SvpSalBitmap* pSalBitmap = new SvpSalBitmap();
+ pSalBitmap->setBitmap( rDevice );
+ Bitmap aBitmap( pSalBitmap );
+ SvMemoryStream aStream( 256, 256 );
+ aStream << aBitmap;
+ aStream.Seek( STREAM_SEEK_TO_END );
+ int nBytes = aStream.Tell();
+ aStream.Seek( STREAM_SEEK_TO_BEGIN );
+ aAnswer.append( (const sal_Char*)aStream.GetData(), nBytes );
+ }
+ break;
+ }
+ }
+ }
+ else if( aCommand.compareTo( "quit", 4 ) == 0 )
+ {
+ Application::Quit();
+ close( m_nSocket );
+ m_nSocket = 0;
+ }
+ write( nFile, aAnswer.getStr(), aAnswer.getLength() );
+ close( nFile );
+
+ return 0;
+}
+
+#endif
+
+using namespace basebmp;
+
+SvpElement::SvpElement()
+{
+ #if defined WITH_SVP_LISTENING
+ SvpElementContainer::get().registerElement( this );
+ #endif
+}
+
+SvpElement::~SvpElement()
+{
+ #if defined WITH_SVP_LISTENING
+ SvpElementContainer::get().deregisterElement( this );
+ #endif
+}
+
+sal_uInt32 SvpElement::getBitCountFromScanlineFormat( sal_Int32 nFormat )
+{
+ sal_uInt32 nBitCount = 1;
+ switch( nFormat )
+ {
+ case Format::ONE_BIT_MSB_GREY:
+ case Format::ONE_BIT_LSB_GREY:
+ case Format::ONE_BIT_MSB_PAL:
+ case Format::ONE_BIT_LSB_PAL:
+ nBitCount = 1;
+ break;
+ case Format::FOUR_BIT_MSB_GREY:
+ case Format::FOUR_BIT_LSB_GREY:
+ case Format::FOUR_BIT_MSB_PAL:
+ case Format::FOUR_BIT_LSB_PAL:
+ nBitCount = 4;
+ break;
+ case Format::EIGHT_BIT_PAL:
+ case Format::EIGHT_BIT_GREY:
+ nBitCount = 8;
+ break;
+ case Format::SIXTEEN_BIT_LSB_TC_MASK:
+ case Format::SIXTEEN_BIT_MSB_TC_MASK:
+ nBitCount = 16;
+ break;
+ case Format::TWENTYFOUR_BIT_TC_MASK:
+ nBitCount = 24;
+ break;
+ case Format::THIRTYTWO_BIT_TC_MASK:
+ nBitCount = 32;
+ break;
+ default:
+ DBG_ERROR( "unsupported basebmp format" );
+ break;
+ }
+ return nBitCount;
+}
+
+
diff --git a/vcl/unx/headless/svpelement.hxx b/vcl/unx/headless/svpelement.hxx
new file mode 100644
index 000000000000..0706e75af9fe
--- /dev/null
+++ b/vcl/unx/headless/svpelement.hxx
@@ -0,0 +1,46 @@
+/*************************************************************************
+ *
+ * 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 _SVP_SVPELEMENT_HXX
+#define _SVP_SVPELEMENT_HXX
+
+#include <basebmp/bitmapdevice.hxx>
+
+#define SVP_DEFAULT_BITMAP_FORMAT basebmp::Format::TWENTYFOUR_BIT_TC_MASK
+
+class SvpElement
+{
+ protected:
+ SvpElement();
+ virtual ~SvpElement();
+ public:
+ virtual const basebmp::BitmapDeviceSharedPtr& getDevice() const = 0;
+
+ static sal_uInt32 getBitCountFromScanlineFormat( sal_Int32 nFormat );
+};
+
+#endif
diff --git a/vcl/unx/headless/svpframe.cxx b/vcl/unx/headless/svpframe.cxx
new file mode 100644
index 000000000000..1adf9a51cce4
--- /dev/null
+++ b/vcl/unx/headless/svpframe.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.
+ *
+ ************************************************************************/
+
+#include "svpframe.hxx"
+#include "svpinst.hxx"
+#include "svpgdi.hxx"
+
+#include <basebmp/scanlineformats.hxx>
+#include <basegfx/vector/b2ivector.hxx>
+
+using namespace basebmp;
+using namespace basegfx;
+
+SvpSalFrame* SvpSalFrame::s_pFocusFrame = NULL;
+
+SvpSalFrame::SvpSalFrame( SvpSalInstance* pInstance,
+ SalFrame* pParent,
+ ULONG nSalFrameStyle,
+ SystemParentData* ) :
+ m_pInstance( pInstance ),
+ m_pParent( static_cast<SvpSalFrame*>(pParent) ),
+ m_nStyle( nSalFrameStyle ),
+ m_bVisible( false ),
+ m_nMinWidth( 0 ),
+ m_nMinHeight( 0 ),
+ m_nMaxWidth( 0 ),
+ m_nMaxHeight( 0 )
+{
+ m_aSystemChildData.nSize = sizeof( SystemChildData );
+ m_aSystemChildData.pDisplay = NULL;
+ m_aSystemChildData.aWindow = 0;
+ m_aSystemChildData.pSalFrame = this;
+ m_aSystemChildData.pWidget = NULL;
+ m_aSystemChildData.pVisual = NULL;
+ m_aSystemChildData.nDepth = 24;
+ m_aSystemChildData.aColormap = 0;
+ m_aSystemChildData.pAppContext = NULL;
+ m_aSystemChildData.aShellWindow = 0;
+ m_aSystemChildData.pShellWidget = NULL;
+
+ if( m_pParent )
+ m_pParent->m_aChildren.push_back( this );
+
+ if( m_pInstance )
+ m_pInstance->registerFrame( this );
+
+ SetPosSize( 0, 0, 800, 600, SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT );
+}
+
+SvpSalFrame::~SvpSalFrame()
+{
+ if( m_pInstance )
+ m_pInstance->deregisterFrame( this );
+
+ std::list<SvpSalFrame*> Children = m_aChildren;
+ for( std::list<SvpSalFrame*>::iterator it = Children.begin();
+ it != Children.end(); ++it )
+ (*it)->SetParent( m_pParent );
+ if( m_pParent )
+ m_pParent->m_aChildren.remove( this );
+
+ if( s_pFocusFrame == this )
+ {
+ s_pFocusFrame = NULL;
+ // call directly here, else an event for a destroyed frame would be dispatched
+ CallCallback( SALEVENT_LOSEFOCUS, NULL );
+ // if the handler has not set a new focus frame
+ // pass focus to another frame, preferably a document style window
+ if( s_pFocusFrame == NULL )
+ {
+ const std::list< SalFrame* >& rFrames( m_pInstance->getFrames() );
+ for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it )
+ {
+ SvpSalFrame* pFrame = const_cast<SvpSalFrame*>(static_cast<const SvpSalFrame*>(*it));
+ if( pFrame->m_bVisible &&
+ pFrame->m_pParent == NULL &&
+ (pFrame->m_nStyle & (SAL_FRAME_STYLE_MOVEABLE |
+ SAL_FRAME_STYLE_SIZEABLE |
+ SAL_FRAME_STYLE_CLOSEABLE) ) != 0
+ )
+ {
+ pFrame->GetFocus();
+ break;
+ }
+ }
+ }
+ }
+}
+
+void SvpSalFrame::GetFocus()
+{
+ if( (m_nStyle & (SAL_FRAME_STYLE_OWNERDRAWDECORATION | SAL_FRAME_STYLE_FLOAT)) == 0 )
+ {
+ if( s_pFocusFrame )
+ s_pFocusFrame->LoseFocus();
+ s_pFocusFrame = this;
+ m_pInstance->PostEvent( this, NULL, SALEVENT_GETFOCUS );
+ }
+}
+
+void SvpSalFrame::LoseFocus()
+{
+ if( s_pFocusFrame == this )
+ {
+ m_pInstance->PostEvent( this, NULL, SALEVENT_LOSEFOCUS );
+ s_pFocusFrame = NULL;
+ }
+}
+
+SalGraphics* SvpSalFrame::GetGraphics()
+{
+ SvpSalGraphics* pGraphics = new SvpSalGraphics();
+ pGraphics->setDevice( m_aFrame );
+ m_aGraphics.push_back( pGraphics );
+ return pGraphics;
+}
+
+void SvpSalFrame::ReleaseGraphics( SalGraphics* pGraphics )
+{
+ SvpSalGraphics* pSvpGraphics = dynamic_cast<SvpSalGraphics*>(pGraphics);
+ m_aGraphics.remove( pSvpGraphics );
+ delete pSvpGraphics;
+}
+
+BOOL SvpSalFrame::PostEvent( void* pData )
+{
+ m_pInstance->PostEvent( this, pData, SALEVENT_USEREVENT );
+ return TRUE;
+}
+
+void SvpSalFrame::PostPaint() const
+{
+ if( m_bVisible )
+ {
+ SalPaintEvent aPEvt(0, 0, maGeometry.nWidth, maGeometry.nHeight);
+ CallCallback( SALEVENT_PAINT, &aPEvt );
+ }
+}
+
+void SvpSalFrame::SetTitle( const XubString& )
+{
+}
+
+void SvpSalFrame::SetIcon( USHORT )
+{
+}
+
+void SvpSalFrame::SetMenu( SalMenu* )
+{
+}
+
+void SvpSalFrame::DrawMenuBar()
+{
+}
+
+void SvpSalFrame::SetExtendedFrameStyle( SalExtStyle )
+{
+}
+
+void SvpSalFrame::Show( BOOL bVisible, BOOL bNoActivate )
+{
+ if( bVisible && ! m_bVisible )
+ {
+ m_bVisible = true;
+ m_pInstance->PostEvent( this, NULL, SALEVENT_RESIZE );
+ if( ! bNoActivate )
+ GetFocus();
+ }
+ else if( ! bVisible && m_bVisible )
+ {
+ m_bVisible = false;
+ m_pInstance->PostEvent( this, NULL, SALEVENT_RESIZE );
+ LoseFocus();
+ }
+}
+
+void SvpSalFrame::Enable( BOOL )
+{
+}
+
+void SvpSalFrame::SetMinClientSize( long nWidth, long nHeight )
+{
+ m_nMinWidth = nWidth;
+ m_nMinHeight = nHeight;
+}
+
+void SvpSalFrame::SetMaxClientSize( long nWidth, long nHeight )
+{
+ m_nMaxWidth = nWidth;
+ m_nMaxHeight = nHeight;
+}
+
+void SvpSalFrame::SetPosSize( long nX, long nY, long nWidth, long nHeight, USHORT nFlags )
+{
+ if( (nFlags & SAL_FRAME_POSSIZE_X) != 0 )
+ maGeometry.nX = nX;
+ if( (nFlags & SAL_FRAME_POSSIZE_Y) != 0 )
+ maGeometry.nY = nY;
+ if( (nFlags & SAL_FRAME_POSSIZE_WIDTH) != 0 )
+ {
+ maGeometry.nWidth = nWidth;
+ if( m_nMaxWidth > 0 && maGeometry.nWidth > (unsigned int)m_nMaxWidth )
+ maGeometry.nWidth = m_nMaxWidth;
+ if( m_nMinWidth > 0 && maGeometry.nWidth < (unsigned int)m_nMinWidth )
+ maGeometry.nWidth = m_nMinWidth;
+ }
+ if( (nFlags & SAL_FRAME_POSSIZE_HEIGHT) != 0 )
+ {
+ maGeometry.nHeight = nHeight;
+ if( m_nMaxHeight > 0 && maGeometry.nHeight > (unsigned int)m_nMaxHeight )
+ maGeometry.nHeight = m_nMaxHeight;
+ if( m_nMinHeight > 0 && maGeometry.nHeight < (unsigned int)m_nMinHeight )
+ maGeometry.nHeight = m_nMinHeight;
+ }
+ B2IVector aFrameSize( maGeometry.nWidth, maGeometry.nHeight );
+ if( ! m_aFrame.get() || m_aFrame->getSize() != aFrameSize )
+ {
+ if( aFrameSize.getX() == 0 )
+ aFrameSize.setX( 1 );
+ if( aFrameSize.getY() == 0 )
+ aFrameSize.setY( 1 );
+ m_aFrame = createBitmapDevice( aFrameSize, false, SVP_DEFAULT_BITMAP_FORMAT );
+ // update device in existing graphics
+ for( std::list< SvpSalGraphics* >::iterator it = m_aGraphics.begin();
+ it != m_aGraphics.end(); ++it )
+ (*it)->setDevice( m_aFrame );
+ }
+ if( m_bVisible )
+ m_pInstance->PostEvent( this, NULL, SALEVENT_RESIZE );
+}
+
+void SvpSalFrame::GetClientSize( long& rWidth, long& rHeight )
+{
+ if( m_bVisible )
+ {
+ rWidth = maGeometry.nWidth;
+ rHeight = maGeometry.nHeight;
+ }
+ else
+ rWidth = rHeight = 0;
+}
+
+void SvpSalFrame::GetWorkArea( Rectangle& rRect )
+{
+ rRect = Rectangle( Point( 0, 0 ),
+ Size( VIRTUAL_DESKTOP_WIDTH, VIRTUAL_DESKTOP_HEIGHT ) );
+}
+
+SalFrame* SvpSalFrame::GetParent() const
+{
+ return m_pParent;
+}
+
+#define _FRAMESTATE_MASK_GEOMETRY \
+ (SAL_FRAMESTATE_MASK_X | SAL_FRAMESTATE_MASK_Y | \
+ SAL_FRAMESTATE_MASK_WIDTH | SAL_FRAMESTATE_MASK_HEIGHT)
+#define _FRAMESTATE_MASK_MAXIMIZED_GEOMETRY \
+ (SAL_FRAMESTATE_MASK_MAXIMIZED_X | SAL_FRAMESTATE_MASK_MAXIMIZED_Y | \
+ SAL_FRAMESTATE_MASK_MAXIMIZED_WIDTH | SAL_FRAMESTATE_MASK_MAXIMIZED_HEIGHT)
+
+void SvpSalFrame::SetWindowState( const SalFrameState *pState )
+{
+ if (pState == NULL)
+ return;
+
+ // Request for position or size change
+ if (pState->mnMask & _FRAMESTATE_MASK_GEOMETRY)
+ {
+ long nX = maGeometry.nX;
+ long nY = maGeometry.nY;
+ long nWidth = maGeometry.nWidth;
+ long nHeight = maGeometry.nHeight;
+
+ // change requested properties
+ if (pState->mnMask & SAL_FRAMESTATE_MASK_X)
+ nX = pState->mnX;
+ if (pState->mnMask & SAL_FRAMESTATE_MASK_Y)
+ nY = pState->mnY;
+ if (pState->mnMask & SAL_FRAMESTATE_MASK_WIDTH)
+ nWidth = pState->mnWidth;
+ if (pState->mnMask & SAL_FRAMESTATE_MASK_HEIGHT)
+ nHeight = pState->mnHeight;
+
+ SetPosSize( nX, nY, nWidth, nHeight,
+ SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y |
+ SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT );
+ }
+}
+
+BOOL SvpSalFrame::GetWindowState( SalFrameState* pState )
+{
+ pState->mnState = SAL_FRAMESTATE_NORMAL;
+ pState->mnX = maGeometry.nX;
+ pState->mnY = maGeometry.nY;
+ pState->mnWidth = maGeometry.nWidth;
+ pState->mnHeight = maGeometry.nHeight;
+ pState->mnMask = _FRAMESTATE_MASK_GEOMETRY | SAL_FRAMESTATE_MASK_STATE;
+
+ return TRUE;
+}
+
+void SvpSalFrame::ShowFullScreen( BOOL, sal_Int32 )
+{
+ SetPosSize( 0, 0, VIRTUAL_DESKTOP_WIDTH, VIRTUAL_DESKTOP_HEIGHT,
+ SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT );
+}
+
+void SvpSalFrame::StartPresentation( BOOL )
+{
+}
+
+void SvpSalFrame::SetAlwaysOnTop( BOOL )
+{
+}
+
+void SvpSalFrame::ToTop( USHORT )
+{
+ GetFocus();
+}
+
+void SvpSalFrame::SetPointer( PointerStyle )
+{
+}
+
+void SvpSalFrame::CaptureMouse( BOOL )
+{
+}
+
+void SvpSalFrame::SetPointerPos( long, long )
+{
+}
+
+void SvpSalFrame::Flush()
+{
+}
+
+void SvpSalFrame::Sync()
+{
+}
+
+void SvpSalFrame::SetInputContext( SalInputContext* )
+{
+}
+
+void SvpSalFrame::EndExtTextInput( USHORT )
+{
+}
+
+String SvpSalFrame::GetKeyName( USHORT )
+{
+ return String();
+}
+
+String SvpSalFrame::GetSymbolKeyName( const XubString&, USHORT )
+{
+ return String();
+}
+
+BOOL SvpSalFrame::MapUnicodeToKeyCode( sal_Unicode, LanguageType, KeyCode& )
+{
+ return FALSE;
+}
+
+LanguageType SvpSalFrame::GetInputLanguage()
+{
+ return LANGUAGE_DONTKNOW;
+}
+
+SalBitmap* SvpSalFrame::SnapShot()
+{
+ return NULL;
+}
+
+void SvpSalFrame::UpdateSettings( AllSettings& )
+{
+}
+
+void SvpSalFrame::Beep( SoundType )
+{
+}
+
+const SystemEnvData* SvpSalFrame::GetSystemData() const
+{
+ return &m_aSystemChildData;
+}
+
+SalFrame::SalPointerState SvpSalFrame::GetPointerState()
+{
+ SalPointerState aState;
+ aState.mnState = 0;
+ return aState;
+}
+
+void SvpSalFrame::SetParent( SalFrame* pNewParent )
+{
+ if( m_pParent )
+ m_pParent->m_aChildren.remove( this );
+ m_pParent = static_cast<SvpSalFrame*>(pNewParent);
+}
+
+bool SvpSalFrame::SetPluginParent( SystemParentData* )
+{
+ return true;
+}
+
+void SvpSalFrame::SetBackgroundBitmap( SalBitmap* )
+{
+}
+
+void SvpSalFrame::ResetClipRegion()
+{
+}
+
+void SvpSalFrame::BeginSetClipRegion( ULONG )
+{
+}
+
+void SvpSalFrame::UnionClipRegion( long, long, long, long )
+{
+}
+
+void SvpSalFrame::EndSetClipRegion()
+{
+}
+
diff --git a/vcl/unx/headless/svpframe.hxx b/vcl/unx/headless/svpframe.hxx
new file mode 100644
index 000000000000..de968bbf7a4a
--- /dev/null
+++ b/vcl/unx/headless/svpframe.hxx
@@ -0,0 +1,126 @@
+/*************************************************************************
+ *
+ * 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 _SVP_SVPFRAME_HXX
+
+#include <vcl/salframe.hxx>
+#include <vcl/sysdata.hxx>
+
+#include "svpelement.hxx"
+
+#include <list>
+
+class SvpSalInstance;
+class SvpSalGraphics;
+
+class SvpSalFrame : public SalFrame, public SvpElement
+{
+ SvpSalInstance* m_pInstance;
+ SvpSalFrame* m_pParent; // pointer to parent frame
+ std::list< SvpSalFrame* > m_aChildren; // List of child frames
+ ULONG m_nStyle;
+ bool m_bVisible;
+ long m_nMinWidth;
+ long m_nMinHeight;
+ long m_nMaxWidth;
+ long m_nMaxHeight;
+
+ SystemEnvData m_aSystemChildData;
+
+ basebmp::BitmapDeviceSharedPtr m_aFrame;
+ std::list< SvpSalGraphics* > m_aGraphics;
+
+ static SvpSalFrame* s_pFocusFrame;
+public:
+ SvpSalFrame( SvpSalInstance* pInstance,
+ SalFrame* pParent,
+ ULONG nSalFrameStyle,
+ SystemParentData* pSystemParent = NULL );
+ virtual ~SvpSalFrame();
+
+ void GetFocus();
+ void LoseFocus();
+ void PostPaint() const;
+
+ // SvpElement
+ virtual const basebmp::BitmapDeviceSharedPtr& getDevice() const { return m_aFrame; }
+
+ // SalFrame
+ virtual SalGraphics* GetGraphics();
+ virtual void ReleaseGraphics( SalGraphics* pGraphics );
+
+ virtual BOOL PostEvent( void* pData );
+
+ virtual void SetTitle( const XubString& rTitle );
+ virtual void SetIcon( USHORT nIcon );
+ virtual void SetMenu( SalMenu* pMenu );
+ virtual void DrawMenuBar();
+
+ virtual void SetExtendedFrameStyle( SalExtStyle nExtStyle );
+ virtual void Show( BOOL bVisible, BOOL bNoActivate = FALSE );
+ virtual void Enable( BOOL bEnable );
+ virtual void SetMinClientSize( long nWidth, long nHeight );
+ virtual void SetMaxClientSize( long nWidth, long nHeight );
+ virtual void SetPosSize( long nX, long nY, long nWidth, long nHeight, USHORT nFlags );
+ virtual void GetClientSize( long& rWidth, long& rHeight );
+ virtual void GetWorkArea( Rectangle& rRect );
+ virtual SalFrame* GetParent() const;
+ virtual void SetWindowState( const SalFrameState* pState );
+ virtual BOOL GetWindowState( SalFrameState* pState );
+ virtual void ShowFullScreen( BOOL bFullScreen, sal_Int32 nDisplay );
+ virtual void StartPresentation( BOOL bStart );
+ virtual void SetAlwaysOnTop( BOOL bOnTop );
+ virtual void ToTop( USHORT nFlags );
+ virtual void SetPointer( PointerStyle ePointerStyle );
+ virtual void CaptureMouse( BOOL bMouse );
+ virtual void SetPointerPos( long nX, long nY );
+ using SalFrame::Flush;
+ virtual void Flush();
+ virtual void Sync();
+ virtual void SetInputContext( SalInputContext* pContext );
+ virtual void EndExtTextInput( USHORT nFlags );
+ virtual String GetKeyName( USHORT nKeyCode );
+ virtual String GetSymbolKeyName( const XubString& rFontName, USHORT nKeyCode );
+ virtual BOOL MapUnicodeToKeyCode( sal_Unicode aUnicode, LanguageType aLangType, KeyCode& rKeyCode );
+ virtual LanguageType GetInputLanguage();
+ virtual SalBitmap* SnapShot();
+ virtual void UpdateSettings( AllSettings& rSettings );
+ virtual void Beep( SoundType eSoundType );
+ virtual const SystemEnvData* GetSystemData() const;
+ virtual SalPointerState GetPointerState();
+ virtual void SetParent( SalFrame* pNewParent );
+ virtual bool SetPluginParent( SystemParentData* pNewParent );
+ virtual void SetBackgroundBitmap( SalBitmap* pBitmap );
+ virtual void ResetClipRegion();
+ virtual void BeginSetClipRegion( ULONG nRects );
+ virtual void UnionClipRegion( long nX, long nY, long nWidth, long nHeight );
+ virtual void EndSetClipRegion();
+
+ /*TODO: functional implementation */
+ virtual void SetScreenNumber( unsigned int nScreen ) { (void)nScreen; }
+};
+#endif // _SVP_SVPFRAME_HXX
diff --git a/vcl/unx/headless/svpgdi.cxx b/vcl/unx/headless/svpgdi.cxx
new file mode 100644
index 000000000000..68d8be7cb4eb
--- /dev/null
+++ b/vcl/unx/headless/svpgdi.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.
+ *
+ ************************************************************************/
+
+#include "svpgdi.hxx"
+#include "svpbmp.hxx"
+
+#include <vcl/sysdata.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <basegfx/range/b2irange.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basebmp/scanlineformats.hxx>
+
+#include <tools/debug.hxx>
+
+#if OSL_DEBUG_LEVEL > 2
+#include <basebmp/debug.hxx>
+#include <fstream>
+#include <rtl/strbuf.hxx>
+#include <sys/stat.h>
+#endif
+
+#include <svppspgraphics.hxx>
+
+using namespace basegfx;
+using namespace basebmp;
+
+inline void dbgOut( const BitmapDeviceSharedPtr&
+#if OSL_DEBUG_LEVEL > 2
+rDevice
+#endif
+)
+{
+ #if OSL_DEBUG_LEVEL > 2
+ static int dbgStreamNum = 0;
+ rtl::OStringBuffer aBuf( 256 );
+ aBuf.append( "debug" );
+ mkdir( aBuf.getStr(), 0777 );
+ aBuf.append( "/" );
+ aBuf.append( sal_Int64(reinterpret_cast<sal_uInt32>(rDevice.get())), 16 );
+ mkdir( aBuf.getStr(), 0777 );
+ aBuf.append( "/bmp" );
+ aBuf.append( sal_Int32(dbgStreamNum++) );
+ std::fstream bmpstream( aBuf.getStr(), std::ios::out );
+ debugDump( rDevice, bmpstream );
+ #endif
+}
+
+// ===========================================================================
+
+bool SvpSalGraphics::drawAlphaBitmap( const SalTwoRect&, const SalBitmap& /*rSourceBitmap*/, const SalBitmap& /*rAlphaBitmap*/ )
+{
+ // TODO(P3) implement alpha blending
+ return false;
+}
+
+bool SvpSalGraphics::drawAlphaRect( long /*nX*/, long /*nY*/, long /*nWidth*/, long /*nHeight*/, sal_uInt8 /*nTransparency*/ )
+{
+ // TODO(P3) implement alpha blending
+ return false;
+}
+
+SvpSalGraphics::SvpSalGraphics() :
+ m_bUseLineColor( true ),
+ m_aLineColor( COL_BLACK ),
+ m_bUseFillColor( false ),
+ m_aFillColor( COL_WHITE ),
+ m_aTextColor( COL_BLACK ),
+ m_aDrawMode( DrawMode_PAINT ),
+ m_eTextFmt( Format::EIGHT_BIT_GREY )
+{
+ for( int i = 0; i < MAX_FALLBACK; ++i )
+ m_pServerFont[i] = NULL;
+}
+
+SvpSalGraphics::~SvpSalGraphics()
+{
+}
+
+void SvpSalGraphics::setDevice( BitmapDeviceSharedPtr& rDevice )
+{
+ m_aDevice = rDevice;
+ m_aOrigDevice = rDevice;
+ m_aClipMap.reset();
+
+ // determine matching bitmap format for masks
+ sal_uInt32 nDeviceFmt = m_aDevice->getScanlineFormat();
+ DBG_ASSERT( (nDeviceFmt <= (sal_uInt32)Format::MAX), "SVP::setDevice() with invalid bitmap format" );
+ switch( nDeviceFmt )
+ {
+ case Format::EIGHT_BIT_GREY:
+ case Format::SIXTEEN_BIT_LSB_TC_MASK:
+ case Format::SIXTEEN_BIT_MSB_TC_MASK:
+ case Format::TWENTYFOUR_BIT_TC_MASK:
+ case Format::THIRTYTWO_BIT_TC_MASK:
+ m_eTextFmt = Format::EIGHT_BIT_GREY;
+ break;
+ default:
+ m_eTextFmt = Format::ONE_BIT_LSB_GREY;
+ break;
+ }
+}
+
+void SvpSalGraphics::GetResolution( sal_Int32& rDPIX, sal_Int32& rDPIY )
+{
+ rDPIX = rDPIY = 96;
+}
+
+USHORT SvpSalGraphics::GetBitCount()
+{
+ return SvpElement::getBitCountFromScanlineFormat( m_aDevice->getScanlineFormat() );
+}
+
+long SvpSalGraphics::GetGraphicsWidth() const
+{
+ if( m_aDevice.get() )
+ {
+ B2IVector aSize = m_aDevice->getSize();
+ return aSize.getX();
+ }
+ return 0;
+}
+
+void SvpSalGraphics::ResetClipRegion()
+{
+ m_aDevice = m_aOrigDevice;
+ m_aClipMap.reset();
+}
+
+void SvpSalGraphics::BeginSetClipRegion( ULONG n )
+{
+ if( n <= 1 )
+ {
+ m_aClipMap.reset();
+ }
+ else
+ {
+ m_aDevice = m_aOrigDevice;
+ B2IVector aSize = m_aDevice->getSize();
+ m_aClipMap = createBitmapDevice( aSize, false, Format::ONE_BIT_MSB_GREY );
+ m_aClipMap->clear( basebmp::Color(0xFFFFFFFF) );
+ }
+}
+
+BOOL SvpSalGraphics::unionClipRegion( long nX, long nY, long nWidth, long nHeight )
+{
+ if( m_aClipMap )
+ {
+ B2DPolyPolygon aFull;
+ aFull.append( tools::createPolygonFromRect( B2DRectangle( nX, nY, nX+nWidth, nY+nHeight ) ) );
+ m_aClipMap->fillPolyPolygon( aFull, basebmp::Color(0), DrawMode_PAINT );
+ }
+ else
+ {
+ m_aDevice = basebmp::subsetBitmapDevice( m_aOrigDevice,
+ basegfx::B2IRange(nX,nY,nX+nWidth,nY+nHeight) );
+ }
+
+ return TRUE;
+}
+
+bool SvpSalGraphics::unionClipRegion( const ::basegfx::B2DPolyPolygon& )
+{
+ // TODO: implement and advertise OutDevSupport_B2DClip support
+ return false;
+}
+
+void SvpSalGraphics::EndSetClipRegion()
+{
+}
+
+void SvpSalGraphics::SetLineColor()
+{
+ m_bUseLineColor = false;
+}
+
+void SvpSalGraphics::SetLineColor( SalColor nSalColor )
+{
+ m_bUseLineColor = true;
+ m_aLineColor = basebmp::Color( nSalColor );
+}
+
+void SvpSalGraphics::SetFillColor()
+{
+ m_bUseFillColor = false;
+}
+
+void SvpSalGraphics::SetFillColor( SalColor nSalColor )
+{
+ m_bUseFillColor = true;
+ m_aFillColor = basebmp::Color( nSalColor );
+}
+
+void SvpSalGraphics::SetXORMode( bool bSet, bool )
+{
+ m_aDrawMode = bSet ? DrawMode_XOR : DrawMode_PAINT;
+}
+
+void SvpSalGraphics::SetROPLineColor( SalROPColor nROPColor )
+{
+ m_bUseLineColor = true;
+ switch( nROPColor )
+ {
+ case SAL_ROP_0:
+ m_aLineColor = basebmp::Color( 0 );
+ break;
+ case SAL_ROP_1:
+ m_aLineColor = basebmp::Color( 0xffffff );
+ break;
+ case SAL_ROP_INVERT:
+ m_aLineColor = basebmp::Color( 0xffffff );
+ break;
+ }
+}
+
+void SvpSalGraphics::SetROPFillColor( SalROPColor nROPColor )
+{
+ m_bUseFillColor = true;
+ switch( nROPColor )
+ {
+ case SAL_ROP_0:
+ m_aFillColor = basebmp::Color( 0 );
+ break;
+ case SAL_ROP_1:
+ m_aFillColor = basebmp::Color( 0xffffff );
+ break;
+ case SAL_ROP_INVERT:
+ m_aFillColor = basebmp::Color( 0xffffff );
+ break;
+ }
+}
+
+void SvpSalGraphics::SetTextColor( SalColor nSalColor )
+{
+ m_aTextColor = basebmp::Color( nSalColor );
+}
+
+void SvpSalGraphics::drawPixel( long nX, long nY )
+{
+ if( m_bUseLineColor )
+ m_aDevice->setPixel( B2IPoint( nX, nY ),
+ m_aLineColor,
+ m_aDrawMode,
+ m_aClipMap
+ );
+ dbgOut( m_aDevice );
+}
+
+void SvpSalGraphics::drawPixel( long nX, long nY, SalColor nSalColor )
+{
+ basebmp::Color aColor( nSalColor );
+ m_aDevice->setPixel( B2IPoint( nX, nY ),
+ aColor,
+ m_aDrawMode,
+ m_aClipMap
+ );
+ dbgOut( m_aDevice );
+}
+
+void SvpSalGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 )
+{
+ if( m_bUseLineColor )
+ m_aDevice->drawLine( B2IPoint( nX1, nY1 ),
+ B2IPoint( nX2, nY2 ),
+ m_aLineColor,
+ m_aDrawMode,
+ m_aClipMap );
+ dbgOut( m_aDevice );
+}
+
+void SvpSalGraphics::drawRect( long nX, long nY, long nWidth, long nHeight )
+{
+ if( m_bUseLineColor || m_bUseFillColor )
+ {
+ B2DPolygon aRect = tools::createPolygonFromRect( B2DRectangle( nX, nY, nX+nWidth, nY+nHeight ) );
+ if( m_bUseFillColor )
+ {
+ B2DPolyPolygon aPolyPoly( aRect );
+ m_aDevice->fillPolyPolygon( aPolyPoly, m_aFillColor, m_aDrawMode, m_aClipMap );
+ }
+ if( m_bUseLineColor )
+ m_aDevice->drawPolygon( aRect, m_aLineColor, m_aDrawMode, m_aClipMap );
+ }
+ dbgOut( m_aDevice );
+}
+
+void SvpSalGraphics::drawPolyLine( ULONG nPoints, const SalPoint* pPtAry )
+{
+ if( m_bUseLineColor && nPoints )
+ {
+ B2DPolygon aPoly;
+ aPoly.append( B2DPoint( pPtAry->mnX, pPtAry->mnY ), nPoints );
+ for( ULONG i = 1; i < nPoints; i++ )
+ aPoly.setB2DPoint( i, B2DPoint( pPtAry[i].mnX, pPtAry[i].mnY ) );
+ aPoly.setClosed( false );
+ m_aDevice->drawPolygon( aPoly, m_aLineColor, m_aDrawMode, m_aClipMap );
+ }
+ dbgOut( m_aDevice );
+}
+
+void SvpSalGraphics::drawPolygon( ULONG nPoints, const SalPoint* pPtAry )
+{
+ if( ( m_bUseLineColor || m_bUseFillColor ) && nPoints )
+ {
+ B2DPolygon aPoly;
+ aPoly.append( B2DPoint( pPtAry->mnX, pPtAry->mnY ), nPoints );
+ for( ULONG i = 1; i < nPoints; i++ )
+ aPoly.setB2DPoint( i, B2DPoint( pPtAry[i].mnX, pPtAry[i].mnY ) );
+ if( m_bUseFillColor )
+ {
+ aPoly.setClosed( true );
+ m_aDevice->fillPolyPolygon( B2DPolyPolygon(aPoly), m_aFillColor, m_aDrawMode, m_aClipMap );
+ }
+ if( m_bUseLineColor )
+ {
+ aPoly.setClosed( false );
+ m_aDevice->drawPolygon( aPoly, m_aLineColor, m_aDrawMode, m_aClipMap );
+ }
+ }
+ dbgOut( m_aDevice );
+}
+
+void SvpSalGraphics::drawPolyPolygon( sal_uInt32 nPoly,
+ const sal_uInt32* pPointCounts,
+ PCONSTSALPOINT* pPtAry )
+{
+ if( ( m_bUseLineColor || m_bUseFillColor ) && nPoly )
+ {
+ B2DPolyPolygon aPolyPoly;
+ for( sal_uInt32 nPolygon = 0; nPolygon < nPoly; nPolygon++ )
+ {
+ sal_uInt32 nPoints = pPointCounts[nPolygon];
+ if( nPoints )
+ {
+ PCONSTSALPOINT pPoints = pPtAry[nPolygon];
+ B2DPolygon aPoly;
+ aPoly.append( B2DPoint( pPoints->mnX, pPoints->mnY ), nPoints );
+ for( ULONG i = 1; i < nPoints; i++ )
+ aPoly.setB2DPoint( i, B2DPoint( pPoints[i].mnX, pPoints[i].mnY ) );
+
+ aPolyPoly.append( aPoly );
+ }
+ }
+ if( m_bUseFillColor )
+ {
+ aPolyPoly.setClosed( true );
+ m_aDevice->fillPolyPolygon( aPolyPoly, m_aFillColor, m_aDrawMode, m_aClipMap );
+ }
+ if( m_bUseLineColor )
+ {
+ aPolyPoly.setClosed( false );
+ nPoly = aPolyPoly.count();
+ for( sal_uInt32 i = 0; i < nPoly; i++ )
+ m_aDevice->drawPolygon( aPolyPoly.getB2DPolygon(i), m_aLineColor, m_aDrawMode, m_aClipMap );
+ }
+ }
+ dbgOut( m_aDevice );
+}
+
+bool SvpSalGraphics::drawPolyLine( const ::basegfx::B2DPolygon&, double /*fTransparency*/, const ::basegfx::B2DVector& /*rLineWidths*/, basegfx::B2DLineJoin /*eJoin*/ )
+{
+ // TODO: implement and advertise OutDevSupport_B2DDraw support
+ return false;
+}
+
+sal_Bool SvpSalGraphics::drawPolyLineBezier( ULONG,
+ const SalPoint*,
+ const BYTE* )
+{
+ return sal_False;
+}
+
+sal_Bool SvpSalGraphics::drawPolygonBezier( ULONG,
+ const SalPoint*,
+ const BYTE* )
+{
+ return sal_False;
+}
+
+sal_Bool SvpSalGraphics::drawPolyPolygonBezier( sal_uInt32,
+ const sal_uInt32*,
+ const SalPoint* const*,
+ const BYTE* const* )
+{
+ return sal_False;
+}
+
+bool SvpSalGraphics::drawPolyPolygon( const basegfx::B2DPolyPolygon&, double /*fTransparency*/ )
+{
+ // TODO: maybe BaseBmp can draw B2DPolyPolygons directly
+ return false;
+}
+
+void SvpSalGraphics::copyArea( long nDestX,
+ long nDestY,
+ long nSrcX,
+ long nSrcY,
+ long nSrcWidth,
+ long nSrcHeight,
+ USHORT /*nFlags*/ )
+{
+ B2IRange aSrcRect( nSrcX, nSrcY, nSrcX+nSrcWidth, nSrcY+nSrcHeight );
+ B2IRange aDestRect( nDestX, nDestY, nDestX+nSrcWidth, nDestY+nSrcHeight );
+ m_aDevice->drawBitmap( m_aOrigDevice, aSrcRect, aDestRect, DrawMode_PAINT, m_aClipMap );
+ dbgOut( m_aDevice );
+}
+
+void SvpSalGraphics::copyBits( const SalTwoRect* pPosAry,
+ SalGraphics* pSrcGraphics )
+{
+ SvpSalGraphics* pSrc = pSrcGraphics ?
+ static_cast<SvpSalGraphics*>(pSrcGraphics) : this;
+ B2IRange aSrcRect( pPosAry->mnSrcX, pPosAry->mnSrcY,
+ pPosAry->mnSrcX+pPosAry->mnSrcWidth,
+ pPosAry->mnSrcY+pPosAry->mnSrcHeight );
+ B2IRange aDestRect( pPosAry->mnDestX, pPosAry->mnDestY,
+ pPosAry->mnDestX+pPosAry->mnDestWidth,
+ pPosAry->mnDestY+pPosAry->mnDestHeight );
+ m_aDevice->drawBitmap( pSrc->m_aOrigDevice, aSrcRect, aDestRect, DrawMode_PAINT, m_aClipMap );
+ dbgOut( m_aDevice );
+}
+
+void SvpSalGraphics::drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap )
+{
+ const SvpSalBitmap& rSrc = static_cast<const SvpSalBitmap&>(rSalBitmap);
+ B2IRange aSrcRect( pPosAry->mnSrcX, pPosAry->mnSrcY,
+ pPosAry->mnSrcX+pPosAry->mnSrcWidth,
+ pPosAry->mnSrcY+pPosAry->mnSrcHeight );
+ B2IRange aDestRect( pPosAry->mnDestX, pPosAry->mnDestY,
+ pPosAry->mnDestX+pPosAry->mnDestWidth,
+ pPosAry->mnDestY+pPosAry->mnDestHeight );
+ m_aDevice->drawBitmap( rSrc.getBitmap(), aSrcRect, aDestRect, DrawMode_PAINT, m_aClipMap );
+ dbgOut( m_aDevice );
+}
+
+void SvpSalGraphics::drawBitmap( const SalTwoRect*,
+ const SalBitmap&,
+ SalColor )
+{
+ // SNI, as in X11 plugin
+}
+
+void SvpSalGraphics::drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ const SalBitmap& rTransparentBitmap )
+{
+ const SvpSalBitmap& rSrc = static_cast<const SvpSalBitmap&>(rSalBitmap);
+ const SvpSalBitmap& rSrcTrans = static_cast<const SvpSalBitmap&>(rTransparentBitmap);
+ B2IRange aSrcRect( pPosAry->mnSrcX, pPosAry->mnSrcY,
+ pPosAry->mnSrcX+pPosAry->mnSrcWidth,
+ pPosAry->mnSrcY+pPosAry->mnSrcHeight );
+ B2IRange aDestRect( pPosAry->mnDestX, pPosAry->mnDestY,
+ pPosAry->mnDestX+pPosAry->mnDestWidth,
+ pPosAry->mnDestY+pPosAry->mnDestHeight );
+ m_aDevice->drawMaskedBitmap( rSrc.getBitmap(), rSrcTrans.getBitmap(), aSrcRect, aDestRect, DrawMode_PAINT, m_aClipMap );
+ dbgOut( m_aDevice );
+}
+
+void SvpSalGraphics::drawMask( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ SalColor nMaskColor )
+{
+ const SvpSalBitmap& rSrc = static_cast<const SvpSalBitmap&>(rSalBitmap);
+ B2IRange aSrcRect( pPosAry->mnSrcX, pPosAry->mnSrcY,
+ pPosAry->mnSrcX+pPosAry->mnSrcWidth,
+ pPosAry->mnSrcY+pPosAry->mnSrcHeight );
+ B2IPoint aDestPoint( pPosAry->mnDestX, pPosAry->mnDestY );
+
+ // BitmapDevice::drawMaskedColor works with 0==transparent,
+ // 255==opaque. drawMask() semantic is the other way
+ // around. Therefore, invert mask.
+ BitmapDeviceSharedPtr aCopy =
+ cloneBitmapDevice( B2IVector( pPosAry->mnSrcWidth, pPosAry->mnSrcHeight ),
+ rSrc.getBitmap() );
+ basebmp::Color aBgColor( COL_WHITE );
+ aCopy->clear(aBgColor);
+ basebmp::Color aFgColor( COL_BLACK );
+ aCopy->drawMaskedColor( aFgColor, rSrc.getBitmap(), aSrcRect, B2IPoint() );
+
+ basebmp::Color aColor( nMaskColor );
+ B2IRange aSrcRect2( 0, 0, pPosAry->mnSrcWidth, pPosAry->mnSrcHeight );
+ m_aDevice->drawMaskedColor( aColor, aCopy, aSrcRect, aDestPoint, m_aClipMap );
+ dbgOut( m_aDevice );
+}
+
+SalBitmap* SvpSalGraphics::getBitmap( long nX, long nY, long nWidth, long nHeight )
+{
+ BitmapDeviceSharedPtr aCopy =
+ cloneBitmapDevice( B2IVector( nWidth, nHeight ),
+ m_aDevice );
+ B2IRange aSrcRect( nX, nY, nX+nWidth, nY+nHeight );
+ B2IRange aDestRect( 0, 0, nWidth, nHeight );
+ aCopy->drawBitmap( m_aOrigDevice, aSrcRect, aDestRect, DrawMode_PAINT );
+
+ SvpSalBitmap* pBitmap = new SvpSalBitmap();
+ pBitmap->setBitmap( aCopy );
+ return pBitmap;
+}
+
+SalColor SvpSalGraphics::getPixel( long nX, long nY )
+{
+ basebmp::Color aColor( m_aDevice->getPixel( B2IPoint( nX, nY ) ) );
+ return aColor.toInt32();
+}
+
+void SvpSalGraphics::invert( long nX, long nY, long nWidth, long nHeight, SalInvert /*nFlags*/ )
+{
+ // FIXME: handle SAL_INVERT_50 and SAL_INVERT_TRACKFRAME
+ B2DPolygon aRect = tools::createPolygonFromRect( B2DRectangle( nX, nY, nX+nWidth, nY+nHeight ) );
+ B2DPolyPolygon aPolyPoly( aRect );
+ m_aDevice->fillPolyPolygon( aPolyPoly, basebmp::Color( 0xffffff ), DrawMode_XOR, m_aClipMap );
+ dbgOut( m_aDevice );
+}
+
+void SvpSalGraphics::invert( ULONG nPoints, const SalPoint* pPtAry, SalInvert /*nFlags*/ )
+{
+ // FIXME: handle SAL_INVERT_50 and SAL_INVERT_TRACKFRAME
+ B2DPolygon aPoly;
+ aPoly.append( B2DPoint( pPtAry->mnX, pPtAry->mnY ), nPoints );
+ for( ULONG i = 1; i < nPoints; i++ )
+ aPoly.setB2DPoint( i, B2DPoint( pPtAry[i].mnX, pPtAry[i].mnY ) );
+ aPoly.setClosed( true );
+ m_aDevice->fillPolyPolygon( B2DPolyPolygon(aPoly), basebmp::Color( 0xffffff ), DrawMode_XOR, m_aClipMap );
+ dbgOut( m_aDevice );
+}
+
+BOOL SvpSalGraphics::drawEPS( long, long, long, long, void*, ULONG )
+{
+ return FALSE;
+}
+
+SystemFontData SvpSalGraphics::GetSysFontData( int nFallbacklevel ) const
+{
+ SystemFontData aSysFontData;
+
+ if (nFallbacklevel >= MAX_FALLBACK) nFallbacklevel = MAX_FALLBACK - 1;
+ if (nFallbacklevel < 0 ) nFallbacklevel = 0;
+
+ aSysFontData.nSize = sizeof( SystemFontData );
+ aSysFontData.nFontId = 0;
+ aSysFontData.nFontFlags = 0;
+ aSysFontData.bFakeBold = false;
+ aSysFontData.bFakeItalic = false;
+ aSysFontData.bAntialias = true;
+ return aSysFontData;
+}
+
+SystemGraphicsData SvpSalGraphics::GetGraphicsData() const
+{
+ SystemGraphicsData aRes;
+ aRes.nSize = sizeof(aRes);
+ aRes.hDrawable = 0;
+ aRes.pRenderFormat = 0;
+ return aRes;
+}
+
+bool SvpSalGraphics::supportsOperation( OutDevSupportType ) const
+{
+ return false;
+}
+
diff --git a/vcl/unx/headless/svpgdi.hxx b/vcl/unx/headless/svpgdi.hxx
new file mode 100644
index 000000000000..ca1af87f8862
--- /dev/null
+++ b/vcl/unx/headless/svpgdi.hxx
@@ -0,0 +1,173 @@
+/*************************************************************************
+ *
+ * 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 _SVP_SVPGDI_HXX
+
+#include <vcl/salgdi.hxx>
+#include <vcl/sallayout.hxx>
+#include <basebmp/bitmapdevice.hxx>
+#include <basebmp/color.hxx>
+
+class ServerFont;
+
+class SvpSalGraphics : public SalGraphics
+{
+ basebmp::BitmapDeviceSharedPtr m_aDevice;
+ basebmp::BitmapDeviceSharedPtr m_aOrigDevice;
+ basebmp::BitmapDeviceSharedPtr m_aClipMap;
+
+ bool m_bUseLineColor;
+ basebmp::Color m_aLineColor;
+ bool m_bUseFillColor;
+ basebmp::Color m_aFillColor;
+ basebmp::Color m_aTextColor;
+
+ basebmp::DrawMode m_aDrawMode;
+
+ ServerFont* m_pServerFont[ MAX_FALLBACK ];
+ sal_uInt32 m_eTextFmt;
+
+protected:
+ virtual bool drawAlphaBitmap( const SalTwoRect&, const SalBitmap& rSourceBitmap, const SalBitmap& rAlphaBitmap );
+ virtual bool drawAlphaRect( long nX, long nY, long nWidth, long nHeight, sal_uInt8 nTransparency );
+
+public:
+ SvpSalGraphics();
+ virtual ~SvpSalGraphics();
+
+ const basebmp::BitmapDeviceSharedPtr& getDevice() const { return m_aDevice; }
+ void setDevice( basebmp::BitmapDeviceSharedPtr& rDevice );
+
+ // overload all pure virtual methods
+ virtual void GetResolution( sal_Int32& rDPIX, sal_Int32& rDPIY );
+ virtual USHORT GetBitCount();
+ virtual long GetGraphicsWidth() const;
+
+ virtual void ResetClipRegion();
+ virtual void BeginSetClipRegion( ULONG nCount );
+ virtual BOOL unionClipRegion( long nX, long nY, long nWidth, long nHeight );
+ virtual bool unionClipRegion( const ::basegfx::B2DPolyPolygon& );
+ virtual void EndSetClipRegion();
+
+ virtual void SetLineColor();
+ virtual void SetLineColor( SalColor nSalColor );
+ virtual void SetFillColor();
+
+ virtual void SetFillColor( SalColor nSalColor );
+
+ virtual void SetXORMode( bool bSet, bool );
+
+ virtual void SetROPLineColor( SalROPColor nROPColor );
+ virtual void SetROPFillColor( SalROPColor nROPColor );
+
+ virtual void SetTextColor( SalColor nSalColor );
+ virtual USHORT SetFont( ImplFontSelectData*, int nFallbackLevel );
+ virtual void GetFontMetric( ImplFontMetricData* );
+ virtual ULONG GetKernPairs( ULONG nPairs, ImplKernPairData* pKernPairs );
+ virtual ImplFontCharMap* GetImplFontCharMap() const;
+ virtual void GetDevFontList( ImplDevFontList* );
+ virtual void GetDevFontSubstList( OutputDevice* );
+ virtual bool AddTempDevFont( ImplDevFontList*, const String& rFileURL, const String& rFontName );
+ virtual BOOL CreateFontSubset( const rtl::OUString& rToFile,
+ const ImplFontData*,
+ sal_Int32* pGlyphIDs,
+ sal_uInt8* pEncoding,
+ sal_Int32* pWidths,
+ int nGlyphs,
+ FontSubsetInfo& rInfo
+ );
+ virtual const Ucs2SIntMap* GetFontEncodingVector( const ImplFontData*, const Ucs2OStrMap** ppNonEncoded );
+ virtual const void* GetEmbedFontData( const ImplFontData*,
+ const sal_Ucs* pUnicodes,
+ sal_Int32* pWidths,
+ FontSubsetInfo& rInfo,
+ long* pDataLen );
+ virtual void FreeEmbedFontData( const void* pData, long nDataLen );
+ virtual void GetGlyphWidths( const ImplFontData*,
+ bool bVertical,
+ Int32Vector& rWidths,
+ Ucs2UIntMap& rUnicodeEnc );
+ virtual BOOL GetGlyphBoundRect( long nIndex, Rectangle& );
+ virtual BOOL GetGlyphOutline( long nIndex, ::basegfx::B2DPolyPolygon& );
+ virtual SalLayout* GetTextLayout( ImplLayoutArgs&, int nFallbackLevel );
+ virtual void DrawServerFontLayout( const ServerFontLayout& );
+ virtual bool supportsOperation( OutDevSupportType ) const;
+ virtual void drawPixel( long nX, long nY );
+ virtual void drawPixel( long nX, long nY, SalColor nSalColor );
+ virtual void drawLine( long nX1, long nY1, long nX2, long nY2 );
+ virtual void drawRect( long nX, long nY, long nWidth, long nHeight );
+ virtual bool drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double fTransparency );
+ virtual bool drawPolyLine( const ::basegfx::B2DPolygon&, double fTransparency, const ::basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin );
+ virtual void drawPolyLine( ULONG nPoints, const SalPoint* pPtAry );
+ virtual void drawPolygon( ULONG nPoints, const SalPoint* pPtAry );
+ virtual void drawPolyPolygon( sal_uInt32 nPoly,
+ const sal_uInt32* pPoints,
+ PCONSTSALPOINT* pPtAry );
+ virtual sal_Bool drawPolyLineBezier( ULONG nPoints,
+ const SalPoint* pPtAry,
+ const BYTE* pFlgAry );
+ virtual sal_Bool drawPolygonBezier( ULONG nPoints,
+ const SalPoint* pPtAry,
+ const BYTE* pFlgAry );
+ virtual sal_Bool drawPolyPolygonBezier( sal_uInt32 nPoly,
+ const sal_uInt32* pPoints,
+ const SalPoint* const* pPtAry,
+ const BYTE* const* pFlgAry );
+
+ virtual void copyArea( long nDestX,
+ long nDestY,
+ long nSrcX,
+ long nSrcY,
+ long nSrcWidth,
+ long nSrcHeight,
+ USHORT nFlags );
+ virtual void copyBits( const SalTwoRect* pPosAry,
+ SalGraphics* pSrcGraphics );
+ virtual void drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap );
+ virtual void drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ SalColor nTransparentColor );
+ virtual void drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ const SalBitmap& rTransparentBitmap );
+ virtual void drawMask( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ SalColor nMaskColor );
+ virtual SalBitmap* getBitmap( long nX, long nY, long nWidth, long nHeight );
+ virtual SalColor getPixel( long nX, long nY );
+ virtual void invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags );
+ virtual void invert( ULONG nPoints, const SalPoint* pPtAry, SalInvert nFlags );
+
+ virtual BOOL drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, ULONG nSize );
+
+ virtual SystemGraphicsData GetGraphicsData() const;
+ virtual SystemFontData GetSysFontData( int nFallbacklevel ) const;
+};
+
+#endif
+
diff --git a/vcl/unx/headless/svpinst.cxx b/vcl/unx/headless/svpinst.cxx
new file mode 100644
index 000000000000..466b56868900
--- /dev/null
+++ b/vcl/unx/headless/svpinst.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.
+ *
+ ************************************************************************/
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/poll.h>
+
+#include "svpinst.hxx"
+#include "svpframe.hxx"
+#include "svpdummies.hxx"
+#include "svpvd.hxx"
+#include "svpbmp.hxx"
+
+#include <vcl/salframe.hxx>
+#include <vcl/svdata.hxx>
+#include <vcl/salatype.hxx>
+#include <vcl/saldatabasic.hxx>
+#include <sal/types.h>
+
+// plugin factory function
+extern "C"
+{
+ SAL_DLLPUBLIC_EXPORT SalInstance* create_SalInstance()
+ {
+ SvpSalInstance* pInstance = new SvpSalInstance();
+ SalData* pSalData = new SalData();
+ pSalData->m_pInstance = pInstance;
+ SetSalData( pSalData );
+ return pInstance;
+ }
+}
+
+bool SvpSalInstance::isFrameAlive( const SalFrame* pFrame ) const
+{
+ for( std::list< SalFrame* >::const_iterator it = m_aFrames.begin();
+ it != m_aFrames.end(); ++it )
+ {
+ if( *it == pFrame )
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+SvpSalInstance* SvpSalInstance::s_pDefaultInstance = NULL;
+
+SvpSalInstance::SvpSalInstance()
+{
+ m_aTimeout.tv_sec = 0;
+ m_aTimeout.tv_usec = 0;
+ m_nTimeoutMS = 0;
+
+ m_pTimeoutFDS[0] = m_pTimeoutFDS[1] = -1;
+ if (pipe (m_pTimeoutFDS) != -1)
+ {
+ // initialize 'wakeup' pipe.
+ int flags;
+
+ // set close-on-exec descriptor flag.
+ if ((flags = fcntl (m_pTimeoutFDS[0], F_GETFD)) != -1)
+ {
+ flags |= FD_CLOEXEC;
+ fcntl (m_pTimeoutFDS[0], F_SETFD, flags);
+ }
+ if ((flags = fcntl (m_pTimeoutFDS[1], F_GETFD)) != -1)
+ {
+ flags |= FD_CLOEXEC;
+ fcntl (m_pTimeoutFDS[1], F_SETFD, flags);
+ }
+
+ // set non-blocking I/O flag.
+ if ((flags = fcntl (m_pTimeoutFDS[0], F_GETFL)) != -1)
+ {
+ flags |= O_NONBLOCK;
+ fcntl (m_pTimeoutFDS[0], F_SETFL, flags);
+ }
+ if ((flags = fcntl (m_pTimeoutFDS[1], F_GETFL)) != -1)
+ {
+ flags |= O_NONBLOCK;
+ fcntl (m_pTimeoutFDS[1], F_SETFL, flags);
+ }
+ }
+ m_aEventGuard = osl_createMutex();
+ if( s_pDefaultInstance == NULL )
+ s_pDefaultInstance = this;
+}
+
+SvpSalInstance::~SvpSalInstance()
+{
+ if( s_pDefaultInstance == this )
+ s_pDefaultInstance = NULL;
+
+ // close 'wakeup' pipe.
+ close (m_pTimeoutFDS[0]);
+ close (m_pTimeoutFDS[1]);
+ osl_destroyMutex( m_aEventGuard );
+}
+
+void SvpSalInstance::PostEvent( const SalFrame* pFrame, void* pData, USHORT nEvent )
+{
+ if( osl_acquireMutex( m_aEventGuard ) )
+ {
+ m_aUserEvents.push_back( SalUserEvent( pFrame, pData, nEvent ) );
+ osl_releaseMutex( m_aEventGuard );
+ }
+ Wakeup();
+}
+
+void SvpSalInstance::CancelEvent( const SalFrame* pFrame, void* pData, USHORT nEvent )
+{
+ if( osl_acquireMutex( m_aEventGuard ) )
+ {
+ if( ! m_aUserEvents.empty() )
+ {
+ std::list< SalUserEvent >::iterator it = m_aUserEvents.begin();
+ do
+ {
+ if( it->m_pFrame == pFrame &&
+ it->m_pData == pData &&
+ it->m_nEvent == nEvent )
+ {
+ it = m_aUserEvents.erase( it );
+ }
+ else
+ ++it;
+ } while( it != m_aUserEvents.end() );
+ }
+ osl_releaseMutex( m_aEventGuard );
+ }
+}
+
+void SvpSalInstance::deregisterFrame( SalFrame* pFrame )
+{
+ m_aFrames.remove( pFrame );
+
+ if( osl_acquireMutex( m_aEventGuard ) )
+ {
+ // cancel outstanding events for this frame
+ if( ! m_aUserEvents.empty() )
+ {
+ std::list< SalUserEvent >::iterator it = m_aUserEvents.begin();
+ do
+ {
+ if( it->m_pFrame == pFrame )
+ {
+ it = m_aUserEvents.erase( it );
+ }
+ else
+ ++it;
+ } while( it != m_aUserEvents.end() );
+ }
+ osl_releaseMutex( m_aEventGuard );
+ }
+}
+
+void SvpSalInstance::Wakeup()
+{
+ write (m_pTimeoutFDS[1], "", 1);
+}
+
+
+// -=-= timeval =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+inline int operator >= ( const timeval &t1, const timeval &t2 )
+{
+ if( t1.tv_sec == t2.tv_sec )
+ return t1.tv_usec >= t2.tv_usec;
+ return t1.tv_sec > t2.tv_sec;
+}
+inline timeval &operator += ( timeval &t1, ULONG t2 )
+{
+ t1.tv_sec += t2 / 1000;
+ t1.tv_usec += t2 ? (t2 % 1000) * 1000 : 500;
+ if( t1.tv_usec > 1000000 )
+ {
+ t1.tv_sec++;
+ t1.tv_usec -= 1000000;
+ }
+ return t1;
+}
+inline int operator > ( const timeval &t1, const timeval &t2 )
+{
+ if( t1.tv_sec == t2.tv_sec )
+ return t1.tv_usec > t2.tv_usec;
+ return t1.tv_sec > t2.tv_sec;
+}
+
+bool SvpSalInstance::CheckTimeout( bool bExecuteTimers )
+{
+ bool bRet = false;
+ if( m_aTimeout.tv_sec ) // timer is started
+ {
+ timeval aTimeOfDay;
+ gettimeofday( &aTimeOfDay, 0 );
+ if( aTimeOfDay >= m_aTimeout )
+ {
+ bRet = true;
+ if( bExecuteTimers )
+ {
+ // timed out, update timeout
+ m_aTimeout = aTimeOfDay;
+ m_aTimeout += m_nTimeoutMS;
+ // notify
+ ImplSVData* pSVData = ImplGetSVData();
+ if( pSVData->mpSalTimer )
+ pSVData->mpSalTimer->CallCallback();
+ }
+ }
+ }
+ return bRet;
+}
+
+SalFrame* SvpSalInstance::CreateChildFrame( SystemParentData* pParent, ULONG nStyle )
+{
+ return new SvpSalFrame( this, NULL, nStyle, pParent );
+}
+
+SalFrame* SvpSalInstance::CreateFrame( SalFrame* pParent, ULONG nStyle )
+{
+ return new SvpSalFrame( this, pParent, nStyle );
+}
+
+void SvpSalInstance::DestroyFrame( SalFrame* pFrame )
+{
+ delete pFrame;
+}
+
+SalObject* SvpSalInstance::CreateObject( SalFrame*, SystemWindowData*, BOOL )
+{
+ return new SvpSalObject();
+}
+
+void SvpSalInstance::DestroyObject( SalObject* pObject )
+{
+ delete pObject;
+}
+
+SalVirtualDevice* SvpSalInstance::CreateVirtualDevice( SalGraphics*,
+ long nDX, long nDY,
+ USHORT nBitCount, const SystemGraphicsData* )
+{
+ SvpSalVirtualDevice* pNew = new SvpSalVirtualDevice( nBitCount );
+ pNew->SetSize( nDX, nDY );
+ return pNew;
+}
+
+void SvpSalInstance::DestroyVirtualDevice( SalVirtualDevice* pDevice )
+{
+ delete pDevice;
+}
+
+SalTimer* SvpSalInstance::CreateSalTimer()
+{
+ return new SvpSalTimer( this );
+}
+
+SalI18NImeStatus* SvpSalInstance::CreateI18NImeStatus()
+{
+ return new SvpImeStatus();
+}
+
+SalSystem* SvpSalInstance::CreateSalSystem()
+{
+ return new SvpSalSystem();
+}
+
+SalBitmap* SvpSalInstance::CreateSalBitmap()
+{
+ return new SvpSalBitmap();
+}
+
+vos::IMutex* SvpSalInstance::GetYieldMutex()
+{
+ return &m_aYieldMutex;
+}
+
+ULONG SvpSalInstance::ReleaseYieldMutex()
+{
+ if ( m_aYieldMutex.GetThreadId() ==
+ NAMESPACE_VOS(OThread)::getCurrentIdentifier() )
+ {
+ ULONG nCount = m_aYieldMutex.GetAcquireCount();
+ ULONG n = nCount;
+ while ( n )
+ {
+ m_aYieldMutex.release();
+ n--;
+ }
+
+ return nCount;
+ }
+ else
+ return 0;
+}
+
+void SvpSalInstance::AcquireYieldMutex( ULONG nCount )
+{
+ while ( nCount )
+ {
+ m_aYieldMutex.acquire();
+ nCount--;
+ }
+}
+
+void SvpSalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents )
+{
+ // first, check for already queued events.
+
+ // release yield mutex
+ std::list< SalUserEvent > aEvents;
+ ULONG nAcquireCount = ReleaseYieldMutex();
+ if( osl_acquireMutex( m_aEventGuard ) )
+ {
+ if( ! m_aUserEvents.empty() )
+ {
+ if( bHandleAllCurrentEvents )
+ {
+ aEvents = m_aUserEvents;
+ m_aUserEvents.clear();
+ }
+ else
+ {
+ aEvents.push_back( m_aUserEvents.front() );
+ m_aUserEvents.pop_front();
+ }
+ }
+ osl_releaseMutex( m_aEventGuard );
+ }
+ // acquire yield mutex again
+ AcquireYieldMutex( nAcquireCount );
+
+ bool bEvent = !aEvents.empty();
+ if( bEvent )
+ {
+ for( std::list<SalUserEvent>::const_iterator it = aEvents.begin(); it != aEvents.end(); ++it )
+ {
+ if ( isFrameAlive( it->m_pFrame ) )
+ {
+ it->m_pFrame->CallCallback( it->m_nEvent, it->m_pData );
+ if( it->m_nEvent == SALEVENT_RESIZE )
+ {
+ // this would be a good time to post a paint
+ const SvpSalFrame* pSvpFrame = static_cast<const SvpSalFrame*>(it->m_pFrame);
+ pSvpFrame->PostPaint();
+ }
+ }
+ }
+ }
+
+ bEvent = CheckTimeout() || bEvent;
+
+ if (bWait && ! bEvent )
+ {
+ int nTimeoutMS = 0;
+ if (m_aTimeout.tv_sec) // Timer is started.
+ {
+ timeval Timeout;
+ // determine remaining timeout.
+ gettimeofday (&Timeout, 0);
+ nTimeoutMS = m_aTimeout.tv_sec*1000 + m_aTimeout.tv_usec/1000
+ - Timeout.tv_sec*1000 - Timeout.tv_usec/1000;
+ if( nTimeoutMS < 0 )
+ nTimeoutMS = 0;
+ }
+ else
+ nTimeoutMS = -1; // wait until something happens
+
+ // release yield mutex
+ nAcquireCount = ReleaseYieldMutex();
+ // poll
+ struct pollfd aPoll;
+ aPoll.fd = m_pTimeoutFDS[0];
+ aPoll.events = POLLIN;
+ aPoll.revents = 0;
+ poll( &aPoll, 1, nTimeoutMS );
+
+ // acquire yield mutex again
+ AcquireYieldMutex( nAcquireCount );
+
+ // clean up pipe
+ if( (aPoll.revents & POLLIN) != 0 )
+ {
+ int buffer;
+ while (read (m_pTimeoutFDS[0], &buffer, sizeof(buffer)) > 0)
+ continue;
+ }
+ }
+}
+
+bool SvpSalInstance::AnyInput( USHORT nType )
+{
+ if( (nType & INPUT_TIMER) != 0 )
+ return CheckTimeout( false );
+ return false;
+}
+
+SalMenu* SvpSalInstance::CreateMenu( BOOL )
+{
+ return NULL;
+}
+
+void SvpSalInstance::DestroyMenu( SalMenu* )
+{
+}
+
+SalMenuItem* SvpSalInstance::CreateMenuItem( const SalItemParams* )
+{
+ return NULL;
+}
+
+void SvpSalInstance::DestroyMenuItem( SalMenuItem* )
+{
+}
+
+SalSession* SvpSalInstance::CreateSalSession()
+{
+ return NULL;
+}
+
+void* SvpSalInstance::GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes )
+{
+ rReturnedBytes = 1;
+ rReturnedType = AsciiCString;
+ return const_cast<char*>("");
+}
+
+// -------------------------------------------------------------------------
+//
+// SalYieldMutex
+//
+// -------------------------------------------------------------------------
+
+SvpSalYieldMutex::SvpSalYieldMutex()
+{
+ mnCount = 0;
+ mnThreadId = 0;
+}
+
+void SvpSalYieldMutex::acquire()
+{
+ OMutex::acquire();
+ mnThreadId = NAMESPACE_VOS(OThread)::getCurrentIdentifier();
+ mnCount++;
+}
+
+void SvpSalYieldMutex::release()
+{
+ if ( mnThreadId == NAMESPACE_VOS(OThread)::getCurrentIdentifier() )
+ {
+ if ( mnCount == 1 )
+ mnThreadId = 0;
+ mnCount--;
+ }
+ OMutex::release();
+}
+
+sal_Bool SvpSalYieldMutex::tryToAcquire()
+{
+ if ( OMutex::tryToAcquire() )
+ {
+ mnThreadId = NAMESPACE_VOS(OThread)::getCurrentIdentifier();
+ mnCount++;
+ return sal_True;
+ }
+ else
+ return sal_False;
+}
+
+// ---------------
+// - SalTimer -
+// ---------------
+
+void SvpSalInstance::StopTimer()
+{
+ m_aTimeout.tv_sec = 0;
+ m_aTimeout.tv_usec = 0;
+ m_nTimeoutMS = 0;
+}
+
+void SvpSalInstance::StartTimer( ULONG nMS )
+{
+ timeval Timeout (m_aTimeout); // previous timeout.
+ gettimeofday (&m_aTimeout, 0);
+
+ m_nTimeoutMS = nMS;
+ m_aTimeout += m_nTimeoutMS;
+
+ if ((Timeout > m_aTimeout) || (Timeout.tv_sec == 0))
+ {
+ // Wakeup from previous timeout (or stopped timer).
+ Wakeup();
+ }
+}
+
+void SvpSalInstance::AddToRecentDocumentList(const rtl::OUString&, const rtl::OUString&)
+{
+}
+
+SvpSalTimer::~SvpSalTimer()
+{
+}
+
+void SvpSalTimer::Stop()
+{
+ m_pInstance->StopTimer();
+}
+
+void SvpSalTimer::Start( ULONG nMS )
+{
+ m_pInstance->StartTimer( nMS );
+}
+
diff --git a/vcl/unx/headless/svpinst.hxx b/vcl/unx/headless/svpinst.hxx
new file mode 100644
index 000000000000..284a2d11cd82
--- /dev/null
+++ b/vcl/unx/headless/svpinst.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SVP_SALINST_HXX
+#define _SVP_SALINST_HXX
+
+#include <vcl/salinst.hxx>
+#include <vcl/salwtype.hxx>
+#include <vcl/saltimer.hxx>
+#include <vos/mutex.hxx>
+#include <vos/thread.hxx>
+
+#include <list>
+
+#include <time.h> // timeval
+
+#define VIRTUAL_DESKTOP_WIDTH 1024
+#define VIRTUAL_DESKTOP_HEIGHT 768
+#define VIRTUAL_DESKTOP_DEPTH 24
+
+// -------------------------------------------------------------------------
+// SalYieldMutex
+// -------------------------------------------------------------------------
+
+class SvpSalYieldMutex : public NAMESPACE_VOS(OMutex)
+{
+protected:
+ ULONG mnCount;
+ NAMESPACE_VOS(OThread)::TThreadIdentifier mnThreadId;
+
+public:
+ SvpSalYieldMutex();
+
+ virtual void acquire();
+ virtual void release();
+ virtual sal_Bool tryToAcquire();
+
+ ULONG GetAcquireCount() const { return mnCount; }
+ NAMESPACE_VOS(OThread)::TThreadIdentifier GetThreadId() const { return mnThreadId; }
+};
+
+// ---------------
+// - SalTimer -
+// ---------------
+class SvpSalInstance;
+class SvpSalTimer : public SalTimer
+{
+ SvpSalInstance* m_pInstance;
+public:
+ SvpSalTimer( SvpSalInstance* pInstance ) : m_pInstance( pInstance ) {}
+ virtual ~SvpSalTimer();
+
+ // overload all pure virtual methods
+ virtual void Start( ULONG nMS );
+ virtual void Stop();
+};
+
+// ---------------
+// - SalInstance -
+// ---------------
+class SvpSalFrame;
+class SvpSalInstance : public SalInstance
+{
+ timeval m_aTimeout;
+ ULONG m_nTimeoutMS;
+ int m_pTimeoutFDS[2];
+ SvpSalYieldMutex m_aYieldMutex;
+
+ // internal event queue
+ struct SalUserEvent
+ {
+ const SalFrame* m_pFrame;
+ void* m_pData;
+ USHORT m_nEvent;
+
+ SalUserEvent( const SalFrame* pFrame, void* pData, USHORT nEvent = SALEVENT_USEREVENT )
+ : m_pFrame( pFrame ),
+ m_pData( pData ),
+ m_nEvent( nEvent )
+ {}
+ };
+
+ oslMutex m_aEventGuard;
+ std::list< SalUserEvent > m_aUserEvents;
+
+ std::list< SalFrame* > m_aFrames;
+
+ bool isFrameAlive( const SalFrame* pFrame ) const;
+
+public:
+ static SvpSalInstance* s_pDefaultInstance;
+
+ SvpSalInstance();
+ virtual ~SvpSalInstance();
+
+ void PostEvent( const SalFrame* pFrame, void* pData, USHORT nEvent );
+ void CancelEvent( const SalFrame* pFrame, void* pData, USHORT nEvent );
+
+ void StartTimer( ULONG nMS );
+ void StopTimer();
+ void Wakeup();
+
+ void registerFrame( SalFrame* pFrame ) { m_aFrames.push_back( pFrame ); }
+ void deregisterFrame( SalFrame* pFrame );
+ const std::list< SalFrame* >& getFrames() const { return m_aFrames; }
+
+ bool CheckTimeout( bool bExecuteTimers = true );
+
+ // Frame
+ virtual SalFrame* CreateChildFrame( SystemParentData* pParent, ULONG nStyle );
+ virtual SalFrame* CreateFrame( SalFrame* pParent, ULONG nStyle );
+ virtual void DestroyFrame( SalFrame* pFrame );
+
+ // Object (System Child Window)
+ virtual SalObject* CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, BOOL bShow = TRUE );
+ virtual void DestroyObject( SalObject* pObject );
+
+ // VirtualDevice
+ // nDX and nDY in Pixel
+ // nBitCount: 0 == Default(=as window) / 1 == Mono
+ // pData allows for using a system dependent graphics or device context
+ virtual SalVirtualDevice* CreateVirtualDevice( SalGraphics* pGraphics,
+ long nDX, long nDY,
+ USHORT nBitCount, const SystemGraphicsData *pData = NULL );
+ virtual void DestroyVirtualDevice( SalVirtualDevice* pDevice );
+
+ // Printer
+ // pSetupData->mpDriverData can be 0
+ // pSetupData must be updatet with the current
+ // JobSetup
+ virtual SalInfoPrinter* CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
+ ImplJobSetup* pSetupData );
+ virtual void DestroyInfoPrinter( SalInfoPrinter* pPrinter );
+ virtual SalPrinter* CreatePrinter( SalInfoPrinter* pInfoPrinter );
+ virtual void DestroyPrinter( SalPrinter* pPrinter );
+
+ virtual void GetPrinterQueueInfo( ImplPrnQueueList* pList );
+ virtual void GetPrinterQueueState( SalPrinterQueueInfo* pInfo );
+ virtual void DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo );
+ virtual String GetDefaultPrinter();
+
+ // SalTimer
+ virtual SalTimer* CreateSalTimer();
+ // SalI18NImeStatus
+ virtual SalI18NImeStatus* CreateI18NImeStatus();
+ // SalSystem
+ virtual SalSystem* CreateSalSystem();
+ // SalBitmap
+ virtual SalBitmap* CreateSalBitmap();
+
+ // YieldMutex
+ virtual vos::IMutex* GetYieldMutex();
+ virtual ULONG ReleaseYieldMutex();
+ virtual void AcquireYieldMutex( ULONG nCount );
+
+ // wait next event and dispatch
+ // must returned by UserEvent (SalFrame::PostEvent)
+ // and timer
+ virtual void Yield( bool bWait, bool bHandleAllCurrentEvents );
+ virtual bool AnyInput( USHORT nType );
+
+ // Menues
+ virtual SalMenu* CreateMenu( BOOL bMenuBar );
+ virtual void DestroyMenu( SalMenu* pMenu);
+ virtual SalMenuItem* CreateMenuItem( const SalItemParams* pItemData );
+ virtual void DestroyMenuItem( SalMenuItem* pItem );
+
+ // may return NULL to disable session management
+ virtual SalSession* CreateSalSession();
+
+ virtual void* GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes );
+
+ virtual void AddToRecentDocumentList(const rtl::OUString& rFileUrl, const rtl::OUString& rMimeType);
+};
+
+#endif // _SV_SALINST_HXX
diff --git a/vcl/unx/headless/svpprn.cxx b/vcl/unx/headless/svpprn.cxx
new file mode 100644
index 000000000000..5b461bb996ef
--- /dev/null
+++ b/vcl/unx/headless/svpprn.cxx
@@ -0,0 +1,1075 @@
+/*************************************************************************
+ *
+ * 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/jobset.h"
+#include "vcl/print.h"
+#include "vcl/salptype.hxx"
+#include "vcl/timer.hxx"
+#include "vcl/printerinfomanager.hxx"
+
+#include "svpprn.hxx"
+#include "svppspgraphics.hxx"
+#include "svpinst.hxx"
+
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+using namespace psp;
+using namespace rtl;
+
+/*
+ * static helpers
+ */
+
+static String getPdfDir( const PrinterInfo& rInfo )
+{
+ String aDir;
+ sal_Int32 nIndex = 0;
+ while( nIndex != -1 )
+ {
+ OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
+ if( ! aToken.compareToAscii( "pdf=", 4 ) )
+ {
+ sal_Int32 nPos = 0;
+ aDir = aToken.getToken( 1, '=', nPos );
+ if( ! aDir.Len() )
+ aDir = String( ByteString( getenv( "HOME" ) ), osl_getThreadTextEncoding() );
+ break;
+ }
+ }
+ return aDir;
+}
+
+inline int PtTo10Mu( int nPoints ) { return (int)((((double)nPoints)*35.27777778)+0.5); }
+
+inline int TenMuToPt( int nUnits ) { return (int)((((double)nUnits)/35.27777778)+0.5); }
+
+static void copyJobDataToJobSetup( ImplJobSetup* pJobSetup, JobData& rData )
+{
+ pJobSetup->meOrientation = (Orientation)(rData.m_eOrientation == orientation::Landscape ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT);
+
+ // copy page size
+ String aPaper;
+ int width, height;
+
+ rData.m_aContext.getPageSize( aPaper, width, height );
+ pJobSetup->mePaperFormat = PaperInfo::fromPSName(OUStringToOString( aPaper, RTL_TEXTENCODING_ISO_8859_1 ));
+ pJobSetup->mnPaperWidth = 0;
+ pJobSetup->mnPaperHeight = 0;
+ if( pJobSetup->mePaperFormat == PAPER_USER )
+ {
+ // transform to 100dth mm
+ width = PtTo10Mu( width );
+ height = PtTo10Mu( height );
+
+ if( rData.m_eOrientation == psp::orientation::Portrait )
+ {
+ pJobSetup->mnPaperWidth = width;
+ pJobSetup->mnPaperHeight= height;
+ }
+ else
+ {
+ pJobSetup->mnPaperWidth = height;
+ pJobSetup->mnPaperHeight= width;
+ }
+ }
+
+ // copy input slot
+ const PPDKey* pKey = NULL;
+ const PPDValue* pValue = NULL;
+
+ pJobSetup->mnPaperBin = 0xffff;
+ if( rData.m_pParser )
+ pKey = rData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) );
+ if( pKey )
+ pValue = rData.m_aContext.getValue( pKey );
+ if( pKey && pValue )
+ {
+ for( pJobSetup->mnPaperBin = 0;
+ pValue != pKey->getValue( pJobSetup->mnPaperBin ) &&
+ pJobSetup->mnPaperBin < pKey->countValues();
+ pJobSetup->mnPaperBin++ )
+ ;
+ if( pJobSetup->mnPaperBin >= pKey->countValues() || pValue == pKey->getDefaultValue() )
+ pJobSetup->mnPaperBin = 0xffff;
+ }
+
+ // copy duplex
+ pKey = NULL;
+ pValue = NULL;
+
+ pJobSetup->meDuplexMode = DUPLEX_UNKNOWN;
+ if( rData.m_pParser )
+ pKey = rData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) );
+ if( pKey )
+ pValue = rData.m_aContext.getValue( pKey );
+ if( pKey && pValue )
+ {
+ if( pValue->m_aOption.EqualsIgnoreCaseAscii( "None" ) ||
+ pValue->m_aOption.EqualsIgnoreCaseAscii( "Simplex", 0, 7 )
+ )
+ {
+ pJobSetup->meDuplexMode = DUPLEX_OFF;
+ }
+ else if( pValue->m_aOption.EqualsIgnoreCaseAscii( "DuplexNoTumble" ) )
+ {
+ pJobSetup->meDuplexMode = DUPLEX_LONGEDGE;
+ }
+ else if( pValue->m_aOption.EqualsIgnoreCaseAscii( "DuplexTumble" ) )
+ {
+ pJobSetup->meDuplexMode = DUPLEX_SHORTEDGE;
+ }
+ }
+
+ // copy the whole context
+ if( pJobSetup->mpDriverData )
+ rtl_freeMemory( pJobSetup->mpDriverData );
+
+ int nBytes;
+ void* pBuffer = NULL;
+ if( rData.getStreamBuffer( pBuffer, nBytes ) )
+ {
+ pJobSetup->mnDriverDataLen = nBytes;
+ pJobSetup->mpDriverData = (BYTE*)pBuffer;
+ }
+ else
+ {
+ pJobSetup->mnDriverDataLen = 0;
+ pJobSetup->mpDriverData = NULL;
+ }
+}
+
+static bool passFileToCommandLine( const String& rFilename, const String& rCommandLine, bool bRemoveFile = true )
+{
+ bool bSuccess = false;
+
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ ByteString aCmdLine( rCommandLine, aEncoding );
+ ByteString aFilename( rFilename, aEncoding );
+
+ bool bPipe = aCmdLine.Search( "(TMP)" ) != STRING_NOTFOUND ? false : true;
+
+ // setup command line for exec
+ if( ! bPipe )
+ while( aCmdLine.SearchAndReplace( "(TMP)", aFilename ) != STRING_NOTFOUND )
+ ;
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%s commandline: \"%s\"\n",
+ bPipe ? "piping to" : "executing",
+ aCmdLine.GetBuffer() );
+ struct stat aStat;
+ if( stat( aFilename.GetBuffer(), &aStat ) )
+ fprintf( stderr, "stat( %s ) failed\n", aFilename.GetBuffer() );
+ fprintf( stderr, "Tmp file %s has modes: 0%03lo\n", aFilename.GetBuffer(), (long)aStat.st_mode );
+#endif
+ const char* argv[4];
+ if( ! ( argv[ 0 ] = getenv( "SHELL" ) ) )
+ argv[ 0 ] = "/bin/sh";
+ argv[ 1 ] = "-c";
+ argv[ 2 ] = aCmdLine.GetBuffer();
+ argv[ 3 ] = 0;
+
+ bool bHavePipes = false;
+ int pid, fd[2];
+
+ if( bPipe )
+ bHavePipes = pipe( fd ) ? false : true;
+ if( ( pid = fork() ) > 0 )
+ {
+ if( bPipe && bHavePipes )
+ {
+ close( fd[0] );
+ char aBuffer[ 2048 ];
+ FILE* fp = fopen( aFilename.GetBuffer(), "r" );
+ while( fp && ! feof( fp ) )
+ {
+ int nBytes = fread( aBuffer, 1, sizeof( aBuffer ), fp );
+ if( nBytes )
+ write( fd[ 1 ], aBuffer, nBytes );
+ }
+ fclose( fp );
+ close( fd[ 1 ] );
+ }
+ int status = 0;
+ waitpid( pid, &status, 0 );
+ if( ! status )
+ bSuccess = true;
+ }
+ else if( ! pid )
+ {
+ if( bPipe && bHavePipes )
+ {
+ close( fd[1] );
+ if( fd[0] != STDIN_FILENO ) // not probable, but who knows :)
+ dup2( fd[0], STDIN_FILENO );
+ }
+ execv( argv[0], const_cast<char**>(argv) );
+ fprintf( stderr, "failed to execute \"%s\"\n", aCmdLine.GetBuffer() );
+ _exit( 1 );
+ }
+ else
+ fprintf( stderr, "failed to fork\n" );
+
+ // clean up the mess
+ if( bRemoveFile )
+ unlink( aFilename.GetBuffer() );
+
+ return bSuccess;
+}
+
+static bool sendAFax( const String& rFaxNumber, const String& rFileName, const String& rCommand )
+{
+ std::list< OUString > aFaxNumbers;
+
+ if( ! rFaxNumber.Len() )
+ return false;
+
+ sal_Int32 nIndex = 0;
+ OUString aFaxes( rFaxNumber );
+ OUString aBeginToken( RTL_CONSTASCII_USTRINGPARAM("<Fax#>") );
+ OUString aEndToken( RTL_CONSTASCII_USTRINGPARAM("</Fax#>") );
+ while( nIndex != -1 )
+ {
+ nIndex = aFaxes.indexOf( aBeginToken, nIndex );
+ if( nIndex != -1 )
+ {
+ sal_Int32 nBegin = nIndex + aBeginToken.getLength();
+ nIndex = aFaxes.indexOf( aEndToken, nIndex );
+ if( nIndex != -1 )
+ {
+ aFaxNumbers.push_back( aFaxes.copy( nBegin, nIndex-nBegin ) );
+ nIndex += aEndToken.getLength();
+ }
+ }
+ }
+
+ bool bSuccess = true;
+ if( aFaxNumbers.begin() != aFaxNumbers.end() )
+ {
+ while( aFaxNumbers.begin() != aFaxNumbers.end() && bSuccess )
+ {
+ String aCmdLine( rCommand );
+ String aFaxNumber( aFaxNumbers.front() );
+ aFaxNumbers.pop_front();
+ while( aCmdLine.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "(PHONE)" ) ), aFaxNumber ) != STRING_NOTFOUND )
+ ;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "sending fax to \"%s\"\n", OUStringToOString( aFaxNumber, osl_getThreadTextEncoding() ).getStr() );
+#endif
+ bSuccess = passFileToCommandLine( rFileName, aCmdLine, false );
+ }
+ }
+ else
+ bSuccess = false;
+
+ // clean up temp file
+ unlink( ByteString( rFileName, osl_getThreadTextEncoding() ).GetBuffer() );
+
+ return bSuccess;
+}
+
+static bool createPdf( const String& rToFile, const String& rFromFile, const String& rCommandLine )
+{
+ String aCommandLine( rCommandLine );
+ while( aCommandLine.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "(OUTFILE)" ) ), rToFile ) != STRING_NOTFOUND )
+ ;
+ return passFileToCommandLine( rFromFile, aCommandLine );
+}
+
+/*
+ * SalInstance
+ */
+
+// -----------------------------------------------------------------------
+
+SalInfoPrinter* SvpSalInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
+ ImplJobSetup* pJobSetup )
+{
+ // create and initialize SalInfoPrinter
+ PspSalInfoPrinter* pPrinter = new PspSalInfoPrinter;
+
+ if( pJobSetup )
+ {
+ PrinterInfoManager& rManager( PrinterInfoManager::get() );
+ PrinterInfo aInfo( rManager.getPrinterInfo( pQueueInfo->maPrinterName ) );
+ pPrinter->m_aJobData = aInfo;
+ pPrinter->m_aPrinterGfx.Init( pPrinter->m_aJobData );
+
+ if( pJobSetup->mpDriverData )
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aInfo );
+
+ pJobSetup->mnSystem = JOBSETUP_SYSTEM_UNIX;
+ pJobSetup->maPrinterName = pQueueInfo->maPrinterName;
+ pJobSetup->maDriver = aInfo.m_aDriverName;
+ copyJobDataToJobSetup( pJobSetup, aInfo );
+
+ // set/clear backwards compatibility flag
+ bool bStrictSO52Compatibility = false;
+ std::hash_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it =
+ pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StrictSO52Compatibility" ) ) );
+ if( compat_it != pJobSetup->maValueMap.end() )
+ {
+ if( compat_it->second.equalsIgnoreAsciiCaseAscii( "true" ) )
+ bStrictSO52Compatibility = true;
+ }
+ pPrinter->m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility );
+ }
+
+
+ return pPrinter;
+}
+
+// -----------------------------------------------------------------------
+
+void SvpSalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter )
+{
+ delete pPrinter;
+}
+
+// -----------------------------------------------------------------------
+
+SalPrinter* SvpSalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter )
+{
+ // create and initialize SalPrinter
+ PspSalPrinter* pPrinter = new PspSalPrinter( pInfoPrinter );
+ pPrinter->m_aJobData = static_cast<PspSalInfoPrinter*>(pInfoPrinter)->m_aJobData;
+
+ return pPrinter;
+}
+
+// -----------------------------------------------------------------------
+
+void SvpSalInstance::DestroyPrinter( SalPrinter* pPrinter )
+{
+ delete pPrinter;
+}
+
+// -----------------------------------------------------------------------
+
+void SvpSalInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList )
+{
+ PrinterInfoManager& rManager( PrinterInfoManager::get() );
+ static const char* pNoSyncDetection = getenv( "SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION" );
+ if( ! pNoSyncDetection || ! *pNoSyncDetection )
+ {
+ // #i62663# synchronize possible asynchronouse printer detection now
+ rManager.checkPrintersChanged( true );
+ }
+ ::std::list< OUString > aPrinters;
+ rManager.listPrinters( aPrinters );
+
+ for( ::std::list< OUString >::iterator it = aPrinters.begin(); it != aPrinters.end(); ++it )
+ {
+ const PrinterInfo& rInfo( rManager.getPrinterInfo( *it ) );
+ // Neuen Eintrag anlegen
+ SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo;
+ pInfo->maPrinterName = *it;
+ pInfo->maDriver = rInfo.m_aDriverName;
+ pInfo->maLocation = rInfo.m_aLocation;
+ pInfo->maComment = rInfo.m_aComment;
+ pInfo->mpSysData = NULL;
+
+ sal_Int32 nIndex = 0;
+ while( nIndex != -1 )
+ {
+ String aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
+ if( aToken.CompareToAscii( "pdf=", 4 ) == COMPARE_EQUAL )
+ {
+ pInfo->maLocation = getPdfDir( rInfo );
+ break;
+ }
+ }
+
+ pList->Add( pInfo );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SvpSalInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo )
+{
+ delete pInfo;
+}
+
+// -----------------------------------------------------------------------
+
+void SvpSalInstance::GetPrinterQueueState( SalPrinterQueueInfo* )
+{
+}
+
+// -----------------------------------------------------------------------
+
+String SvpSalInstance::GetDefaultPrinter()
+{
+ PrinterInfoManager& rManager( PrinterInfoManager::get() );
+ return rManager.getDefaultPrinter();
+}
+
+// =======================================================================
+
+PspSalInfoPrinter::PspSalInfoPrinter()
+{
+ m_pGraphics = NULL;
+ m_bPapersInit = false;
+}
+
+// -----------------------------------------------------------------------
+
+PspSalInfoPrinter::~PspSalInfoPrinter()
+{
+ if( m_pGraphics )
+ {
+ delete m_pGraphics;
+ m_pGraphics = NULL;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void PspSalInfoPrinter::InitPaperFormats( const ImplJobSetup* )
+{
+ m_aPaperFormats.clear();
+ m_bPapersInit = true;
+
+ if( m_aJobData.m_pParser )
+ {
+ const PPDKey* pKey = m_aJobData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
+ if( pKey )
+ {
+ int nValues = pKey->countValues();
+ for( int i = 0; i < nValues; i++ )
+ {
+ const PPDValue* pValue = pKey->getValue( i );
+ int nWidth = 0, nHeight = 0;
+ m_aJobData.m_pParser->getPaperDimension( pValue->m_aOption, nWidth, nHeight );
+ PaperInfo aInfo(PtTo10Mu( nWidth ), PtTo10Mu( nHeight ));
+ m_aPaperFormats.push_back( aInfo );
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+int PspSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* )
+{
+ return 900;
+}
+
+// -----------------------------------------------------------------------
+
+SalGraphics* PspSalInfoPrinter::GetGraphics()
+{
+ // return a valid pointer only once
+ // the reasoning behind this is that we could have different
+ // SalGraphics that can run in multiple threads
+ // (future plans)
+ SalGraphics* pRet = NULL;
+ if( ! m_pGraphics )
+ {
+ m_pGraphics = new PspGraphics( &m_aJobData, &m_aPrinterGfx, NULL, false, this );
+ m_pGraphics->SetLayout( 0 );
+ pRet = m_pGraphics;
+ }
+ return pRet;
+}
+
+// -----------------------------------------------------------------------
+
+void PspSalInfoPrinter::ReleaseGraphics( SalGraphics* pGraphics )
+{
+ if( pGraphics == m_pGraphics )
+ {
+ delete pGraphics;
+ m_pGraphics = NULL;
+ }
+ return;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL PspSalInfoPrinter::Setup( SalFrame*, ImplJobSetup* )
+{
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+// This function gets the driver data and puts it into pJobSetup
+// If pJobSetup->mpDriverData is NOT NULL, then the independend
+// data should be merged into the driver data
+// If pJobSetup->mpDriverData IS NULL, then the driver defaults
+// should be merged into the independent data
+BOOL PspSalInfoPrinter::SetPrinterData( ImplJobSetup* pJobSetup )
+{
+ if( pJobSetup->mpDriverData )
+ return SetData( ~0, pJobSetup );
+
+ copyJobDataToJobSetup( pJobSetup, m_aJobData );
+
+ // set/clear backwards compatibility flag
+ bool bStrictSO52Compatibility = false;
+ std::hash_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it =
+ pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StrictSO52Compatibility" ) ) );
+ if( compat_it != pJobSetup->maValueMap.end() )
+ {
+ if( compat_it->second.equalsIgnoreAsciiCaseAscii( "true" ) )
+ bStrictSO52Compatibility = true;
+ }
+ m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility );
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+// This function merges the independ driver data
+// and sets the new independ data in pJobSetup
+// Only the data must be changed, where the bit
+// in nGetDataFlags is set
+BOOL PspSalInfoPrinter::SetData(
+ ULONG nSetDataFlags,
+ ImplJobSetup* pJobSetup )
+{
+ JobData aData;
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
+
+ if( aData.m_pParser )
+ {
+ const PPDKey* pKey;
+ const PPDValue* pValue;
+
+ // merge papersize if necessary
+ if( nSetDataFlags & SAL_JOBSET_PAPERSIZE )
+ {
+ int nWidth, nHeight;
+ if( pJobSetup->meOrientation == ORIENTATION_PORTRAIT )
+ {
+ nWidth = pJobSetup->mnPaperWidth;
+ nHeight = pJobSetup->mnPaperHeight;
+ }
+ else
+ {
+ nWidth = pJobSetup->mnPaperHeight;
+ nHeight = pJobSetup->mnPaperWidth;
+ }
+ String aPaper;
+
+ if( pJobSetup->mePaperFormat == PAPER_USER )
+ aPaper = aData.m_pParser->matchPaper(
+ TenMuToPt( pJobSetup->mnPaperWidth ),
+ TenMuToPt( pJobSetup->mnPaperHeight ) );
+ else
+ aPaper = rtl::OStringToOUString(PaperInfo::toPSName(pJobSetup->mePaperFormat), RTL_TEXTENCODING_ISO_8859_1);
+
+ pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
+ pValue = pKey ? pKey->getValue( aPaper ) : NULL;
+ if( ! ( pKey && pValue && aData.m_aContext.setValue( pKey, pValue, false ) == pValue ) )
+ return FALSE;
+ }
+
+ // merge paperbin if necessary
+ if( nSetDataFlags & SAL_JOBSET_PAPERBIN )
+ {
+ pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) );
+ if( pKey )
+ {
+ int nPaperBin = pJobSetup->mnPaperBin;
+ if( nPaperBin == 0xffff )
+ pValue = pKey->getDefaultValue();
+ else
+ pValue = pKey->getValue( pJobSetup->mnPaperBin );
+
+ // may fail due to constraints;
+ // real paper bin is copied back to jobsetup in that case
+ aData.m_aContext.setValue( pKey, pValue );
+ }
+ // if printer has no InputSlot key simply ignore this setting
+ // (e.g. SGENPRT has no InputSlot)
+ }
+
+ // merge orientation if necessary
+ if( nSetDataFlags & SAL_JOBSET_ORIENTATION )
+ aData.m_eOrientation = pJobSetup->meOrientation == ORIENTATION_LANDSCAPE ? orientation::Landscape : orientation::Portrait;
+
+ // merge duplex if necessary
+ if( nSetDataFlags & SAL_JOBSET_DUPLEXMODE )
+ {
+ pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) );
+ if( pKey )
+ {
+ pValue = NULL;
+ switch( pJobSetup->meDuplexMode )
+ {
+ case DUPLEX_OFF:
+ pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "None" ) ) );
+ if( pValue == NULL )
+ pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "SimplexNoTumble" ) ) );
+ break;
+ case DUPLEX_SHORTEDGE:
+ pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "DuplexTumble" ) ) );
+ break;
+ case DUPLEX_LONGEDGE:
+ pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "DuplexNoTumble" ) ) );
+ break;
+ case DUPLEX_UNKNOWN:
+ default:
+ pValue = 0;
+ break;
+ }
+ if( ! pValue )
+ pValue = pKey->getDefaultValue();
+ aData.m_aContext.setValue( pKey, pValue );
+ }
+ }
+
+ m_aJobData = aData;
+ copyJobDataToJobSetup( pJobSetup, aData );
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void PspSalInfoPrinter::GetPageInfo(
+ const ImplJobSetup* pJobSetup,
+ long& rOutWidth, long& rOutHeight,
+ long& rPageOffX, long& rPageOffY,
+ long& rPageWidth, long& rPageHeight )
+{
+ if( ! pJobSetup )
+ return;
+
+ JobData aData;
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
+
+ // get the selected page size
+ if( aData.m_pParser )
+ {
+
+ String aPaper;
+ int width, height;
+ int left = 0, top = 0, right = 0, bottom = 0;
+ int nDPI = aData.m_aContext.getRenderResolution();
+
+
+ if( aData.m_eOrientation == psp::orientation::Portrait )
+ {
+ aData.m_aContext.getPageSize( aPaper, width, height );
+ aData.m_pParser->getMargins( aPaper, left, right, top, bottom );
+ }
+ else
+ {
+ aData.m_aContext.getPageSize( aPaper, height, width );
+ aData.m_pParser->getMargins( aPaper, top, bottom, right, left );
+ }
+
+ rPageWidth = width * nDPI / 72;
+ rPageHeight = height * nDPI / 72;
+ rPageOffX = left * nDPI / 72;
+ rPageOffY = top * nDPI / 72;
+ rOutWidth = ( width - left - right ) * nDPI / 72;
+ rOutHeight = ( height - top - bottom ) * nDPI / 72;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ULONG PspSalInfoPrinter::GetPaperBinCount( const ImplJobSetup* pJobSetup )
+{
+ if( ! pJobSetup )
+ return 0;
+
+ JobData aData;
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
+
+ const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ): NULL;
+ return pKey ? pKey->countValues() : 0;
+}
+
+// -----------------------------------------------------------------------
+
+String PspSalInfoPrinter::GetPaperBinName( const ImplJobSetup* pJobSetup, ULONG nPaperBin )
+{
+ JobData aData;
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
+
+ String aRet;
+ if( aData.m_pParser )
+ {
+ const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ): NULL;
+ if( nPaperBin == 0xffff || ! pKey )
+ aRet = aData.m_pParser->getDefaultInputSlot();
+ else
+ {
+ const PPDValue* pValue = pKey->getValue( nPaperBin );
+ if( pValue )
+ aRet = aData.m_pParser->translateOption( pKey->getKey(), pValue->m_aOption );
+ }
+ }
+
+ return aRet;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG PspSalInfoPrinter::GetCapabilities( const ImplJobSetup* pJobSetup, USHORT nType )
+{
+ switch( nType )
+ {
+ case PRINTER_CAPABILITIES_SUPPORTDIALOG:
+ return 1;
+ case PRINTER_CAPABILITIES_COPIES:
+ return 0xffff;
+ case PRINTER_CAPABILITIES_COLLATECOPIES:
+ {
+ // see if the PPD contains a value to set Collate to True
+ JobData aData;
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
+
+ const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ) ) : NULL;
+ const PPDValue* pVal = pKey ? pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "True" ) ) ) : NULL;
+
+ // PPDs don't mention the number of possible collated copies.
+ // so let's guess as many as we want ?
+ return pVal ? 0xffff : 0;
+ }
+ case PRINTER_CAPABILITIES_SETORIENTATION:
+ return 1;
+ case PRINTER_CAPABILITIES_SETDUPLEX:
+ return 1;
+ case PRINTER_CAPABILITIES_SETPAPERBIN:
+ return 1;
+ case PRINTER_CAPABILITIES_SETPAPERSIZE:
+ return 1;
+ case PRINTER_CAPABILITIES_SETPAPER:
+ return 0;
+ case PRINTER_CAPABILITIES_FAX:
+ {
+ PrinterInfoManager& rManager = PrinterInfoManager::get();
+ PrinterInfo aInfo( rManager.getPrinterInfo( pJobSetup->maPrinterName ) );
+ String aFeatures( aInfo.m_aFeatures );
+ int nTokenCount = aFeatures.GetTokenCount( ',' );
+ for( int i = 0; i < nTokenCount; i++ )
+ {
+ if( aFeatures.GetToken( i ).CompareToAscii( "fax", 3 ) == COMPARE_EQUAL )
+ return 1;
+ }
+ return 0;
+ }
+ case PRINTER_CAPABILITIES_PDF:
+ {
+ PrinterInfoManager& rManager = PrinterInfoManager::get();
+ PrinterInfo aInfo( rManager.getPrinterInfo( pJobSetup->maPrinterName ) );
+ String aFeatures( aInfo.m_aFeatures );
+ int nTokenCount = aFeatures.GetTokenCount( ',' );
+ for( int i = 0; i < nTokenCount; i++ )
+ {
+ if( aFeatures.GetToken( i ).CompareToAscii( "pdf=", 4 ) == COMPARE_EQUAL )
+ return 1;
+ }
+ return 0;
+ }
+ default: break;
+ };
+ return 0;
+}
+
+// =======================================================================
+
+/*
+ * SalPrinter
+ */
+
+PspSalPrinter::PspSalPrinter( SalInfoPrinter* pInfoPrinter )
+ : m_bFax( false ),
+ m_bPdf( false ),
+ m_bSwallowFaxNo( false ),
+ m_pGraphics( NULL ),
+ m_nCopies( 1 ),
+ m_bCollate( false ),
+ m_pInfoPrinter( pInfoPrinter )
+{
+}
+
+// -----------------------------------------------------------------------
+
+PspSalPrinter::~PspSalPrinter()
+{
+}
+
+// -----------------------------------------------------------------------
+
+static String getTmpName()
+{
+ rtl::OUString aTmp, aSys;
+ osl_createTempFile( NULL, NULL, &aTmp.pData );
+ osl_getSystemPathFromFileURL( aTmp.pData, &aSys.pData );
+
+ return aSys;
+}
+
+BOOL PspSalPrinter::StartJob(
+ const XubString* pFileName,
+ const XubString& rJobName,
+ const XubString& rAppName,
+ ULONG nCopies,
+ bool bCollate,
+ bool /*bDirect*/,
+ ImplJobSetup* pJobSetup )
+{
+ vcl_sal::PrinterUpdate::jobStarted();
+
+ m_bFax = false;
+ m_bPdf = false;
+ m_aFileName = pFileName ? *pFileName : String();
+ m_aTmpFile = String();
+ m_nCopies = nCopies;
+ m_bCollate = bCollate;
+
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData );
+ if( m_nCopies > 1 )
+ {
+ // in case user did not do anything (m_nCopies=1)
+ // take the default from jobsetup
+ m_aJobData.m_nCopies = m_nCopies;
+ m_aJobData.setCollate( bCollate );
+ }
+
+ // check wether this printer is configured as fax
+ int nMode = 0;
+ const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) );
+ sal_Int32 nIndex = 0;
+ while( nIndex != -1 )
+ {
+ OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
+ if( ! aToken.compareToAscii( "fax", 3 ) )
+ {
+ m_bFax = true;
+ m_aTmpFile = getTmpName();
+ nMode = S_IRUSR | S_IWUSR;
+
+ ::std::hash_map< ::rtl::OUString, ::rtl::OUString, ::rtl::OUStringHash >::const_iterator it;
+ it = pJobSetup->maValueMap.find( ::rtl::OUString::createFromAscii( "FAX#" ) );
+ if( it != pJobSetup->maValueMap.end() )
+ m_aFaxNr = it->second;
+
+ sal_Int32 nPos = 0;
+ m_bSwallowFaxNo = ! aToken.getToken( 1, '=', nPos ).compareToAscii( "swallow", 7 ) ? true : false;
+
+ break;
+ }
+ if( ! aToken.compareToAscii( "pdf=", 4 ) )
+ {
+ m_bPdf = true;
+ m_aTmpFile = getTmpName();
+ nMode = S_IRUSR | S_IWUSR;
+
+ if( ! m_aFileName.Len() )
+ {
+ m_aFileName = getPdfDir( rInfo );
+ m_aFileName.Append( '/' );
+ m_aFileName.Append( rJobName );
+ m_aFileName.AppendAscii( ".pdf" );
+ }
+ break;
+ }
+ }
+ m_aPrinterGfx.Init( m_aJobData );
+
+ // set/clear backwards compatibility flag
+ bool bStrictSO52Compatibility = false;
+ std::hash_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it =
+ pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StrictSO52Compatibility" ) ) );
+ if( compat_it != pJobSetup->maValueMap.end() )
+ {
+ if( compat_it->second.equalsIgnoreAsciiCaseAscii( "true" ) )
+ bStrictSO52Compatibility = true;
+ }
+ m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility );
+
+ return m_aPrintJob.StartJob( m_aTmpFile.Len() ? m_aTmpFile : m_aFileName, nMode, rJobName, rAppName, m_aJobData, &m_aPrinterGfx, false ) ? TRUE : FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL PspSalPrinter::EndJob()
+{
+ BOOL bSuccess = m_aPrintJob.EndJob();
+
+ if( bSuccess )
+ {
+ // check for fax
+ if( m_bFax )
+ {
+
+ const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) );
+ // sendAFax removes the file after use
+ bSuccess = sendAFax( m_aFaxNr, m_aTmpFile, rInfo.m_aCommand );
+ }
+ else if( m_bPdf )
+ {
+ const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) );
+ bSuccess = createPdf( m_aFileName, m_aTmpFile, rInfo.m_aCommand );
+ }
+ }
+ vcl_sal::PrinterUpdate::jobEnded();
+ return bSuccess;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL PspSalPrinter::AbortJob()
+{
+ BOOL bAbort = m_aPrintJob.AbortJob() ? TRUE : FALSE;
+ vcl_sal::PrinterUpdate::jobEnded();
+ return bAbort;
+}
+
+// -----------------------------------------------------------------------
+
+SalGraphics* PspSalPrinter::StartPage( ImplJobSetup* pJobSetup, BOOL )
+{
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData );
+ m_pGraphics = new PspGraphics( &m_aJobData, &m_aPrinterGfx, m_bFax ? &m_aFaxNr : NULL, m_bSwallowFaxNo, m_pInfoPrinter );
+ m_pGraphics->SetLayout( 0 );
+ if( m_nCopies > 1 )
+ {
+ // in case user did not do anything (m_nCopies=1)
+ // take the default from jobsetup
+ m_aJobData.m_nCopies = m_nCopies;
+ m_aJobData.setCollate( m_nCopies > 1 && m_bCollate );
+ }
+
+ m_aPrintJob.StartPage( m_aJobData );
+ m_aPrinterGfx.Init( m_aPrintJob );
+
+ return m_pGraphics;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL PspSalPrinter::EndPage()
+{
+ sal_Bool bResult = m_aPrintJob.EndPage();
+ m_aPrinterGfx.Clear();
+ return bResult ? TRUE : FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG PspSalPrinter::GetErrorCode()
+{
+ return 0;
+}
+
+/*
+ * vcl::PrinterUpdate
+ */
+
+Timer* vcl_sal::PrinterUpdate::pPrinterUpdateTimer = NULL;
+int vcl_sal::PrinterUpdate::nActiveJobs = 0;
+
+void vcl_sal::PrinterUpdate::doUpdate()
+{
+ ::psp::PrinterInfoManager& rManager( ::psp::PrinterInfoManager::get() );
+ if( rManager.checkPrintersChanged( false ) && SvpSalInstance::s_pDefaultInstance )
+ {
+ const std::list< SalFrame* >& rList = SvpSalInstance::s_pDefaultInstance->getFrames();
+ for( std::list< SalFrame* >::const_iterator it = rList.begin();
+ it != rList.end(); ++it )
+ SvpSalInstance::s_pDefaultInstance->PostEvent( *it, NULL, SALEVENT_PRINTERCHANGED );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_STATIC_LINK_NOINSTANCE( vcl_sal::PrinterUpdate, UpdateTimerHdl, void*, )
+{
+ if( nActiveJobs < 1 )
+ {
+ doUpdate();
+ delete pPrinterUpdateTimer;
+ pPrinterUpdateTimer = NULL;
+ }
+ else
+ pPrinterUpdateTimer->Start();
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void vcl_sal::PrinterUpdate::update()
+{
+ if( Application::GetSettings().GetMiscSettings().GetDisablePrinting() )
+ return;
+
+ static bool bOnce = false;
+ if( ! bOnce )
+ {
+ bOnce = true;
+ // start background printer detection
+ psp::PrinterInfoManager::get();
+ return;
+ }
+
+ if( nActiveJobs < 1 )
+ doUpdate();
+ else if( ! pPrinterUpdateTimer )
+ {
+ pPrinterUpdateTimer = new Timer();
+ pPrinterUpdateTimer->SetTimeout( 500 );
+ pPrinterUpdateTimer->SetTimeoutHdl( STATIC_LINK( NULL, vcl_sal::PrinterUpdate, UpdateTimerHdl ) );
+ pPrinterUpdateTimer->Start();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void vcl_sal::PrinterUpdate::jobEnded()
+{
+ nActiveJobs--;
+ if( nActiveJobs < 1 )
+ {
+ if( pPrinterUpdateTimer )
+ {
+ pPrinterUpdateTimer->Stop();
+ delete pPrinterUpdateTimer;
+ pPrinterUpdateTimer = NULL;
+ doUpdate();
+ }
+ }
+}
diff --git a/vcl/unx/headless/svpprn.hxx b/vcl/unx/headless/svpprn.hxx
new file mode 100644
index 000000000000..0da506076908
--- /dev/null
+++ b/vcl/unx/headless/svpprn.hxx
@@ -0,0 +1,120 @@
+/*************************************************************************
+ *
+ * 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 _SVP_SVPPRN_HXX
+#define _SVP_SVPPRN_HXX
+
+#include "vcl/jobdata.hxx"
+#include "vcl/printergfx.hxx"
+#include "vcl/printerjob.hxx"
+#include "vcl/salprn.hxx"
+
+class PspGraphics;
+
+class PspSalInfoPrinter : public SalInfoPrinter
+{
+public:
+ PspGraphics* m_pGraphics;
+ psp::JobData m_aJobData;
+ psp::PrinterGfx m_aPrinterGfx;
+
+ PspSalInfoPrinter();
+ virtual ~PspSalInfoPrinter();
+
+ // overload all pure virtual methods
+ virtual SalGraphics* GetGraphics();
+ virtual void ReleaseGraphics( SalGraphics* pGraphics );
+ virtual BOOL Setup( SalFrame* pFrame, ImplJobSetup* pSetupData );
+ virtual BOOL SetPrinterData( ImplJobSetup* pSetupData );
+ virtual BOOL SetData( ULONG nFlags, ImplJobSetup* pSetupData );
+ virtual void GetPageInfo( const ImplJobSetup* pSetupData,
+ long& rOutWidth, long& rOutHeight,
+ long& rPageOffX, long& rPageOffY,
+ long& rPageWidth, long& rPageHeight );
+ virtual ULONG GetCapabilities( const ImplJobSetup* pSetupData, USHORT nType );
+ virtual ULONG GetPaperBinCount( const ImplJobSetup* pSetupData );
+ virtual String GetPaperBinName( const ImplJobSetup* pSetupData, ULONG nPaperBin );
+ virtual void InitPaperFormats( const ImplJobSetup* pSetupData );
+ virtual int GetLandscapeAngle( const ImplJobSetup* pSetupData );
+};
+
+class PspSalPrinter : public SalPrinter
+{
+public:
+ String m_aFileName;
+ String m_aTmpFile;
+ String m_aFaxNr;
+ bool m_bFax:1;
+ bool m_bPdf:1;
+ bool m_bSwallowFaxNo:1;
+ PspGraphics* m_pGraphics;
+ psp::PrinterJob m_aPrintJob;
+ psp::JobData m_aJobData;
+ psp::PrinterGfx m_aPrinterGfx;
+ ULONG m_nCopies;
+ bool m_bCollate;
+ SalInfoPrinter* m_pInfoPrinter;
+
+ PspSalPrinter( SalInfoPrinter* );
+ virtual ~PspSalPrinter();
+
+ // overload all pure virtual methods
+ using SalPrinter::StartJob;
+ virtual BOOL StartJob( const XubString* pFileName,
+ const XubString& rJobName,
+ const XubString& rAppName,
+ ULONG nCopies,
+ bool bCollate,
+ bool bDirect,
+ ImplJobSetup* pSetupData );
+ virtual BOOL EndJob();
+ virtual BOOL AbortJob();
+ virtual SalGraphics* StartPage( ImplJobSetup* pSetupData, BOOL bNewJobData );
+ virtual BOOL EndPage();
+ virtual ULONG GetErrorCode();
+};
+
+class Timer;
+
+namespace vcl_sal {
+class VCL_DLLPUBLIC PrinterUpdate
+{
+ static Timer* pPrinterUpdateTimer;
+ static int nActiveJobs;
+
+ static void doUpdate();
+ DECL_STATIC_LINK( PrinterUpdate, UpdateTimerHdl, void* );
+public:
+ static void update();
+ static void jobStarted() { nActiveJobs++; }
+ static void jobEnded();
+};
+}
+
+#endif // _SVP_SVPPRN_HXX
+
+
diff --git a/vcl/unx/headless/svppspgraphics.cxx b/vcl/unx/headless/svppspgraphics.cxx
new file mode 100644
index 000000000000..6da09b38023c
--- /dev/null
+++ b/vcl/unx/headless/svppspgraphics.cxx
@@ -0,0 +1,1368 @@
+/*************************************************************************
+ *
+ * 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 "svppspgraphics.hxx"
+#include "svpbmp.hxx"
+
+#include "vcl/jobdata.hxx"
+#include "vcl/printergfx.hxx"
+#include "vcl/printerinfomanager.hxx"
+#include "vcl/bmpacc.hxx"
+#include "vcl/salbmp.hxx"
+#include "vcl/glyphcache.hxx"
+#include "vcl/impfont.hxx"
+#include "vcl/outfont.hxx"
+#include "vcl/fontsubset.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/salprn.hxx"
+#include "vcl/sysdata.hxx"
+
+#include "basegfx/vector/b2ivector.hxx"
+#include "basegfx/point/b2ipoint.hxx"
+#include "basebmp/color.hxx"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+using namespace psp;
+using namespace rtl;
+using namespace basebmp;
+using namespace basegfx;
+
+// ----- Implementation of PrinterBmp by means of SalBitmap/BitmapBuffer ---------------
+
+class SalPrinterBmp : public psp::PrinterBmp
+{
+ private:
+ SalPrinterBmp ();
+
+ BitmapDeviceSharedPtr m_aBitmap;
+ public:
+
+ SalPrinterBmp (const BitmapDeviceSharedPtr& rDevice);
+ virtual ~SalPrinterBmp ();
+ virtual sal_uInt32 GetPaletteColor (sal_uInt32 nIdx) const;
+ virtual sal_uInt32 GetPaletteEntryCount () const;
+ virtual sal_uInt32 GetPixelRGB (sal_uInt32 nRow, sal_uInt32 nColumn) const;
+ virtual sal_uInt8 GetPixelGray (sal_uInt32 nRow, sal_uInt32 nColumn) const;
+ virtual sal_uInt8 GetPixelIdx (sal_uInt32 nRow, sal_uInt32 nColumn) const;
+ virtual sal_uInt32 GetWidth () const;
+ virtual sal_uInt32 GetHeight() const;
+ virtual sal_uInt32 GetDepth () const;
+
+ static sal_uInt32 getRGBFromColor( const basebmp::Color& rCol )
+ {
+ return ((rCol.getBlue()) & 0x000000ff)
+ | ((rCol.getGreen() << 8) & 0x0000ff00)
+ | ((rCol.getRed() << 16) & 0x00ff0000);
+ }
+};
+
+SalPrinterBmp::SalPrinterBmp(const BitmapDeviceSharedPtr& rDevice) :
+ m_aBitmap( rDevice )
+{
+}
+
+SalPrinterBmp::~SalPrinterBmp ()
+{
+}
+
+sal_uInt32
+SalPrinterBmp::GetWidth () const
+{
+ return m_aBitmap.get() ? m_aBitmap->getSize().getX() : 0;
+}
+
+sal_uInt32
+SalPrinterBmp::GetHeight () const
+{
+ return m_aBitmap.get() ? m_aBitmap->getSize().getY() : 0;
+}
+
+sal_uInt32
+SalPrinterBmp::GetDepth () const
+{
+ return m_aBitmap.get() ?
+ SvpElement::getBitCountFromScanlineFormat( m_aBitmap->getScanlineFormat() )
+ : 0;
+}
+
+
+sal_uInt32
+SalPrinterBmp::GetPaletteEntryCount () const
+{
+ return m_aBitmap.get() ? m_aBitmap->getPaletteEntryCount() : 0;
+}
+
+sal_uInt32
+SalPrinterBmp::GetPaletteColor (sal_uInt32 nIdx) const
+{
+ sal_uInt32 nCol = 0;
+ if( m_aBitmap.get() && nIdx < static_cast<sal_uInt32>(m_aBitmap->getPaletteEntryCount()) )
+ {
+ const basebmp::Color& rColor = (*m_aBitmap->getPalette().get())[ nIdx ];
+ nCol = getRGBFromColor( rColor );
+ }
+ return nCol;
+}
+
+sal_uInt32
+SalPrinterBmp::GetPixelRGB (sal_uInt32 nRow, sal_uInt32 nColumn) const
+{
+ sal_uInt32 nCol = 0;
+ if( m_aBitmap.get() )
+ nCol = getRGBFromColor( m_aBitmap->getPixel( B2IPoint( nColumn, nRow ) ) );
+ return nCol;
+}
+
+sal_uInt8
+SalPrinterBmp::GetPixelGray (sal_uInt32 nRow, sal_uInt32 nColumn) const
+{
+ sal_uInt8 nGray = 0;
+ if( m_aBitmap.get() )
+ {
+ // TODO: don't use tools color
+ basebmp::Color aCol = m_aBitmap->getPixel( B2IPoint( nColumn, nRow ) );
+ ::Color aColor( aCol.getRed(), aCol.getGreen(), aCol.getBlue() );
+ nGray = aColor.GetLuminance();
+ }
+ return nGray;
+}
+
+sal_uInt8
+SalPrinterBmp::GetPixelIdx (sal_uInt32 nRow, sal_uInt32 nColumn) const
+{
+ sal_uInt8 nIdx = 0;
+ if( m_aBitmap.get() )
+ nIdx = static_cast<sal_uInt8>(m_aBitmap->getPixelData( B2IPoint( nColumn, nRow ) ));
+ return nIdx;
+}
+
+/*******************************************************
+ * PspGraphics *
+ *******************************************************/
+
+bool PspGraphics::drawAlphaBitmap( const SalTwoRect&, const SalBitmap& /*rSourceBitmap*/, const SalBitmap& /*rAlphaBitmap*/ )
+{
+ return false;
+}
+
+bool PspGraphics::drawAlphaRect( long /*nX*/, long /*nY*/, long /*nWidth*/, long /*nHeight*/, sal_uInt8 /*nTransparency*/ )
+{
+ return false;
+}
+
+bool PspGraphics::supportsOperation( OutDevSupportType ) const
+{
+ return false;
+}
+
+PspGraphics::~PspGraphics()
+{
+ ReleaseFonts();
+}
+
+void PspGraphics::GetResolution( sal_Int32 &rDPIX, sal_Int32 &rDPIY )
+{
+ if (m_pJobData != NULL)
+ {
+ int x = m_pJobData->m_aContext.getRenderResolution();
+
+ rDPIX = x;
+ rDPIY = x;
+ }
+}
+
+USHORT PspGraphics::GetBitCount()
+{
+ return m_pPrinterGfx->GetBitCount();
+}
+
+long PspGraphics::GetGraphicsWidth() const
+{
+ return 0;
+}
+
+void PspGraphics::ResetClipRegion()
+{
+ m_pPrinterGfx->ResetClipRegion ();
+}
+
+void PspGraphics::BeginSetClipRegion( ULONG n )
+{
+ m_pPrinterGfx->BeginSetClipRegion(n);
+}
+
+BOOL PspGraphics::unionClipRegion( long nX, long nY, long nDX, long nDY )
+{
+ return (BOOL)m_pPrinterGfx->UnionClipRegion (nX, nY, nDX, nDY);
+}
+
+bool PspGraphics::unionClipRegion( const ::basegfx::B2DPolyPolygon& )
+{
+ // TODO: implement and advertise OutDevSupport_B2DClip support
+ return false;
+}
+
+void PspGraphics::EndSetClipRegion()
+{
+ m_pPrinterGfx->EndSetClipRegion ();
+}
+
+void PspGraphics::SetLineColor()
+{
+ m_pPrinterGfx->SetLineColor ();
+}
+
+void PspGraphics::SetLineColor( SalColor nSalColor )
+{
+ psp::PrinterColor aColor (SALCOLOR_RED (nSalColor),
+ SALCOLOR_GREEN (nSalColor),
+ SALCOLOR_BLUE (nSalColor));
+ m_pPrinterGfx->SetLineColor (aColor);
+}
+
+void PspGraphics::SetFillColor()
+{
+ m_pPrinterGfx->SetFillColor ();
+}
+
+void PspGraphics::SetFillColor( SalColor nSalColor )
+{
+ psp::PrinterColor aColor (SALCOLOR_RED (nSalColor),
+ SALCOLOR_GREEN (nSalColor),
+ SALCOLOR_BLUE (nSalColor));
+ m_pPrinterGfx->SetFillColor (aColor);
+}
+
+void PspGraphics::SetROPLineColor( SalROPColor )
+{
+ DBG_ASSERT( 0, "Error: PrinterGfx::SetROPLineColor() not implemented" );
+}
+
+void PspGraphics::SetROPFillColor( SalROPColor )
+{
+ DBG_ASSERT( 0, "Error: PrinterGfx::SetROPFillColor() not implemented" );
+}
+
+void PspGraphics::SetXORMode( bool bSet, bool )
+{
+ (void)bSet;
+ DBG_ASSERT( !bSet, "Error: PrinterGfx::SetXORMode() not implemented" );
+}
+
+void PspGraphics::drawPixel( long nX, long nY )
+{
+ m_pPrinterGfx->DrawPixel (Point(nX, nY));
+}
+
+void PspGraphics::drawPixel( long nX, long nY, SalColor nSalColor )
+{
+ psp::PrinterColor aColor (SALCOLOR_RED (nSalColor),
+ SALCOLOR_GREEN (nSalColor),
+ SALCOLOR_BLUE (nSalColor));
+ m_pPrinterGfx->DrawPixel (Point(nX, nY), aColor);
+}
+
+void PspGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 )
+{
+ m_pPrinterGfx->DrawLine (Point(nX1, nY1), Point(nX2, nY2));
+}
+
+void PspGraphics::drawRect( long nX, long nY, long nDX, long nDY )
+{
+ m_pPrinterGfx->DrawRect (Rectangle(Point(nX, nY), Size(nDX, nDY)));
+}
+
+void PspGraphics::drawPolyLine( ULONG nPoints, const SalPoint *pPtAry )
+{
+ m_pPrinterGfx->DrawPolyLine (nPoints, (Point*)pPtAry);
+}
+
+void PspGraphics::drawPolygon( ULONG nPoints, const SalPoint* pPtAry )
+{
+ // Point must be equal to SalPoint! see vcl/inc/salgtype.hxx
+ m_pPrinterGfx->DrawPolygon (nPoints, (Point*)pPtAry);
+}
+
+void PspGraphics::drawPolyPolygon( sal_uInt32 nPoly,
+ const sal_uInt32 *pPoints,
+ PCONSTSALPOINT *pPtAry )
+{
+ m_pPrinterGfx->DrawPolyPolygon (nPoly, pPoints, (const Point**)pPtAry);
+}
+
+bool PspGraphics::drawPolyLine( const ::basegfx::B2DPolygon&, double /*fTransparency*/, const ::basegfx::B2DVector& /*rLineWidths*/, basegfx::B2DLineJoin /*eJoin*/ )
+{
+ // TODO: implement and advertise OutDevSupport_B2DDraw support
+ return false;
+}
+
+sal_Bool PspGraphics::drawPolyLineBezier( ULONG nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry )
+{
+ m_pPrinterGfx->DrawPolyLineBezier (nPoints, (Point*)pPtAry, pFlgAry);
+ return sal_True;
+}
+
+sal_Bool PspGraphics::drawPolygonBezier( ULONG nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry )
+{
+ m_pPrinterGfx->DrawPolygonBezier (nPoints, (Point*)pPtAry, pFlgAry);
+ return sal_True;
+}
+
+sal_Bool PspGraphics::drawPolyPolygonBezier( sal_uInt32 nPoly,
+ const sal_uInt32* pPoints,
+ const SalPoint* const* pPtAry,
+ const BYTE* const* pFlgAry )
+{
+ // Point must be equal to SalPoint! see vcl/inc/salgtype.hxx
+ m_pPrinterGfx->DrawPolyPolygonBezier (nPoly, pPoints, (Point**)pPtAry, (BYTE**)pFlgAry);
+ return sal_True;
+}
+
+bool PspGraphics::drawPolyPolygon( const basegfx::B2DPolyPolygon&, double /*fTransparency*/ )
+{
+ // TODO: implement and advertise OutDevSupport_B2DDraw support
+ return false;
+}
+
+void PspGraphics::invert( ULONG /*nPoints*/,
+ const SalPoint* /*pPtAry*/,
+ SalInvert /*nFlags*/ )
+{
+ DBG_ASSERT( 0, "Error: PrinterGfx::Invert() not implemented" );
+}
+BOOL PspGraphics::drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, ULONG nSize )
+{
+ return m_pPrinterGfx->DrawEPS( Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) ), pPtr, nSize );
+}
+
+void PspGraphics::copyBits( const SalTwoRect* /*pPosAry*/,
+ SalGraphics* /*pSSrcGraphics*/ )
+{
+ DBG_ERROR( "Error: PrinterGfx::CopyBits() not implemented" );
+}
+
+void PspGraphics::copyArea ( long /*nDestX*/, long /*nDestY*/,
+ long /*nSrcX*/, long /*nSrcY*/,
+ long /*nSrcWidth*/, long /*nSrcHeight*/,
+ USHORT /*nFlags*/ )
+{
+ DBG_ERROR( "Error: PrinterGfx::CopyArea() not implemented" );
+}
+
+void PspGraphics::drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap )
+{
+ Rectangle aSrc (Point(pPosAry->mnSrcX, pPosAry->mnSrcY),
+ Size(pPosAry->mnSrcWidth, pPosAry->mnSrcHeight));
+ Rectangle aDst (Point(pPosAry->mnDestX, pPosAry->mnDestY),
+ Size(pPosAry->mnDestWidth, pPosAry->mnDestHeight));
+
+ const SvpSalBitmap* pBmp = dynamic_cast<const SvpSalBitmap*>(&rSalBitmap);
+ if( pBmp )
+ {
+ SalPrinterBmp aBmp(pBmp->getBitmap());
+ m_pPrinterGfx->DrawBitmap(aDst, aSrc, aBmp);
+ }
+}
+
+void PspGraphics::drawBitmap( const SalTwoRect* /*pPosAry*/,
+ const SalBitmap& /*rSalBitmap*/,
+ const SalBitmap& /*rTransBitmap*/ )
+{
+ DBG_ERROR("Error: no PrinterGfx::DrawBitmap() for transparent bitmap");
+}
+
+void PspGraphics::drawBitmap( const SalTwoRect* /*pPosAry*/,
+ const SalBitmap& /*rSalBitmap*/,
+ SalColor /*nTransparentColor*/ )
+{
+ DBG_ERROR("Error: no PrinterGfx::DrawBitmap() for transparent color");
+}
+
+void PspGraphics::drawMask( const SalTwoRect* /*pPosAry*/,
+ const SalBitmap& /*rSalBitmap*/,
+ SalColor /*nMaskColor*/ )
+{
+ DBG_ERROR("Error: PrinterGfx::DrawMask() not implemented");
+}
+
+SalBitmap* PspGraphics::getBitmap( long /*nX*/, long /*nY*/, long /*nDX*/, long /*nDY*/ )
+{
+ DBG_WARNING ("Warning: PrinterGfx::GetBitmap() not implemented");
+ return NULL;
+}
+
+SalColor PspGraphics::getPixel( long /*nX*/, long /*nY*/ )
+{
+ DBG_ERROR ("Warning: PrinterGfx::GetPixel() not implemented");
+ return 0;
+}
+
+void PspGraphics::invert(
+ long /*nX*/,
+ long /*nY*/,
+ long /*nDX*/,
+ long /*nDY*/,
+ SalInvert /*nFlags*/ )
+{
+ DBG_ERROR ("Warning: PrinterGfx::Invert() not implemented");
+}
+
+//==========================================================================
+
+class ImplPspFontData : public ImplFontData
+{
+private:
+ enum { PSPFD_MAGIC = 0xb5bf01f0 };
+ sal_IntPtr mnFontId;
+
+public:
+ ImplPspFontData( const psp::FastPrintFontInfo& );
+ virtual sal_IntPtr GetFontId() const { return mnFontId; }
+ virtual ImplFontData* Clone() const { return new ImplPspFontData( *this ); }
+ virtual ImplFontEntry* CreateFontInstance( ImplFontSelectData& ) const;
+ static bool CheckFontData( const ImplFontData& r ) { return r.CheckMagic( PSPFD_MAGIC ); }
+};
+
+//--------------------------------------------------------------------------
+
+ImplPspFontData::ImplPspFontData( const psp::FastPrintFontInfo& rInfo )
+: ImplFontData( PspGraphics::Info2DevFontAttributes(rInfo), PSPFD_MAGIC ),
+ mnFontId( rInfo.m_nID )
+{}
+
+//--------------------------------------------------------------------------
+
+ImplFontEntry* ImplPspFontData::CreateFontInstance( ImplFontSelectData& rFSD ) const
+{
+ ImplServerFontEntry* pEntry = new ImplServerFontEntry( rFSD );
+ return pEntry;
+}
+
+//==========================================================================
+
+class PspFontLayout : public GenericSalLayout
+{
+public:
+ PspFontLayout( ::psp::PrinterGfx& );
+ virtual bool LayoutText( ImplLayoutArgs& );
+ virtual void InitFont() const;
+ virtual void DrawText( SalGraphics& ) const;
+private:
+ ::psp::PrinterGfx& mrPrinterGfx;
+ sal_IntPtr mnFontID;
+ int mnFontHeight;
+ int mnFontWidth;
+ bool mbVertical;
+ bool mbArtItalic;
+ bool mbArtBold;
+};
+
+//--------------------------------------------------------------------------
+
+PspFontLayout::PspFontLayout( ::psp::PrinterGfx& rGfx )
+: mrPrinterGfx( rGfx )
+{
+ mnFontID = mrPrinterGfx.GetFontID();
+ mnFontHeight = mrPrinterGfx.GetFontHeight();
+ mnFontWidth = mrPrinterGfx.GetFontWidth();
+ mbVertical = mrPrinterGfx.GetFontVertical();
+ mbArtItalic = mrPrinterGfx.GetArtificialItalic();
+ mbArtBold = mrPrinterGfx.GetArtificialBold();
+}
+
+//--------------------------------------------------------------------------
+
+bool PspFontLayout::LayoutText( ImplLayoutArgs& rArgs )
+{
+ mbVertical = ((rArgs.mnFlags & SAL_LAYOUT_VERTICAL) != 0);
+
+ long nUnitsPerPixel = 1;
+ int nOldGlyphId = -1;
+ long nGlyphWidth = 0;
+ int nCharPos = -1;
+ Point aNewPos( 0, 0 );
+ GlyphItem aPrevItem;
+ rtl_TextEncoding aFontEnc = mrPrinterGfx.GetFontMgr().getFontEncoding( mnFontID );
+ for(;;)
+ {
+ bool bRightToLeft;
+ if( !rArgs.GetNextPos( &nCharPos, &bRightToLeft ) )
+ break;
+
+ sal_UCS4 cChar = rArgs.mpStr[ nCharPos ];
+ if( bRightToLeft )
+ cChar = GetMirroredChar( cChar );
+ // symbol font aliasing: 0x0020-0x00ff -> 0xf020 -> 0xf0ff
+ if( aFontEnc == RTL_TEXTENCODING_SYMBOL )
+ if( cChar < 256 )
+ cChar += 0xf000;
+ int nGlyphIndex = cChar; // printer glyphs = unicode
+
+ // update fallback_runs if needed
+ psp::CharacterMetric aMetric;
+ mrPrinterGfx.GetFontMgr().getMetrics( mnFontID, cChar, cChar, &aMetric, mbVertical );
+ if( aMetric.width == -1 && aMetric.height == -1 )
+ rArgs.NeedFallback( nCharPos, bRightToLeft );
+
+ // apply pair kerning to prev glyph if requested
+ if( SAL_LAYOUT_KERNING_PAIRS & rArgs.mnFlags )
+ {
+ if( nOldGlyphId > 0 )
+ {
+ const std::list< KernPair >& rKernPairs = mrPrinterGfx.getKernPairs(mbVertical);
+ for( std::list< KernPair >::const_iterator it = rKernPairs.begin();
+ it != rKernPairs.end(); ++it )
+ {
+ if( it->first == nOldGlyphId && it->second == nGlyphIndex )
+ {
+ int nTextScale = mrPrinterGfx.GetFontWidth();
+ if( ! nTextScale )
+ nTextScale = mrPrinterGfx.GetFontHeight();
+ int nKern = (mbVertical ? it->kern_y : it->kern_x) * nTextScale;
+ nGlyphWidth += nKern;
+ aPrevItem.mnNewWidth = nGlyphWidth;
+ break;
+ }
+ }
+ }
+ }
+
+ // finish previous glyph
+ if( nOldGlyphId >= 0 )
+ AppendGlyph( aPrevItem );
+ nOldGlyphId = nGlyphIndex;
+ aNewPos.X() += nGlyphWidth;
+
+ // prepare GlyphItem for appending it in next round
+ nUnitsPerPixel = mrPrinterGfx.GetCharWidth( cChar, cChar, &nGlyphWidth );
+ int nGlyphFlags = bRightToLeft ? GlyphItem::IS_RTL_GLYPH : 0;
+ nGlyphIndex |= GF_ISCHAR;
+ aPrevItem = GlyphItem( nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nGlyphWidth );
+ }
+
+ // append last glyph item if any
+ if( nOldGlyphId >= 0 )
+ AppendGlyph( aPrevItem );
+
+ SetOrientation( mrPrinterGfx.GetFontAngle() );
+ SetUnitsPerPixel( nUnitsPerPixel );
+ return (nOldGlyphId >= 0);
+}
+
+class PspServerFontLayout : public ServerFontLayout
+{
+public:
+ PspServerFontLayout( psp::PrinterGfx&, ServerFont& rFont, const ImplLayoutArgs& rArgs );
+
+ virtual void InitFont() const;
+ const sal_Unicode* getTextPtr() const { return maText.getStr() - mnMinCharPos; }
+ int getMinCharPos() const { return mnMinCharPos; }
+ int getMaxCharPos() const { return mnMinCharPos+maText.getLength()-1; }
+private:
+ ::psp::PrinterGfx& mrPrinterGfx;
+ sal_IntPtr mnFontID;
+ int mnFontHeight;
+ int mnFontWidth;
+ bool mbVertical;
+ bool mbArtItalic;
+ bool mbArtBold;
+ rtl::OUString maText;
+ int mnMinCharPos;
+};
+
+PspServerFontLayout::PspServerFontLayout( ::psp::PrinterGfx& rGfx, ServerFont& rFont, const ImplLayoutArgs& rArgs )
+ : ServerFontLayout( rFont ),
+ mrPrinterGfx( rGfx )
+{
+ mnFontID = mrPrinterGfx.GetFontID();
+ mnFontHeight = mrPrinterGfx.GetFontHeight();
+ mnFontWidth = mrPrinterGfx.GetFontWidth();
+ mbVertical = mrPrinterGfx.GetFontVertical();
+ mbArtItalic = mrPrinterGfx.GetArtificialItalic();
+ mbArtBold = mrPrinterGfx.GetArtificialBold();
+ maText = OUString( rArgs.mpStr + rArgs.mnMinCharPos, rArgs.mnEndCharPos - rArgs.mnMinCharPos+1 );
+ mnMinCharPos = rArgs.mnMinCharPos;
+}
+
+void PspServerFontLayout::InitFont() const
+{
+ mrPrinterGfx.SetFont( mnFontID, mnFontHeight, mnFontWidth,
+ mnOrientation, mbVertical, mbArtItalic, mbArtBold );
+}
+
+//--------------------------------------------------------------------------
+
+static void DrawPrinterLayout( const SalLayout& rLayout, ::psp::PrinterGfx& rGfx, bool bIsPspServerFontLayout )
+{
+ const int nMaxGlyphs = 200;
+ sal_GlyphId aGlyphAry[ nMaxGlyphs ];
+ sal_Int32 aWidthAry[ nMaxGlyphs ];
+ sal_Int32 aIdxAry [ nMaxGlyphs ];
+ sal_Ucs aUnicodes[ nMaxGlyphs ];
+ int aCharPosAry [ nMaxGlyphs ];
+
+ Point aPos;
+ long nUnitsPerPixel = rLayout.GetUnitsPerPixel();
+ const sal_Unicode* pText = bIsPspServerFontLayout ? static_cast<const PspServerFontLayout&>(rLayout).getTextPtr() : NULL;
+ int nMinCharPos = bIsPspServerFontLayout ? static_cast<const PspServerFontLayout&>(rLayout).getMinCharPos() : 0;
+ int nMaxCharPos = bIsPspServerFontLayout ? static_cast<const PspServerFontLayout&>(rLayout).getMaxCharPos() : 0;
+ for( int nStart = 0;; )
+ {
+ int nGlyphCount = rLayout.GetNextGlyphs( nMaxGlyphs, aGlyphAry, aPos, nStart, aWidthAry, bIsPspServerFontLayout ? aCharPosAry : NULL );
+ if( !nGlyphCount )
+ break;
+
+ sal_Int32 nXOffset = 0;
+ for( int i = 0; i < nGlyphCount; ++i )
+ {
+ nXOffset += aWidthAry[ i ];
+ aIdxAry[ i ] = nXOffset / nUnitsPerPixel;
+ sal_Int32 nGlyphIdx = aGlyphAry[i] & (GF_IDXMASK | GF_ROTMASK);
+ if( bIsPspServerFontLayout )
+ aUnicodes[i] = (aCharPosAry[i] >= nMinCharPos && aCharPosAry[i] <= nMaxCharPos) ? pText[ aCharPosAry[i] ] : 0;
+ else
+ aUnicodes[i] = (aGlyphAry[i] & GF_ISCHAR) ? nGlyphIdx : 0;
+ aGlyphAry[i] = nGlyphIdx;
+ }
+
+ rGfx.DrawGlyphs( aPos, (sal_uInt32 *)aGlyphAry, aUnicodes, nGlyphCount, aIdxAry );
+ }
+}
+
+//--------------------------------------------------------------------------
+
+void PspFontLayout::InitFont() const
+{
+ mrPrinterGfx.SetFont( mnFontID, mnFontHeight, mnFontWidth,
+ mnOrientation, mbVertical, mbArtItalic, mbArtBold );
+}
+
+//--------------------------------------------------------------------------
+
+void PspFontLayout::DrawText( SalGraphics& ) const
+{
+ DrawPrinterLayout( *this, mrPrinterGfx, false );
+}
+
+void PspGraphics::DrawServerFontLayout( const ServerFontLayout& rLayout )
+{
+ // print complex text
+ DrawPrinterLayout( rLayout, *m_pPrinterGfx, true );
+}
+
+ImplFontCharMap* PspGraphics::GetImplFontCharMap() const
+{
+ // TODO: get ImplFontCharMap directly from fonts
+ if( !m_pServerFont[0] )
+ return NULL;
+
+ CmapResult aCmapResult;
+ if( !m_pServerFont[0]->GetFontCodeRanges( aCmapResult ) )
+ return NULL;
+ return new ImplFontCharMap( aCmapResult );
+}
+
+USHORT PspGraphics::SetFont( ImplFontSelectData *pEntry, int nFallbackLevel )
+{
+ // release all fonts that are to be overridden
+ for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
+ {
+ if( m_pServerFont[i] != NULL )
+ {
+ // old server side font is no longer referenced
+ GlyphCache::GetInstance().UncacheFont( *m_pServerFont[i] );
+ m_pServerFont[i] = NULL;
+ }
+ }
+
+ // return early if there is no new font
+ if( !pEntry )
+ return 0;
+
+ sal_IntPtr nID = pEntry->mpFontData ? pEntry->mpFontData->GetFontId() : 0;
+
+ // determine which font attributes need to be emulated
+ bool bArtItalic = false;
+ bool bArtBold = false;
+ if( pEntry->meItalic == ITALIC_OBLIQUE || pEntry->meItalic == ITALIC_NORMAL )
+ {
+ psp::italic::type eItalic = m_pPrinterGfx->GetFontMgr().getFontItalic( nID );
+ if( eItalic != psp::italic::Italic && eItalic != psp::italic::Oblique )
+ bArtItalic = true;
+ }
+ int nWeight = (int)pEntry->meWeight;
+ int nRealWeight = (int)m_pPrinterGfx->GetFontMgr().getFontWeight( nID );
+ if( nRealWeight <= (int)psp::weight::Medium && nWeight > (int)WEIGHT_MEDIUM )
+ {
+ bArtBold = true;
+ }
+
+ // also set the serverside font for layouting
+ m_bFontVertical = pEntry->mbVertical;
+ if( pEntry->mpFontData )
+ {
+ // requesting a font provided by builtin rasterizer
+ ServerFont* pServerFont = GlyphCache::GetInstance().CacheFont( *pEntry );
+ if( pServerFont != NULL )
+ {
+ if( pServerFont->TestFont() )
+ m_pServerFont[ nFallbackLevel ] = pServerFont;
+ else
+ GlyphCache::GetInstance().UncacheFont( *pServerFont );
+ }
+ }
+
+ // set the printer font
+ return m_pPrinterGfx->SetFont( nID,
+ pEntry->mnHeight,
+ pEntry->mnWidth,
+ pEntry->mnOrientation,
+ pEntry->mbVertical,
+ bArtItalic,
+ bArtBold
+ );
+}
+
+void PspGraphics::SetTextColor( SalColor nSalColor )
+{
+ psp::PrinterColor aColor (SALCOLOR_RED (nSalColor),
+ SALCOLOR_GREEN (nSalColor),
+ SALCOLOR_BLUE (nSalColor));
+ m_pPrinterGfx->SetTextColor (aColor);
+}
+
+bool PspGraphics::AddTempDevFont( ImplDevFontList*, const String&, const String& )
+{
+ return false;
+}
+
+void PspGraphics::GetDevFontList( ImplDevFontList *pList )
+{
+ ::std::list< psp::fontID > aList;
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ rMgr.getFontList( aList, m_pJobData->m_pParser, m_pInfoPrinter->m_bCompatMetrics );
+
+ ::std::list< psp::fontID >::iterator it;
+ psp::FastPrintFontInfo aInfo;
+ for (it = aList.begin(); it != aList.end(); ++it)
+ if (rMgr.getFontFastInfo (*it, aInfo))
+ AnnounceFonts( pList, aInfo );
+}
+
+void PspGraphics::GetDevFontSubstList( OutputDevice* pOutDev )
+{
+ const psp::PrinterInfo& rInfo = psp::PrinterInfoManager::get().getPrinterInfo( m_pJobData->m_aPrinterName );
+ if( rInfo.m_bPerformFontSubstitution )
+ {
+ for( std::hash_map< rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator it = rInfo.m_aFontSubstitutes.begin(); it != rInfo.m_aFontSubstitutes.end(); ++it )
+ AddDevFontSubstitute( pOutDev, it->first, it->second, FONT_SUBSTITUTE_ALWAYS );
+ }
+}
+
+void PspGraphics::GetFontMetric( ImplFontMetricData *pMetric )
+{
+ const psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ psp::PrintFontInfo aInfo;
+
+ if (rMgr.getFontInfo (m_pPrinterGfx->GetFontID(), aInfo))
+ {
+ ImplDevFontAttributes aDFA = Info2DevFontAttributes( aInfo );
+ static_cast<ImplFontAttributes&>(*pMetric) = aDFA;
+ pMetric->mbDevice = aDFA.mbDevice;
+ pMetric->mbScalableFont = true;
+
+ pMetric->mnOrientation = m_pPrinterGfx->GetFontAngle();
+ pMetric->mnSlant = 0;
+
+ sal_Int32 nTextHeight = m_pPrinterGfx->GetFontHeight();
+ sal_Int32 nTextWidth = m_pPrinterGfx->GetFontWidth();
+ if( ! nTextWidth )
+ nTextWidth = nTextHeight;
+
+ pMetric->mnWidth = nTextWidth;
+ pMetric->mnAscent = ( aInfo.m_nAscend * nTextHeight + 500 ) / 1000;
+ pMetric->mnDescent = ( aInfo.m_nDescend * nTextHeight + 500 ) / 1000;
+ pMetric->mnIntLeading = ( aInfo.m_nLeading * nTextHeight + 500 ) / 1000;
+ pMetric->mnExtLeading = 0;
+ }
+}
+
+ULONG PspGraphics::GetKernPairs( ULONG nPairs, ImplKernPairData *pKernPairs )
+{
+ const ::std::list< ::psp::KernPair >& rPairs( m_pPrinterGfx->getKernPairs() );
+ ULONG nHavePairs = rPairs.size();
+ if( pKernPairs && nPairs )
+ {
+ ::std::list< ::psp::KernPair >::const_iterator it;
+ unsigned int i;
+ int nTextScale = m_pPrinterGfx->GetFontWidth();
+ if( ! nTextScale )
+ nTextScale = m_pPrinterGfx->GetFontHeight();
+ for( i = 0, it = rPairs.begin(); i < nPairs && i < nHavePairs; i++, ++it )
+ {
+ pKernPairs[i].mnChar1 = it->first;
+ pKernPairs[i].mnChar2 = it->second;
+ pKernPairs[i].mnKern = it->kern_x * nTextScale / 1000;
+ }
+
+ }
+ return nHavePairs;
+}
+
+BOOL PspGraphics::GetGlyphBoundRect( long nGlyphIndex, Rectangle& rRect )
+{
+ int nLevel = nGlyphIndex >> GF_FONTSHIFT;
+ if( nLevel >= MAX_FALLBACK )
+ return FALSE;
+
+ ServerFont* pSF = m_pServerFont[ nLevel ];
+ if( !pSF )
+ return FALSE;
+
+ nGlyphIndex &= ~GF_FONTMASK;
+ const GlyphMetric& rGM = pSF->GetGlyphMetric( nGlyphIndex );
+ rRect = Rectangle( rGM.GetOffset(), rGM.GetSize() );
+ return TRUE;
+}
+
+BOOL PspGraphics::GetGlyphOutline( long nGlyphIndex,
+ ::basegfx::B2DPolyPolygon& rB2DPolyPoly )
+{
+ int nLevel = nGlyphIndex >> GF_FONTSHIFT;
+ if( nLevel >= MAX_FALLBACK )
+ return FALSE;
+
+ ServerFont* pSF = m_pServerFont[ nLevel ];
+ if( !pSF )
+ return FALSE;
+
+ nGlyphIndex &= ~GF_FONTMASK;
+ if( pSF->GetGlyphOutline( nGlyphIndex, rB2DPolyPoly ) )
+ return TRUE;
+
+ return FALSE;
+}
+
+SalLayout* PspGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLevel )
+{
+ // workaround for printers not handling glyph indexing for non-TT fonts
+ int nFontId = m_pPrinterGfx->GetFontID();
+ if( psp::fonttype::TrueType != psp::PrintFontManager::get().getFontType( nFontId ) )
+ rArgs.mnFlags |= SAL_LAYOUT_DISABLE_GLYPH_PROCESSING;
+ else if( nFallbackLevel > 0 )
+ rArgs.mnFlags &= ~SAL_LAYOUT_DISABLE_GLYPH_PROCESSING;
+
+ GenericSalLayout* pLayout = NULL;
+
+ if( m_pServerFont[ nFallbackLevel ]
+ && !(rArgs.mnFlags & SAL_LAYOUT_DISABLE_GLYPH_PROCESSING) )
+ pLayout = new PspServerFontLayout( *m_pPrinterGfx, *m_pServerFont[nFallbackLevel], rArgs );
+ else
+ pLayout = new PspFontLayout( *m_pPrinterGfx );
+
+ return pLayout;
+}
+
+//--------------------------------------------------------------------------
+
+BOOL PspGraphics::CreateFontSubset(
+ const rtl::OUString& rToFile,
+ const ImplFontData* pFont,
+ sal_Int32* pGlyphIDs,
+ sal_uInt8* pEncoding,
+ sal_Int32* pWidths,
+ int nGlyphCount,
+ FontSubsetInfo& rInfo
+ )
+{
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ bool bSuccess = rMgr.createFontSubset( rInfo,
+ aFont,
+ rToFile,
+ pGlyphIDs,
+ pEncoding,
+ pWidths,
+ nGlyphCount );
+ return bSuccess;
+}
+
+//--------------------------------------------------------------------------
+
+const void* PspGraphics::GetEmbedFontData( const ImplFontData* pFont, const sal_Ucs* pUnicodes, sal_Int32* pWidths, FontSubsetInfo& rInfo, long* pDataLen )
+{
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+ return PspGraphics::DoGetEmbedFontData( aFont, pUnicodes, pWidths, rInfo, pDataLen );
+}
+
+//--------------------------------------------------------------------------
+
+void PspGraphics::FreeEmbedFontData( const void* pData, long nLen )
+{
+ PspGraphics::DoFreeEmbedFontData( pData, nLen );
+}
+
+//--------------------------------------------------------------------------
+
+const Ucs2SIntMap* PspGraphics::GetFontEncodingVector( const ImplFontData* pFont, const Ucs2OStrMap** pNonEncoded )
+{
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+ return PspGraphics::DoGetFontEncodingVector( aFont, pNonEncoded );
+}
+
+//--------------------------------------------------------------------------
+
+void PspGraphics::GetGlyphWidths( const ImplFontData* pFont,
+ bool bVertical,
+ Int32Vector& rWidths,
+ Ucs2UIntMap& rUnicodeEnc )
+{
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+ PspGraphics::DoGetGlyphWidths( aFont, bVertical, rWidths, rUnicodeEnc );
+}
+
+// static helpers of PspGraphics
+
+const void* PspGraphics::DoGetEmbedFontData( fontID aFont, const sal_Ucs* pUnicodes, sal_Int32* pWidths, FontSubsetInfo& rInfo, long* pDataLen )
+{
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+
+ psp::PrintFontInfo aFontInfo;
+ if( ! rMgr.getFontInfo( aFont, aFontInfo ) )
+ return NULL;
+
+ // fill in font info
+ rInfo.m_nAscent = aFontInfo.m_nAscend;
+ rInfo.m_nDescent = aFontInfo.m_nDescend;
+ rInfo.m_aPSName = rMgr.getPSName( aFont );
+
+ int xMin, yMin, xMax, yMax;
+ rMgr.getFontBoundingBox( aFont, xMin, yMin, xMax, yMax );
+
+ psp::CharacterMetric aMetrics[256];
+ sal_Ucs aUnicodes[256];
+ if( aFontInfo.m_aEncoding == RTL_TEXTENCODING_SYMBOL && aFontInfo.m_eType == psp::fonttype::Type1 )
+ {
+ for( int i = 0; i < 256; i++ )
+ aUnicodes[i] = pUnicodes[i] < 0x0100 ? pUnicodes[i] + 0xf000 : pUnicodes[i];
+ pUnicodes = aUnicodes;
+ }
+ if( ! rMgr.getMetrics( aFont, pUnicodes, 256, aMetrics ) )
+ return NULL;
+
+ OString aSysPath = rMgr.getFontFileSysPath( aFont );
+ struct stat aStat;
+ if( stat( aSysPath.getStr(), &aStat ) )
+ return NULL;
+ int fd = open( aSysPath.getStr(), O_RDONLY );
+ if( fd < 0 )
+ return NULL;
+ void* pFile = mmap( NULL, aStat.st_size, PROT_READ, MAP_SHARED, fd, 0 );
+ close( fd );
+ if( pFile == MAP_FAILED )
+ return NULL;
+
+ *pDataLen = aStat.st_size;
+
+ rInfo.m_aFontBBox = Rectangle( Point( xMin, yMin ), Size( xMax-xMin, yMax-yMin ) );
+ rInfo.m_nCapHeight = yMax; // Well ...
+
+ for( int i = 0; i < 256; i++ )
+ pWidths[i] = (aMetrics[i].width > 0 ? aMetrics[i].width : 0);
+
+ switch( aFontInfo.m_eType )
+ {
+ case psp::fonttype::TrueType:
+ rInfo.m_nFontType = FontSubsetInfo::SFNT_TTF;
+ break;
+ case psp::fonttype::Type1: {
+ const bool bPFA = ((*(unsigned char*)pFile) < 0x80);
+ rInfo.m_nFontType = bPFA ? FontSubsetInfo::TYPE1_PFA : FontSubsetInfo::TYPE1_PFB;
+ }
+ break;
+ default:
+ return NULL;
+ }
+
+ return pFile;
+}
+
+void PspGraphics::DoFreeEmbedFontData( const void* pData, long nLen )
+{
+ if( pData )
+ munmap( (char*)pData, nLen );
+}
+
+const Ucs2SIntMap* PspGraphics::DoGetFontEncodingVector( fontID aFont, const Ucs2OStrMap** pNonEncoded )
+{
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+
+ psp::PrintFontInfo aFontInfo;
+ if( ! rMgr.getFontInfo( aFont, aFontInfo ) )
+ {
+ if( pNonEncoded )
+ *pNonEncoded = NULL;
+ return NULL;
+ }
+
+ return rMgr.getEncodingMap( aFont, pNonEncoded );
+}
+
+void PspGraphics::DoGetGlyphWidths( psp::fontID aFont,
+ bool bVertical,
+ Int32Vector& rWidths,
+ Ucs2UIntMap& rUnicodeEnc )
+{
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ rMgr.getGlyphWidths( aFont, bVertical, rWidths, rUnicodeEnc );
+}
+
+// ----------------------------------------------------------------------------
+
+FontWidth PspGraphics::ToFontWidth (psp::width::type eWidth)
+{
+ switch (eWidth)
+ {
+ case psp::width::UltraCondensed: return WIDTH_ULTRA_CONDENSED;
+ case psp::width::ExtraCondensed: return WIDTH_EXTRA_CONDENSED;
+ case psp::width::Condensed: return WIDTH_CONDENSED;
+ case psp::width::SemiCondensed: return WIDTH_SEMI_CONDENSED;
+ case psp::width::Normal: return WIDTH_NORMAL;
+ case psp::width::SemiExpanded: return WIDTH_SEMI_EXPANDED;
+ case psp::width::Expanded: return WIDTH_EXPANDED;
+ case psp::width::ExtraExpanded: return WIDTH_EXTRA_EXPANDED;
+ case psp::width::UltraExpanded: return WIDTH_ULTRA_EXPANDED;
+ default: break;
+ }
+ return WIDTH_DONTKNOW;
+}
+
+FontWeight PspGraphics::ToFontWeight (psp::weight::type eWeight)
+{
+ switch (eWeight)
+ {
+ case psp::weight::Thin: return WEIGHT_THIN;
+ case psp::weight::UltraLight: return WEIGHT_ULTRALIGHT;
+ case psp::weight::Light: return WEIGHT_LIGHT;
+ case psp::weight::SemiLight: return WEIGHT_SEMILIGHT;
+ case psp::weight::Normal: return WEIGHT_NORMAL;
+ case psp::weight::Medium: return WEIGHT_MEDIUM;
+ case psp::weight::SemiBold: return WEIGHT_SEMIBOLD;
+ case psp::weight::Bold: return WEIGHT_BOLD;
+ case psp::weight::UltraBold: return WEIGHT_ULTRABOLD;
+ case psp::weight::Black: return WEIGHT_BLACK;
+ default: break;
+ }
+ return WEIGHT_DONTKNOW;
+}
+
+FontPitch PspGraphics::ToFontPitch (psp::pitch::type ePitch)
+{
+ switch (ePitch)
+ {
+ case psp::pitch::Fixed: return PITCH_FIXED;
+ case psp::pitch::Variable: return PITCH_VARIABLE;
+ default: break;
+ }
+ return PITCH_DONTKNOW;
+}
+
+FontItalic PspGraphics::ToFontItalic (psp::italic::type eItalic)
+{
+ switch (eItalic)
+ {
+ case psp::italic::Upright: return ITALIC_NONE;
+ case psp::italic::Oblique: return ITALIC_OBLIQUE;
+ case psp::italic::Italic: return ITALIC_NORMAL;
+ default: break;
+ }
+ return ITALIC_DONTKNOW;
+}
+
+FontFamily PspGraphics::ToFontFamily (psp::family::type eFamily)
+{
+ switch (eFamily)
+ {
+ case psp::family::Decorative: return FAMILY_DECORATIVE;
+ case psp::family::Modern: return FAMILY_MODERN;
+ case psp::family::Roman: return FAMILY_ROMAN;
+ case psp::family::Script: return FAMILY_SCRIPT;
+ case psp::family::Swiss: return FAMILY_SWISS;
+ case psp::family::System: return FAMILY_SYSTEM;
+ default: break;
+ }
+ return FAMILY_DONTKNOW;
+}
+
+ImplDevFontAttributes PspGraphics::Info2DevFontAttributes( const psp::FastPrintFontInfo& rInfo )
+{
+ ImplDevFontAttributes aDFA;
+ aDFA.maName = rInfo.m_aFamilyName;
+ aDFA.maStyleName = rInfo.m_aStyleName;
+ aDFA.meFamily = ToFontFamily (rInfo.m_eFamilyStyle);
+ aDFA.meWeight = ToFontWeight (rInfo.m_eWeight);
+ aDFA.meItalic = ToFontItalic (rInfo.m_eItalic);
+ aDFA.meWidthType = ToFontWidth (rInfo.m_eWidth);
+ aDFA.mePitch = ToFontPitch (rInfo.m_ePitch);
+ aDFA.mbSymbolFlag = (rInfo.m_aEncoding == RTL_TEXTENCODING_SYMBOL);
+
+ switch( rInfo.m_eType )
+ {
+ case psp::fonttype::Builtin:
+ aDFA.mnQuality = 1024;
+ aDFA.mbDevice = true;
+ aDFA.mbSubsettable = false;
+ aDFA.mbEmbeddable = false;
+ break;
+ case psp::fonttype::TrueType:
+ aDFA.mnQuality = 512;
+ aDFA.mbDevice = false;
+ aDFA.mbSubsettable = true;
+ aDFA.mbEmbeddable = false;
+ break;
+ case psp::fonttype::Type1:
+ aDFA.mnQuality = 0;
+ aDFA.mbDevice = false;
+ aDFA.mbSubsettable = false;
+ aDFA.mbEmbeddable = true;
+ break;
+ default:
+ aDFA.mnQuality = 0;
+ aDFA.mbDevice = false;
+ aDFA.mbSubsettable = false;
+ aDFA.mbEmbeddable = false;
+ break;
+ }
+
+ aDFA.mbOrientation = true;
+
+ // add font family name aliases
+ ::std::list< OUString >::const_iterator it = rInfo.m_aAliases.begin();
+ bool bHasMapNames = false;
+ for(; it != rInfo.m_aAliases.end(); ++it )
+ {
+ if( bHasMapNames )
+ aDFA.maMapNames.Append( ';' );
+ aDFA.maMapNames.Append( (*it).getStr() );
+ bHasMapNames = true;
+ }
+
+#if OSL_DEBUG_LEVEL > 2
+ if( bHasMapNames )
+ {
+ ByteString aOrigName( aDFA.maName, osl_getThreadTextEncoding() );
+ ByteString aAliasNames( aDFA.maMapNames, osl_getThreadTextEncoding() );
+ fprintf( stderr, "using alias names \"%s\" for font family \"%s\"\n",
+ aAliasNames.GetBuffer(), aOrigName.GetBuffer() );
+ }
+#endif
+
+ return aDFA;
+}
+
+// -----------------------------------------------------------------------
+
+void PspGraphics::AnnounceFonts( ImplDevFontList* pFontList, const psp::FastPrintFontInfo& aInfo )
+{
+ int nQuality = 0;
+
+ if( aInfo.m_eType == psp::fonttype::TrueType )
+ {
+ // asian type 1 fonts are not known
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ ByteString aFileName( rMgr.getFontFileSysPath( aInfo.m_nID ) );
+ int nPos = aFileName.SearchBackward( '_' );
+ if( nPos == STRING_NOTFOUND || aFileName.GetChar( nPos+1 ) == '.' )
+ nQuality += 5;
+ else
+ {
+ static const char* pLangBoost = NULL;
+ static bool bOnce = true;
+ if( bOnce )
+ {
+ bOnce = false;
+ const 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 )
+ if( aFileName.Copy( nPos+1, 3 ).EqualsIgnoreCaseAscii( pLangBoost ) )
+ nQuality += 10;
+ }
+ }
+
+ ImplPspFontData* pFD = new ImplPspFontData( aInfo );
+ pFD->mnQuality += nQuality;
+ pFontList->Add( pFD );
+}
+
+bool PspGraphics::filterText( const String& rOrig, String& rNewText, xub_StrLen nIndex, xub_StrLen& rLen, xub_StrLen& rCutStart, xub_StrLen& rCutStop )
+{
+ if( ! m_pPhoneNr )
+ return false;
+
+ rCutStop = rCutStart = STRING_NOTFOUND;
+
+#define FAX_PHONE_TOKEN "@@#"
+#define FAX_PHONE_TOKEN_LENGTH 3
+#define FAX_END_TOKEN "@@"
+#define FAX_END_TOKEN_LENGTH 2
+
+ bool bRet = false;
+ bool bStarted = false;
+ bool bStopped = false;
+ USHORT nPos;
+ USHORT nStart = 0;
+ USHORT nStop = rLen;
+ String aPhone = rOrig.Copy( nIndex, rLen );
+
+ if( ! m_bPhoneCollectionActive )
+ {
+ if( ( nPos = aPhone.SearchAscii( FAX_PHONE_TOKEN ) ) != STRING_NOTFOUND )
+ {
+ nStart = nPos;
+ m_bPhoneCollectionActive = true;
+ m_aPhoneCollection.Erase();
+ bRet = true;
+ bStarted = true;
+ }
+ }
+ if( m_bPhoneCollectionActive )
+ {
+ bRet = true;
+ nPos = bStarted ? nStart + FAX_PHONE_TOKEN_LENGTH : 0;
+ if( ( nPos = aPhone.SearchAscii( FAX_END_TOKEN, nPos ) ) != STRING_NOTFOUND )
+ {
+ m_bPhoneCollectionActive = false;
+ nStop = nPos + FAX_END_TOKEN_LENGTH;
+ bStopped = true;
+ }
+ int nTokenStart = nStart + (bStarted ? FAX_PHONE_TOKEN_LENGTH : 0);
+ int nTokenStop = nStop - (bStopped ? FAX_END_TOKEN_LENGTH : 0);
+ m_aPhoneCollection += aPhone.Copy( nTokenStart, nTokenStop - nTokenStart );
+ if( ! m_bPhoneCollectionActive )
+ {
+ m_pPhoneNr->AppendAscii( "<Fax#>" );
+ m_pPhoneNr->Append( m_aPhoneCollection );
+ m_pPhoneNr->AppendAscii( "</Fax#>" );
+ m_aPhoneCollection.Erase();
+ }
+ }
+ if( m_aPhoneCollection.Len() > 1024 )
+ {
+ m_bPhoneCollectionActive = false;
+ m_aPhoneCollection.Erase();
+ bRet = false;
+ }
+
+ if( bRet && m_bSwallowFaxNo )
+ {
+ rLen -= nStop - nStart;
+ rCutStart = nStart+nIndex;
+ rCutStop = nStop+nIndex;
+ if( rCutStart )
+ rNewText = rOrig.Copy( 0, rCutStart );
+ rNewText += rOrig.Copy( rCutStop );
+ }
+
+ return bRet && m_bSwallowFaxNo;
+}
+
+SystemFontData PspGraphics::GetSysFontData( int nFallbacklevel ) const
+{
+ SystemFontData aSysFontData;
+
+ if (nFallbacklevel >= MAX_FALLBACK) nFallbacklevel = MAX_FALLBACK - 1;
+ if (nFallbacklevel < 0 ) nFallbacklevel = 0;
+
+ aSysFontData.nSize = sizeof( SystemFontData );
+ aSysFontData.nFontId = 0;
+ aSysFontData.nFontFlags = 0;
+ aSysFontData.bFakeBold = false;
+ aSysFontData.bFakeItalic = false;
+ aSysFontData.bAntialias = true;
+ return aSysFontData;
+}
+
+SystemGraphicsData PspGraphics::GetGraphicsData() const
+{
+ SystemGraphicsData aRes;
+ aRes.nSize = sizeof(aRes);
+ aRes.hDrawable = 0;
+ aRes.pRenderFormat = 0;
+ return aRes;
+}
+
diff --git a/vcl/unx/headless/svppspgraphics.hxx b/vcl/unx/headless/svppspgraphics.hxx
new file mode 100644
index 000000000000..063dff34c3c2
--- /dev/null
+++ b/vcl/unx/headless/svppspgraphics.hxx
@@ -0,0 +1,193 @@
+/*************************************************************************
+ *
+ * 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 _SVP_PSPGRAPHICS_HXX
+#define _SVP_PSPGRAPHICS_HXX
+
+
+#include "vcl/fontmanager.hxx"
+#include "vcl/sallayout.hxx"
+#include "vcl/salgdi.hxx"
+
+namespace psp { struct JobData; class PrinterGfx; }
+
+class ServerFont;
+class ImplDevFontAttributes;
+class SalInfoPrinter;
+
+class PspGraphics : public SalGraphics
+{
+ psp::JobData* m_pJobData;
+ psp::PrinterGfx* m_pPrinterGfx;
+ String* m_pPhoneNr;
+ bool m_bSwallowFaxNo;
+ String m_aPhoneCollection;
+ bool m_bPhoneCollectionActive;
+
+ ServerFont* m_pServerFont[ MAX_FALLBACK ];
+ bool m_bFontVertical;
+ SalInfoPrinter* m_pInfoPrinter;
+
+protected:
+ virtual bool drawAlphaBitmap( const SalTwoRect&, const SalBitmap& rSourceBitmap, const SalBitmap& rAlphaBitmap );
+ virtual bool drawAlphaRect( long nX, long nY, long nWidth, long nHeight, sal_uInt8 nTransparency );
+
+public:
+ PspGraphics( psp::JobData* pJob, psp::PrinterGfx* pGfx, String* pPhone, bool bSwallow, SalInfoPrinter* pInfoPrinter )
+ : m_pJobData( pJob ),
+ m_pPrinterGfx( pGfx ),
+ m_pPhoneNr( pPhone ),
+ m_bSwallowFaxNo( bSwallow ),
+ m_bPhoneCollectionActive( false ),
+ m_bFontVertical( false ),
+ m_pInfoPrinter( pInfoPrinter )
+ { for( int i = 0; i < MAX_FALLBACK; i++ ) m_pServerFont[i] = 0; }
+ virtual ~PspGraphics();
+
+ // helper methods for sharing with X11SalGraphics
+ static const void* DoGetEmbedFontData( psp::fontID aFont, const sal_Ucs* pUnicodes, sal_Int32* pWidths, FontSubsetInfo& rInfo, long* pDataLen );
+ static void DoFreeEmbedFontData( const void* pData, long nLen );
+ static const Ucs2SIntMap* DoGetFontEncodingVector( psp::fontID aFont, const Ucs2OStrMap** pNonEncoded );
+ static void DoGetGlyphWidths( psp::fontID aFont,
+ bool bVertical,
+ Int32Vector& rWidths,
+ Ucs2UIntMap& rUnicodeEnc );
+ static ImplDevFontAttributes Info2DevFontAttributes( const psp::FastPrintFontInfo& );
+ static void AnnounceFonts( ImplDevFontList*, const psp::FastPrintFontInfo& );
+ static FontWidth ToFontWidth (psp::width::type eWidth);
+ static FontWeight ToFontWeight (psp::weight::type eWeight);
+ static FontPitch ToFontPitch (psp::pitch::type ePitch);
+ static FontItalic ToFontItalic (psp::italic::type eItalic);
+ static FontFamily ToFontFamily (psp::family::type eFamily);
+
+ // overload all pure virtual methods
+ virtual void GetResolution( sal_Int32& rDPIX, sal_Int32& rDPIY );
+ virtual USHORT GetBitCount();
+ virtual long GetGraphicsWidth() const;
+
+ virtual void ResetClipRegion();
+ virtual void BeginSetClipRegion( ULONG nCount );
+ virtual BOOL unionClipRegion( long nX, long nY, long nWidth, long nHeight );
+ virtual bool unionClipRegion( const ::basegfx::B2DPolyPolygon& );
+ virtual void EndSetClipRegion();
+
+ virtual void SetLineColor();
+ virtual void SetLineColor( SalColor nSalColor );
+ virtual void SetFillColor();
+ virtual void SetFillColor( SalColor nSalColor );
+ virtual void SetXORMode( bool bSet, bool );
+ virtual void SetROPLineColor( SalROPColor nROPColor );
+ virtual void SetROPFillColor( SalROPColor nROPColor );
+
+ virtual void SetTextColor( SalColor nSalColor );
+ virtual USHORT SetFont( ImplFontSelectData*, int nFallbackLevel );
+ virtual void GetFontMetric( ImplFontMetricData* );
+ virtual ULONG GetKernPairs( ULONG nPairs, ImplKernPairData* pKernPairs );
+ virtual ImplFontCharMap* GetImplFontCharMap() const;
+ virtual void GetDevFontList( ImplDevFontList* );
+ virtual void GetDevFontSubstList( OutputDevice* );
+ virtual bool AddTempDevFont( ImplDevFontList*, const String& rFileURL, const String& rFontName );
+ virtual BOOL CreateFontSubset( const rtl::OUString& rToFile,
+ const ImplFontData*,
+ sal_Int32* pGlyphIDs,
+ sal_uInt8* pEncoding,
+ sal_Int32* pWidths,
+ int nGlyphs,
+ FontSubsetInfo& rInfo
+ );
+ virtual const Ucs2SIntMap* GetFontEncodingVector( const ImplFontData*, const Ucs2OStrMap** ppNonEncoded );
+ virtual const void* GetEmbedFontData( const ImplFontData*,
+ const sal_Ucs* pUnicodes,
+ sal_Int32* pWidths,
+ FontSubsetInfo& rInfo,
+ long* pDataLen );
+ virtual void FreeEmbedFontData( const void* pData, long nDataLen );
+ virtual void GetGlyphWidths( const ImplFontData*,
+ bool bVertical,
+ Int32Vector& rWidths,
+ Ucs2UIntMap& rUnicodeEnc );
+ virtual BOOL GetGlyphBoundRect( long nIndex, Rectangle& );
+ virtual BOOL GetGlyphOutline( long nIndex, ::basegfx::B2DPolyPolygon& );
+ virtual SalLayout* GetTextLayout( ImplLayoutArgs&, int nFallbackLevel );
+ virtual void DrawServerFontLayout( const ServerFontLayout& );
+ virtual bool supportsOperation( OutDevSupportType ) const;
+ virtual void drawPixel( long nX, long nY );
+ virtual void drawPixel( long nX, long nY, SalColor nSalColor );
+ virtual void drawLine( long nX1, long nY1, long nX2, long nY2 );
+ virtual void drawRect( long nX, long nY, long nWidth, long nHeight );
+ virtual void drawPolyLine( ULONG nPoints, const SalPoint* pPtAry );
+ virtual void drawPolygon( ULONG nPoints, const SalPoint* pPtAry );
+ virtual bool drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double fTransparency );
+ virtual bool drawPolyLine( const ::basegfx::B2DPolygon&, double fTransparency, const ::basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin );
+ virtual void drawPolyPolygon( sal_uInt32 nPoly,
+ const sal_uInt32* pPoints,
+ PCONSTSALPOINT* pPtAry );
+ virtual sal_Bool drawPolyLineBezier( ULONG nPoints,
+ const SalPoint* pPtAry,
+ const BYTE* pFlgAry );
+ virtual sal_Bool drawPolygonBezier( ULONG nPoints,
+ const SalPoint* pPtAry,
+ const BYTE* pFlgAry );
+ virtual sal_Bool drawPolyPolygonBezier( sal_uInt32 nPoly,
+ const sal_uInt32* pPoints,
+ const SalPoint* const* pPtAry,
+ const BYTE* const* pFlgAry );
+
+ virtual void copyArea( long nDestX,
+ long nDestY,
+ long nSrcX,
+ long nSrcY,
+ long nSrcWidth,
+ long nSrcHeight,
+ USHORT nFlags );
+ virtual void copyBits( const SalTwoRect* pPosAry,
+ SalGraphics* pSrcGraphics );
+ virtual void drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap );
+ virtual void drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ SalColor nTransparentColor );
+ virtual void drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ const SalBitmap& rTransparentBitmap );
+ virtual void drawMask( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ SalColor nMaskColor );
+ virtual SalBitmap* getBitmap( long nX, long nY, long nWidth, long nHeight );
+ virtual SalColor getPixel( long nX, long nY );
+ virtual void invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags );
+ virtual void invert( ULONG nPoints, const SalPoint* pPtAry, SalInvert nFlags );
+
+ virtual BOOL drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, ULONG nSize );
+ virtual bool filterText( const String& rOrigText, String& rNewText, xub_StrLen nIndex, xub_StrLen& rLen, xub_StrLen& rCutStart, xub_StrLen& rCutStop );
+
+ virtual SystemGraphicsData GetGraphicsData() const;
+ virtual SystemFontData GetSysFontData( int nFallbacklevel ) const;
+};
+
+#endif // _SVP_PSPGRAPHICS_HXX
+
diff --git a/vcl/unx/headless/svptext.cxx b/vcl/unx/headless/svptext.cxx
new file mode 100644
index 000000000000..ecb8b11b7e04
--- /dev/null
+++ b/vcl/unx/headless/svptext.cxx
@@ -0,0 +1,501 @@
+/*************************************************************************
+ *
+ * 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 "svpgdi.hxx"
+#include "svpbmp.hxx"
+
+#include <basegfx/range/b2drange.hxx>
+#include <basegfx/range/b2irange.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basebmp/scanlineformats.hxx>
+
+#include <tools/debug.hxx>
+
+#if OSL_DEBUG_LEVEL > 2
+#include <basebmp/debug.hxx>
+#endif
+
+#include <vcl/outfont.hxx>
+#include <vcl/glyphcache.hxx>
+#include <vcl/impfont.hxx>
+
+#include "svppspgraphics.hxx"
+
+using namespace basegfx;
+using namespace basebmp;
+
+// ===========================================================================
+
+class SvpGlyphPeer
+: public GlyphCachePeer
+{
+public:
+ SvpGlyphPeer() {}
+
+ BitmapDeviceSharedPtr GetGlyphBmp( ServerFont&, int nGlyphIndex,
+ sal_uInt32 nBmpFormat, B2IPoint& rTargetPos );
+
+protected:
+ virtual void RemovingFont( ServerFont& );
+ virtual void RemovingGlyph( ServerFont&, GlyphData&, int nGlyphIndex );
+
+ class SvpGcpHelper
+ {
+ public:
+ RawBitmap maRawBitmap;
+ BitmapDeviceSharedPtr maBitmapDev;
+ };
+};
+
+// ===========================================================================
+
+class SvpGlyphCache : public GlyphCache
+{
+public:
+ SvpGlyphPeer& GetPeer() { return reinterpret_cast<SvpGlyphPeer&>( mrPeer ); }
+static SvpGlyphCache& GetInstance();
+private:
+ SvpGlyphCache( SvpGlyphPeer& rPeer ) : GlyphCache( rPeer) {}
+};
+
+//--------------------------------------------------------------------------
+
+SvpGlyphCache& SvpGlyphCache::GetInstance()
+{
+ static SvpGlyphPeer aSvpGlyphPeer;
+ static SvpGlyphCache aGC( aSvpGlyphPeer );
+ return aGC;
+}
+
+// ===========================================================================
+
+BitmapDeviceSharedPtr SvpGlyphPeer::GetGlyphBmp( ServerFont& rServerFont,
+ int nGlyphIndex, sal_uInt32 nBmpFormat, B2IPoint& rTargetPos )
+{
+ GlyphData& rGlyphData = rServerFont.GetGlyphData( nGlyphIndex );
+ SvpGcpHelper* pGcpHelper = (SvpGcpHelper*)rGlyphData.ExtDataRef().mpData;
+
+ // nothing to do if the GlyphPeer hasn't allocated resources for the glyph
+ if( rGlyphData.ExtDataRef().meInfo != sal::static_int_cast<int>(nBmpFormat) )
+ {
+ if( rGlyphData.ExtDataRef().meInfo == Format::NONE )
+ pGcpHelper = new SvpGcpHelper;
+ RawBitmap& rRawBitmap = pGcpHelper->maRawBitmap;
+
+ // get glyph bitmap in matching format
+ bool bFound = false;
+ switch( nBmpFormat )
+ {
+ case Format::ONE_BIT_LSB_GREY:
+ bFound = rServerFont.GetGlyphBitmap1( nGlyphIndex, pGcpHelper->maRawBitmap );
+ break;
+ case Format::EIGHT_BIT_GREY:
+ bFound = rServerFont.GetGlyphBitmap8( nGlyphIndex, pGcpHelper->maRawBitmap );
+ break;
+ default:
+ DBG_ERROR( "SVP GCP::GetGlyphBmp(): illegal scanline format");
+ // fall back to black&white mask
+ nBmpFormat = Format::ONE_BIT_LSB_GREY;
+ bFound = false;
+ break;
+ }
+
+ // return .notdef glyph if needed
+ if( !bFound && (nGlyphIndex != 0) )
+ {
+ delete pGcpHelper;
+ return GetGlyphBmp( rServerFont, 0, nBmpFormat, rTargetPos );
+ }
+
+ // construct alpha mask from raw bitmap
+ const B2IVector aSize( rRawBitmap.mnScanlineSize, rRawBitmap.mnHeight );
+ if( aSize.getX() && aSize.getY() )
+ {
+ static PaletteMemorySharedVector aDummyPAL;
+ RawMemorySharedArray aRawPtr( rRawBitmap.mpBits );
+ pGcpHelper->maBitmapDev = createBitmapDevice( aSize, true, nBmpFormat, aRawPtr, aDummyPAL );
+ }
+
+ rServerFont.SetExtended( nBmpFormat, (void*)pGcpHelper );
+ }
+
+ rTargetPos += B2IPoint( pGcpHelper->maRawBitmap.mnXOffset, pGcpHelper->maRawBitmap.mnYOffset );
+ return pGcpHelper->maBitmapDev;
+}
+
+//--------------------------------------------------------------------------
+
+void SvpGlyphPeer::RemovingFont( ServerFont& )
+{
+ // nothing to do: no font resources held in SvpGlyphPeer
+}
+
+//--------------------------------------------------------------------------
+
+void SvpGlyphPeer::RemovingGlyph( ServerFont&, GlyphData& rGlyphData, int /*nGlyphIndex*/ )
+{
+ if( rGlyphData.ExtDataRef().mpData != Format::NONE )
+ {
+ // release the glyph related resources
+ DBG_ASSERT( (rGlyphData.ExtDataRef().meInfo <= Format::MAX), "SVP::RG() invalid alpha format" );
+ SvpGcpHelper* pGcpHelper = (SvpGcpHelper*)rGlyphData.ExtDataRef().mpData;
+ delete[] pGcpHelper->maRawBitmap.mpBits;
+ delete pGcpHelper;
+ }
+}
+
+// ===========================================================================
+
+// PspKernInfo allows on-demand-querying of psprint provided kerning info (#i29881#)
+class PspKernInfo : public ExtraKernInfo
+{
+public:
+ PspKernInfo( int nFontId ) : ExtraKernInfo(nFontId) {}
+protected:
+ virtual void Initialize() const;
+};
+
+//--------------------------------------------------------------------------
+
+void PspKernInfo::Initialize() const
+{
+ mbInitialized = true;
+
+ // get the kerning pairs from psprint
+ const psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ typedef std::list< psp::KernPair > PspKernPairs;
+ const PspKernPairs& rKernPairs = rMgr.getKernPairs( mnFontId );
+ if( rKernPairs.empty() )
+ return;
+
+ // feed psprint's kerning list into a lookup-friendly container
+ maUnicodeKernPairs.resize( rKernPairs.size() );
+ PspKernPairs::const_iterator it = rKernPairs.begin();
+ for(; it != rKernPairs.end(); ++it )
+ {
+ ImplKernPairData aKernPair = { it->first, it->second, it->kern_x };
+ maUnicodeKernPairs.insert( aKernPair );
+ }
+}
+
+// ===========================================================================
+
+USHORT SvpSalGraphics::SetFont( ImplFontSelectData* pIFSD, int nFallbackLevel )
+{
+ // release all no longer needed font resources
+ for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
+ {
+ if( m_pServerFont[i] != NULL )
+ {
+ // old server side font is no longer referenced
+ SvpGlyphCache::GetInstance().UncacheFont( *m_pServerFont[i] );
+ m_pServerFont[i] = NULL;
+ }
+ }
+
+ // return early if there is no new font
+ if( !pIFSD )
+ return 0;
+
+ // handle the request for a non-native X11-font => use the GlyphCache
+ ServerFont* pServerFont = SvpGlyphCache::GetInstance().CacheFont( *pIFSD );
+ if( !pServerFont )
+ return SAL_SETFONT_BADFONT;
+
+ // check selected font
+ if( !pServerFont->TestFont() )
+ {
+ SvpGlyphCache::GetInstance().UncacheFont( *pServerFont );
+ return SAL_SETFONT_BADFONT;
+ }
+
+ // update SalGraphics font settings
+ m_pServerFont[ nFallbackLevel ] = pServerFont;
+ return SAL_SETFONT_USEDRAWTEXTARRAY;
+}
+
+// ---------------------------------------------------------------------------
+
+void SvpSalGraphics::GetFontMetric( ImplFontMetricData* pMetric )
+{
+ if( m_pServerFont[0] != NULL )
+ {
+ long rDummyFactor;
+ m_pServerFont[0]->FetchFontMetric( *pMetric, rDummyFactor );
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+ULONG SvpSalGraphics::GetKernPairs( ULONG nPairs, ImplKernPairData* pKernPairs )
+{
+ ULONG nGotPairs = 0;
+
+ if( m_pServerFont[0] != NULL )
+ {
+ ImplKernPairData* pTmpKernPairs = NULL;
+ nGotPairs = m_pServerFont[0]->GetKernPairs( &pTmpKernPairs );
+ for( ULONG i = 0; i < nPairs && i < nGotPairs; ++i )
+ pKernPairs[ i ] = pTmpKernPairs[ i ];
+ delete[] pTmpKernPairs;
+ }
+
+ return nGotPairs;
+}
+
+// ---------------------------------------------------------------------------
+
+ImplFontCharMap* SvpSalGraphics::GetImplFontCharMap() const
+{
+ if( !m_pServerFont[0] )
+ return NULL;
+
+ CmapResult aCmapResult;
+ if( !m_pServerFont[0]->GetFontCodeRanges( aCmapResult ) )
+ return NULL;
+ return new ImplFontCharMap( aCmapResult );
+}
+
+// ---------------------------------------------------------------------------
+
+void SvpSalGraphics::GetDevFontList( ImplDevFontList* pDevFontList )
+{
+ GlyphCache& rGC = SvpGlyphCache::GetInstance();
+
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ psp::FastPrintFontInfo aInfo;
+ ::std::list< psp::fontID > aList;
+ rMgr.getFontList( aList );
+ ::std::list< psp::fontID >::iterator it;
+ for( it = aList.begin(); it != aList.end(); ++it )
+ {
+ if( !rMgr.getFontFastInfo( *it, aInfo ) )
+ continue;
+
+ // the GlyphCache must not bother with builtin fonts because
+ // it cannot access or use them anyway
+ if( aInfo.m_eType == psp::fonttype::Builtin )
+ continue;
+
+ // normalize face number to the GlyphCache
+ int nFaceNum = rMgr.getFontFaceNumber( aInfo.m_nID );
+ if( nFaceNum < 0 )
+ nFaceNum = 0;
+
+ // for fonts where extra kerning info can be provided on demand
+ // an ExtraKernInfo object is supplied
+ const ExtraKernInfo* pExtraKernInfo = NULL;
+ if( aInfo.m_eType == psp::fonttype::Type1 )
+ pExtraKernInfo = new PspKernInfo( *it );
+
+ // inform GlyphCache about this font provided by the PsPrint subsystem
+ ImplDevFontAttributes aDFA = PspGraphics::Info2DevFontAttributes( aInfo );
+ aDFA.mnQuality += 4096;
+ const rtl::OString& rFileName = rMgr.getFontFileSysPath( aInfo.m_nID );
+ rGC.AddFontFile( rFileName, nFaceNum, aInfo.m_nID, aDFA, pExtraKernInfo );
+ }
+
+ // announce glyphcache fonts
+ rGC.AnnounceFonts( pDevFontList );
+}
+
+// ---------------------------------------------------------------------------
+
+void SvpSalGraphics::GetDevFontSubstList( OutputDevice* )
+{}
+
+// ---------------------------------------------------------------------------
+
+bool SvpSalGraphics::AddTempDevFont( ImplDevFontList*,
+ const String&, const String& )
+{
+ return false;
+}
+
+// ---------------------------------------------------------------------------
+
+BOOL SvpSalGraphics::CreateFontSubset(
+ const rtl::OUString& rToFile,
+ const ImplFontData* pFont,
+ sal_Int32* pGlyphIDs,
+ sal_uInt8* pEncoding,
+ sal_Int32* pWidths,
+ int nGlyphCount,
+ FontSubsetInfo& rInfo
+ )
+{
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ bool bSuccess = rMgr.createFontSubset( rInfo,
+ aFont,
+ rToFile,
+ pGlyphIDs,
+ pEncoding,
+ pWidths,
+ nGlyphCount );
+ return bSuccess;
+}
+
+// ---------------------------------------------------------------------------
+
+const Ucs2SIntMap* SvpSalGraphics::GetFontEncodingVector( const ImplFontData* pFont, const Ucs2OStrMap** pNonEncoded )
+{
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+ return PspGraphics::DoGetFontEncodingVector( aFont, pNonEncoded );
+}
+
+// ---------------------------------------------------------------------------
+
+const void* SvpSalGraphics::GetEmbedFontData(
+ const ImplFontData* pFont,
+ const sal_Ucs* pUnicodes,
+ sal_Int32* pWidths,
+ FontSubsetInfo& rInfo,
+ long* pDataLen
+ )
+{
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+ return PspGraphics::DoGetEmbedFontData( aFont, pUnicodes, pWidths, rInfo, pDataLen );
+}
+
+// ---------------------------------------------------------------------------
+
+void SvpSalGraphics::FreeEmbedFontData( const void* pData, long nLen )
+{
+ PspGraphics::DoFreeEmbedFontData( pData, nLen );
+}
+
+void SvpSalGraphics::GetGlyphWidths( const ImplFontData* pFont,
+ bool bVertical,
+ Int32Vector& rWidths,
+ Ucs2UIntMap& rUnicodeEnc )
+{
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+ PspGraphics::DoGetGlyphWidths( aFont, bVertical, rWidths, rUnicodeEnc );
+}
+
+// ---------------------------------------------------------------------------
+
+BOOL SvpSalGraphics::GetGlyphBoundRect( long nGlyphIndex, Rectangle& rRect )
+{
+ int nLevel = nGlyphIndex >> GF_FONTSHIFT;
+ if( nLevel >= MAX_FALLBACK )
+ return FALSE;
+
+ ServerFont* pSF = m_pServerFont[ nLevel ];
+ if( !pSF )
+ return FALSE;
+
+ nGlyphIndex &= ~GF_FONTMASK;
+ const GlyphMetric& rGM = pSF->GetGlyphMetric( nGlyphIndex );
+ rRect = Rectangle( rGM.GetOffset(), rGM.GetSize() );
+ return TRUE;
+}
+
+// ---------------------------------------------------------------------------
+
+BOOL SvpSalGraphics::GetGlyphOutline( long nGlyphIndex, B2DPolyPolygon& rPolyPoly )
+{
+ int nLevel = nGlyphIndex >> GF_FONTSHIFT;
+ if( nLevel >= MAX_FALLBACK )
+ return FALSE;
+
+ const ServerFont* pSF = m_pServerFont[ nLevel ];
+ if( !pSF )
+ return FALSE;
+
+ nGlyphIndex &= ~GF_FONTMASK;
+ if( pSF->GetGlyphOutline( nGlyphIndex, rPolyPoly ) )
+ return TRUE;
+
+ return FALSE;
+}
+
+// ---------------------------------------------------------------------------
+
+SalLayout* SvpSalGraphics::GetTextLayout( ImplLayoutArgs&, int nFallbackLevel )
+{
+ GenericSalLayout* pLayout = NULL;
+
+ if( m_pServerFont[ nFallbackLevel ] )
+ pLayout = new ServerFontLayout( *m_pServerFont[ nFallbackLevel ] );
+
+ return pLayout;
+}
+
+// ---------------------------------------------------------------------------
+
+void SvpSalGraphics::DrawServerFontLayout( const ServerFontLayout& rSalLayout )
+{
+ // iterate over all glyphs in the layout
+ Point aPos;
+ sal_GlyphId nGlyphIndex;
+ SvpGlyphPeer& rGlyphPeer = SvpGlyphCache::GetInstance().GetPeer();
+ for( int nStart = 0; rSalLayout.GetNextGlyphs( 1, &nGlyphIndex, aPos, nStart ); )
+ {
+ int nLevel = nGlyphIndex >> GF_FONTSHIFT;
+ DBG_ASSERT( nLevel < MAX_FALLBACK, "SvpGDI: invalid glyph fallback level" );
+ ServerFont* pSF = m_pServerFont[ nLevel ];
+ if( !pSF )
+ continue;
+
+ // get the glyph's alpha mask and adjust the drawing position
+ nGlyphIndex &= ~GF_FONTMASK;
+ B2IPoint aDstPoint( aPos.X(), aPos.Y() );
+ BitmapDeviceSharedPtr aAlphaMask
+ = rGlyphPeer.GetGlyphBmp( *pSF, nGlyphIndex, m_eTextFmt, aDstPoint );
+ if( !aAlphaMask ) // ignore empty glyphs
+ continue;
+
+ // blend text color into target using the glyph's mask
+ const B2IRange aSrcRect( B2ITuple(0,0), aAlphaMask->getSize() );
+ m_aDevice->drawMaskedColor( m_aTextColor, aAlphaMask, aSrcRect, aDstPoint, m_aClipMap );
+ }
+}
+
+// ===========================================================================
diff --git a/vcl/unx/headless/svpvd.cxx b/vcl/unx/headless/svpvd.cxx
new file mode 100644
index 000000000000..1c2ab01ccca2
--- /dev/null
+++ b/vcl/unx/headless/svpvd.cxx
@@ -0,0 +1,110 @@
+/*************************************************************************
+ *
+ * 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 "svpvd.hxx"
+#include "svpgdi.hxx"
+
+#include <basegfx/vector/b2ivector.hxx>
+#include <basebmp/scanlineformats.hxx>
+
+#include "stdio.h"
+
+using namespace basegfx;
+using namespace basebmp;
+
+SvpSalVirtualDevice::~SvpSalVirtualDevice()
+{
+}
+
+SalGraphics* SvpSalVirtualDevice::GetGraphics()
+{
+ SvpSalGraphics* pGraphics = new SvpSalGraphics();
+ pGraphics->setDevice( m_aDevice );
+ m_aGraphics.push_back( pGraphics );
+ return pGraphics;
+}
+
+void SvpSalVirtualDevice::ReleaseGraphics( SalGraphics* pGraphics )
+{
+ m_aGraphics.remove( dynamic_cast<SvpSalGraphics*>(pGraphics) );
+ delete pGraphics;
+}
+
+BOOL SvpSalVirtualDevice::SetSize( long nNewDX, long nNewDY )
+{
+ B2IVector aDevSize( nNewDX, nNewDY );
+ if( aDevSize.getX() == 0 )
+ aDevSize.setX( 1 );
+ if( aDevSize.getY() == 0 )
+ aDevSize.setY( 1 );
+ if( ! m_aDevice.get() || m_aDevice->getSize() != aDevSize )
+ {
+ sal_uInt32 nFormat = SVP_DEFAULT_BITMAP_FORMAT;
+ std::vector< basebmp::Color > aDevPal;
+ switch( m_nBitCount )
+ {
+ case 1: nFormat = Format::ONE_BIT_MSB_PAL;
+ aDevPal.reserve(2);
+ aDevPal.push_back( basebmp::Color( 0, 0, 0 ) );
+ aDevPal.push_back( basebmp::Color( 0xff, 0xff, 0xff ) );
+ break;
+ case 4: nFormat = Format::FOUR_BIT_MSB_PAL; break;
+ case 8: nFormat = Format::EIGHT_BIT_PAL; break;
+#ifdef OSL_BIGENDIAN
+ case 16: nFormat = Format::SIXTEEN_BIT_MSB_TC_MASK; break;
+#else
+ case 16: nFormat = Format::SIXTEEN_BIT_LSB_TC_MASK; break;
+#endif
+ case 0:
+ case 24: nFormat = Format::TWENTYFOUR_BIT_TC_MASK; break;
+ case 32: nFormat = Format::THIRTYTWO_BIT_TC_MASK; break;
+ }
+ m_aDevice = aDevPal.empty()
+ ? createBitmapDevice( aDevSize, false, nFormat )
+ : createBitmapDevice( aDevSize, false, nFormat, PaletteMemorySharedVector( new std::vector< basebmp::Color >(aDevPal) ) );
+
+ // update device in existing graphics
+ for( std::list< SvpSalGraphics* >::iterator it = m_aGraphics.begin();
+ it != m_aGraphics.end(); ++it )
+ (*it)->setDevice( m_aDevice );
+
+ }
+ return true;
+}
+
+void SvpSalVirtualDevice::GetSize( long& rWidth, long& rHeight )
+{
+ if( m_aDevice.get() )
+ {
+ B2IVector aDevSize( m_aDevice->getSize() );
+ rWidth = aDevSize.getX();
+ rHeight = aDevSize.getY();
+ }
+ else
+ rWidth = rHeight = 0;
+}
+
diff --git a/vcl/unx/headless/svpvd.hxx b/vcl/unx/headless/svpvd.hxx
new file mode 100644
index 000000000000..083547cf19a9
--- /dev/null
+++ b/vcl/unx/headless/svpvd.hxx
@@ -0,0 +1,59 @@
+/*************************************************************************
+ *
+ * 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 _SVP_SVPVD_HXX
+#define _SVP_SVPVD_HXX
+
+#include <vcl/salvd.hxx>
+#include "svpelement.hxx"
+
+#include <list>
+
+class SvpSalGraphics;
+
+class SvpSalVirtualDevice : public SalVirtualDevice, public SvpElement
+{
+ USHORT m_nBitCount;
+ basebmp::BitmapDeviceSharedPtr m_aDevice;
+ std::list< SvpSalGraphics* > m_aGraphics;
+
+public:
+ SvpSalVirtualDevice( USHORT nBitCount ) : SvpElement(), m_nBitCount(nBitCount) {}
+ virtual ~SvpSalVirtualDevice();
+
+ // SvpElement
+ virtual const basebmp::BitmapDeviceSharedPtr& getDevice() const { return m_aDevice; }
+
+ // SalVirtualDevice
+ virtual SalGraphics* GetGraphics();
+ virtual void ReleaseGraphics( SalGraphics* pGraphics );
+
+ virtual BOOL SetSize( long nNewDX, long nNewDY );
+ virtual void GetSize( long& rWidth, long& rHeight );
+};
+
+#endif // _SVP_SVPVD_HXX
diff --git a/vcl/unx/inc/XIM.h b/vcl/unx/inc/XIM.h
new file mode 100644
index 000000000000..b00634090b5d
--- /dev/null
+++ b/vcl/unx/inc/XIM.h
@@ -0,0 +1,137 @@
+/*************************************************************************
+ *
+ * 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 _XIM_h
+#define _XIM_h
+
+#include <X11/Xlib.h>
+#include <X11/Xresource.h>
+
+#ifdef __cplusplus
+extern "C"
+#endif
+XIM XvaOpenIM( Display*, XrmDatabase, char*, char*, ... );
+
+extern Status XCloseIM(XIM);
+
+#ifndef XIMCallback1
+typedef int (*XIMProc1)(XIC, XPointer, XPointer);
+typedef struct {
+ XPointer client_data;
+ XIMProc1 callback;
+} XIMCallback1;
+#endif
+
+typedef struct _XIMAnnotation {
+ int start_position;
+ int end_position;
+ XPointer data;
+} XIMAnnotation;
+
+/*
+ XIMUText: XIMText extention for UTF16
+ */
+typedef struct _XIMUnicodeText {
+ unsigned short length;
+ XIMFeedback *feedback;
+ Bool encoding_is_wchar;
+ union {
+ char *multi_byte;
+ wchar_t *wide_char;
+ unsigned short *utf16_char;
+ } string;
+ unsigned int count_annotations;
+ XIMAnnotation *annotations;
+} XIMUnicodeText;
+
+/* lookup choice */
+typedef enum {
+ XIMDrawUpHorizontally = 0 ,
+ XIMDrawUpVertically = 1
+} XIMDrawUpDirection ;
+
+typedef struct _XIMLookupStartCallbackStruct {
+ int choice_per_window; /* Number of choices can be display
+ * in the region
+ */
+ int nrows;
+ int ncolumns;
+ XIMDrawUpDirection draw_up_direction;
+} XIMLookupStartCallbackStruct;
+
+typedef struct _XIMUnicodeChoiceObject {
+ XIMUnicodeText *label;
+ XIMUnicodeText *value;
+} XIMUnicodeChoiceObject;
+
+typedef struct _XIMLookupDrawCallbackStruct {
+ XIMUnicodeChoiceObject *choices; /* the lookup choices */
+ int n_choices; /* Total number of lookup choices */
+ int first_index;
+ int last_index;
+ int current_index;
+ XIMUnicodeText *title;
+} XIMLookupDrawCallbackStruct;
+
+/* Unicode Subset */
+typedef enum {
+ XIMKatakana, XIMHanzi
+} XIMUnicodeCharacterSubsetID;
+
+typedef struct _XIMUncodeSubset {
+ XIMUnicodeCharacterSubsetID index;
+ XIMUnicodeCharacterSubsetID subset_id;
+ char *name;
+ Bool is_active;
+} XIMUnicodeCharacterSubset;
+
+typedef struct _XIMUncodeSubsets {
+ unsigned short count_subsets;
+ XIMUnicodeCharacterSubset *supported_subsets;
+} XIMUnicodeCharacterSubsets;
+
+typedef struct _XIMSwitchIMNotifyCallbackStruct {
+ XIMUnicodeCharacterSubset *from;
+ XIMUnicodeCharacterSubset *to;
+} XIMSwitchIMNotifyCallbackStruct;
+
+/* XIM attributes for multilingual IM extension */
+#define XNMultiLingualInput "multiLingualInput"
+#define XNQueryUnicodeCharacterSubset "unicodeCharacterSubset"
+
+/* XIC attributes for multilingual IM extension */
+
+#define XNUnicodeCharacterSubset "UnicodeChararcterSubset"
+
+#define XNSwitchIMNotifyCallback "switchIMNotifyCallback"
+#define XNCommitStringCallback "commitStringCallback"
+#define XNForwardEventCallback "forwardEventCallback"
+
+#define XNLookupStartCallback "lookupStartCallback"
+#define XNLookupDrawCallback "lookupDrawCallback"
+#define XNLookupDoneCallback "lookupDoneCallback"
+
+#endif
diff --git a/vcl/unx/inc/Xproto.h b/vcl/unx/inc/Xproto.h
new file mode 100644
index 000000000000..804b3ffa98cc
--- /dev/null
+++ b/vcl/unx/inc/Xproto.h
@@ -0,0 +1,49 @@
+/*************************************************************************
+ *
+ * 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 INCLUDED_VCL_UNX_INC_XPROTO_H
+#define INCLUDED_VCL_UNX_INC_XPROTO_H
+
+#include "sal/config.h"
+
+#include <tools/prex.h>
+
+#if defined __GNUC__
+#pragma GCC system_header
+#elif defined __SUNPRO_CC
+#pragma disable_warn
+#endif
+
+#include <X11/Xproto.h>
+
+#if defined __SUNPRO_CC
+#pragma enable_warn
+#endif
+
+#include <tools/postx.h>
+
+#endif
diff --git a/vcl/unx/inc/cdeint.hxx b/vcl/unx/inc/cdeint.hxx
new file mode 100644
index 000000000000..91cbf33caf47
--- /dev/null
+++ b/vcl/unx/inc/cdeint.hxx
@@ -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 _SV_CDEINT_HXX
+#define _SV_CDEINT_HXX
+
+#include <dtint.hxx>
+
+class CDEIntegrator : public DtIntegrator
+{
+ friend DtIntegrator* DtIntegrator::CreateDtIntegrator();
+private:
+ CDEIntegrator();
+
+public:
+ virtual ~CDEIntegrator();
+
+ virtual void GetSystemLook( AllSettings& rSettings );
+};
+
+#endif
diff --git a/vcl/unx/inc/dtint.hxx b/vcl/unx/inc/dtint.hxx
new file mode 100644
index 000000000000..75f197c81e13
--- /dev/null
+++ b/vcl/unx/inc/dtint.hxx
@@ -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.
+ *
+ ************************************************************************/
+#ifndef _SV_DTINT_HXX
+#define _SV_DTINT_HXX
+
+#include <tools/link.hxx>
+#include <tools/string.hxx>
+#include <tools/color.hxx>
+#include <vcl/font.hxx>
+
+class SalBitmap;
+class SalDisplay;
+class AllSettings;
+
+#ifndef _XLIB_H_
+// forwards from X
+struct Display;
+struct XEvent;
+#define Atom UINT32
+#define XLIB_Window UINT32
+#endif
+
+enum DtType {
+ DtGeneric,
+ DtCDE
+};
+
+class DtIntegrator
+{
+protected:
+ DtType meType;
+ Display* mpDisplay;
+ SalDisplay* mpSalDisplay;
+ int mnSystemLookCommandProcess;
+
+
+ DtIntegrator();
+
+ static String aHomeDir;
+
+public:
+ static DtIntegrator* CreateDtIntegrator();
+
+ virtual ~DtIntegrator();
+
+ // SystemLook
+ virtual void GetSystemLook( AllSettings& rSettings );
+
+ DtType GetDtType() { return meType; }
+ SalDisplay* GetSalDisplay() { return mpSalDisplay; }
+ Display* GetDisplay() { return mpDisplay; }
+};
+
+#endif
diff --git a/vcl/unx/inc/i18n_cb.hxx b/vcl/unx/inc/i18n_cb.hxx
new file mode 100644
index 000000000000..d2301c26a3b0
--- /dev/null
+++ b/vcl/unx/inc/i18n_cb.hxx
@@ -0,0 +1,95 @@
+/*************************************************************************
+ *
+ * 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 _SAL_I18N_CALLBACK_HXX
+#define _SAL_I18N_CALLBACK_HXX
+
+#include <vcl/salwtype.hxx>
+#include <vector>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// for iiimp / ml input
+int CommitStringCallback( XIC ic, XPointer client_data, XPointer call_data);
+
+// xim callbacks
+void PreeditDoneCallback ( XIC ic, XPointer client_data, XPointer call_data);
+int PreeditStartCallback( XIC ic, XPointer client_data, XPointer call_data);
+void PreeditDoneCallback ( XIC ic, XPointer client_data, XPointer call_data);
+void PreeditDrawCallback ( XIC ic, XPointer client_data,
+ XIMPreeditDrawCallbackStruct *call_data );
+void PreeditCaretCallback( XIC ic, XPointer client_data,
+ XIMPreeditCaretCallbackStruct *call_data );
+void GetPreeditSpotLocation(XIC ic, XPointer client_data);
+
+// private hook to prevent from sending further edit events
+void PreeditCancelCallback( XPointer client_data );
+
+void StatusStartCallback (XIC ic, XPointer client_data, XPointer call_data);
+void StatusDoneCallback (XIC ic, XPointer client_data, XPointer call_data);
+void StatusDrawCallback (XIC ic, XPointer client_data,
+ XIMStatusDrawCallbackStruct *call_data);
+void SwitchIMCallback (XIC ix, XPointer client_data, XPointer call_data );
+
+// keep informed if kinput2 crashed again
+void IC_IMDestroyCallback (XIM im, XPointer client_data, XPointer call_data);
+void IM_IMDestroyCallback (XIM im, XPointer client_data, XPointer call_data);
+
+Bool IsControlCode(sal_Unicode nChar);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+typedef struct {
+ sal_Unicode *pUnicodeBuffer;
+ XIMFeedback *pCharStyle;
+ unsigned int nCursorPos;
+ unsigned int nLength;
+ unsigned int nSize;
+} preedit_text_t;
+
+class SalFrame;
+
+typedef enum {
+ ePreeditStatusDontKnow = 0,
+ ePreeditStatusActive,
+ ePreeditStatusActivationRequired,
+ ePreeditStatusStartPending
+} preedit_status_t;
+
+typedef struct {
+ SalFrame* pFrame;
+ Bool bIsMultilingual;
+ preedit_status_t eState;
+ preedit_text_t aText;
+ SalExtTextInputEvent aInputEv;
+ std::vector< USHORT > aInputFlags;
+} preedit_data_t;
+
+#endif /* _SAL_I18N_CALLBACK_HXX */
diff --git a/vcl/unx/inc/i18n_ic.hxx b/vcl/unx/inc/i18n_ic.hxx
new file mode 100644
index 000000000000..2fb97a00b6f2
--- /dev/null
+++ b/vcl/unx/inc/i18n_ic.hxx
@@ -0,0 +1,100 @@
+/*************************************************************************
+ *
+ * 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 _SAL_I18N_INPUTCONTEXT_HXX
+#define _SAL_I18N_INPUTCONTEXT_HXX
+
+#include <i18npool/lang.h>
+#include "i18n_cb.hxx"
+
+class SalI18N_InputContext
+{
+
+private:
+
+ Bool mbUseable; // system supports current locale ?
+ Bool mbMultiLingual; // system supports iiimp ?
+ XIC maContext;
+
+ XIMStyle mnSupportedStatusStyle;
+ XIMStyle mnSupportedPreeditStyle;
+ XIMStyle mnStatusStyle;
+ XIMStyle mnPreeditStyle;
+
+ preedit_data_t maClientData;
+ XIMCallback maPreeditStartCallback;
+ XIMCallback maPreeditDoneCallback;
+ XIMCallback maPreeditDrawCallback;
+ XIMCallback maPreeditCaretCallback;
+ XIMCallback maCommitStringCallback;
+ XIMCallback maSwitchIMCallback;
+ XIMCallback maDestroyCallback;
+
+ XVaNestedList mpAttributes;
+ XVaNestedList mpStatusAttributes;
+ XVaNestedList mpPreeditAttributes;
+
+ Bool SupportInputMethodStyle( XIMStyles *pIMStyles );
+ unsigned int GetWeightingOfIMStyle( XIMStyle n_style ) const ;
+ Bool IsSupportedIMStyle( XIMStyle n_style ) const ;
+
+public:
+
+ Bool UseContext() { return mbUseable; }
+ Bool IsMultiLingual() { return mbMultiLingual; }
+ Bool IsPreeditMode() { return maClientData.eState == ePreeditStatusActive; }
+ XIC GetContext() { return maContext; }
+
+ void ExtendEventMask( XLIB_Window aFocusWindow );
+ void SetICFocus( SalFrame* pFocusFrame );
+ void UnsetICFocus( SalFrame* pFrame );
+ void HandleDestroyIM();
+
+ int HandleKeyEvent( XKeyEvent *pEvent, SalFrame *pFrame ); // unused
+ void EndExtTextInput( USHORT nFlags ); // unused
+ int CommitStringCallback( sal_Unicode* pText, sal_Size nLength );
+ int CommitKeyEvent( sal_Unicode* pText, sal_Size nLength );
+ int UpdateSpotLocation();
+
+ void Map( SalFrame *pFrame );
+ void Unmap( SalFrame* pFrame );
+
+ void SetPreeditState(Bool aPreeditState);
+ void SetLanguage(LanguageType aInputLanguage);
+
+ SalI18N_InputContext( SalFrame *aFrame );
+ ~SalI18N_InputContext();
+
+private:
+
+ SalI18N_InputContext(); // do not use this
+
+};
+
+#endif // _SAL_I18N_INPUTCONTEXT_HXX
+
+
diff --git a/vcl/unx/inc/i18n_im.hxx b/vcl/unx/inc/i18n_im.hxx
new file mode 100644
index 000000000000..297bc8edec17
--- /dev/null
+++ b/vcl/unx/inc/i18n_im.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SAL_I18N_INPUTMETHOD_HXX
+#define _SAL_I18N_INPUTMETHOD_HXX
+
+#include <vcl/dllapi.h>
+
+extern "C" char* GetMethodName( XIMStyle nStyle, char *pBuf, int nBufSize);
+
+#define bUseInputMethodDefault True
+
+class VCL_DLLPUBLIC SalI18N_InputMethod
+{
+ Bool mbUseable; // system supports locale as well as status
+ // and preedit style ?
+ Bool mbMultiLingual; // system supports iiimp
+ XIM maMethod;
+ XIMCallback maDestroyCallback;
+ XIMStyles *mpStyles;
+
+public:
+
+ Bool IsMultiLingual() { return mbMultiLingual; }
+ Bool PosixLocale();
+ Bool UseMethod() { return mbUseable; }
+ XIM GetMethod() { return maMethod; }
+ void HandleDestroyIM();
+ Bool CreateMethod( Display *pDisplay );
+ XIMStyles *GetSupportedStyles() { return mpStyles; }
+ Bool SetLocale( const char* pLocale = "" );
+ Bool FilterEvent( XEvent *pEvent, XLIB_Window window );
+ Bool AddConnectionWatch (Display *pDisplay, void *pConnectionHandler);
+
+ #ifdef _USE_PRINT_EXTENSION_
+ void Invalidate() { mbUseable = False; }
+ #endif
+
+ SalI18N_InputMethod();
+ ~SalI18N_InputMethod();
+};
+
+#endif // _SAL_I18N_INPUTMETHOD_HXX
+
+
diff --git a/vcl/unx/inc/i18n_keysym.hxx b/vcl/unx/inc/i18n_keysym.hxx
new file mode 100644
index 000000000000..641d00dc02c0
--- /dev/null
+++ b/vcl/unx/inc/i18n_keysym.hxx
@@ -0,0 +1,71 @@
+/*************************************************************************
+ *
+ * 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 _SAL_I18N_KEYSYM_HXX
+#define _SAL_I18N_KEYSYM_HXX
+
+/*
+ convert a keysym as defined in /usr/{X11R6|openwin}/include/X11/keysymdef.h
+ to unicode
+
+ supported charsets: (byte1 and byte2 are always 0x0)
+
+ Latin-1 Byte 3 = 0x00
+ Latin-2 Byte 3 = 0x01
+ Latin-3 Byte 3 = 0x02
+ Latin-4 Byte 3 = 0x03
+ Kana Byte 3 = 0x04
+ Arabic Byte 3 = 0x05
+ Cyrillic Byte 3 = 0x06
+ Greek Byte 3 = 0x07
+ Technical Byte 3 = 0x08
+ Special Byte 3 = 0x09
+ Publishing Byte 3 = 0x0a = 10
+ APL Byte 3 = 0x0b = 11
+ Hebrew Byte 3 = 0x0c = 12
+ Thai Byte 3 = 0x0d = 13
+ Korean Byte 3 = 0x0e = 14
+ Latin-9 Byte 3 = 0x13 = 19
+ Currency Byte 3 = 0x20 = 32
+ Keyboard Byte 3 = 0xff = 255
+
+ missing charsets:
+
+ Latin-8 Byte 3 = 0x12 = 18
+ Armenian Byte 3 = 0x14 = 20
+ Georgian Byte 3 = 0x15 = 21
+ Azeri Byte 3 = 0x16 = 22
+ Vietnamese Byte 3 = 0x1e = 30
+
+ of course not all keysyms can be mapped to a unicode code point
+*/
+
+sal_Unicode KeysymToUnicode (KeySym nKeySym);
+
+#endif /* _SAL_I18N_KEYSYM_HXX */
+
+
diff --git a/vcl/unx/inc/i18n_status.hxx b/vcl/unx/inc/i18n_status.hxx
new file mode 100644
index 000000000000..7202cf6e0eef
--- /dev/null
+++ b/vcl/unx/inc/i18n_status.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SAL_I18N_STATUS_HXX
+#define _SAL_I18N_STATUS_HXX
+
+#include <tools/string.hxx>
+#include <tools/link.hxx>
+#include <tools/gen.hxx>
+
+#ifndef _RTL_USTRING_HXX
+#include <rtl/ustring.hxx>
+#endif
+#include <vcl/salimestatus.hxx>
+
+#include <vector>
+
+class SalFrame;
+class WorkWindow;
+class ListBox;
+class FixedText;
+class PushButton;
+class SalI18N_InputContext;
+
+namespace vcl
+{
+
+class StatusWindow;
+
+class X11ImeStatus : public SalI18NImeStatus
+{
+public:
+ X11ImeStatus() {}
+ virtual ~X11ImeStatus();
+
+ virtual bool canToggle();
+ virtual void toggle();
+};
+
+class I18NStatus
+{
+public:
+ struct ChoiceData
+ {
+ String aString;
+ void* pData;
+ };
+private:
+ SalFrame* m_pParent;
+ StatusWindow* m_pStatusWindow;
+ String m_aCurrentIM;
+ ::std::vector< ChoiceData > m_aChoices;
+
+ I18NStatus();
+ ~I18NStatus();
+
+ static I18NStatus* pInstance;
+
+ static bool getStatusWindowMode();
+
+public:
+ static I18NStatus& get();
+ static bool exists();
+ static void free();
+
+ void setParent( SalFrame* pParent );
+ SalFrame* getParent() const { return m_pParent; }
+ SalFrame* getStatusFrame() const;
+
+ void setStatusText( const String& rText );
+ String getStatusText() const;
+
+ enum ShowReason { focus, presentation, contextmap };
+ void show( bool bShow, ShowReason eReason );
+
+ const ::std::vector< ChoiceData >& getChoices() const { return m_aChoices; }
+ void clearChoices();
+ void addChoice( const String&, void* pData );
+
+ void toTop() const;
+
+ // for SwitchIMCallback
+ void changeIM( const String& );
+
+ // External Control:
+
+ /** Return true if the status window can be toggled on and off externally.
+ */
+ bool canToggleStatusWindow() const;
+
+ /** Toggle the status window on or off.
+
+ This only works if canToggleStatusWindow returns true (otherwise, any
+ calls of this method are ignored).
+ */
+ void toggleStatusWindow();
+};
+
+} // namespace
+
+#endif // _SAL_I18N_STATUS_HXX
diff --git a/vcl/unx/inc/i18n_xkb.hxx b/vcl/unx/inc/i18n_xkb.hxx
new file mode 100644
index 000000000000..db6517cbea0b
--- /dev/null
+++ b/vcl/unx/inc/i18n_xkb.hxx
@@ -0,0 +1,115 @@
+/*************************************************************************
+ *
+ * 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 _SAL_I18N_XKBDEXTENSION_HXX
+#define _SAL_I18N_XKBDEXTENSION_HXX
+
+#include <sal/types.h>
+#include <vcl/dllapi.h>
+
+class VCL_DLLPUBLIC SalI18N_KeyboardExtension
+{
+private:
+
+ sal_Bool mbUseExtension;
+ sal_uInt32 mnDefaultGroup;
+ sal_uInt32 mnGroup;
+ int mnEventBase;
+ int mnErrorBase;
+ Display* mpDisplay;
+
+public:
+
+ SalI18N_KeyboardExtension( Display *pDisplay );
+ inline ~SalI18N_KeyboardExtension();
+
+ inline sal_Bool UseExtension() const ; // server and client support the
+ // extension
+ inline void UseExtension( sal_Bool bState );// used to disable the Extension
+
+ void Dispatch( XEvent *pEvent ); // keep track of group changes
+
+ sal_uInt32 LookupKeysymInGroup( sal_uInt32 nKeyCode,
+ sal_uInt32 nShiftState,
+ sal_uInt32 nGroup ) const ;
+
+ inline sal_uInt32 LookupKeysymInDefaultGroup(
+ sal_uInt32 nKeyCode,
+ sal_uInt32 nShiftState ) const ;
+ inline sal_uInt32 GetGroup() const ; // the current keyboard group
+ inline sal_uInt32 GetDefaultGroup() const ; // base group, usually group 1
+ inline int GetEventBase() const ;
+
+protected:
+
+ SalI18N_KeyboardExtension(); // disabled
+};
+
+inline
+SalI18N_KeyboardExtension::~SalI18N_KeyboardExtension()
+{
+}
+
+inline sal_Bool
+SalI18N_KeyboardExtension::UseExtension() const
+{
+ return mbUseExtension;
+}
+
+inline void
+SalI18N_KeyboardExtension::UseExtension( sal_Bool bState )
+{
+ mbUseExtension = mbUseExtension && bState;
+}
+
+inline sal_uInt32
+SalI18N_KeyboardExtension::LookupKeysymInDefaultGroup( sal_uInt32 nKeyCode,
+ sal_uInt32 nShiftState ) const
+{
+ return LookupKeysymInGroup( nKeyCode, nShiftState, mnDefaultGroup );
+}
+
+inline sal_uInt32
+SalI18N_KeyboardExtension::GetGroup() const
+{
+ return mnGroup;
+}
+
+inline sal_uInt32
+SalI18N_KeyboardExtension::GetDefaultGroup() const
+{
+ return mnDefaultGroup;
+}
+
+inline int
+SalI18N_KeyboardExtension::GetEventBase() const
+{
+ return mnEventBase;
+}
+
+#endif // _SAL_I18N_XKBDEXTENSION_HXX
+
diff --git a/vcl/unx/inc/plugins/gtk/atkbridge.hxx b/vcl/unx/inc/plugins/gtk/atkbridge.hxx
new file mode 100644
index 000000000000..959b3aec1fb1
--- /dev/null
+++ b/vcl/unx/inc/plugins/gtk/atkbridge.hxx
@@ -0,0 +1,36 @@
+/*************************************************************************
+ *
+ * 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 __ATK_BRIDGE_HXX__
+#define __ATK_BRIDGE_HXX__
+
+#include <vcl/dllapi.h>
+
+bool VCL_DLLPUBLIC InitAtkBridge(void);
+void VCL_DLLPUBLIC DeInitAtkBridge(void);
+
+#endif
diff --git a/vcl/unx/inc/plugins/gtk/gtkdata.hxx b/vcl/unx/inc/plugins/gtk/gtkdata.hxx
new file mode 100644
index 000000000000..d4dec957a6b3
--- /dev/null
+++ b/vcl/unx/inc/plugins/gtk/gtkdata.hxx
@@ -0,0 +1,89 @@
+/*************************************************************************
+ *
+ * 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_GTKDATA_HXX
+#define _VCL_GTKDATA_HXX
+
+#include <tools/prex.h>
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+#include <tools/postx.h>
+
+#include <saldisp.hxx>
+#include <saldata.hxx>
+#include <vcl/ptrstyle.hxx>
+
+#include <list>
+
+class GtkData : public X11SalData
+{
+public:
+ GtkData() {}
+ virtual ~GtkData();
+
+ virtual void Init();
+
+ virtual void initNWF();
+ virtual void deInitNWF();
+};
+
+class GtkSalFrame;
+
+class GtkSalDisplay : public SalDisplay
+{
+ GdkDisplay* m_pGdkDisplay;
+ GdkCursor *m_aCursors[ POINTER_COUNT ];
+ bool m_bStartupCompleted;
+ GdkCursor* getFromXPM( const char *pBitmap, const char *pMask,
+ int nWidth, int nHeight, int nXHot, int nYHot );
+public:
+ GtkSalDisplay( GdkDisplay* pDisplay );
+ virtual ~GtkSalDisplay();
+
+ GdkDisplay* GetGdkDisplay() const { return m_pGdkDisplay; }
+
+ virtual void deregisterFrame( SalFrame* pFrame );
+ GdkCursor *getCursor( PointerStyle ePointerStyle );
+ virtual int CaptureMouse( SalFrame* pFrame );
+ virtual long Dispatch( XEvent *pEvent );
+ virtual void initScreen( int nScreen ) const;
+
+ static GdkFilterReturn filterGdkEvent( GdkXEvent* sys_event,
+ GdkEvent* event,
+ gpointer data );
+ inline bool HasMoreEvents() { return m_aUserEvents.size() > 1; }
+ inline void EventGuardAcquire() { osl_acquireMutex( hEventGuard_ ); }
+ inline void EventGuardRelease() { osl_releaseMutex( hEventGuard_ ); }
+ void startupNotificationCompleted() { m_bStartupCompleted = true; }
+
+ void screenSizeChanged( GdkScreen* );
+ void monitorsChanged( GdkScreen* );
+};
+
+
+#endif // _VCL_GTKDATA_HXX
diff --git a/vcl/unx/inc/plugins/gtk/gtkframe.hxx b/vcl/unx/inc/plugins/gtk/gtkframe.hxx
new file mode 100644
index 000000000000..18dd476fc2c4
--- /dev/null
+++ b/vcl/unx/inc/plugins/gtk/gtkframe.hxx
@@ -0,0 +1,403 @@
+/*************************************************************************
+ *
+ * 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_GTKFRAME_HXX
+#define _VCL_GTKFRAME_HXX
+
+#include <tools/prex.h>
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#include <gdk/gdkkeysyms.h>
+#include <tools/postx.h>
+
+#include <vcl/salframe.hxx>
+#include <vcl/sysdata.hxx>
+
+#include <list>
+#include <vector>
+
+class GtkSalGraphics;
+class GtkSalDisplay;
+
+class GtkSalFrame : public SalFrame
+{
+ static const int nMaxGraphics = 2;
+
+ struct GraphicsHolder
+ {
+ GtkSalGraphics* pGraphics;
+ bool bInUse;
+ GraphicsHolder()
+ : pGraphics( NULL ),
+ bInUse( false )
+ {}
+ ~GraphicsHolder();
+ };
+
+ struct IMHandler
+ {
+ //--------------------------------------------------------
+ // Not all GTK Input Methods swallow key release
+ // events. Since they swallow the key press events and we
+ // are left with the key release events, we need to
+ // manually swallow those. To do this, we keep a list of
+ // the previous 10 key press events in each GtkSalFrame
+ // and when we get a key release that matches one of the
+ // key press events in our list, we swallow it.
+ struct PreviousKeyPress
+ {
+ GdkWindow *window;
+ gint8 send_event;
+ guint32 time;
+ guint state;
+ guint keyval;
+ guint16 hardware_keycode;
+ guint8 group;
+
+ PreviousKeyPress (GdkEventKey *event)
+ : window (NULL),
+ send_event (0),
+ time (0),
+ state (0),
+ keyval (0),
+ hardware_keycode (0),
+ group (0)
+ {
+ if (event)
+ {
+ window = event->window;
+ send_event = event->send_event;
+ time = event->time;
+ state = event->state;
+ keyval = event->keyval;
+ hardware_keycode = event->hardware_keycode;
+ group = event->group;
+ }
+ }
+
+ PreviousKeyPress( const PreviousKeyPress& rPrev )
+ : window( rPrev.window ),
+ send_event( rPrev.send_event ),
+ time( rPrev.time ),
+ state( rPrev.state ),
+ keyval( rPrev.keyval ),
+ hardware_keycode( rPrev.hardware_keycode ),
+ group( rPrev.group )
+ {}
+
+ bool operator== (GdkEventKey *event) const
+ {
+ return (event != NULL)
+ && (event->window == window)
+ && (event->send_event == send_event)
+ && (event->state == state)
+ && (event->keyval == keyval)
+ && (event->hardware_keycode == hardware_keycode)
+ && (event->group == group)
+ && (event->time - time < 3)
+ ;
+ }
+ };
+
+
+ GtkSalFrame* m_pFrame;
+ std::list< PreviousKeyPress > m_aPrevKeyPresses;
+ int m_nPrevKeyPresses; // avoid using size()
+ GtkIMContext* m_pIMContext;
+ bool m_bFocused;
+ bool m_bPreeditJustChanged;
+ SalExtTextInputEvent m_aInputEvent;
+ std::vector< USHORT > m_aInputFlags;
+
+ IMHandler( GtkSalFrame* );
+ ~IMHandler();
+
+ void createIMContext();
+ void deleteIMContext();
+ void updateIMSpotLocation();
+ void setInputContext( SalInputContext* pContext );
+ void endExtTextInput( USHORT nFlags );
+ bool handleKeyEvent( GdkEventKey* pEvent );
+ void focusChanged( bool bFocusIn );
+
+ void doCallEndExtTextInput();
+ void sendEmptyCommit();
+
+
+ static void signalIMCommit( GtkIMContext*, gchar*, gpointer );
+ static gboolean signalIMDeleteSurrounding( GtkIMContext*, gint, gint, gpointer );
+ static void signalIMPreeditChanged( GtkIMContext*, gpointer );
+ static void signalIMPreeditEnd( GtkIMContext*, gpointer );
+ static void signalIMPreeditStart( GtkIMContext*, gpointer );
+ static gboolean signalIMRetrieveSurrounding( GtkIMContext*, gpointer );
+ };
+ friend struct IMHandler;
+
+ int m_nScreen;
+ GtkWidget* m_pWindow;
+ GdkWindow* m_pForeignParent;
+ GdkNativeWindow m_aForeignParentWindow;
+ GdkWindow* m_pForeignTopLevel;
+ GdkNativeWindow m_aForeignTopLevelWindow;
+ Pixmap m_hBackgroundPixmap;
+ ULONG m_nStyle;
+ SalExtStyle m_nExtStyle;
+ GtkFixed* m_pFixedContainer;
+ GtkSalFrame* m_pParent;
+ std::list< GtkSalFrame* > m_aChildren;
+ GdkWindowState m_nState;
+ SystemEnvData m_aSystemData;
+ GraphicsHolder m_aGraphics[ nMaxGraphics ];
+ USHORT m_nKeyModifiers;
+ GdkCursor *m_pCurrentCursor;
+ GdkVisibilityState m_nVisibility;
+ PointerStyle m_ePointerStyle;
+ int m_nSavedScreenSaverTimeout;
+ guint m_nGSMCookie;
+ int m_nWorkArea;
+ bool m_bFullscreen;
+ bool m_bSingleAltPress;
+ bool m_bDefaultPos;
+ bool m_bDefaultSize;
+ bool m_bSendModChangeOnRelease;
+ bool m_bWindowIsGtkPlug;
+ bool m_bSetFocusOnMap;
+ String m_aTitle;
+
+ IMHandler* m_pIMHandler;
+
+ Size m_aMaxSize;
+ Size m_aMinSize;
+ Rectangle m_aRestorePosSize;
+
+ GdkRegion* m_pRegion;
+
+ void Init( SalFrame* pParent, ULONG nStyle );
+ void Init( SystemParentData* pSysData );
+ void InitCommon();
+
+ // signals
+ static gboolean signalButton( GtkWidget*, GdkEventButton*, gpointer );
+ static void signalStyleSet( GtkWidget*, GtkStyle* pPrevious, gpointer );
+ static gboolean signalExpose( GtkWidget*, GdkEventExpose*, gpointer );
+ static gboolean signalFocus( GtkWidget*, GdkEventFocus*, gpointer );
+ static gboolean signalMap( GtkWidget*, GdkEvent*, gpointer );
+ static gboolean signalUnmap( GtkWidget*, GdkEvent*, gpointer );
+ static gboolean signalConfigure( GtkWidget*, GdkEventConfigure*, gpointer );
+ static gboolean signalMotion( GtkWidget*, GdkEventMotion*, gpointer );
+ static gboolean signalKey( GtkWidget*, GdkEventKey*, gpointer );
+ static gboolean signalDelete( GtkWidget*, GdkEvent*, gpointer );
+ static gboolean signalState( GtkWidget*, GdkEvent*, gpointer );
+ static gboolean signalScroll( GtkWidget*, GdkEvent*, gpointer );
+ static gboolean signalCrossing( GtkWidget*, GdkEventCrossing*, gpointer );
+ static gboolean signalVisibility( GtkWidget*, GdkEventVisibility*, gpointer );
+ static void signalDestroy( GtkObject*, gpointer );
+
+ void Center();
+ void SetDefaultSize();
+ void setAutoLock( bool bLock );
+ void setScreenSaverTimeout( int nTimeout );
+
+ void doKeyCallback( guint state,
+ guint keyval,
+ guint16 hardware_keycode,
+ guint8 group,
+ guint32 time,
+ sal_Unicode aOrigCode,
+ bool bDown,
+ bool bSendRelease
+ );
+
+
+ GdkNativeWindow findTopLevelSystemWindow( GdkNativeWindow aWindow );
+
+ static int m_nFloats;
+
+ bool isFloatGrabWindow() const
+ {
+ return
+ (m_nStyle & SAL_FRAME_STYLE_FLOAT) && // only a float can be floatgrab
+ !(m_nStyle & SAL_FRAME_STYLE_TOOLTIP) && // tool tips are not
+ !(m_nStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) && // toolbars are also not
+ !(m_nStyle & SAL_FRAME_STYLE_FLOAT_FOCUSABLE); // focusable floats are not
+ }
+
+ bool isChild( bool bPlug = true, bool bSysChild = true )
+ {
+ ULONG nMask = 0;
+ if( bPlug )
+ nMask |= SAL_FRAME_STYLE_PLUG;
+ if( bSysChild )
+ nMask |= SAL_FRAME_STYLE_SYSTEMCHILD;
+ return (m_nStyle & nMask) != 0;
+ }
+
+ void resizeWindow( long nWidth, long nHeight );
+ void moveWindow( long nX, long nY );
+
+ Size calcDefaultSize();
+
+ void setMinMaxSize();
+ void createNewWindow( XLIB_Window aParent, bool bXEmbed, int nScreen );
+ void askForXEmbedFocus( sal_Int32 nTimecode );
+public:
+ GtkSalFrame( SalFrame* pParent, ULONG nStyle );
+ GtkSalFrame( SystemParentData* pSysData );
+
+ // dispatches an event, returns true if dispatched
+ // and false else; if true was returned the event should
+ // be swallowed
+ bool Dispatch( const XEvent* pEvent );
+ void grabPointer( BOOL bGrab, BOOL bOwnerEvents = FALSE );
+
+ GtkSalDisplay* getDisplay();
+ GdkDisplay* getGdkDisplay();
+ GtkWidget* getWindow() const { return m_pWindow; }
+ GtkFixed* getFixedContainer() const { return m_pFixedContainer; }
+ GdkWindow* getForeignParent() const { return m_pForeignParent; }
+ GdkNativeWindow getForeignParentWindow() const { return m_aForeignParentWindow; }
+ GdkWindow* getForeignTopLevel() const { return m_pForeignTopLevel; }
+ GdkNativeWindow getForeignTopLevelWindow() const { return m_aForeignTopLevelWindow; }
+ GdkVisibilityState getVisibilityState() const
+ { return m_nVisibility; }
+ Pixmap getBackgroundPixmap() const { return m_hBackgroundPixmap; }
+ int getScreenNumber() const { return m_nScreen; }
+ void updateScreenNumber();
+
+ void moveToScreen( int nScreen );
+
+ virtual ~GtkSalFrame();
+
+ // SalGraphics or NULL, but two Graphics for all SalFrames
+ // must be returned
+ virtual SalGraphics* GetGraphics();
+ virtual void ReleaseGraphics( SalGraphics* pGraphics );
+
+ // Event must be destroyed, when Frame is destroyed
+ // When Event is called, SalInstance::Yield() must be returned
+ virtual BOOL PostEvent( void* pData );
+
+ virtual void SetTitle( const XubString& rTitle );
+ virtual void SetIcon( USHORT nIcon );
+ virtual void SetMenu( SalMenu *pSalMenu );
+ virtual void DrawMenuBar();
+
+ virtual void SetExtendedFrameStyle( SalExtStyle nExtStyle );
+ // Before the window is visible, a resize event
+ // must be sent with the correct size
+ virtual void Show( BOOL bVisible, BOOL bNoActivate = FALSE );
+ virtual void Enable( BOOL bEnable );
+ // Set ClientSize and Center the Window to the desktop
+ // and send/post a resize message
+ virtual void SetMinClientSize( long nWidth, long nHeight );
+ virtual void SetMaxClientSize( long nWidth, long nHeight );
+ virtual void SetPosSize( long nX, long nY, long nWidth, long nHeight, USHORT nFlags );
+ virtual void GetClientSize( long& rWidth, long& rHeight );
+ virtual void GetWorkArea( Rectangle& rRect );
+ virtual SalFrame* GetParent() const;
+ virtual void SetWindowState( const SalFrameState* pState );
+ virtual BOOL GetWindowState( SalFrameState* pState );
+ virtual void ShowFullScreen( BOOL bFullScreen, sal_Int32 nDisplay );
+ // Enable/Disable ScreenSaver, SystemAgents, ...
+ virtual void StartPresentation( BOOL bStart );
+ // Show Window over all other Windows
+ virtual void SetAlwaysOnTop( BOOL bOnTop );
+
+ // Window to top and grab focus
+ virtual void ToTop( USHORT nFlags );
+
+ // this function can call with the same
+ // pointer style
+ virtual void SetPointer( PointerStyle ePointerStyle );
+ virtual void CaptureMouse( BOOL bMouse );
+ virtual void SetPointerPos( long nX, long nY );
+
+ // flush output buffer
+ using SalFrame::Flush;
+ virtual void Flush();
+ // flush output buffer, wait till outstanding operations are done
+ virtual void Sync();
+
+ virtual void SetInputContext( SalInputContext* pContext );
+ virtual void EndExtTextInput( USHORT nFlags );
+
+ virtual String GetKeyName( USHORT nKeyCode );
+ virtual String GetSymbolKeyName( const XubString& rFontName, USHORT nKeyCode );
+ virtual BOOL MapUnicodeToKeyCode( sal_Unicode aUnicode, LanguageType aLangType, KeyCode& rKeyCode );
+
+ // returns the input language used for the last key stroke
+ // may be LANGUAGE_DONTKNOW if not supported by the OS
+ virtual LanguageType GetInputLanguage();
+
+ virtual SalBitmap* SnapShot();
+
+ virtual void UpdateSettings( AllSettings& rSettings );
+
+ virtual void Beep( SoundType eSoundType );
+
+ // returns system data (most prominent: window handle)
+ virtual const SystemEnvData* GetSystemData() const;
+
+
+ // get current modifier and button mask
+ virtual SalPointerState GetPointerState();
+
+ // set new parent window
+ virtual void SetParent( SalFrame* pNewParent );
+ // reparent window to act as a plugin; implementation
+ // may choose to use a new system window internally
+ // return false to indicate failure
+ virtual bool SetPluginParent( SystemParentData* pNewParent );
+
+ virtual void SetBackgroundBitmap( SalBitmap* );
+
+ virtual void SetScreenNumber( unsigned int );
+
+ // shaped system windows
+ // set clip region to none (-> rectangular windows, normal state)
+ virtual void ResetClipRegion();
+ // start setting the clipregion consisting of nRects rectangles
+ virtual void BeginSetClipRegion( ULONG nRects );
+ // add a rectangle to the clip region
+ virtual void UnionClipRegion( long nX, long nY, long nWidth, long nHeight );
+ // done setting up the clipregion
+ virtual void EndSetClipRegion();
+
+ static GtkSalFrame *getFromWindow( GtkWindow *pWindow );
+};
+
+
+#define OOO_TYPE_FIXED ooo_fixed_get_type()
+
+extern "C" {
+
+GType ooo_fixed_get_type( void );
+
+} // extern "C"
+
+#endif //_VCL_GTKFRAME_HXX
diff --git a/vcl/unx/inc/plugins/gtk/gtkgdi.hxx b/vcl/unx/inc/plugins/gtk/gtkgdi.hxx
new file mode 100644
index 000000000000..065b5435eeb0
--- /dev/null
+++ b/vcl/unx/inc/plugins/gtk/gtkgdi.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _VCL_GTKGDI_HXX
+#define _VCL_GTKGDI_HXX
+
+#include <tools/prex.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#include <gdk/gdkkeysyms.h>
+#include <tools/postx.h>
+
+#include <salgdi.h>
+
+class GtkSalGraphics : public X11SalGraphics
+{
+ GtkWidget *m_pWindow;
+ Region m_aClipRegion;
+
+public:
+ GtkSalGraphics( GtkWidget *window )
+ : m_pWindow( window ),
+ m_aClipRegion( REGION_NULL )
+ {}
+ virtual ~GtkSalGraphics();
+
+ inline GtkWidget* GetGtkWidget() const { return m_pWindow; }
+ inline GdkWindow* GetGdkWindow() const { return m_pWindow->window; }
+ inline GtkSalFrame* GetGtkFrame() const { return static_cast<GtkSalFrame*>(m_pFrame); }
+ void SetWindow( GtkWidget* window ) { m_pWindow = window; }
+
+
+ // will be set when UI theme was changed
+ static BOOL bThemeChanged;
+ static BOOL bNeedPixmapPaint;
+ static BOOL bGlobalNeedPixmapPaint;
+ static BOOL bToolbarGripWorkaround;
+ static BOOL bNeedButtonStyleAsEditBackgroundWorkaround;
+
+ // native widget methods
+ virtual BOOL IsNativeControlSupported( ControlType nType, ControlPart nPart );
+ virtual BOOL hitTestNativeControl( ControlType nType, ControlPart nPart, const Region& rControlRegion,
+ const Point& aPos, BOOL& rIsInside );
+ virtual BOOL drawNativeControl( ControlType nType, ControlPart nPart, const Region& rControlRegion,
+ ControlState nState, const ImplControlValue& aValue,
+ const rtl::OUString& rCaption );
+ virtual BOOL drawNativeControlText( ControlType nType, ControlPart nPart, const Region& rControlRegion,
+ ControlState nState, const ImplControlValue& aValue,
+ const rtl::OUString& rCaption );
+ virtual BOOL getNativeControlRegion( ControlType nType, ControlPart nPart, const Region& rControlRegion, ControlState nState,
+ const ImplControlValue& aValue, const rtl::OUString& rCaption,
+ Region &rNativeBoundingRegion, Region &rNativeContentRegion );
+
+ //helper methods for frame's UpdateSettings
+ void updateSettings( AllSettings& rSettings );
+
+ virtual void ResetClipRegion();
+ virtual void BeginSetClipRegion( ULONG nCount );
+ virtual BOOL unionClipRegion( long nX, long nY, long nWidth, long nHeight );
+ virtual bool unionClipRegion( const ::basegfx::B2DPolyPolygon& );
+ virtual void EndSetClipRegion();
+
+ // some themes set the background pixmap of our window EVERY time
+ // a control is painted; but presentation effects need
+ // the background set to None; workaround: set the background
+ // before copyBits
+ virtual void copyBits( const SalTwoRect* pPosAry,
+ SalGraphics* pSrcGraphics );
+
+protected:
+ typedef std::list< Rectangle > clipList;
+
+ GdkPixmap* NWGetPixmapFromScreen( Rectangle srcRect );
+ BOOL NWRenderPixmapToScreen( GdkPixmap* pPixmap, Rectangle dstRect );
+
+ BOOL NWPaintGTKButton( GdkDrawable* gdkDrawable, ControlType nType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState, const ImplControlValue& aValue,
+ const OUString& rCaption );
+ BOOL NWPaintGTKRadio( GdkDrawable* gdkDrawable, ControlType nType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState, const ImplControlValue& aValue,
+ const OUString& rCaption );
+ BOOL NWPaintGTKCheck( GdkDrawable* gdkDrawable, ControlType nType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState, const ImplControlValue& aValue,
+ const OUString& rCaption );
+ BOOL NWPaintGTKScrollbar( ControlType nType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState, const ImplControlValue& aValue,
+ const OUString& rCaption );
+ BOOL NWPaintGTKEditBox( GdkDrawable* gdkDrawable, ControlType nType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState, const ImplControlValue& aValue,
+ const OUString& rCaption );
+ BOOL NWPaintGTKSpinBox( ControlType nType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState, const ImplControlValue& aValue,
+ const OUString& rCaption );
+ BOOL NWPaintGTKComboBox( GdkDrawable* gdkDrawable, ControlType nType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState, const ImplControlValue& aValue,
+ const OUString& rCaption );
+ BOOL NWPaintGTKTabItem( ControlType nType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState, const ImplControlValue& aValue,
+ const OUString& rCaption );
+ BOOL NWPaintGTKListBox( GdkDrawable* gdkDrawable, ControlType nType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState, const ImplControlValue& aValue,
+ const OUString& rCaption );
+
+ BOOL NWPaintGTKToolbar( GdkDrawable* gdkDrawable, ControlType nType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState, const ImplControlValue& aValue,
+ const OUString& rCaption );
+ BOOL NWPaintGTKMenubar( GdkDrawable* gdkDrawable, ControlType nType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState, const ImplControlValue& aValue,
+ const OUString& rCaption );
+ BOOL NWPaintGTKPopupMenu( GdkDrawable* gdkDrawable, ControlType nType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState, const ImplControlValue& aValue,
+ const OUString& rCaption );
+ BOOL NWPaintGTKTooltip( GdkDrawable* gdkDrawable, ControlType nType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState, const ImplControlValue& aValue,
+ const OUString& rCaption );
+ BOOL NWPaintGTKProgress( GdkDrawable* gdkDrawable, ControlType nType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState, const ImplControlValue& aValue,
+ const OUString& rCaption );
+ BOOL NWPaintGTKSlider( GdkDrawable* gdkDrawable, ControlType nType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState, const ImplControlValue& aValue,
+ const OUString& rCaption );
+ BOOL NWPaintGTKListNode( GdkDrawable* gdkDrawable, ControlType nType, ControlPart nPart,
+ const Rectangle& rControlRectangle,
+ const clipList& rClipList,
+ ControlState nState, const ImplControlValue& aValue,
+ const OUString& rCaption );
+
+ BOOL drawNativeMixedStateCheck( ControlType nType, ControlPart nPart, const Region& rControlRegion,
+ ControlState nState, const ImplControlValue& aValue,
+ const rtl::OUString& rCaption );
+};
+
+#endif // _VCL_GTKGDI_HXX
diff --git a/vcl/unx/inc/plugins/gtk/gtkinst.hxx b/vcl/unx/inc/plugins/gtk/gtkinst.hxx
new file mode 100644
index 000000000000..ee07199cb266
--- /dev/null
+++ b/vcl/unx/inc/plugins/gtk/gtkinst.hxx
@@ -0,0 +1,105 @@
+/*************************************************************************
+ *
+ * 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_GTKINST_HXX
+#define _VCL_GTKINST_HXX
+
+#include <salinst.h>
+#include <salsys.h>
+
+class GtkYieldMutex : public SalYieldMutex
+{
+public:
+ GtkYieldMutex();
+ virtual void acquire();
+ virtual void release();
+ virtual sal_Bool tryToAcquire();
+
+ virtual int Grab();
+ virtual void Ungrab( int );
+
+ class GtkYieldGuard
+ {
+ GtkYieldMutex* m_pMutex;
+ int m_nGrab;
+ public:
+ GtkYieldGuard( GtkYieldMutex* pMutex )
+ : m_pMutex( pMutex )
+ {
+ m_nGrab = m_pMutex->Grab();
+ }
+ ~GtkYieldGuard()
+ {
+ m_pMutex->Ungrab( m_nGrab );
+ }
+ };
+};
+
+class GtkHookedYieldMutex : public GtkYieldMutex
+{
+ virtual int Grab() { return 0; };
+ virtual void Ungrab(int ) {};
+ std::list<ULONG> aYieldStack;
+public:
+ GtkHookedYieldMutex();
+ virtual void acquire();
+ virtual void release();
+ virtual sal_Bool tryToAcquire() { return SalYieldMutex::tryToAcquire(); }
+ void ThreadsEnter();
+ void ThreadsLeave();
+};
+
+
+#define GTK_YIELD_GRAB() GtkYieldMutex::GtkYieldGuard aLocalGtkYieldGuard( static_cast<GtkYieldMutex*>(GetSalData()->m_pInstance->GetYieldMutex()) )
+
+class GtkInstance : public X11SalInstance
+{
+public:
+ GtkInstance( SalYieldMutex* pMutex )
+ : X11SalInstance( pMutex )
+ {}
+ virtual ~GtkInstance();
+
+ virtual SalFrame* CreateFrame( SalFrame* pParent, ULONG nStyle );
+ virtual SalFrame* CreateChildFrame( SystemParentData* pParent, ULONG nStyle );
+ virtual SalObject* CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, BOOL bShow = TRUE );
+ virtual SalSystem* CreateSalSystem();
+ virtual void AddToRecentDocumentList(const rtl::OUString& rFileUrl, const rtl::OUString& rMimeType);
+};
+
+class GtkSalSystem : public X11SalSystem
+{
+public:
+ GtkSalSystem() : X11SalSystem() {}
+ virtual ~GtkSalSystem();
+ virtual int ShowNativeDialog( const String& rTitle,
+ const String& rMessage,
+ const std::list< String >& rButtons,
+ int nDefButton );
+};
+
+#endif // _VCL_GTKINST_HXX
diff --git a/vcl/unx/inc/plugins/gtk/gtkobject.hxx b/vcl/unx/inc/plugins/gtk/gtkobject.hxx
new file mode 100644
index 000000000000..ea740249f1c6
--- /dev/null
+++ b/vcl/unx/inc/plugins/gtk/gtkobject.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _VCL_GTKOBJECT_HXX
+#define _VCL_GTKOBJECT_HXX
+
+#include <vcl/sv.h>
+#include <vcl/sysdata.hxx>
+#include <vcl/salobj.hxx>
+#include <plugins/gtk/gtkframe.hxx>
+
+class GtkSalObject : public SalObject
+{
+ SystemChildData m_aSystemData;
+ GtkWidget* m_pSocket;
+ GdkRegion* m_pRegion;
+
+ // signals
+ static gboolean signalButton( GtkWidget*, GdkEventButton*, gpointer );
+ static gboolean signalFocus( GtkWidget*, GdkEventFocus*, gpointer );
+ static void signalDestroy( GtkObject*, gpointer );
+public:
+ GtkSalObject( GtkSalFrame* pParent, BOOL bShow = TRUE );
+ virtual ~GtkSalObject();
+
+ // overload all pure virtual methods
+ virtual void ResetClipRegion();
+ virtual USHORT GetClipRegionType();
+ virtual void BeginSetClipRegion( ULONG nRects );
+ virtual void UnionClipRegion( long nX, long nY, long nWidth, long nHeight );
+ virtual void EndSetClipRegion();
+
+ virtual void SetPosSize( long nX, long nY, long nWidth, long nHeight );
+ virtual void Show( BOOL bVisible );
+ virtual void Enable( BOOL nEnable );
+ virtual void GrabFocus();
+
+ virtual void SetBackground();
+ virtual void SetBackground( SalColor nSalColor );
+
+ virtual const SystemEnvData* GetSystemData() const;
+
+};
+
+#endif // _SV_SALOBJ_H
diff --git a/vcl/unx/inc/plugins/kde/kdedata.hxx b/vcl/unx/inc/plugins/kde/kdedata.hxx
new file mode 100644
index 000000000000..a55471901283
--- /dev/null
+++ b/vcl/unx/inc/plugins/kde/kdedata.hxx
@@ -0,0 +1,110 @@
+/*************************************************************************
+ *
+ * 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_KDEDATA_HXX
+#define _VCL_KDEDATA_HXX
+
+#include <saldisp.hxx>
+#include <saldata.hxx>
+#include <salframe.h>
+
+class KDEData : public X11SalData
+{
+public:
+ KDEData() {}
+ virtual ~KDEData();
+
+ virtual void Init();
+ virtual void initNWF();
+ virtual void deInitNWF();
+};
+
+class SalKDEDisplay : public SalX11Display
+{
+public:
+ SalKDEDisplay( Display* pDisp );
+ virtual ~SalKDEDisplay();
+};
+
+class KDESalFrame : public X11SalFrame
+{
+ static const int nMaxGraphics = 2;
+
+ struct GraphicsHolder
+ {
+ X11SalGraphics* pGraphics;
+ bool bInUse;
+ GraphicsHolder()
+ : pGraphics( NULL ),
+ bInUse( false )
+ {}
+ ~GraphicsHolder();
+ };
+ GraphicsHolder m_aGraphics[ nMaxGraphics ];
+
+public:
+ KDESalFrame( SalFrame* pParent, ULONG nStyle );
+ virtual ~KDESalFrame();
+
+ virtual SalGraphics* GetGraphics();
+ virtual void ReleaseGraphics( SalGraphics *pGraphics );
+ virtual void updateGraphics( bool bClear );
+ virtual void UpdateSettings( AllSettings& rSettings );
+ virtual void Show( BOOL bVisible, BOOL bNoActivate );
+};
+
+class KDESalInstance : public X11SalInstance
+{
+public:
+ KDESalInstance( SalYieldMutex* pMutex )
+ : X11SalInstance( pMutex ) {}
+ virtual ~KDESalInstance() {}
+ virtual SalFrame* CreateFrame( SalFrame* pParent, ULONG nStyle );
+};
+
+class KDEXLib : public SalXLib
+{
+ bool m_bStartupDone;
+ void* m_pApplication;
+ char** m_pFreeCmdLineArgs;
+ char** m_pAppCmdLineArgs;
+ int m_nFakeCmdLineArgs;
+public:
+ KDEXLib() : SalXLib(),
+ m_bStartupDone( false ),
+ m_pApplication( NULL ),
+ m_pFreeCmdLineArgs( NULL ),
+ m_pAppCmdLineArgs( NULL ),
+ m_nFakeCmdLineArgs( 0 )
+ {}
+ virtual ~KDEXLib();
+ virtual void Init();
+
+ void doStartup();
+};
+
+#endif // _VCL_KDEDATA_HXX
diff --git a/vcl/unx/inc/pspgraphics.h b/vcl/unx/inc/pspgraphics.h
new file mode 100644
index 000000000000..4b1ac12116a3
--- /dev/null
+++ b/vcl/unx/inc/pspgraphics.h
@@ -0,0 +1,193 @@
+/*************************************************************************
+ *
+ * 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_PSPGRAPHICS_H
+#define _VCL_PSPGRAPHICS_H
+
+
+#include "vcl/fontmanager.hxx"
+#include "vcl/salgdi.hxx"
+#include "vcl/sallayout.hxx"
+#include "vcl/dllapi.h"
+
+namespace psp { struct JobData; class PrinterGfx; }
+
+class ServerFont;
+class ImplDevFontAttributes;
+class SalInfoPrinter;
+
+class VCL_DLLPUBLIC PspGraphics : public SalGraphics
+{
+ psp::JobData* m_pJobData;
+ psp::PrinterGfx* m_pPrinterGfx;
+ String* m_pPhoneNr;
+ bool m_bSwallowFaxNo;
+ String m_aPhoneCollection;
+ bool m_bPhoneCollectionActive;
+
+ ServerFont* m_pServerFont[ MAX_FALLBACK ];
+ bool m_bFontVertical;
+ SalInfoPrinter* m_pInfoPrinter;
+public:
+ PspGraphics( psp::JobData* pJob, psp::PrinterGfx* pGfx, String* pPhone, bool bSwallow, SalInfoPrinter* pInfoPrinter )
+ : m_pJobData( pJob ),
+ m_pPrinterGfx( pGfx ),
+ m_pPhoneNr( pPhone ),
+ m_bSwallowFaxNo( bSwallow ),
+ m_bPhoneCollectionActive( false ),
+ m_bFontVertical( false ),
+ m_pInfoPrinter( pInfoPrinter )
+ { for( int i = 0; i < MAX_FALLBACK; i++ ) m_pServerFont[i] = 0; }
+ virtual ~PspGraphics();
+
+ // helper methods for sharing with X11SalGraphics
+ static const void* DoGetEmbedFontData( psp::fontID aFont, const sal_Ucs* pUnicodes, sal_Int32* pWidths, FontSubsetInfo& rInfo, long* pDataLen );
+ static void DoFreeEmbedFontData( const void* pData, long nLen );
+ static const Ucs2SIntMap* DoGetFontEncodingVector( psp::fontID aFont, const Ucs2OStrMap** pNonEncoded );
+ static void DoGetGlyphWidths( psp::fontID aFont,
+ bool bVertical,
+ Int32Vector& rWidths,
+ Ucs2UIntMap& rUnicodeEnc );
+
+ static ImplDevFontAttributes Info2DevFontAttributes( const psp::FastPrintFontInfo& );
+ static void AnnounceFonts( ImplDevFontList*, const psp::FastPrintFontInfo& );
+ static FontWidth ToFontWidth (psp::width::type eWidth);
+ static FontWeight ToFontWeight (psp::weight::type eWeight);
+ static FontPitch ToFontPitch (psp::pitch::type ePitch);
+ static FontItalic ToFontItalic (psp::italic::type eItalic);
+ static FontFamily ToFontFamily (psp::family::type eFamily);
+
+ // overload all pure virtual methods
+ virtual void GetResolution( sal_Int32& rDPIX, sal_Int32& rDPIY );
+ virtual USHORT GetBitCount();
+ virtual long GetGraphicsWidth() const;
+
+ virtual void ResetClipRegion();
+ virtual void BeginSetClipRegion( ULONG nCount );
+ virtual BOOL unionClipRegion( long nX, long nY, long nWidth, long nHeight );
+ virtual bool unionClipRegion( const ::basegfx::B2DPolyPolygon& );
+ virtual void EndSetClipRegion();
+
+ virtual void SetLineColor();
+ virtual void SetLineColor( SalColor nSalColor );
+ virtual void SetFillColor();
+ virtual void SetFillColor( SalColor nSalColor );
+ virtual void SetXORMode( bool bSet, bool );
+ virtual void SetROPLineColor( SalROPColor nROPColor );
+ virtual void SetROPFillColor( SalROPColor nROPColor );
+
+ virtual void SetTextColor( SalColor nSalColor );
+ virtual USHORT SetFont( ImplFontSelectData*, int nFallbackLevel );
+ virtual void GetFontMetric( ImplFontMetricData* );
+ virtual ULONG GetKernPairs( ULONG nMaxPairs, ImplKernPairData* );
+ virtual ImplFontCharMap* GetImplFontCharMap() const;
+ virtual void GetDevFontList( ImplDevFontList* );
+ virtual void GetDevFontSubstList( OutputDevice* );
+ virtual bool AddTempDevFont( ImplDevFontList*, const String& rFileURL, const String& rFontName );
+ virtual BOOL CreateFontSubset( const rtl::OUString& rToFile,
+ const ImplFontData*,
+ sal_Int32* pGlyphIDs,
+ sal_uInt8* pEncoding,
+ sal_Int32* pWidths,
+ int nGlyphs,
+ FontSubsetInfo& rInfo
+ );
+ virtual const Ucs2SIntMap* GetFontEncodingVector( const ImplFontData*, const Ucs2OStrMap** ppNonEncoded );
+ virtual const void* GetEmbedFontData( const ImplFontData*,
+ const sal_Ucs* pUnicodes,
+ sal_Int32* pWidths,
+ FontSubsetInfo& rInfo,
+ long* pDataLen );
+ virtual void FreeEmbedFontData( const void* pData, long nDataLen );
+ virtual void GetGlyphWidths( const ImplFontData*,
+ bool bVertical,
+ Int32Vector& rWidths,
+ Ucs2UIntMap& rUnicodeEnc );
+ virtual BOOL GetGlyphBoundRect( long nIndex, Rectangle& );
+ virtual BOOL GetGlyphOutline( long nIndex, ::basegfx::B2DPolyPolygon& );
+ virtual SalLayout* GetTextLayout( ImplLayoutArgs&, int nFallbackLevel );
+ virtual void DrawServerFontLayout( const ServerFontLayout& );
+ virtual bool supportsOperation( OutDevSupportType ) const;
+ virtual void drawPixel( long nX, long nY );
+ virtual void drawPixel( long nX, long nY, SalColor nSalColor );
+ virtual void drawLine( long nX1, long nY1, long nX2, long nY2 );
+ virtual void drawRect( long nX, long nY, long nWidth, long nHeight );
+ virtual void drawPolyLine( ULONG nPoints, const SalPoint* pPtAry );
+ virtual void drawPolygon( ULONG nPoints, const SalPoint* pPtAry );
+ virtual void drawPolyPolygon( sal_uInt32 nPoly,
+ const sal_uInt32* pPoints,
+ PCONSTSALPOINT* pPtAry );
+ virtual bool drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double fTransparency );
+ virtual bool drawPolyLine( const basegfx::B2DPolygon&, double fTransparency, const basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin);
+ virtual sal_Bool drawPolyLineBezier( ULONG nPoints,
+ const SalPoint* pPtAry,
+ const BYTE* pFlgAry );
+ virtual sal_Bool drawPolygonBezier( ULONG nPoints,
+ const SalPoint* pPtAry,
+ const BYTE* pFlgAry );
+ virtual sal_Bool drawPolyPolygonBezier( sal_uInt32 nPoly,
+ const sal_uInt32* pPoints,
+ const SalPoint* const* pPtAry,
+ const BYTE* const* pFlgAry );
+ virtual void copyArea( long nDestX,
+ long nDestY,
+ long nSrcX,
+ long nSrcY,
+ long nSrcWidth,
+ long nSrcHeight,
+ USHORT nFlags );
+ virtual void copyBits( const SalTwoRect* pPosAry,
+ SalGraphics* pSrcGraphics );
+ virtual void drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap );
+ virtual void drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ SalColor nTransparentColor );
+ virtual void drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ const SalBitmap& rTransparentBitmap );
+ virtual void drawMask( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ SalColor nMaskColor );
+ virtual SalBitmap* getBitmap( long nX, long nY, long nWidth, long nHeight );
+ virtual SalColor getPixel( long nX, long nY );
+ virtual void invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags );
+ virtual void invert( ULONG nPoints, const SalPoint* pPtAry, SalInvert nFlags );
+
+ virtual BOOL drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, ULONG nSize );
+ virtual bool filterText( const String& rOrigText, String& rNewText, xub_StrLen nIndex, xub_StrLen& rLen, xub_StrLen& rCutStart, xub_StrLen& rCutStop );
+
+ virtual bool drawAlphaBitmap( const SalTwoRect&,
+ const SalBitmap& rSourceBitmap,
+ const SalBitmap& rAlphaBitmap );
+ virtual bool drawAlphaRect( long nX, long nY, long nWidth, long nHeight, sal_uInt8 nTransparency );
+
+ virtual SystemGraphicsData GetGraphicsData() const;
+ virtual SystemFontData GetSysFontData( int nFallbacklevel ) const;
+};
+
+#endif // _VCL_PSPGRAPHICS_H
diff --git a/vcl/unx/inc/salbmp.h b/vcl/unx/inc/salbmp.h
new file mode 100644
index 000000000000..23e038f30ab1
--- /dev/null
+++ b/vcl/unx/inc/salbmp.h
@@ -0,0 +1,237 @@
+/*************************************************************************
+ *
+ * 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_SALBMP_H
+#define _SV_SALBMP_H
+
+#include <salstd.hxx>
+#ifndef _SV_SALGTYPE
+#include <vcl/salgtype.hxx>
+#endif
+#include <saldisp.hxx>
+#include <vcl/salbmp.hxx>
+#include <vcl/dllapi.h>
+
+struct BitmapBuffer;
+class BitmapPalette;
+class SalGraphics;
+class ImplSalDDB;
+class ImplSalBitmapCache;
+
+// -------------
+// - SalBitmap -
+// -------------
+
+class VCL_DLLPUBLIC X11SalBitmap : public SalBitmap
+{
+private:
+
+ static BitmapBuffer* ImplCreateDIB( const Size& rSize,
+ USHORT nBitCount,
+ const BitmapPalette& rPal );
+ static BitmapBuffer* ImplCreateDIB( Drawable aDrawable,
+ int nScreen,
+ long nDrawableDepth,
+ long nX, long nY,
+ long nWidth, long nHeight );
+
+public:
+
+ static ImplSalBitmapCache* mpCache;
+ static ULONG mnCacheInstCount;
+
+ static void ImplCreateCache();
+ static void ImplDestroyCache();
+ void ImplRemovedFromCache();
+
+ bool SnapShot (Display* pDisplay, XLIB_Window hWindow);
+ bool ImplCreateFromXImage( Display* pDisplay,
+ XLIB_Window hWindow,
+ int nScreen,
+ XImage* pImage);
+private:
+
+
+ BitmapBuffer* mpDIB;
+ ImplSalDDB* mpDDB;
+
+public:
+
+ SAL_DLLPRIVATE bool ImplCreateFromDrawable( Drawable aDrawable,
+ int nScreen,
+ long nDrawableDepth,
+ long nX, long nY,
+ long nWidth, long nHeight );
+
+ SAL_DLLPRIVATE XImage* ImplCreateXImage( SalDisplay* pSalDisp,
+ int nScreen, long nDepth,
+ const SalTwoRect& rTwoRect ) const;
+
+ SAL_DLLPRIVATE ImplSalDDB* ImplGetDDB( Drawable, int nScreen, long nDrawableDepth,
+ const SalTwoRect& ) const;
+ void ImplDraw( Drawable aDrawable, int nScreen, long nDrawableDepth,
+ const SalTwoRect& rTwoRect, const GC& rGC ) const;
+
+public:
+
+ X11SalBitmap();
+ virtual ~X11SalBitmap();
+
+ // overload pure virtual methods
+ virtual bool Create( const Size& rSize,
+ USHORT nBitCount,
+ const BitmapPalette& rPal );
+ virtual bool Create( const SalBitmap& rSalBmp );
+ virtual bool Create( const SalBitmap& rSalBmp,
+ SalGraphics* pGraphics );
+ virtual bool Create( const SalBitmap& rSalBmp,
+ USHORT nNewBitCount );
+
+ virtual void Destroy();
+
+ virtual Size GetSize() const;
+ virtual USHORT GetBitCount() const;
+
+ virtual BitmapBuffer* AcquireBuffer( bool bReadOnly );
+ virtual void ReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly );
+ virtual bool GetSystemData( BitmapSystemData& rData );
+};
+
+// --------------
+// - ImplSalDDB -
+// --------------
+
+class ImplSalDDB
+{
+private:
+
+ Pixmap maPixmap;
+ SalTwoRect maTwoRect;
+ long mnDepth;
+ int mnScreen;
+
+ ImplSalDDB() {}
+
+ static void ImplDraw( Drawable aSrcDrawable, long nSrcDrawableDepth,
+ Drawable aDstDrawable, long nDstDrawableDepth,
+ long nSrcX, long nSrcY,
+ long nDestWidth, long nDestHeight,
+ long nDestX, long nDestY, const GC& rGC );
+
+public:
+
+ ImplSalDDB( XImage* pImage,
+ Drawable aDrawable, int nScreen,
+ const SalTwoRect& rTwoRect );
+ ImplSalDDB( Drawable aDrawable,
+ int nScreen,
+ long nDrawableDepth,
+ long nX, long nY, long nWidth, long nHeight );
+ ImplSalDDB( Display* pDisplay,
+ XLIB_Window hWindow,
+ int nScreen,
+ XImage* pImage);
+ ~ImplSalDDB();
+
+ Pixmap ImplGetPixmap() const { return maPixmap; }
+ long ImplGetWidth() const { return maTwoRect.mnDestWidth; }
+ long ImplGetHeight() const { return maTwoRect.mnDestHeight; }
+ long ImplGetDepth() const { return mnDepth; }
+ ULONG ImplGetMemSize() const { return( ( maTwoRect.mnDestWidth * maTwoRect.mnDestHeight * mnDepth ) >> 3 ); }
+ int ImplGetScreen() const { return mnScreen; }
+
+ bool ImplMatches( int nScreen, long nDepth, const SalTwoRect& rTwoRect ) const;
+ void ImplDraw( Drawable aDrawable, long nDrawableDepth,
+ const SalTwoRect& rTwoRect, const GC& rGC ) const;
+};
+
+// ----------------------
+// - ImplSalBitmapCache -
+// ----------------------
+
+class ImplSalBitmapCache
+{
+private:
+
+ List maBmpList;
+ ULONG mnTotalSize;
+
+public:
+
+ ImplSalBitmapCache();
+ ~ImplSalBitmapCache();
+
+ void ImplAdd( X11SalBitmap* pBmp, ULONG nMemSize = 0UL, ULONG nFlags = 0UL );
+ void ImplRemove( X11SalBitmap* pBmp );
+ void ImplClear();
+};
+
+#endif // _SV_SALBMP_HXX
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vcl/unx/inc/saldata.hxx b/vcl/unx/inc/saldata.hxx
new file mode 100644
index 000000000000..7e38e0a89bf2
--- /dev/null
+++ b/vcl/unx/inc/saldata.hxx
@@ -0,0 +1,132 @@
+/*************************************************************************
+ *
+ * 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_SALDATA_HXX
+#define _SV_SALDATA_HXX
+
+// -=-= includes -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#include <signal.h>
+#include <salstd.hxx>
+#include <vcl/salframe.hxx>
+#include <salinst.h>
+#include <vcl/saldatabasic.hxx>
+#ifndef _OSL_MODULE_H
+#include <osl/module.h>
+#endif
+#include <vcl/dllapi.h>
+
+// -=-= forwards -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+class SalXLib;
+class SalDisplay;
+class SalPrinter;
+
+// -=-= typedefs -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+DECLARE_LIST( SalDisplays, SalDisplay* )
+
+#if defined SCO || defined LINUX || defined NETBSD || defined AIX || defined HPUX || defined FREEBSD
+#include <pthread.h>
+#else
+typedef unsigned int pthread_t;
+#endif
+
+// -=-= SalData =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+class VCL_DLLPUBLIC X11SalData : public SalData
+{
+protected:
+ BOOL bNoExceptions_;
+ SalXLib *pXLib_;
+ SalDisplay *m_pSalDisplay;
+ pthread_t hMainThread_;
+ rtl::OUString maLocalHostName;
+
+public:
+ X11SalData();
+ virtual ~X11SalData();
+
+ virtual void Init();
+ virtual void initNWF();
+ virtual void deInitNWF();
+
+ inline void XError( Display *pDisplay, XErrorEvent *pEvent ) const;
+
+ SalDisplay* GetDisplay() const
+ { return m_pSalDisplay; }
+ void SetSalDisplay( SalDisplay* pDisplay )
+ { m_pSalDisplay = pDisplay; }
+
+ void DeleteDisplay(); // for shutdown
+
+ inline SalXLib* GetLib() const { return pXLib_; }
+ inline pthread_t GetMainThread() const { return hMainThread_; }
+
+ void StartTimer( ULONG nMS );
+ inline void StopTimer();
+ void Timeout() const;
+
+ const rtl::OUString& GetLocalHostName() const
+ { return maLocalHostName; }
+
+ static int XErrorHdl( Display*, XErrorEvent* );
+ static int XIOErrorHdl( Display* );
+
+ // set helper functions to set class and res name in W_CLASS hint
+ static const char* getFrameResName();
+ static const char* getFrameClassName();
+ static rtl::OString getFrameResName( SalExtStyle nStyle );
+
+};
+
+inline X11SalData* GetX11SalData()
+{ return (X11SalData*)ImplGetSVData()->mpSalData; }
+
+
+#ifdef _SV_SALDISP_HXX
+inline void X11SalData::XError( Display *pDisplay, XErrorEvent *pEvent ) const
+{ pXLib_->XError( pDisplay, pEvent ); }
+#endif
+
+class YieldMutexReleaser
+{
+ ULONG m_nYieldCount;
+public:
+ inline YieldMutexReleaser();
+ inline ~YieldMutexReleaser();
+};
+
+inline YieldMutexReleaser::YieldMutexReleaser()
+{
+ m_nYieldCount = GetSalData()->m_pInstance->ReleaseYieldMutex();
+}
+
+inline YieldMutexReleaser::~YieldMutexReleaser()
+{
+ GetSalData()->m_pInstance->AcquireYieldMutex( m_nYieldCount );
+}
+
+#endif // _SV_SALDATA_HXX
+
diff --git a/vcl/unx/inc/saldisp.hxx b/vcl/unx/inc/saldisp.hxx
new file mode 100644
index 000000000000..3734cbec6ef7
--- /dev/null
+++ b/vcl/unx/inc/saldisp.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALDISP_HXX
+#define _SV_SALDISP_HXX
+
+// -=-= exports =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+class SalDisplay;
+class SalColormap;
+class SalVisual;
+class SalXLib;
+
+// -=-= #includes =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#include <salunx.h>
+#include <vcl/salgtype.hxx>
+#ifndef _SV_PTRSTYLE_HXX
+#include <vcl/ptrstyle.hxx>
+#endif
+#include <sal/types.h>
+#ifndef _OSL_MUTEX_H
+#include <osl/mutex.h>
+#endif
+#include <vector>
+#include <list>
+#include <hash_map>
+#include <tools/gen.hxx>
+#include <vcl/salwtype.hxx>
+#include <vcl/dllapi.h>
+
+// -=-= forwards -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+class BitmapPalette;
+class SalFrame;
+class ColorMask;
+
+namespace vcl_sal { class WMAdaptor; }
+class DtIntegrator;
+
+// -=-= #defines -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#define PROPERTY_SUPPORT_WM_SetPos 0x00000001
+#define PROPERTY_SUPPORT_WM_Screen 0x00000002
+#define PROPERTY_SUPPORT_WM_Parent_Pixmap_None 0x00000004
+#define PROPERTY_SUPPORT_WM_ClientPos 0x00000008
+#define PROPERTY_SUPPORT_XSetClipMask 0x00000010 // for bitmap ops.
+#define PROPERTY_SUPPORT_3ButtonMouse 0x00000020
+
+#define PROPERTY_BUG_XA_FAMILY_NAME_nil 0x00001000
+#define PROPERTY_BUG_XCopyArea_GXxor 0x00002000 // from window
+#define PROPERTY_BUG_Stipple 0x00004000 // 0/1 inverted
+#define PROPERTY_BUG_Tile 0x00008000 // Recreate the
+ // dither brush each time
+#define PROPERTY_BUG_FillPolygon_Tile 0x00010000 // always Toggle Fillstyle
+#define PROPERTY_BUG_DrawLine 0x00020000 // a DrawLine is one point to short
+#define PROPERTY_BUG_CopyPlane_RevertBWPixel 0x00040000 // revert fg and bg for xcopyplane
+#define PROPERTY_BUG_CopyArea_OnlySmallSlices 0x00080000
+#define PROPERTY_BUG_Bitmap_Bit_Order 0x00100000
+
+#define PROPERTY_FEATURE_Maximize 0x01000000
+#define PROPERTY_FEATURE_SharedMemory 0x02000000
+#define PROPERTY_FEATURE_TrustedSolaris 0x04000000
+
+#define PROPERTY_DEFAULT 0x00000FCB
+
+// ------------------------------------------------------------------------
+// server vendor
+
+typedef enum {
+ vendor_none = 0,
+ vendor_attachmate,
+ vendor_excursion,
+ vendor_hp,
+ vendor_hummingbird,
+ vendor_ibm,
+ vendor_sco,
+ vendor_sgi,
+ vendor_sun,
+ vendor_xfree,
+ vendor_xinside,
+ vendor_xprinter,
+ vendor_unknown
+} srv_vendor_t;
+
+extern "C" srv_vendor_t sal_GetServerVendor( Display *p_display );
+
+// -=-= SalWM =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+enum SalWM { olwm, // Open Look
+ mwm, // Motif
+ kwm, // KDE Desktop Environment
+ FourDwm, // SGI
+ vuewm, // HP
+ dtwm, // CDE
+ winmgr, // Oracle NC
+ twm,
+ fvwm, // ...
+ pmwm, // SCO
+ otherwm };
+
+// -=-= SalRGB -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// MSB/Bigendian Sicht (SalColor == RGB, r=0xFF0000, g=0xFF00, b=0xFF)
+
+enum SalRGB { RGB, RBG,
+ GBR, GRB,
+ BGR, BRG,
+ RGBA, RBGA,
+ GBRA, GRBA,
+ BGRA, BRGA,
+ other };
+
+// -=-= SalVisual =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+class SalVisual : public XVisualInfo
+{
+ SalRGB eRGBMode_;
+ int nRedShift_;
+ int nGreenShift_;
+ int nBlueShift_;
+ int nRedBits_;
+ int nGreenBits_;
+ int nBlueBits_;
+public:
+ SalVisual();
+ ~SalVisual();
+ SalVisual( const XVisualInfo* pXVI );
+
+ inline VisualID GetVisualId() const { return visualid; }
+ inline Visual *GetVisual() const { return visual; }
+ inline int GetClass() const { return c_class; }
+ inline int GetDepth() const { return depth; }
+ inline SalRGB GetMode() const { return eRGBMode_; }
+
+ Pixel GetTCPixel( SalColor nColor ) const;
+ SalColor GetTCColor( Pixel nPixel ) const;
+ BOOL Convert( int &n0, int &n1, int &n2, int &n3 ); // 32bit
+ BOOL Convert( int &n0, int &n1, int &n2 ); // 24bit
+};
+
+// -=-= SalColormap =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+class SalColormap
+{
+ const SalDisplay* m_pDisplay;
+ Colormap m_hColormap;
+ std::vector<SalColor> m_aPalette; // Pseudocolor
+ SalVisual m_aVisual;
+ std::vector<USHORT> m_aLookupTable; // Pseudocolor: 12bit reduction
+ Pixel m_nWhitePixel;
+ Pixel m_nBlackPixel;
+ Pixel m_nUsed; // Pseudocolor
+ int m_nScreen;
+
+ void GetPalette();
+ void GetLookupTable();
+public:
+ SalColormap( const SalDisplay* pSalDisplay,
+ Colormap hColormap,
+ int nScreen );
+ SalColormap( const BitmapPalette &rpPalette );
+ SalColormap( USHORT nDepth );
+ SalColormap();
+ ~SalColormap();
+
+ inline Colormap GetXColormap() const { return m_hColormap; }
+ inline const SalDisplay* GetDisplay() const { return m_pDisplay; }
+ inline Display* GetXDisplay() const;
+ inline const SalVisual& GetVisual() const { return m_aVisual; }
+ inline Visual* GetXVisual() const { return m_aVisual.GetVisual(); }
+ inline Pixel GetWhitePixel() const { return m_nWhitePixel; }
+ inline Pixel GetBlackPixel() const { return m_nBlackPixel; }
+ inline Pixel GetUsed() const { return m_nUsed; }
+ inline int GetClass() const { return m_aVisual.GetClass(); }
+ inline int GetScreenNumber() const { return m_nScreen; }
+
+ BOOL GetXPixels( XColor &rColor,
+ int r,
+ int g,
+ int b ) const;
+ inline BOOL GetXPixel( XColor &rColor,
+ int r,
+ int g,
+ int b ) const;
+ Pixel GetPixel( SalColor nColor ) const;
+ SalColor GetColor( Pixel nPixel ) const;
+ void SetPalette( const BitmapPalette &rPalette );
+};
+
+// -=-= SalXLib =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+typedef int(*YieldFunc)(int fd, void* data);
+struct YieldEntry;
+
+class VCL_DLLPUBLIC SalXLib
+{
+protected:
+ timeval m_aTimeout;
+ ULONG m_nTimeoutMS;
+ int m_pTimeoutFDS[2];
+
+ bool m_bHaveSystemChildFrames;
+
+ int nFDs_;
+ fd_set aReadFDS_;
+ fd_set aExceptionFDS_;
+ YieldEntry *pYieldEntries_;
+
+
+ struct XErrorStackEntry
+ {
+ bool m_bIgnore;
+ bool m_bWas;
+ unsigned int m_nLastErrorRequest;
+ XErrorHandler m_aHandler;
+ };
+ std::vector< XErrorStackEntry > m_aXErrorHandlerStack;
+ XIOErrorHandler m_aOrigXIOErrorHandler;
+public:
+ SalXLib();
+ virtual ~SalXLib();
+ virtual void Init();
+
+ virtual void Yield( bool bWait, bool bHandleAllCurrentEvents );
+ virtual void Wakeup();
+ virtual void PostUserEvent();
+
+ virtual void Insert( int fd, void* data,
+ YieldFunc pending,
+ YieldFunc queued,
+ YieldFunc handle );
+ virtual void Remove( int fd );
+
+ void XError( Display *pDisp, XErrorEvent *pEvent );
+ bool HasXErrorOccured() const { return m_aXErrorHandlerStack.back().m_bWas; }
+ unsigned int GetLastXErrorRequestCode() const { return m_aXErrorHandlerStack.back().m_nLastErrorRequest; }
+ void ResetXErrorOccured() { m_aXErrorHandlerStack.back().m_bWas = false; }
+ void PushXErrorLevel( bool bIgnore );
+ void PopXErrorLevel();
+
+ virtual void StartTimer( ULONG nMS );
+ virtual void StopTimer();
+
+ bool CheckTimeout( bool bExecuteTimers = true );
+
+ void setHaveSystemChildFrame()
+ { m_bHaveSystemChildFrames = true; }
+ bool getHaveSystemChildFrame() const
+ { return m_bHaveSystemChildFrames; }
+};
+
+// -=-= SalDisplay -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+class SalI18N_InputMethod;
+class SalI18N_KeyboardExtension;
+class XlfdStorage;
+class ExtendedFontStruct;
+class ExtendedXlfd;
+class AttributeProvider;
+class SalUnicodeConverter;
+class SalConverterCache;
+
+DECLARE_LIST( SalFontCache, ExtendedFontStruct* )
+
+extern "C" {
+ struct SnDisplay;
+ struct SnLauncheeContext;
+ typedef Bool(*X_if_predicate)(Display*,XEvent*,XPointer);
+}
+
+class VCL_DLLPUBLIC SalDisplay
+{
+public:
+ struct RenderEntry
+ {
+ Pixmap m_aPixmap;
+ Picture m_aPicture;
+
+ RenderEntry() : m_aPixmap( 0 ), m_aPicture( 0 ) {}
+ };
+
+ typedef std::hash_map<int,RenderEntry> RenderEntryMap;
+
+ struct ScreenData
+ {
+ bool m_bInit;
+
+ XLIB_Window m_aRoot;
+ XLIB_Window m_aRefWindow;
+ Size m_aSize;
+ SalVisual m_aVisual;
+ SalColormap m_aColormap;
+ GC m_aMonoGC;
+ GC m_aCopyGC;
+ GC m_aAndInvertedGC;
+ GC m_aAndGC;
+ GC m_aOrGC;
+ GC m_aStippleGC;
+ Pixmap m_hInvert50;
+ mutable RenderEntryMap m_aRenderData;
+
+ ScreenData() :
+ m_bInit( false ),
+ m_aRoot( None ),
+ m_aRefWindow( None ),
+ m_aMonoGC( None ),
+ m_aCopyGC( None ),
+ m_aAndInvertedGC( None ),
+ m_aAndGC( None ),
+ m_aOrGC( None ),
+ m_aStippleGC( None ),
+ m_hInvert50( None ),
+ m_aRenderData( 1 )
+ {}
+ };
+// -=-= UserEvent =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ struct SalUserEvent
+ {
+ SalFrame* m_pFrame;
+ void* m_pData;
+ USHORT m_nEvent;
+
+ SalUserEvent( SalFrame* pFrame, void* pData, USHORT nEvent = SALEVENT_USEREVENT )
+ : m_pFrame( pFrame ),
+ m_pData( pData ),
+ m_nEvent( nEvent )
+ {}
+ };
+
+protected:
+ SalXLib *pXLib_;
+ SalI18N_InputMethod *mpInputMethod;
+ SalI18N_KeyboardExtension *mpKbdExtension;
+
+ AttributeProvider *mpFactory;
+ XlfdStorage *mpFontList;
+ const ExtendedXlfd *mpFallbackFactory;
+
+ Display *pDisp_; // X Display
+ int m_nDefaultScreen; // XDefaultScreen
+ std::vector< ScreenData > m_aScreens;
+ ScreenData m_aInvalidScreenData;
+ Pair aResolution_; // [dpi]
+ bool mbExactResolution;
+ ULONG nMaxRequestSize_; // [byte]
+
+ srv_vendor_t meServerVendor;
+ SalWM eWindowManager_;
+ ULONG nProperties_; // PROPERTY_SUPPORT, BUG, FEATURE
+ BOOL bLocal_; // Server==Client? Init
+ // in SalDisplay::IsLocal()
+ BOOL mbLocalIsValid; // bLocal_ is valid ?
+ // until x bytes
+
+ oslMutex hEventGuard_;
+ std::list< SalUserEvent > m_aUserEvents;
+
+ XLIB_Cursor aPointerCache_[POINTER_COUNT];
+ SalFrame* m_pCapture;
+
+ mutable SalFontCache* m_pFontCache;
+
+ // Keyboard
+ BOOL bNumLockFromXS_; // Num Lock handled by X Server
+ int nNumLockIndex_; // modifier index in modmap
+ int nNumLockMask_; // keyevent state mask for
+ KeySym nShiftKeySym_; // first shift modifier
+ KeySym nCtrlKeySym_; // first control modifier
+ KeySym nMod1KeySym_; // first mod1 modifier
+ ByteString m_aKeyboardName;
+
+ vcl_sal::WMAdaptor* m_pWMAdaptor;
+ DtIntegrator* m_pDtIntegrator;
+
+ bool m_bXinerama;
+ std::vector< Rectangle > m_aXineramaScreens;
+ std::list<SalFrame*> m_aFrames;
+ std::list<SalObject*> m_aSalObjects;
+
+ bool m_bUseRandRWrapper; // don't use randr on gtk, use gdk signals there
+
+ mutable XLIB_Time m_nLastUserEventTime; // mutable because changed on first access
+
+ void DestroyFontCache();
+ virtual long Dispatch( XEvent *pEvent ) = 0;
+ void InitXinerama();
+ void InitRandR( XLIB_Window aRoot ) const;
+ void DeInitRandR();
+ int processRandREvent( XEvent* );
+
+ void doDestruct();
+ void addXineramaScreenUnique( long i_nX, long i_nY, long i_nWidth, long i_nHeight );
+public:
+ static SalDisplay *GetSalDisplay( Display* display );
+ static BOOL BestVisual( Display *pDisp,
+ int nScreen,
+ XVisualInfo &rVI );
+
+ SalDisplay( Display* pDisp );
+
+ virtual ~SalDisplay();
+
+
+ virtual void registerFrame( SalFrame* pFrame );
+ virtual void deregisterFrame( SalFrame* pFrame );
+ void setHaveSystemChildFrame() const
+ { pXLib_->setHaveSystemChildFrame(); }
+ bool getHaveSystemChildFrame() const
+ { return pXLib_->getHaveSystemChildFrame(); }
+
+ void Init();
+
+ void SendInternalEvent( SalFrame* pFrame, void* pData, USHORT nEvent = SALEVENT_USEREVENT );
+ void CancelInternalEvent( SalFrame* pFrame, void* pData, USHORT nEvent );
+ bool DispatchInternalEvent();
+ void PrintInfo() const;
+
+ void PrintEvent( const ByteString &rComment,
+ XEvent *pEvent ) const;
+
+ XlfdStorage* GetXlfdList() const;
+ ExtendedFontStruct*
+ GetFont( const ExtendedXlfd *pFont,
+ const Size& rPixelSize, sal_Bool bVertical ) const;
+ const ExtendedXlfd*
+ GetFallbackFactory()
+ { return mpFallbackFactory; }
+
+ void Beep() const;
+
+ void ModifierMapping();
+ String GetKeyNameFromKeySym( KeySym keysym ) const;
+ XubString GetKeyName( USHORT nKeyCode ) const;
+ USHORT GetKeyCode( KeySym keysym, char*pcPrintable ) const;
+ KeySym GetKeySym( XKeyEvent *pEvent,
+ unsigned char *pPrintable,
+ int *pLen,
+ KeySym *pUnmodifiedKeySym,
+ Status *pStatus,
+ XIC = NULL ) const;
+
+ XLIB_Cursor GetPointer( int ePointerStyle );
+ virtual int CaptureMouse( SalFrame *pCapture );
+
+ BOOL IsLocal();
+
+ void Remove( XEvent *pEvent );
+
+ virtual void initScreen( int nScreen ) const;
+ const ScreenData& getDataForScreen( int nScreen ) const
+ {
+ if( nScreen < 0 || nScreen >= static_cast<int>(m_aScreens.size()) )
+ return m_aInvalidScreenData;
+ if( ! m_aScreens[nScreen].m_bInit )
+ initScreen( nScreen );
+ return m_aScreens[nScreen];
+ }
+
+ XLIB_Window GetDrawable( int nScreen ) const { return getDataForScreen( nScreen ).m_aRefWindow; }
+ Display *GetDisplay() const { return pDisp_; }
+ int GetDefaultScreenNumber() const { return m_nDefaultScreen; }
+ const Size& GetScreenSize( int nScreen ) const { return getDataForScreen( nScreen ).m_aSize; }
+ srv_vendor_t GetServerVendor() const { return meServerVendor; }
+ void SetServerVendor() { meServerVendor = sal_GetServerVendor(pDisp_); }
+ BOOL IsDisplay() const { return !!pXLib_; }
+ GC GetMonoGC( int nScreen ) const { return getDataForScreen(nScreen).m_aMonoGC; }
+ GC GetCopyGC( int nScreen ) const { return getDataForScreen(nScreen).m_aCopyGC; }
+ GC GetAndInvertedGC( int nScreen ) const { return getDataForScreen(nScreen).m_aAndInvertedGC; }
+ GC GetAndGC( int nScreen ) const { return getDataForScreen(nScreen).m_aAndGC; }
+ GC GetOrGC( int nScreen ) const { return getDataForScreen(nScreen).m_aOrGC; }
+ GC GetStippleGC( int nScreen ) const { return getDataForScreen(nScreen).m_aStippleGC; }
+ GC GetGC( USHORT nDepth, int nScreen ) const;
+ Pixmap GetInvert50( int nScreen ) const { return getDataForScreen(nScreen).m_hInvert50; }
+ const SalColormap& GetColormap( int nScreen ) const { return getDataForScreen(nScreen).m_aColormap; }
+ const SalVisual& GetVisual( int nScreen ) const { return getDataForScreen(nScreen).m_aVisual; }
+ RenderEntryMap& GetRenderEntries( int nScreen ) const { return getDataForScreen(nScreen).m_aRenderData; }
+ const Pair &GetResolution() const { return aResolution_; }
+ bool GetExactResolution() const { return mbExactResolution; }
+ ULONG GetProperties() const { return nProperties_; }
+ ULONG GetMaxRequestSize() const { return nMaxRequestSize_; }
+ XLIB_Time GetLastUserEventTime( bool bAlwaysReget = false ) const;
+
+ bool XIfEventWithTimeout( XEvent*, XPointer, X_if_predicate, long i_nTimeout = 1000 ) const;
+
+ BOOL MouseCaptured( const SalFrame *pFrameData ) const
+ { return m_pCapture == pFrameData; }
+ SalFrame* GetCaptureFrame() const
+ { return m_pCapture; }
+ SalXLib* GetXLib() const { return pXLib_; }
+
+ SalI18N_InputMethod* GetInputMethod() const { return mpInputMethod; }
+ SalI18N_KeyboardExtension* GetKbdExtension() const { return mpKbdExtension; }
+ void SetInputMethod( SalI18N_InputMethod *pInputMethod )
+ { mpInputMethod = pInputMethod; }
+ void SetKbdExtension(SalI18N_KeyboardExtension *pKbdExtension)
+ { mpKbdExtension = pKbdExtension; }
+ const char* GetKeyboardName( BOOL bRefresh = FALSE );
+ ::vcl_sal::WMAdaptor* getWMAdaptor() const { return m_pWMAdaptor; }
+ DtIntegrator* getDtIntegrator() const { return m_pDtIntegrator; }
+ bool IsXinerama() const { return m_bXinerama; }
+ const std::vector< Rectangle >& GetXineramaScreens() const { return m_aXineramaScreens; }
+ XLIB_Window GetRootWindow( int nScreen ) const
+ { return getDataForScreen( nScreen ).m_aRoot; }
+ const std::vector< ScreenData >& GetScreenData()
+ { return m_aScreens; }
+ int GetScreenCount() const { return static_cast<int>(m_aScreens.size()); }
+
+ const std::list< SalFrame* >& getFrames() const
+ { return m_aFrames; }
+
+ BOOL IsNumLockFromXS() const { return bNumLockFromXS_; }
+
+ std::list< SalObject* >& getSalObjects() { return m_aSalObjects; }
+};
+
+// -=-= inlines =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+inline GC SalDisplay::GetGC( USHORT nDepth, int nScreen ) const
+{ return 1 == nDepth
+ ? GetMonoGC( nScreen )
+ : getDataForScreen(nScreen).m_aVisual.GetDepth() == nDepth
+ ? GetCopyGC( nScreen )
+ : None; }
+
+inline Display *SalColormap::GetXDisplay() const
+{ return m_pDisplay->GetDisplay(); }
+
+class VCL_DLLPUBLIC SalX11Display : public SalDisplay
+{
+public:
+ SalX11Display( Display* pDisp );
+ virtual ~SalX11Display();
+
+ virtual long Dispatch( XEvent *pEvent );
+ virtual void Yield();
+
+ BOOL IsEvent();
+};
+
+/*----------------------------------------------------------
+ keep track of correct size of the initial window
+ */
+// get foreign key names
+namespace vcl_sal {
+ String getKeysymReplacementName(
+ const char* pKeyboard,
+ KeySym nSymbol );
+}
+
+
+#endif // _SV_SALDISP_HXX
diff --git a/vcl/unx/inc/salfont.h b/vcl/unx/inc/salfont.h
new file mode 100644
index 000000000000..b3fbe93137f3
--- /dev/null
+++ b/vcl/unx/inc/salfont.h
@@ -0,0 +1,180 @@
+/*************************************************************************
+ *
+ * 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_SALFONT_H
+#define _SV_SALFONT_H
+
+// -=-= exports =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+class SalFontCache;
+struct SalFontDimension;
+class SalFontFamily;
+class SalFontFamilyList;
+class SalFontStruct;
+class SalFontStructList;
+class SalFonts;
+
+// -=-= includes -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#include <salstd.hxx>
+#include <vcl/outfont.hxx>
+
+// -=-= forwards =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+typedef ULONG XFP_FLAGS;
+
+class SalDisplay;
+class SalFontCacheItem;
+
+// -=-= SalFontCache -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+DECLARE_LIST( SalFontCache, SalFontCacheItem* )
+
+// -=-= SalFontDimension -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+struct SalFontDimension
+{
+ USHORT nHeight_; // [pixel]
+ USHORT nPtHeight_; // [point/10]
+ USHORT nAverage_; // [pixel/10]
+ USHORT nXRes_; // [dpi]
+ USHORT nYRes_; // [dpi]
+ USHORT nSlant_; // [pixel]
+// size_t nUnderlineThickness_; // [pixel]
+// size_t nUnderlinePosition_; // [pixel]
+// size_t nStrikeoutAscent_; // [pixel]
+// size_t nStrikeoutDescent_; // [pixel]
+// Subscript, Superscript, Capital, Space ...
+
+ inline SalFontDimension( USHORT nA = 0, USHORT nH = 0 );
+
+ inline BOOL IsScalable() const;
+ inline USHORT GetWidth() const { return (nAverage_ + 5) / 10; }
+ inline Size GetSize() const;
+ inline void SetSize( const Size & rSize );
+ inline BOOL operator == ( const SalFontDimension &r ) const;
+ inline BOOL operator != ( const SalFontDimension &r ) const;
+ inline BOOL operator >= ( const SalFontDimension &r ) const;
+};
+
+inline SalFontDimension::SalFontDimension( USHORT nA, USHORT nH )
+ : nHeight_( nH ), nAverage_( nA )
+{ nPtHeight_ = nXRes_ = nYRes_ = nSlant_ = 0; }
+
+inline BOOL SalFontDimension::IsScalable() const
+{ return !nHeight_ && !nPtHeight_ && !nAverage_; }
+
+inline Size SalFontDimension::GetSize() const
+{ return Size( (nAverage_ + 5) / 10, nHeight_ ); }
+
+inline void SalFontDimension::SetSize( const Size & rSize )
+{ nAverage_ = (USHORT)rSize.Width() * 10; nHeight_ = (USHORT)rSize.Height(); }
+
+inline BOOL SalFontDimension::operator == ( const SalFontDimension &r ) const
+{ return nHeight_ == r.nHeight_ && (!r.nAverage_ || nAverage_ == r.nAverage_); }
+
+inline BOOL SalFontDimension::operator != ( const SalFontDimension &r ) const
+{ return !(*this == r); }
+
+inline BOOL SalFontDimension::operator >= ( const SalFontDimension &r ) const
+{ return nHeight_ > r.nHeight_
+ || (nHeight_ == r.nHeight_ && nAverage_ >= r.nAverage_); }
+
+// -=-= SalFontStruct =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+class SalFontStruct : public ImplFontMetricData
+{
+ friend class SalDisplay;
+ friend class SalGraphicsData;
+
+ SalFontCacheItem*pCache_;
+
+#if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
+ ByteString aFontName_;
+#endif
+ USHORT nHeightCount_; // Anzahl der Hoehen-Eintraege
+ SalFontDimension*pDimensions_; // Hoehen-Array
+ USHORT nWeight_;
+
+ USHORT nFoundry_; // properties indexies
+ USHORT nFamily_;
+ USHORT nWeightName_;
+ USHORT nSlant_;
+ USHORT nSetWidthName_;
+ ByteString aAddStyleName_;
+ USHORT nSpacing_;
+ USHORT nCharSet_;
+ USHORT nFaceName_;
+ BOOL mbValidFontDescription; // valid xlfd entries
+
+ void Init();
+ BOOL Init( SalDisplay* pDisp,
+ const char* pFontName,
+ SalFontDimension& rDim );
+
+ ByteString GetXFontName( const SalFontDimension& );
+
+ inline void SetFoundry( USHORT n )
+ { nFoundry_ = n; }
+ inline void SetFamily( USHORT n )
+ { meFamily = sal_FamilyToSal( nFamily_ = n ); }
+ inline void SetWeightName( USHORT n )
+ { meWeight = sal_WeightToSal( nWeightName_ = n ); }
+ inline void SetSlant( USHORT n )
+ { meItalic = sal_ItalicToSal( nSlant_ = n ); }
+ inline void SetSetWidthName( USHORT n )
+ { nSetWidthName_ = n; }
+ inline void SetAddStyleName( const ByteString& rAddStyle )
+ { aAddStyleName_ = rAddStyle; aAddStyleName_.ToLowerAscii(); }
+ inline void SetSpacing( USHORT n )
+ { mePitch = sal_PitchToSal( nSpacing_ = n ); }
+ inline void SetAverage( long n )
+ { mnWidth = (n + 5) / 10; }
+ void SetCharSet( USHORT n );
+
+ SalFontStruct( const SalFontStruct& rFont );
+public:
+ SalFontStruct( SalDisplay* pDisp,
+ const char* pFontName,
+ SalFontDimension& rDim );
+
+ ~SalFontStruct();
+
+ inline void Cache( SalFontCacheItem *p ) { pCache_ = p; }
+ inline SalFontCacheItem*IsCache() const { return pCache_; }
+ inline BOOL IsScalable() const { return TYPE_SCALABLE==meType; }
+ inline SalFontDimension*GetDim() const { return pDimensions_; }
+ inline BOOL IsValid() const { return mbValidFontDescription; }
+#ifdef DBG_UTIL
+ const ByteString& GetName() const { return aFontName_; }
+#endif
+
+ ImplFontData *GetDevFontData();
+ SalFontCacheItem*Load( SalDisplay *pDisp, const SalFontDimension &rDim );
+ CharSet GetCharSet() { return meCharSet; }
+
+};
+
+// -=-= SalFontStructList =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+DECLARE_LIST( SalFontStructList, SalFontStruct* )
+
+#endif // _SV_SALFONT_H
+
diff --git a/vcl/unx/inc/salframe.h b/vcl/unx/inc/salframe.h
new file mode 100644
index 000000000000..6f962c9a13b3
--- /dev/null
+++ b/vcl/unx/inc/salframe.h
@@ -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.
+ *
+ ************************************************************************/
+#ifndef _SV_SALFRAME_H
+#define _SV_SALFRAME_H
+
+// -=-= #includes -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+#include <salstd.hxx>
+#include <vcl/salframe.hxx>
+#include <vcl/salwtype.hxx>
+#ifndef _SV_PTRSTYLE_HXX
+#include <vcl/ptrstyle.hxx>
+#endif
+#include <vcl/salinst.hxx>
+#include <vcl/sysdata.hxx>
+#include <vcl/timer.hxx>
+#include <vcl/dllapi.h>
+
+#include <salunx.h>
+#include <list>
+
+// -=-= forwards -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+class SalDisplay;
+class X11SalGraphics;
+class SalGraphicsLayout;
+class SalI18N_InputContext;
+
+namespace vcl_sal { class WMAdaptor; class NetWMAdaptor; class GnomeWMAdaptor; }
+
+// -=-= X11SalFrame =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+#define SHOWSTATE_UNKNOWN -1
+#define SHOWSTATE_MINIMIZED 0
+#define SHOWSTATE_NORMAL 1
+#define SHOWSTATE_HIDDEN 2
+
+class VCL_DLLPUBLIC X11SalFrame : public SalFrame
+{
+ friend class vcl_sal::WMAdaptor;
+ friend class vcl_sal::NetWMAdaptor;
+ friend class vcl_sal::GnomeWMAdaptor;
+
+ static X11SalFrame* s_pSaveYourselfFrame;
+
+ X11SalFrame* mpParent; // pointer to parent frame
+ // which should never obscur this frame
+ bool mbTransientForRoot;
+ std::list< X11SalFrame* > maChildren; // List of child frames
+
+ SalDisplay *pDisplay_;
+ int m_nScreen;
+ XLIB_Window mhWindow;
+ XLIB_Window mhShellWindow;
+ XLIB_Window mhForeignParent;
+ // window to fall back to when no longer in fullscreen mode
+ XLIB_Window mhStackingWindow;
+ // window to listen for CirculateNotify events
+
+ Pixmap mhBackgroundPixmap;
+
+ XLIB_Cursor hCursor_;
+ int nCaptured_; // is captured
+
+ X11SalGraphics *pGraphics_; // current frame graphics
+ X11SalGraphics *pFreeGraphics_; // first free frame graphics
+
+ XLIB_Time nReleaseTime_; // timestamp of last key release
+ USHORT nKeyCode_; // last key code
+ USHORT nKeyState_; // last key state
+ int nCompose_; // compose state
+ bool mbKeyMenu;
+ bool mbSendExtKeyModChange;
+ USHORT mnExtKeyMod;
+
+ int nShowState_; // show state
+ int nWidth_; // client width
+ int nHeight_; // client height
+ Rectangle maRestorePosSize;
+ ULONG nStyle_;
+ SalExtStyle mnExtStyle;
+ BOOL bAlwaysOnTop_;
+ BOOL bViewable_;
+ BOOL bMapped_;
+ BOOL mbInShow;
+ BOOL bDefaultPosition_; // client is centered initially
+ bool m_bXEmbed;
+ int nVisibility_;
+ int m_nWorkArea;
+
+ int nScreenSaversTimeout_;
+ Rectangle maPaintRegion;
+
+ Timer maAlwaysOnTopRaiseTimer;
+
+ // data for WMAdaptor
+ int meWindowType;
+ int mnDecorationFlags;
+ bool mbMaximizedVert;
+ bool mbMaximizedHorz;
+ bool mbShaded;
+ bool mbFullScreen;
+
+ // icon id
+ int mnIconID;
+
+ String m_aTitle;
+
+ SystemChildData maSystemChildData;
+
+ SalI18N_InputContext *mpInputContext;
+ Bool mbInputFocus;
+
+ XRectangle* m_pClipRectangles;
+ int m_nCurClipRect;
+ int m_nMaxClipRect;
+
+
+ void GetPosSize( Rectangle &rPosSize );
+ void SetSize ( const Size &rSize );
+ void Center();
+ void SetPosSize( const Rectangle &rPosSize );
+ void Minimize();
+ void Maximize();
+ void Restore();
+ void SetWindowGravity (int nGravity ) const;
+
+ void RestackChildren( XLIB_Window* pTopLevelWindows, int nTopLevelWindows );
+ void RestackChildren();
+
+ long HandleKeyEvent ( XKeyEvent *pEvent );
+ long HandleMouseEvent ( XEvent *pEvent );
+ long HandleFocusEvent ( XFocusChangeEvent *pEvent );
+ long HandleExposeEvent ( XEvent *pEvent );
+ long HandleSizeEvent ( XConfigureEvent *pEvent );
+ long HandleColormapEvent ( XColormapEvent *pEvent );
+ long HandleMapUnmapEvent ( XEvent *pEvent );
+ long HandleStateEvent ( XPropertyEvent *pEvent );
+ long HandleReparentEvent ( XReparentEvent *pEvent );
+ long HandleClientMessage ( XClientMessageEvent*pEvent );
+
+ DECL_LINK( HandleAlwaysOnTopRaise, void* );
+
+ void passOnSaveYourSelf();
+
+ void createNewWindow( XLIB_Window aParent, int nScreen = -1 );
+ void updateScreenNumber();
+
+ void setXEmbedInfo();
+ void askForXEmbedFocus( sal_Int32 i_nTimeCode );
+public:
+ X11SalFrame( SalFrame* pParent, ULONG nSalFrameStyle, SystemParentData* pSystemParent = NULL );
+ virtual ~X11SalFrame();
+
+ long Dispatch( XEvent *pEvent );
+ void Init( ULONG nSalFrameStyle, int nScreen = -1,
+ SystemParentData* pParentData = NULL, bool bUseGeometry = false );
+
+ SalDisplay* GetDisplay() const { return pDisplay_; }
+ Display* GetXDisplay() const;
+ XLIB_Window GetDrawable() const;
+ int GetScreenNumber() const { return m_nScreen; }
+ XLIB_Window GetWindow() const { return mhWindow; }
+ XLIB_Window GetShellWindow() const { return mhShellWindow; }
+ XLIB_Window GetForeignParent() const { return mhForeignParent; }
+ XLIB_Window GetStackingWindow() const { return mhStackingWindow; }
+ long ShutDown() const { return CallCallback( SALEVENT_SHUTDOWN, 0 ); }
+ long Close() const { return CallCallback( SALEVENT_CLOSE, 0 ); }
+ ULONG GetStyle() const { return nStyle_; }
+
+ inline XLIB_Cursor GetCursor() const { return hCursor_; }
+ inline BOOL IsCaptured() const { return nCaptured_ == 1; }
+#if !defined(__synchronous_extinput__)
+ void HandleExtTextEvent (XClientMessageEvent *pEvent);
+ void PostExtTextEvent (sal_uInt16 nExtTextEventType,
+ void *pExtTextEvent);
+#endif
+ bool IsOverrideRedirect() const;
+ bool IsChildWindow() const { return (nStyle_ & (SAL_FRAME_STYLE_PLUG|SAL_FRAME_STYLE_SYSTEMCHILD)) != 0; }
+ bool IsSysChildWindow() const { return (nStyle_ & (SAL_FRAME_STYLE_SYSTEMCHILD)) != 0; }
+ bool IsFloatGrabWindow() const;
+ SalI18N_InputContext* getInputContext() const { return mpInputContext; }
+ void getPosSize( Rectangle& rRect ) { GetPosSize( rRect ); }
+ void setPosSize( const Rectangle& rRect ) { SetPosSize( rRect ); }
+ bool isMapped() const { return bMapped_; }
+ bool hasFocus() const { return mbInputFocus; }
+
+ virtual SalGraphics* GetGraphics();
+ virtual void ReleaseGraphics( SalGraphics* pGraphics );
+
+ // call with true to clear graphics (setting None as drawable)
+ // call with false to setup graphics with window (GetWindow())
+ virtual void updateGraphics( bool bClear );
+
+ virtual BOOL PostEvent( void* pData );
+
+ virtual void SetTitle( const XubString& rTitle );
+ virtual void SetIcon( USHORT nIcon );
+ virtual void SetMenu( SalMenu* pMenu );
+ virtual void DrawMenuBar();
+
+ virtual void SetExtendedFrameStyle( SalExtStyle nExtStyle );
+ virtual void Show( BOOL bVisible, BOOL bNoActivate = FALSE );
+ virtual void Enable( BOOL bEnable );
+ virtual void SetMinClientSize( long nWidth, long nHeight );
+ virtual void SetMaxClientSize( long nWidth, long nHeight );
+ virtual void SetPosSize( long nX, long nY, long nWidth, long nHeight, USHORT nFlags );
+ virtual void GetClientSize( long& rWidth, long& rHeight );
+ virtual void GetWorkArea( Rectangle& rRect );
+ virtual SalFrame* GetParent() const;
+ virtual void SetWindowState( const SalFrameState* pState );
+ virtual BOOL GetWindowState( SalFrameState* pState );
+ virtual void ShowFullScreen( BOOL bFullScreen, sal_Int32 nMonitor );
+ virtual void StartPresentation( BOOL bStart );
+ virtual void SetAlwaysOnTop( BOOL bOnTop );
+ virtual void ToTop( USHORT nFlags );
+ virtual void SetPointer( PointerStyle ePointerStyle );
+ virtual void CaptureMouse( BOOL bMouse );
+ virtual void SetPointerPos( long nX, long nY );
+ using SalFrame::Flush;
+ virtual void Flush();
+ virtual void Sync();
+ virtual void SetInputContext( SalInputContext* pContext );
+ virtual void EndExtTextInput( USHORT nFlags );
+ virtual String GetKeyName( USHORT nKeyCode );
+ virtual String GetSymbolKeyName( const XubString& rFontName, USHORT nKeyCode );
+ virtual BOOL MapUnicodeToKeyCode( sal_Unicode aUnicode, LanguageType aLangType, KeyCode& rKeyCode );
+ virtual LanguageType GetInputLanguage();
+ virtual SalBitmap* SnapShot();
+ virtual void UpdateSettings( AllSettings& rSettings );
+ virtual void Beep( SoundType eSoundType );
+ virtual const SystemEnvData* GetSystemData() const;
+ virtual SalPointerState GetPointerState();
+ virtual void SetParent( SalFrame* pNewParent );
+ virtual bool SetPluginParent( SystemParentData* pNewParent );
+ virtual void SetBackgroundBitmap( SalBitmap* pBitmap );
+
+ virtual void SetScreenNumber( unsigned int );
+
+ // shaped system windows
+ // set clip region to none (-> rectangular windows, normal state)
+ virtual void ResetClipRegion();
+ // start setting the clipregion consisting of nRects rectangles
+ virtual void BeginSetClipRegion( ULONG nRects );
+ // add a rectangle to the clip region
+ virtual void UnionClipRegion( long nX, long nY, long nWidth, long nHeight );
+ // done setting up the clipregion
+ virtual void EndSetClipRegion();
+
+ static void SaveYourselfDone( SalFrame* );
+ static Bool checkKeyReleaseForRepeat( Display*, XEvent*, XPointer pX11SalFrame );
+};
+
+#ifdef _SV_SALDISP_HXX
+
+inline Display *X11SalFrame::GetXDisplay() const
+{ return pDisplay_->GetDisplay(); }
+
+inline XLIB_Window X11SalFrame::GetDrawable() const
+{ return GetWindow(); }
+
+#endif
+
+#endif // _SV_SALFRAME_H
+
diff --git a/vcl/unx/inc/salgdi.h b/vcl/unx/inc/salgdi.h
new file mode 100644
index 000000000000..42d9c5592317
--- /dev/null
+++ b/vcl/unx/inc/salgdi.h
@@ -0,0 +1,405 @@
+/*************************************************************************
+ *
+ * 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_SALGDI_H
+#define _SV_SALGDI_H
+
+
+// -=-= exports -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+class SalFontCacheItem;
+
+// -=-= includes -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#include "salstd.hxx"
+#include "vcl/salgdi.hxx"
+#include "vcl/salgtype.hxx"
+#include "tools/fract.hxx"
+#include "vcl/dllapi.h"
+#include <deque>
+#include "xfont.hxx"
+
+// -=-= forwards -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+struct ImplFontMetricData;
+struct ImplFontSelectData;
+class SalBitmap;
+class SalColormap;
+class SalDisplay;
+class SalFrame;
+class X11SalVirtualDevice;
+class SalPolyLine;
+class PspSalPrinter;
+class PspSalInfoPrinter;
+class ServerFont;
+class ImplLayoutArgs;
+class X11FontLayout;
+class ServerFontLayout;
+
+namespace basegfx {
+ class B2DTrapezoid;
+}
+
+// -=-= SalGraphicsData =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+class CairoFontsCache
+{
+private:
+ static int mnRefCount;
+ typedef std::deque< std::pair<void *, void*> > LRUFonts;
+ static LRUFonts maLRUFonts;
+public:
+ CairoFontsCache();
+ static void CacheFont(void *pFont, void *pId);
+ static void* FindCachedFont(void *pId);
+ ~CairoFontsCache();
+};
+
+class VCL_DLLPUBLIC X11SalGraphics : public SalGraphics
+{
+ friend class X11FontLayout;
+ friend class ServerFontLayout;
+protected:
+ SalFrame* m_pFrame; // the SalFrame which created this Graphics or NULL
+ X11SalVirtualDevice* m_pVDev; // the SalVirtualDevice which created this Graphics or NULL
+
+ const SalColormap* m_pColormap;
+ SalColormap *m_pDeleteColormap;
+ Drawable hDrawable_; // use
+ int m_nScreen;
+ void* m_pRenderFormat;
+ XID m_aRenderPicture;
+ CairoFontsCache m_aCairoFontsCache;
+
+ XLIB_Region pPaintRegion_;
+ XLIB_Region pClipRegion_;
+
+ GC pPenGC_; // Pen attributes
+ SalColor nPenColor_;
+ Pixel nPenPixel_;
+
+ GC pFontGC_; // Font attributes
+ ExtendedFontStructRef mXFont[ MAX_FALLBACK ];
+ ServerFont* mpServerFont[ MAX_FALLBACK ];
+
+ SalColor nTextColor_;
+ Pixel nTextPixel_;
+ BOOL bFontVertical_;
+
+ BOOL bDisableGraphite_;
+
+ GC pBrushGC_; // Brush attributes
+ SalColor nBrushColor_;
+ Pixel nBrushPixel_;
+ Pixmap hBrush_; // Dither
+
+ GC pMonoGC_;
+ GC pCopyGC_;
+ GC pMaskGC_;
+ GC pInvertGC_;
+ GC pInvert50GC_;
+ GC pStippleGC_;
+ GC pTrackingGC_;
+
+ BOOL bWindow_ : 1; // is Window
+ BOOL bPrinter_ : 1; // is Printer
+ BOOL bVirDev_ : 1; // is VirDev
+ BOOL bPenGC_ : 1; // is Pen GC valid
+ BOOL bFontGC_ : 1; // is Font GC valid
+ BOOL bBrushGC_ : 1; // is Brush GC valid
+ BOOL bMonoGC_ : 1; // is Mono GC valid
+ BOOL bCopyGC_ : 1; // is Copy GC valid
+ BOOL bInvertGC_ : 1; // is Invert GC valid
+ BOOL bInvert50GC_ : 1; // is Invert50 GC valid
+ BOOL bStippleGC_ : 1; // is Stipple GC valid
+ BOOL bTrackingGC_ : 1; // is Tracking GC valid
+ bool bXORMode_ : 1; // is ROP XOR Mode set
+ BOOL bDitherBrush_ : 1; // is solid or tile
+
+ void SetClipRegion( GC pGC,
+ XLIB_Region pXReg = NULL ) const;
+
+ GC GetTrackingGC();
+ GC GetInvertGC();
+ GC GetInvert50GC();
+ GC CreateGC( Drawable hDrawable,
+ unsigned long nMask = GCGraphicsExposures );
+ GC SelectPen();
+ GC SelectBrush();
+ void DrawLines( ULONG nPoints,
+ const SalPolyLine &rPoints,
+ GC pGC,
+ bool bClose
+ );
+ BOOL GetDitherPixmap ( SalColor nSalColor );
+
+ inline GC GetMonoGC( Pixmap hPixmap );
+ inline GC GetCopyGC();
+ inline GC GetStippleGC();
+
+ int Clip ( XLIB_Region pRegion,
+ int &nX,
+ int &nY,
+ unsigned int &nDX,
+ unsigned int &nDY,
+ int &nSrcX,
+ int &nSrcY ) const;
+ int Clip ( int &nX,
+ int &nY,
+ unsigned int &nDX,
+ unsigned int &nDY,
+ int &nSrcX,
+ int &nSrcY ) const;
+ GC SetMask ( int &nX,
+ int &nY,
+ unsigned int &nDX,
+ unsigned int &nDY,
+ int &nSrcX,
+ int &nSrcY,
+ Pixmap hClipMask );
+ using SalGraphics::DrawBitmap;
+ void DrawBitmap( const SalTwoRect *pPosAry,
+ SalGraphics *pThis,
+ const SalBitmap &rSalBitmap,
+ const SalBitmap &rTransparentBitmap,
+ SalColor nTransparentColor );
+
+ GC SelectFont();
+ bool setFont( const ImplFontSelectData* pEntry, int nFallbackLevel );
+
+ void drawMaskedBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ const SalBitmap& rTransparentBitmap );
+
+protected:
+ void DrawStringUCS2MB( ExtendedFontStruct& rFont, const Point&,
+ const sal_Unicode* pStr, int nLength );
+
+ void DrawPrinterString( const SalLayout& );
+
+ void DrawServerFontString( const ServerFontLayout& );
+ void DrawServerSimpleFontString( const ServerFontLayout& );
+ void DrawServerAAFontString( const ServerFontLayout& );
+ bool DrawServerAAForcedString( const ServerFontLayout& );
+ void DrawCairoAAFontString( const ServerFontLayout& );
+
+ void freeResources();
+public:
+ X11SalGraphics();
+ virtual ~X11SalGraphics();
+
+ void Init( SalFrame *pFrame, Drawable aDrawable, int nScreen );
+ void Init( X11SalVirtualDevice *pVirtualDevice, SalColormap* pColormap = NULL, bool bDeleteColormap = false );
+ void Init( class ImplSalPrinterData *pPrinter );
+ void DeInit();
+
+ inline const SalDisplay* GetDisplay() const;
+ inline Display* GetXDisplay() const;
+ inline const SalVisual& GetVisual() const;
+ inline Drawable GetDrawable() const { return hDrawable_; }
+ void SetDrawable( Drawable d, int nScreen );
+ XID GetXRenderPicture();
+ void* GetXRenderFormat() const { return m_pRenderFormat; }
+ inline void SetXRenderFormat( void* pRenderFormat ) { m_pRenderFormat = pRenderFormat; }
+ inline const SalColormap& GetColormap() const { return *m_pColormap; }
+ using SalGraphics::GetPixel;
+ inline Pixel GetPixel( SalColor nSalColor ) const;
+
+ int GetScreenNumber() const { return m_nScreen; }
+
+ // overload all pure virtual methods
+ virtual void GetResolution( sal_Int32& rDPIX, sal_Int32& rDPIY );
+ virtual USHORT GetBitCount();
+ virtual long GetGraphicsWidth() const;
+ virtual long GetGraphicsHeight() const;
+
+ virtual void ResetClipRegion();
+ virtual void BeginSetClipRegion( ULONG nCount );
+ virtual BOOL unionClipRegion( long nX, long nY, long nWidth, long nHeight );
+ virtual bool unionClipRegion( const ::basegfx::B2DPolyPolygon& );
+ virtual void EndSetClipRegion();
+
+ virtual void SetLineColor();
+ virtual void SetLineColor( SalColor nSalColor );
+ virtual void SetFillColor();
+
+ virtual void SetFillColor( SalColor nSalColor );
+
+ virtual void SetXORMode( bool bSet, bool );
+
+ virtual void SetROPLineColor( SalROPColor nROPColor );
+ virtual void SetROPFillColor( SalROPColor nROPColor );
+
+ virtual void SetTextColor( SalColor nSalColor );
+ virtual USHORT SetFont( ImplFontSelectData*, int nFallbackLevel );
+ virtual void GetFontMetric( ImplFontMetricData* );
+ virtual ULONG GetKernPairs( ULONG nMaxPairs, ImplKernPairData* );
+ virtual ImplFontCharMap* GetImplFontCharMap() const;
+ virtual void GetDevFontList( ImplDevFontList* );
+ virtual void GetDevFontSubstList( OutputDevice* );
+ virtual bool AddTempDevFont( ImplDevFontList*, const String& rFileURL, const String& rFontName );
+ virtual BOOL CreateFontSubset( const rtl::OUString& rToFile,
+ const ImplFontData*,
+ sal_Int32* pGlyphIDs,
+ sal_uInt8* pEncoding,
+ sal_Int32* pWidths,
+ int nGlyphs,
+ FontSubsetInfo& rInfo
+ );
+ virtual const Ucs2SIntMap* GetFontEncodingVector( const ImplFontData*, const Ucs2OStrMap** ppNonEncoded );
+ virtual const void* GetEmbedFontData( const ImplFontData*,
+ const sal_Ucs* pUnicodes,
+ sal_Int32* pWidths,
+ FontSubsetInfo& rInfo,
+ long* pDataLen );
+ virtual void FreeEmbedFontData( const void* pData, long nDataLen );
+ virtual void GetGlyphWidths( const ImplFontData*,
+ bool bVertical,
+ Int32Vector& rWidths,
+ Ucs2UIntMap& rUnicodeEnc );
+ virtual BOOL GetGlyphBoundRect( long nIndex, Rectangle& );
+ virtual BOOL GetGlyphOutline( long nIndex, ::basegfx::B2DPolyPolygon& );
+ virtual SalLayout* GetTextLayout( ImplLayoutArgs&, int nFallbackLevel );
+ virtual void DrawServerFontLayout( const ServerFontLayout& );
+ virtual bool supportsOperation( OutDevSupportType ) const;
+ virtual void drawPixel( long nX, long nY );
+ virtual void drawPixel( long nX, long nY, SalColor nSalColor );
+ virtual void drawLine( long nX1, long nY1, long nX2, long nY2 );
+ virtual void drawRect( long nX, long nY, long nWidth, long nHeight );
+ void drawPolyLine( ULONG nPoints, const SalPoint* pPtAry, bool bClose );
+ virtual void drawPolyLine( ULONG nPoints, const SalPoint* pPtAry );
+ virtual void drawPolygon( ULONG nPoints, const SalPoint* pPtAry );
+ virtual void drawPolyPolygon( sal_uInt32 nPoly,
+ const sal_uInt32* pPoints,
+ PCONSTSALPOINT* pPtAry );
+ virtual bool drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double fTransparency );
+ virtual bool drawPolyLine( const ::basegfx::B2DPolygon&, double fTransparency, const ::basegfx::B2DVector& rLineWidth, basegfx::B2DLineJoin );
+ virtual bool drawFilledTrapezoids( const ::basegfx::B2DTrapezoid*, int nTrapCount, double fTransparency );
+
+#if 1 // TODO: remove these obselete methods
+ virtual sal_Bool drawPolyLineBezier( ULONG nPoints,
+ const SalPoint* pPtAry,
+ const BYTE* pFlgAry );
+ virtual sal_Bool drawPolygonBezier( ULONG nPoints,
+ const SalPoint* pPtAry,
+ const BYTE* pFlgAry );
+ virtual sal_Bool drawPolyPolygonBezier( sal_uInt32 nPoly,
+ const sal_uInt32* pPoints,
+ const SalPoint* const* pPtAry,
+ const BYTE* const* pFlgAry );
+#endif
+
+ virtual void copyArea( long nDestX,
+ long nDestY,
+ long nSrcX,
+ long nSrcY,
+ long nSrcWidth,
+ long nSrcHeight,
+ USHORT nFlags );
+ virtual void copyBits( const SalTwoRect* pPosAry,
+ SalGraphics* pSrcGraphics );
+ virtual void drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap );
+ virtual void drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ SalColor nTransparentColor );
+ virtual void drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ const SalBitmap& rMaskBitmap );
+ virtual void drawMask( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ SalColor nMaskColor );
+ virtual SalBitmap* getBitmap( long nX, long nY, long nWidth, long nHeight );
+ virtual SalColor getPixel( long nX, long nY );
+ virtual void invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags );
+ virtual void invert( ULONG nPoints, const SalPoint* pPtAry, SalInvert nFlags );
+
+ virtual BOOL drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, ULONG nSize );
+
+ virtual bool drawAlphaBitmap( const SalTwoRect&,
+ const SalBitmap& rSourceBitmap,
+ const SalBitmap& rAlphaBitmap );
+
+ virtual bool drawAlphaRect( long nX, long nY, long nWidth,
+ long nHeight, sal_uInt8 nTransparency );
+
+ virtual SystemGraphicsData GetGraphicsData() const;
+ virtual SystemFontData GetSysFontData( int nFallbacklevel ) const;
+
+ /* use to handle GraphicsExpose/NoExpose after XCopyArea & friends
+ * if pFrame is not NULL, corresponding Paint events are generated
+ * and dispatched to pFrame
+ *
+ * it is imperative to eat up graphics exposes even in case you don't need
+ * them because the next one using XCopyArea can depend on them
+ */
+ void YieldGraphicsExpose();
+
+ // do XCopyArea or XGet/PutImage depending on screen numbers
+ // signature is like XCopyArea with screen numbers added
+ static void CopyScreenArea( Display* pDisplay,
+ Drawable aSrc, int nScreenSrc, int nSrcDepth,
+ Drawable aDest, int nScreenDest, int nDestDepth,
+ GC aDestGC,
+ int src_x, int src_y,
+ unsigned int w, unsigned int h,
+ int dest_x, int dest_y );
+ static void releaseGlyphPeer();
+};
+
+
+inline const SalDisplay *X11SalGraphics::GetDisplay() const
+{ return GetColormap().GetDisplay(); }
+
+inline const SalVisual& X11SalGraphics::GetVisual() const
+{ return GetColormap().GetVisual(); }
+
+inline Display *X11SalGraphics::GetXDisplay() const
+{ return GetColormap().GetXDisplay(); }
+
+inline Pixel X11SalGraphics::GetPixel( SalColor nSalColor ) const
+{ return GetColormap().GetPixel( nSalColor ); }
+
+
+// -=-= Shortcuts =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+#ifdef DBG_UTIL
+#define stderr0( s ) fprintf( stderr, s )
+#define stderr1( s, a ) fprintf( stderr, s, a )
+#define stderr2( s, a, b ) fprintf( stderr, s, a, b )
+#define stderr3( s, a, b, c ) fprintf( stderr, s, a, b, c )
+#define stdass0( b ) (void)( !(b) \
+ ? fprintf( stderr, "\"%s\" (%s line %d)\n", \
+ #b, __FILE__, __LINE__ ) \
+ : 0 )
+#else
+#define stderr0( s ) ;
+#define stderr1( s, a ) ;
+#define stderr2( s, a, b ) ;
+#define stderr3( s, a, b, c ) ;
+#define stdass0( b ) ;
+#endif
+
+#endif // _SV_SALGDI_H
+
diff --git a/vcl/unx/inc/salinst.h b/vcl/unx/inc/salinst.h
new file mode 100644
index 000000000000..d73d67f81425
--- /dev/null
+++ b/vcl/unx/inc/salinst.h
@@ -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.
+ *
+ ************************************************************************/
+
+// -=-= includes -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#ifndef _SV_SALINST_H
+#define _SV_SALINST_H
+
+#include <vcl/sv.h>
+#ifndef _VOS_MUTEX_HXX
+#include <vos/mutex.hxx>
+#endif
+#ifndef _VOS_THREAD_HXX
+#include <vos/thread.hxx>
+#endif
+#include <vcl/dllapi.h>
+#include <vcl/salinst.hxx>
+
+class VCL_DLLPUBLIC SalYieldMutex : public NAMESPACE_VOS(OMutex)
+{
+protected:
+ ULONG mnCount;
+ NAMESPACE_VOS(OThread)::TThreadIdentifier mnThreadId;
+
+public:
+ SalYieldMutex();
+
+ virtual void acquire();
+ virtual void release();
+ virtual sal_Bool tryToAcquire();
+
+ ULONG GetAcquireCount() const { return mnCount; }
+ NAMESPACE_VOS(OThread)::TThreadIdentifier GetThreadId() const { return mnThreadId; }
+};
+
+// -=-= SalInstanceData =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+class VCL_DLLPUBLIC X11SalInstance : public SalInstance
+{
+protected:
+ SalYieldMutex* mpSalYieldMutex;
+ bool mbPrinterInit;
+
+public:
+ X11SalInstance( SalYieldMutex* pMutex )
+ : mpSalYieldMutex( pMutex ),
+ mbPrinterInit( false )
+ {}
+ virtual ~X11SalInstance();
+
+ virtual SalFrame* CreateChildFrame( SystemParentData* pParent, ULONG nStyle );
+ virtual SalFrame* CreateFrame( SalFrame* pParent, ULONG nStyle );
+ virtual void DestroyFrame( SalFrame* pFrame );
+
+ virtual SalObject* CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, BOOL bShow = TRUE );
+ virtual void DestroyObject( SalObject* pObject );
+
+ virtual SalVirtualDevice* CreateVirtualDevice( SalGraphics* pGraphics,
+ long nDX, long nDY,
+ USHORT nBitCount, const SystemGraphicsData *pData = NULL );
+ virtual void DestroyVirtualDevice( SalVirtualDevice* pDevice );
+
+ virtual SalInfoPrinter* CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
+ ImplJobSetup* pSetupData );
+ virtual void DestroyInfoPrinter( SalInfoPrinter* pPrinter );
+ virtual SalPrinter* CreatePrinter( SalInfoPrinter* pInfoPrinter );
+ virtual void DestroyPrinter( SalPrinter* pPrinter );
+
+ virtual void GetPrinterQueueInfo( ImplPrnQueueList* pList );
+ virtual void GetPrinterQueueState( SalPrinterQueueInfo* pInfo );
+ virtual void DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo );
+ virtual String GetDefaultPrinter();
+
+ virtual SalTimer* CreateSalTimer();
+ virtual SalI18NImeStatus* CreateI18NImeStatus();
+ virtual SalSystem* CreateSalSystem();
+ virtual SalBitmap* CreateSalBitmap();
+ virtual SalSession* CreateSalSession();
+
+ virtual vos::IMutex* GetYieldMutex();
+ virtual ULONG ReleaseYieldMutex();
+ virtual void AcquireYieldMutex( ULONG nCount );
+
+ virtual void Yield( bool bWait, bool bHandleAllCurrentEvents );
+ virtual bool AnyInput( USHORT nType );
+ virtual SalMenu* CreateMenu( BOOL bMenuBar );
+ virtual void DestroyMenu( SalMenu* pMenu);
+ virtual SalMenuItem* CreateMenuItem( const SalItemParams* pItemData );
+ virtual void DestroyMenuItem( SalMenuItem* pItem );
+
+ virtual void* GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes );
+ void FillFontPathList( std::list< rtl::OString >& o_rFontPaths );
+
+ // dtrans implementation
+ virtual com::sun::star::uno::Reference< com::sun::star::uno::XInterface >
+ CreateClipboard( const com::sun::star::uno::Sequence< com::sun::star::uno::Any >& i_rArguments );
+ virtual com::sun::star::uno::Reference< com::sun::star::uno::XInterface > CreateDragSource();
+ virtual com::sun::star::uno::Reference< com::sun::star::uno::XInterface > CreateDropTarget();
+ virtual void AddToRecentDocumentList(const rtl::OUString& rFileUrl, const rtl::OUString& rMimeType);
+
+
+ bool isPrinterInit() const
+ {
+ return mbPrinterInit;
+ }
+};
+
+#endif // _SV_SALINST_H
+
diff --git a/vcl/unx/inc/salmenu.h b/vcl/unx/inc/salmenu.h
new file mode 100644
index 000000000000..09a753ff1d98
--- /dev/null
+++ b/vcl/unx/inc/salmenu.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALMENU_H
+#define _SV_SALMENU_H
+
+#include <vcl/sv.h>
+#include <vcl/bitmap.hxx>
+#include <vcl/salmenu.hxx>
+
+
+class X11SalMenu : public SalMenu
+{
+public:
+ X11SalMenu() {}
+ virtual ~X11SalMenu();
+
+ virtual BOOL VisibleMenuBar(); // must return TRUE to actually DISPLAY native menu bars
+ // otherwise only menu messages are processed (eg, OLE on Windows)
+
+ virtual void InsertItem( SalMenuItem* pSalMenuItem, unsigned nPos );
+ virtual void RemoveItem( unsigned nPos );
+ virtual void SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos );
+ virtual void SetFrame( const SalFrame* pFrame );
+ virtual void CheckItem( unsigned nPos, BOOL bCheck );
+ virtual void EnableItem( unsigned nPos, BOOL bEnable );
+ virtual void SetItemText( unsigned nPos, SalMenuItem* pSalMenuItem, const XubString& rText );
+ virtual void SetItemImage( unsigned nPos, SalMenuItem* pSalMenuItem, const Image& rImage);
+ virtual void SetAccelerator( unsigned nPos, SalMenuItem* pSalMenuItem, const KeyCode& rKeyCode, const XubString& rKeyName );
+ virtual void GetSystemMenuData( SystemMenuData* pData );
+};
+
+class X11SalMenuItem : public SalMenuItem
+{
+public:
+ X11SalMenuItem() {}
+ virtual ~X11SalMenuItem();
+};
+
+#endif // _SV_SALMENU_H
+
diff --git a/vcl/unx/inc/salobj.h b/vcl/unx/inc/salobj.h
new file mode 100644
index 000000000000..fa9f1309c8ca
--- /dev/null
+++ b/vcl/unx/inc/salobj.h
@@ -0,0 +1,103 @@
+/*************************************************************************
+ *
+ * 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_SALOBJ_H
+#define _SV_SALOBJ_H
+
+#include <vcl/sv.h>
+#include <vcl/sysdata.hxx>
+#include <vcl/salobj.hxx>
+#include <vcl/dllapi.h>
+
+class SalClipRegion
+{
+
+public:
+
+ SalClipRegion();
+ ~SalClipRegion();
+
+ void BeginSetClipRegion( ULONG nRects );
+ void UnionClipRegion( long nX, long nY, long nWidth, long nHeight );
+
+ XRectangle *EndSetClipRegion() {
+ return ClipRectangleList; }
+ void ResetClipRegion() {
+ numClipRectangles = 0; }
+ USHORT GetClipRegionType() {
+ return nClipRegionType; }
+ void SetClipRegionType( USHORT nType ) {
+ nClipRegionType = nType; }
+ int GetRectangleCount() {
+ return numClipRectangles; }
+
+private:
+
+ XRectangle* ClipRectangleList;
+ int numClipRectangles;
+ int maxClipRectangles;
+ USHORT nClipRegionType;
+};
+
+
+class X11SalObject : public SalObject
+{
+public:
+ SystemChildData maSystemChildData;
+ SalFrame* mpParent;
+ XLIB_Window maPrimary;
+ XLIB_Window maSecondary;
+ Colormap maColormap;
+ SalClipRegion maClipRegion;
+ BOOL mbVisible;
+
+ static VCL_DLLPUBLIC long Dispatch( XEvent* pEvent );
+ static VCL_DLLPUBLIC X11SalObject* CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, BOOL bShow = TRUE );
+
+ X11SalObject();
+ virtual ~X11SalObject();
+
+ // overload all pure virtual methods
+ virtual void ResetClipRegion();
+ virtual USHORT GetClipRegionType();
+ virtual void BeginSetClipRegion( ULONG nRects );
+ virtual void UnionClipRegion( long nX, long nY, long nWidth, long nHeight );
+ virtual void EndSetClipRegion();
+
+ virtual void SetPosSize( long nX, long nY, long nWidth, long nHeight );
+ virtual void Show( BOOL bVisible );
+ virtual void Enable( BOOL nEnable );
+ virtual void GrabFocus();
+
+ virtual void SetBackground();
+ virtual void SetBackground( SalColor nSalColor );
+
+ virtual const SystemEnvData* GetSystemData() const;
+
+};
+
+#endif // _SV_SALOBJ_H
diff --git a/vcl/unx/inc/salprn.h b/vcl/unx/inc/salprn.h
new file mode 100644
index 000000000000..fa68f1b38e73
--- /dev/null
+++ b/vcl/unx/inc/salprn.h
@@ -0,0 +1,120 @@
+/*************************************************************************
+ *
+ * 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_SALPRN_H
+#define _SV_SALPRN_H
+
+#include "vcl/jobdata.hxx"
+#include "vcl/printergfx.hxx"
+#include "vcl/printerjob.hxx"
+#include "vcl/salprn.hxx"
+
+class PspGraphics;
+
+class PspSalInfoPrinter : public SalInfoPrinter
+{
+public:
+ PspGraphics* m_pGraphics;
+ psp::JobData m_aJobData;
+ psp::PrinterGfx m_aPrinterGfx;
+
+ PspSalInfoPrinter();
+ virtual ~PspSalInfoPrinter();
+
+ // overload all pure virtual methods
+ virtual SalGraphics* GetGraphics();
+ virtual void ReleaseGraphics( SalGraphics* pGraphics );
+ virtual BOOL Setup( SalFrame* pFrame, ImplJobSetup* pSetupData );
+ virtual BOOL SetPrinterData( ImplJobSetup* pSetupData );
+ virtual BOOL SetData( ULONG nFlags, ImplJobSetup* pSetupData );
+ virtual void GetPageInfo( const ImplJobSetup* pSetupData,
+ long& rOutWidth, long& rOutHeight,
+ long& rPageOffX, long& rPageOffY,
+ long& rPageWidth, long& rPageHeight );
+ virtual ULONG GetCapabilities( const ImplJobSetup* pSetupData, USHORT nType );
+ virtual ULONG GetPaperBinCount( const ImplJobSetup* pSetupData );
+ virtual String GetPaperBinName( const ImplJobSetup* pSetupData, ULONG nPaperBin );
+ virtual void InitPaperFormats( const ImplJobSetup* pSetupData );
+ virtual int GetLandscapeAngle( const ImplJobSetup* pSetupData );
+};
+
+class PspSalPrinter : public SalPrinter
+{
+public:
+ String m_aFileName;
+ String m_aTmpFile;
+ String m_aFaxNr;
+ bool m_bFax:1;
+ bool m_bPdf:1;
+ bool m_bSwallowFaxNo:1;
+ PspGraphics* m_pGraphics;
+ psp::PrinterJob m_aPrintJob;
+ psp::JobData m_aJobData;
+ psp::PrinterGfx m_aPrinterGfx;
+ ULONG m_nCopies;
+ bool m_bCollate;
+ SalInfoPrinter* m_pInfoPrinter;
+
+ PspSalPrinter( SalInfoPrinter* );
+ virtual ~PspSalPrinter();
+
+ // overload all pure virtual methods
+ using SalPrinter::StartJob;
+ virtual BOOL StartJob( const XubString* pFileName,
+ const XubString& rJobName,
+ const XubString& rAppName,
+ ULONG nCopies,
+ bool bCollate,
+ bool bDirect,
+ ImplJobSetup* pSetupData );
+ virtual BOOL EndJob();
+ virtual BOOL AbortJob();
+ virtual SalGraphics* StartPage( ImplJobSetup* pSetupData, BOOL bNewJobData );
+ virtual BOOL EndPage();
+ virtual ULONG GetErrorCode();
+};
+
+class Timer;
+
+namespace vcl_sal {
+class VCL_DLLPUBLIC PrinterUpdate
+{
+ static Timer* pPrinterUpdateTimer;
+ static int nActiveJobs;
+
+ static void doUpdate();
+ DECL_STATIC_LINK( PrinterUpdate, UpdateTimerHdl, void* );
+public:
+ static void update();
+ static void jobStarted() { nActiveJobs++; }
+ static void jobEnded();
+};
+}
+
+#endif // _SV_SALPRN_H
+
+
diff --git a/vcl/unx/inc/salstd.hxx b/vcl/unx/inc/salstd.hxx
new file mode 100644
index 000000000000..cc03b3fb35a4
--- /dev/null
+++ b/vcl/unx/inc/salstd.hxx
@@ -0,0 +1,77 @@
+/*************************************************************************
+ *
+ * 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 _SALSTD_HXX
+#define _SALSTD_HXX
+
+// -=-= includes -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#include <tools/ref.hxx>
+#include <tools/string.hxx>
+#include <tools/gen.hxx>
+#include <vcl/sv.h>
+
+// -=-= X-Lib forwards -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#ifndef _SVUNX_H
+typedef unsigned long Pixel;
+typedef unsigned long XID;
+typedef unsigned long XLIB_Time;
+typedef unsigned long XtIntervalId;
+
+typedef XID Colormap;
+typedef XID Drawable;
+typedef XID Pixmap;
+typedef XID XLIB_Cursor;
+typedef XID XLIB_Font;
+typedef XID XLIB_Window;
+
+typedef struct _XDisplay Display;
+typedef struct _XGC *GC;
+typedef struct _XImage XImage;
+typedef struct _XRegion *XLIB_Region;
+
+typedef union _XEvent XEvent;
+
+typedef struct _XConfigureEvent XConfigureEvent;
+typedef struct _XReparentEvent XReparentEvent;
+typedef struct _XClientMessageEvent XClientMessageEvent;
+typedef struct _XErrorEvent XErrorEvent;
+
+struct Screen;
+struct Visual;
+struct XColormapEvent;
+struct XFocusChangeEvent;
+struct XFontStruct;
+struct XKeyEvent;
+struct XPropertyEvent;
+struct XTextItem;
+struct XWindowChanges;
+
+#define None 0L
+#endif
+
+#endif
+
diff --git a/vcl/unx/inc/salsys.h b/vcl/unx/inc/salsys.h
new file mode 100644
index 000000000000..1da7cae8564a
--- /dev/null
+++ b/vcl/unx/inc/salsys.h
@@ -0,0 +1,67 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// -=-= includes -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#ifndef _SV_SALSYS_H
+#define _SV_SALSYS_H
+
+#include <vcl/sv.h>
+#ifndef _VOS_MUTEX_HXX
+#include <vos/mutex.hxx>
+#endif
+#ifndef _VOS_THREAD_HXX
+#include <vos/thread.hxx>
+#endif
+#include <vcl/salsys.hxx>
+#include <vcl/dllapi.h>
+
+#include <list>
+
+class VCL_DLLPUBLIC X11SalSystem : public SalSystem
+{
+public:
+ X11SalSystem() {}
+ virtual ~X11SalSystem();
+
+ // overload pure virtual methods
+ virtual unsigned int GetDisplayScreenCount();
+ virtual bool IsMultiDisplay();
+ virtual unsigned int GetDefaultDisplayNumber();
+ virtual Rectangle GetDisplayScreenPosSizePixel( unsigned int nScreen );
+ virtual Rectangle GetDisplayWorkAreaPosSizePixel( unsigned int nScreen );
+ virtual rtl::OUString GetScreenName( unsigned int nScreen );
+ virtual int ShowNativeDialog( const String& rTitle,
+ const String& rMessage,
+ const std::list< String >& rButtons,
+ int nDefButton );
+ virtual int ShowNativeMessageBox( const String& rTitle,
+ const String& rMessage,
+ int nButtonCombination,
+ int nDefaultButton);
+};
+
+#endif // _SV_SALSYS_H
diff --git a/vcl/unx/inc/saltimer.h b/vcl/unx/inc/saltimer.h
new file mode 100644
index 000000000000..132107d705f8
--- /dev/null
+++ b/vcl/unx/inc/saltimer.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 _SV_SALTIMER_H
+#define _SV_SALTIMER_H
+
+#include <vcl/saltimer.hxx>
+
+class X11SalTimer : public SalTimer
+{
+public:
+ X11SalTimer() {}
+ virtual ~X11SalTimer();
+
+ // overload all pure virtual methods
+ void Start( ULONG nMS );
+ void Stop();
+};
+
+#endif
diff --git a/vcl/unx/inc/salunx.h b/vcl/unx/inc/salunx.h
new file mode 100644
index 000000000000..ef53273b60b4
--- /dev/null
+++ b/vcl/unx/inc/salunx.h
@@ -0,0 +1,128 @@
+/*************************************************************************
+ *
+ * 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 _SALUNX_H
+#define _SALUNX_H
+
+// -=-= #includes =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#if defined SCO || defined LINUX || defined HPUX || defined FREEBSD || defined NETBSD
+#include <sys/time.h>
+#elif defined AIX
+#include <time.h>
+#include <sys/time.h>
+#include <strings.h>
+#endif
+#include <svunx.h>
+#include <salstd.hxx>
+
+// -=-= #defines -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#define capacityof(a) (sizeof(a)/sizeof(*a))
+
+// -=-= inlines =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+inline long Divide( long nDividend, long nDivisor )
+{ return (nDividend + nDivisor/2) / nDivisor; }
+
+inline long DPI( long pixel, long mm )
+{ return Divide( pixel*254, mm*10 ); }
+
+// -=-= timeval =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+inline int operator >= ( const timeval &t1, const timeval &t2 )
+{
+ if( t1.tv_sec == t2.tv_sec )
+ return t1.tv_usec >= t2.tv_usec;
+ return t1.tv_sec > t2.tv_sec;
+}
+
+inline int operator > ( const timeval &t1, const timeval &t2 )
+{
+ if( t1.tv_sec == t2.tv_sec )
+ return t1.tv_usec > t2.tv_usec;
+ return t1.tv_sec > t2.tv_sec;
+}
+
+inline int operator == ( const timeval &t1, const timeval &t2 )
+{
+ if( t1.tv_sec == t2.tv_sec )
+ return t1.tv_usec == t2.tv_usec;
+ return FALSE;
+}
+
+inline timeval &operator -= ( timeval &t1, const timeval &t2 )
+{
+ if( t1.tv_usec < t2.tv_usec )
+ {
+ t1.tv_sec--;
+ t1.tv_usec += 1000000;
+ }
+ t1.tv_sec -= t2.tv_sec;
+ t1.tv_usec -= t2.tv_usec;
+ return t1;
+}
+
+inline timeval &operator += ( timeval &t1, const timeval &t2 )
+{
+ t1.tv_sec += t2.tv_sec;
+ t1.tv_usec += t2.tv_usec;
+ if( t1.tv_usec > 1000000 )
+ {
+ t1.tv_sec++;
+ t1.tv_usec -= 1000000;
+ }
+ return t1;
+}
+
+inline timeval &operator += ( timeval &t1, ULONG t2 )
+{
+ t1.tv_sec += t2 / 1000;
+ t1.tv_usec += t2 ? (t2 % 1000) * 1000 : 500;
+ if( t1.tv_usec > 1000000 )
+ {
+ t1.tv_sec++;
+ t1.tv_usec -= 1000000;
+ }
+ return t1;
+}
+
+inline timeval operator + ( const timeval &t1, const timeval &t2 )
+{
+ timeval t0 = t1;
+ return t0 += t2;
+}
+
+inline timeval operator + ( const timeval &t1, ULONG t2 )
+{
+ timeval t0 = t1;
+ return t0 += t2;
+}
+
+inline timeval operator - ( const timeval &t1, const timeval &t2 )
+{
+ timeval t0 = t1;
+ return t0 -= t2;
+}
+#endif
+
diff --git a/vcl/unx/inc/salvd.h b/vcl/unx/inc/salvd.h
new file mode 100644
index 000000000000..3d8c681c4e22
--- /dev/null
+++ b/vcl/unx/inc/salvd.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALVD_H
+#define _SV_SALVD_H
+
+// -=-= #includes -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+#include <salstd.hxx>
+#include <vcl/salvd.hxx>
+
+// -=-= forwards -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+class SalDisplay;
+class X11SalGraphics;
+
+// -=-= SalVirDevData -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+class X11SalVirtualDevice : public SalVirtualDevice
+{
+ SalDisplay *pDisplay_;
+ X11SalGraphics *pGraphics_;
+
+
+ Pixmap hDrawable_;
+ int m_nScreen;
+
+ int nDX_;
+ int nDY_;
+ USHORT nDepth_;
+ BOOL bGraphics_; // is Graphics used
+ BOOL bExternPixmap_;
+
+public:
+ X11SalVirtualDevice();
+ virtual ~X11SalVirtualDevice();
+
+ BOOL Init( SalDisplay *pDisplay,
+ long nDX, long nDY,
+ USHORT nBitCount,
+ int nScreen,
+ Pixmap hDrawable = None,
+ void* pRenderFormat = NULL );
+ inline void InitGraphics( X11SalVirtualDevice *pVD );
+
+ inline Display *GetXDisplay() const;
+ inline SalDisplay *GetDisplay() const;
+ inline BOOL IsDisplay() const;
+ inline Pixmap GetDrawable() const { return hDrawable_; }
+ inline USHORT GetDepth() const { return nDepth_; }
+ int GetWidth() const { return nDX_; }
+ int GetHeight() const { return nDY_; }
+ int GetScreenNumber() const { return m_nScreen; }
+
+ virtual SalGraphics* GetGraphics();
+ virtual void ReleaseGraphics( SalGraphics* pGraphics );
+
+ // Set new size, without saving the old contents
+ virtual BOOL SetSize( long nNewDX, long nNewDY );
+ virtual void GetSize( long& rWidth, long& rHeight );
+};
+
+#ifdef _SV_SALDISP_HXX
+
+inline void X11SalVirtualDevice::InitGraphics( X11SalVirtualDevice *pVD )
+{ pGraphics_->Init( pVD ); }
+
+inline Display *X11SalVirtualDevice::GetXDisplay() const
+{ return pDisplay_->GetDisplay(); }
+
+inline SalDisplay *X11SalVirtualDevice::GetDisplay() const
+{ return pDisplay_; }
+
+inline BOOL X11SalVirtualDevice::IsDisplay() const
+{ return pDisplay_->IsDisplay(); }
+
+#endif
+
+#endif // _SV_SALVD_H
+
diff --git a/vcl/unx/inc/sm.hxx b/vcl/unx/inc/sm.hxx
new file mode 100644
index 000000000000..b4339bb8567e
--- /dev/null
+++ b/vcl/unx/inc/sm.hxx
@@ -0,0 +1,91 @@
+/*************************************************************************
+ *
+ * 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_SM_HXX
+#define _VCL_SM_HXX
+
+#include <tools/link.hxx>
+#include <salunx.h>
+#include <X11/SM/SMlib.h>
+#include <vcl/salsession.hxx>
+
+class SessionManagerClient
+{
+ static SmcConn aSmcConnection;
+ static ByteString aClientID;
+ static bool bDocSaveDone;
+
+ static void SaveYourselfProc( SmcConn connection,
+ SmPointer client_data,
+ int save_type,
+ Bool shutdown,
+ int interact_style,
+ Bool fast );
+ static void DieProc( SmcConn connection,
+ SmPointer client_data );
+ static void SaveCompleteProc( SmcConn connection,
+ SmPointer client_data );
+ static void ShutdownCanceledProc( SmcConn connection,
+ SmPointer client_data );
+ static void InteractProc( SmcConn connection,
+ SmPointer clientData );
+
+ static const ByteString& getPreviousSessionID();
+
+ DECL_STATIC_LINK( SessionManagerClient, ShutDownHdl, void* );
+ DECL_STATIC_LINK( SessionManagerClient, ShutDownCancelHdl, void* );
+ DECL_STATIC_LINK( SessionManagerClient, SaveYourselfHdl, void* );
+ DECL_STATIC_LINK( SessionManagerClient, InteractionHdl, void* );
+public:
+ static VCL_DLLPUBLIC void open(); // needed by other plugins, so export
+ static void close();
+
+ static bool checkDocumentsSaved();
+ static bool queryInteraction();
+ static void saveDone();
+ static void interactionDone( bool bCancelShutdown );
+
+ static String getExecName();
+ static VCL_DLLPUBLIC const ByteString& getSessionID();
+};
+
+class SalFrame;
+
+class IceSalSession : public SalSession
+{
+public:
+ IceSalSession();
+ virtual ~IceSalSession();
+
+ virtual void queryInteraction();
+ virtual void interactionDone();
+ virtual void saveDone();
+ virtual bool cancelShutdown();
+
+ static void handleOldX11SaveYourself( SalFrame* pFrame );
+};
+
+#endif
diff --git a/vcl/unx/inc/soicon.hxx b/vcl/unx/inc/soicon.hxx
new file mode 100644
index 000000000000..419f9b2cc54a
--- /dev/null
+++ b/vcl/unx/inc/soicon.hxx
@@ -0,0 +1,37 @@
+/*************************************************************************
+ *
+ * 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_SOICON_HXX
+#define _SV_SOICON_HXX
+
+class SalDisplay;
+class SalBitmap;
+class Bitmap;
+
+BOOL SelectAppIconPixmap( SalDisplay *pDisplay, int nScreen,
+ USHORT nIcon, USHORT iconSize,
+ Pixmap& icon_pixmap, Pixmap& icon_mask );
+#endif
diff --git a/vcl/unx/inc/strhelper.hxx b/vcl/unx/inc/strhelper.hxx
new file mode 100644
index 000000000000..cd0220b77e05
--- /dev/null
+++ b/vcl/unx/inc/strhelper.hxx
@@ -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.
+ *
+ ************************************************************************/
+#ifndef _SV_STRHELPER_HXX
+#define _SV_STRHELPER_HXX
+#include <tools/string.hxx>
+
+String GetCommandLineToken( int, const String& );
+// gets one token of a unix command line style string
+// doublequote, singlequote and singleleftquote protect their respective
+// contents
+
+int GetCommandLineTokenCount( const String& );
+// returns number of tokens (zero if empty or whitespace only)
+
+String WhitespaceToSpace( const String&, BOOL bProtect = TRUE );
+
+#endif
diff --git a/vcl/unx/inc/svsys.h b/vcl/unx/inc/svsys.h
new file mode 100644
index 000000000000..d4077d0998e9
--- /dev/null
+++ b/vcl/unx/inc/svsys.h
@@ -0,0 +1,32 @@
+/*************************************************************************
+ *
+ * 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_SVSYS_H
+#define _SV_SVSYS_H
+
+#include <svunx.h>
+
+#endif // _SV_SVSYS_H
diff --git a/vcl/unx/inc/svunx.h b/vcl/unx/inc/svunx.h
new file mode 100644
index 000000000000..e7d6150b79f4
--- /dev/null
+++ b/vcl/unx/inc/svunx.h
@@ -0,0 +1,35 @@
+/*************************************************************************
+ *
+ * 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 _SVUNX_H
+#define _SVUNX_H
+
+#include <tools/prex.h>
+#include <tools/postx.h>
+
+#endif
+
diff --git a/vcl/unx/inc/wmadaptor.hxx b/vcl/unx/inc/wmadaptor.hxx
new file mode 100644
index 000000000000..cbedede2cc99
--- /dev/null
+++ b/vcl/unx/inc/wmadaptor.hxx
@@ -0,0 +1,350 @@
+/*************************************************************************
+ *
+ * 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_WMADAPTOR_HXX_
+#define _VCL_WMADAPTOR_HXX_
+
+#ifndef _TL_STRING_HXX
+#include <tools/string.hxx>
+#endif
+#include <tools/gen.hxx>
+#include <vcl/dllapi.h>
+#ifndef _PREX_H
+#include <tools/prex.h>
+#include <X11/Xlib.h>
+#include <tools/postx.h>
+#endif
+#include <vector>
+
+class SalDisplay;
+class X11SalFrame;
+
+namespace vcl_sal {
+
+class VCL_DLLPUBLIC WMAdaptor
+{
+public:
+ enum WMAtom {
+ // atoms for types
+ UTF8_STRING,
+
+ // atoms for extended WM hints
+ NET_SUPPORTED,
+ NET_SUPPORTING_WM_CHECK,
+ NET_WM_NAME,
+ NET_WM_DESKTOP,
+ NET_WM_ICON_NAME,
+ NET_WM_PID,
+ NET_WM_PING,
+ NET_WM_STATE,
+ NET_WM_STATE_MAXIMIZED_HORZ,
+ NET_WM_STATE_MAXIMIZED_VERT,
+ NET_WM_STATE_MODAL,
+ NET_WM_STATE_SHADED,
+ NET_WM_STATE_SKIP_PAGER,
+ NET_WM_STATE_SKIP_TASKBAR,
+ NET_WM_STATE_STAYS_ON_TOP,
+ NET_WM_STATE_STICKY,
+ NET_WM_STATE_FULLSCREEN,
+ NET_WM_STRUT,
+ NET_WM_STRUT_PARTIAL,
+ NET_WM_USER_TIME,
+ NET_WM_WINDOW_TYPE,
+ NET_WM_WINDOW_TYPE_DESKTOP,
+ NET_WM_WINDOW_TYPE_DIALOG,
+ NET_WM_WINDOW_TYPE_DOCK,
+ NET_WM_WINDOW_TYPE_MENU,
+ NET_WM_WINDOW_TYPE_NORMAL,
+ NET_WM_WINDOW_TYPE_TOOLBAR,
+ KDE_NET_WM_WINDOW_TYPE_OVERRIDE,
+ NET_WM_WINDOW_TYPE_SPLASH,
+ NET_WM_WINDOW_TYPE_UTILITY,
+ NET_NUMBER_OF_DESKTOPS,
+ NET_CURRENT_DESKTOP,
+ NET_WORKAREA,
+
+ // atoms for Gnome WM hints
+ WIN_SUPPORTING_WM_CHECK,
+ WIN_PROTOCOLS,
+ WIN_WORKSPACE_COUNT,
+ WIN_WORKSPACE,
+ WIN_LAYER,
+ WIN_STATE,
+ WIN_HINTS,
+ WIN_APP_STATE,
+ WIN_EXPANDED_SIZE,
+ WIN_ICONS,
+ WIN_WORKSPACE_NAMES,
+ WIN_CLIENT_LIST,
+
+ // atoms for general WM hints
+ WM_STATE,
+ MOTIF_WM_HINTS,
+ WM_PROTOCOLS,
+ WM_DELETE_WINDOW,
+ WM_TAKE_FOCUS,
+ WM_SAVE_YOURSELF,
+ WM_CLIENT_LEADER,
+ WM_COMMAND,
+ WM_LOCALE_NAME,
+ WM_TRANSIENT_FOR,
+
+ // special atoms
+ SAL_QUITEVENT,
+ SAL_USEREVENT,
+ SAL_EXTTEXTEVENT,
+ SAL_GETTIMEEVENT,
+ DTWM_IS_RUNNING,
+ VCL_SYSTEM_SETTINGS,
+ XSETTINGS,
+ XEMBED,
+ XEMBED_INFO,
+ NetAtomMax
+ };
+
+ /*
+ * flags for frame decoration
+ */
+ static const int decoration_Title = 0x00000001;
+ static const int decoration_Border = 0x00000002;
+ static const int decoration_Resize = 0x00000004;
+ static const int decoration_MinimizeBtn = 0x00000008;
+ static const int decoration_MaximizeBtn = 0x00000010;
+ static const int decoration_CloseBtn = 0x00000020;
+ static const int decoration_All = 0x10000000;
+
+ /*
+ * window type
+ */
+ enum WMWindowType
+ {
+ windowType_Normal,
+ windowType_ModalDialogue,
+ windowType_ModelessDialogue,
+ windowType_Utility,
+ windowType_Splash,
+ windowType_Toolbar,
+ windowType_Dock
+ };
+
+protected:
+ SalDisplay* m_pSalDisplay; // Display to use
+ Display* m_pDisplay; // X Display of SalDisplay
+ String m_aWMName;
+ Atom m_aWMAtoms[ NetAtomMax];
+ int m_nDesktops;
+ bool m_bEqualWorkAreas;
+ ::std::vector< Rectangle >
+ m_aWMWorkAreas;
+ bool m_bTransientBehaviour;
+ bool m_bEnableAlwaysOnTopWorks;
+ bool m_bLegacyPartialFullscreen;
+ int m_nWinGravity;
+ int m_nInitWinGravity;
+
+ WMAdaptor( SalDisplay * )
+;
+ void initAtoms();
+ bool getNetWmName();
+
+ /*
+ * returns whether this instance is useful
+ * only useful for createWMAdaptor
+ */
+ virtual bool isValid() const;
+
+public:
+ virtual ~WMAdaptor();
+
+ /*
+ * creates a vaild WMAdaptor instance for the SalDisplay
+ */
+ static WMAdaptor* createWMAdaptor( SalDisplay* );
+
+ /*
+ * may return an empty string if the window manager could
+ * not be identified.
+ */
+ const String& getWindowManagerName() const
+ { return m_aWMName; }
+
+ /*
+ * gets the number of workareas
+ */
+ int getWorkAreaCount() const
+ { return m_aWMWorkAreas.size(); }
+
+ /*
+ * gets the current work area/desktop number: [0,m_nDesktops[ or -1 if unknown
+ */
+ int getCurrentWorkArea() const;
+ /*
+ * gets the workarea the specified window is on (or -1)
+ */
+ int getWindowWorkArea( XLIB_Window aWindow ) const;
+ /*
+ * gets the specified workarea
+ */
+ const Rectangle& getWorkArea( int n ) const
+ { return m_aWMWorkAreas[n]; }
+
+ /*
+ * attemp to switch the desktop to a certain workarea
+ */
+ void switchToWorkArea( int nWorkArea ) const;
+
+ /*
+ * sets window title
+ */
+ virtual void setWMName( X11SalFrame* pFrame, const String& rWMName ) const;
+
+ /*
+ * set NET_WM_PID
+ */
+ virtual void setPID( X11SalFrame* pFrame ) const;
+
+ /*
+ * set WM_CLIENT_MACHINE
+ */
+ virtual void setClientMachine( X11SalFrame* pFrame ) const;
+
+ virtual void answerPing( X11SalFrame*, XClientMessageEvent* ) const;
+
+ /*
+ * maximizes frame
+ * maximization can be toggled in either direction
+ * to get the original position and size
+ * use maximizeFrame( pFrame, false, false )
+ */
+ virtual void maximizeFrame( X11SalFrame* pFrame, bool bHorizontal = true, bool bVertical = true ) const;
+ /*
+ * start/stop fullscreen mode on a frame
+ */
+ virtual void showFullScreen( X11SalFrame* pFrame, bool bFullScreen ) const;
+ /*
+ * tell whether legacy partial full screen handling is necessary
+ * see #i107249#: NET_WM_STATE_FULLSCREEN is not well defined, but de facto
+ * modern WM's interpret it the "right" way, namely they make "full screen"
+ * taking twin view or Xinerama into accound and honor the positioning hints
+ * to see which screen actually was meant to use for fullscreen.
+ */
+ bool isLegacyPartialFullscreen() const
+ { return m_bLegacyPartialFullscreen; }
+ /*
+ * set window struts
+ */
+ virtual void setFrameStruts( X11SalFrame*pFrame,
+ int left, int right, int top, int bottom,
+ int left_start_y, int left_end_y,
+ int right_start_y, int right_end_y,
+ int top_start_x, int top_end_x,
+ int bottom_start_x, int bottom_end_x ) const;
+ /*
+ * set _NET_WM_USER_TIME property, if NetWM
+ */
+ virtual void setUserTime( X11SalFrame* i_pFrame, long i_nUserTime ) const;
+
+ /*
+ * tells whether fullscreen mode is supported by WM
+ */
+ bool supportsFullScreen() const { return m_aWMAtoms[ NET_WM_STATE_FULLSCREEN ] != 0; }
+
+ /*
+ * shade/unshade frame
+ */
+ virtual void shade( X11SalFrame* pFrame, bool bToShaded ) const;
+
+ /*
+ * set hints what decoration is needed;
+ * must be called before showing the frame
+ */
+ virtual void setFrameTypeAndDecoration( X11SalFrame* pFrame, WMWindowType eType, int nDecorationFlags, X11SalFrame* pTransientFrame = NULL ) const;
+
+ /*
+ * tells whether there is WM support for splash screens
+ */
+ bool supportsSplash() const { return m_aWMAtoms[ NET_WM_WINDOW_TYPE_SPLASH ] != 0; }
+
+ /*
+ * tells whteher there is WM support for NET_WM_WINDOW_TYPE_TOOLBAR
+ */
+ bool supportsToolbar() const { return m_aWMAtoms[ NET_WM_WINDOW_TYPE_TOOLBAR ] != 0; }
+
+ /*
+ * enables always on top or equivalent if possible
+ */
+ virtual void enableAlwaysOnTop( X11SalFrame* pFrame, bool bEnable ) const;
+
+ /*
+ * tells whether enableAlwaysOnTop actually works with this WM
+ */
+ bool isAlwaysOnTopOK() const { return m_bEnableAlwaysOnTopWorks; }
+
+ /*
+ * handle WM messages (especially WM state changes)
+ */
+ virtual int handlePropertyNotify( X11SalFrame* pFrame, XPropertyEvent* pEvent ) const;
+
+ /*
+ * called by SalFrame::Show: time to update state properties
+ */
+ virtual void frameIsMapping( X11SalFrame* ) const;
+
+ /*
+ * gets a WM atom
+ */
+ Atom getAtom( WMAtom eAtom ) const
+ { return m_aWMAtoms[ eAtom ]; }
+
+ /*
+ * supports correct positioning
+ */
+
+ virtual bool supportsICCCMPos () const;
+
+ int getPositionWinGravity () const
+ { return m_nWinGravity; }
+ int getInitWinGravity() const
+ { return m_nInitWinGravity; }
+
+ /*
+ * expected behaviour is that the WM will not allow transient
+ * windows to get stacked behind the windows they are transient for
+ */
+ bool isTransientBehaviourAsExpected() const
+ { return m_bTransientBehaviour; }
+
+ /*
+ * changes the transient hint of a window to reference frame
+ * if reference frame is NULL the root window is used instead
+ */
+ void changeReferenceFrame( X11SalFrame* pFrame, X11SalFrame* pReferenceFrame ) const;
+};
+
+} // namespace
+
+#endif
diff --git a/vcl/unx/inc/xfont.hxx b/vcl/unx/inc/xfont.hxx
new file mode 100644
index 000000000000..4041ed7ce67d
--- /dev/null
+++ b/vcl/unx/inc/xfont.hxx
@@ -0,0 +1,162 @@
+/*************************************************************************
+ *
+ * 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 EXTENDED_FONTSTRUCT_HXX
+#define EXTENDED_FONTSTRUCT_HXX
+
+#ifndef _XLIB_H_
+#include <tools/prex.h>
+#include <X11/Xlib.h>
+#include <tools/postx.h>
+#endif
+#include <tools/ref.hxx>
+#include <rtl/tencinfo.h>
+#include <vcl/vclenum.hxx>
+#include <vcl/sallayout.hxx>
+
+typedef unsigned short sal_MultiByte;
+
+class ImplFontMetricData;
+class ExtendedXlfd;
+
+struct VerticalTextItem
+{
+ BOOL mbFixed;
+ XFontStruct* mpXFontStruct;
+ const sal_Unicode* mpString;
+ int mnLength;
+ int mnTransX;
+ int mnTransY;
+ int mnFixedAdvance;
+ int* mpAdvanceAry;
+
+ VerticalTextItem( XFontStruct* pXFontStruct,
+ const sal_Unicode* pString,
+ int nLength,
+ int nTransX,
+ int nTransY,
+ int nFixedAdvance )
+ : mbFixed( TRUE ),
+ mpXFontStruct( pXFontStruct ),
+ mpString( pString ),
+ mnLength( nLength ),
+ mnTransX( nTransX ),
+ mnTransY( nTransY ),
+ mnFixedAdvance( nFixedAdvance )
+ {}
+
+ VerticalTextItem( XFontStruct* pXFontStruct,
+ const sal_Unicode* pString,
+ int nLength,
+ int nTransX,
+ int nTransY,
+ int* pAdvanceAry )
+ : mbFixed( FALSE ),
+ mpXFontStruct( pXFontStruct ),
+ mpString( pString ),
+ mnLength( nLength ),
+ mnTransX( nTransX ),
+ mnTransY( nTransY ),
+ mpAdvanceAry( pAdvanceAry )
+ {}
+
+ ~VerticalTextItem()
+ {
+ if (!mbFixed)
+ {
+ delete( mpAdvanceAry );
+ }
+ }
+};
+
+class ExtendedFontStruct : public SvRefBase
+{
+ private:
+ Display* mpDisplay;
+ Size maPixelSize;
+ float mfXScale;
+ float mfYScale;
+ sal_Size mnDefaultWidth;
+ sal_Bool mbVertical;
+ rtl_TextEncoding mnCachedEncoding;
+ rtl_TextEncoding mnAsciiEncoding;
+
+ ExtendedXlfd* mpXlfd;
+ XFontStruct** mpXFontStruct;
+
+ // unicode range cache
+ mutable sal_uInt32* mpRangeCodes;
+ mutable int mnRangeCount;
+
+ int LoadEncoding( rtl_TextEncoding nEncoding );
+ FontPitch GetSpacing( rtl_TextEncoding nEncoding );
+ bool GetFontBoundingBox( XCharStruct *pCharStruct,
+ int *pAscent, int *pDescent ) ;
+
+ sal_Size GetDefaultWidth();
+ sal_Size GetCharWidth8( sal_Unicode nFrom, sal_Unicode nTo,
+ sal_Int32 *pWidthArray,
+ rtl_TextEncoding nEncoding );
+ sal_Size GetCharWidthUTF16( sal_Unicode nFrom, sal_Unicode nTo,
+ sal_Int32 *pWidthArray );
+ sal_Size GetCharWidth16( sal_Unicode nFrom, sal_Unicode nTo,
+ sal_Int32 *pWidthArray, ExtendedFontStruct *pFallback );
+ public:
+ ExtendedFontStruct( Display* pDisplay,
+ const Size& rPixelSize, sal_Bool bVertical,
+ ExtendedXlfd* pXlfd );
+ ~ExtendedFontStruct();
+ bool Match( const ExtendedXlfd *pXlfd,
+ const Size& rPixelSize, sal_Bool bVertical ) const;
+ XFontStruct* GetFontStruct( rtl_TextEncoding nEncoding );
+ XFontStruct* GetFontStruct( sal_Unicode nChar,
+ rtl_TextEncoding *pEncoding );
+ bool ToImplFontMetricData( ImplFontMetricData *pMetric );
+ rtl_TextEncoding GetAsciiEncoding( int *pAsciiRange = NULL ) const;
+ sal_Size GetCharWidth( sal_Unicode,
+ sal_Int32* pPhysWidth, sal_Int32* pLogWidth );
+ int GetFontCodeRanges( sal_uInt32* pCodePairs ) const;
+ bool HasUnicodeChar( sal_Unicode ) const;
+};
+
+// Declaration and Implementation for ExtendedFontStructRef: Add RefCounting
+// to ExtendedFontStruct (it's not possible to separate decl and impl into
+// a separate source file: all ref member functions are inline
+SV_DECL_IMPL_REF( ExtendedFontStruct );
+
+class X11FontLayout : public GenericSalLayout
+{
+public:
+ X11FontLayout( ExtendedFontStruct& );
+ virtual bool LayoutText( ImplLayoutArgs& );
+ virtual void AdjustLayout( ImplLayoutArgs& );
+ virtual void DrawText( SalGraphics& ) const;
+
+private:
+ ExtendedFontStruct& mrFont;
+};
+
+#endif /* EXTENDED_FONTSTRUCT_HXX */
diff --git a/vcl/unx/kde/kdedata.cxx b/vcl/unx/kde/kdedata.cxx
new file mode 100644
index 000000000000..34b0ff652cde
--- /dev/null
+++ b/vcl/unx/kde/kdedata.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"
+
+#define _SV_SALDATA_CXX
+#include <shell/kde_headers.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <errno.h>
+#include <poll.h>
+#ifdef FREEBSD
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#endif
+#include <plugins/kde/kdedata.hxx>
+#include <osl/thread.h>
+#include <osl/process.h>
+#include <osl/module.h>
+
+#include <tools/debug.hxx>
+#include "i18n_im.hxx"
+#include "i18n_xkb.hxx"
+#include <vos/process.hxx>
+#ifndef _VOS_MUTEX_HXX
+#include <vos/mutex.hxx>
+#endif
+
+/* #i59042# override KApplications method for session management
+ * since it will interfere badly with our own.
+ */
+class VCLKDEApplication : public KApplication
+{
+ public:
+ VCLKDEApplication() : KApplication() {}
+
+ virtual void commitData(QSessionManager &sm);
+};
+
+void VCLKDEApplication::commitData(QSessionManager&)
+{
+}
+
+/***************************************************************************
+ * class SalKDEDisplay *
+ ***************************************************************************/
+
+SalKDEDisplay::SalKDEDisplay( Display* pDisp )
+ : SalX11Display( pDisp )
+{
+}
+
+SalKDEDisplay::~SalKDEDisplay()
+{
+ // in case never a frame opened
+ static_cast<KDEXLib*>(GetXLib())->doStartup();
+ // clean up own members
+ doDestruct();
+ // prevent SalDisplay from closing KApplication's display
+ pDisp_ = NULL;
+}
+
+/***************************************************************************
+ * class KDEXLib *
+ ***************************************************************************/
+
+KDEXLib::~KDEXLib()
+{
+ // #158056# on 64 bit linux using libXRandr.so.2 will crash in
+ // XCloseDisplay when freeing extension data
+ // no known work around, therefor currently leak. Hopefully
+ // this does not make problems since we're shutting down anyway
+ // should we ever get a real kde plugin that uses the KDE event loop
+ // we should use kde's method to signal screen changes similar
+ // to the gtk plugin
+ #if ! defined USE_RANDR || ! (defined LINUX && defined X86_64)
+ // properly deinitialize KApplication
+ delete (VCLKDEApplication*)m_pApplication;
+ #endif
+ // free the faked cmdline arguments no longer needed by KApplication
+ for( int i = 0; i < m_nFakeCmdLineArgs; i++ )
+ free( m_pFreeCmdLineArgs[i] );
+ delete [] m_pFreeCmdLineArgs;
+ delete [] m_pAppCmdLineArgs;
+}
+
+void KDEXLib::Init()
+{
+ SalI18N_InputMethod* pInputMethod = new SalI18N_InputMethod;
+ pInputMethod->SetLocale();
+ XrmInitialize();
+
+ KAboutData *kAboutData = new KAboutData( "OpenOffice.org",
+ I18N_NOOP( "OpenOffice.org" ),
+ "1.1.0",
+ I18N_NOOP( "OpenOffice.org with KDE Native Widget Support." ),
+ KAboutData::License_LGPL,
+ "(c) 2003, 2004 Novell, Inc",
+ I18N_NOOP( "OpenOffice.org is an office suite.\n" ),
+ "http://kde.openoffice.org/index.html",
+ "dev@kde.openoffice.org");
+ kAboutData->addAuthor( "Jan Holesovsky",
+ I18N_NOOP( "Original author and maintainer of the KDE NWF." ),
+ "kendy@artax.karlin.mff.cuni.cz",
+ "http://artax.karlin.mff.cuni.cz/~kendy" );
+
+ m_nFakeCmdLineArgs = 1;
+ USHORT nIdx;
+ vos::OExtCommandLine aCommandLine;
+ int nParams = aCommandLine.getCommandArgCount();
+ rtl::OString aDisplay;
+ rtl::OUString aParam, aBin;
+
+ for ( nIdx = 0; nIdx < nParams; ++nIdx )
+ {
+ aCommandLine.getCommandArg( nIdx, aParam );
+ if ( !m_pFreeCmdLineArgs && aParam.equalsAscii( "-display" ) && nIdx + 1 < nParams )
+ {
+ aCommandLine.getCommandArg( nIdx + 1, aParam );
+ aDisplay = rtl::OUStringToOString( aParam, osl_getThreadTextEncoding() );
+
+ m_nFakeCmdLineArgs = 3;
+ m_pFreeCmdLineArgs = new char*[ m_nFakeCmdLineArgs ];
+ m_pFreeCmdLineArgs[ 1 ] = strdup( "-display" );
+ m_pFreeCmdLineArgs[ 2 ] = strdup( aDisplay.getStr() );
+ }
+ }
+ if ( !m_pFreeCmdLineArgs )
+ m_pFreeCmdLineArgs = new char*[ m_nFakeCmdLineArgs ];
+
+ osl_getExecutableFile( &aParam.pData );
+ osl_getSystemPathFromFileURL( aParam.pData, &aBin.pData );
+ rtl::OString aExec = rtl::OUStringToOString( aBin, osl_getThreadTextEncoding() );
+ m_pFreeCmdLineArgs[0] = strdup( aExec.getStr() );
+
+ // make a copy of the string list for freeing it since
+ // KApplication manipulates the pointers inside the argument vector
+ // note: KApplication bad !
+ m_pAppCmdLineArgs = new char*[ m_nFakeCmdLineArgs ];
+ for( int i = 0; i < m_nFakeCmdLineArgs; i++ )
+ m_pAppCmdLineArgs[i] = m_pFreeCmdLineArgs[i];
+
+ KCmdLineArgs::init( m_nFakeCmdLineArgs, m_pAppCmdLineArgs, kAboutData );
+
+ KApplication::disableAutoDcopRegistration();
+ m_pApplication = new VCLKDEApplication();
+ kapp->disableSessionManagement();
+
+ Display* pDisp = QPaintDevice::x11AppDisplay();
+
+ SalDisplay *pSalDisplay = new SalKDEDisplay( pDisp );
+
+ pInputMethod->CreateMethod( pDisp );
+ pInputMethod->AddConnectionWatch( pDisp, (void*)this );
+ pSalDisplay->SetInputMethod( pInputMethod );
+
+ PushXErrorLevel( true );
+ SalI18N_KeyboardExtension *pKbdExtension = new SalI18N_KeyboardExtension( pDisp );
+ XSync( pDisp, False );
+
+ pKbdExtension->UseExtension( ! HasXErrorOccured() );
+ PopXErrorLevel();
+
+ pSalDisplay->SetKbdExtension( pKbdExtension );
+}
+
+void KDEXLib::doStartup()
+{
+ if( ! m_bStartupDone )
+ {
+ KStartupInfo::appStarted();
+ m_bStartupDone = true;
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "called KStartupInfo::appStarted()\n" );
+ #endif
+ }
+}
+
+/**********************************************************************
+ * class KDEData *
+ **********************************************************************/
+
+KDEData::~KDEData()
+{
+}
+
+void KDEData::Init()
+{
+ pXLib_ = new KDEXLib();
+ pXLib_->Init();
+}
+
+/**********************************************************************
+ * plugin entry point *
+ **********************************************************************/
+
+extern "C" {
+ VCL_DLLPUBLIC SalInstance* create_SalInstance( oslModule )
+ {
+ /* #i92121# workaround deadlocks in the X11 implementation
+ */
+ static const char* pNoXInitThreads = getenv( "SAL_NO_XINITTHREADS" );
+ /* #i90094#
+ from now on we know that an X connection will be
+ established, so protect X against itself
+ */
+ if( ! ( pNoXInitThreads && *pNoXInitThreads ) )
+ XInitThreads();
+
+ rtl::OString aVersion( qVersion() );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "qt version string is \"%s\"\n", aVersion.getStr() );
+#endif
+ sal_Int32 nIndex = 0, nMajor = 0, nMinor = 0, nMicro = 0;
+ nMajor = aVersion.getToken( 0, '.', nIndex ).toInt32();
+ if( nIndex > 0 )
+ nMinor = aVersion.getToken( 0, '.', nIndex ).toInt32();
+ if( nIndex > 0 )
+ nMicro = aVersion.getToken( 0, '.', nIndex ).toInt32();
+ if( nMajor != 3 || nMinor < 2 || (nMinor == 2 && nMicro < 2) )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "unsuitable qt version %d.%d.%d\n", (int)nMajor, (int)nMinor, (int)nMicro );
+#endif
+ return NULL;
+ }
+
+ KDESalInstance* pInstance = new KDESalInstance( new SalYieldMutex() );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "created KDESalInstance 0x%p\n", pInstance );
+#endif
+
+ // initialize SalData
+ KDEData *pSalData = new KDEData();
+ SetSalData( pSalData );
+ pSalData->m_pInstance = pInstance;
+ pSalData->Init();
+ pSalData->initNWF();
+
+ return pInstance;
+ }
+}
diff --git a/vcl/unx/kde/makefile.mk b/vcl/unx/kde/makefile.mk
new file mode 100644
index 000000000000..e4e056ee6435
--- /dev/null
+++ b/vcl/unx/kde/makefile.mk
@@ -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.
+#
+#*************************************************************************
+
+PRJ=..$/..
+
+PRJNAME=vcl
+TARGET=kdeplug
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# workaround for makedepend hang
+MKDEPENDSOLVER=
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+# For some of the included external KDE headers, GCC complains about shadowed
+# symbols in instantiated template code only at the end of a compilation unit,
+# so the only solution is to disable that warning here:
+.IF "$(COM)" == "GCC"
+CFLAGSCXX+=-Wno-shadow
+.ENDIF
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)"!="unx"
+
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+
+.ELSE # "$(GUIBASE)"!="unx"
+
+.IF "$(ENABLE_KDE)" != ""
+
+CFLAGS+=$(KDE_CFLAGS)
+
+.IF "$(ENABLE_RANDR)" != ""
+CDEFS+=-DUSE_RANDR
+.ENDIF
+
+SLOFILES=\
+ $(SLO)$/kdedata.obj \
+ $(SLO)$/salnativewidgets-kde.obj
+
+.ELSE # "$(ENABLE_KDE)" != ""
+
+dummy:
+ @echo KDE disabled - nothing to build
+.ENDIF
+.ENDIF # "$(GUIBASE)"!="unx"
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
+.INCLUDE : $(PRJ)$/util$/target.pmk
diff --git a/vcl/unx/kde/salnativewidgets-kde.cxx b/vcl/unx/kde/salnativewidgets-kde.cxx
new file mode 100644
index 000000000000..3adc9f5c679a
--- /dev/null
+++ b/vcl/unx/kde/salnativewidgets-kde.cxx
@@ -0,0 +1,2116 @@
+/*************************************************************************
+ *
+ * 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 _SV_SALNATIVEWIDGETS_KDE_CXX
+#include <shell/kde_headers.h>
+
+#include <salunx.h>
+#include <saldata.hxx>
+#include <saldisp.hxx>
+
+#ifndef _SV_SALGDI_HXX
+#include <salgdi.h>
+#endif
+
+#ifndef _SV_SALGDI_HXX
+#include <salframe.h>
+#endif
+#include <vcl/settings.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <plugins/kde/kdedata.hxx>
+#include <iostream>
+
+#include <pspgraphics.h>
+
+using namespace ::rtl;
+
+/** Cached native widgets.
+
+ A class which caches and paints the native widgets.
+*/
+class WidgetPainter
+{
+ protected:
+ /** Cached push button.
+
+ It is necessary for the QStyle::drawControl(). The buttons are created
+ on demand and they are still hidden (no QWidget::show() is called).
+ */
+ QPushButton *m_pPushButton;
+
+ /** Cached radio button.
+
+ @see m_pPushButton
+ */
+ QRadioButton *m_pRadioButton;
+
+ /** Cached check box.
+
+ @see m_pPushButton
+ */
+ QCheckBox *m_pCheckBox;
+
+ /** Cached combo box.
+
+ @see m_pPushButton
+ */
+ QComboBox *m_pComboBox;
+
+ /** Cached editable combo box.
+
+ Needed, because some styles do not like dynamic changes
+ (QComboBox::setEditable()).
+
+ @see m_pPushButton
+ */
+ QComboBox *m_pEditableComboBox;
+
+ /** Cached line edit box.
+
+ @see m_pPushButton
+ */
+ QLineEdit *m_pLineEdit;
+
+ /** Cached spin box.
+
+ @see m_pPushButton
+ */
+ QSpinWidget *m_pSpinWidget;
+
+ /** Cached spin box'es line edit.
+
+ @see m_pPushButton
+ */
+ QLineEdit *m_pSpinEdit;
+
+ /** Cached tab.
+
+ Left, middle, right tab and a tab which is alone.
+
+ @see m_pPushButton
+ */
+ QTab *m_pTabLeft, *m_pTabMiddle, *m_pTabRight, *m_pTabAlone;
+
+ /** Cached tab bar's parent widget.
+
+ Needed, because the Qt windows style checks for the availability
+ of tab bar's parent. We cannot use m_pTabWidget, because
+ TabWidget::setTabBar() and TabWidget::tabBar() methods are
+ protected.
+
+ @see m_pPushButton, m_pTabWidget
+ */
+ QWidget *m_pTabBarParent;
+
+ /** Cached tab bar widget.
+
+ @see m_pPushButton
+ */
+ QTabBar *m_pTabBar;
+
+ /** Cached tab widget.
+
+ We need it to draw the tab page. It cannot be used to draw the
+ tabs themselves, because the drawing has to be tweaked a little
+ due to not enough information from VCL.
+
+ @see m_pPushButton, m_pTabBarParent
+ */
+ QTabWidget *m_pTabWidget;
+
+ /** Cached list view.
+
+ @see m_pPushButton
+ */
+ QListView *m_pListView;
+
+ /** Cached scroll bar.
+
+ @see m_pPushButton
+ */
+ QScrollBar *m_pScrollBar;
+
+ /** Cached dock area. Needed for proper functionality of tool bars.
+
+ @see m_pPushButton
+ */
+ QMainWindow *m_pMainWindow;
+
+ /** Cached tool bar.
+
+ @see m_pPushButton
+ */
+ QToolBar *m_pToolBarHoriz, *m_pToolBarVert;
+
+ /** Cached tool button.
+
+ @see m_pPushButton
+ */
+ QToolButton *m_pToolButton;
+
+ /** Cached menu bar.
+
+ @see m_pPushButton
+ */
+ QMenuBar *m_pMenuBar;
+
+ /** Identifiers of menu bar items.
+ */
+ int m_nMenuBarEnabledItem, m_nMenuBarDisabledItem;
+
+ /** Cached popup menu.
+
+ @see m_pPushButton
+ */
+ QPopupMenu *m_pPopupMenu;
+
+ /** Identifiers of popup menu items.
+ */
+ int m_nPopupMenuEnabledItem, m_nPopupMenuDisabledItem;
+
+ /** cached progress bar
+ */
+ QProgressBar *m_pProgressBar;
+
+ // TODO other widgets
+
+ public:
+ /** Implicit constructor.
+
+ It creates an empty WidgetPainter with all the cached widgets initialized
+ to NULL. The widgets are created on demand and they are still hidden
+ (no QWidget::show()), because they are needed just as a parameter for
+ QStyle::drawControl().
+
+ @see m_pPushButton
+ */
+ WidgetPainter( void );
+
+ /** Destructor.
+
+ Destruct all the cached widgets.
+ */
+ virtual ~WidgetPainter( void );
+
+ /** Paints the specified widget to the X window.
+
+ Use X calls to bitblt (bit block transfer) the widget qWidget to
+ the window specified by drawable with the style defined by nStyle.
+
+ @param qWidget
+ A pointer to the cached widget.
+
+ @param nState
+ The state of the control (focused, on/off, ...)
+
+ @param aValue
+ The value (true/false, ...)
+
+ @param dpy
+ The display to be used by the X calls.
+
+ @param drawable
+ The destination X window.
+
+ @param gc
+ The graphics context.
+ */
+ BOOL drawStyledWidget( QWidget *pWidget,
+ ControlState nState, const ImplControlValue& aValue,
+ Display *dpy, XLIB_Window drawable, int nScreen, int nDepth, GC gc,
+ ControlPart nPart = PART_ENTIRE_CONTROL );
+
+ /** 'Get' method for push button.
+
+ The method returns the cached push button. It is constructed if it
+ does not exist. It has NULL as a parent and it stays hidden, but it
+ is necessary for the drawStyledWidget() method.
+
+ @return valid push button.
+ */
+ QPushButton *pushButton( const Region& rControlRegion, BOOL bDefault );
+
+ /** 'Get' method for radio button.
+
+ @see pushButton()
+ */
+ QRadioButton *radioButton( const Region& rControlRegion );
+
+ /** 'Get' method for check box.
+
+ @see pushButton()
+ */
+ QCheckBox *checkBox( const Region& rControlRegion );
+
+ /** 'Get' method for combo box.
+
+ It returns m_pComboBox or m_pEditableComboBox according to
+ bEditable.
+
+ @see pushButton(), m_pEditableComboBox
+ */
+ QComboBox *comboBox( const Region& rControlRegion, BOOL bEditable );
+
+ /** 'Get' method for line edit box.
+
+ @see pushButton()
+ */
+ QLineEdit *lineEdit( const Region& rControlRegion );
+
+ /** 'Get' method for spin box.
+
+ @see pushButton()
+ */
+ QSpinWidget *spinWidget( const Region& rControlRegion );
+
+ /** 'Get' method for tab bar.
+
+ @see pushButton()
+ */
+ QTabBar *tabBar( const Region& rControlRegion );
+
+ /** 'Get' method for tab widget.
+
+ @see pushButton()
+ */
+ QTabWidget *tabWidget( const Region& rControlRegion );
+
+ /** 'Get' method for list view.
+
+ @see pushButton()
+ */
+ QListView *listView( const Region& rControlRegion );
+
+ /** 'Get' method for scroll bar.
+
+ @see pushButton()
+ */
+ QScrollBar *scrollBar( const Region& rControlRegion,
+ BOOL bHorizontal, const ImplControlValue& aValue );
+
+ /** 'Get' method for tool bar.
+
+ @see pushButton()
+ */
+ QToolBar *toolBar( const Region& rControlRegion, BOOL bHorizontal );
+
+ /** 'Get' method for tool button.
+
+ @see pushButton()
+ */
+ QToolButton *toolButton( const Region& rControlRegion );
+
+ /** 'Get' method for menu bar.
+
+ @see pushButton()
+ */
+ QMenuBar *menuBar( const Region& rControlRegion );
+
+ /** 'Get' method for popup menu.
+
+ @see pushButton()
+ */
+ QPopupMenu *popupMenu( const Region& rControlRegion );
+
+ /** 'Get' method for progress bar
+
+ @see pushButton()
+ */
+ QProgressBar *progressBar( const Region& rControlRegion );
+
+ // TODO other widgets
+
+ protected:
+ /** Style conversion function.
+
+ Conversion function between VCL ControlState together with
+ ImplControlValue and Qt state flags.
+
+ @param nState
+ State of the widget (default, focused, ...) as defined in Native
+ Widget Framework.
+
+ @param aValue
+ Value held by the widget (on, off, ...)
+ */
+ QStyle::SFlags vclStateValue2SFlags( ControlState nState, const ImplControlValue& aValue );
+
+ public:
+ /** Convert VCL Region to QRect.
+
+ @param rControlRegion
+ The region to convert.
+
+ @return
+ The bounding box of the region.
+ */
+ static QRect region2QRect( const Region& rControlRegion );
+};
+
+WidgetPainter::WidgetPainter( void )
+ : m_pPushButton( NULL ),
+ m_pRadioButton( NULL ),
+ m_pCheckBox( NULL ),
+ m_pComboBox( NULL ),
+ m_pEditableComboBox( NULL ),
+ m_pLineEdit( NULL ),
+ m_pSpinWidget( NULL ),
+ m_pSpinEdit( NULL ),
+ m_pTabLeft( NULL ),
+ m_pTabMiddle( NULL ),
+ m_pTabRight( NULL ),
+ m_pTabAlone( NULL ),
+ m_pTabBarParent( NULL ),
+ m_pTabBar( NULL ),
+ m_pTabWidget( NULL ),
+ m_pListView( NULL ),
+ m_pScrollBar( NULL ),
+ m_pMainWindow( NULL ),
+ m_pToolBarHoriz( NULL ),
+ m_pToolBarVert( NULL ),
+ m_pToolButton( NULL ),
+ m_pMenuBar( NULL ),
+ m_pPopupMenu( NULL ),
+ m_pProgressBar( NULL )
+{
+}
+
+WidgetPainter::~WidgetPainter( void )
+{
+ delete m_pPushButton, m_pPushButton = NULL;
+ delete m_pRadioButton, m_pRadioButton = NULL;
+ delete m_pCheckBox, m_pCheckBox = NULL;
+ delete m_pComboBox, m_pComboBox = NULL;
+ delete m_pEditableComboBox, m_pEditableComboBox = NULL;
+ delete m_pLineEdit, m_pLineEdit = NULL;
+ delete m_pSpinWidget, m_pSpinWidget = NULL;
+ m_pSpinEdit = NULL; // Deleted in m_pSpinWidget's destructor
+ delete m_pTabAlone, m_pTabAlone = NULL;
+ delete m_pTabBarParent, m_pTabBarParent = NULL;
+ m_pTabBar = NULL; // Deleted in m_pTabBarParent's destructor
+ m_pTabLeft = NULL;
+ m_pTabMiddle = NULL;
+ m_pTabRight = NULL;
+ delete m_pTabWidget, m_pTabWidget = NULL;
+ delete m_pListView, m_pListView = NULL;
+ delete m_pScrollBar, m_pScrollBar = NULL;
+ delete m_pToolBarHoriz, m_pToolBarHoriz = NULL;
+ delete m_pToolBarVert, m_pToolBarVert = NULL;
+ delete m_pMainWindow, m_pMainWindow = NULL;
+ delete m_pToolButton, m_pToolButton = NULL;
+ delete m_pMenuBar, m_pMenuBar = NULL;
+ delete m_pPopupMenu, m_pPopupMenu = NULL;
+ delete m_pProgressBar, m_pProgressBar = NULL;
+}
+
+BOOL WidgetPainter::drawStyledWidget( QWidget *pWidget,
+ ControlState nState, const ImplControlValue& aValue,
+ Display *dpy, XLIB_Window drawable, int nScreen, int nDepth, GC gc,
+ ControlPart nPart )
+{
+ if ( !pWidget )
+ return FALSE;
+
+ // Normalize the widget
+ QPoint qWidgetPos( pWidget->pos() );
+ pWidget->move( 0, 0 );
+
+ // Enable/disable the widget
+ pWidget->setEnabled( nState & CTRL_STATE_ENABLED );
+
+ // Create pixmap to paint to
+ QPixmap qPixmap( pWidget->width(), pWidget->height() );
+ QPainter qPainter( &qPixmap );
+ QRect qRect( 0, 0, pWidget->width(), pWidget->height() );
+
+ // Use the background of the widget
+ qPixmap.fill( pWidget, QPoint(0, 0) );
+
+ // Convert the flags
+ QStyle::SFlags nStyle = vclStateValue2SFlags( nState, aValue );
+
+ // Store the widget class
+ const char *pClassName = pWidget->className();
+
+ // Draw the widget to the pixmap
+ if ( strcmp( "QPushButton", pClassName ) == 0 )
+ {
+ // Workaround for the Platinum style.
+ // Platinum takes the state directly from the widget, not from SFlags.
+ QPushButton *pPushButton = static_cast<QPushButton *>( pWidget->qt_cast( "QPushButton" ) );
+ if ( pPushButton )
+ {
+ pPushButton->setDown ( nStyle & QStyle::Style_Down );
+ pPushButton->setOn ( nStyle & QStyle::Style_On );
+ pPushButton->setEnabled( nStyle & QStyle::Style_Enabled );
+ }
+
+ kapp->style().drawControl( QStyle::CE_PushButton,
+ &qPainter, pWidget, qRect,
+ pWidget->colorGroup(), nStyle );
+ }
+ else if ( strcmp( "QRadioButton", pClassName ) == 0 )
+ {
+ // Bitblt from the screen, because the radio buttons are usually not
+ // rectangular, and there could be a bitmap under them
+ GC aTmpGC = XCreateGC( dpy, qPixmap.handle(), 0, NULL );
+ X11SalGraphics::CopyScreenArea( dpy,
+ drawable, nScreen, nDepth,
+ qPixmap.handle(), qPixmap.x11Screen(), qPixmap.x11Depth(),
+ aTmpGC,
+ qWidgetPos.x(), qWidgetPos.y(), qRect.width(), qRect.height(),
+ 0, 0 );
+ XFreeGC( dpy, aTmpGC );
+
+ kapp->style().drawControl( QStyle::CE_RadioButton,
+ &qPainter, pWidget, qRect,
+ pWidget->colorGroup(), nStyle );
+ }
+ else if ( strcmp( "QCheckBox", pClassName ) == 0 )
+ {
+ kapp->style().drawControl( QStyle::CE_CheckBox,
+ &qPainter, pWidget, qRect,
+ pWidget->colorGroup(), nStyle );
+ }
+ else if ( strcmp( "QComboBox", pClassName ) == 0 )
+ {
+ kapp->style().drawComplexControl( QStyle::CC_ComboBox,
+ &qPainter, pWidget, qRect,
+ pWidget->colorGroup(), nStyle );
+
+ // Editable combo box uses the background of the associated edit box
+ QComboBox *pComboBox = static_cast<QComboBox *>( pWidget->qt_cast( "QComboBox" ) );
+ if ( pComboBox && pComboBox->editable() && pComboBox->lineEdit() )
+ {
+ QColorGroup::ColorRole eColorRole = ( pComboBox->isEnabled() )?
+ QColorGroup::Base: QColorGroup::Background;
+ qPainter.fillRect(
+ kapp->style().querySubControlMetrics( QStyle::CC_ComboBox,
+ pComboBox, QStyle::SC_ComboBoxEditField ),
+ pComboBox->lineEdit()->colorGroup().brush( eColorRole ) );
+ }
+ }
+ else if ( strcmp( "QLineEdit", pClassName ) == 0 )
+ {
+ kapp->style().drawPrimitive( QStyle::PE_PanelLineEdit,
+ &qPainter, qRect,
+ pWidget->colorGroup(), nStyle | QStyle::Style_Sunken );
+ }
+ else if ( strcmp( "QSpinWidget", pClassName ) == 0 )
+ {
+ SpinbuttonValue *pValue = static_cast<SpinbuttonValue *> ( aValue.getOptionalVal() );
+
+ // Is any of the buttons pressed?
+ QStyle::SCFlags eActive = QStyle::SC_None;
+ if ( pValue )
+ {
+ if ( pValue->mnUpperState & CTRL_STATE_PRESSED )
+ eActive = QStyle::SC_SpinWidgetUp;
+ else if ( pValue->mnLowerState & CTRL_STATE_PRESSED )
+ eActive = QStyle::SC_SpinWidgetDown;
+
+ // Update the enable/disable state of the widget
+ if ( ( nState & CTRL_STATE_ENABLED ) ||
+ ( pValue->mnUpperState & CTRL_STATE_ENABLED ) ||
+ ( pValue->mnLowerState & CTRL_STATE_ENABLED ) )
+ {
+ pWidget->setEnabled( true );
+ nStyle |= QStyle::Style_Enabled;
+ }
+ else
+ pWidget->setEnabled( false );
+
+ // Mouse-over effect
+ if ( (pValue->mnUpperState & CTRL_STATE_ROLLOVER) ||
+ (pValue->mnLowerState & CTRL_STATE_ROLLOVER) )
+ nStyle |= QStyle::Style_MouseOver;
+ }
+
+ // Spin widget uses the background of the associated edit box
+ QSpinWidget *pSpinWidget = static_cast<QSpinWidget *>( pWidget->qt_cast( "QSpinWidget" ) );
+ if ( pSpinWidget && pSpinWidget->editWidget() )
+ {
+ QColorGroup::ColorRole eColorRole = ( pSpinWidget->isEnabled() )?
+ QColorGroup::Base: QColorGroup::Background;
+ qPainter.fillRect(
+ kapp->style().querySubControlMetrics( QStyle::CC_SpinWidget,
+ pSpinWidget, QStyle::SC_SpinWidgetEditField ),
+ pSpinWidget->editWidget()->colorGroup().brush( eColorRole ) );
+ }
+
+ // Adjust the frame (needed for Motif Plus style)
+ QRect qFrameRect = kapp->style().querySubControlMetrics( QStyle::CC_SpinWidget,
+ pWidget, QStyle::SC_SpinWidgetFrame );
+
+ kapp->style().drawComplexControl( QStyle::CC_SpinWidget,
+ &qPainter, pWidget, qFrameRect,
+ pWidget->colorGroup(), nStyle,
+ QStyle::SC_All, eActive );
+ }
+ else if ( strcmp( "QTabBar", pClassName ) == 0 )
+ {
+ TabitemValue *pValue = static_cast<TabitemValue *> ( aValue.getOptionalVal() );
+
+ QTab *pTab = NULL;
+ if ( pValue )
+ {
+ if ( ( pValue->isFirst() || pValue->isLeftAligned() ) && ( pValue->isLast() || pValue->isRightAligned() ) )
+ pTab = m_pTabAlone;
+ else if ( pValue->isFirst() || pValue->isLeftAligned() )
+ pTab = m_pTabLeft;
+ else if ( pValue->isLast() || pValue->isRightAligned() )
+ pTab = m_pTabRight;
+ else
+ pTab = m_pTabMiddle;
+ }
+ if ( !pTab )
+ return FALSE;
+
+ pTab->setRect( qRect );
+
+ kapp->style().drawControl( QStyle::CE_TabBarTab,
+ &qPainter, pWidget, qRect,
+ pWidget->colorGroup(), nStyle,
+ QStyleOption( pTab ) );
+ }
+ else if ( strcmp( "QTabWidget", pClassName ) == 0 )
+ {
+ kapp->style().drawPrimitive( QStyle::PE_PanelTabWidget,
+ &qPainter, qRect,
+ pWidget->colorGroup(), nStyle );
+ }
+ else if ( strcmp( "QListView", pClassName ) == 0 )
+ {
+ kapp->style().drawPrimitive( QStyle::PE_Panel,
+ &qPainter, qRect,
+ pWidget->colorGroup(), nStyle | QStyle::Style_Sunken );
+ }
+ else if ( strcmp( "QScrollBar", pClassName ) == 0 )
+ {
+ ScrollbarValue *pValue = static_cast<ScrollbarValue *> ( aValue.getOptionalVal() );
+
+ QStyle::SCFlags eActive = QStyle::SC_None;
+ if ( pValue )
+ {
+ // Workaround for Style_MouseOver-aware themes.
+ // Quite ugly, but I do not know about a better solution.
+ const char *pStyleName = kapp->style().className();
+ if ( strcmp( "QMotifPlusStyle", pStyleName ) == 0 )
+ {
+ nStyle |= QStyle::Style_MouseOver;
+ if ( pValue->mnThumbState & CTRL_STATE_ROLLOVER )
+ eActive = QStyle::SC_ScrollBarSlider;
+ }
+ else if ( strcmp( "QSGIStyle", pStyleName ) == 0 )
+ {
+ nStyle |= QStyle::Style_MouseOver;
+ if ( pValue->mnButton1State & CTRL_STATE_ROLLOVER )
+ eActive = QStyle::SC_ScrollBarSubLine;
+ else if ( pValue->mnButton2State & CTRL_STATE_ROLLOVER )
+ eActive = QStyle::SC_ScrollBarAddLine;
+ else if ( pValue->mnThumbState & CTRL_STATE_ROLLOVER )
+ eActive = QStyle::SC_ScrollBarSlider;
+ }
+
+ if ( pValue->mnButton1State & CTRL_STATE_PRESSED )
+ eActive = QStyle::SC_ScrollBarSubLine;
+ else if ( pValue->mnButton2State & CTRL_STATE_PRESSED )
+ eActive = QStyle::SC_ScrollBarAddLine;
+ else if ( pValue->mnThumbState & CTRL_STATE_PRESSED )
+ eActive = QStyle::SC_ScrollBarSlider;
+ else if ( pValue->mnPage1State & CTRL_STATE_PRESSED )
+ eActive = QStyle::SC_ScrollBarSubPage;
+ else if ( pValue->mnPage2State & CTRL_STATE_PRESSED )
+ eActive = QStyle::SC_ScrollBarAddPage;
+
+ // Update the enable/disable state of the widget
+ if ( ( nState & CTRL_STATE_ENABLED ) ||
+ ( pValue->mnButton1State & CTRL_STATE_ENABLED ) ||
+ ( pValue->mnButton2State & CTRL_STATE_ENABLED ) ||
+ ( pValue->mnThumbState & CTRL_STATE_ENABLED ) ||
+ ( pValue->mnPage1State & CTRL_STATE_ENABLED ) ||
+ ( pValue->mnPage2State & CTRL_STATE_ENABLED ) )
+ {
+ pWidget->setEnabled( true );
+ nStyle |= QStyle::Style_Enabled;
+ }
+ else
+ pWidget->setEnabled( false );
+ }
+
+ // Is it a horizontal scroll bar?
+ QScrollBar *pScrollBar = static_cast<QScrollBar *> ( pWidget->qt_cast( "QScrollBar" ) );
+ QStyle::StyleFlags eHoriz = QStyle::Style_Default;
+ if ( pScrollBar && pScrollBar->orientation() == Qt::Horizontal )
+ eHoriz = QStyle::Style_Horizontal;
+
+ kapp->style().drawComplexControl( QStyle::CC_ScrollBar,
+ &qPainter, pWidget, qRect,
+ pWidget->colorGroup(), nStyle | eHoriz,
+ QStyle::SC_All, eActive );
+ }
+ else if ( strcmp( "QToolBar", pClassName ) == 0 )
+ {
+ QToolBar *pToolBar = static_cast< QToolBar * >( pWidget->qt_cast( "QToolBar" ) );
+ bool bIsHorizontal = false;
+ if ( pToolBar && pToolBar->orientation() == Qt::Horizontal )
+ {
+ nStyle |= QStyle::Style_Horizontal;
+ bIsHorizontal = true;
+ }
+
+ kapp->style().drawControl( QStyle::CE_DockWindowEmptyArea,
+ &qPainter, pWidget, qRect,
+ pWidget->colorGroup(), nStyle );
+
+ kapp->style().drawPrimitive( QStyle::PE_PanelDockWindow,
+ &qPainter, qRect, pWidget->colorGroup(), nStyle );
+
+ if ( nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT )
+ {
+ ToolbarValue *pValue = static_cast< ToolbarValue * >( aValue.getOptionalVal() );
+
+ QRect qThumbRect = region2QRect( pValue->maGripRect );
+ qThumbRect.moveBy( -qWidgetPos.x(), -qWidgetPos.y() );
+ if ( bIsHorizontal )
+ qThumbRect.addCoords( 0, 2, 0, -3 ); // make the thumb a bit nicer
+ else
+ qThumbRect.addCoords( 2, 0, -3, 0 ); // make the thumb a bit nicer
+
+ if ( kapp->style().inherits( "HighColorStyle" ) ||
+ kapp->style().inherits( "HighContrastStyle" ) ||
+ kapp->style().inherits( "KeramikStyle" ) ||
+ kapp->style().inherits( "KThemeStyle" ) ||
+ kapp->style().inherits( "ThinKeramikStyle" ) )
+ {
+ // Workaround for the workaround in KStyle::drawPrimitive()
+ KStyle *pStyle = static_cast< KStyle * >( &kapp->style() );
+ pStyle->drawKStylePrimitive( KStyle::KPE_ToolBarHandle,
+ &qPainter, pToolBar, qThumbRect,
+ pWidget->colorGroup(), nStyle );
+ }
+ else
+ kapp->style().drawPrimitive( QStyle::PE_DockWindowHandle,
+ &qPainter, qThumbRect, pWidget->colorGroup(), nStyle );
+ }
+ }
+ else if ( strcmp( "QToolButton", pClassName ) == 0 )
+ {
+ if( (nStyle & QStyle::Style_MouseOver) )
+ nStyle &= ~QStyle::Style_Off;
+ kapp->style().drawComplexControl( QStyle::CC_ToolButton,
+ &qPainter, pWidget, qRect,
+ pWidget->colorGroup(), nStyle,
+ QStyle::SC_ToolButton );
+ }
+ else if ( strcmp( "QMenuBar", pClassName ) == 0 )
+ {
+ if ( nPart == PART_ENTIRE_CONTROL )
+ {
+ kapp->style().drawControl( QStyle::CE_MenuBarEmptyArea,
+ &qPainter, pWidget, qRect,
+ pWidget->colorGroup(), nStyle );
+ }
+ else if ( nPart == PART_MENU_ITEM )
+ {
+ int nMenuItem = ( nStyle & QStyle::Style_Enabled )? m_nMenuBarEnabledItem: m_nMenuBarDisabledItem;
+ QMenuItem *pMenuItem = static_cast<QMenuBar*>( pWidget )->findItem( nMenuItem );
+
+ if ( nStyle & QStyle::Style_Selected )
+ nStyle |= QStyle::Style_Active | QStyle::Style_Down | QStyle::Style_HasFocus;
+
+ kapp->style().drawControl( QStyle::CE_MenuBarItem,
+ &qPainter, pWidget, qRect,
+ pWidget->colorGroup(), nStyle,
+ QStyleOption( pMenuItem ) );
+ }
+ }
+ else if ( strcmp( "QPopupMenu", pClassName ) == 0 )
+ {
+ int nMenuItem = ( nStyle & QStyle::Style_Enabled )? m_nPopupMenuEnabledItem: m_nPopupMenuDisabledItem;
+ QMenuItem *pMenuItem = static_cast<QPopupMenu*>( pWidget )->findItem( nMenuItem );
+
+ if ( nStyle & QStyle::Style_Selected )
+ nStyle |= QStyle::Style_Active;
+
+ kapp->style().drawControl( QStyle::CE_PopupMenuItem,
+ &qPainter, pWidget, qRect,
+ pWidget->colorGroup(), nStyle,
+ QStyleOption( pMenuItem, 0, 0 ) );
+ }
+ else if ( strcmp( "QProgressBar", pClassName ) == 0 )
+ {
+ long nProgressWidth = aValue.getNumericVal();
+ QProgressBar* pProgress = static_cast<QProgressBar*>(pWidget);
+ pProgress->setProgress( nProgressWidth, qRect.width() );
+
+ kapp->style().drawControl( QStyle::CE_ProgressBarGroove,
+ &qPainter, pWidget, qRect,
+ pWidget->colorGroup(), nStyle );
+ kapp->style().drawControl( QStyle::CE_ProgressBarContents,
+ &qPainter, pWidget, qRect,
+ pWidget->colorGroup(), nStyle );
+ }
+ else
+ return FALSE;
+
+ // Bitblt it to the screen
+ X11SalGraphics::CopyScreenArea( dpy,
+ qPixmap.handle(), qPixmap.x11Screen(), qPixmap.x11Depth(),
+ drawable, nScreen, nDepth,
+ gc,
+ 0, 0, qRect.width(), qRect.height(),
+ qWidgetPos.x(), qWidgetPos.y() );
+
+ // Restore widget's position
+ pWidget->move( qWidgetPos );
+
+ return TRUE;
+}
+
+QPushButton *WidgetPainter::pushButton( const Region& rControlRegion,
+ BOOL bDefault )
+{
+ if ( !m_pPushButton )
+ m_pPushButton = new QPushButton( NULL, "push_button" );
+
+ QRect qRect = region2QRect( rControlRegion );
+
+ // Workaround for broken styles which do not add
+ // QStyle::PM_ButtonDefaultIndicator to the size of the default button
+ // (for example Keramik)
+ // FIXME Fix Keramik style to be consistant with Qt built-in styles. Aargh!
+ if ( bDefault )
+ {
+ QSize qContentsSize( 50, 50 );
+ m_pPushButton->setDefault( false );
+ QSize qNormalSize = kapp->style().sizeFromContents( QStyle::CT_PushButton,
+ m_pPushButton, qContentsSize );
+ m_pPushButton->setDefault( true );
+ QSize qDefSize = kapp->style().sizeFromContents( QStyle::CT_PushButton,
+ m_pPushButton, qContentsSize );
+
+ int nIndicatorSize = kapp->style().pixelMetric(
+ QStyle::PM_ButtonDefaultIndicator, m_pPushButton );
+ if ( qNormalSize.width() == qDefSize.width() )
+ qRect.addCoords( nIndicatorSize, 0, -nIndicatorSize, 0 );
+ if ( qNormalSize.height() == qDefSize.height() )
+ qRect.addCoords( 0, nIndicatorSize, 0, -nIndicatorSize );
+ }
+
+ m_pPushButton->move( qRect.topLeft() );
+ m_pPushButton->resize( qRect.size() );
+ m_pPushButton->setDefault( bDefault );
+
+ return m_pPushButton;
+}
+
+QRadioButton *WidgetPainter::radioButton( const Region& rControlRegion )
+{
+ if ( !m_pRadioButton )
+ m_pRadioButton = new QRadioButton( NULL, "radio_button" );
+
+ QRect qRect = region2QRect( rControlRegion );
+
+ // Workaround for broken themes which do not honor the given size.
+ // Quite ugly, but I do not know about a better solution.
+ const char *pStyleName = kapp->style().className();
+ if ( strcmp( "KThemeStyle", pStyleName ) == 0 )
+ {
+ QRect qOldRect( qRect );
+
+ qRect.setWidth( kapp->style().pixelMetric(
+ QStyle::PM_ExclusiveIndicatorWidth, m_pRadioButton ) );
+ qRect.setHeight( kapp->style().pixelMetric(
+ QStyle::PM_ExclusiveIndicatorHeight, m_pRadioButton ) );
+
+ qRect.moveBy( ( qOldRect.width() - qRect.width() ) / 2,
+ ( qOldRect.height() - qRect.height() ) / 2 );
+ }
+
+ m_pRadioButton->move( qRect.topLeft() );
+ m_pRadioButton->resize( qRect.size() );
+
+ return m_pRadioButton;
+}
+
+QCheckBox *WidgetPainter::checkBox( const Region& rControlRegion )
+{
+ if ( !m_pCheckBox )
+ m_pCheckBox = new QCheckBox( NULL, "check_box" );
+
+ QRect qRect = region2QRect( rControlRegion );
+
+ // Workaround for broken themes which do not honor the given size.
+ // Quite ugly, but I do not know about a better solution.
+ const char *pStyleName = kapp->style().className();
+ if ( strcmp( "KThemeStyle", pStyleName ) == 0 )
+ {
+ QRect qOldRect( qRect );
+
+ qRect.setWidth( kapp->style().pixelMetric(
+ QStyle::PM_IndicatorWidth, m_pCheckBox ) );
+ qRect.setHeight( kapp->style().pixelMetric(
+ QStyle::PM_IndicatorHeight, m_pCheckBox ) );
+
+ qRect.moveBy( ( qOldRect.width() - qRect.width() ) / 2,
+ ( qOldRect.height() - qRect.height() ) / 2 );
+ }
+
+ m_pCheckBox->move( qRect.topLeft() );
+ m_pCheckBox->resize( qRect.size() );
+
+ return m_pCheckBox;
+}
+
+QComboBox *WidgetPainter::comboBox( const Region& rControlRegion,
+ BOOL bEditable )
+{
+ QComboBox *pComboBox = NULL;
+ if ( bEditable )
+ {
+ if ( !m_pEditableComboBox )
+ m_pEditableComboBox = new QComboBox( true, NULL, "combo_box_edit" );
+ pComboBox = m_pEditableComboBox;
+ }
+ else
+ {
+ if ( !m_pComboBox )
+ m_pComboBox = new QComboBox( false, NULL, "combo_box" );
+ pComboBox = m_pComboBox;
+ }
+
+ QRect qRect = region2QRect( rControlRegion );
+
+ pComboBox->move( qRect.topLeft() );
+ pComboBox->resize( qRect.size() );
+
+ return pComboBox;
+}
+
+QLineEdit *WidgetPainter::lineEdit( const Region& rControlRegion )
+{
+ if ( !m_pLineEdit )
+ m_pLineEdit = new QLineEdit( NULL, "line_edit" );
+
+ QRect qRect = region2QRect( rControlRegion );
+
+ m_pLineEdit->move( qRect.topLeft() );
+ m_pLineEdit->resize( qRect.size() );
+
+ return m_pLineEdit;
+}
+
+QSpinWidget *WidgetPainter::spinWidget( const Region& rControlRegion )
+{
+ if ( !m_pSpinWidget )
+ {
+ m_pSpinWidget = new QSpinWidget( NULL, "spin_widget" );
+
+ m_pSpinEdit = new QLineEdit( NULL, "line_edit_spin" );
+ m_pSpinWidget->setEditWidget( m_pSpinEdit );
+ }
+
+ QRect qRect = region2QRect( rControlRegion );
+
+ m_pSpinWidget->move( qRect.topLeft() );
+ m_pSpinWidget->resize( qRect.size() );
+ m_pSpinWidget->arrange();
+
+ return m_pSpinWidget;
+}
+
+QTabBar *WidgetPainter::tabBar( const Region& rControlRegion )
+{
+ if ( !m_pTabBar )
+ {
+ if ( !m_pTabBarParent )
+ m_pTabBarParent = new QWidget( NULL, "tab_bar_parent" );
+
+ m_pTabBar = new QTabBar( m_pTabBarParent, "tab_bar" );
+
+ m_pTabLeft = new QTab();
+ m_pTabMiddle = new QTab();
+ m_pTabRight = new QTab();
+ m_pTabAlone = new QTab();
+
+ m_pTabBar->addTab( m_pTabLeft );
+ m_pTabBar->addTab( m_pTabMiddle );
+ m_pTabBar->addTab( m_pTabRight );
+ }
+
+ QRect qRect = region2QRect( rControlRegion );
+
+ m_pTabBar->move( qRect.topLeft() );
+ m_pTabBar->resize( qRect.size() );
+
+ m_pTabBar->setShape( QTabBar::RoundedAbove );
+
+ return m_pTabBar;
+}
+
+QTabWidget *WidgetPainter::tabWidget( const Region& rControlRegion )
+{
+ if ( !m_pTabWidget )
+ m_pTabWidget = new QTabWidget( NULL, "tab_widget" );
+
+ QRect qRect = region2QRect( rControlRegion );
+ --qRect.rTop();
+
+ m_pTabWidget->move( qRect.topLeft() );
+ m_pTabWidget->resize( qRect.size() );
+
+ return m_pTabWidget;
+}
+
+QListView *WidgetPainter::listView( const Region& rControlRegion )
+{
+ if ( !m_pListView )
+ m_pListView = new QListView( NULL, "list_view" );
+
+ QRect qRect = region2QRect( rControlRegion );
+
+ m_pListView->move( qRect.topLeft() );
+ m_pListView->resize( qRect.size() );
+
+ return m_pListView;
+}
+
+QScrollBar *WidgetPainter::scrollBar( const Region& rControlRegion,
+ BOOL bHorizontal, const ImplControlValue& aValue )
+{
+ if ( !m_pScrollBar )
+ {
+ m_pScrollBar = new QScrollBar( NULL, "scroll_bar" );
+ m_pScrollBar->setTracking( false );
+ m_pScrollBar->setLineStep( 1 );
+ }
+
+ QRect qRect = region2QRect( rControlRegion );
+
+ m_pScrollBar->move( qRect.topLeft() );
+ m_pScrollBar->resize( qRect.size() );
+ m_pScrollBar->setOrientation( bHorizontal? Qt::Horizontal: Qt::Vertical );
+
+ ScrollbarValue *pValue = static_cast<ScrollbarValue *> ( aValue.getOptionalVal() );
+ if ( pValue )
+ {
+ m_pScrollBar->setMinValue( pValue->mnMin );
+ m_pScrollBar->setMaxValue( pValue->mnMax - pValue->mnVisibleSize );
+ m_pScrollBar->setValue( pValue->mnCur );
+ m_pScrollBar->setPageStep( pValue->mnVisibleSize );
+ }
+
+ return m_pScrollBar;
+}
+
+QToolBar *WidgetPainter::toolBar( const Region& rControlRegion, BOOL bHorizontal )
+{
+ if ( !m_pMainWindow )
+ m_pMainWindow = new QMainWindow( NULL, "main_window" );
+
+ QToolBar *pToolBar;
+ if ( bHorizontal )
+ {
+ if ( !m_pToolBarHoriz )
+ {
+ m_pToolBarHoriz = new QToolBar( m_pMainWindow, "tool_bar_horiz" );
+ m_pMainWindow->moveDockWindow( m_pToolBarHoriz, Qt::DockTop );
+ }
+ pToolBar = m_pToolBarHoriz;
+ }
+ else
+ {
+ if ( !m_pToolBarVert )
+ {
+ m_pToolBarVert = new QToolBar( m_pMainWindow, "tool_bar_horiz" );
+ m_pMainWindow->moveDockWindow( m_pToolBarVert, Qt::DockLeft );
+ }
+ pToolBar = m_pToolBarVert;
+ }
+
+ QRect qRect = region2QRect( rControlRegion );
+
+ pToolBar->move( qRect.topLeft() );
+ pToolBar->resize( qRect.size() );
+
+ return pToolBar;
+}
+
+QToolButton *WidgetPainter::toolButton( const Region& rControlRegion)
+{
+ if ( !m_pToolButton )
+ m_pToolButton = new QToolButton( NULL, "tool_button" );
+
+ QRect qRect = region2QRect( rControlRegion );
+
+ m_pToolButton->move( qRect.topLeft() );
+ m_pToolButton->resize( qRect.size() );
+
+ return m_pToolButton;
+}
+
+QMenuBar *WidgetPainter::menuBar( const Region& rControlRegion)
+{
+ if ( !m_pMenuBar )
+ {
+ m_pMenuBar = new QMenuBar( NULL, "menu_bar" );
+
+ m_nMenuBarEnabledItem = m_pMenuBar->insertItem( "" );
+ m_nMenuBarDisabledItem = m_pMenuBar->insertItem( "" );
+
+ m_pMenuBar->setItemEnabled( m_nMenuBarEnabledItem, true );
+ m_pMenuBar->setItemEnabled( m_nMenuBarDisabledItem, false );
+ }
+
+ QRect qRect = region2QRect( rControlRegion );
+
+ m_pMenuBar->move( qRect.topLeft() );
+ m_pMenuBar->resize( qRect.size() );
+
+ return m_pMenuBar;
+}
+
+QPopupMenu *WidgetPainter::popupMenu( const Region& rControlRegion)
+{
+ if ( !m_pPopupMenu )
+ {
+ m_pPopupMenu = new QPopupMenu( NULL, "popup_menu" );
+
+ m_nPopupMenuEnabledItem = m_pPopupMenu->insertItem( "" );
+ m_nPopupMenuDisabledItem = m_pPopupMenu->insertItem( "" );
+
+ m_pPopupMenu->setItemEnabled( m_nPopupMenuEnabledItem, true );
+ m_pPopupMenu->setItemEnabled( m_nPopupMenuDisabledItem, false );
+ }
+
+ QRect qRect = region2QRect( rControlRegion );
+
+ m_pPopupMenu->move( qRect.topLeft() );
+ m_pPopupMenu->resize( qRect.size() );
+
+ return m_pPopupMenu;
+}
+
+QProgressBar *WidgetPainter::progressBar( const Region& rControlRegion )
+{
+ if ( !m_pProgressBar )
+ m_pProgressBar = new QProgressBar( NULL, "progress_bar" );
+
+ QRect qRect = region2QRect( rControlRegion );
+
+ m_pProgressBar->move( qRect.topLeft() );
+ m_pProgressBar->resize( qRect.size() );
+
+ return m_pProgressBar;
+}
+
+QStyle::SFlags WidgetPainter::vclStateValue2SFlags( ControlState nState,
+ const ImplControlValue& aValue )
+{
+ QStyle::SFlags nStyle =
+ ( (nState & CTRL_STATE_DEFAULT)? QStyle::Style_ButtonDefault: QStyle::Style_Default ) |
+ ( (nState & CTRL_STATE_ENABLED)? QStyle::Style_Enabled: QStyle::Style_Default ) |
+ ( (nState & CTRL_STATE_FOCUSED)? QStyle::Style_HasFocus: QStyle::Style_Default ) |
+ ( (nState & CTRL_STATE_PRESSED)? QStyle::Style_Down: QStyle::Style_Raised ) |
+ ( (nState & CTRL_STATE_SELECTED)? QStyle::Style_Selected : QStyle::Style_Default ) |
+ ( (nState & CTRL_STATE_ROLLOVER)? QStyle::Style_MouseOver: QStyle::Style_Default );
+ //TODO ( (nState & CTRL_STATE_HIDDEN)? QStyle::Style_: QStyle::Style_Default ) |
+
+ switch ( aValue.getTristateVal() )
+ {
+ case BUTTONVALUE_ON: nStyle |= QStyle::Style_On; break;
+ case BUTTONVALUE_OFF: nStyle |= QStyle::Style_Off; break;
+ case BUTTONVALUE_MIXED: nStyle |= QStyle::Style_NoChange; break;
+ default: break;
+ }
+
+ return nStyle;
+}
+
+QRect WidgetPainter::region2QRect( const Region& rControlRegion )
+{
+ Rectangle aRect = rControlRegion.GetBoundRect();
+
+ return QRect( QPoint( aRect.Left(), aRect.Top() ),
+ QPoint( aRect.Right(), aRect.Bottom() ) );
+}
+
+/** Instance of WidgetPainter.
+
+ It is used to paint the widgets requested by NWF.
+*/
+static WidgetPainter *pWidgetPainter;
+
+class KDESalGraphics : public X11SalGraphics
+{
+ public:
+ KDESalGraphics() {}
+ virtual ~KDESalGraphics() {}
+ virtual BOOL IsNativeControlSupported( ControlType nType, ControlPart nPart );
+ virtual BOOL hitTestNativeControl( ControlType nType, ControlPart nPart,
+ const Region& rControlRegion, const Point& aPos,
+ BOOL& rIsInside );
+ virtual BOOL drawNativeControl( ControlType nType, ControlPart nPart,
+ const Region& rControlRegion, ControlState nState,
+ const ImplControlValue& aValue,
+ const OUString& aCaption );
+ virtual BOOL drawNativeControlText( ControlType nType, ControlPart nPart,
+ const Region& rControlRegion, ControlState nState,
+ const ImplControlValue& aValue,
+ const OUString& aCaption );
+ virtual BOOL getNativeControlRegion( ControlType nType, ControlPart nPart,
+ const Region& rControlRegion, ControlState nState,
+ const ImplControlValue& aValue,
+ const OUString& aCaption,
+ Region &rNativeBoundingRegion, Region &rNativeContentRegion );
+};
+
+/** What widgets can be drawn the native way.
+
+ @param nType
+ Type of the widget.
+
+ @param nPart
+ Specification of the widget's part if it consists of more than one.
+
+ @return TRUE if the platform supports native drawing of the widget nType
+ defined by nPart.
+*/
+BOOL KDESalGraphics::IsNativeControlSupported( ControlType nType, ControlPart nPart )
+{
+ return
+ ( (nType == CTRL_PUSHBUTTON) && (nPart == PART_ENTIRE_CONTROL) ) ||
+ ( (nType == CTRL_RADIOBUTTON) && (nPart == PART_ENTIRE_CONTROL) ) ||
+ ( (nType == CTRL_CHECKBOX) && (nPart == PART_ENTIRE_CONTROL) ) ||
+ ( (nType == CTRL_COMBOBOX) && (nPart == PART_ENTIRE_CONTROL || nPart == HAS_BACKGROUND_TEXTURE) ) ||
+ ( (nType == CTRL_EDITBOX) && (nPart == PART_ENTIRE_CONTROL || nPart == HAS_BACKGROUND_TEXTURE) ) ||
+ ( (nType == CTRL_LISTBOX) && (nPart == PART_ENTIRE_CONTROL || nPart == PART_WINDOW || nPart == HAS_BACKGROUND_TEXTURE ) ) ||
+ ( (nType == CTRL_SPINBOX) && (nPart == PART_ENTIRE_CONTROL || nPart == HAS_BACKGROUND_TEXTURE) ) ||
+ // no CTRL_SPINBUTTONS for KDE
+ ( (nType == CTRL_TAB_ITEM) && (nPart == PART_ENTIRE_CONTROL) ) ||
+ ( (nType == CTRL_TAB_PANE) && (nPart == PART_ENTIRE_CONTROL) ) ||
+ // no CTRL_TAB_BODY for KDE
+ ( (nType == CTRL_SCROLLBAR) && (nPart == PART_ENTIRE_CONTROL || nPart == PART_DRAW_BACKGROUND_HORZ || nPart == PART_DRAW_BACKGROUND_VERT) ) ||
+ ( (nType == CTRL_SCROLLBAR) && (nPart == HAS_THREE_BUTTONS) ) || // TODO small optimization is possible here: return this only if the style really has 3 buttons
+ // CTRL_GROUPBOX not supported
+ // CTRL_FIXEDLINE not supported
+ // CTRL_FIXEDBORDER not supported
+ ( (nType == CTRL_TOOLBAR) && (nPart == PART_ENTIRE_CONTROL ||
+ nPart == PART_DRAW_BACKGROUND_HORZ || nPart == PART_DRAW_BACKGROUND_VERT ||
+ nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT ||
+ nPart == PART_BUTTON) ) ||
+ ( (nType == CTRL_MENUBAR) && (nPart == PART_ENTIRE_CONTROL || nPart == PART_MENU_ITEM) ) ||
+ ( (nType == CTRL_MENU_POPUP) && (nPart == PART_ENTIRE_CONTROL || nPart == PART_MENU_ITEM) ) ||
+ ( (nType == CTRL_PROGRESS) && (nPart == PART_ENTIRE_CONTROL) )
+ ;
+}
+
+
+/** Test whether the position is in the native widget.
+
+ 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 KDESalGraphics::hitTestNativeControl( ControlType nType, ControlPart nPart,
+ const Region& rControlRegion, const Point& rPos,
+ BOOL& rIsInside )
+{
+ if ( nType == CTRL_SCROLLBAR )
+ {
+ // make position relative to rControlRegion
+ Point aPos = rPos - rControlRegion.GetBoundRect().TopLeft();
+ rIsInside = FALSE;
+
+ BOOL bHorizontal = ( nPart == PART_BUTTON_LEFT || nPart == PART_BUTTON_RIGHT );
+
+ QScrollBar *pScrollBar = pWidgetPainter->scrollBar( rControlRegion,
+ bHorizontal, ImplControlValue() );
+ QRect qRectSubLine = kapp->style().querySubControlMetrics(
+ QStyle::CC_ScrollBar, pScrollBar, QStyle::SC_ScrollBarSubLine );
+ QRect qRectAddLine = kapp->style().querySubControlMetrics(
+ QStyle::CC_ScrollBar, pScrollBar, QStyle::SC_ScrollBarAddLine );
+
+ // There are 2 buttons on the right/bottom side of the scrollbar
+ BOOL bTwoSubButtons = FALSE;
+
+ // It is a Platinum style scroll bar
+ BOOL bPlatinumStyle = FALSE;
+
+ // Workaround for Platinum and 3 button style scroll bars.
+ // It makes the right/down button bigger.
+ if ( bHorizontal )
+ {
+ qRectAddLine.setLeft( kapp->style().querySubControlMetrics(
+ QStyle::CC_ScrollBar, pScrollBar,
+ QStyle::SC_ScrollBarAddPage ).right() + 1 );
+ if ( qRectAddLine.width() > qRectSubLine.width() )
+ bTwoSubButtons = TRUE;
+ if ( qRectSubLine.left() > kapp->style().querySubControlMetrics( QStyle::CC_ScrollBar, pScrollBar, QStyle::SC_ScrollBarSubPage ).left() )
+ bPlatinumStyle = TRUE;
+ }
+ else
+ {
+ qRectAddLine.setTop( kapp->style().querySubControlMetrics(
+ QStyle::CC_ScrollBar, pScrollBar,
+ QStyle::SC_ScrollBarAddPage ).bottom() + 1 );
+ if ( qRectAddLine.height() > qRectSubLine.height() )
+ bTwoSubButtons = TRUE;
+ if ( qRectSubLine.top() > kapp->style().querySubControlMetrics( QStyle::CC_ScrollBar, pScrollBar, QStyle::SC_ScrollBarSubPage ).top() )
+ bPlatinumStyle = TRUE;
+ }
+
+ switch ( nPart )
+ {
+ case PART_BUTTON_LEFT:
+ if ( !bPlatinumStyle && qRectSubLine.contains( aPos.getX(), aPos.getY() ) )
+ rIsInside = TRUE;
+ else if ( bTwoSubButtons )
+ {
+ qRectAddLine.setWidth( qRectAddLine.width() / 2 );
+ rIsInside = qRectAddLine.contains( aPos.getX(), aPos.getY() );
+ }
+ break;
+
+ case PART_BUTTON_UP:
+ if ( !bPlatinumStyle && qRectSubLine.contains( aPos.getX(), aPos.getY() ) )
+ rIsInside = TRUE;
+ else if ( bTwoSubButtons )
+ {
+ qRectAddLine.setHeight( qRectAddLine.height() / 2 );
+ rIsInside = qRectAddLine.contains( aPos.getX(), aPos.getY() );
+ }
+ break;
+
+ case PART_BUTTON_RIGHT:
+ if ( bTwoSubButtons )
+ qRectAddLine.setLeft( qRectAddLine.left() + qRectAddLine.width() / 2 );
+
+ rIsInside = qRectAddLine.contains( aPos.getX(), aPos.getY() );
+ break;
+
+ case PART_BUTTON_DOWN:
+ if ( bTwoSubButtons )
+ qRectAddLine.setTop( qRectAddLine.top() + qRectAddLine.height() / 2 );
+
+ rIsInside = qRectAddLine.contains( aPos.getX(), aPos.getY() );
+ break;
+
+ // cases PART_TRACK_HORZ_AREA and PART_TRACK_VERT_AREA
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/** Draw the requested control described by nPart/nState.
+
+ @param rControlRegion
+ The bounding region of the complete control in VCL frame coordinates.
+
+ @param aValue
+ An optional value (tristate/numerical/string).
+
+ @param aCaption
+ A caption or title string (like button text etc.)
+*/
+BOOL KDESalGraphics::drawNativeControl( ControlType nType, ControlPart nPart,
+ const Region& rControlRegion, ControlState nState,
+ const ImplControlValue& aValue,
+ const OUString& )
+{
+ BOOL bReturn = FALSE;
+
+ Display *dpy = GetXDisplay();
+ XLIB_Window drawable = GetDrawable();
+ GC gc = SelectPen(); //SelectFont(); // GC with current clipping region set
+
+ if ( (nType == CTRL_PUSHBUTTON) && (nPart == PART_ENTIRE_CONTROL) )
+ {
+ bReturn = pWidgetPainter->drawStyledWidget(
+ pWidgetPainter->pushButton( rControlRegion, (nState & CTRL_STATE_DEFAULT) ),
+ nState, aValue,
+ dpy, drawable, GetScreenNumber(), GetVisual().GetDepth(), gc );
+ }
+ else if ( (nType == CTRL_RADIOBUTTON) && (nPart == PART_ENTIRE_CONTROL) )
+ {
+ bReturn = pWidgetPainter->drawStyledWidget(
+ pWidgetPainter->radioButton( rControlRegion ),
+ nState, aValue,
+ dpy, drawable, GetScreenNumber(), GetVisual().GetDepth(), gc );
+ }
+ else if ( (nType == CTRL_CHECKBOX) && (nPart == PART_ENTIRE_CONTROL) )
+ {
+ bReturn = pWidgetPainter->drawStyledWidget(
+ pWidgetPainter->checkBox( rControlRegion ),
+ nState, aValue,
+ dpy, drawable, GetScreenNumber(), GetVisual().GetDepth(), gc );
+ }
+ else if ( (nType == CTRL_COMBOBOX) && (nPart == PART_ENTIRE_CONTROL) )
+ {
+ bReturn = pWidgetPainter->drawStyledWidget(
+ pWidgetPainter->comboBox( rControlRegion, TRUE ),
+ nState, aValue,
+ dpy, drawable, GetScreenNumber(), GetVisual().GetDepth(), gc );
+ }
+ else if ( (nType == CTRL_EDITBOX) && (nPart == PART_ENTIRE_CONTROL) )
+ {
+ bReturn = pWidgetPainter->drawStyledWidget(
+ pWidgetPainter->lineEdit( rControlRegion ),
+ nState, aValue,
+ dpy, drawable, GetScreenNumber(), GetVisual().GetDepth(), gc );
+ }
+ else if ( (nType == CTRL_LISTBOX) && (nPart == PART_ENTIRE_CONTROL) )
+ {
+ bReturn = pWidgetPainter->drawStyledWidget(
+ pWidgetPainter->comboBox( rControlRegion, FALSE ),
+ nState, aValue,
+ dpy, drawable, GetScreenNumber(), GetVisual().GetDepth(), gc );
+ }
+ else if ( (nType == CTRL_LISTBOX) && (nPart == PART_WINDOW) )
+ {
+ bReturn = pWidgetPainter->drawStyledWidget(
+ pWidgetPainter->listView( rControlRegion ),
+ nState, aValue,
+ dpy, drawable, GetScreenNumber(), GetVisual().GetDepth(), gc );
+ }
+ else if ( (nType == CTRL_SPINBOX) && (nPart == PART_ENTIRE_CONTROL) )
+ {
+ bReturn = pWidgetPainter->drawStyledWidget(
+ pWidgetPainter->spinWidget( rControlRegion ),
+ nState, aValue,
+ dpy, drawable, GetScreenNumber(), GetVisual().GetDepth(), gc );
+ }
+ else if ( (nType==CTRL_TAB_ITEM) && (nPart == PART_ENTIRE_CONTROL) )
+ {
+ bReturn = pWidgetPainter->drawStyledWidget(
+ pWidgetPainter->tabBar( rControlRegion ),
+ nState, aValue,
+ dpy, drawable, GetScreenNumber(), GetVisual().GetDepth(), gc );
+ }
+ else if ( (nType==CTRL_TAB_PANE) && (nPart == PART_ENTIRE_CONTROL) )
+ {
+ bReturn = pWidgetPainter->drawStyledWidget(
+ pWidgetPainter->tabWidget( rControlRegion ),
+ nState, aValue,
+ dpy, drawable, GetScreenNumber(), GetVisual().GetDepth(), gc );
+ }
+ else if ( (nType == CTRL_SCROLLBAR) && (nPart == PART_DRAW_BACKGROUND_HORZ || nPart == PART_DRAW_BACKGROUND_VERT) )
+ {
+ bReturn = pWidgetPainter->drawStyledWidget(
+ pWidgetPainter->scrollBar( rControlRegion, nPart == PART_DRAW_BACKGROUND_HORZ, aValue ),
+ nState, aValue,
+ dpy, drawable, GetScreenNumber(), GetVisual().GetDepth(), gc );
+ }
+ else if ( (nType == CTRL_TOOLBAR) && (nPart == PART_DRAW_BACKGROUND_HORZ || nPart == PART_DRAW_BACKGROUND_VERT || nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT) )
+ {
+ bReturn = pWidgetPainter->drawStyledWidget(
+ pWidgetPainter->toolBar( rControlRegion, nPart == PART_DRAW_BACKGROUND_HORZ || nPart == PART_THUMB_VERT ),
+ nState, aValue,
+ dpy, drawable, GetScreenNumber(), GetVisual().GetDepth(), gc, nPart );
+ }
+ else if ( (nType == CTRL_TOOLBAR) && (nPart == PART_BUTTON) )
+ {
+ bReturn = pWidgetPainter->drawStyledWidget(
+ pWidgetPainter->toolButton( rControlRegion ),
+ nState, aValue,
+ dpy, drawable, GetScreenNumber(), GetVisual().GetDepth(), gc, nPart );
+ }
+ else if ( (nType == CTRL_MENUBAR) && (nPart == PART_ENTIRE_CONTROL || nPart == PART_MENU_ITEM) )
+ {
+ bReturn = pWidgetPainter->drawStyledWidget(
+ pWidgetPainter->menuBar( rControlRegion ),
+ nState, aValue,
+ dpy, drawable, GetScreenNumber(), GetVisual().GetDepth(), gc, nPart );
+ }
+ else if ( (nType == CTRL_MENU_POPUP) && (nPart == PART_ENTIRE_CONTROL || nPart == PART_MENU_ITEM) )
+ {
+ bReturn = pWidgetPainter->drawStyledWidget(
+ pWidgetPainter->popupMenu( rControlRegion ),
+ nState, aValue,
+ dpy, drawable, GetScreenNumber(), GetVisual().GetDepth(), gc );
+ }
+ else if ( (nType == CTRL_PROGRESS) && (nPart == PART_ENTIRE_CONTROL) )
+ {
+ bReturn = pWidgetPainter->drawStyledWidget(
+ pWidgetPainter->progressBar( rControlRegion ),
+ nState, aValue,
+ dpy, drawable, GetScreenNumber(), GetVisual().GetDepth(), gc );
+ }
+
+ return bReturn;
+}
+
+
+/** Draw text on the widget.
+
+ OPTIONAL. Draws the requested text for the control described by nPart/nState.
+ Used if text is not drawn by DrawNativeControl().
+
+ @param rControlRegion
+ The bounding region of the complete control in VCL frame coordinates.
+
+ @param aValue
+ An optional value (tristate/numerical/string)
+
+ @param aCaption
+ A caption or title string (like button text etc.)
+*/
+BOOL KDESalGraphics::drawNativeControlText( ControlType, ControlPart,
+ const Region&, ControlState,
+ const ImplControlValue&,
+ const OUString& )
+{
+ return FALSE;
+}
+
+/** Check if the bounding regions match.
+
+ 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.
+
+ @param rControlRegion
+ The bounding region of the control in VCL frame coordinates.
+
+ @param aValue
+ An optional value (tristate/numerical/string)
+
+ @param aCaption
+ A caption or title string (like button text etc.)
+*/
+BOOL KDESalGraphics::getNativeControlRegion( ControlType nType, ControlPart nPart,
+ const Region& rControlRegion, ControlState nState,
+ const ImplControlValue&,
+ const OUString&,
+ Region &rNativeBoundingRegion, Region &rNativeContentRegion )
+{
+ BOOL bReturn = FALSE;
+ QRect qBoundingRect = WidgetPainter::region2QRect( rControlRegion );
+ QRect qRect;
+
+ QWidget *pWidget = NULL;
+ switch ( nType )
+ {
+ // Metrics of the push button
+ case CTRL_PUSHBUTTON:
+ pWidget = pWidgetPainter->pushButton( rControlRegion, ( nState & CTRL_STATE_DEFAULT ) );
+
+ switch ( nPart )
+ {
+ case PART_ENTIRE_CONTROL:
+ qRect = qBoundingRect;
+
+ if ( nState & CTRL_STATE_DEFAULT )
+ {
+ int nIndicatorSize = kapp->style().pixelMetric(
+ QStyle::PM_ButtonDefaultIndicator, pWidget );
+ qBoundingRect.addCoords( -nIndicatorSize, -nIndicatorSize,
+ nIndicatorSize, nIndicatorSize );
+ bReturn = TRUE;
+ }
+ break;
+ }
+ break;
+
+ // Metrics of the radio button
+ case CTRL_RADIOBUTTON:
+ pWidget = pWidgetPainter->radioButton( rControlRegion );
+
+ if ( nPart == PART_ENTIRE_CONTROL )
+ {
+ qRect.setWidth( kapp->style().pixelMetric( QStyle::PM_ExclusiveIndicatorWidth, pWidget ) );
+ qRect.setHeight( kapp->style().pixelMetric( QStyle::PM_ExclusiveIndicatorHeight, pWidget ) );
+
+ bReturn = TRUE;
+ }
+ break;
+
+ // Metrics of the check box
+ case CTRL_CHECKBOX:
+ pWidget = pWidgetPainter->checkBox( rControlRegion );
+
+ if ( nPart == PART_ENTIRE_CONTROL )
+ {
+ qRect.setWidth( kapp->style().pixelMetric( QStyle::PM_IndicatorWidth, pWidget ) );
+ qRect.setHeight( kapp->style().pixelMetric( QStyle::PM_IndicatorHeight, pWidget ) );
+
+ bReturn = TRUE;
+ }
+ break;
+
+ // Metrics of the combo box
+ case CTRL_COMBOBOX:
+ case CTRL_LISTBOX:
+ pWidget = pWidgetPainter->comboBox( rControlRegion, ( nType == CTRL_COMBOBOX ) );
+ switch ( nPart )
+ {
+ case PART_BUTTON_DOWN:
+ qRect = kapp->style().querySubControlMetrics(
+ QStyle::CC_ComboBox, pWidget, QStyle::SC_ComboBoxArrow );
+ qRect.setLeft( kapp->style().querySubControlMetrics(
+ QStyle::CC_ComboBox, pWidget,
+ QStyle::SC_ComboBoxEditField ).right() + 1 );
+ qRect.moveBy( qBoundingRect.left(), qBoundingRect.top() );
+ bReturn = TRUE;
+ break;
+
+ case PART_SUB_EDIT:
+ qRect = kapp->style().querySubControlMetrics(
+ QStyle::CC_ComboBox, pWidget, QStyle::SC_ComboBoxEditField );
+ qRect.moveBy( qBoundingRect.left(), qBoundingRect.top() );
+ bReturn = TRUE;
+ break;
+ }
+ break;
+
+ // Metrics of the spin box
+ case CTRL_SPINBOX:
+ pWidget = pWidgetPainter->spinWidget( rControlRegion );
+ switch ( nPart )
+ {
+ case PART_BUTTON_UP:
+ qRect = kapp->style().querySubControlMetrics(
+ QStyle::CC_SpinWidget, pWidget, QStyle::SC_SpinWidgetUp );
+ bReturn = TRUE;
+ qRect.moveBy( qBoundingRect.left(), qBoundingRect.top() );
+ break;
+
+ case PART_BUTTON_DOWN:
+ qRect = kapp->style().querySubControlMetrics(
+ QStyle::CC_SpinWidget, pWidget, QStyle::SC_SpinWidgetDown );
+ bReturn = TRUE;
+ qRect.moveBy( qBoundingRect.left(), qBoundingRect.top() );
+ break;
+
+ case PART_SUB_EDIT:
+ qRect = kapp->style().querySubControlMetrics(
+ QStyle::CC_SpinWidget, pWidget, QStyle::SC_SpinWidgetEditField );
+ qRect.moveBy( qBoundingRect.left(), qBoundingRect.top() );
+ bReturn = TRUE;
+ break;
+ }
+ break;
+
+ // Metrics of the scroll bar
+ case CTRL_SCROLLBAR:
+ pWidget = pWidgetPainter->scrollBar( rControlRegion,
+ ( nPart == PART_BUTTON_LEFT || nPart == PART_BUTTON_RIGHT ),
+ ImplControlValue() );
+ switch ( nPart )
+ {
+ case PART_BUTTON_LEFT:
+ case PART_BUTTON_UP:
+ qRect = kapp->style().querySubControlMetrics(
+ QStyle::CC_ScrollBar, pWidget, QStyle::SC_ScrollBarSubLine );
+
+ // Workaround for Platinum style scroll bars. It makes the
+ // left/up button invisible.
+ if ( nPart == PART_BUTTON_LEFT )
+ {
+ if ( qRect.left() > kapp->style().querySubControlMetrics(
+ QStyle::CC_ScrollBar, pWidget,
+ QStyle::SC_ScrollBarSubPage ).left() )
+ {
+ qRect.setLeft( 0 );
+ qRect.setRight( 0 );
+ }
+ }
+ else
+ {
+ if ( qRect.top() > kapp->style().querySubControlMetrics(
+ QStyle::CC_ScrollBar, pWidget,
+ QStyle::SC_ScrollBarSubPage ).top() )
+ {
+ qRect.setTop( 0 );
+ qRect.setBottom( 0 );
+ }
+ }
+
+ qRect.moveBy( qBoundingRect.left(), qBoundingRect.top() );
+
+ bReturn = TRUE;
+ break;
+
+ case PART_BUTTON_RIGHT:
+ case PART_BUTTON_DOWN:
+ qRect = kapp->style().querySubControlMetrics(
+ QStyle::CC_ScrollBar, pWidget, QStyle::SC_ScrollBarAddLine );
+
+ // Workaround for Platinum and 3 button style scroll bars.
+ // It makes the right/down button bigger.
+ if ( nPart == PART_BUTTON_RIGHT )
+ qRect.setLeft( kapp->style().querySubControlMetrics(
+ QStyle::CC_ScrollBar, pWidget,
+ QStyle::SC_ScrollBarAddPage ).right() + 1 );
+ else
+ qRect.setTop( kapp->style().querySubControlMetrics(
+ QStyle::CC_ScrollBar, pWidget,
+ QStyle::SC_ScrollBarAddPage ).bottom() + 1 );
+
+ qRect.moveBy( qBoundingRect.left(), qBoundingRect.top() );
+
+ bReturn = TRUE;
+ break;
+ }
+ break;
+ }
+
+ // Fill rNativeBoundingRegion and rNativeContentRegion
+ if ( bReturn )
+ {
+ // Bounding region
+ Point aBPoint( qBoundingRect.x(), qBoundingRect.y() );
+ Size aBSize( qBoundingRect.width(), qBoundingRect.height() );
+ rNativeBoundingRegion = Region( Rectangle( aBPoint, aBSize ) );
+
+ // Region of the content
+ Point aPoint( qRect.x(), qRect.y() );
+ Size aSize( qRect.width(), qRect.height() );
+ rNativeContentRegion = Region( Rectangle( aPoint, aSize ) );
+ }
+
+ return bReturn;
+}
+
+// -----------------------------------------------------------------------
+// KDESalFrame implementation
+// -----------------------------------------------------------------------
+
+KDESalFrame::KDESalFrame( SalFrame* pParent, ULONG nStyle ) :
+ X11SalFrame( pParent, nStyle )
+{
+}
+
+void KDESalFrame::Show( BOOL bVisible, BOOL bNoActivate )
+{
+ if ( !GetParent() && ! (GetStyle() & SAL_FRAME_STYLE_INTRO) )
+ {
+ KDEXLib* pXLib = static_cast<KDEXLib*>(GetDisplay()->GetXLib());
+ pXLib->doStartup();
+ }
+ X11SalFrame::Show( bVisible, bNoActivate );
+}
+
+/** Helper function to convert colors.
+*/
+static Color toColor( const QColor &rColor )
+{
+ return Color( rColor.red(), rColor.green(), rColor.blue() );
+}
+
+/** Helper function to read untranslated text entry from KConfig configuration repository.
+*/
+static OUString readEntryUntranslated( KConfig *pConfig, const char *pKey )
+{
+ return OUString::createFromAscii( pConfig->readEntryUntranslated( pKey ).ascii() );
+}
+
+/** Helper function to read color from KConfig configuration repository.
+*/
+static Color readColor( KConfig *pConfig, const char *pKey )
+{
+ return toColor( pConfig->readColorEntry( pKey ) );
+}
+
+/** Helper function to add information to Font from QFont.
+
+ Mostly grabbed from the Gtk+ vclplug (salnativewidgets-gtk.cxx).
+*/
+static Font toFont( const QFont &rQFont, const ::com::sun::star::lang::Locale& rLocale )
+{
+ psp::FastPrintFontInfo aInfo;
+ QFontInfo qFontInfo( rQFont );
+
+ // set family name
+ aInfo.m_aFamilyName = String( rQFont.family().utf8(), RTL_TEXTENCODING_UTF8 );
+
+ // set italic
+ aInfo.m_eItalic = ( qFontInfo.italic()? psp::italic::Italic: psp::italic::Upright );
+
+ // set weight
+ int nWeight = qFontInfo.weight();
+ if ( nWeight <= QFont::Light )
+ aInfo.m_eWeight = psp::weight::Light;
+ else if ( nWeight <= QFont::Normal )
+ aInfo.m_eWeight = psp::weight::Normal;
+ else if ( nWeight <= QFont::DemiBold )
+ aInfo.m_eWeight = psp::weight::SemiBold;
+ else if ( nWeight <= QFont::Bold )
+ aInfo.m_eWeight = psp::weight::Bold;
+ else
+ aInfo.m_eWeight = psp::weight::UltraBold;
+
+ // set width
+ int nStretch = rQFont.stretch();
+ if ( nStretch <= QFont::UltraCondensed )
+ aInfo.m_eWidth = psp::width::UltraCondensed;
+ else if ( nStretch <= QFont::ExtraCondensed )
+ aInfo.m_eWidth = psp::width::ExtraCondensed;
+ else if ( nStretch <= QFont::Condensed )
+ aInfo.m_eWidth = psp::width::Condensed;
+ else if ( nStretch <= QFont::SemiCondensed )
+ aInfo.m_eWidth = psp::width::SemiCondensed;
+ else if ( nStretch <= QFont::Unstretched )
+ aInfo.m_eWidth = psp::width::Normal;
+ else if ( nStretch <= QFont::SemiExpanded )
+ aInfo.m_eWidth = psp::width::SemiExpanded;
+ else if ( nStretch <= QFont::Expanded )
+ aInfo.m_eWidth = psp::width::Expanded;
+ else if ( nStretch <= QFont::ExtraExpanded )
+ aInfo.m_eWidth = psp::width::ExtraExpanded;
+ else
+ aInfo.m_eWidth = psp::width::UltraExpanded;
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "font name BEFORE system match: \"%s\"\n", OUStringToOString( aInfo.m_aFamilyName, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+
+ // match font to e.g. resolve "Sans"
+ psp::PrintFontManager::get().matchFont( aInfo, rLocale );
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "font match %s, name AFTER: \"%s\"\n",
+ aInfo.m_nID != 0 ? "succeeded" : "failed",
+ OUStringToOString( aInfo.m_aFamilyName, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+
+ // font height
+ int nPointHeight = qFontInfo.pointSize();
+ if ( nPointHeight <= 0 )
+ nPointHeight = rQFont.pointSize();
+
+ // Create the font
+ Font aFont( aInfo.m_aFamilyName, Size( 0, nPointHeight ) );
+ if( aInfo.m_eWeight != psp::weight::Unknown )
+ aFont.SetWeight( PspGraphics::ToFontWeight( aInfo.m_eWeight ) );
+ if( aInfo.m_eWidth != psp::width::Unknown )
+ aFont.SetWidthType( PspGraphics::ToFontWidth( aInfo.m_eWidth ) );
+ if( aInfo.m_eItalic != psp::italic::Unknown )
+ aFont.SetItalic( PspGraphics::ToFontItalic( aInfo.m_eItalic ) );
+ if( aInfo.m_ePitch != psp::pitch::Unknown )
+ aFont.SetPitch( PspGraphics::ToFontPitch( aInfo.m_ePitch ) );
+
+ return aFont;
+}
+
+/** Implementation of KDE integration's main method.
+*/
+void KDESalFrame::UpdateSettings( AllSettings& rSettings )
+{
+ StyleSettings aStyleSettings( rSettings.GetStyleSettings() );
+ bool bSetTitleFont = false;
+
+ // WM settings
+ KConfig *pConfig = KGlobal::config();
+ if ( pConfig )
+ {
+ pConfig->setGroup( "WM" );
+ const char *pKey;
+
+ pKey = "activeBackground";
+ if ( pConfig->hasKey( pKey ) )
+ aStyleSettings.SetActiveColor( readColor( pConfig, pKey ) );
+
+ pKey = "activeBlend";
+ if ( pConfig->hasKey( pKey ) )
+ aStyleSettings.SetActiveColor2( readColor( pConfig, pKey ) );
+
+ pKey = "inactiveBackground";
+ if ( pConfig->hasKey( pKey ) )
+ aStyleSettings.SetDeactiveColor( readColor( pConfig, pKey ) );
+
+ pKey = "inactiveBlend";
+ if ( pConfig->hasKey( pKey ) )
+ aStyleSettings.SetDeactiveColor2( readColor( pConfig, pKey ) );
+
+ pKey = "inactiveForeground";
+ if ( pConfig->hasKey( pKey ) )
+ aStyleSettings.SetDeactiveTextColor( readColor( pConfig, pKey ) );
+
+ pKey = "activeForeground";
+ if ( pConfig->hasKey( pKey ) )
+ aStyleSettings.SetActiveTextColor( readColor( pConfig, pKey ) );
+
+ pKey = "titleFont";
+ if ( pConfig->hasKey( pKey ) )
+ {
+ Font aFont = toFont( pConfig->readFontEntry( pKey ), rSettings.GetUILocale() );
+ aStyleSettings.SetTitleFont( aFont );
+ bSetTitleFont = true;
+ }
+
+ pConfig->setGroup( "Icons" );
+
+ pKey = "Theme";
+ if ( pConfig->hasKey( pKey ) )
+ aStyleSettings.SetPreferredSymbolsStyleName( readEntryUntranslated( pConfig, pKey ) );
+ }
+
+ // General settings
+ QColorGroup qColorGroup = kapp->palette().active();
+
+ Color aFore = toColor( qColorGroup.foreground() );
+ Color aBack = toColor( qColorGroup.background() );
+ Color aText = toColor( qColorGroup.text() );
+ Color aBase = toColor( qColorGroup.base() );
+
+ // Foreground
+ aStyleSettings.SetRadioCheckTextColor( aFore );
+ aStyleSettings.SetLabelTextColor( aFore );
+ aStyleSettings.SetInfoTextColor( aFore );
+ aStyleSettings.SetDialogTextColor( aFore );
+ aStyleSettings.SetGroupTextColor( aFore );
+
+ // Text
+ aStyleSettings.SetFieldTextColor( aText );
+ aStyleSettings.SetFieldRolloverTextColor( aText );
+ aStyleSettings.SetWindowTextColor( aText );
+ aStyleSettings.SetHelpTextColor( aText );
+
+ // Base
+ aStyleSettings.SetFieldColor( aBase );
+ aStyleSettings.SetHelpColor( aBase );
+ aStyleSettings.SetWindowColor( aBase );
+ aStyleSettings.SetActiveTabColor( aBase );
+
+ // Buttons
+ aStyleSettings.SetButtonTextColor( toColor( qColorGroup.buttonText() ) );
+ aStyleSettings.SetButtonRolloverTextColor( toColor( qColorGroup.buttonText() ) );
+
+ // Disable color
+ aStyleSettings.SetDisableColor( toColor( qColorGroup.mid() ) );
+
+ // Workspace
+ aStyleSettings.SetWorkspaceColor( toColor( qColorGroup.mid() ) );
+
+ // Background
+ aStyleSettings.Set3DColors( aBack );
+ aStyleSettings.SetFaceColor( aBack );
+ aStyleSettings.SetInactiveTabColor( aBack );
+ aStyleSettings.SetDialogColor( aBack );
+ if( aBack == COL_LIGHTGRAY )
+ aStyleSettings.SetCheckedColor( Color( 0xCC, 0xCC, 0xCC ) );
+ else
+ {
+ Color aColor2 = aStyleSettings.GetLightColor();
+ aStyleSettings.
+ SetCheckedColor( Color( (BYTE)(((USHORT)aBack.GetRed()+(USHORT)aColor2.GetRed())/2),
+ (BYTE)(((USHORT)aBack.GetGreen()+(USHORT)aColor2.GetGreen())/2),
+ (BYTE)(((USHORT)aBack.GetBlue()+(USHORT)aColor2.GetBlue())/2)
+ ) );
+ }
+
+ // Selection
+ aStyleSettings.SetHighlightColor( toColor( qColorGroup.highlight() ) );
+ aStyleSettings.SetHighlightTextColor( toColor( qColorGroup.highlightedText() ) );
+
+ // Font
+ Font aFont = toFont( kapp->font(), rSettings.GetUILocale() );
+
+ aStyleSettings.SetAppFont( aFont );
+ aStyleSettings.SetHelpFont( aFont );
+ if( !bSetTitleFont )
+ aStyleSettings.SetTitleFont( aFont );
+ aStyleSettings.SetFloatTitleFont( aFont );
+ aStyleSettings.SetMenuFont( aFont ); // will be changed according to pMenuBar
+ aStyleSettings.SetToolFont( aFont ); // will be changed according to pToolBar
+ aStyleSettings.SetLabelFont( aFont );
+ aStyleSettings.SetInfoFont( aFont );
+ aStyleSettings.SetRadioCheckFont( aFont );
+ aStyleSettings.SetPushButtonFont( aFont );
+ aStyleSettings.SetFieldFont( aFont );
+ aStyleSettings.SetIconFont( aFont );
+ aStyleSettings.SetGroupFont( aFont );
+ int flash_time = QApplication::cursorFlashTime();
+ aStyleSettings.SetCursorBlinkTime( flash_time != 0 ? flash_time/2 : STYLE_CURSOR_NOBLINKTIME );
+
+ KMainWindow qMainWindow;
+ qMainWindow.createGUI( "/dev/null" ); // hack
+
+ // Menu
+ aStyleSettings.SetSkipDisabledInMenus( TRUE );
+ KMenuBar *pMenuBar = qMainWindow.menuBar();
+ if ( pMenuBar )
+ {
+ // Color
+ QColorGroup qMenuCG = pMenuBar->colorGroup();
+
+ // Menu text and background color, theme specific
+ Color aMenuFore = toColor( qMenuCG.foreground() );
+ Color aMenuBack = toColor( qMenuCG.background() );
+ if ( kapp->style().inherits( "LightStyleV2" ) ||
+ kapp->style().inherits( "LightStyleV3" ) ||
+ ( kapp->style().inherits( "QMotifStyle" ) && !kapp->style().inherits( "QSGIStyle" ) ) ||
+ kapp->style().inherits( "QWindowsStyle" ) )
+ {
+ aMenuFore = toColor( qMenuCG.buttonText() );
+ aMenuBack = toColor( qMenuCG.button() );
+ }
+
+ aStyleSettings.SetMenuTextColor( aMenuFore );
+ aStyleSettings.SetMenuBarTextColor( aMenuFore );
+ aStyleSettings.SetMenuColor( aMenuBack );
+ aStyleSettings.SetMenuBarColor( aMenuBack );
+
+ aStyleSettings.SetMenuHighlightColor( toColor ( qMenuCG.highlight() ) );
+
+ // Menu items higlight text color, theme specific
+ if ( kapp->style().inherits( "HighContrastStyle" ) ||
+ kapp->style().inherits( "KeramikStyle" ) ||
+ kapp->style().inherits( "QWindowsStyle" ) ||
+ kapp->style().inherits( "ThinKeramikStyle" ) ||
+ kapp->style().inherits( "PlastikStyle" ) )
+ {
+ aStyleSettings.SetMenuHighlightTextColor( toColor ( qMenuCG.highlightedText() ) );
+ }
+ else
+ aStyleSettings.SetMenuHighlightTextColor( aMenuFore );
+
+ // set special menubar higlight text color
+ if ( kapp->style().inherits( "HighContrastStyle" ) )
+ ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor = toColor( qMenuCG.highlightedText() );
+ else
+ ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor = aMenuFore;
+
+ // Font
+ aFont = toFont( pMenuBar->font(), rSettings.GetUILocale() );
+ aStyleSettings.SetMenuFont( aFont );
+ }
+
+ // Tool bar
+ KToolBar *pToolBar = qMainWindow.toolBar();
+ if ( pToolBar )
+ {
+ aFont = toFont( pToolBar->font(), rSettings.GetUILocale() );
+ aStyleSettings.SetToolFont( aFont );
+ }
+
+ // Scroll bar size
+ aStyleSettings.SetScrollBarSize( kapp->style().pixelMetric( QStyle::PM_ScrollBarExtent ) );
+
+ rSettings.SetStyleSettings( aStyleSettings );
+}
+
+SalGraphics* KDESalFrame::GetGraphics()
+{
+ if( GetWindow() )
+ {
+ for( int i = 0; i < nMaxGraphics; i++ )
+ {
+ if( ! m_aGraphics[i].bInUse )
+ {
+ m_aGraphics[i].bInUse = true;
+ if( ! m_aGraphics[i].pGraphics )
+ {
+ m_aGraphics[i].pGraphics = new KDESalGraphics();
+ m_aGraphics[i].pGraphics->Init( this, GetWindow(), GetScreenNumber() );
+ }
+ return m_aGraphics[i].pGraphics;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+void KDESalFrame::ReleaseGraphics( SalGraphics *pGraphics )
+{
+ for( int i = 0; i < nMaxGraphics; i++ )
+ {
+ if( m_aGraphics[i].pGraphics == pGraphics )
+ {
+ m_aGraphics[i].bInUse = false;
+ break;
+ }
+ }
+}
+
+void KDESalFrame::updateGraphics( bool bClear )
+{
+ Drawable aDrawable = bClear ? None : GetWindow();
+ for( int i = 0; i < nMaxGraphics; i++ )
+ {
+ if( m_aGraphics[i].bInUse )
+ m_aGraphics[i].pGraphics->SetDrawable( aDrawable, GetScreenNumber() );
+ }
+}
+
+KDESalFrame::~KDESalFrame()
+{
+}
+
+KDESalFrame::GraphicsHolder::~GraphicsHolder()
+{
+ delete pGraphics;
+}
+
+// -----------------------------------------------------------------------
+// KDESalInstance implementation
+// -----------------------------------------------------------------------
+
+SalFrame *
+KDESalInstance::CreateFrame( SalFrame *pParent, ULONG nStyle )
+{
+ return new KDESalFrame( pParent, nStyle );
+}
+
+// -----------------------------------------------------------------------
+// KDESalData pieces
+// -----------------------------------------------------------------------
+
+// Create the widget painter so we have some control over
+// the destruction sequence, so Qt doesn't die in action.
+
+void KDEData::initNWF()
+{
+ ImplSVData *pSVData = ImplGetSVData();
+ // draw toolbars on separate lines
+ pSVData->maNWFData.mbDockingAreaSeparateTB = true;
+
+ pWidgetPainter = new WidgetPainter();
+}
+
+void KDEData::deInitNWF()
+{
+ delete pWidgetPainter;
+ pWidgetPainter = NULL;
+
+ // We have to destroy the style early
+ kapp->setStyle( NULL );
+}
diff --git a/vcl/unx/kde4/KDEData.cxx b/vcl/unx/kde4/KDEData.cxx
new file mode 100644
index 000000000000..99871edadae3
--- /dev/null
+++ b/vcl/unx/kde4/KDEData.cxx
@@ -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.
+ *
+ ************************************************************************/
+
+#include "KDEData.hxx"
+
+#include "KDEXLib.hxx"
+
+KDEData::~KDEData()
+{
+}
+
+void KDEData::Init()
+{
+ pXLib_ = new KDEXLib();
+ pXLib_->Init();
+}
+
+void KDEData::initNWF()
+{
+ ImplSVData *pSVData = ImplGetSVData();
+
+ // draw toolbars on separate lines
+ pSVData->maNWFData.mbDockingAreaSeparateTB = true;
+ // no borders for menu, theming does that
+ pSVData->maNWFData.mbFlatMenu = true;
+}
+
+void KDEData::deInitNWF()
+{
+} \ No newline at end of file
diff --git a/vcl/unx/kde4/KDEData.hxx b/vcl/unx/kde4/KDEData.hxx
new file mode 100644
index 000000000000..7cf5836c9688
--- /dev/null
+++ b/vcl/unx/kde4/KDEData.hxx
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include <saldisp.hxx>
+#include <saldata.hxx>
+
+class KDEData : public X11SalData
+{
+ public:
+ KDEData() {}
+ virtual ~KDEData();
+
+ virtual void Init();
+ virtual void initNWF();
+ virtual void deInitNWF();
+}; \ No newline at end of file
diff --git a/vcl/unx/kde4/KDESalDisplay.cxx b/vcl/unx/kde4/KDESalDisplay.cxx
new file mode 100644
index 000000000000..d67399528a7c
--- /dev/null
+++ b/vcl/unx/kde4/KDESalDisplay.cxx
@@ -0,0 +1,45 @@
+/*************************************************************************
+ *
+ * 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 "KDESalDisplay.hxx"
+
+#include "KDEXLib.hxx"
+
+SalKDEDisplay::SalKDEDisplay( Display* pDisp )
+ : SalX11Display( pDisp )
+{
+}
+
+SalKDEDisplay::~SalKDEDisplay()
+{
+ // in case never a frame opened
+ static_cast<KDEXLib*>(GetXLib())->doStartup();
+ // clean up own members
+ doDestruct();
+ // prevent SalDisplay from closing KApplication's display
+ pDisp_ = NULL;
+} \ No newline at end of file
diff --git a/vcl/unx/kde4/KDESalDisplay.hxx b/vcl/unx/kde4/KDESalDisplay.hxx
new file mode 100644
index 000000000000..1ab966b1847b
--- /dev/null
+++ b/vcl/unx/kde4/KDESalDisplay.hxx
@@ -0,0 +1,37 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include <saldisp.hxx>
+
+class SalKDEDisplay : public SalX11Display
+{
+ public:
+ SalKDEDisplay( Display* pDisp );
+ virtual ~SalKDEDisplay();
+};
diff --git a/vcl/unx/kde4/KDESalFrame.cxx b/vcl/unx/kde4/KDESalFrame.cxx
new file mode 100644
index 000000000000..0c8f04f9fe41
--- /dev/null
+++ b/vcl/unx/kde4/KDESalFrame.cxx
@@ -0,0 +1,405 @@
+/*************************************************************************
+ *
+ * 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 Region QtXRegion
+
+#include <QColor>
+#include <QStyle>
+
+#include <kconfig.h>
+#include <kglobal.h>
+#include <kmenubar.h>
+#include <kconfiggroup.h>
+#include <kmainwindow.h>
+#include <kapplication.h>
+#include <ktoolbar.h>
+
+#undef Region
+
+#include "KDESalFrame.hxx"
+#include "KDEXLib.hxx"
+#include "KDESalGraphics.hxx"
+
+#include <vcl/settings.hxx>
+#include <vcl/font.hxx>
+#include <tools/color.hxx>
+
+#include <vcl/svdata.hxx>
+
+#include <pspgraphics.h>
+
+#if OSL_DEBUG_LEVEL > 1
+#include <stdio.h>
+#endif
+
+KDESalFrame::KDESalFrame( SalFrame* pParent, ULONG nState ) :
+ X11SalFrame( pParent, nState )
+{
+}
+
+void KDESalFrame::Show( BOOL bVisible, BOOL bNoActivate )
+{
+ if ( !GetParent() && ! (GetStyle() & SAL_FRAME_STYLE_INTRO) )
+ {
+ KDEXLib* pXLib = static_cast<KDEXLib*>(GetDisplay()->GetXLib());
+ pXLib->doStartup();
+ }
+
+ X11SalFrame::Show( bVisible, bNoActivate );
+}
+
+/** Helper function to convert colors.
+*/
+static Color toColor( const QColor &rColor )
+{
+ return Color( rColor.red(), rColor.green(), rColor.blue() );
+}
+
+/** Helper function to read untranslated text entry from KConfig configuration repository.
+*/
+static OUString readEntryUntranslated( KConfigGroup *pGroup, const char *pKey )
+{
+ return OUString::createFromAscii( (const char *) pGroup->readEntryUntranslated( pKey ).toAscii() );
+}
+
+/** Helper function to read color from KConfig configuration repository.
+*/
+static Color readColor( KConfigGroup *pGroup, const char *pKey )
+{
+ return toColor( pGroup->readEntry( pKey, QColor(Qt::white) ) );
+}
+
+/** Helper function to add information to Font from QFont.
+
+ Mostly grabbed from the Gtk+ vclplug (salnativewidgets-gtk.cxx).
+*/
+static Font toFont( const QFont &rQFont, const ::com::sun::star::lang::Locale& rLocale )
+{
+ psp::FastPrintFontInfo aInfo;
+ QFontInfo qFontInfo( rQFont );
+
+ // set family name
+ aInfo.m_aFamilyName = String( (const char *) rQFont.family().toUtf8(), RTL_TEXTENCODING_UTF8 );
+
+ // set italic
+ aInfo.m_eItalic = ( qFontInfo.italic()? psp::italic::Italic: psp::italic::Upright );
+
+ // set weight
+ int nWeight = qFontInfo.weight();
+ if ( nWeight <= QFont::Light )
+ aInfo.m_eWeight = psp::weight::Light;
+ else if ( nWeight <= QFont::Normal )
+ aInfo.m_eWeight = psp::weight::Normal;
+ else if ( nWeight <= QFont::DemiBold )
+ aInfo.m_eWeight = psp::weight::SemiBold;
+ else if ( nWeight <= QFont::Bold )
+ aInfo.m_eWeight = psp::weight::Bold;
+ else
+ aInfo.m_eWeight = psp::weight::UltraBold;
+
+ // set width
+ int nStretch = rQFont.stretch();
+ if ( nStretch <= QFont::UltraCondensed )
+ aInfo.m_eWidth = psp::width::UltraCondensed;
+ else if ( nStretch <= QFont::ExtraCondensed )
+ aInfo.m_eWidth = psp::width::ExtraCondensed;
+ else if ( nStretch <= QFont::Condensed )
+ aInfo.m_eWidth = psp::width::Condensed;
+ else if ( nStretch <= QFont::SemiCondensed )
+ aInfo.m_eWidth = psp::width::SemiCondensed;
+ else if ( nStretch <= QFont::Unstretched )
+ aInfo.m_eWidth = psp::width::Normal;
+ else if ( nStretch <= QFont::SemiExpanded )
+ aInfo.m_eWidth = psp::width::SemiExpanded;
+ else if ( nStretch <= QFont::Expanded )
+ aInfo.m_eWidth = psp::width::Expanded;
+ else if ( nStretch <= QFont::ExtraExpanded )
+ aInfo.m_eWidth = psp::width::ExtraExpanded;
+ else
+ aInfo.m_eWidth = psp::width::UltraExpanded;
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "font name BEFORE system match: \"%s\"\n", OUStringToOString( aInfo.m_aFamilyName, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+
+ // match font to e.g. resolve "Sans"
+ psp::PrintFontManager::get().matchFont( aInfo, rLocale );
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "font match %s, name AFTER: \"%s\"\n",
+ aInfo.m_nID != 0 ? "succeeded" : "failed",
+ OUStringToOString( aInfo.m_aFamilyName, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+
+ // font height
+ int nPointHeight = qFontInfo.pointSize();
+ if ( nPointHeight <= 0 )
+ nPointHeight = rQFont.pointSize();
+
+ // Create the font
+ Font aFont( aInfo.m_aFamilyName, Size( 0, nPointHeight ) );
+ if( aInfo.m_eWeight != psp::weight::Unknown )
+ aFont.SetWeight( PspGraphics::ToFontWeight( aInfo.m_eWeight ) );
+ if( aInfo.m_eWidth != psp::width::Unknown )
+ aFont.SetWidthType( PspGraphics::ToFontWidth( aInfo.m_eWidth ) );
+ if( aInfo.m_eItalic != psp::italic::Unknown )
+ aFont.SetItalic( PspGraphics::ToFontItalic( aInfo.m_eItalic ) );
+ if( aInfo.m_ePitch != psp::pitch::Unknown )
+ aFont.SetPitch( PspGraphics::ToFontPitch( aInfo.m_ePitch ) );
+
+ return aFont;
+}
+
+/** Implementation of KDE integration's main method.
+*/
+void KDESalFrame::UpdateSettings( AllSettings& rSettings )
+{
+ StyleSettings style( rSettings.GetStyleSettings() );
+ BOOL bSetTitleFont = false;
+
+ // General settings
+ QPalette pal = kapp->palette();
+
+ style.SetActiveColor(toColor(pal.color(QPalette::Active, QPalette::Window)));
+ style.SetDeactiveColor(toColor(pal.color(QPalette::Inactive, QPalette::Window)));
+
+ style.SetActiveColor2(toColor(pal.color(QPalette::Active, QPalette::Window)));
+ style.SetDeactiveColor2(toColor(pal.color(QPalette::Inactive, QPalette::Window)));
+
+ style.SetActiveTextColor(toColor(pal.color(QPalette::Active, QPalette::WindowText)));
+ style.SetDeactiveTextColor(toColor(pal.color(QPalette::Inactive, QPalette::WindowText)));
+
+ // WM settings
+ KConfig *pConfig = KGlobal::config().data();
+ if ( pConfig )
+ {
+ KConfigGroup aGroup = pConfig->group( "WM" );
+ const char *pKey;
+
+ pKey = "titleFont";
+ if ( aGroup.hasKey( pKey ) )
+ {
+ Font aFont = toFont( aGroup.readEntry( pKey, QFont() ), rSettings.GetUILocale() );
+ style.SetTitleFont( aFont );
+ bSetTitleFont = true;
+ }
+
+ aGroup = pConfig->group( "Icons" );
+
+ pKey = "Theme";
+ if ( aGroup.hasKey( pKey ) )
+ style.SetPreferredSymbolsStyleName( readEntryUntranslated( &aGroup, pKey ) );
+
+ //toolbar
+ pKey = "toolbarFont";
+ if ( aGroup.hasKey( pKey ) )
+ {
+ Font aFont = toFont( aGroup.readEntry( pKey, QFont() ), rSettings.GetUILocale() );
+ style.SetToolFont( aFont );
+ }
+ }
+
+ Color aFore = toColor( pal.color( QPalette::Active, QPalette::WindowText ) );
+ Color aBack = toColor( pal.color( QPalette::Active, QPalette::Window ) );
+ Color aText = toColor( pal.color( QPalette::Active, QPalette::Text ) );
+ Color aBase = toColor( pal.color( QPalette::Active, QPalette::Base ) );
+ Color aButn = toColor( pal.color( QPalette::Active, QPalette::ButtonText ) );
+ Color aMid = toColor( pal.color( QPalette::Active, QPalette::Mid ) );
+ Color aHigh = toColor( pal.color( QPalette::Active, QPalette::Highlight ) );
+
+ // Foreground
+ style.SetRadioCheckTextColor( aFore );
+ style.SetLabelTextColor( aFore );
+ style.SetInfoTextColor( aFore );
+ style.SetDialogTextColor( aFore );
+ style.SetGroupTextColor( aFore );
+
+ // Text
+ style.SetFieldTextColor( aText );
+ style.SetFieldRolloverTextColor( aText );
+ style.SetWindowTextColor( aText );
+ style.SetHelpTextColor( aText );
+
+ // Base
+ style.SetFieldColor( aBase );
+ style.SetHelpColor( aBase );
+ style.SetWindowColor( aBase );
+ style.SetActiveTabColor( aBase );
+
+ // Buttons
+ style.SetButtonTextColor( aButn );
+ style.SetButtonRolloverTextColor( aButn );
+
+ // Disable color
+ style.SetDisableColor( aMid );
+
+ // Workspace
+ style.SetWorkspaceColor( aMid );
+
+ // Background
+ style.Set3DColors( aBack );
+ style.SetFaceColor( aBack );
+ style.SetInactiveTabColor( aBack );
+ style.SetDialogColor( aBack );
+
+ if( aBack == COL_LIGHTGRAY )
+ style.SetCheckedColor( Color( 0xCC, 0xCC, 0xCC ) );
+ else
+ {
+ Color aColor2 = style.GetLightColor();
+ style.
+ SetCheckedColor( Color( (BYTE)(((USHORT)aBack.GetRed()+(USHORT)aColor2.GetRed())/2),
+ (BYTE)(((USHORT)aBack.GetGreen()+(USHORT)aColor2.GetGreen())/2),
+ (BYTE)(((USHORT)aBack.GetBlue()+(USHORT)aColor2.GetBlue())/2)
+ ) );
+ }
+
+ // Selection
+ style.SetHighlightColor( aHigh );
+ style.SetHighlightTextColor( toColor(pal.color( QPalette::HighlightedText)) );
+
+ // Font
+ Font aFont = toFont( kapp->font(), rSettings.GetUILocale() );
+
+ style.SetAppFont( aFont );
+ style.SetHelpFont( aFont );
+
+ if( !bSetTitleFont )
+ {
+ style.SetTitleFont( aFont );
+ }
+
+ style.SetFloatTitleFont( aFont );
+ style.SetMenuFont( aFont ); // will be changed according to pMenuBar
+ //style.SetToolFont( aFont ); //already set above
+ style.SetLabelFont( aFont );
+ style.SetInfoFont( aFont );
+ style.SetRadioCheckFont( aFont );
+ style.SetPushButtonFont( aFont );
+ style.SetFieldFont( aFont );
+ style.SetIconFont( aFont );
+ style.SetGroupFont( aFont );
+
+ int flash_time = QApplication::cursorFlashTime();
+ style.SetCursorBlinkTime( flash_time != 0 ? flash_time/2 : STYLE_CURSOR_NOBLINKTIME );
+
+ // Menu
+ style.SetSkipDisabledInMenus( TRUE );
+ KMenuBar* pMenuBar = new KMenuBar();
+ if ( pMenuBar )
+ {
+ // Color
+ QPalette qMenuCG = pMenuBar->palette();
+
+ // Menu text and background color, theme specific
+ Color aMenuFore = toColor( qMenuCG.color( QPalette::WindowText ) );
+ Color aMenuBack = toColor( qMenuCG.color( QPalette::Window ) );
+
+ aMenuFore = toColor( qMenuCG.color( QPalette::ButtonText ) );
+ aMenuBack = toColor( qMenuCG.color( QPalette::Button ) );
+
+ style.SetMenuTextColor( aMenuFore );
+ style.SetMenuBarTextColor( aMenuFore );
+ style.SetMenuColor( aMenuBack );
+ style.SetMenuBarColor( aMenuBack );
+
+ style.SetMenuHighlightColor( toColor ( qMenuCG.color( QPalette::Highlight ) ) );
+
+ style.SetMenuHighlightTextColor( aMenuFore );
+
+ // set special menubar higlight text color
+ if ( kapp->style()->inherits( "HighContrastStyle" ) )
+ ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor = toColor( qMenuCG.color( QPalette::HighlightedText ) );
+ else
+ ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor = aMenuFore;
+
+ // Font
+ aFont = toFont( pMenuBar->font(), rSettings.GetUILocale() );
+ style.SetMenuFont( aFont );
+ }
+
+ delete pMenuBar;
+
+ // Scroll bar size
+ style.SetScrollBarSize( kapp->style()->pixelMetric( QStyle::PM_ScrollBarExtent ) );
+
+ rSettings.SetStyleSettings( style );
+}
+
+
+void KDESalFrame::ReleaseGraphics( SalGraphics *pGraphics )
+{
+ for( int i = 0; i < nMaxGraphics; i++ )
+ {
+ if( m_aGraphics[i].pGraphics == pGraphics )
+ {
+ m_aGraphics[i].bInUse = false;
+ break;
+ }
+ }
+}
+
+void KDESalFrame::updateGraphics( bool bClear )
+{
+ Drawable aDrawable = bClear ? None : GetWindow();
+ for( int i = 0; i < nMaxGraphics; i++ )
+ {
+ if( m_aGraphics[i].bInUse )
+ m_aGraphics[i].pGraphics->SetDrawable( aDrawable, GetScreenNumber() );
+ }
+}
+
+KDESalFrame::~KDESalFrame()
+{
+}
+
+KDESalFrame::GraphicsHolder::~GraphicsHolder()
+{
+ delete pGraphics;
+}
+
+SalGraphics* KDESalFrame::GetGraphics()
+{
+ if( GetWindow() )
+ {
+ for( int i = 0; i < nMaxGraphics; i++ )
+ {
+ if( ! m_aGraphics[i].bInUse )
+ {
+ m_aGraphics[i].bInUse = true;
+ if( ! m_aGraphics[i].pGraphics )
+ {
+ m_aGraphics[i].pGraphics = new KDESalGraphics();
+ m_aGraphics[i].pGraphics->Init( this, GetWindow(), GetScreenNumber() );
+ }
+ return m_aGraphics[i].pGraphics;
+ }
+ }
+ }
+
+ return NULL;
+} \ No newline at end of file
diff --git a/vcl/unx/kde4/KDESalFrame.hxx b/vcl/unx/kde4/KDESalFrame.hxx
new file mode 100644
index 000000000000..643be72c27f3
--- /dev/null
+++ b/vcl/unx/kde4/KDESalFrame.hxx
@@ -0,0 +1,58 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include <saldisp.hxx>
+#include <salframe.h>
+
+class KDESalFrame : public X11SalFrame
+{
+ private:
+ static const int nMaxGraphics = 2;
+
+ struct GraphicsHolder
+ {
+ X11SalGraphics* pGraphics;
+ bool bInUse;
+
+ GraphicsHolder() : pGraphics(0),bInUse( false ) {}
+ ~GraphicsHolder();
+ };
+
+ GraphicsHolder m_aGraphics[ nMaxGraphics ];
+
+ public:
+ KDESalFrame( SalFrame* pParent, ULONG nStyle );
+ virtual ~KDESalFrame();
+
+ virtual SalGraphics* GetGraphics();
+ virtual void ReleaseGraphics( SalGraphics *pGraphics );
+ virtual void updateGraphics( bool bClear );
+ virtual void UpdateSettings( AllSettings& rSettings );
+ virtual void Show( BOOL bVisible, BOOL bNoActivate );
+}; \ No newline at end of file
diff --git a/vcl/unx/kde4/KDESalGraphics.cxx b/vcl/unx/kde4/KDESalGraphics.cxx
new file mode 100644
index 000000000000..5f8b5d2ae59e
--- /dev/null
+++ b/vcl/unx/kde4/KDESalGraphics.cxx
@@ -0,0 +1,881 @@
+/*************************************************************************
+ *
+ * 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 _SV_SALNATIVEWIDGETS_KDE_CXX
+
+#define Region QtXRegion
+
+#include <QStyle>
+#include <QStyleOption>
+#include <QPainter>
+#include <QFrame>
+#include <QLabel>
+
+#include <kapplication.h>
+
+#undef Region
+
+#include "KDESalGraphics.hxx"
+
+#include "vcl/settings.hxx"
+#include "vcl/decoview.hxx"
+#include "rtl/ustrbuf.hxx"
+
+using namespace ::rtl;
+
+/**
+ Conversion function between VCL ControlState together with
+ ImplControlValue and Qt state flags.
+ @param nControlState State of the widget (default, focused, ...) in Native Widget Framework.
+ @param aValue Value held by the widget (on, off, ...)
+*/
+QStyle::State vclStateValue2StateFlag( ControlState nControlState,
+ const ImplControlValue& aValue )
+{
+ QStyle::State nState =
+ ( (nControlState & CTRL_STATE_DEFAULT)? QStyle::State_None: QStyle::State_None ) |
+ ( (nControlState & CTRL_STATE_ENABLED)? QStyle::State_Enabled: QStyle::State_None ) |
+ ( (nControlState & CTRL_STATE_FOCUSED)? QStyle::State_HasFocus: QStyle::State_None ) |
+ ( (nControlState & CTRL_STATE_PRESSED)? QStyle::State_Sunken: QStyle::State_None ) |
+ ( (nControlState & CTRL_STATE_SELECTED)? QStyle::State_Selected : QStyle::State_None ) |
+ ( (nControlState & CTRL_STATE_ROLLOVER)? QStyle::State_MouseOver: QStyle::State_None );
+ //TODO ( (nControlState & CTRL_STATE_HIDDEN)? QStyle::State_: QStyle::State_None ) |
+
+ switch ( aValue.getTristateVal() )
+ {
+ case BUTTONVALUE_ON: nState |= QStyle::State_On; break;
+ case BUTTONVALUE_OFF: nState |= QStyle::State_Off; break;
+ case BUTTONVALUE_MIXED: nState |= QStyle::State_NoChange; break;
+ default: break;
+ }
+
+ return nState;
+}
+
+/**
+ Convert VCL Region to QRect.
+ @param rControlRegion The region to convert.
+ @return The bounding box of the region.
+*/
+QRect region2QRect( const Region& rControlRegion )
+{
+ Rectangle aRect = rControlRegion.GetBoundRect();
+
+ return QRect(aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight());
+}
+
+KDESalGraphics::KDESalGraphics() :
+ m_image(0)
+{
+}
+
+KDESalGraphics::~KDESalGraphics()
+{
+ if (m_image)
+ delete m_image;
+}
+
+BOOL KDESalGraphics::IsNativeControlSupported( ControlType type, ControlPart part )
+{
+ if (type == CTRL_PUSHBUTTON) return true;
+
+ if (type == CTRL_MENUBAR) return true;
+
+ if (type == CTRL_MENU_POPUP) return true;
+
+ if (type == CTRL_EDITBOX) return true;
+
+ if (type == CTRL_COMBOBOX) return true;
+
+ if (type == CTRL_TOOLBAR) return true;
+
+ if (type == CTRL_CHECKBOX) return true;
+
+ if (type == CTRL_LISTBOX) return true;
+
+ if (type == CTRL_LISTNODE) return true;
+
+ if (type == CTRL_FRAME) return true;
+
+ if (type == CTRL_SCROLLBAR) return true;
+
+ if (type == CTRL_WINDOW_BACKGROUND) return true;
+
+ if (type == CTRL_SPINBOX && (part == PART_ENTIRE_CONTROL || part == HAS_BACKGROUND_TEXTURE) ) return true;
+
+ // no spinbuttons for KDE, paint spinbox complete
+ //if (type == CTRL_SPINBUTTONS) return true;
+
+ if (type == CTRL_GROUPBOX) return true;
+
+ if (type == CTRL_FIXEDLINE) return true;
+
+ if (type == CTRL_FIXEDBORDER) return true;
+
+ if (type == CTRL_TOOLTIP) return true;
+
+ if (type == CTRL_RADIOBUTTON) return true;
+
+ if (type == CTRL_SLIDER && (part == PART_TRACK_HORZ_AREA || part == PART_TRACK_VERT_AREA) )
+ return true;
+
+ return false;
+
+ if ( (type == CTRL_TAB_ITEM) && (part == PART_ENTIRE_CONTROL) ) return true;
+ if ( (type == CTRL_TAB_PANE) && (part == PART_ENTIRE_CONTROL) ) return true;
+ // no CTRL_TAB_BODY for KDE
+ if ( (type == CTRL_PROGRESS) && (part == PART_ENTIRE_CONTROL) ) return true;
+
+ return false;
+}
+
+BOOL KDESalGraphics::hitTestNativeControl( ControlType, ControlPart,
+ const Region&, const Point&,
+ BOOL& )
+{
+ return FALSE;
+}
+
+/// helper drawing methods
+namespace
+{
+ void draw( QStyle::ControlElement element, QStyleOption* option, QImage* image, QStyle::State state )
+ {
+ option->state |= state;
+ option->rect = image->rect();
+
+ QPainter painter(image);
+ kapp->style()->drawControl(element, option, &painter);
+ }
+
+ void draw( QStyle::PrimitiveElement element, QStyleOption* option, QImage* image, QStyle::State state, int nAdjust = 0 )
+ {
+ option->state |= state;
+ option->rect = image->rect();
+ if( nAdjust )
+ option->rect.adjust( nAdjust, nAdjust, -nAdjust, -nAdjust );
+
+ QPainter painter(image);
+ kapp->style()->drawPrimitive(element, option, &painter);
+ }
+
+ void draw( QStyle::ComplexControl element, QStyleOptionComplex* option, QImage* image, QStyle::State state )
+ {
+ option->state |= state;
+ option->rect = image->rect();
+
+ QPainter painter(image);
+ kapp->style()->drawComplexControl(element, option, &painter);
+ }
+
+ void lcl_drawFrame(QStyle::PrimitiveElement element, QImage* image, QStyle::State state)
+ {
+ #if ( QT_VERSION >= QT_VERSION_CHECK( 4, 5, 0 ) )
+ QStyleOptionFrameV3 option;
+ option.frameShape = QFrame::StyledPanel;
+ option.state = QStyle::State_Sunken;
+ #else
+ QStyleOptionFrame option;
+
+ QFrame aFrame( NULL );
+ aFrame.setFrameRect( QRect(0, 0, image->width(), image->height()) );
+ aFrame.setFrameStyle( QFrame::StyledPanel | QFrame::Sunken );
+ aFrame.ensurePolished();
+
+ option.initFrom( &aFrame );
+ option.lineWidth = aFrame.lineWidth();
+ option.midLineWidth = aFrame.midLineWidth();
+ #endif
+
+ draw(element, &option, image, state);
+ }
+}
+
+BOOL KDESalGraphics::drawNativeControl( ControlType type, ControlPart part,
+ const Region& rControlRegion, ControlState nControlState,
+ const ImplControlValue& value,
+ const OUString& )
+{
+ // put not implemented types here
+ if (type == CTRL_SPINBUTTONS)
+ {
+ return false;
+ }
+
+ BOOL returnVal = true;
+
+ QRect widgetRect = region2QRect(rControlRegion);
+ if( type == CTRL_SPINBOX && part == PART_ALL_BUTTONS )
+ type = CTRL_SPINBUTTONS;
+ if( type == CTRL_SPINBUTTONS )
+ {
+ SpinbuttonValue* pSpinVal = (SpinbuttonValue *)(value.getOptionalVal());
+ Rectangle aButtonRect( pSpinVal->maUpperRect);
+ aButtonRect.Union( pSpinVal->maLowerRect );;
+ widgetRect = QRect( aButtonRect.Left(), aButtonRect.Top(),
+ aButtonRect.Right(), aButtonRect.Bottom() );
+ }
+
+ //if no image, or resized, make a new image
+ if (!m_image || m_image->size() != widgetRect.size())
+ {
+ if (m_image)
+ delete m_image;
+
+ m_image = new QImage( widgetRect.width(),
+ widgetRect.height(),
+ QImage::Format_ARGB32 );
+ }
+ m_image->fill(KApplication::palette().color(QPalette::Window).rgb());
+
+
+ XLIB_Region pTempClipRegion = 0;
+
+ if (type == CTRL_PUSHBUTTON)
+ {
+ QStyleOptionButton option;
+ draw( QStyle::CE_PushButton, &option, m_image,
+ vclStateValue2StateFlag(nControlState, value) );
+ }
+ else if ( (type == CTRL_MENUBAR))
+ {
+ if (part == PART_MENU_ITEM)
+ {
+ QStyleOptionMenuItem option;
+ draw( QStyle::CE_MenuBarItem, &option, m_image,
+ vclStateValue2StateFlag(nControlState, value) );
+ }
+ else if (part == PART_ENTIRE_CONTROL)
+ {
+ }
+ else
+ {
+ returnVal = false;
+ }
+ }
+ else if (type == CTRL_MENU_POPUP)
+ {
+ if (part == PART_MENU_ITEM)
+ {
+ QStyleOptionMenuItem option;
+ draw( QStyle::CE_MenuItem, &option, m_image,
+ vclStateValue2StateFlag(nControlState, value) );
+ }
+ else if (part == PART_MENU_ITEM_CHECK_MARK && (nControlState & CTRL_STATE_PRESSED) )
+ {
+ QStyleOptionButton option;
+ draw( QStyle::PE_IndicatorMenuCheckMark, &option, m_image,
+ vclStateValue2StateFlag(nControlState, value) );
+ }
+ else if (part == PART_MENU_ITEM_RADIO_MARK && (nControlState & CTRL_STATE_PRESSED) )
+ {
+ QStyleOptionButton option;
+ draw( QStyle::PE_IndicatorRadioButton, &option, m_image,
+ vclStateValue2StateFlag(nControlState, value) );
+ }
+ else
+ {
+ #if ( QT_VERSION >= QT_VERSION_CHECK( 4, 5, 0 ) )
+ QStyleOptionFrameV3 option;
+ option.frameShape = QFrame::StyledPanel;
+ #else
+ QStyleOptionFrameV2 option;
+ #endif
+ draw( QStyle::PE_FrameMenu, &option, m_image,
+ vclStateValue2StateFlag(nControlState, value) );
+ }
+ }
+ else if ( (type == CTRL_TOOLBAR) && (part == PART_BUTTON) )
+ {
+ QStyleOptionToolButton option;
+
+ option.arrowType = Qt::NoArrow;
+ option.subControls = QStyle::SC_ToolButton;
+
+ option.state = vclStateValue2StateFlag( nControlState, value );
+ option.state |= QStyle::State_Raised | QStyle::State_Enabled | QStyle::State_AutoRaise;
+
+ draw( QStyle::CC_ToolButton, &option, m_image,
+ vclStateValue2StateFlag(nControlState, value) );
+ }
+ else if ( (type == CTRL_TOOLBAR) && (part == PART_ENTIRE_CONTROL) )
+ {
+ QStyleOptionToolBar option;
+
+ option.rect = QRect(0, 0, widgetRect.width(), widgetRect.height());
+ option.state = vclStateValue2StateFlag( nControlState, value );
+
+ draw( QStyle::CE_ToolBar, &option, m_image,
+ vclStateValue2StateFlag(nControlState, value) );
+ }
+ else if ( (type == CTRL_TOOLBAR) && (part == PART_THUMB_VERT) )
+ {
+ const int tw = widgetRect.width();
+ widgetRect.setWidth(kapp->style()->pixelMetric(QStyle::PM_ToolBarHandleExtent));
+
+ QStyleOption option;
+ option.state = QStyle::State_Horizontal;
+
+ draw( QStyle::PE_IndicatorToolBarHandle, &option, m_image,
+ vclStateValue2StateFlag(nControlState, value) );
+
+ widgetRect.setWidth(tw);
+ }
+ else if (type == CTRL_EDITBOX)
+ {
+ QStyleOptionFrameV2 option;
+ draw( QStyle::PE_PanelLineEdit, &option, m_image,
+ vclStateValue2StateFlag(nControlState, value), 2 );
+
+ draw( QStyle::PE_FrameLineEdit, &option, m_image,
+ vclStateValue2StateFlag(nControlState, value), 0 );
+ }
+ else if (type == CTRL_COMBOBOX)
+ {
+ QStyleOptionComboBox option;
+ option.editable = true;
+
+ draw( QStyle::CC_ComboBox, &option, m_image,
+ vclStateValue2StateFlag(nControlState, value) );
+ }
+ else if (type == CTRL_LISTBOX)
+ {
+ if( part == PART_WINDOW )
+ {
+ lcl_drawFrame( QStyle::PE_Frame, m_image,
+ vclStateValue2StateFlag(nControlState, value) );
+ }
+ else
+ {
+ QStyleOptionComboBox option;
+ if (part == PART_SUB_EDIT)
+ {
+ draw( QStyle::CE_ComboBoxLabel, &option, m_image,
+ vclStateValue2StateFlag(nControlState, value) );
+ }
+ else
+ {
+ draw( QStyle::CC_ComboBox, &option, m_image,
+ vclStateValue2StateFlag(nControlState, value) );
+ }
+ }
+ }
+ else if (type == CTRL_LISTNODE)
+ {
+ QStyleOption option;
+ option.state = QStyle::State_Item | QStyle::State_Children;
+
+ if (nControlState & CTRL_STATE_PRESSED)
+ option.state |= QStyle::State_Open;
+
+ draw( QStyle::PE_IndicatorBranch, &option, m_image,
+ vclStateValue2StateFlag(nControlState, value) );
+ }
+ else if (type == CTRL_CHECKBOX)
+ {
+ QStyleOptionButton option;
+ draw( QStyle::CE_CheckBox, &option, m_image,
+ vclStateValue2StateFlag(nControlState, value) );
+ }
+ else if (type == CTRL_SCROLLBAR)
+ {
+ if ((part == PART_DRAW_BACKGROUND_VERT) || (part == PART_DRAW_BACKGROUND_HORZ))
+ {
+ QStyleOptionSlider option;
+ ScrollbarValue* sbVal = static_cast<ScrollbarValue *> ( value.getOptionalVal() );
+
+ //if the scroll bar is active (aka not degenrate...allow for hover events
+ if (sbVal->mnVisibleSize < sbVal->mnMax)
+ option.state = QStyle::State_MouseOver;
+
+ //horizontal or vertical
+ if (part == PART_DRAW_BACKGROUND_VERT)
+ option.orientation = Qt::Vertical;
+ else
+ option.state |= QStyle::State_Horizontal;
+
+ //setup parameters from the OO values
+ option.minimum = sbVal->mnMin;
+ option.maximum = sbVal->mnMax - sbVal->mnVisibleSize;
+ option.sliderValue = sbVal->mnCur;
+ option.sliderPosition = sbVal->mnCur;
+ option.pageStep = sbVal->mnVisibleSize;
+
+ //setup the active control...always the slider
+ if (sbVal->mnThumbState & CTRL_STATE_ROLLOVER)
+ option.activeSubControls = QStyle::SC_ScrollBarSlider;
+
+ draw( QStyle::CC_ScrollBar, &option, m_image,
+ vclStateValue2StateFlag(nControlState, value) );
+ }
+ else
+ {
+ returnVal = false;
+ }
+ }
+ else if (type == CTRL_SPINBOX)
+ {
+ QStyleOptionSpinBox option;
+
+ // determine active control
+ SpinbuttonValue* pSpinVal = (SpinbuttonValue *)(value.getOptionalVal());
+ if( pSpinVal )
+ {
+ if( (pSpinVal->mnUpperState & CTRL_STATE_PRESSED) )
+ option.activeSubControls |= QStyle::SC_SpinBoxUp;
+ if( (pSpinVal->mnLowerState & CTRL_STATE_PRESSED) )
+ option.activeSubControls |= QStyle::SC_SpinBoxDown;
+ }
+
+ draw( QStyle::CC_SpinBox, &option, m_image,
+ vclStateValue2StateFlag(nControlState, value) );
+ }
+ else if (type == CTRL_GROUPBOX)
+ {
+ QStyleOptionGroupBox option;
+ draw( QStyle::CC_GroupBox, &option, m_image,
+ vclStateValue2StateFlag(nControlState, value) );
+ }
+ else if (type == CTRL_RADIOBUTTON)
+ {
+ QStyleOptionButton option;
+ draw( QStyle::CE_RadioButton, &option, m_image,
+ vclStateValue2StateFlag(nControlState, value) );
+ }
+ else if (type == CTRL_TOOLTIP)
+ {
+ QStyleOption option;
+ draw( QStyle::PE_PanelTipLabel, &option, m_image,
+ vclStateValue2StateFlag(nControlState, value) );
+ }
+ else if (type == CTRL_FRAME)
+ {
+ lcl_drawFrame( QStyle::PE_Frame, m_image,
+ vclStateValue2StateFlag(nControlState, value) );
+
+ int size = kapp->style()->pixelMetric(QStyle::PM_LayoutLeftMargin);
+ pTempClipRegion = XCreateRegion();
+ XRectangle xRect = { widgetRect.left(), widgetRect.top(), widgetRect.width(), widgetRect.height() };
+ XUnionRectWithRegion( &xRect, pTempClipRegion, pTempClipRegion );
+ XLIB_Region pSubtract = XCreateRegion();
+ xRect.x += size;
+ xRect.y += size;
+ xRect.width -= 2* size;
+ xRect.height -= 2*size;
+ XUnionRectWithRegion( &xRect, pSubtract, pSubtract );
+ XSubtractRegion( pTempClipRegion, pSubtract, pTempClipRegion );
+ XDestroyRegion( pSubtract );
+ }
+ else if (type == CTRL_FIXEDBORDER)
+ {
+ lcl_drawFrame( QStyle::PE_FrameWindow, m_image,
+ vclStateValue2StateFlag(nControlState, value) );
+ }
+ else if (type == CTRL_WINDOW_BACKGROUND)
+ {
+ m_image->fill(KApplication::palette().color(QPalette::Window).rgb());
+ }
+ else if (type == CTRL_FIXEDLINE)
+ {
+ QStyleOptionMenuItem option;
+ option.menuItemType = QStyleOptionMenuItem::Separator;
+ option.state |= QStyle::State_Item;
+
+ draw( QStyle::CE_MenuItem, &option, m_image,
+ vclStateValue2StateFlag(nControlState, value) );
+ }
+ else if (type == CTRL_SLIDER && (part == PART_TRACK_HORZ_AREA || part == PART_TRACK_VERT_AREA))
+ {
+ SliderValue* slVal = static_cast<SliderValue *> ( value.getOptionalVal() );
+ QStyleOptionSlider option;
+
+ option.rect = QRect(0, 0, widgetRect.width(), widgetRect.height());
+ option.state = vclStateValue2StateFlag( nControlState, value );
+ option.maximum = slVal->mnMax;
+ option.minimum = slVal->mnMin;
+ option.sliderPosition = option.sliderValue = slVal->mnCur;
+ option.orientation = (part == PART_TRACK_HORZ_AREA) ? Qt::Horizontal : Qt::Vertical;
+
+ draw( QStyle::CC_Slider, &option, m_image, vclStateValue2StateFlag(nControlState, value) );
+ }
+ else
+ {
+ returnVal = false;
+ }
+
+ if (returnVal)
+ {
+ GC gc = SelectFont();
+
+ if( gc )
+ {
+ if( pTempClipRegion )
+ {
+ if( pClipRegion_ )
+ XIntersectRegion( pTempClipRegion, pClipRegion_, pTempClipRegion );
+ XSetRegion( GetXDisplay(), gc, pTempClipRegion );
+ }
+ QPixmap pixmap = QPixmap::fromImage(*m_image, Qt::ColorOnly | Qt::OrderedDither | Qt::OrderedAlphaDither);
+ X11SalGraphics::CopyScreenArea( GetXDisplay(),
+ pixmap.handle(), pixmap.x11Info().screen(), pixmap.x11Info().depth(),
+ GetDrawable(), GetScreenNumber(), GetVisual().GetDepth(),
+ gc, 0, 0, widgetRect.width(), widgetRect.height(), widgetRect.left(), widgetRect.top());
+
+ if( pTempClipRegion )
+ {
+ if( pClipRegion_ )
+ XSetRegion( GetXDisplay(), gc, pClipRegion_ );
+ else
+ XSetClipMask( GetXDisplay(), gc, None );
+ }
+ }
+ else
+ returnVal = false;
+ }
+ if( pTempClipRegion )
+ XDestroyRegion( pTempClipRegion );
+
+ return returnVal;
+}
+
+BOOL KDESalGraphics::getNativeControlRegion( ControlType type, ControlPart part,
+ const Region& controlRegion, ControlState controlState,
+ const ImplControlValue& val,
+ const OUString&,
+ Region &nativeBoundingRegion, Region &nativeContentRegion )
+{
+ bool retVal = false;
+
+ QRect boundingRect = region2QRect( controlRegion );
+ QRect contentRect = boundingRect;
+ QStyleOptionComplex styleOption;
+
+ switch ( type )
+ {
+ // Metrics of the push button
+ case CTRL_PUSHBUTTON:
+ if (part == PART_ENTIRE_CONTROL)
+ {
+ styleOption.state = vclStateValue2StateFlag(controlState, val);
+
+ if ( controlState & CTRL_STATE_DEFAULT )
+ {
+ int size = kapp->style()->pixelMetric(
+ QStyle::PM_ButtonDefaultIndicator, &styleOption );
+
+ boundingRect.adjust( -size, -size, size, size );
+
+ retVal = true;
+ }
+ }
+ break;
+ case CTRL_EDITBOX:
+ {
+ int nFontHeight = kapp->fontMetrics().height();
+ //int nFrameSize = kapp->style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
+ int nLayoutTop = kapp->style()->pixelMetric(QStyle::PM_LayoutTopMargin);
+ int nLayoutBottom = kapp->style()->pixelMetric(QStyle::PM_LayoutBottomMargin);
+ int nLayoutLeft = kapp->style()->pixelMetric(QStyle::PM_LayoutLeftMargin);
+ int nLayoutRight = kapp->style()->pixelMetric(QStyle::PM_LayoutRightMargin);
+
+ int nMinHeight = (nFontHeight + nLayoutTop + nLayoutBottom);
+ if( boundingRect.height() < nMinHeight )
+ {
+ int delta = nMinHeight - boundingRect.height();
+ boundingRect.adjust( 0, 0, 0, delta );
+ }
+ contentRect = boundingRect;
+ contentRect.adjust( -nLayoutLeft+1, -nLayoutTop+1, nLayoutRight-1, nLayoutBottom-1 );
+ retVal = true;
+
+ break;
+ }
+ case CTRL_CHECKBOX:
+ if (part == PART_ENTIRE_CONTROL)
+ {
+ styleOption.state = vclStateValue2StateFlag(controlState, val);
+
+ contentRect.setWidth(kapp->style()->pixelMetric(
+ QStyle::PM_IndicatorWidth, &styleOption));
+ contentRect.setHeight(kapp->style()->pixelMetric(
+ QStyle::PM_IndicatorHeight, &styleOption));
+
+ contentRect.adjust(0, 0,
+ 2 * kapp->style()->pixelMetric(
+ QStyle::PM_FocusFrameHMargin, &styleOption),
+ 2 * kapp->style()->pixelMetric(
+ QStyle::PM_FocusFrameVMargin, &styleOption)
+ );
+
+ boundingRect = contentRect;
+
+ retVal = true;
+
+ break;
+ }
+ case CTRL_COMBOBOX:
+ case CTRL_LISTBOX:
+ {
+ QStyleOptionComboBox cbo;
+
+ cbo.rect = QRect(0, 0, contentRect.width(), contentRect.height());
+ cbo.state = vclStateValue2StateFlag(controlState, val);
+
+ switch ( part )
+ {
+ case PART_ENTIRE_CONTROL:
+ {
+ int size = kapp->style()->pixelMetric(QStyle::PM_ComboBoxFrameWidth) - 2;
+
+ // find out the minimum size that should be used
+ // assume contents is a text ling
+ int nHeight = kapp->fontMetrics().height();
+ QSize aContentSize( contentRect.width(), nHeight );
+ QSize aMinSize = kapp->style()->
+ sizeFromContents( QStyle::CT_ComboBox, &cbo, aContentSize );
+ if( aMinSize.height() > contentRect.height() )
+ contentRect.adjust( 0, 0, 0, aMinSize.height() - contentRect.height() );
+ boundingRect = contentRect;
+ // FIXME: why this difference between comboboxes and listboxes ?
+ // because a combobox has a sub edit and that is positioned
+ // inside the outer bordered control ?
+ if( type == CTRL_COMBOBOX )
+ contentRect.adjust(-size,-size,size,size);
+ retVal = true;
+ break;
+ }
+ case PART_BUTTON_DOWN:
+ //the entire control can be used as the "down" button
+ retVal = true;
+ break;
+ case PART_SUB_EDIT:
+ contentRect = kapp->style()->subControlRect(
+ QStyle::CC_ComboBox, &cbo, QStyle::SC_ComboBoxEditField );
+
+ contentRect.translate( boundingRect.left(), boundingRect.top() );
+
+ retVal = true;
+ break;
+ case PART_WINDOW:
+ retVal = true;
+ break;
+ }
+ break;
+ }
+ case CTRL_SPINBOX:
+ {
+ QStyleOptionSpinBox sbo;
+
+ sbo.rect = QRect(0, 0, contentRect.width(), contentRect.height());
+ sbo.state = vclStateValue2StateFlag(controlState, val);
+
+ switch ( part )
+ {
+ case PART_BUTTON_UP:
+ contentRect = kapp->style()->subControlRect(
+ QStyle::CC_SpinBox, &sbo, QStyle::SC_SpinBoxUp );
+ contentRect.translate( boundingRect.left(), boundingRect.top() );
+ retVal = true;
+ boundingRect = QRect();
+ break;
+
+ case PART_BUTTON_DOWN:
+ contentRect = kapp->style()->subControlRect(
+ QStyle::CC_SpinBox, &sbo, QStyle::SC_SpinBoxDown );
+ retVal = true;
+ contentRect.translate( boundingRect.left(), boundingRect.top() );
+ boundingRect = QRect();
+ break;
+
+ case PART_SUB_EDIT:
+ contentRect = kapp->style()->subControlRect(
+ QStyle::CC_SpinBox, &sbo, QStyle::SC_SpinBoxEditField );
+ retVal = true;
+ contentRect.translate( boundingRect.left(), boundingRect.top() );
+ break;
+ default:
+ retVal = true;
+ }
+ break;
+ }
+ case CTRL_MENU_POPUP:
+ //just limit the widget of the menu items
+ //OO isn't very flexible in all reguards with the menu
+ //so we do the best we can
+ if (part == PART_MENU_ITEM_CHECK_MARK)
+ {
+ contentRect.setWidth(contentRect.height());
+ retVal = true;
+ }
+ else if (part == PART_MENU_ITEM_RADIO_MARK)
+ {
+ contentRect.setWidth(contentRect.height());
+ retVal = true;
+ }
+ break;
+ case CTRL_FRAME:
+ {
+ if( part == PART_BORDER )
+ {
+ int size = kapp->style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
+ USHORT nStyle = val.getNumericVal();
+ if( nStyle & FRAME_DRAW_NODRAW )
+ {
+ // in this case the question is: how thick would a frame be
+ // see brdwin.cxx, decoview.cxx
+ // most probably the behavior in decoview.cxx is wrong.
+ contentRect.adjust(size, size, -size, -size);
+ }
+ retVal = true;
+ }
+ break;
+ }
+ case CTRL_RADIOBUTTON:
+ {
+ const int h = kapp->style()->pixelMetric(QStyle::PM_ExclusiveIndicatorHeight);
+ const int w = kapp->style()->pixelMetric(QStyle::PM_ExclusiveIndicatorWidth);
+
+ contentRect = QRect(boundingRect.left(), boundingRect.top(), w, h);
+ contentRect.adjust(0, 0,
+ 2 * kapp->style()->pixelMetric(
+ QStyle::PM_FocusFrameHMargin, &styleOption),
+ 2 * kapp->style()->pixelMetric(
+ QStyle::PM_FocusFrameVMargin, &styleOption)
+ );
+ boundingRect = contentRect;
+
+ retVal = true;
+ break;
+ }
+ case CTRL_SLIDER:
+ {
+ const int w = kapp->style()->pixelMetric(QStyle::PM_SliderLength);
+ if( part == PART_THUMB_HORZ )
+ {
+ contentRect = QRect(boundingRect.left(), boundingRect.top(), w, boundingRect.height());
+ boundingRect = contentRect;
+ retVal = true;
+ }
+ else if( part == PART_THUMB_VERT )
+ {
+ contentRect = QRect(boundingRect.left(), boundingRect.top(), boundingRect.width(), w);
+ boundingRect = contentRect;
+ retVal = true;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+#if 0
+
+
+ // Metrics of the scroll bar
+ case CTRL_SCROLLBAR:
+ //pWidget = pWidgetPainter->scrollBar( rControlRegion,
+ //( part == PART_BUTTON_LEFT || part == PART_BUTTON_RIGHT ),
+ //ImplControlValue() );
+ //aStyleOption.initFrom( pWidget );
+
+ switch ( part )
+ {
+ case PART_BUTTON_LEFT:
+ case PART_BUTTON_UP:
+ qRect = kapp->style()->subControlRect(
+ QStyle::CC_ScrollBar, &aStyleOption, QStyle::SC_ScrollBarSubLine );
+
+ // Workaround for Platinum style scroll bars. It makes the
+ // left/up button invisible.
+ if ( part == PART_BUTTON_LEFT )
+ {
+ if ( qRect.left() > kapp->style()->subControlRect(
+ QStyle::CC_ScrollBar, &aStyleOption,
+ QStyle::SC_ScrollBarSubPage ).left() )
+ {
+ qRect.setLeft( 0 );
+ qRect.setRight( 0 );
+ }
+ }
+ else
+ {
+ if ( qRect.top() > kapp->style()->subControlRect(
+ QStyle::CC_ScrollBar, &aStyleOption,
+ QStyle::SC_ScrollBarSubPage ).top() )
+ {
+ qRect.setTop( 0 );
+ qRect.setBottom( 0 );
+ }
+ }
+
+ qRect.translate( qBoundingRect.left(), qBoundingRect.top() );
+
+ bReturn = TRUE;
+ break;
+
+ case PART_BUTTON_RIGHT:
+ case PART_BUTTON_DOWN:
+ qRect = kapp->style()->subControlRect(
+ QStyle::CC_ScrollBar, &aStyleOption, QStyle::SC_ScrollBarAddLine );
+
+ // Workaround for Platinum and 3 button style scroll bars.
+ // It makes the right/down button bigger.
+ if ( part == PART_BUTTON_RIGHT )
+ qRect.setLeft( kapp->style()->subControlRect(
+ QStyle::CC_ScrollBar, &aStyleOption,
+ QStyle::SC_ScrollBarAddPage ).right() + 1 );
+ else
+ qRect.setTop( kapp->style()->subControlRect(
+ QStyle::CC_ScrollBar, &aStyleOption,
+ QStyle::SC_ScrollBarAddPage ).bottom() + 1 );
+
+ qRect.translate( qBoundingRect.left(), qBoundingRect.top() );
+
+ bReturn = TRUE;
+ break;
+ }
+ break;
+ }
+#endif
+
+ if (retVal)
+ {
+ // Bounding region
+ Point aBPoint( boundingRect.x(), boundingRect.y() );
+ Size aBSize( boundingRect.width(), boundingRect.height() );
+ nativeBoundingRegion = Region( Rectangle( aBPoint, aBSize ) );
+
+ // Region of the content
+ Point aPoint( contentRect.x(), contentRect.y() );
+ Size aSize( contentRect.width(), contentRect.height() );
+ nativeContentRegion = Region( Rectangle( aPoint, aSize ) );
+ }
+
+ return retVal;
+}
diff --git a/vcl/unx/kde4/KDESalGraphics.hxx b/vcl/unx/kde4/KDESalGraphics.hxx
new file mode 100644
index 000000000000..5661d743e0cd
--- /dev/null
+++ b/vcl/unx/kde4/KDESalGraphics.hxx
@@ -0,0 +1,113 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include <rtl/string.hxx>
+#include <saldisp.hxx>
+#include <salgdi.h>
+
+#define Region QtXRegion
+#include <QImage>
+#undef Region
+
+/** handles graphics drawings requests and performs the needed drawing operations */
+class KDESalGraphics : public X11SalGraphics
+{
+ QImage* m_image;
+
+ public:
+ KDESalGraphics();
+ virtual ~KDESalGraphics();
+
+ /**
+ What widgets can be drawn the native way.
+ @param type Type of the widget.
+ @param part Specification of the widget's part if it consists of more than one.
+ @return true if the platform supports native drawing of the widget type defined by part.
+ */
+ virtual BOOL IsNativeControlSupported( ControlType type, ControlPart part );
+
+ /** Test whether the position is in the native widget.
+ If the return value is TRUE, bIsInside contains information whether
+ aPos was or was not inside the native widget specified by the
+ type/part combination.
+ */
+ virtual BOOL hitTestNativeControl( ControlType type, ControlPart part,
+ const Region& rControlRegion, const Point& aPos,
+ BOOL& rIsInside );
+ /** Draw the requested control described by part/nControlState.
+
+ @param rControlRegion
+ The bounding region of the complete control in VCL frame coordinates.
+
+ @param aValue
+ An optional value (tristate/numerical/string).
+
+ @param aCaption
+ A caption or title string (like button text etc.)
+ */
+ virtual BOOL drawNativeControl( ControlType type, ControlPart part,
+ const Region& rControlRegion, ControlState nControlState,
+ const ImplControlValue& aValue,
+ const rtl::OUString& aCaption );
+
+ /** Draw text on the widget.
+ OPTIONAL. Draws the requested text for the control described by part/nControlState.
+ Used if text is not drawn by DrawNativeControl().
+
+ @param rControlRegion The bounding region of the complete control in VCL frame coordinates.
+ @param aValue An optional value (tristate/numerical/string)
+ @param aCaption A caption or title string (like button text etc.)
+ */
+ virtual BOOL drawNativeControlText( ControlType, ControlPart,
+ const Region&, ControlState,
+ const ImplControlValue&,
+ const rtl::OUString& ) { return false; }
+ /** Check if the bounding regions match.
+
+ 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.
+
+ @param rControlRegion
+ The bounding region of the control in VCL frame coordinates.
+
+ @param aValue
+ An optional value (tristate/numerical/string)
+
+ @param aCaption
+ A caption or title string (like button text etc.)
+ */
+ virtual BOOL getNativeControlRegion( ControlType type, ControlPart part,
+ const Region& rControlRegion, ControlState nControlState,
+ const ImplControlValue& aValue,
+ const rtl::OUString& aCaption,
+ Region &rNativeBoundingRegion, Region &rNativeContentRegion );
+}; \ No newline at end of file
diff --git a/vcl/unx/kde4/KDESalInstance.cxx b/vcl/unx/kde4/KDESalInstance.cxx
new file mode 100644
index 000000000000..01c4723bd530
--- /dev/null
+++ b/vcl/unx/kde4/KDESalInstance.cxx
@@ -0,0 +1,35 @@
+/*************************************************************************
+ *
+ * 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 "KDESalInstance.hxx"
+
+#include "KDESalFrame.hxx"
+
+SalFrame* KDESalInstance::CreateFrame( SalFrame *pParent, ULONG nState )
+{
+ return new KDESalFrame( pParent, nState );
+} \ No newline at end of file
diff --git a/vcl/unx/kde4/KDESalInstance.hxx b/vcl/unx/kde4/KDESalInstance.hxx
new file mode 100644
index 000000000000..7d050fe6819e
--- /dev/null
+++ b/vcl/unx/kde4/KDESalInstance.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include <salinst.h>
+
+class SalYieldMutex;
+class SalFrame;
+
+class KDESalInstance : public X11SalInstance
+{
+ public:
+ KDESalInstance( SalYieldMutex* pMutex ) : X11SalInstance( pMutex ) {}
+ virtual ~KDESalInstance() {}
+ virtual SalFrame* CreateFrame( SalFrame* pParent, ULONG nStyle );
+}; \ No newline at end of file
diff --git a/vcl/unx/kde4/KDEXLib.cxx b/vcl/unx/kde4/KDEXLib.cxx
new file mode 100644
index 000000000000..6a2793b8abe3
--- /dev/null
+++ b/vcl/unx/kde4/KDEXLib.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.
+ *
+ ************************************************************************/
+
+#include "VCLKDEApplication.hxx"
+
+#define Region QtXRegion
+
+#include <kapplication.h>
+#include <klocale.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <kstartupinfo.h>
+
+#undef Region
+
+#include "KDEXLib.hxx"
+
+#include <i18n_im.hxx>
+#include <i18n_xkb.hxx>
+
+#include <saldata.hxx>
+#include <vos/process.hxx>
+
+#include "KDESalDisplay.hxx"
+
+#if OSL_DEBUG_LEVEL > 1
+#include <stdio.h>
+#endif
+
+KDEXLib::KDEXLib() :
+ SalXLib(), m_bStartupDone(false), m_pApplication(0),
+ m_pFreeCmdLineArgs(0), m_pAppCmdLineArgs(0), m_nFakeCmdLineArgs( 0 )
+{
+}
+
+KDEXLib::~KDEXLib()
+{
+ delete (VCLKDEApplication*)m_pApplication;
+
+ // free the faked cmdline arguments no longer needed by KApplication
+ for( int i = 0; i < m_nFakeCmdLineArgs; i++ )
+ {
+ free( m_pFreeCmdLineArgs[i] );
+ }
+
+ delete [] m_pFreeCmdLineArgs;
+ delete [] m_pAppCmdLineArgs;
+}
+
+void KDEXLib::Init()
+{
+ SalI18N_InputMethod* pInputMethod = new SalI18N_InputMethod;
+ pInputMethod->SetLocale();
+ XrmInitialize();
+
+ KAboutData *kAboutData = new KAboutData("OpenOffice.org",
+ "kdelibs4",
+ ki18n( "OpenOffice.org" ),
+ "3.0.0",
+ ki18n( "OpenOffice.org with KDE Native Widget Support." ),
+ KAboutData::License_LGPL,
+ ki18n( "Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Novell, Inc"),
+ ki18n( "OpenOffice.org is an office suite.\n" ),
+ "http://kde.openoffice.org/index.html",
+ "dev@kde.openoffice.org" );
+
+ kAboutData->addAuthor( ki18n( "Jan Holesovsky" ),
+ ki18n( "Original author and maintainer of the KDE NWF." ),
+ "kendy@artax.karlin.mff.cuni.cz",
+ "http://artax.karlin.mff.cuni.cz/~kendy" );
+ kAboutData->addAuthor( ki18n("Roman Shtylman"),
+ ki18n( "Porting to KDE 4." ),
+ "shtylman@gmail.com", "http://shtylman.com" );
+ kAboutData->addAuthor( ki18n("Eric Bischoff"),
+ ki18n( "Accessibility fixes, porting to KDE 4." ),
+ "bischoff@kde.org" );
+
+ //kAboutData->setProgramIconName("OpenOffice");
+
+ m_nFakeCmdLineArgs = 1;
+ USHORT nIdx;
+ vos::OExtCommandLine aCommandLine;
+ int nParams = aCommandLine.getCommandArgCount();
+ rtl::OString aDisplay;
+ rtl::OUString aParam, aBin;
+
+ for ( nIdx = 0; nIdx < nParams; ++nIdx )
+ {
+ aCommandLine.getCommandArg( nIdx, aParam );
+ if ( !m_pFreeCmdLineArgs && aParam.equalsAscii( "-display" ) && nIdx + 1 < nParams )
+ {
+ aCommandLine.getCommandArg( nIdx + 1, aParam );
+ aDisplay = rtl::OUStringToOString( aParam, osl_getThreadTextEncoding() );
+
+ m_nFakeCmdLineArgs = 3;
+ m_pFreeCmdLineArgs = new char*[ m_nFakeCmdLineArgs ];
+ m_pFreeCmdLineArgs[ 1 ] = strdup( "-display" );
+ m_pFreeCmdLineArgs[ 2 ] = strdup( aDisplay.getStr() );
+ }
+ }
+ if ( !m_pFreeCmdLineArgs )
+ m_pFreeCmdLineArgs = new char*[ m_nFakeCmdLineArgs ];
+
+ osl_getExecutableFile( &aParam.pData );
+ osl_getSystemPathFromFileURL( aParam.pData, &aBin.pData );
+ rtl::OString aExec = rtl::OUStringToOString( aBin, osl_getThreadTextEncoding() );
+ m_pFreeCmdLineArgs[0] = strdup( aExec.getStr() );
+
+ // make a copy of the string list for freeing it since
+ // KApplication manipulates the pointers inside the argument vector
+ // note: KApplication bad !
+ m_pAppCmdLineArgs = new char*[ m_nFakeCmdLineArgs ];
+ for( int i = 0; i < m_nFakeCmdLineArgs; i++ )
+ m_pAppCmdLineArgs[i] = m_pFreeCmdLineArgs[i];
+
+ KCmdLineArgs::init( m_nFakeCmdLineArgs, m_pAppCmdLineArgs, kAboutData );
+
+ m_pApplication = new VCLKDEApplication();
+ kapp->disableSessionManagement();
+ KApplication::setQuitOnLastWindowClosed(false);
+
+ Display* pDisp = QX11Info::display();
+ SalKDEDisplay *pSalDisplay = new SalKDEDisplay(pDisp);
+
+ ((VCLKDEApplication*)m_pApplication)->disp = pSalDisplay;
+
+ pInputMethod->CreateMethod( pDisp );
+ pInputMethod->AddConnectionWatch( pDisp, (void*)this );
+ pSalDisplay->SetInputMethod( pInputMethod );
+
+ PushXErrorLevel( true );
+ SalI18N_KeyboardExtension *pKbdExtension = new SalI18N_KeyboardExtension( pDisp );
+ XSync( pDisp, False );
+
+ pKbdExtension->UseExtension( ! HasXErrorOccured() );
+ PopXErrorLevel();
+
+ pSalDisplay->SetKbdExtension( pKbdExtension );
+}
+
+void KDEXLib::doStartup()
+{
+ if( ! m_bStartupDone )
+ {
+ KStartupInfo::appStarted();
+ m_bStartupDone = true;
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "called KStartupInfo::appStarted()\n" );
+ #endif
+ }
+}
diff --git a/vcl/unx/kde4/KDEXLib.hxx b/vcl/unx/kde4/KDEXLib.hxx
new file mode 100644
index 000000000000..985e0c3c6717
--- /dev/null
+++ b/vcl/unx/kde4/KDEXLib.hxx
@@ -0,0 +1,48 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#include <saldisp.hxx>
+
+class KDEXLib : public SalXLib
+{
+ private:
+ bool m_bStartupDone;
+ void* m_pApplication;
+ char** m_pFreeCmdLineArgs;
+ char** m_pAppCmdLineArgs;
+ int m_nFakeCmdLineArgs;
+
+ public:
+ KDEXLib();
+
+ virtual ~KDEXLib();
+ virtual void Init();
+
+ void doStartup();
+};
diff --git a/vcl/unx/kde4/VCLKDEApplication.cxx b/vcl/unx/kde4/VCLKDEApplication.cxx
new file mode 100644
index 000000000000..2cfb071e96ae
--- /dev/null
+++ b/vcl/unx/kde4/VCLKDEApplication.cxx
@@ -0,0 +1,52 @@
+/*************************************************************************
+ *
+ * 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 "VCLKDEApplication.hxx"
+
+#define Region QtXRegion
+#include <QEvent>
+#undef Region
+
+#include "KDESalDisplay.hxx"
+
+VCLKDEApplication::VCLKDEApplication() :
+ KApplication()
+{
+ disp = 0;
+}
+
+bool VCLKDEApplication::x11EventFilter(XEvent* event)
+{
+ //if we have a display and the display consumes the event
+ //do not process the event in qt
+ if (disp && disp->Dispatch(event) > 0)
+ {
+ return true;
+ }
+
+ return false;
+} \ No newline at end of file
diff --git a/vcl/unx/kde4/VCLKDEApplication.hxx b/vcl/unx/kde4/VCLKDEApplication.hxx
new file mode 100644
index 000000000000..2edfddd69a9c
--- /dev/null
+++ b/vcl/unx/kde4/VCLKDEApplication.hxx
@@ -0,0 +1,53 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#pragma once
+
+#define Region QtXRegion
+
+#include <QSessionManager>
+
+#include <kapplication.h>
+
+#undef Region
+
+class SalKDEDisplay;
+
+/* #i59042# override KApplications method for session management
+ * since it will interfere badly with our own.
+ */
+class VCLKDEApplication : public KApplication
+{
+ public:
+ VCLKDEApplication();
+
+ virtual void commitData(QSessionManager&) {};
+
+ virtual bool x11EventFilter(XEvent* event);
+
+ SalKDEDisplay* disp;
+}; \ No newline at end of file
diff --git a/vcl/unx/kde4/main.cxx b/vcl/unx/kde4/main.cxx
new file mode 100644
index 000000000000..962a882af26b
--- /dev/null
+++ b/vcl/unx/kde4/main.cxx
@@ -0,0 +1,93 @@
+/*************************************************************************
+ *
+ * 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 Region QtXRegion
+#include <QApplication>
+#undef Region
+
+#include "KDEData.hxx"
+#include "KDESalInstance.hxx"
+
+#if OSL_DEBUG_LEVEL > 1
+#include <stdio.h>
+#endif
+
+#include <rtl/string.hxx>
+
+/// entry point for the KDE4 VCL plugin
+extern "C" {
+ VCL_DLLPUBLIC SalInstance* create_SalInstance( oslModule )
+ {
+ /* #i92121# workaround deadlocks in the X11 implementation
+ */
+ static const char* pNoXInitThreads = getenv( "SAL_NO_XINITTHREADS" );
+ /* #i90094#
+ from now on we know that an X connection will be
+ established, so protect X against itself
+ */
+ if( ! ( pNoXInitThreads && *pNoXInitThreads ) )
+ XInitThreads();
+
+#if QT_VERSION < 0x050000
+ // Qt 4.x support needs >= 4.1.0
+ rtl::OString aVersion( qVersion() );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "qt version string is \"%s\"\n", aVersion.getStr() );
+#endif
+ sal_Int32 nIndex = 0, nMajor = 0, nMinor = 0, nMicro = 0;
+ nMajor = aVersion.getToken( 0, '.', nIndex ).toInt32();
+ if( nIndex > 0 )
+ nMinor = aVersion.getToken( 0, '.', nIndex ).toInt32();
+ if( nIndex > 0 )
+ nMicro = aVersion.getToken( 0, '.', nIndex ).toInt32();
+ if( nMajor != 4 || nMinor < 1 )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "unsuitable qt version %d.%d.%d\n", nMajor, nMinor, nMicro );
+#endif
+ return NULL;
+ }
+#endif
+
+ KDESalInstance* pInstance = new KDESalInstance( new SalYieldMutex() );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "created KDESalInstance 0x%p\n", pInstance );
+#endif
+
+ // initialize SalData
+ KDEData *salData = new KDEData();
+ SetSalData(salData);
+ salData->m_pInstance = pInstance;
+ salData->Init();
+ salData->initNWF();
+
+ return pInstance;
+ }
+}
diff --git a/vcl/unx/kde4/makefile.mk b/vcl/unx/kde4/makefile.mk
new file mode 100644
index 000000000000..fd1e9ca59236
--- /dev/null
+++ b/vcl/unx/kde4/makefile.mk
@@ -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.
+#
+#*************************************************************************
+
+PRJ=..$/..
+
+PRJNAME=vcl
+TARGET=kde4plug
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# workaround for makedepend hang
+MKDEPENDSOLVER=
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+# For some of the included external KDE headers, GCC complains about shadowed
+# symbols in instantiated template code only at the end of a compilation unit,
+# so the only solution is to disable that warning here:
+.IF "$(COM)" == "GCC"
+CFLAGSCXX+=-Wno-shadow
+.ENDIF
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)"!="unx"
+
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+
+.ELSE # "$(GUIBASE)"!="unx"
+
+.IF "$(ENABLE_KDE4)" != ""
+
+CFLAGS+=$(KDE4_CFLAGS)
+
+.IF "$(ENABLE_RANDR)" != ""
+CDEFS+=-DUSE_RANDR
+.ENDIF
+
+SLOFILES=\
+ $(SLO)$/main.obj \
+ $(SLO)$/VCLKDEApplication.obj \
+ $(SLO)$/KDEXLib.obj \
+ $(SLO)$/KDESalDisplay.obj \
+ $(SLO)$/KDESalFrame.obj \
+ $(SLO)$/KDESalGraphics.obj \
+ $(SLO)$/KDESalInstance.obj \
+ $(SLO)$/KDEData.obj
+
+
+.ELSE # "$(ENABLE_KDE4)" != ""
+
+dummy:
+ @echo KDE disabled - nothing to build
+.ENDIF
+.ENDIF # "$(GUIBASE)"!="unx"
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
+.INCLUDE : $(PRJ)$/util$/target.pmk
diff --git a/vcl/unx/source/app/i18n_cb.cxx b/vcl/unx/source/app/i18n_cb.cxx
new file mode 100644
index 000000000000..d3a4f2b819ae
--- /dev/null
+++ b/vcl/unx/source/app/i18n_cb.cxx
@@ -0,0 +1,664 @@
+/*************************************************************************
+ *
+ * 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 <string.h>
+#include <sal/alloca.h>
+#include <tools/prex.h>
+#include <X11/Xlocale.h>
+#include <X11/Xlib.h>
+#include <tools/postx.h>
+
+#include <salunx.h>
+#include <XIM.h>
+#include <i18n_cb.hxx>
+#include <i18n_status.hxx>
+#include "i18n_ic.hxx"
+#include "i18n_im.hxx"
+#ifndef _OSL_THREAD_H
+#include <osl/thread.h>
+#endif
+#include <vcl/salframe.hxx>
+
+// -------------------------------------------------------------------------
+//
+// i. preedit start callback
+//
+// -------------------------------------------------------------------------
+
+int
+PreeditStartCallback ( XIC, XPointer client_data, XPointer )
+{
+ preedit_data_t* pPreeditData = (preedit_data_t*)client_data;
+ if ( pPreeditData->eState == ePreeditStatusActivationRequired )
+ {
+ pPreeditData->eState = ePreeditStatusActive;
+ pPreeditData->aText.nCursorPos = 0;
+ pPreeditData->aText.nLength = 0;
+ }
+
+ return -1;
+}
+
+// -------------------------------------------------------------------------
+//
+// ii. preedit done callback
+//
+// -------------------------------------------------------------------------
+
+void
+PreeditDoneCallback ( XIC, XPointer client_data, XPointer )
+{
+ preedit_data_t* pPreeditData = (preedit_data_t*)client_data;
+ if (pPreeditData->eState == ePreeditStatusActive )
+ {
+ if( pPreeditData->pFrame )
+ pPreeditData->pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, (void*)NULL );
+ }
+ pPreeditData->eState = ePreeditStatusStartPending;
+}
+
+// -------------------------------------------------------------------------
+//
+// iii. preedit draw callback
+//
+// -------------------------------------------------------------------------
+
+//
+// Handle deletion of text in a preedit_draw_callback
+// from and howmuch are guaranteed to be nonnegative
+//
+
+void
+Preedit_DeleteText(preedit_text_t *ptext, int from, int howmuch)
+{
+ // If we've been asked to delete no text then just set
+ // nLength correctly and return
+ if (ptext->nLength == 0)
+ {
+ ptext->nLength = from;
+ return;
+ }
+
+ int to = from + howmuch;
+
+ if (to == (int)ptext->nLength)
+ {
+ // delete from the end of the text
+ ptext->nLength = from;
+ }
+ else
+ if (to < (int)ptext->nLength)
+ {
+ // cut out of the middle of the text
+ memmove( (void*)(ptext->pUnicodeBuffer + from),
+ (void*)(ptext->pUnicodeBuffer + to),
+ (ptext->nLength - to) * sizeof(sal_Unicode));
+ memmove( (void*)(ptext->pCharStyle + from),
+ (void*)(ptext->pCharStyle + to),
+ (ptext->nLength - to) * sizeof(XIMFeedback));
+ ptext->nLength -= howmuch;
+ }
+ else
+ // if ( to > pText->nLength )
+ {
+ // XXX this indicates an error, are we out of sync ?
+ fprintf(stderr, "Preedit_DeleteText( from=%i to=%i length=%i )\n",
+ from, to, ptext->nLength );
+ fprintf (stderr, "\t XXX internal error, out of sync XXX\n");
+
+ ptext->nLength = from;
+ }
+
+ // NULL-terminate the string
+ ptext->pUnicodeBuffer[ptext->nLength] = (sal_Unicode)0;
+}
+
+// reallocate the textbuffer with sufficiently large size 2^x
+// nnewlimit is presupposed to be larger than ptext->size
+void
+enlarge_buffer ( preedit_text_t *ptext, int nnewlimit )
+{
+ size_t nnewsize = ptext->nSize;
+
+ while ( nnewsize <= (size_t)nnewlimit )
+ nnewsize *= 2;
+
+ ptext->nSize = nnewsize;
+ ptext->pUnicodeBuffer = (sal_Unicode*)realloc((void*)ptext->pUnicodeBuffer,
+ nnewsize * sizeof(sal_Unicode));
+ ptext->pCharStyle = (XIMFeedback*)realloc((void*)ptext->pCharStyle,
+ nnewsize * sizeof(XIMFeedback));
+}
+
+//
+// Handle insertion of text in a preedit_draw_callback
+// string field of XIMText struct is guaranteed to be != NULL
+//
+
+void
+Preedit_InsertText(preedit_text_t *pText, XIMText *pInsertText, int where,
+ Bool isMultilingual)
+{
+ sal_Unicode *pInsertTextString;
+ int nInsertTextLength = 0;
+ XIMFeedback *pInsertTextCharStyle = pInsertText->feedback;
+
+ nInsertTextLength = pInsertText->length;
+
+ if (isMultilingual)
+ {
+ XIMUnicodeText *pUniText = (XIMUnicodeText*)pInsertText;
+ pInsertTextString = pUniText->string.utf16_char;
+ }
+ else
+ {
+ // can't handle wchar_t strings, so convert to multibyte chars first
+ char *pMBString;
+ size_t nMBLength;
+ if (pInsertText->encoding_is_wchar)
+ {
+ wchar_t *pWCString = pInsertText->string.wide_char;
+ size_t nBytes = wcstombs ( NULL, pWCString, 1024 /* dont care */);
+ pMBString = (char*)alloca( nBytes + 1 );
+ nMBLength = wcstombs ( pMBString, pWCString, nBytes + 1);
+ }
+ else
+ {
+ pMBString = pInsertText->string.multi_byte;
+ nMBLength = strlen(pMBString); // xxx
+ }
+
+ // convert multibyte chars to unicode
+ rtl_TextEncoding nEncoding = osl_getThreadTextEncoding();
+
+ if (nEncoding != RTL_TEXTENCODING_UNICODE)
+ {
+ rtl_TextToUnicodeConverter aConverter =
+ rtl_createTextToUnicodeConverter( nEncoding );
+ rtl_TextToUnicodeContext aContext =
+ rtl_createTextToUnicodeContext(aConverter);
+
+ sal_Size nBufferSize = nInsertTextLength * 2;
+
+ pInsertTextString = (sal_Unicode*)alloca(nBufferSize);
+
+ sal_uInt32 nConversionInfo;
+ sal_Size nConvertedChars;
+
+ rtl_convertTextToUnicode( aConverter, aContext,
+ pMBString, nMBLength,
+ pInsertTextString, nBufferSize,
+ RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_IGNORE
+ | RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE,
+ &nConversionInfo, &nConvertedChars );
+
+ rtl_destroyTextToUnicodeContext(aConverter, aContext);
+ rtl_destroyTextToUnicodeConverter(aConverter);
+
+ }
+ else
+ {
+ pInsertTextString = (sal_Unicode*)pMBString;
+ }
+ }
+
+ // enlarge target text-buffer if necessary
+ if (pText->nSize <= (pText->nLength + nInsertTextLength))
+ enlarge_buffer(pText, pText->nLength + nInsertTextLength);
+
+ // insert text: displace old mem and put new bytes in
+ int from = where;
+ int to = where + nInsertTextLength;
+ int howmany = pText->nLength - where;
+
+ memmove((void*)(pText->pUnicodeBuffer + to),
+ (void*)(pText->pUnicodeBuffer + from),
+ howmany * sizeof(sal_Unicode));
+ memmove((void*)(pText->pCharStyle + to),
+ (void*)(pText->pCharStyle + from),
+ howmany * sizeof(XIMFeedback));
+
+ to = from;
+ howmany = nInsertTextLength;
+
+ memcpy((void*)(pText->pUnicodeBuffer + to), (void*)pInsertTextString,
+ howmany * sizeof(sal_Unicode));
+ memcpy((void*)(pText->pCharStyle + to), (void*)pInsertTextCharStyle,
+ howmany * sizeof(XIMFeedback));
+
+ pText->nLength += howmany;
+
+ // NULL-terminate the string
+ pText->pUnicodeBuffer[pText->nLength] = (sal_Unicode)0;
+}
+
+//
+// Handle the change of attributes in a preedit_draw_callback
+//
+void
+Preedit_UpdateAttributes ( preedit_text_t* ptext, XIMFeedback* feedback,
+ int from, int amount )
+{
+ if ( (from + amount) > (int)ptext->nLength )
+ {
+ // XXX this indicates an error, are we out of sync ?
+ fprintf (stderr, "Preedit_UpdateAttributes( %i + %i > %i )\n",
+ from, amount, ptext->nLength );
+ fprintf (stderr, "\t XXX internal error, out of sync XXX\n");
+
+ return;
+ }
+
+ memcpy ( ptext->pCharStyle + from,
+ feedback, amount * sizeof(XIMFeedback) );
+}
+
+// Convert the XIM feedback values into appropriate VCL
+// SAL_EXTTEXTINPUT_ATTR values
+// returns an allocate list of attributes, which must be freed by caller
+USHORT*
+Preedit_FeedbackToSAL ( XIMFeedback* pfeedback, int nlength, std::vector<USHORT>& rSalAttr )
+{
+ USHORT *psalattr;
+ USHORT nval;
+ USHORT noldval = 0;
+ XIMFeedback nfeedback;
+
+ // only work with reasonable length
+ if (nlength > 0 && nlength > sal::static_int_cast<int>(rSalAttr.size()) )
+ {
+ rSalAttr.reserve( nlength );
+ psalattr = &rSalAttr[0];
+ }
+ else
+ return (USHORT*)NULL;
+
+ for (int npos = 0; npos < nlength; npos++)
+ {
+ nval = 0;
+ nfeedback = pfeedback[npos];
+
+ // means to use the feedback of the previous char
+ if (nfeedback == 0)
+ {
+ nval = noldval;
+ }
+ // convert feedback to attributes
+ else
+ {
+ if (nfeedback & XIMReverse)
+ nval |= SAL_EXTTEXTINPUT_ATTR_HIGHLIGHT;
+ if (nfeedback & XIMUnderline)
+ nval |= SAL_EXTTEXTINPUT_ATTR_UNDERLINE;
+ if (nfeedback & XIMHighlight)
+ nval |= SAL_EXTTEXTINPUT_ATTR_HIGHLIGHT;
+ if (nfeedback & XIMPrimary)
+ nval |= SAL_EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE;
+ if (nfeedback & XIMSecondary)
+ nval |= SAL_EXTTEXTINPUT_ATTR_DASHDOTUNDERLINE;
+ if (nfeedback & XIMTertiary) // same as 2ery
+ nval |= SAL_EXTTEXTINPUT_ATTR_DASHDOTUNDERLINE;
+
+ /*
+ // visibility feedback not supported now
+ if ( (nfeedback & XIMVisibleToForward)
+ || (nfeedback & XIMVisibleToBackward)
+ || (nfeedback & XIMVisibleCenter) )
+ { }
+ */
+ }
+ // copy in list
+ psalattr[npos] = nval;
+ noldval = nval;
+ }
+ // return list of sal attributes
+ return psalattr;
+}
+
+void
+PreeditDrawCallback(XIC ic, XPointer client_data,
+ XIMPreeditDrawCallbackStruct *call_data)
+{
+ preedit_data_t* pPreeditData = (preedit_data_t*)client_data;
+
+ // if there's nothing to change then change nothing
+ if ( ( (call_data->text == NULL) && (call_data->chg_length == 0) )
+ || pPreeditData->pFrame == NULL )
+ return;
+
+ // #88564# Solaris 7 deletes the preedit buffer after commit
+ // since the next call to preeditstart will have the same effect just skip this.
+ // if (pPreeditData->eState == ePreeditStatusStartPending && call_data->text == NULL)
+ // return;
+
+ if ( pPreeditData->eState == ePreeditStatusStartPending )
+ pPreeditData->eState = ePreeditStatusActivationRequired;
+ PreeditStartCallback( ic, client_data, NULL );
+
+ // Edit the internal textbuffer as indicated by the call_data,
+ // chg_first and chg_length are guaranteed to be nonnegative
+
+ // handle text deletion
+ if (call_data->text == NULL)
+ {
+ Preedit_DeleteText(&(pPreeditData->aText),
+ call_data->chg_first, call_data->chg_length );
+ }
+ else
+ {
+ // handle text insertion
+ if ( (call_data->chg_length == 0)
+ && (call_data->text->string.wide_char != NULL))
+ {
+ Preedit_InsertText(&(pPreeditData->aText), call_data->text,
+ call_data->chg_first, pPreeditData->bIsMultilingual);
+ }
+ else
+ // handle text replacement by deletion and insertion of text,
+ // not smart, just good enough
+ if ( (call_data->chg_length != 0)
+ && (call_data->text->string.wide_char != NULL))
+ {
+ Preedit_DeleteText(&(pPreeditData->aText),
+ call_data->chg_first, call_data->chg_length);
+ Preedit_InsertText(&(pPreeditData->aText), call_data->text,
+ call_data->chg_first, pPreeditData->bIsMultilingual);
+ }
+ else
+ // not really a text update, only attributes are concerned
+ if ( (call_data->chg_length != 0)
+ && (call_data->text->string.wide_char == NULL))
+ {
+ Preedit_UpdateAttributes(&(pPreeditData->aText),
+ call_data->text->feedback,
+ call_data->chg_first, call_data->chg_length);
+ }
+ }
+
+ //
+ // build the SalExtTextInputEvent and send it up
+ //
+ pPreeditData->aInputEv.mnTime = 0;
+ pPreeditData->aInputEv.mpTextAttr = Preedit_FeedbackToSAL(
+ pPreeditData->aText.pCharStyle, pPreeditData->aText.nLength, pPreeditData->aInputFlags);
+ pPreeditData->aInputEv.mnCursorPos = call_data->caret;
+ pPreeditData->aInputEv.maText = String (pPreeditData->aText.pUnicodeBuffer,
+ pPreeditData->aText.nLength);
+ pPreeditData->aInputEv.mnCursorFlags = 0; // default: make cursor visible
+ pPreeditData->aInputEv.mnDeltaStart = 0; // call_data->chg_first;
+ pPreeditData->aInputEv.mbOnlyCursor = False;
+
+ if ( pPreeditData->eState == ePreeditStatusActive && pPreeditData->pFrame )
+ pPreeditData->pFrame->CallCallback(SALEVENT_EXTTEXTINPUT, (void*)&pPreeditData->aInputEv);
+ if (pPreeditData->aText.nLength == 0 && pPreeditData->pFrame )
+ pPreeditData->pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, (void*)NULL );
+
+ if (pPreeditData->aText.nLength == 0)
+ pPreeditData->eState = ePreeditStatusStartPending;
+
+ GetPreeditSpotLocation(ic, (XPointer)pPreeditData);
+}
+
+void
+GetPreeditSpotLocation(XIC ic, XPointer client_data)
+{
+ //
+ // Send SalEventExtTextInputPos event to get spotlocation
+ //
+ SalExtTextInputPosEvent mPosEvent;
+ preedit_data_t* pPreeditData = (preedit_data_t*)client_data;
+
+ if( pPreeditData->pFrame )
+ pPreeditData->pFrame->CallCallback(SALEVENT_EXTTEXTINPUTPOS, (void*)&mPosEvent);
+
+ XPoint point;
+ point.x = mPosEvent.mnX + mPosEvent.mnWidth;
+ point.y = mPosEvent.mnY + mPosEvent.mnHeight;
+
+ XVaNestedList preedit_attr;
+ preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &point, NULL);
+ XSetICValues(ic, XNPreeditAttributes, preedit_attr, NULL);
+ XFree(preedit_attr);
+
+ return;
+}
+
+// -------------------------------------------------------------------------
+//
+// iv. preedit caret callback
+//
+// -------------------------------------------------------------------------
+
+#if OSL_DEBUG_LEVEL > 1
+void
+PreeditCaretCallback ( XIC ic, XPointer client_data,
+ XIMPreeditCaretCallbackStruct *call_data )
+#else
+void
+PreeditCaretCallback ( XIC, XPointer,XIMPreeditCaretCallbackStruct* )
+#endif
+{
+ #if OSL_DEBUG_LEVEL > 1
+ // XXX PreeditCaretCallback is pure debug code for now
+ const char *direction = "?";
+ const char *style = "?";
+
+ switch ( call_data->style )
+ {
+ case XIMIsInvisible: style = "Invisible"; break;
+ case XIMIsPrimary: style = "Primary"; break;
+ case XIMIsSecondary: style = "Secondary"; break;
+ }
+ switch ( call_data->direction )
+ {
+ case XIMForwardChar: direction = "Forward char"; break;
+ case XIMBackwardChar: direction = "Backward char"; break;
+ case XIMForwardWord: direction = "Forward word"; break;
+ case XIMBackwardWord: direction = "Backward word"; break;
+ case XIMCaretUp: direction = "Caret up"; break;
+ case XIMCaretDown: direction = "Caret down"; break;
+ case XIMNextLine: direction = "Next line"; break;
+ case XIMPreviousLine: direction = "Previous line"; break;
+ case XIMLineStart: direction = "Line start"; break;
+ case XIMLineEnd: direction = "Line end"; break;
+ case XIMAbsolutePosition: direction = "Absolute"; break;
+ case XIMDontChange: direction = "Dont change"; break;
+ }
+
+ fprintf (stderr, "PreeditCaretCallback( ic=%p, client=%p,\n",
+ ic, client_data );
+ fprintf (stderr, "\t position=%i, direction=\"%s\", style=\"%s\" )\n",
+ call_data->position, direction, style );
+ #endif
+}
+
+// -----------------------------------------------------------------------
+//
+// v. commit string callback: convert an extended text input (iiimp ... )
+// into an ordinary key-event
+//
+// -----------------------------------------------------------------------
+
+Bool
+IsControlCode(sal_Unicode nChar)
+{
+ if ( nChar <= 0x1F // C0 controls
+ /* || (0x80 <= nChar && nChar <= 0x9F) C1 controls */ )
+ return True;
+ else
+ return False;
+}
+
+int
+CommitStringCallback( XIC ic, XPointer client_data, XPointer call_data )
+{
+ preedit_data_t* pPreeditData = (preedit_data_t*)client_data;
+
+ XIMUnicodeText *cbtext = (XIMUnicodeText *)call_data;
+ sal_Unicode *p_unicode_data = (sal_Unicode*)cbtext->string.utf16_char;
+
+ // #86964# filter unexpected pure control events
+ if (cbtext->length == 1 && IsControlCode(p_unicode_data[0]) )
+ {
+ if( pPreeditData->pFrame )
+ {
+ pPreeditData->pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, (void*)NULL );
+ }
+ }
+ else
+ {
+ if( pPreeditData->pFrame )
+ {
+ pPreeditData->aInputEv.mnTime = 0;
+ pPreeditData->aInputEv.mpTextAttr = 0;
+ pPreeditData->aInputEv.mnCursorPos = cbtext->length;
+ pPreeditData->aInputEv.maText = UniString(p_unicode_data, cbtext->length);
+ pPreeditData->aInputEv.mnCursorFlags = 0; // default: make cursor visible
+ pPreeditData->aInputEv.mnDeltaStart = 0;
+ pPreeditData->aInputEv.mbOnlyCursor = False;
+
+ pPreeditData->pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&pPreeditData->aInputEv);
+ pPreeditData->pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, (void*)NULL );
+ }
+ }
+ pPreeditData->eState = ePreeditStatusStartPending;
+
+ GetPreeditSpotLocation(ic, (XPointer)pPreeditData);
+
+ return 0;
+}
+
+// ----------------------------------------------------------------------------------
+//
+// vi. status callbacks: for now these are empty, they are just needed for turbo linux
+//
+// ----------------------------------------------------------------------------------
+
+void
+StatusStartCallback (XIC, XPointer, XPointer)
+{
+ return;
+}
+
+void
+StatusDoneCallback (XIC, XPointer, XPointer)
+{
+ return;
+}
+
+void
+StatusDrawCallback (XIC ic, XPointer client_data, XIMStatusDrawCallbackStruct *call_data)
+{
+ preedit_data_t* pPreeditData = (preedit_data_t*)client_data;
+ if( pPreeditData->bIsMultilingual )
+ {
+ // IIIMP
+ XIMUnicodeText *cbtext = (XIMUnicodeText *)call_data->data.text;
+ ::vcl::I18NStatus::get().setStatusText( String( cbtext->string.utf16_char, call_data->data.text->length ) );
+ XIMUnicodeCharacterSubset* pSubset = NULL;
+ if( ! XGetICValues( ic,
+ XNUnicodeCharacterSubset, & pSubset,
+ NULL )
+ && pSubset )
+ {
+ ::vcl::I18NStatus::get().changeIM( String( ByteString( pSubset->name ), RTL_TEXTENCODING_UTF8 ) );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "got XNUnicodeCharacterSubset\n %d\n %d\n %s\n %d\n", pSubset->index, pSubset->subset_id, pSubset->name, pSubset->is_active );
+#endif
+ }
+ }
+ else if( call_data->type == XIMTextType )
+ {
+ String aText;
+ if( call_data->data.text )
+ {
+ // XIM with text
+ sal_Char* pMBString = NULL;
+ size_t nLength = 0;
+ if( call_data->data.text->encoding_is_wchar )
+ {
+ if( call_data->data.text->string.wide_char )
+ {
+ wchar_t* pWString = call_data->data.text->string.wide_char;
+ size_t nBytes = wcstombs( NULL, pWString, 1024 );
+ pMBString = (sal_Char*)alloca( nBytes+1 );
+ nLength = wcstombs( pMBString, pWString, nBytes+1 );
+ }
+ }
+ else
+ {
+ if( call_data->data.text->string.multi_byte )
+ {
+ pMBString = call_data->data.text->string.multi_byte;
+ nLength = strlen( pMBString );
+ }
+ }
+ if( nLength )
+ aText = String( pMBString, nLength, gsl_getSystemTextEncoding() );
+ }
+ ::vcl::I18NStatus::get().setStatusText( aText );
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "XIMStatusDataType %s not supported\n",
+ call_data->type == XIMBitmapType ? "XIMBitmapType" : ByteString::CreateFromInt32( call_data->type ).GetBuffer() );
+#endif
+ return;
+}
+
+void
+SwitchIMCallback (XIC, XPointer, XPointer call_data)
+{
+ XIMSwitchIMNotifyCallbackStruct* pCallData = (XIMSwitchIMNotifyCallbackStruct*)call_data;
+ ::vcl::I18NStatus::get().changeIM( String( ByteString( pCallData->to->name ), RTL_TEXTENCODING_UTF8 ) );
+}
+
+// ----------------------------------------------------------------------------------
+//
+// vii. destroy callbacks: internally disable all IC/IM calls
+//
+// ----------------------------------------------------------------------------------
+
+void
+IC_IMDestroyCallback (XIM, XPointer client_data, XPointer)
+{
+ SalI18N_InputContext *pContext = (SalI18N_InputContext*)client_data;
+ if (pContext != NULL)
+ pContext->HandleDestroyIM();
+}
+
+void
+IM_IMDestroyCallback (XIM, XPointer client_data, XPointer)
+{
+ SalI18N_InputMethod *pMethod = (SalI18N_InputMethod*)client_data;
+ if (pMethod != NULL)
+ pMethod->HandleDestroyIM();
+}
diff --git a/vcl/unx/source/app/i18n_ic.cxx b/vcl/unx/source/app/i18n_ic.cxx
new file mode 100644
index 000000000000..3064be9367e1
--- /dev/null
+++ b/vcl/unx/source/app/i18n_ic.cxx
@@ -0,0 +1,786 @@
+/*************************************************************************
+ *
+ * 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 <sal/alloca.h>
+
+#include <tools/prex.h>
+#include <X11/Xlocale.h>
+#include <X11/Xlib.h>
+#include <tools/postx.h>
+
+#include <salunx.h>
+
+#include <XIM.h>
+#include <i18n_ic.hxx>
+#include <i18n_im.hxx>
+#include <i18n_status.hxx>
+
+#ifndef _SV_SALFRAME_HXX
+#include <salframe.h>
+#endif
+#include <saldata.hxx>
+#include <saldisp.hxx>
+
+#ifndef _OSL_THREAD_H
+#include <osl/thread.h>
+#endif
+
+using namespace vcl;
+
+static void sendEmptyCommit( SalFrame* pFrame )
+{
+ vcl::DeletionListener aDel( pFrame );
+
+ SalExtTextInputEvent aEmptyEv;
+ aEmptyEv.mnTime = 0;
+ aEmptyEv.mpTextAttr = 0;
+ aEmptyEv.maText = String();
+ aEmptyEv.mnCursorPos = 0;
+ aEmptyEv.mnCursorFlags = 0;
+ aEmptyEv.mnDeltaStart = 0;
+ aEmptyEv.mbOnlyCursor = False;
+ pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&aEmptyEv );
+ if( ! aDel.isDeleted() )
+ pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, NULL );
+}
+
+// ---------------------------------------------------------------------------
+//
+// Constructor / Destructor, the InputContext is bound to the SalFrame, as it
+// needs the shell window as a focus window
+//
+// ----------------------------------------------------------------------------
+
+SalI18N_InputContext::~SalI18N_InputContext()
+{
+ if ( maContext != NULL )
+ XDestroyIC( maContext );
+ if ( mpAttributes != NULL )
+ XFree( mpAttributes );
+ if ( mpStatusAttributes != NULL )
+ XFree( mpStatusAttributes );
+ if ( mpPreeditAttributes != NULL )
+ XFree( mpPreeditAttributes );
+
+ if (maClientData.aText.pUnicodeBuffer != NULL)
+ free(maClientData.aText.pUnicodeBuffer);
+ if (maClientData.aText.pCharStyle != NULL)
+ free(maClientData.aText.pCharStyle);
+}
+
+// ----------------------------------------------------------------------------
+// convenience routine to add items to a XVaNestedList
+// ----------------------------------------------------------------------------
+
+static XVaNestedList
+XVaAddToNestedList( XVaNestedList a_srclist, char* name, XPointer value )
+{
+ XVaNestedList a_dstlist;
+
+ // if ( value == NULL )
+ // return a_srclist;
+
+ if ( a_srclist == NULL )
+ {
+ a_dstlist = XVaCreateNestedList(
+ 0,
+ name, value,
+ NULL );
+ }
+ else
+ {
+ a_dstlist = XVaCreateNestedList(
+ 0,
+ XNVaNestedList, a_srclist,
+ name, value,
+ NULL );
+ }
+
+ return a_dstlist != NULL ? a_dstlist : a_srclist ;
+}
+
+// ----------------------------------------------------------------------------
+// convenience routine to create a fontset
+// ----------------------------------------------------------------------------
+
+static XFontSet
+get_font_set( Display *p_display )
+{
+ static XFontSet p_font_set = NULL;
+
+ if (p_font_set == NULL)
+ {
+ char **pp_missing_list;
+ int n_missing_count;
+ char *p_default_string;
+
+ p_font_set = XCreateFontSet(p_display, "-*",
+ &pp_missing_list, &n_missing_count, &p_default_string);
+ }
+
+ return p_font_set;
+}
+
+// ---------------------------------------------------------------------------
+//
+// Constructor for a InputContext (IC)
+//
+// ----------------------------------------------------------------------------
+
+SalI18N_InputContext::SalI18N_InputContext ( SalFrame *pFrame ) :
+ mbUseable( True ),
+ maContext( (XIC)NULL ),
+ mnSupportedStatusStyle(
+ XIMStatusCallbacks |
+ XIMStatusNothing |
+ XIMStatusNone
+ ),
+ mnSupportedPreeditStyle(
+ XIMPreeditCallbacks |
+ XIMPreeditNothing |
+ XIMPreeditNone
+ ),
+ mnStatusStyle( 0 ),
+ mnPreeditStyle( 0 ),
+ mpAttributes( NULL ),
+ mpStatusAttributes( NULL ),
+ mpPreeditAttributes( NULL )
+{
+#ifdef SOLARIS
+ static const char* pIIIMPEnable = getenv( "SAL_DISABLE_OWN_IM_STATUS" );
+ if( pIIIMPEnable && *pIIIMPEnable )
+ mnSupportedStatusStyle &= ~XIMStatusCallbacks;
+#endif
+
+ maClientData.aText.pUnicodeBuffer = NULL;
+ maClientData.aText.pCharStyle = NULL;
+ maClientData.aInputEv.mnTime = 0;
+ maClientData.aInputEv.mpTextAttr = NULL;
+ maClientData.aInputEv.mnCursorPos = 0;
+ maClientData.aInputEv.mnDeltaStart = 0;
+ maClientData.aInputEv.mnCursorFlags = 0;
+ maClientData.aInputEv.mbOnlyCursor = FALSE;
+
+ SalI18N_InputMethod *pInputMethod;
+ pInputMethod = GetX11SalData()->GetDisplay()->GetInputMethod();
+ mbMultiLingual = pInputMethod->IsMultiLingual();
+
+ mnSupportedPreeditStyle = XIMPreeditCallbacks | XIMPreeditPosition
+ | XIMPreeditNothing | XIMPreeditNone;
+ if (pInputMethod->UseMethod()
+ && SupportInputMethodStyle( pInputMethod->GetSupportedStyles() ) )
+ {
+ const SystemEnvData* pEnv = pFrame->GetSystemData();
+ XLIB_Window aClientWindow = pEnv->aShellWindow;
+ XLIB_Window aFocusWindow = pEnv->aWindow;
+
+ // for status callbacks and commit string callbacks
+#define PREEDIT_BUFSZ 16
+ maClientData.bIsMultilingual = mbMultiLingual;
+ maClientData.eState = ePreeditStatusStartPending;
+ maClientData.pFrame = pFrame;
+ maClientData.aText.pUnicodeBuffer =
+ (sal_Unicode*)malloc(PREEDIT_BUFSZ * sizeof(sal_Unicode));
+ maClientData.aText.pCharStyle =
+ (XIMFeedback*)malloc(PREEDIT_BUFSZ * sizeof(XIMFeedback));;
+ maClientData.aText.nSize = PREEDIT_BUFSZ;
+ maClientData.aText.nCursorPos = 0;
+ maClientData.aText.nLength = 0;
+
+ //
+ // Status attributes
+ //
+
+ switch ( mnStatusStyle )
+ {
+ case XIMStatusCallbacks:
+ {
+ static XIMCallback aStatusStartCallback;
+ static XIMCallback aStatusDoneCallback;
+ static XIMCallback aStatusDrawCallback;
+
+ aStatusStartCallback.callback = (XIMProc)StatusStartCallback;
+ aStatusStartCallback.client_data = (XPointer)&maClientData;
+ aStatusDoneCallback.callback = (XIMProc)StatusDoneCallback;
+ aStatusDoneCallback.client_data = (XPointer)&maClientData;
+ aStatusDrawCallback.callback = (XIMProc)StatusDrawCallback;
+ aStatusDrawCallback.client_data = (XPointer)&maClientData;
+
+ mpStatusAttributes = XVaCreateNestedList (
+ 0,
+ XNStatusStartCallback, &aStatusStartCallback,
+ XNStatusDoneCallback, &aStatusDoneCallback,
+ XNStatusDrawCallback, &aStatusDrawCallback,
+ NULL );
+
+ break;
+ }
+
+ case XIMStatusArea:
+ /* not supported */
+ break;
+
+ case XIMStatusNone:
+ case XIMStatusNothing:
+ default:
+ /* no arguments needed */
+ break;
+ }
+
+ //
+ // set preedit attributes
+ //
+
+ switch ( mnPreeditStyle )
+ {
+ case XIMPreeditCallbacks:
+
+ maPreeditCaretCallback.callback = (XIMProc)PreeditCaretCallback;
+ maPreeditStartCallback.callback = (XIMProc)PreeditStartCallback;
+ maPreeditDoneCallback.callback = (XIMProc)PreeditDoneCallback;
+ maPreeditDrawCallback.callback = (XIMProc)PreeditDrawCallback;
+ maPreeditCaretCallback.client_data = (XPointer)&maClientData;
+ maPreeditStartCallback.client_data = (XPointer)&maClientData;
+ maPreeditDoneCallback.client_data = (XPointer)&maClientData;
+ maPreeditDrawCallback.client_data = (XPointer)&maClientData;
+
+ mpPreeditAttributes = XVaCreateNestedList (
+ 0,
+ XNPreeditStartCallback, &maPreeditStartCallback,
+ XNPreeditDoneCallback, &maPreeditDoneCallback,
+ XNPreeditDrawCallback, &maPreeditDrawCallback,
+ XNPreeditCaretCallback, &maPreeditCaretCallback,
+ NULL );
+
+ break;
+
+ case XIMPreeditArea:
+ /* not supported */
+ break;
+
+ case XIMPreeditPosition:
+ {
+ // spot location
+ SalExtTextInputPosEvent aPosEvent;
+ pFrame->CallCallback(SALEVENT_EXTTEXTINPUTPOS, (void*)&aPosEvent);
+
+ static XPoint aSpot;
+ aSpot.x = aPosEvent.mnX + aPosEvent.mnWidth;
+ aSpot.y = aPosEvent.mnY + aPosEvent.mnHeight;
+
+ // create attributes for preedit position style
+ mpPreeditAttributes = XVaCreateNestedList (
+ 0,
+ XNSpotLocation, &aSpot,
+ NULL );
+
+ // XCreateIC() fails on Redflag Linux 2.0 if there is no
+ // fontset though the data itself is not evaluated nor is
+ // it required according to the X specs.
+ Display* pDisplay = GetX11SalData()->GetDisplay()->GetDisplay();
+ XFontSet pFontSet = get_font_set(pDisplay);
+
+ if (pFontSet != NULL)
+ {
+ mpPreeditAttributes = XVaAddToNestedList( mpPreeditAttributes,
+ const_cast<char*>(XNFontSet), (XPointer)pFontSet);
+ }
+
+ break;
+ }
+
+ case XIMPreeditNone:
+ case XIMPreeditNothing:
+ default:
+ /* no arguments needed */
+ break;
+ }
+
+ // Create the InputContext by giving it exactly the information it
+ // deserves, because inappropriate attributes
+ // let XCreateIC fail on Solaris (eg. for C locale)
+
+ mpAttributes = XVaCreateNestedList(
+ 0,
+ XNFocusWindow, aFocusWindow,
+ XNClientWindow, aClientWindow,
+ XNInputStyle, mnPreeditStyle | mnStatusStyle,
+ NULL );
+
+ if ( mnPreeditStyle != XIMPreeditNone )
+ {
+#if defined LINUX || defined FREEBSD || defined NETBSD
+ if ( mpPreeditAttributes != NULL )
+#endif
+ mpAttributes = XVaAddToNestedList( mpAttributes,
+ const_cast<char*>(XNPreeditAttributes), (XPointer)mpPreeditAttributes );
+ }
+ if ( mnStatusStyle != XIMStatusNone )
+ {
+#if defined LINUX || defined FREEBSD || defined NETBSD
+ if ( mpStatusAttributes != NULL )
+#endif
+ mpAttributes = XVaAddToNestedList( mpAttributes,
+ const_cast<char*>(XNStatusAttributes), (XPointer)mpStatusAttributes );
+ }
+ maContext = XCreateIC( pInputMethod->GetMethod(),
+ XNVaNestedList, mpAttributes,
+ NULL );
+ }
+
+ if ( maContext == NULL )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf(stderr, "input context creation failed\n");
+#endif
+
+ mbUseable = False;
+ mbMultiLingual = False;
+
+ if ( mpAttributes != NULL )
+ XFree( mpAttributes );
+ if ( mpStatusAttributes != NULL )
+ XFree( mpStatusAttributes );
+ if ( mpPreeditAttributes != NULL )
+ XFree( mpPreeditAttributes );
+ if ( maClientData.aText.pUnicodeBuffer != NULL )
+ free ( maClientData.aText.pUnicodeBuffer );
+ if ( maClientData.aText.pCharStyle != NULL )
+ free ( maClientData.aText.pCharStyle );
+
+ mpAttributes = NULL;
+ mpStatusAttributes = NULL;
+ mpPreeditAttributes = NULL;
+ maClientData.aText.pUnicodeBuffer = NULL;
+ maClientData.aText.pCharStyle = NULL;
+ }
+
+ if ( maContext != NULL && mbMultiLingual )
+ {
+ maCommitStringCallback.callback = (XIMProc)::CommitStringCallback;
+ maCommitStringCallback.client_data = (XPointer)&maClientData;
+ maSwitchIMCallback.callback = (XIMProc)::SwitchIMCallback;
+ maSwitchIMCallback.client_data = (XPointer)&maClientData;
+ XSetICValues( maContext,
+ XNCommitStringCallback, &maCommitStringCallback,
+ XNSwitchIMNotifyCallback, &maSwitchIMCallback,
+ NULL );
+ }
+ if ( maContext != NULL)
+ {
+ maDestroyCallback.callback = (XIMProc)IC_IMDestroyCallback;
+ maDestroyCallback.client_data = (XPointer)this;
+ XSetICValues( maContext,
+ XNDestroyCallback, &maDestroyCallback,
+ NULL );
+ }
+
+ if( mbMultiLingual )
+ {
+ // set initial IM status
+ XIMUnicodeCharacterSubset* pSubset = NULL;
+ if( ! XGetICValues( maContext,
+ XNUnicodeCharacterSubset, & pSubset,
+ NULL )
+ && pSubset )
+ {
+ String aCurrent( ByteString( pSubset->name ), RTL_TEXTENCODING_UTF8 );
+ ::vcl::I18NStatus::get().changeIM( aCurrent );
+ ::vcl::I18NStatus::get().setStatusText( aCurrent );
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+//
+// In Solaris 8 the status window does not unmap if the frame unmapps, so
+// unmap it the hard way
+//
+// ---------------------------------------------------------------------------
+
+void
+SalI18N_InputContext::Unmap( SalFrame* pFrame )
+{
+ if ( maContext != NULL )
+ {
+ I18NStatus& rStatus( I18NStatus::get() );
+ if( rStatus.getParent() == pFrame )
+ rStatus.show( false, I18NStatus::contextmap );
+
+ }
+ UnsetICFocus( pFrame );
+ maClientData.pFrame = NULL;
+}
+
+void
+SalI18N_InputContext::Map( SalFrame *pFrame )
+{
+ if( mbUseable )
+ {
+ I18NStatus& rStatus(I18NStatus::get() );
+ rStatus.setParent( pFrame );
+ if( pFrame )
+ {
+ rStatus.show( true, I18NStatus::contextmap );
+ if ( maContext == NULL )
+ {
+ SalI18N_InputMethod *pInputMethod;
+ pInputMethod = GetX11SalData()->GetDisplay()->GetInputMethod();
+
+ maContext = XCreateIC( pInputMethod->GetMethod(),
+ XNVaNestedList, mpAttributes,
+ NULL );
+ if ( maContext != NULL && mbMultiLingual )
+ XSetICValues( maContext,
+ XNCommitStringCallback, &maCommitStringCallback,
+ XNSwitchIMNotifyCallback, &maSwitchIMCallback,
+ NULL );
+ }
+ if( maClientData.pFrame != pFrame )
+ SetICFocus( pFrame );
+ }
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Handle DestroyCallbacks
+// in fact this is a callback called from the XNDestroyCallback
+//
+// --------------------------------------------------------------------------
+
+void
+SalI18N_InputContext::HandleDestroyIM()
+{
+ maContext = 0; // noli me tangere
+ mbUseable = False;
+}
+
+// ---------------------------------------------------------------------------
+//
+// make sure, the input method gets all the X-Events it needs, this is only
+// called once on each frame, it relys on a valid maContext
+//
+// ---------------------------------------------------------------------------
+
+void
+SalI18N_InputContext::ExtendEventMask( XLIB_Window aFocusWindow )
+{
+ unsigned long nIMEventMask;
+ XWindowAttributes aWindowAttributes;
+
+ if ( mbUseable )
+ {
+ Display *pDisplay = XDisplayOfIM( XIMOfIC(maContext) );
+
+ XGetWindowAttributes( pDisplay, aFocusWindow,
+ &aWindowAttributes );
+ XGetICValues ( maContext,
+ XNFilterEvents, &nIMEventMask,
+ NULL);
+ nIMEventMask |= aWindowAttributes.your_event_mask;
+ XSelectInput ( pDisplay, aFocusWindow, nIMEventMask );
+ }
+}
+
+// ---------------------------------------------------------------------------
+//
+// tune the styles provided by the input method with the supported one
+//
+// ---------------------------------------------------------------------------
+
+unsigned int
+SalI18N_InputContext::GetWeightingOfIMStyle( XIMStyle nStyle ) const
+{
+ struct StyleWeightingT {
+ const XIMStyle nStyle;
+ const unsigned int nWeight;
+ };
+
+ StyleWeightingT const *pWeightPtr;
+ const StyleWeightingT pWeight[] = {
+ { XIMPreeditCallbacks, 0x10000000 },
+ { XIMPreeditPosition, 0x02000000 },
+ { XIMPreeditArea, 0x01000000 },
+ { XIMPreeditNothing, 0x00100000 },
+ { XIMPreeditNone, 0x00010000 },
+ { XIMStatusCallbacks, 0x1000 },
+ { XIMStatusArea, 0x0100 },
+ { XIMStatusNothing, 0x0010 },
+ { XIMStatusNone, 0x0001 },
+ { 0, 0x0 }
+ };
+
+ int nWeight = 0;
+ for ( pWeightPtr = pWeight; pWeightPtr->nStyle != 0; pWeightPtr++ )
+ {
+ if ( (pWeightPtr->nStyle & nStyle) != 0 )
+ nWeight += pWeightPtr->nWeight;
+ }
+ return nWeight;
+}
+
+Bool
+SalI18N_InputContext::IsSupportedIMStyle( XIMStyle nStyle ) const
+{
+ if ( (nStyle & mnSupportedPreeditStyle)
+ && (nStyle & mnSupportedStatusStyle) )
+ {
+ return True;
+ }
+ return False;
+}
+
+Bool
+SalI18N_InputContext::SupportInputMethodStyle( XIMStyles *pIMStyles )
+{
+ int nBestScore = 0;
+ int nActualScore = 0;
+
+ mnPreeditStyle = 0;
+ mnStatusStyle = 0;
+
+ if ( pIMStyles != NULL )
+ {
+ // check whether the XIM supports one of the desired styles
+ // only a single preedit and a single status style must occure
+ // in a inpuut method style. Hideki said so, so i trust him
+ for ( int nStyle = 0; nStyle < pIMStyles->count_styles; nStyle++ )
+ {
+ XIMStyle nProvidedStyle = pIMStyles->supported_styles[ nStyle ];
+ if ( IsSupportedIMStyle(nProvidedStyle) )
+ {
+ nActualScore = GetWeightingOfIMStyle( nProvidedStyle );
+ if ( nActualScore >= nBestScore )
+ {
+ nBestScore = nActualScore;
+ mnPreeditStyle = nProvidedStyle & mnSupportedPreeditStyle;
+ mnStatusStyle = nProvidedStyle & mnSupportedStatusStyle;
+ }
+ }
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ char pBuf[ 128 ];
+ fprintf( stderr, "selected inputmethod style = %s\n",
+ GetMethodName(mnPreeditStyle | mnStatusStyle, pBuf, sizeof(pBuf)) );
+#endif
+
+ return (mnPreeditStyle != 0) && (mnStatusStyle != 0) ;
+}
+
+// ---------------------------------------------------------------------------
+//
+// handle extended and normal key input
+//
+// ---------------------------------------------------------------------------
+
+int
+SalI18N_InputContext::CommitStringCallback (sal_Unicode* pText, sal_Size nLength)
+{
+ XIMUnicodeText call_data;
+
+ call_data.string.utf16_char = pText;
+ call_data.length = nLength;
+ call_data.annotations = NULL;
+ call_data.count_annotations = 0;
+ call_data.feedback = NULL;
+
+ return ::CommitStringCallback( maContext,
+ (XPointer)&maClientData, (XPointer)&call_data );
+}
+
+int
+SalI18N_InputContext::CommitKeyEvent(sal_Unicode* pText, sal_Size nLength)
+{
+ if (nLength == 1 && IsControlCode(pText[0]))
+ return 0;
+
+ if( maClientData.pFrame )
+ {
+ SalExtTextInputEvent aTextEvent;
+
+ aTextEvent.mnTime = 0;
+ aTextEvent.mpTextAttr = 0;
+ aTextEvent.mnCursorPos = nLength;
+ aTextEvent.maText = UniString(pText, nLength);
+ aTextEvent.mnCursorFlags = 0;
+ aTextEvent.mnDeltaStart = 0;
+ aTextEvent.mbOnlyCursor = False;
+
+ maClientData.pFrame->CallCallback(SALEVENT_EXTTEXTINPUT, (void*)&aTextEvent);
+ maClientData.pFrame->CallCallback(SALEVENT_ENDEXTTEXTINPUT, (void*)NULL);
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf(stderr, "CommitKeyEvent without frame\n" );
+#endif
+
+ return 0;
+}
+
+int
+SalI18N_InputContext::UpdateSpotLocation()
+{
+ if (maContext == 0 || maClientData.pFrame == NULL)
+ return -1;
+
+ SalExtTextInputPosEvent aPosEvent;
+ maClientData.pFrame->CallCallback(SALEVENT_EXTTEXTINPUTPOS, (void*)&aPosEvent);
+
+ XPoint aSpot;
+ aSpot.x = aPosEvent.mnX + aPosEvent.mnWidth;
+ aSpot.y = aPosEvent.mnY + aPosEvent.mnHeight;
+
+ XVaNestedList preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &aSpot, NULL);
+ XSetICValues(maContext, XNPreeditAttributes, preedit_attr, NULL);
+ XFree(preedit_attr);
+
+ I18NStatus::get().show( true, I18NStatus::contextmap );
+
+ return 0;
+}
+
+// ---------------------------------------------------------------------------
+//
+// set and unset the focus for the Input Context
+// the context may be NULL despite it is useable if the framewindow is
+// in unmapped state
+//
+// ---------------------------------------------------------------------------
+
+void
+SalI18N_InputContext::SetICFocus( SalFrame* pFocusFrame )
+{
+ I18NStatus::get().setParent( pFocusFrame );
+ if ( mbUseable && (maContext != NULL) )
+ {
+ maClientData.pFrame = pFocusFrame;
+
+ const SystemEnvData* pEnv = pFocusFrame->GetSystemData();
+ XLIB_Window aClientWindow = pEnv->aShellWindow;
+ XLIB_Window aFocusWindow = pEnv->aWindow;
+
+ XSetICValues( maContext,
+ XNFocusWindow, aFocusWindow,
+ XNClientWindow, aClientWindow,
+ NULL );
+
+ if( maClientData.aInputEv.mpTextAttr )
+ {
+ sendEmptyCommit(pFocusFrame);
+ // begin preedit again
+ GetX11SalData()->GetDisplay()->SendInternalEvent( pFocusFrame, &maClientData.aInputEv, SALEVENT_EXTTEXTINPUT );
+ }
+
+ XSetICFocus( maContext );
+ }
+}
+
+void
+SalI18N_InputContext::UnsetICFocus( SalFrame* pFrame )
+{
+ I18NStatus& rStatus( I18NStatus::get() );
+ if( rStatus.getParent() == pFrame )
+ rStatus.setParent( NULL );
+
+ if ( mbUseable && (maContext != NULL) )
+ {
+ // cancel an eventual event posted to begin preedit again
+ GetX11SalData()->GetDisplay()->CancelInternalEvent( maClientData.pFrame, &maClientData.aInputEv, SALEVENT_EXTTEXTINPUT );
+ maClientData.pFrame = NULL;
+ XUnsetICFocus( maContext );
+ }
+}
+
+// ---------------------------------------------------------------------------
+//
+// multi byte input method only
+//
+// ---------------------------------------------------------------------------
+
+void
+SalI18N_InputContext::SetPreeditState(Bool aPreeditState)
+{
+ XIMPreeditState preedit_state = XIMPreeditUnKnown;
+ XVaNestedList preedit_attr;
+
+ preedit_attr = XVaCreateNestedList(
+ 0,
+ XNPreeditState, &preedit_state,
+ NULL);
+ if (!XGetICValues(maContext, XNPreeditAttributes, preedit_attr, NULL))
+ {
+ XFree(preedit_attr);
+
+ preedit_state = aPreeditState? XIMPreeditEnable : XIMPreeditDisable;
+ preedit_attr = XVaCreateNestedList(
+ 0,
+ XNPreeditState, preedit_state,
+ NULL);
+ XSetICValues(maContext, XNPreeditAttributes, preedit_attr, NULL);
+ }
+
+ XFree(preedit_attr);
+
+ return;
+}
+
+void
+SalI18N_InputContext::SetLanguage(LanguageType)
+{
+ // not yet implemented
+ return;
+}
+
+void
+SalI18N_InputContext::EndExtTextInput( USHORT /*nFlags*/ )
+{
+ if ( mbUseable && (maContext != NULL) && maClientData.pFrame )
+ {
+ vcl::DeletionListener aDel( maClientData.pFrame );
+ // delete preedit in sal (commit an empty string)
+ sendEmptyCommit( maClientData.pFrame );
+ if( ! aDel.isDeleted() )
+ {
+ // mark previous preedit state again (will e.g. be sent at focus gain)
+ maClientData.aInputEv.mpTextAttr = &maClientData.aInputFlags[0];
+ if( static_cast<X11SalFrame*>(maClientData.pFrame)->hasFocus() )
+ {
+ // begin preedit again
+ GetX11SalData()->GetDisplay()->SendInternalEvent( maClientData.pFrame, &maClientData.aInputEv, SALEVENT_EXTTEXTINPUT );
+ }
+ }
+ }
+}
+
+
diff --git a/vcl/unx/source/app/i18n_im.cxx b/vcl/unx/source/app/i18n_im.cxx
new file mode 100644
index 000000000000..9f1ffee3d1c4
--- /dev/null
+++ b/vcl/unx/source/app/i18n_im.cxx
@@ -0,0 +1,628 @@
+/*************************************************************************
+ *
+ * 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 <string.h>
+#ifdef LINUX
+# ifndef __USE_XOPEN
+# define __USE_XOPEN
+# endif
+#endif
+#include <poll.h>
+#ifdef SOLARIS
+// for SetSystemEnvironment()
+#include <sal/alloca.h>
+#endif
+
+#include <tools/prex.h>
+#include <X11/Xlocale.h>
+#include <X11/Xlib.h>
+#include <XIM.h>
+#include <tools/postx.h>
+
+#include <salunx.h>
+#include <saldisp.hxx>
+#include "i18n_im.hxx"
+#include <i18n_status.hxx>
+
+#include <osl/thread.h>
+
+using namespace vcl;
+#include "i18n_cb.hxx"
+#if defined(SOLARIS) || defined(LINUX)
+extern "C" char * XSetIMValues(XIM im, ...);
+#endif
+
+// ------------------------------------------------------------------------------------
+//
+// kinput2 IME needs special key handling since key release events are filtered in
+// preeditmode and XmbResetIC does not work
+//
+// ------------------------------------------------------------------------------------
+
+Bool
+IMServerKinput2 ()
+{
+ const static char* p_xmodifiers = getenv ("XMODIFIERS");
+ const static Bool b_kinput2 = (p_xmodifiers != NULL)
+ && (strcmp(p_xmodifiers, "@im=kinput2") == 0);
+
+ return b_kinput2;
+}
+
+class XKeyEventOp : XKeyEvent
+{
+ private:
+ void init();
+
+ public:
+ XKeyEventOp();
+ ~XKeyEventOp();
+
+ XKeyEventOp& operator= (const XKeyEvent &rEvent);
+ void erase ();
+ Bool match (const XKeyEvent &rEvent) const;
+};
+
+void
+XKeyEventOp::init()
+{
+ type = 0; /* serial = 0; */
+ send_event = 0; display = 0;
+ window = 0; root = 0;
+ subwindow = 0; /* time = 0; */
+ /* x = 0; y = 0; */
+ /* x_root = 0; y_root = 0; */
+ state = 0; keycode = 0;
+ same_screen = 0;
+}
+
+XKeyEventOp::XKeyEventOp()
+{
+ init();
+}
+
+XKeyEventOp::~XKeyEventOp()
+{
+}
+
+XKeyEventOp&
+XKeyEventOp::operator= (const XKeyEvent &rEvent)
+{
+ type = rEvent.type; /* serial = rEvent.serial; */
+ send_event = rEvent.send_event; display = rEvent.display;
+ window = rEvent.window; root = rEvent.root;
+ subwindow = rEvent.subwindow;/* time = rEvent.time; */
+ /* x = rEvent.x, y = rEvent.y; */
+ /* x_root = rEvent.x_root, y_root = rEvent.y_root; */
+ state = rEvent.state; keycode = rEvent.keycode;
+ same_screen = rEvent.same_screen;
+
+ return *this;
+}
+
+void
+XKeyEventOp::erase ()
+{
+ init();
+}
+
+Bool
+XKeyEventOp::match (const XKeyEvent &rEvent) const
+{
+ return ( (type == XLIB_KeyPress && rEvent.type == KeyRelease)
+ || (type == KeyRelease && rEvent.type == XLIB_KeyPress ))
+ /* && serial == rEvent.serial */
+ && send_event == rEvent.send_event
+ && display == rEvent.display
+ && window == rEvent.window
+ && root == rEvent.root
+ && subwindow == rEvent.subwindow
+ /* && time == rEvent.time
+ && x == rEvent.x
+ && y == rEvent.y
+ && x_root == rEvent.x_root
+ && y_root == rEvent.y_root */
+ && state == rEvent.state
+ && keycode == rEvent.keycode
+ && same_screen == rEvent.same_screen;
+}
+
+// -------------------------------------------------------------------------
+//
+// locale handling
+//
+// -------------------------------------------------------------------------
+
+// Locale handling of the operating system layer
+
+static char*
+SetSystemLocale( const char* p_inlocale )
+{
+ char *p_outlocale;
+
+ if ( (p_outlocale = setlocale(LC_ALL, p_inlocale)) == NULL )
+ {
+ fprintf( stderr, "I18N: Operating system doesn't support locale \"%s\"\n",
+ p_inlocale );
+ }
+
+ return p_outlocale;
+}
+
+#ifdef SOLARIS
+static void
+SetSystemEnvironment( const char* p_locale )
+{
+ const char *lc_all = "LC_ALL=%s";
+ const char *lang = "LANG=%s";
+
+ char *p_buffer;
+
+ if (p_locale != NULL)
+ {
+ p_buffer = (char*)alloca(10 + strlen(p_locale));
+ sprintf(p_buffer, lc_all, p_locale);
+ putenv(strdup(p_buffer));
+ sprintf(p_buffer, lang, p_locale);
+ putenv(strdup(p_buffer));
+ }
+}
+#endif
+
+static Bool
+IsPosixLocale( const char* p_locale )
+{
+ if ( p_locale == NULL )
+ return False;
+ if ( (p_locale[ 0 ] == 'C') && (p_locale[ 1 ] == '\0') )
+ return True;
+ if ( strncmp(p_locale, "POSIX", sizeof("POSIX")) == 0 )
+ return True;
+
+ return False;
+}
+
+// Locale handling of the X Window System layer
+
+static Bool
+IsXWindowCompatibleLocale( const char* p_locale )
+{
+ if ( p_locale == NULL )
+ return False;
+
+ if ( !XSupportsLocale() )
+ {
+ fprintf (stderr, "I18N: X Window System doesn't support locale \"%s\"\n",
+ p_locale );
+ return False;
+ }
+ return True;
+}
+
+// Set the operating system locale prior to trying to open an
+// XIM InputMethod.
+// Handle the cases where the current locale is either not supported by the
+// operating system (LANG=gaga) or by the XWindow system (LANG=aa_ER@saaho)
+// by providing a fallback.
+// Upgrade "C" or "POSIX" to "en_US" locale to allow umlauts and accents
+// see i8988, i9188, i8930, i16318
+// on Solaris the environment needs to be set equivalent to the locale (#i37047#)
+
+Bool
+SalI18N_InputMethod::SetLocale( const char* pLocale )
+{
+ // check whether we want an Input Method engine, if we don't we
+ // do not need to set the locale
+ if ( mbUseable )
+ {
+ char *locale = SetSystemLocale( pLocale );
+ if ( (!IsXWindowCompatibleLocale(locale)) || IsPosixLocale(locale) )
+ {
+ osl_setThreadTextEncoding (RTL_TEXTENCODING_ISO_8859_1);
+ locale = SetSystemLocale( "en_US" );
+ #ifdef SOLARIS
+ SetSystemEnvironment( "en_US" );
+ #endif
+ if (! IsXWindowCompatibleLocale(locale))
+ {
+ locale = SetSystemLocale( "C" );
+ #ifdef SOLARIS
+ SetSystemEnvironment( "C" );
+ #endif
+ if (! IsXWindowCompatibleLocale(locale))
+ mbUseable = False;
+ }
+ }
+
+ // must not fail if mbUseable since XSupportsLocale() asserts success
+ if ( mbUseable && XSetLocaleModifiers("") == NULL )
+ {
+ fprintf (stderr, "I18N: Can't set X modifiers for locale \"%s\"\n",
+ locale);
+ mbUseable = False;
+ }
+ }
+
+ return mbUseable;
+}
+
+Bool
+SalI18N_InputMethod::PosixLocale()
+{
+ if (mbMultiLingual)
+ return False;
+ if (maMethod)
+ return IsPosixLocale (XLocaleOfIM (maMethod));
+ return False;
+}
+
+// ------------------------------------------------------------------------
+//
+// Constructor / Destructor / Initialisation
+//
+// ------------------------------------------------------------------------
+
+SalI18N_InputMethod::SalI18N_InputMethod( ) : mbUseable( bUseInputMethodDefault ),
+ mbMultiLingual( False ),
+ maMethod( (XIM)NULL ),
+ mpStyles( (XIMStyles*)NULL )
+{
+ const char *pUseInputMethod = getenv( "SAL_USEINPUTMETHOD" );
+ if ( pUseInputMethod != NULL )
+ mbUseable = pUseInputMethod[0] != '\0' ;
+}
+
+SalI18N_InputMethod::~SalI18N_InputMethod()
+{
+ ::vcl::I18NStatus::free();
+ if ( mpStyles != NULL )
+ XFree( mpStyles );
+ if ( maMethod != NULL )
+ XCloseIM ( maMethod );
+}
+
+//
+// XXX
+// debug routine: lets have a look at the provided method styles
+//
+
+#if OSL_DEBUG_LEVEL > 1
+
+extern "C" char*
+GetMethodName( XIMStyle nStyle, char *pBuf, int nBufSize)
+{
+ struct StyleName {
+ const XIMStyle nStyle;
+ const char *pName;
+ const int nNameLen;
+ };
+
+ StyleName *pDescPtr;
+ static const StyleName pDescription[] = {
+ { XIMPreeditArea, "PreeditArea ", sizeof("PreeditArea ") },
+ { XIMPreeditCallbacks, "PreeditCallbacks ",sizeof("PreeditCallbacks ")},
+ { XIMPreeditPosition, "PreeditPosition ", sizeof("PreeditPosition ") },
+ { XIMPreeditNothing, "PreeditNothing ", sizeof("PreeditNothing ") },
+ { XIMPreeditNone, "PreeditNone ", sizeof("PreeditNone ") },
+ { XIMStatusArea, "StatusArea ", sizeof("StatusArea ") },
+ { XIMStatusCallbacks, "StatusCallbacks ", sizeof("StatusCallbacks ") },
+ { XIMStatusNothing, "StatusNothing ", sizeof("StatusNothing ") },
+ { XIMStatusNone, "StatusNone ", sizeof("StatusNone ") },
+ { 0, "NULL", 0 }
+ };
+
+ if ( nBufSize > 0 )
+ pBuf[0] = '\0';
+
+ char *pBufPtr = pBuf;
+ for ( pDescPtr = const_cast<StyleName*>(pDescription); pDescPtr->nStyle != 0; pDescPtr++ )
+ {
+ int nSize = pDescPtr->nNameLen - 1;
+ if ( (nStyle & pDescPtr->nStyle) && (nBufSize > nSize) )
+ {
+ strncpy( pBufPtr, pDescPtr->pName, nSize + 1);
+ pBufPtr += nSize;
+ nBufSize -= nSize;
+ }
+ }
+
+ return pBuf;
+}
+
+extern "C" void
+PrintInputStyle( XIMStyles *pStyle )
+{
+ char pBuf[ 128 ];
+ int nBuf = sizeof( pBuf );
+
+ if ( pStyle == NULL )
+ fprintf( stderr, "no input method styles\n");
+ else
+ for ( int nStyle = 0; nStyle < pStyle->count_styles; nStyle++ )
+ {
+ fprintf( stderr, "style #%i = %s\n", nStyle,
+ GetMethodName(pStyle->supported_styles[nStyle], pBuf, nBuf) );
+ }
+}
+
+#endif
+
+//
+// this is the real constructing routine, since locale setting has to be done
+// prior to xopendisplay, the xopenim call has to be delayed
+//
+
+Bool
+SalI18N_InputMethod::CreateMethod ( Display *pDisplay )
+{
+ if ( mbUseable )
+ {
+ const bool bTryMultiLingual =
+ #ifdef LINUX
+ false;
+ #else
+ true;
+ #endif
+ if ( bTryMultiLingual && getenv("USE_XOPENIM") == NULL )
+ {
+ mbMultiLingual = True; // set ml-input flag to create input-method
+ maMethod = XvaOpenIM(pDisplay, NULL, NULL, NULL,
+ XNMultiLingualInput, mbMultiLingual, /* dummy */
+ (void *)0);
+ // get ml-input flag from input-method
+ if ( maMethod == (XIM)NULL )
+ mbMultiLingual = False;
+ else
+ if ( XGetIMValues(maMethod,
+ XNMultiLingualInput, &mbMultiLingual, NULL ) != NULL )
+ mbMultiLingual = False;
+ if( mbMultiLingual )
+ {
+ XIMUnicodeCharacterSubsets* subsets;
+ if( XGetIMValues( maMethod,
+ XNQueryUnicodeCharacterSubset, &subsets, NULL ) == NULL )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "IM reports %d subsets: ", subsets->count_subsets );
+#endif
+ I18NStatus& rStatus( I18NStatus::get() );
+ rStatus.clearChoices();
+ for( int i = 0; i < subsets->count_subsets; i++ )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr,"\"%s\" ", subsets->supported_subsets[i].name );
+#endif
+ rStatus.addChoice( String( subsets->supported_subsets[i].name, RTL_TEXTENCODING_UTF8 ), &subsets->supported_subsets[i] );
+ }
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "\n" );
+#endif
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "query subsets failed\n" );
+#endif
+ }
+ }
+ else
+ {
+ maMethod = XOpenIM(pDisplay, NULL, NULL, NULL);
+ mbMultiLingual = False;
+ }
+
+ if ((maMethod == (XIM)NULL) && (getenv("XMODIFIERS") != NULL))
+ {
+ putenv (strdup("XMODIFIERS"));
+ XSetLocaleModifiers("");
+ maMethod = XOpenIM(pDisplay, NULL, NULL, NULL);
+ mbMultiLingual = False;
+ }
+
+ if ( maMethod != (XIM)NULL )
+ {
+ if ( XGetIMValues(maMethod, XNQueryInputStyle, &mpStyles, NULL)
+ != NULL)
+ mbUseable = False;
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf(stderr, "Creating %s-Lingual InputMethod\n",
+ mbMultiLingual ? "Multi" : "Mono" );
+ PrintInputStyle( mpStyles );
+ #endif
+ }
+ else
+ {
+ mbUseable = False;
+ }
+ }
+
+ #if OSL_DEBUG_LEVEL > 1
+ if ( !mbUseable )
+ fprintf(stderr, "input method creation failed\n");
+ #endif
+
+ maDestroyCallback.callback = (XIMProc)IM_IMDestroyCallback;
+ maDestroyCallback.client_data = (XPointer)this;
+ if (mbUseable && maMethod != NULL)
+ XSetIMValues(maMethod, XNDestroyCallback, &maDestroyCallback, NULL);
+
+ return mbUseable;
+}
+
+//
+// give IM the opportunity to look at the event, and possibly hide it
+//
+
+Bool
+SalI18N_InputMethod::FilterEvent( XEvent *pEvent, XLIB_Window window )
+{
+ if (!mbUseable)
+ return False;
+
+ Bool bFilterEvent = XFilterEvent (pEvent, window);
+
+ if (pEvent->type != XLIB_KeyPress && pEvent->type != KeyRelease)
+ return bFilterEvent;
+
+ /*
+ * fix broken key release handling of some IMs
+ */
+ XKeyEvent* pKeyEvent = &(pEvent->xkey);
+ static XKeyEventOp maLastKeyPress;
+
+ if (bFilterEvent)
+ {
+ if (pKeyEvent->type == KeyRelease)
+ bFilterEvent = !maLastKeyPress.match (*pKeyEvent);
+ maLastKeyPress.erase();
+ }
+ else /* (!bFilterEvent) */
+ {
+ if (pKeyEvent->type == XLIB_KeyPress)
+ maLastKeyPress = *pKeyEvent;
+ else
+ maLastKeyPress.erase();
+ }
+
+ return bFilterEvent;
+}
+
+void
+SalI18N_InputMethod::HandleDestroyIM()
+{
+ mbUseable = False;
+ mbMultiLingual = False;
+ maMethod = NULL;
+}
+
+// ------------------------------------------------------------------------
+//
+// add a connection watch into the SalXLib yieldTable to allow iiimp
+// connection processing: soffice waits in select() not in XNextEvent(), so
+// there may be requests pending on the iiimp internal connection that will
+// not be processed until XNextEvent is called the next time. If we do not
+// have the focus because the atok12 lookup choice aux window has it we stay
+// deaf and dump otherwise.
+//
+// ------------------------------------------------------------------------
+
+int
+InputMethod_HasPendingEvent(int nFileDescriptor, void *pData)
+{
+ if (pData == NULL)
+ return 0;
+
+ struct pollfd aFileDescriptor;
+ #ifdef SOLARIS
+ nfds_t nNumDescriptor = 1;
+ #else
+ unsigned int nNumDescriptor = 1;
+ #endif
+ aFileDescriptor.fd = nFileDescriptor;
+ aFileDescriptor.events = POLLRDNORM;
+ aFileDescriptor.revents = 0;
+
+ int nPoll = poll (&aFileDescriptor, nNumDescriptor, 0 /* timeout */ );
+
+ if (nPoll > 0)
+ {
+ /* at least some conditions in revent are set */
+ if ( (aFileDescriptor.revents & POLLHUP)
+ || (aFileDescriptor.revents & POLLERR)
+ || (aFileDescriptor.revents & POLLNVAL))
+ return 0; /* oops error condition set */
+
+ if (aFileDescriptor.revents & POLLRDNORM)
+ return 1; /* success */
+ }
+
+ /* nPoll == 0 means timeout, nPoll < 0 means error */
+ return 0;
+}
+
+int
+InputMethod_IsEventQueued(int nFileDescriptor, void *pData)
+{
+ return InputMethod_HasPendingEvent (nFileDescriptor, pData);
+}
+
+int
+InputMethod_HandleNextEvent(int nFileDescriptor, void *pData)
+{
+ if (pData != NULL)
+ XProcessInternalConnection((Display*)pData, nFileDescriptor);
+
+ return 0;
+}
+
+extern "C" void
+InputMethod_ConnectionWatchProc (Display *pDisplay, XPointer pClientData,
+ int nFileDescriptor, Bool bOpening, XPointer*)
+{
+ SalXLib *pConnectionHandler = (SalXLib*)pClientData;
+
+ if (pConnectionHandler == NULL)
+ return;
+
+ if (bOpening)
+ {
+ pConnectionHandler->Insert (nFileDescriptor, pDisplay,
+ InputMethod_HasPendingEvent,
+ InputMethod_IsEventQueued,
+ InputMethod_HandleNextEvent);
+ }
+ else
+ {
+ pConnectionHandler->Remove (nFileDescriptor);
+ }
+}
+
+Bool
+SalI18N_InputMethod::AddConnectionWatch(Display *pDisplay, void *pConnectionHandler)
+{
+ // sanity check
+ if (pDisplay == NULL || pConnectionHandler == NULL)
+ return False;
+
+ // if we are not ml all the extended text input comes on the stock X queue,
+ // so there is no need to monitor additional file descriptors.
+#ifndef SOLARIS
+ if (!mbMultiLingual || !mbUseable)
+ return False;
+#endif
+
+ // pConnectionHandler must be really a pointer to a SalXLib
+ Status nStatus = XAddConnectionWatch (pDisplay, InputMethod_ConnectionWatchProc,
+ (XPointer)pConnectionHandler);
+ return (Bool)nStatus;
+}
+
+
+
diff --git a/vcl/unx/source/app/i18n_keysym.cxx b/vcl/unx/source/app/i18n_keysym.cxx
new file mode 100644
index 000000000000..812e54aae937
--- /dev/null
+++ b/vcl/unx/source/app/i18n_keysym.cxx
@@ -0,0 +1,365 @@
+/*************************************************************************
+ *
+ * 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 <X11/X.h>
+#include <sal/types.h>
+
+#include <i18n_keysym.hxx>
+
+// convert keysyms to unicode
+// for all keysyms with byte1 and byte2 equal zero, and of course only for
+// keysyms that have a unicode counterpart
+
+typedef const sal_Unicode unicode_t;
+typedef struct {
+ const int first; const int last;
+ unicode_t *map;
+} keymap_t;
+
+// Latin-1 Byte 3 = 0x00
+unicode_t keymap00_map[] = {
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
+ 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
+ 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
+ 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
+ 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
+ 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
+ 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
+ 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
+ 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
+ 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
+ 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
+ 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff };
+const keymap_t keymap00 = { 32, 255, keymap00_map };
+
+// Latin-2 Byte 3 = 0x01
+unicode_t keymap01_map[] = {
+ 0x0104, 0x02d8, 0x0141, 0x0000, 0x013d, 0x015a, 0x0000, 0x0000,
+ 0x0160, 0x015e, 0x0164, 0x0179, 0x0000, 0x017d, 0x017b, 0x0000,
+ 0x0105, 0x02db, 0x0142, 0x0000, 0x013e, 0x015b, 0x02c7, 0x0000,
+ 0x0161, 0x015f, 0x0165, 0x017a, 0x02dd, 0x017e, 0x017c, 0x0154,
+ 0x0000, 0x0000, 0x0102, 0x0000, 0x0139, 0x0106, 0x0000, 0x010c,
+ 0x0000, 0x0118, 0x0000, 0x011a, 0x0000, 0x0000, 0x010e, 0x0110,
+ 0x0143, 0x0147, 0x0000, 0x0000, 0x0150, 0x0000, 0x0000, 0x0158,
+ 0x016e, 0x0000, 0x0170, 0x0000, 0x0000, 0x0162, 0x0000, 0x0155,
+ 0x0000, 0x0000, 0x0103, 0x0000, 0x013a, 0x0107, 0x0000, 0x010d,
+ 0x0000, 0x0119, 0x0000, 0x011b, 0x0000, 0x0000, 0x010f, 0x0111,
+ 0x0144, 0x0148, 0x0000, 0x0000, 0x0151, 0x0000, 0x0000, 0x0159,
+ 0x016f, 0x0000, 0x0171, 0x0000, 0x0000, 0x0163, 0x02d9 };
+const keymap_t keymap01 = { 161, 255, keymap01_map };
+
+// Latin-3 Byte 3 = 0x02
+unicode_t keymap02_map[] = {
+ 0x0126, 0x0000, 0x0000, 0x0000, 0x0000, 0x0124, 0x0000, 0x0000,
+ 0x0130, 0x0000, 0x011e, 0x0134, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0127, 0x0000, 0x0000, 0x0000, 0x0000, 0x0125, 0x0000, 0x0000,
+ 0x0131, 0x0000, 0x011f, 0x0135, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x010a, 0x0108, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0120, 0x0000, 0x0000, 0x011c,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x016c, 0x015c, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x010b, 0x0109, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0121, 0x0000, 0x0000, 0x011d,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x016d, 0x015d };
+const keymap_t keymap02 = { 161, 254, keymap02_map };
+
+// Latin-4 Byte 3 = 0x03
+unicode_t keymap03_map[] = {
+ 0x0138, 0x0156, 0x0000, 0x0128, 0x013b, 0x0000, 0x0000, 0x0000,
+ 0x0112, 0x0122, 0x0166, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0157, 0x0000, 0x0129, 0x013c, 0x0000, 0x0000, 0x0000,
+ 0x0113, 0x0123, 0x0167, 0x014a, 0x0000, 0x014b, 0x0100, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x012e, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0116, 0x0000, 0x0000, 0x012a, 0x0000, 0x0145,
+ 0x014c, 0x0136, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0172,
+ 0x0000, 0x0000, 0x0000, 0x0168, 0x016a, 0x0000, 0x0101, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x012f, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0117, 0x0000, 0x0000, 0x012b, 0x0000, 0x0146,
+ 0x014d, 0x0137, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0173,
+ 0x0000, 0x0000, 0x0000, 0x0169, 0x016b };
+const keymap_t keymap03 = { 162, 254, keymap03_map };
+
+// Kana Byte 3 = 0x04
+unicode_t keymap04_map[] = {
+ 0x203e, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x3002, 0x300c, 0x300d, 0x3001, 0x30fb,
+ 0x30f2, 0x30a1, 0x30a3, 0x30a5, 0x30a7, 0x30a9, 0x30e3, 0x30e5,
+ 0x30e7, 0x30c3, 0x30fc, 0x30a2, 0x30a4, 0x30a6, 0x30a8, 0x30aa,
+ 0x30ab, 0x30ad, 0x30af, 0x30b1, 0x30b3, 0x30b5, 0x30b7, 0x30b9,
+ 0x30bb, 0x30bd, 0x30bf, 0x30c1, 0x30c4, 0x30c6, 0x30c8, 0x30ca,
+ 0x30cb, 0x30cc, 0x30cd, 0x30ce, 0x30cf, 0x30d2, 0x30d5, 0x30d8,
+ 0x30db, 0x30de, 0x30df, 0x30e0, 0x30e1, 0x30e2, 0x30e4, 0x30e6,
+ 0x30e8, 0x30e9, 0x30ea, 0x30eb, 0x30ec, 0x30ed, 0x30ef, 0x30f3,
+ 0x309b, 0x309c };
+const keymap_t keymap04 = { 126, 223, keymap04_map };
+
+// Arabic Byte 3 = 0x05
+unicode_t keymap05_map[] = {
+ 0x060c, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x061b,
+ 0x0000, 0x0000, 0x0000, 0x061f, 0x0000, 0x0621, 0x0622, 0x0623,
+ 0x0624, 0x0625, 0x0626, 0x0627, 0x0628, 0x0629, 0x062a, 0x062b,
+ 0x062c, 0x062d, 0x062e, 0x062f, 0x0630, 0x0631, 0x0632, 0x0633,
+ 0x0634, 0x0635, 0x0636, 0x0637, 0x0638, 0x0639, 0x063a, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0640, 0x0641, 0x0642, 0x0643,
+ 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064a, 0x064b,
+ 0x064c, 0x064d, 0x064e, 0x064f, 0x0650, 0x0651, 0x0652 };
+const keymap_t keymap05 = { 172, 242, keymap05_map };
+
+// Cyrillic Byte 3 = 0x06
+unicode_t keymap06_map[] = {
+ 0x0452, 0x0453, 0x0451, 0x0454, 0x0455, 0x0456, 0x0457, 0x0458,
+ 0x0459, 0x045a, 0x045b, 0x045c, 0x0000, 0x045e, 0x045f, 0x2116,
+ 0x0402, 0x0403, 0x0401, 0x0404, 0x0405, 0x0406, 0x0407, 0x0408,
+ 0x0409, 0x040a, 0x040b, 0x040c, 0x0000, 0x040e, 0x040f, 0x044e,
+ 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, 0x0445,
+ 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f,
+ 0x044f, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, 0x044c,
+ 0x044b, 0x0437, 0x0448, 0x044d, 0x0449, 0x0447, 0x044a, 0x042e,
+ 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425,
+ 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f,
+ 0x042f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, 0x042c,
+ 0x042b, 0x0417, 0x0428, 0x042d, 0x0429, 0x0427, 0x042a };
+const keymap_t keymap06 = { 161, 255, keymap06_map };
+
+// Greek Byte 3 = 0x07
+unicode_t keymap07_map[] = {
+ 0x0386, 0x0388, 0x0389, 0x038a, 0x03aa, 0x0000, 0x038c, 0x038e,
+ 0x03ab, 0x0000, 0x038f, 0x0000, 0x0000, 0x0385, 0x2015, 0x0000,
+ 0x03ac, 0x03ad, 0x03ae, 0x03af, 0x03ca, 0x0390, 0x03cc, 0x03cd,
+ 0x03cb, 0x03b0, 0x03ce, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398,
+ 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, 0x03a0,
+ 0x03a1, 0x03a3, 0x0000, 0x03a4, 0x03a5, 0x03a6, 0x03a7, 0x03a8,
+ 0x03a9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, 0x03b8,
+ 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, 0x03c0,
+ 0x03c1, 0x03c3, 0x03c2, 0x03c4, 0x03c5, 0x03c6, 0x03c7, 0x03c8,
+ 0x03c9 };
+const keymap_t keymap07 = { 161, 249, keymap07_map };
+
+// Technical Byte 3 = 0x08
+unicode_t keymap08_map[] = {
+ 0x23b7, 0x250c, 0x2500, 0x2320, 0x2321, 0x2502, 0x23a1, 0x23a3,
+ 0x23a4, 0x23a6, 0x239b, 0x239d, 0x239e, 0x23a0, 0x23a8, 0x23ac,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x2264, 0x2260, 0x2265, 0x222b, 0x2234,
+ 0x221d, 0x221e, 0x0000, 0x0000, 0x2207, 0x0000, 0x0000, 0x223c,
+ 0x2243, 0x0000, 0x0000, 0x0000, 0x21d4, 0x21d2, 0x2261, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x221a, 0x0000, 0x0000,
+ 0x0000, 0x2282, 0x2283, 0x2229, 0x222a, 0x2227, 0x2228, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2202, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0192, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x2190, 0x2191, 0x2192, 0x2193 };
+const keymap_t keymap08 = { 161, 254, keymap08_map };
+
+// Special Byte 3 = 0x09
+unicode_t keymap09_map[] = {
+ 0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x0000, 0x0000,
+ 0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba,
+ 0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c,
+ 0x2502 };
+const keymap_t keymap09 = { 224, 248, keymap09_map };
+
+// Publishing Byte 3 = 0x0a = 10
+unicode_t keymap10_map[] = {
+ 0x2003, 0x2002, 0x2004, 0x2005, 0x2007, 0x2008, 0x2009, 0x200a,
+ 0x2014, 0x2013, 0x0000, 0x0000, 0x0000, 0x2026, 0x2025, 0x2153,
+ 0x2154, 0x2155, 0x2156, 0x2157, 0x2158, 0x2159, 0x215a, 0x2105,
+ 0x0000, 0x0000, 0x2012, 0x2329, 0x0000, 0x232a, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x215b, 0x215c, 0x215d, 0x215e, 0x0000, 0x0000,
+ 0x2122, 0x2613, 0x0000, 0x25c1, 0x25b7, 0x25cb, 0x25af, 0x2018,
+ 0x2019, 0x201c, 0x201d, 0x211e, 0x0000, 0x2032, 0x2033, 0x0000,
+ 0x271d, 0x0000, 0x25ac, 0x25c0, 0x25b6, 0x25cf, 0x25ae, 0x25e6,
+ 0x25ab, 0x25ad, 0x25b3, 0x25bd, 0x2606, 0x2022, 0x25aa, 0x25b2,
+ 0x25bc, 0x261c, 0x261e, 0x2663, 0x2666, 0x2665, 0x0000, 0x2720,
+ 0x2020, 0x2021, 0x2713, 0x2717, 0x266f, 0x266d, 0x2642, 0x2640,
+ 0x260e, 0x2315, 0x2117, 0x2038, 0x201a, 0x201e };
+const keymap_t keymap10 = { 161, 254, keymap10_map };
+
+// APL Byte 3 = 0x0b = 11
+unicode_t keymap11_map[] = {
+ 0x003c, 0x0000, 0x0000, 0x003e, 0x0000, 0x2228, 0x2227, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00af, 0x0000, 0x22a5,
+ 0x2229, 0x230a, 0x0000, 0x005f, 0x0000, 0x0000, 0x0000, 0x2218,
+ 0x0000, 0x2395, 0x0000, 0x22a4, 0x25cb, 0x0000, 0x0000, 0x0000,
+ 0x2308, 0x0000, 0x0000, 0x222a, 0x0000, 0x2283, 0x0000, 0x2282,
+ 0x0000, 0x22a2, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x22a3 };
+const keymap_t keymap11 = { 163, 252, keymap11_map };
+
+// Hebrew Byte 3 = 0x0c = 12
+unicode_t keymap12_map[] = {
+ 0x2017, 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6,
+ 0x05d7, 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de,
+ 0x05df, 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6,
+ 0x05e7, 0x05e8, 0x05e9, 0x05ea };
+const keymap_t keymap12 = { 223, 250, keymap12_map };
+
+// Thai Byte 3 = 0x0d = 13
+unicode_t keymap13_map[] = {
+ 0x0e01, 0x0e02, 0x0e03, 0x0e04, 0x0e05, 0x0e06, 0x0e07, 0x0e08,
+ 0x0e09, 0x0e0a, 0x0e0b, 0x0e0c, 0x0e0d, 0x0e0e, 0x0e0f, 0x0e10,
+ 0x0e11, 0x0e12, 0x0e13, 0x0e14, 0x0e15, 0x0e16, 0x0e17, 0x0e18,
+ 0x0e19, 0x0e1a, 0x0e1b, 0x0e1c, 0x0e1d, 0x0e1e, 0x0e1f, 0x0e20,
+ 0x0e21, 0x0e22, 0x0e23, 0x0e24, 0x0e25, 0x0e26, 0x0e27, 0x0e28,
+ 0x0e29, 0x0e2a, 0x0e2b, 0x0e2c, 0x0e2d, 0x0e2e, 0x0e2f, 0x0e30,
+ 0x0e31, 0x0e32, 0x0e33, 0x0e34, 0x0e35, 0x0e36, 0x0e37, 0x0e38,
+ 0x0e39, 0x0e3a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0e3f, 0x0e40,
+ 0x0e41, 0x0e42, 0x0e43, 0x0e44, 0x0e45, 0x0e46, 0x0e47, 0x0e48,
+ 0x0e49, 0x0e4a, 0x0e4b, 0x0e4c, 0x0e4d, 0x0000, 0x0000, 0x0e50,
+ 0x0e51, 0x0e52, 0x0e53, 0x0e54, 0x0e55, 0x0e56, 0x0e57, 0x0e58,
+ 0x0e59 };
+const keymap_t keymap13 = { 161, 249, keymap13_map };
+
+// Korean Byte 3 = 0x0e = 14
+unicode_t keymap14_map[] = {
+ 0x3131, 0x3132, 0x3133, 0x3134, 0x3135, 0x3136, 0x3137, 0x3138,
+ 0x3139, 0x313a, 0x313b, 0x313c, 0x313d, 0x313e, 0x313f, 0x3140,
+ 0x3141, 0x3142, 0x3143, 0x3144, 0x3145, 0x3146, 0x3147, 0x3148,
+ 0x3149, 0x314a, 0x314b, 0x314c, 0x314d, 0x314e, 0x314f, 0x3150,
+ 0x3151, 0x3152, 0x3153, 0x3154, 0x3155, 0x3156, 0x3157, 0x3158,
+ 0x3159, 0x315a, 0x315b, 0x315c, 0x315d, 0x315e, 0x315f, 0x3160,
+ 0x3161, 0x3162, 0x3163, 0x11a8, 0x11a9, 0x11aa, 0x11ab, 0x11ac,
+ 0x11ad, 0x11ae, 0x11af, 0x11b0, 0x11b1, 0x11b2, 0x11b3, 0x11b4,
+ 0x11b5, 0x11b6, 0x11b7, 0x11b8, 0x11b9, 0x11ba, 0x11bb, 0x11bc,
+ 0x11bd, 0x11be, 0x11bf, 0x11c0, 0x11c1, 0x11c2, 0x316d, 0x3171,
+ 0x3178, 0x317f, 0x3181, 0x3184, 0x3186, 0x318d, 0x318e, 0x11eb,
+ 0x11f0, 0x11f9, 0x0000, 0x0000, 0x0000, 0x0000, 0x20a9 };
+const keymap_t keymap14 = { 161, 255, keymap14_map };
+
+// missing:
+// Latin-8 Byte 3 = 0x12 = 18
+
+// Latin-9 Byte 3 = 0x13 = 19
+unicode_t keymap19_map[] = {
+ 0x0152, 0x0153, 0x0178 };
+const keymap_t keymap19 = { 188, 190, keymap19_map };
+
+// missing:
+// Armenian Byte 3 = 0x14 = 20
+// Georgian Byte 3 = 0x15 = 21
+// Azeri Byte 3 = 0x16 = 22
+// Vietnamese Byte 3 = 0x1e = 30
+
+// Currency Byte 3 = 0x20 = 32
+unicode_t keymap32_map[] = {
+ 0x20a0, 0x20a1, 0x20a2, 0x20a3, 0x20a4, 0x20a5, 0x20a6, 0x20a7,
+ 0x20a8, 0x0000, 0x20aa, 0x20ab, 0x20ac };
+const keymap_t keymap32 = { 160, 172, keymap32_map };
+
+// Keyboard (Keypad mappings) Byte 3 = 0xff = 255
+unicode_t keymap255_map[] = {
+ 0x0020, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x0000, 0x0000, 0x0000, 0x003d };
+const keymap_t keymap255 = { 128, 189, keymap255_map };
+
+#define INITIAL_KEYMAPS 33
+const keymap_t* p_keymap[INITIAL_KEYMAPS] = {
+ &keymap00, &keymap01, &keymap02, &keymap03, /* 00 -- 03 */
+ &keymap04, &keymap05, &keymap06, &keymap07, /* 04 -- 07 */
+ &keymap08, &keymap09, &keymap10, &keymap11, /* 08 -- 11 */
+ &keymap12, &keymap13, &keymap14, (keymap_t*)NULL, /* 12 -- 15 */
+ (keymap_t*)NULL, (keymap_t*)NULL, (keymap_t*)NULL, &keymap19, /* 16 -- 19 */
+ (keymap_t*)NULL, (keymap_t*)NULL, (keymap_t*)NULL, (keymap_t*)NULL, /* 20 -- 23 */
+ (keymap_t*)NULL, (keymap_t*)NULL, (keymap_t*)NULL, (keymap_t*)NULL, /* 24 -- 27 */
+ (keymap_t*)NULL, (keymap_t*)NULL, (keymap_t*)NULL, (keymap_t*)NULL, /* 28 -- 31 */
+ &keymap32 /* 32 */
+};
+
+sal_Unicode
+KeysymToUnicode (KeySym nKeySym)
+{
+ // keysym is already unicode
+ if ((nKeySym & 0xff000000) == 0x01000000)
+ {
+ // strip off group indicator and iso10646 plane
+ // FIXME can't handle chars from surrogate area.
+ if (! (nKeySym & 0x00ff0000) )
+ return (sal_Unicode)(nKeySym & 0x0000ffff);
+ }
+ // legacy keysyms, switch to appropriate codeset
+ else
+ {
+ unsigned char n_byte1 = (nKeySym & 0xff000000) >> 24;
+ unsigned char n_byte2 = (nKeySym & 0x00ff0000) >> 16;
+ unsigned char n_byte3 = (nKeySym & 0x0000ff00) >> 8;
+ unsigned char n_byte4 = (nKeySym & 0x000000ff);
+
+ if (n_byte1 != 0)
+ return 0;
+ if (n_byte2 != 0)
+ return 0;
+
+ keymap_t const* p_map = NULL;
+ if (n_byte3 < INITIAL_KEYMAPS)
+ p_map = p_keymap[n_byte3];
+ else
+ if (n_byte3 == 255)
+ p_map = &keymap255;
+
+ if ((p_map != NULL) && (n_byte4 >= p_map->first) && (n_byte4 <= p_map->last) )
+ return p_map->map[n_byte4 - p_map->first];
+ }
+
+ return 0;
+}
diff --git a/vcl/unx/source/app/i18n_status.cxx b/vcl/unx/source/app/i18n_status.cxx
new file mode 100644
index 000000000000..3a6ae26a2b0e
--- /dev/null
+++ b/vcl/unx/source/app/i18n_status.cxx
@@ -0,0 +1,733 @@
+/*************************************************************************
+ *
+ * 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"
+
+#if OSL_DEBUG_LEVEL > 1
+#include <stdio.h>
+#endif
+#include <sal/alloca.h>
+
+#include <tools/prex.h>
+#include <X11/Xlib.h>
+#include <XIM.h>
+#include <tools/postx.h>
+
+#include <salunx.h>
+
+#include <i18n_status.hxx>
+#include <i18n_ic.hxx>
+
+#include <vcl/wrkwin.hxx>
+#include <vcl/fixed.hxx>
+#include <vcl/menubtn.hxx>
+#include <vcl/menu.hxx>
+#include <vcl/svdata.hxx>
+#include <vcl/svapp.hxx>
+#include <saldisp.hxx>
+#include <salframe.h>
+#include <saldata.hxx>
+#include <vcl/sysdata.hxx>
+
+using namespace vcl;
+using namespace rtl;
+
+namespace vcl {
+
+class StatusWindow : public WorkWindow
+{
+protected:
+ StatusWindow( WinBits nWinBits );
+public:
+ virtual ~StatusWindow();
+
+ virtual void setPosition( SalFrame* );
+ virtual void setText( const String & ) = 0;
+ virtual String getText() const = 0;
+ virtual void show( bool bShow, I18NStatus::ShowReason eReason ) = 0;
+ virtual void toggle( bool bOn ) = 0;
+};
+
+}
+
+StatusWindow::StatusWindow( WinBits nWinBits ) :
+ WorkWindow( NULL, nWinBits )
+{
+}
+
+StatusWindow::~StatusWindow() {}
+
+void StatusWindow::setPosition( SalFrame* )
+{
+}
+
+// --------------------------------------------------------------------------
+
+namespace vcl {
+
+class XIMStatusWindow : public StatusWindow
+{
+ FixedText m_aStatusText;
+ SalFrame* m_pLastParent;
+ Size m_aWindowSize;
+ bool m_bAnchoredAtRight;
+ // true if the right edge (instead of the left edge) should stay at a
+ // fixed position when re-sizing the window
+
+ // for delayed showing
+ bool m_bDelayedShow;
+ I18NStatus::ShowReason m_eDelayedReason;
+ ULONG m_nDelayedEvent;
+ // for toggling
+ bool m_bOn;
+
+ Point updatePosition();
+ void layout();
+ bool checkLastParent() const;
+
+ DECL_LINK( DelayedShowHdl, void* );
+public:
+ XIMStatusWindow( bool bOn );
+ virtual ~XIMStatusWindow();
+
+ virtual void setPosition( SalFrame* );
+ virtual void setText( const String & );
+ virtual String getText() const;
+ virtual void show( bool bShow, I18NStatus::ShowReason eReason );
+ virtual void toggle( bool bOn );
+
+ // overload WorkWindow::DataChanged
+ virtual void DataChanged( const DataChangedEvent& rEvt );
+};
+
+}
+
+XIMStatusWindow::XIMStatusWindow( bool bOn ) :
+ StatusWindow( WB_BORDER | WB_SYSTEMFLOATWIN | WB_TOOLTIPWIN ),
+ m_aStatusText( this, 0 ),
+ m_pLastParent( NULL ),
+ m_bAnchoredAtRight( false ),
+ m_bDelayedShow( false ),
+ m_eDelayedReason( I18NStatus::contextmap ),
+ m_nDelayedEvent( 0 ),
+ m_bOn( bOn )
+{
+ layout();
+}
+
+XIMStatusWindow::~XIMStatusWindow()
+{
+ if( m_nDelayedEvent )
+ Application::RemoveUserEvent( m_nDelayedEvent );
+}
+
+void XIMStatusWindow::toggle( bool bOn )
+{
+ m_bOn = bOn;
+ show( bOn, I18NStatus::contextmap );
+}
+
+void XIMStatusWindow::layout()
+{
+ m_aWindowSize.Width() = m_aStatusText.GetTextWidth( m_aStatusText.GetText() )+8;
+ Font aFont( m_aStatusText.GetFont() );
+ m_aWindowSize.Height() = aFont.GetHeight()+10;
+ m_aWindowSize = LogicToPixel( m_aWindowSize );
+
+ Size aControlSize( m_aWindowSize );
+ aControlSize.Width() -= 4;
+ aControlSize.Height() -= 4;
+
+ m_aStatusText.SetPosSizePixel( Point( 1, 1 ), aControlSize );
+ m_aStatusText.SetFont( aFont );
+ m_aStatusText.Show( TRUE );
+
+ if (m_bAnchoredAtRight && IsVisible())
+ {
+ SalFrame* pFrame = (SalFrame*)GetSystemData()->pSalFrame;
+ long nDelta = pFrame->maGeometry.nWidth - m_aWindowSize.Width();
+ pFrame->SetPosSize( pFrame->maGeometry.nX + nDelta,
+ pFrame->maGeometry.nY,
+ m_aWindowSize.Width(),
+ m_aWindowSize.Height(),
+ SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y | SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT );
+ }
+ else
+ SetOutputSizePixel( m_aWindowSize );
+}
+
+bool XIMStatusWindow::checkLastParent() const
+{
+ if( m_pLastParent )
+ {
+ const std::list< SalFrame* >& rFrames = GetX11SalData()->GetDisplay()->getFrames();
+ for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it )
+ {
+ if( *it == m_pLastParent )
+ return true;
+ }
+ }
+ return false;
+}
+
+void XIMStatusWindow::DataChanged( const DataChangedEvent& )
+{
+ m_aStatusText.SetSettings( GetSettings() );
+ layout();
+}
+
+Point XIMStatusWindow::updatePosition()
+{
+ Point aRet;
+ if( checkLastParent() )
+ {
+ const SystemEnvData* pParentEnvData = m_pLastParent->GetSystemData();
+
+ SalExtTextInputPosEvent aPosEvent;
+ m_pLastParent->CallCallback( SALEVENT_EXTTEXTINPUTPOS, (void*)&aPosEvent );
+ int x, y;
+ XLIB_Window aChild;
+ XTranslateCoordinates( (Display*)pParentEnvData->pDisplay,
+ (XLIB_Window)pParentEnvData->aShellWindow,
+ GetX11SalData()->GetDisplay()->GetRootWindow( GetX11SalData()->GetDisplay()->GetDefaultScreenNumber() ),
+ 0, 0,
+ &x, &y,
+ &aChild );
+
+ // TODO: Currently, place the status window to the (physical) left of
+ // the cursor iff in vertical mode (assuming that the columns in
+ // vertical mode are always written from right to left, this causes the
+ // status window to keep out of the text already written). This
+ // heuristic would break if there is ever a vertical mode in which the
+ // columns are written from left to right. Also, more elaborate
+ // positioning for (both horizontal and vertical) left-to-right and
+ // right-to-left text would be possible.
+ bool bLeft = aPosEvent.mbVertical;
+ // true if status window is to the left of the cursor
+
+ int const nGap = 4; // between cursor and status window
+ if (aPosEvent.mbVertical)
+ {
+ aRet.X() = x + aPosEvent.mnX + (bLeft
+ ? -m_aWindowSize.Width() - nGap
+ : aPosEvent.mnHeight + nGap);
+ aRet.Y() = y + aPosEvent.mnY;
+ }
+ else
+ {
+ aRet.X() = x + aPosEvent.mnX + (bLeft ? -m_aWindowSize.Width() : 0);
+ aRet.Y() = y + aPosEvent.mnY+aPosEvent.mnHeight + nGap;
+ }
+
+ m_bAnchoredAtRight = bLeft;
+ }
+ return aRet;
+}
+
+void XIMStatusWindow::setPosition( SalFrame* pParent )
+{
+ if( pParent )
+ {
+ if( pParent != m_pLastParent )
+ {
+ setText( String() );
+ m_pLastParent = pParent;
+ Show( FALSE, SHOW_NOACTIVATE );
+ }
+ if( IsVisible() )
+ {
+ const SystemEnvData* pEnvData = GetSystemData();
+ SalFrame* pStatusFrame = (SalFrame*)pEnvData->pSalFrame;
+ Point aPoint = updatePosition();
+ pStatusFrame->SetPosSize( aPoint.X(), aPoint.Y(), m_aWindowSize.Width(), m_aWindowSize.Height(), SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y | SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT );
+ }
+ }
+}
+
+IMPL_LINK( XIMStatusWindow, DelayedShowHdl, void*, EMPTYARG )
+{
+ m_nDelayedEvent = 0;
+ const SystemEnvData* pData = GetSystemData();
+ SalFrame* pStatusFrame = (SalFrame*)pData->pSalFrame;
+ if( m_bDelayedShow )
+ {
+ Size aControlSize( m_aWindowSize.Width()-4, m_aWindowSize.Height()-4 );
+ m_aStatusText.SetPosSizePixel( Point( 1, 1 ), aControlSize );
+ Point aPoint = updatePosition();
+ pStatusFrame->SetPosSize( aPoint.X(), aPoint.Y(), m_aWindowSize.Width(), m_aWindowSize.Height(), SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y | SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT );
+ }
+ Show( m_bDelayedShow && m_bOn, SHOW_NOACTIVATE );
+ if( m_bDelayedShow )
+ {
+ XRaiseWindow( (Display*)pData->pDisplay,
+ (XLIB_Window)pData->aShellWindow );
+ }
+ return 0;
+}
+
+void XIMStatusWindow::show( bool bShow, I18NStatus::ShowReason eReason )
+{
+ if( bShow && ! m_aStatusText.GetText().Len() )
+ bShow = false;
+
+ m_bDelayedShow = bShow;
+ m_eDelayedReason = eReason;
+ if( ! m_nDelayedEvent )
+ m_nDelayedEvent = Application::PostUserEvent( LINK( this, XIMStatusWindow, DelayedShowHdl ) );
+}
+
+void XIMStatusWindow::setText( const String& rText )
+{
+ m_aStatusText.SetText( rText );
+ m_aWindowSize.Width() = m_aStatusText.GetTextWidth( rText )+8;
+}
+
+String XIMStatusWindow::getText() const
+{
+ return m_aStatusText.GetText();
+}
+
+// --------------------------------------------------------------------------
+
+namespace vcl {
+
+class IIIMPStatusWindow : public StatusWindow
+{
+ MenuButton m_aStatusBtn;
+ PopupMenu m_aMenu;
+ SalFrame* m_pResetFocus;
+ bool m_bShow;
+ bool m_bOn;
+
+ DECL_LINK( SelectHdl, MenuButton* );
+
+ void show();
+
+public:
+ IIIMPStatusWindow( SalFrame* pParent, bool bOn ); // for initial position
+ virtual ~IIIMPStatusWindow();
+
+ virtual void setText( const String & );
+ virtual String getText() const;
+ virtual void show( bool bShow, I18NStatus::ShowReason eReason );
+ virtual void toggle( bool bOn );
+ void layout();
+
+ // overload Window focus handler
+ virtual void GetFocus();
+ // overload WorkWindow::DataChanged
+ virtual void DataChanged( const DataChangedEvent& rEvt );
+};
+
+}
+
+IIIMPStatusWindow::IIIMPStatusWindow( SalFrame* pParent, bool bOn ) :
+ StatusWindow( WB_MOVEABLE ),
+ m_aStatusBtn( this, WB_BORDER ),
+ m_pResetFocus( pParent ),
+ m_bShow( true ),
+ m_bOn( bOn )
+{
+ SetText( String( RTL_CONSTASCII_USTRINGPARAM( "IME Status" ) ) );
+
+ layout();
+
+ m_aStatusBtn.SetSelectHdl( LINK( this, IIIMPStatusWindow, SelectHdl ) );
+ m_aStatusBtn.SetPopupMenu( &m_aMenu );
+ m_aStatusBtn.Show( TRUE );
+
+ const ::std::vector< I18NStatus::ChoiceData >& rChoices( I18NStatus::get().getChoices() );
+ int i = 1;
+ for( ::std::vector< I18NStatus::ChoiceData >::const_iterator it = rChoices.begin(); it != rChoices.end(); ++it, i++ )
+ m_aMenu.InsertItem( i, it->aString );
+
+ if( pParent )
+ {
+ const SystemEnvData* pEnvData = GetSystemData();
+
+ const SalFrameGeometry& rGeom( pParent->GetUnmirroredGeometry() );
+ int nDistance = rGeom.nTopDecoration;
+ if( nDistance < 20 )
+ nDistance = 20;
+ XMoveWindow( (Display*)pEnvData->pDisplay,
+ (XLIB_Window)pEnvData->aShellWindow,
+ rGeom.nX,
+ rGeom.nY + rGeom.nHeight + nDistance
+ );
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "Warning: could not reposition status window since no frame\n" );
+#endif
+ EnableAlwaysOnTop( TRUE );
+}
+
+IIIMPStatusWindow::~IIIMPStatusWindow()
+{
+}
+
+void IIIMPStatusWindow::layout()
+{
+ Font aFont( m_aStatusBtn.GetFont() );
+ Size aSize( 15*aFont.GetHeight(), aFont.GetHeight()+14 );
+ aSize = m_aStatusBtn.LogicToPixel( aSize );
+
+ m_aStatusBtn.SetPosSizePixel( Point( 0, 0 ), aSize );
+ SetOutputSizePixel( aSize );
+ if( IsVisible() )
+ Invalidate();
+}
+
+void IIIMPStatusWindow::DataChanged( const DataChangedEvent& )
+{
+ m_aStatusBtn.SetSettings( GetSettings() );
+ layout();
+}
+
+void IIIMPStatusWindow::setText( const String& rText )
+{
+ m_aStatusBtn.SetText( rText );
+}
+
+String IIIMPStatusWindow::getText() const
+{
+ return m_aStatusBtn.GetText();
+}
+
+void IIIMPStatusWindow::show( bool bShow, I18NStatus::ShowReason eReason )
+{
+ // hide IIIMPStatusWindow only in presentations
+ if( ! bShow
+ && eReason != I18NStatus::presentation
+ )
+ return;
+
+ m_bShow = bShow;
+ show();
+}
+
+void IIIMPStatusWindow::toggle( bool bOn )
+{
+ if (bOn != m_bOn)
+ {
+ m_bOn = bOn;
+ show();
+ }
+}
+
+void IIIMPStatusWindow::show()
+{
+ if (m_bOn && m_bShow && !IsVisible())
+ m_pResetFocus = I18NStatus::get().getParent();
+ Show(m_bOn && m_bShow);
+}
+
+void IIIMPStatusWindow::GetFocus()
+{
+ /*
+ * this is here just to put the focus back to the application
+ * window at startup on clickToFocus WMs
+ */
+ WorkWindow::GetFocus();
+ if( m_pResetFocus )
+ {
+ /*
+ * look if reset focus still exists
+ * since reset focus really is an internal hack there should
+ * not be a method to be called in SalFrame destructor
+ */
+ const std::list< SalFrame* >& rFrames = GetX11SalData()->GetDisplay()->getFrames();
+ std::list< SalFrame* >::const_iterator it;
+ for( it = rFrames.begin(); it != rFrames.end() && *it != m_pResetFocus; ++it )
+ ;
+ if( it != rFrames.end() )
+ {
+ const SystemEnvData* pParentEnvData = m_pResetFocus->GetSystemData();
+ SalXLib* pXLib = GetX11SalData()->GetDisplay()->GetXLib();
+ pXLib->PushXErrorLevel( true );
+ XSetInputFocus( (Display*)pParentEnvData->pDisplay,
+ (XLIB_Window)pParentEnvData->aShellWindow,
+ RevertToNone,
+ CurrentTime
+ );
+ XSync( (Display*)pParentEnvData->pDisplay, False );
+ pXLib->PopXErrorLevel();
+ }
+ m_pResetFocus = NULL;
+ }
+}
+
+// --------------------------------------------------------------------------
+
+IMPL_LINK( IIIMPStatusWindow, SelectHdl, MenuButton*, pBtn )
+{
+ if( pBtn == & m_aStatusBtn )
+ {
+ const ::std::vector< I18NStatus::ChoiceData >& rChoices( I18NStatus::get().getChoices() );
+ unsigned int nIndex = m_aStatusBtn.GetCurItemId()-1;
+ if( nIndex < rChoices.size() )
+ {
+ XSetICValues( static_cast<X11SalFrame*>(I18NStatus::get().getParent())->getInputContext()->GetContext(),
+ XNUnicodeCharacterSubset,
+ rChoices[nIndex].pData,
+ NULL);
+ // FIXME: get rid of X11SalFrame
+ X11SalFrame* pParent = static_cast<X11SalFrame*>(I18NStatus::get().getParent());
+ if( pParent && pParent->isMapped() )
+ {
+ const SystemEnvData* pEnv = pParent->GetSystemData();
+ SalXLib* pXLib = GetX11SalData()->GetDisplay()->GetXLib();
+ pXLib->PushXErrorLevel( true );
+ XSetInputFocus( (Display*)pEnv->pDisplay,
+ (XLIB_Window)pEnv->aShellWindow,
+ RevertToNone,
+ CurrentTime
+ );
+ XSync( (Display*)pEnv->pDisplay, False );
+ pXLib->PopXErrorLevel();
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * I18NStatus
+ */
+
+I18NStatus* I18NStatus::pInstance = NULL;
+
+I18NStatus& I18NStatus::get()
+{
+ if( ! pInstance )
+ pInstance = new I18NStatus();
+ return *pInstance;
+}
+
+// --------------------------------------------------------------------------
+
+bool I18NStatus::exists()
+{
+ return pInstance != NULL;
+}
+
+// --------------------------------------------------------------------------
+
+void I18NStatus::free()
+{
+ if( pInstance )
+ delete pInstance, pInstance = NULL;
+}
+
+// --------------------------------------------------------------------------
+
+I18NStatus::I18NStatus() :
+ m_pParent( NULL ),
+ m_pStatusWindow( NULL )
+{
+}
+
+// --------------------------------------------------------------------------
+
+I18NStatus::~I18NStatus()
+{
+ if( m_pStatusWindow )
+ delete m_pStatusWindow, m_pStatusWindow = NULL;
+ if( pInstance == this )
+ pInstance = NULL;
+}
+
+// --------------------------------------------------------------------------
+
+void I18NStatus::setParent( SalFrame* pParent )
+{
+ m_pParent = pParent;
+ if( ! m_pStatusWindow )
+ {
+ bool bIIIMPmode = m_aChoices.begin() != m_aChoices.end();
+ if( bIIIMPmode )
+ m_pStatusWindow = new IIIMPStatusWindow( pParent,
+ getStatusWindowMode() );
+ else
+ m_pStatusWindow = new XIMStatusWindow( getStatusWindowMode() );
+ setStatusText( m_aCurrentIM );
+ }
+ m_pStatusWindow->setPosition( m_pParent );
+}
+
+// --------------------------------------------------------------------------
+
+void I18NStatus::show( bool bShow, ShowReason eReason )
+{
+ if( m_pStatusWindow )
+ {
+ m_pStatusWindow->setPosition( m_pParent );
+ m_pStatusWindow->show( bShow, eReason );
+ }
+}
+
+// --------------------------------------------------------------------------
+
+void I18NStatus::setStatusText( const String& rText )
+{
+ if( m_pStatusWindow )
+ {
+ /*
+ * #93614# convert fullwidth ASCII forms to ascii
+ */
+ int nChars = rText.Len()+1;
+ sal_Unicode* pBuffer = (sal_Unicode*)alloca( nChars*sizeof( sal_Unicode ) );
+ const sal_Unicode* pCopy = rText.GetBuffer();
+ for( int i = 0; i < nChars; i++ )
+ {
+ if( pCopy[i] >=0xff00 && pCopy[i] <= 0xff5f )
+ pBuffer[i] = (pCopy[i] & 0xff) + 0x20;
+ else
+ pBuffer[i] = pCopy[i];
+ }
+ String aText( pBuffer );
+ m_pStatusWindow->setText( aText );
+ m_pStatusWindow->setPosition( m_pParent );
+
+ bool bVisible = true;
+ if( m_pParent )
+ {
+ long w, h;
+ m_pParent->GetClientSize( w, h );
+ if( w == 0 || h == 0 )
+ {
+ bVisible = false;
+ }
+ }
+
+ m_pStatusWindow->show( bVisible, contextmap );
+ }
+}
+
+// --------------------------------------------------------------------------
+
+void I18NStatus::changeIM( const String& rIM )
+{
+ m_aCurrentIM = rIM;
+}
+
+// --------------------------------------------------------------------------
+
+String I18NStatus::getStatusText() const
+{
+ return m_pStatusWindow ? m_pStatusWindow->getText() : String();
+}
+
+// --------------------------------------------------------------------------
+
+void I18NStatus::clearChoices()
+{
+ m_aChoices.clear();
+}
+
+// --------------------------------------------------------------------------
+
+void I18NStatus::addChoice( const String& rChoice, void* pData )
+{
+ ChoiceData aData;
+ aData.pData = pData;
+ aData.aString = rChoice;
+ m_aChoices.push_back( aData );
+}
+
+// --------------------------------------------------------------------------
+
+void I18NStatus::toTop() const
+{
+ if( m_pStatusWindow )
+ {
+ const SystemEnvData* pData = m_pStatusWindow->GetSystemData();
+ XRaiseWindow( (Display*)pData->pDisplay,
+ (XLIB_Window)pData->aShellWindow );
+ }
+}
+
+// --------------------------------------------------------------------------
+
+SalFrame* I18NStatus::getStatusFrame() const
+{
+ SalFrame* pRet = NULL;
+ if( m_pStatusWindow )
+ {
+ const SystemEnvData* pData = m_pStatusWindow->GetSystemData();
+ pRet = (SalFrame*)pData->pSalFrame;
+ }
+ return pRet;
+}
+
+bool I18NStatus::canToggleStatusWindow() const
+{
+ return true;
+}
+
+void I18NStatus::toggleStatusWindow()
+{
+ if (m_pStatusWindow != 0)
+ m_pStatusWindow->toggle(getStatusWindowMode());
+}
+
+bool I18NStatus::getStatusWindowMode()
+{
+ switch (ImplGetSVData()->maAppData.meShowImeStatusWindow)
+ {
+ default: // ImplSVAppData::ImeStatusWindowMode_UNKNOWN
+ return Application::GetShowImeStatusWindowDefault();
+ case ImplSVAppData::ImeStatusWindowMode_HIDE:
+ return false;
+ case ImplSVAppData::ImeStatusWindowMode_SHOW:
+ return true;
+ }
+}
+
+/*
+ * X11ImeStatus
+ */
+X11ImeStatus::~X11ImeStatus()
+{
+ vcl::I18NStatus::free();
+}
+
+bool X11ImeStatus::canToggle()
+{
+ return vcl::I18NStatus::get().canToggleStatusWindow();
+}
+
+void X11ImeStatus::toggle()
+{
+ vcl::I18NStatus::get().toggleStatusWindow();
+}
+
+SalI18NImeStatus* X11SalInstance::CreateI18NImeStatus()
+{
+ return new X11ImeStatus();
+}
diff --git a/vcl/unx/source/app/i18n_wrp.cxx b/vcl/unx/source/app/i18n_wrp.cxx
new file mode 100644
index 000000000000..eb48962a24d0
--- /dev/null
+++ b/vcl/unx/source/app/i18n_wrp.cxx
@@ -0,0 +1,259 @@
+/*************************************************************************
+ *
+ * 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"
+
+struct XIMArg
+{
+ char *name;
+ char *value;
+};
+
+#if defined(SOLARIS) && !defined(__GNUC__)
+#include <varargs.h>
+#else
+#include <stdarg.h>
+#endif
+#include <sal/alloca.h>
+
+#include <string.h>
+#include <dlfcn.h>
+#include <X11/Xlib.h>
+#include <X11/Xlibint.h>
+#include "XIM.h"
+
+#define XIIIMP_LIB "xiiimp.so.2"
+
+#ifdef SOLARIS
+#define XIIIMP_PATH "/usr/openwin/lib/locale/common/" XIIIMP_LIB
+#else /* Linux */
+#define XIIIMP_PATH "/usr/lib/im/" XIIIMP_LIB
+#endif
+
+extern "C" {
+typedef XIM (*OpenFunction)(Display*, XrmDatabase, char*, char*, XIMArg*);
+}
+
+/* global variables */
+static void *g_dlmodule = 0;
+static OpenFunction g_open_im = (OpenFunction)NULL;
+
+/* utility function to transform vararg list into an array of XIMArg */
+
+int
+XvaCountArgs( XIMArg *pInArgs )
+{
+ int nArgs = 0;
+ char *pName, *pValue;
+
+ while ( (pName = pInArgs->name) != NULL )
+ {
+ pValue = pInArgs->value;
+
+ if ( strcmp(pName, XNVaNestedList) == 0 )
+ {
+ nArgs += XvaCountArgs( (XIMArg*)pValue );
+ }
+ else
+ {
+ nArgs += 1;
+ }
+ pInArgs++;
+ }
+
+ return nArgs;
+}
+
+int
+XvaCountArgs( va_list pInArgs )
+{
+ int nArgs = 0;
+ char *pName, *pValue;
+
+ while ( (pName = va_arg(pInArgs, char*)) != NULL)
+ {
+ pValue = va_arg(pInArgs, char*);
+
+ if ( strcmp(pName, XNVaNestedList) == 0 )
+ {
+ nArgs += XvaCountArgs( (XIMArg*)pValue );
+ }
+ else
+ {
+ nArgs += 1;
+ }
+ }
+
+ return nArgs;
+}
+
+XIMArg*
+XvaGetArgs( XIMArg *pInArgs, XIMArg *pOutArgs )
+{
+ char *pName, *pValue;
+
+ while ( (pName = pInArgs->name) != NULL )
+ {
+ pValue = pInArgs->value;
+
+ if ( strcmp(pName, XNVaNestedList) == 0 )
+ {
+ pOutArgs = XvaGetArgs( (XIMArg*)pValue, pOutArgs );
+ }
+ else
+ {
+ pOutArgs->name = pName;
+ pOutArgs->value = pValue;
+ pOutArgs++;
+ }
+ pInArgs++;
+ }
+
+ return pOutArgs;
+}
+
+void
+XvaGetArgs( va_list pInArgs, XIMArg *pOutArgs )
+{
+ char *pName, *pValue;
+
+ while ((pName = va_arg(pInArgs, char*)) != NULL)
+ {
+ pValue = va_arg(pInArgs, char*);
+
+ if ( strcmp(pName, XNVaNestedList) == 0 )
+ {
+ pOutArgs = XvaGetArgs( (XIMArg*)pValue, pOutArgs );
+ }
+ else
+ {
+ pOutArgs->name = pName;
+ pOutArgs->value = pValue;
+ pOutArgs++;
+ }
+ }
+
+ pOutArgs->name = NULL;
+ pOutArgs->value = NULL;
+}
+
+
+/* Puplic functions */
+
+#ifdef __cplusplus
+extern "C"
+#endif
+XIM
+XvaOpenIM(Display *display, XrmDatabase rdb,
+ char *res_name, char *res_class, ...)
+{
+ XIM xim = (XIM)0;
+ va_list variable;
+ int total_count = 0;
+
+ /*
+ * so count the stuff dangling here
+ */
+
+#if defined(SOLARIS) && !defined(__GNUC__)
+ va_start(variable);
+#else
+ va_start(variable, res_class);
+#endif
+ total_count = XvaCountArgs(variable);
+ va_end(variable);
+
+ if (total_count > 0)
+ {
+ /* call a new open IM method */
+
+ XIMArg* args = (XIMArg*)alloca( (total_count + 1) * sizeof(XIMArg) );
+
+ /*
+ * now package it up so we can set it along
+ */
+#if defined(SOLARIS) && !defined(__GNUC__)
+ va_start(variable);
+#else
+ va_start(variable, res_class);
+#endif
+ XvaGetArgs( variable, args );
+ va_end(variable);
+
+ if (!g_dlmodule)
+ {
+ g_dlmodule = dlopen(XIIIMP_LIB, RTLD_LAZY);
+ if(!g_dlmodule)
+ {
+ g_dlmodule = dlopen(XIIIMP_PATH, RTLD_LAZY);
+ if (!g_dlmodule)
+ goto legacy_XIM;
+ }
+ g_open_im = (OpenFunction)(long)dlsym(g_dlmodule, "__XOpenIM");
+ if (!g_open_im)
+ goto legacy_XIM;
+
+ xim = (*g_open_im)(display, (XrmDatabase)rdb,
+ (char*)res_name, (char *)res_class, (XIMArg*)args);
+ }
+ else
+ {
+ goto legacy_XIM;
+ }
+ }
+
+// in #if to prevent warning "warning: label 'legacy_XIM' defined but not used"
+ legacy_XIM:
+
+ if (!xim)
+ xim = XOpenIM(display, rdb, res_name, res_class);
+
+ return xim;
+}
+
+/*
+ * Close the connection to the input manager, and free the XIM structure
+ */
+
+Status XvaCloseIM(XIM)
+{
+ Status s = False;
+
+ if (!g_dlmodule)
+ {
+ /* assuming one XvaOpenIM call */
+ dlclose(g_dlmodule);
+ g_dlmodule = (void*)0;
+ g_open_im = (OpenFunction)NULL;
+ s = True;
+ }
+ return (s);
+}
+
+
+
diff --git a/vcl/unx/source/app/i18n_xkb.cxx b/vcl/unx/source/app/i18n_xkb.cxx
new file mode 100644
index 000000000000..e9a787eda667
--- /dev/null
+++ b/vcl/unx/source/app/i18n_xkb.cxx
@@ -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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+
+#include <stdio.h>
+
+#include "saldisp.hxx"
+#include "saldata.hxx"
+#include "i18n_xkb.hxx"
+
+SalI18N_KeyboardExtension::SalI18N_KeyboardExtension( Display*
+#if __XKeyboardExtension__
+pDisplay
+#endif
+)
+ : mbUseExtension( (sal_Bool)__XKeyboardExtension__ ),
+ mnDefaultGroup( 0 )
+{
+ #if __XKeyboardExtension__
+
+ mpDisplay = pDisplay;
+
+ // allow user to set the default keyboard group idx or to disable the usage
+ // of x keyboard extension at all:
+ // setenv SAL_XKEYBOARDGROUP disables keyboard extension
+ // setenv SAL_XKEYBOARDGROUP 2 sets the keyboard group index to 2
+ // keyboard group index must be in [1,4], may be specified in hex or decimal
+ static char *pUseKeyboardExtension = getenv( "SAL_XKEYBOARDGROUP" );
+ if ( pUseKeyboardExtension != NULL )
+ {
+ mbUseExtension = pUseKeyboardExtension[0] != '\0' ;
+ if ( mbUseExtension )
+ mnDefaultGroup = strtol( pUseKeyboardExtension, NULL, 0 );
+ if ( mnDefaultGroup > XkbMaxKbdGroup )
+ mnDefaultGroup = 0;
+ }
+
+ // query XServer support for XKB Extension,
+ // do not call XQueryExtension() / XInitExtension() due to possible version
+ // clashes !
+ if ( mbUseExtension )
+ {
+ int nMajorExtOpcode;
+ int nExtMajorVersion = XkbMajorVersion;
+ int nExtMinorVersion = XkbMinorVersion;
+
+ mbUseExtension = (sal_Bool)XkbQueryExtension( mpDisplay,
+ &nMajorExtOpcode, (int*)&mnEventBase, (int*)&mnErrorBase,
+ &nExtMajorVersion, &nExtMinorVersion );
+ }
+
+ // query notification for changes of the keyboard group
+ if ( mbUseExtension )
+ {
+ #define XkbGroupMask ( XkbGroupStateMask | XkbGroupBaseMask \
+ | XkbGroupLatchMask | XkbGroupLockMask )
+
+ mbUseExtension = XkbSelectEventDetails( mpDisplay,
+ XkbUseCoreKbd, XkbStateNotify, XkbGroupMask, XkbGroupMask );
+ }
+
+ // query initial keyboard group
+ if ( mbUseExtension )
+ {
+ XkbStateRec aStateRecord;
+ XkbGetState( mpDisplay, XkbUseCoreKbd, &aStateRecord );
+ mnGroup = aStateRecord.group;
+ }
+
+ #endif // __XKeyboardExtension__
+}
+
+void
+SalI18N_KeyboardExtension::Dispatch( XEvent*
+#if __XKeyboardExtension__
+pEvent
+#endif
+)
+{
+ #if __XKeyboardExtension__
+
+ // must the event be handled?
+ if ( !mbUseExtension
+ || (pEvent->type != mnEventBase) )
+ return;
+
+ // only handle state notify events for now, and only interested
+ // in group details
+ sal_uInt32 nXKBType = ((XkbAnyEvent*)pEvent)->xkb_type;
+ switch ( nXKBType )
+ {
+ case XkbStateNotify:
+
+ mnGroup = ((XkbStateNotifyEvent*)pEvent)->group;
+ break;
+
+ default:
+
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf(stderr, "Got unrequested XkbAnyEvent %#x/%i\n",
+ static_cast<unsigned int>(nXKBType), static_cast<int>(nXKBType) );
+ #endif
+ break;
+ }
+ #endif // __XKeyboardExtension__
+}
+
+#if __XKeyboardExtension__
+sal_uInt32
+SalI18N_KeyboardExtension::LookupKeysymInGroup( sal_uInt32 nKeyCode,
+ sal_uInt32 nShiftState,
+ sal_uInt32 nGroup ) const
+#else
+sal_uInt32
+SalI18N_KeyboardExtension::LookupKeysymInGroup( sal_uInt32,sal_uInt32,sal_uInt32 ) const
+#endif
+{
+ #if __XKeyboardExtension__
+
+ if ( !mbUseExtension )
+ return NoSymbol;
+
+ nShiftState &= ShiftMask;
+
+ KeySym nKeySymbol;
+ nKeySymbol = XkbKeycodeToKeysym( mpDisplay, nKeyCode, nGroup, nShiftState );
+ return nKeySymbol;
+
+ #else
+
+ return NoSymbol;
+
+ #endif // __XKeyboardExtension__
+}
+
+
diff --git a/vcl/unx/source/app/keysymnames.cxx b/vcl/unx/source/app/keysymnames.cxx
new file mode 100644
index 000000000000..c9515f016433
--- /dev/null
+++ b/vcl/unx/source/app/keysymnames.cxx
@@ -0,0 +1,688 @@
+/*************************************************************************
+ *
+ * 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 SOLARIS
+#include <tools/prex.h>
+#include <X11/XKBlib.h>
+#include <tools/postx.h>
+#endif
+
+#include <saldisp.hxx>
+#include <X11/keysym.h>
+
+#if !defined (SunXK_Undo)
+#define SunXK_Undo 0x0000FF65 // XK_Undo
+#define SunXK_Again 0x0000FF66 // XK_Redo
+#define SunXK_Find 0x0000FF68 // XK_Find
+#define SunXK_Stop 0x0000FF69 // XK_Cancel
+#define SunXK_Props 0x1005FF70
+#define SunXK_Front 0x1005FF71
+#define SunXK_Copy 0x1005FF72
+#define SunXK_Open 0x1005FF73
+#define SunXK_Paste 0x1005FF74
+#define SunXK_Cut 0x1005FF75
+#endif
+
+#ifdef SOLARIS
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/kbio.h>
+#include <sys/kbd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <deflt.h>
+#include <unistd.h>
+#include <stdlib.h>
+#endif
+
+#include <string.h>
+
+namespace vcl_sal {
+
+ struct KeysymNameReplacement
+ {
+ KeySym aSymbol;
+ const char* pName;
+ };
+
+ struct KeyboardReplacements
+ {
+ const char* pKeyboardName;
+ const KeysymNameReplacement* pReplacements;
+ int nReplacements;
+ };
+
+ // ====================================================================
+ //
+ // CAUTION CAUTION CAUTION
+ // every string value in the replacements tables must be in UTF8
+ // be careful with your editor !
+ //
+ // ====================================================================
+
+ static const struct KeysymNameReplacement aImplReplacements_English[] =
+ {
+ { XK_Control_L, "Ctrl" },
+ { XK_Control_R, "Ctrl" },
+ { XK_Escape, "Esc" },
+ { XK_space, "Space" },
+ { XK_minus, "-" },
+ { XK_plus, "+" }
+ };
+
+ static const struct KeysymNameReplacement aImplReplacements_Turkish[] =
+ {
+ { XK_Control_L, "Ctrl" },
+ { XK_Control_R, "Ctrl" },
+ { XK_Right, "SaÄŸ" },
+ { XK_Left, "Sol" },
+ { XK_Up, "Yukarı" },
+ { XK_Down, "Aşağı" },
+ { XK_space, "BoÅŸluk" }
+ };
+
+ static const struct KeysymNameReplacement aImplReplacements_Russian[] =
+ {
+ { XK_Right, "Вправо" },
+ { XK_Left, "Влево" },
+ { XK_Up, "Вверх" },
+ { XK_Down, "Вниз" },
+ { XK_space, "Пробел" }
+ };
+
+ static const struct KeysymNameReplacement aImplReplacements_German[] =
+ {
+ { XK_Control_L, "Strg" },
+ { XK_Control_R, "Strg" },
+ { XK_Shift_L, "Umschalt" },
+ { XK_Shift_R, "Umschalt" },
+ { XK_Alt_L, "Alt" },
+ { XK_Alt_R, "Alt Gr" },
+ { XK_Page_Up, "Bild auf" },
+ { XK_Page_Down, "Bild ab" },
+ { XK_End, "Ende" },
+ { XK_Home, "Pos 1" },
+ { XK_Insert, "Einfg" },
+ { XK_Delete, "Entf" },
+ { XK_Escape, "Esc" },
+ { XK_Right, "Rechts" },
+ { XK_Left, "Links" },
+ { XK_Up, "Oben" },
+ { XK_Down, "Unten" },
+ { XK_BackSpace, "Rückschritt" },
+ { XK_Return, "Eingabe" },
+ { XK_slash, "Schrägstrich" },
+ { XK_space, "Leertaste" },
+ { SunXK_Stop, "Stop" },
+ { SunXK_Again, "Wiederholen" },
+ { SunXK_Props, "Eigenschaften" },
+ { SunXK_Undo, "Zurücknehmen" },
+ { SunXK_Front, "Vordergrund" },
+ { SunXK_Copy, "Kopieren" },
+ { SunXK_Open, "Öffnen" },
+ { SunXK_Paste, "Einsetzen" },
+ { SunXK_Find, "Suchen" },
+ { SunXK_Cut, "Ausschneiden" },
+ { XK_minus, "-" },
+ { XK_plus, "+" }
+ };
+
+ static const struct KeysymNameReplacement aImplReplacements_French[] =
+ {
+ { XK_Shift_L, "Maj" },
+ { XK_Shift_R, "Maj" },
+ { XK_Page_Up, "Pg. Préc" },
+ { XK_Page_Down, "Pg. Suiv" },
+ { XK_End, "Fin" },
+ { XK_Home, "Origine" },
+ { XK_Insert, "Insérer" },
+ { XK_Delete, "Suppr" },
+ { XK_Escape, "Esc" },
+ { XK_Right, "Droite" },
+ { XK_Left, "Gauche" },
+ { XK_Up, "Haut" },
+ { XK_Down, "Bas" },
+ { XK_BackSpace, "Ret. Arr" },
+ { XK_Return, "Retour" },
+ { XK_KP_Enter, "Entrée" },
+ { SunXK_Stop, "Stop" },
+ { SunXK_Again, "Encore" },
+ { SunXK_Props, "Props" },
+ { SunXK_Undo, "Annuler" },
+ { SunXK_Front, "Devant" },
+ { SunXK_Copy, "Copy" },
+ { SunXK_Open, "Ouvrir" },
+ { SunXK_Paste, "Coller" },
+ { SunXK_Find, "Cher." },
+ { SunXK_Cut, "Couper" },
+ { XK_minus, "-" },
+ { XK_plus, "+" }
+ };
+
+ static const struct KeysymNameReplacement aImplReplacements_Italian[] =
+ {
+ { XK_Shift_L, "Maiusc" },
+ { XK_Shift_R, "Maiusc" },
+ { XK_Page_Up, "PgSu" },
+ { XK_Page_Down, "PgGiu" },
+ { XK_End, "Fine" },
+ { XK_Insert, "Ins" },
+ { XK_Delete, "Canc" },
+ { XK_Escape, "Esc" },
+ { XK_Right, "A destra" },
+ { XK_Left, "A sinistra" },
+ { XK_Up, "Sposta verso l'alto" },
+ { XK_Down, "Sposta verso il basso" },
+ { XK_BackSpace, "Backspace" },
+ { XK_Return, "Invio" },
+ { XK_space, "Spazio" },
+ { SunXK_Stop, "Stop" },
+ { SunXK_Again, "Ancora" },
+ { SunXK_Props, "Proprietà" },
+ { SunXK_Undo, "Annulla" },
+ { SunXK_Front, "Davanti" },
+ { SunXK_Copy, "Copia" },
+ { SunXK_Open, "Apri" },
+ { SunXK_Paste, "Incolla" },
+ { SunXK_Find, "Trova" },
+ { SunXK_Cut, "Taglia" },
+ { XK_minus, "-" },
+ { XK_plus, "+" }
+ };
+
+ static const struct KeysymNameReplacement aImplReplacements_Dutch[] =
+ {
+ { XK_Page_Up, "PageUp" },
+ { XK_Page_Down, "PageDown" },
+ { XK_Escape, "Esc" },
+ { XK_Right, "Rechts" },
+ { XK_Left, "Links" },
+ { XK_Up, "Boven" },
+ { XK_Down, "Onder" },
+ { XK_BackSpace, "Backspace" },
+ { XK_Return, "Return" },
+ { XK_space, "Spatiebalk" },
+ { SunXK_Stop, "Stop" },
+ { SunXK_Again, "Again" },
+ { SunXK_Props, "Props" },
+ { SunXK_Undo, "Undo" },
+ { SunXK_Front, "Front" },
+ { SunXK_Copy, "Copy" },
+ { SunXK_Open, "Open" },
+ { SunXK_Paste, "Paste" },
+ { SunXK_Find, "Find" },
+ { SunXK_Cut, "Cut" },
+ { XK_minus, "-" },
+ { XK_plus, "+" }
+ };
+
+ static const struct KeysymNameReplacement aImplReplacements_Norwegian[] =
+ {
+ { XK_Shift_L, "Skift" },
+ { XK_Shift_R, "Skift" },
+ { XK_Page_Up, "PageUp" },
+ { XK_Page_Down, "PageDown" },
+ { XK_Escape, "Esc" },
+ { XK_Right, "Hyre" },
+ { XK_Left, "Venstre" },
+ { XK_Up, "Opp" },
+ { XK_Down, "Ned" },
+ { XK_BackSpace, "Tilbake" },
+ { XK_Return, "Enter" },
+ { SunXK_Stop, "Avbryt" },
+ { SunXK_Again, "Gjenta" },
+ { SunXK_Props, "Egenskaper" },
+ { SunXK_Undo, "Angre" },
+ { SunXK_Front, "Front" },
+ { SunXK_Copy, "Kopi" },
+ { SunXK_Open, "Ã…pne" },
+ { SunXK_Paste, "Lim" },
+ { SunXK_Find, "Søk" },
+ { SunXK_Cut, "Klipp" },
+ { XK_minus, "-" },
+ { XK_plus, "+" }
+ };
+
+ static const struct KeysymNameReplacement aImplReplacements_Swedish[] =
+ {
+ { XK_Shift_L, "Skift" },
+ { XK_Shift_R, "Skift" },
+ { XK_Page_Up, "PageUp" },
+ { XK_Page_Down, "PageDown" },
+ { XK_Escape, "Esc" },
+ { XK_Right, "Höger" },
+ { XK_Left, "Vänster" },
+ { XK_Up, "Up" },
+ { XK_Down, "Ned" },
+ { XK_BackSpace, "Backsteg" },
+ { XK_Return, "Retur" },
+ { XK_space, "Blank" },
+ { SunXK_Stop, "Avbryt" },
+ { SunXK_Again, "Upprepa" },
+ { SunXK_Props, "Egenskaper" },
+ { SunXK_Undo, "Ã…ngra" },
+ { SunXK_Front, "Fram" },
+ { SunXK_Copy, "Kopiera" },
+ { SunXK_Open, "Öppna" },
+ { SunXK_Paste, "Klistra in" },
+ { SunXK_Find, "Sök" },
+ { SunXK_Cut, "Klipp ut" },
+ { XK_minus, "-" },
+ { XK_plus, "+" }
+ };
+
+ static const struct KeysymNameReplacement aImplReplacements_Portuguese[] =
+ {
+ { XK_Page_Up, "PageUp" },
+ { XK_Page_Down, "PageDown" },
+ { XK_Escape, "Esc" },
+ { XK_Right, "Direita" },
+ { XK_Left, "Esquerda" },
+ { XK_Up, "Acima" },
+ { XK_Down, "Abaixo" },
+ { XK_BackSpace, "Backspace" },
+ { XK_Return, "Enter" },
+ { XK_slash, "Barra" },
+ { SunXK_Stop, "Stop" },
+ { SunXK_Again, "Again" },
+ { SunXK_Props, "Props" },
+ { SunXK_Undo, "Undo" },
+ { SunXK_Front, "Front" },
+ { SunXK_Copy, "Copy" },
+ { SunXK_Open, "Open" },
+ { SunXK_Paste, "Paste" },
+ { SunXK_Find, "Find" },
+ { SunXK_Cut, "Cut" },
+ { XK_minus, "-" },
+ { XK_plus, "+" }
+ };
+
+ static const struct KeysymNameReplacement aImplReplacements_Spanish[] =
+ {
+ { XK_Shift_L, "Mayús" },
+ { XK_Shift_R, "Mayús" },
+ { XK_Page_Up, "RePág" },
+ { XK_Page_Down, "AvPág" },
+ { XK_End, "Fin" },
+ { XK_Home, "Inicio" },
+ { XK_Delete, "Supr" },
+ { XK_Escape, "Esc" },
+ { XK_Right, "Hacia la derecha" },
+ { XK_Left, "Hacia la izquierda" },
+ { XK_Up, "Hacia arriba" },
+ { XK_Down, "Hacia abajo" },
+ { XK_BackSpace, "Ret" },
+ { XK_Return, "Entrada" },
+ { XK_space, "Espacio" },
+ { XK_KP_Enter, "Intro" },
+ { SunXK_Stop, "Stop" },
+ { SunXK_Again, "Repetir" },
+ { SunXK_Props, "Props" },
+ { SunXK_Undo, "Anular" },
+ { SunXK_Front, "Delante" },
+ { SunXK_Copy, "Copiar" },
+ { SunXK_Open, "Abrir" },
+ { SunXK_Paste, "Pegar" },
+ { SunXK_Find, "Buscar" },
+ { SunXK_Cut, "Cortar" },
+ { XK_minus, "-" },
+ { XK_plus, "+" }
+ };
+
+ static const struct KeyboardReplacements aKeyboards[] =
+ {
+#ifdef SOLARIS
+ { "Germany5", aImplReplacements_German, sizeof(aImplReplacements_German)/sizeof(aImplReplacements_German[0]) },
+ { "Germany4", aImplReplacements_German, sizeof(aImplReplacements_German)/sizeof(aImplReplacements_German[0]) },
+ { "France5", aImplReplacements_French, sizeof(aImplReplacements_French)/sizeof(aImplReplacements_French[0]) },
+ { "France6", aImplReplacements_French, sizeof(aImplReplacements_French)/sizeof(aImplReplacements_French[0]) },
+ { "France_x86", aImplReplacements_French, sizeof(aImplReplacements_French)/sizeof(aImplReplacements_French[0]) },
+ { "Italy5", aImplReplacements_Italian, sizeof(aImplReplacements_Italian)/sizeof(aImplReplacements_Italian[0]) },
+ { "Italy5-Hobo", aImplReplacements_Italian, sizeof(aImplReplacements_Italian)/sizeof(aImplReplacements_Italian[0]) },
+ { "Italy4", aImplReplacements_Italian, sizeof(aImplReplacements_Italian)/sizeof(aImplReplacements_Italian[0]) },
+ { "Italy6", aImplReplacements_Italian, sizeof(aImplReplacements_Italian)/sizeof(aImplReplacements_Italian[0]) },
+ { "Italy_x86", aImplReplacements_Italian, sizeof(aImplReplacements_Italian)/sizeof(aImplReplacements_Italian[0]) },
+ { "Netherland4", aImplReplacements_Dutch, sizeof(aImplReplacements_Dutch)/sizeof(aImplReplacements_Dutch[0]) },
+ { "Netherland5", aImplReplacements_Dutch, sizeof(aImplReplacements_Dutch)/sizeof(aImplReplacements_Dutch[0]) },
+ { "Netherland5-Hobo", aImplReplacements_Dutch, sizeof(aImplReplacements_Dutch)/sizeof(aImplReplacements_Dutch[0]) },
+ { "Netherland6", aImplReplacements_Dutch, sizeof(aImplReplacements_Dutch)/sizeof(aImplReplacements_Dutch[0]) },
+ { "Netherland_x86", aImplReplacements_Dutch, sizeof(aImplReplacements_Dutch)/sizeof(aImplReplacements_Dutch[0]) },
+ { "Norway5", aImplReplacements_Norwegian, sizeof(aImplReplacements_Norwegian)/sizeof(aImplReplacements_Norwegian[0]) },
+ { "Norway5-Hobo", aImplReplacements_Norwegian, sizeof(aImplReplacements_Norwegian)/sizeof(aImplReplacements_Norwegian[0]) },
+ { "Norway4", aImplReplacements_Norwegian, sizeof(aImplReplacements_Norwegian)/sizeof(aImplReplacements_Norwegian[0]) },
+ { "Norway6", aImplReplacements_Norwegian, sizeof(aImplReplacements_Norwegian)/sizeof(aImplReplacements_Norwegian[0]) },
+ { "Norway_x86", aImplReplacements_Norwegian, sizeof(aImplReplacements_Norwegian)/sizeof(aImplReplacements_Norwegian[0]) },
+ { "Portugal5", aImplReplacements_Portuguese, sizeof(aImplReplacements_Portuguese)/sizeof(aImplReplacements_Portuguese[0]) },
+ { "Portugal5-Hobo", aImplReplacements_Portuguese, sizeof(aImplReplacements_Portuguese)/sizeof(aImplReplacements_Portuguese[0]) },
+ { "Portugal4", aImplReplacements_Portuguese, sizeof(aImplReplacements_Portuguese)/sizeof(aImplReplacements_Portuguese[0]) },
+ { "Portugal6", aImplReplacements_Portuguese, sizeof(aImplReplacements_Portuguese)/sizeof(aImplReplacements_Portuguese[0]) },
+ { "Portugal_x86", aImplReplacements_Portuguese, sizeof(aImplReplacements_Portuguese)/sizeof(aImplReplacements_Portuguese[0]) },
+ { "Spain5", aImplReplacements_Spanish, sizeof(aImplReplacements_Spanish)/sizeof(aImplReplacements_Spanish[0]) },
+ { "Spain5-Hobo", aImplReplacements_Spanish, sizeof(aImplReplacements_Spanish)/sizeof(aImplReplacements_Spanish[0]) },
+ { "Spain4", aImplReplacements_Spanish, sizeof(aImplReplacements_Spanish)/sizeof(aImplReplacements_Spanish[0]) },
+ { "Spain6", aImplReplacements_Spanish, sizeof(aImplReplacements_Spanish)/sizeof(aImplReplacements_Spanish[0]) },
+ { "Spain_x86", aImplReplacements_Spanish, sizeof(aImplReplacements_Spanish)/sizeof(aImplReplacements_Spanish[0]) },
+ { "Sweden5", aImplReplacements_Swedish, sizeof(aImplReplacements_Swedish)/sizeof(aImplReplacements_Swedish[0]) },
+ { "Sweden5-Hobo", aImplReplacements_Swedish, sizeof(aImplReplacements_Swedish)/sizeof(aImplReplacements_Swedish[0]) },
+ { "Sweden4", aImplReplacements_Swedish, sizeof(aImplReplacements_Swedish)/sizeof(aImplReplacements_Swedish[0]) },
+ { "Sweden6", aImplReplacements_Swedish, sizeof(aImplReplacements_Swedish)/sizeof(aImplReplacements_Swedish[0]) },
+ { "Sweden_x86", aImplReplacements_Swedish, sizeof(aImplReplacements_Swedish)/sizeof(aImplReplacements_Swedish[0]) },
+#endif
+ { "U.S. English", aImplReplacements_English, sizeof(aImplReplacements_English)/sizeof(aImplReplacements_English[0]) },
+ { "United Kingdom", aImplReplacements_English, sizeof(aImplReplacements_English)/sizeof(aImplReplacements_English[0]) },
+ // Germany, German
+ { "German", aImplReplacements_German, sizeof(aImplReplacements_German)/sizeof(aImplReplacements_German[0]) },
+ { "France", aImplReplacements_French, sizeof(aImplReplacements_French)/sizeof(aImplReplacements_French[0]) },
+ { "French", aImplReplacements_French, sizeof(aImplReplacements_French)/sizeof(aImplReplacements_French[0]) },
+ // Italy, Italian
+ { "Ital", aImplReplacements_Italian, sizeof(aImplReplacements_Italian)/sizeof(aImplReplacements_Italian[0]) },
+ // Norway, Norwegian
+ { "Norw", aImplReplacements_Norwegian, sizeof(aImplReplacements_Norwegian)/sizeof(aImplReplacements_Norwegian[0]) },
+ // Portugal, Portuguese
+ { "Portu", aImplReplacements_Portuguese, sizeof(aImplReplacements_Portuguese)/sizeof(aImplReplacements_Portuguese[0]) },
+ { "Spain", aImplReplacements_Spanish, sizeof(aImplReplacements_Spanish)/sizeof(aImplReplacements_Spanish[0]) },
+ { "Spanish", aImplReplacements_Spanish, sizeof(aImplReplacements_Spanish)/sizeof(aImplReplacements_Spanish[0]) },
+ // Sweden, Swedish
+ { "Swed", aImplReplacements_Swedish, sizeof(aImplReplacements_Swedish)/sizeof(aImplReplacements_Swedish[0]) },
+ { "Netherland", aImplReplacements_Dutch, sizeof(aImplReplacements_Dutch)/sizeof(aImplReplacements_Dutch[0]) },
+ { "Dutch", aImplReplacements_Dutch, sizeof(aImplReplacements_Dutch)/sizeof(aImplReplacements_Dutch[0]) },
+ // Turkish, Turkey
+ { "Turk", aImplReplacements_Turkish, sizeof(aImplReplacements_Turkish)/sizeof(aImplReplacements_Turkish[0]) },
+ // Russian, Russia
+ { "Russia", aImplReplacements_Russian, sizeof(aImplReplacements_Russian)/sizeof(aImplReplacements_Russian[0]) },
+ { "English", aImplReplacements_English, sizeof(aImplReplacements_English)/sizeof(aImplReplacements_English[0]) }
+ };
+
+ String getKeysymReplacementName( const char* pKeyboard, KeySym nSymbol )
+ {
+ for( unsigned int n = 0; n < sizeof(aKeyboards)/sizeof(aKeyboards[0]); n++ )
+ {
+ if( ! strncasecmp( pKeyboard, aKeyboards[n].pKeyboardName, strlen( aKeyboards[n].pKeyboardName ) ) )
+ {
+ const struct KeysymNameReplacement* pRepl = aKeyboards[n].pReplacements;
+ for( int m = aKeyboards[n].nReplacements ; m ; )
+ {
+ if( nSymbol == pRepl[--m].aSymbol )
+ return String( pRepl[m].pName, RTL_TEXTENCODING_UTF8 );
+ }
+ }
+ }
+ // try english fallbacks
+ const struct KeysymNameReplacement* pRepl = aImplReplacements_English;
+ for( int m = sizeof(aImplReplacements_English)/sizeof(aImplReplacements_English[0]) ; m ; )
+ {
+ if( nSymbol == pRepl[--m].aSymbol )
+ return String( pRepl[m].pName, RTL_TEXTENCODING_UTF8 );
+ }
+ return String();
+ }
+
+}
+
+#ifdef SOLARIS
+typedef struct {
+ int n_layout;
+ const char* p_description;
+} keyboard_layout;
+
+static const keyboard_layout type0_layout[] =
+{
+ { 0, "US4" },
+ { -1, NULL }
+};
+
+static const keyboard_layout type3_layout[] =
+{
+ { 0, "US3" },
+ { -1, NULL }
+};
+
+static const keyboard_layout type4_layout[] =
+{
+ { 0, "US4" },
+ { 1, "US4" },
+ { 2, "FranceBelg4" },
+ { 3, "Canada4" },
+ { 4, "Denmark4" },
+ { 5, "Germany4" },
+ { 6, "Italy4" },
+ { 7, "Netherland4" },
+ { 8, "Norway4" },
+ { 9, "Portugal4" },
+ { 10, "SpainLatAm4" },
+ { 11, "SwedenFin4" },
+ { 12, "Switzer_Fr4" },
+ { 13, "Switzer_Ge4" },
+ { 14, "UK4" },
+ { 16, "Korea4" },
+ { 17, "Taiwan4" },
+ { 19, "US101A_PC" },
+ { 19, "US101A_Sun" },
+ { 32, "Japan4" },
+ { 33, "US5" },
+ { 34, "US_UNIX5" },
+ { 35, "France5" },
+ { 36, "Denmark5" },
+ { 37, "Germany5" },
+ { 38, "Italy5" },
+ { 39, "Netherland5" },
+ { 40, "Norway5" },
+ { 41, "Portugal5" },
+ { 42, "Spain5" },
+ { 43, "Sweden5" },
+ { 44, "Switzer_Fr5" },
+ { 45, "Switzer_Ge5" },
+ { 46, "UK5" },
+ { 47, "Korea5" },
+ { 48, "Taiwan5" },
+ { 49, "Japan5" },
+ { 50, "Canada_Fr5" },
+ { 51, "Hungary5" },
+ { 52, "Poland5" },
+ { 53, "Czech5" },
+ { 54, "Russia5" },
+ { 55, "Latvia5" },
+ { 56, "Turkey5" },
+ { 57, "Greece5" },
+ { 58, "Estonia5" },
+ { 59, "Lithuania5" },
+ { 63, "Canada_Fr5_TBITS5" },
+ { 80, "US5_Hobo" },
+ { 81, "US_UNIX5_Hobo" },
+ { 82, "France5_Hobo" },
+ { 83, "Denmark5_Hobo" },
+ { 84, "Germany5_Hobo" },
+ { 85, "Italy5_Hobo" },
+ { 86, "Netherland5_Hobo" },
+ { 87, "Norway5_Hobo" },
+ { 88, "Portugal5_Hobo" },
+ { 89, "Spain5_Hobo" },
+ { 90, "Sweden5_Hobo" },
+ { 91, "Switzer_Fr5_Hobo" },
+ { 92, "Switzer_Ge5_Hobo" },
+ { 93, "UK5_Hobo" },
+ { 94, "Korea5_Hobo" },
+ { 95, "Taiwan5_Hobo" },
+ { 96, "Japan5_Hobo" },
+ { 97, "Canada_Fr5_Hobo" },
+ { -1, NULL }
+};
+
+static const keyboard_layout type101_layout[] =
+{
+ { 0, "US101A_x86" },
+ { 1, "US101A_x86" },
+ { 34, "J3100_x86" },
+ { 35, "France_x86" },
+ { 36, "Denmark_x86" },
+ { 37, "Germany_x86" },
+ { 38, "Italy_x86" },
+ { 39, "Netherland_x86" },
+ { 40, "Norway_x86" },
+ { 41, "Portugal_x86" },
+ { 42, "Spain_x86" },
+ { 43, "Sweden_x86" },
+ { 44, "Switzer_Fr_x86" },
+ { 45, "Switzer_Ge_x86" },
+ { 46, "UK_x86" },
+ { 47, "Korea_x86" },
+ { 48, "Taiwan_x86" },
+ { 49, "Japan_x86" },
+ { 50, "Canada_Fr2_x86" },
+ { 51, "Hungary_x86" },
+ { 52, "Poland_x86" },
+ { 53, "Czech_x86" },
+ { 54, "Russia_x86" },
+ { 55, "Latvia_x86" },
+ { 56, "Turkey_x86" },
+ { 57, "Greece_x86" },
+ { 59, "Lithuania_x86" },
+ { 1001, "MS_US101A_x86" },
+ { -1, NULL }
+};
+
+static const keyboard_layout type6_layout[] =
+{
+ { 0, "US6" },
+ { 6, "Denmark6" },
+ { 7, "Finnish6" },
+ { 8, "France6" },
+ { 9, "Germany6" },
+ { 14, "Italy6" },
+ { 15, "Japan6" },
+ { 16, "Korea6" },
+ { 18, "Netherland6" },
+ { 19, "Norway6" },
+ { 22, "Portugal6" },
+ { 25, "Spain6" },
+ { 26, "Sweden6" },
+ { 27, "Switzer_Fr6" },
+ { 28, "Switzer_Ge6" },
+ { 30, "Taiwan6" },
+ { 32, "UK6" },
+ { 33, "US6" },
+ { -1, NULL }
+};
+#endif
+
+
+#if OSL_DEBUG_LEVEL > 1
+#include <stdio.h>
+#endif
+
+const char* SalDisplay::GetKeyboardName( BOOL bRefresh )
+{
+ if( bRefresh || ! m_aKeyboardName.Len() )
+ {
+#ifdef SOLARIS
+ if( IsLocal() )
+ {
+ int kbd = open( "/dev/kbd", O_RDONLY );
+ if( kbd >= 0 )
+ {
+ int kbd_type = 0;
+ if( ! ioctl( kbd, KIOCTYPE, &kbd_type ) )
+ {
+ int kbd_layout = 0;
+ if( ! ioctl( kbd, KIOCLAYOUT, &kbd_layout ) )
+ {
+ const keyboard_layout *p_layout = NULL;
+ switch( kbd_type )
+ {
+ case KB_KLUNK: p_layout = type0_layout; break;
+ case KB_SUN3: p_layout = type3_layout; break;
+ case KB_SUN4: p_layout = type4_layout; break;
+ case KB_USB: p_layout = type6_layout; break;
+ case KB_PC: p_layout = type101_layout; break;
+ }
+
+ if( p_layout )
+ {
+ while( p_layout->n_layout != -1 )
+ {
+ if ( p_layout->n_layout == kbd_layout )
+ {
+ m_aKeyboardName = p_layout->p_description;
+ break;
+ }
+ p_layout++;
+ }
+ }
+ }
+ }
+ close(kbd);
+ }
+ }
+#else
+ int opcode, event, error;
+ int major = XkbMajorVersion, minor = XkbMinorVersion;
+ if( XkbQueryExtension( GetDisplay(), &opcode, &event,&error, &major, &minor ) )
+ {
+ XkbDescPtr pXkbDesc = NULL;
+ // try X keyboard extension
+ if( (pXkbDesc = XkbGetKeyboard( GetDisplay(), XkbAllComponentsMask, XkbUseCoreKbd )) )
+ {
+ const char* pAtom = NULL;
+ if( pXkbDesc->names->groups[0] )
+ {
+ pAtom = XGetAtomName( GetDisplay(), pXkbDesc->names->groups[0] );
+ m_aKeyboardName = pAtom;
+ XFree( (void*)pAtom );
+ }
+ else
+ m_aKeyboardName = "<unknown keyboard>";
+#if OSL_DEBUG_LEVEL > 1
+#define PRINT_ATOM( x ) { if( pXkbDesc->names->x ) { pAtom = XGetAtomName( GetDisplay(), pXkbDesc->names->x ); fprintf( stderr, "%s: %s\n", #x, pAtom ); XFree( (void*)pAtom ); } else fprintf( stderr, "%s: <nil>\n", #x ); }
+
+ PRINT_ATOM( keycodes );
+ PRINT_ATOM( geometry );
+ PRINT_ATOM( symbols );
+ PRINT_ATOM( types );
+ PRINT_ATOM( compat );
+ PRINT_ATOM( phys_symbols );
+
+#define PRINT_ATOM_2( x ) { if( pXkbDesc->names->x[i] ) { pAtom = XGetAtomName( GetDisplay(), pXkbDesc->names->x[i] ); fprintf( stderr, "%s[%d]: %s\n", #x, i, pAtom ); XFree( (void*)pAtom ); } else fprintf( stderr, "%s[%d]: <nil>\n", #x, i ); }
+ int i;
+ for( i = 0; i < XkbNumVirtualMods; i++ )
+ PRINT_ATOM_2( vmods );
+ for( i = 0; i < XkbNumIndicators; i++ )
+ PRINT_ATOM_2( indicators );
+ for( i = 0; i < XkbNumKbdGroups; i++ )
+ PRINT_ATOM_2( groups );
+#endif
+ XkbFreeKeyboard( pXkbDesc, XkbAllComponentsMask, True );
+ }
+ }
+#endif
+ if( ! m_aKeyboardName.Len() )
+ m_aKeyboardName = "<unknown keyboard>";
+ }
+ return m_aKeyboardName.GetBuffer();
+}
diff --git a/vcl/unx/source/app/makefile.mk b/vcl/unx/source/app/makefile.mk
new file mode 100644
index 000000000000..bd7549945c7c
--- /dev/null
+++ b/vcl/unx/source/app/makefile.mk
@@ -0,0 +1,110 @@
+#*************************************************************************
+#
+# 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=salapp
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)"!="unx"
+
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+
+.ELSE # "$(GUIBASE)"!="unx"
+
+SLOFILES=\
+ $(SLO)$/i18n_cb.obj \
+ $(SLO)$/i18n_ic.obj \
+ $(SLO)$/i18n_im.obj \
+ $(SLO)$/i18n_xkb.obj \
+ $(SLO)$/i18n_wrp.obj \
+ $(SLO)$/i18n_status.obj \
+ $(SLO)$/i18n_keysym.obj \
+ $(SLO)$/saldata.obj \
+ $(SLO)$/saltimer.obj \
+ $(SLO)$/saldisp.obj \
+ $(SLO)$/randrwrapper.obj \
+ $(SLO)$/salinst.obj \
+ $(SLO)$/salsys.obj \
+ $(SLO)$/soicon.obj \
+ $(SLO)$/sm.obj \
+ $(SLO)$/keysymnames.obj \
+ $(SLO)$/wmadaptor.obj
+
+EXCEPTIONSFILES=\
+ $(SLO)$/wmadaptor.obj \
+ $(SLO)$/saldata.obj \
+ $(SLO)$/salinst.obj \
+ $(SLO)$/saldisp.obj \
+ $(SLO)$/i18n_status.obj \
+ $(SLO)$/i18n_cb.obj \
+ $(SLO)$/i18n_ic.obj \
+ $(SLO)$/salsys.obj
+
+
+.IF "$(ENABLE_RANDR)" != ""
+CDEFS+=-DUSE_RANDR
+.IF "$(XRANDR_DLOPEN)" == "FALSE"
+CDEFS+=$(XRANDR_CFLAGS)
+.ELSE
+CDEFS+=-DXRANDR_DLOPEN
+.ENDIF
+.ENDIF
+
+.IF "$(USE_XINERAMA)" != "NO"
+CDEFS+=-DUSE_XINERAMA
+.IF "$(USE_XINERAMA_VERSION)" == "Xorg"
+CDEFS+=-DUSE_XINERAMA_XORG
+.ELIF "$(USE_XINERAMA_VERSION)" == "Xsun"
+CDEFS+=-DUSE_XINERAMA_XSUN
+.ELSE
+# provide sensible default
+.IF "$(OS)" != "SOLARIS"
+CDEFS+=-DUSE_XINERAMA_XORG
+.ELSE
+CDEFS+=-DUSE_XINERAMA_XSUN
+.ENDIF
+.ENDIF
+.ENDIF
+
+.ENDIF # "$(GUIBASE)"!="unx"
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
+.INCLUDE : $(PRJ)$/util$/target.pmk
+
diff --git a/vcl/unx/source/app/randrwrapper.cxx b/vcl/unx/source/app/randrwrapper.cxx
new file mode 100644
index 000000000000..27f9b1d1b77c
--- /dev/null
+++ b/vcl/unx/source/app/randrwrapper.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.
+ *
+ ************************************************************************/
+
+#ifdef USE_RANDR
+
+#include <tools/prex.h>
+#include <X11/extensions/Xrandr.h>
+#include <tools/postx.h>
+
+#include "osl/module.h"
+#include "rtl/ustring.hxx"
+
+namespace
+{
+
+# ifdef XRANDR_DLOPEN
+
+class RandRWrapper
+{
+ oslModule m_pRandRLib;
+
+ // function pointers
+ Bool(*m_pXRRQueryExtension)(Display*,int*,int*);
+ Status(*m_pXRRQueryVersion)(Display*,int*,int*);
+ XRRScreenConfiguration*(*m_pXRRGetScreenInfo)(Display*,Drawable);
+ void(*m_pXRRFreeScreenConfigInfo)(XRRScreenConfiguration*);
+ void(*m_pXRRSelectInput)(Display*,XLIB_Window,int);
+ int(*m_pXRRUpdateConfiguration)(XEvent*);
+ XRRScreenSize*(*m_pXRRSizes)(Display*,int,int*);
+ XRRScreenSize*(*m_pXRRConfigSizes)(XRRScreenConfiguration*,int*);
+ SizeID(*m_pXRRConfigCurrentConfiguration)(XRRScreenConfiguration*,Rotation*);
+ int(*m_pXRRRootToScreen)(Display*, XLIB_Window);
+
+ bool m_bValid;
+
+ void initFromModule();
+
+ RandRWrapper(Display*);
+ ~RandRWrapper();
+public:
+ static RandRWrapper& get(Display*);
+ static void releaseWrapper();
+
+ Bool XRRQueryExtension(Display* i_pDisp, int* o_event_base, int* o_error_base )
+ {
+ Bool bRet = False;
+ if( m_bValid )
+ bRet = m_pXRRQueryExtension( i_pDisp, o_event_base, o_error_base );
+ return bRet;
+ }
+ Status XRRQueryVersion( Display* i_pDisp, int* o_major, int* o_minor )
+ {
+ return m_bValid ? m_pXRRQueryVersion( i_pDisp, o_major, o_minor ) : 0;
+ }
+ XRRScreenConfiguration* XRRGetScreenInfo( Display* i_pDisp, Drawable i_aDrawable )
+ {
+ return m_bValid ? m_pXRRGetScreenInfo( i_pDisp, i_aDrawable ) : NULL;
+ }
+ void XRRFreeScreenConfigInfo( XRRScreenConfiguration* i_pConfig )
+ {
+ if( m_bValid )
+ m_pXRRFreeScreenConfigInfo( i_pConfig );
+ }
+ void XRRSelectInput( Display* i_pDisp, XLIB_Window i_window, int i_nMask )
+ {
+ if( m_bValid )
+ m_pXRRSelectInput( i_pDisp, i_window, i_nMask );
+ }
+ int XRRUpdateConfiguration( XEvent* i_pEvent )
+ {
+ return m_bValid ? m_pXRRUpdateConfiguration( i_pEvent ) : 0;
+ }
+ XRRScreenSize* XRRSizes( Display* i_pDisp, int i_screen, int* o_nscreens )
+ {
+ return m_bValid ? m_pXRRSizes( i_pDisp, i_screen, o_nscreens ) : NULL;
+ }
+ XRRScreenSize* XRRConfigSizes( XRRScreenConfiguration* i_pConfig, int* o_nSizes )
+ {
+ return m_bValid ? m_pXRRConfigSizes( i_pConfig, o_nSizes ) : NULL;
+ }
+ SizeID XRRConfigCurrentConfiguration( XRRScreenConfiguration* i_pConfig, Rotation* o_pRot )
+ {
+ return m_bValid ? m_pXRRConfigCurrentConfiguration( i_pConfig, o_pRot ) : 0;
+ }
+ int XRRRootToScreen( Display *dpy, XLIB_Window root )
+ {
+ return m_bValid ? m_pXRRRootToScreen( dpy, root ) : -1;
+ }
+};
+
+void RandRWrapper::initFromModule()
+{
+ m_pXRRQueryExtension = (Bool(*)(Display*,int*,int*))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRQueryExtension" );
+ m_pXRRQueryVersion = (Status(*)(Display*,int*,int*))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRQueryVersion" );
+ m_pXRRGetScreenInfo = (XRRScreenConfiguration*(*)(Display*,Drawable))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRGetScreenInfo" );
+ m_pXRRFreeScreenConfigInfo = (void(*)(XRRScreenConfiguration*))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRFreeScreenConfigInfo" );
+ m_pXRRSelectInput = (void(*)(Display*,XLIB_Window,int))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRSelectInput" );
+ m_pXRRUpdateConfiguration = (int(*)(XEvent*))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRUpdateConfiguration" );
+ m_pXRRSizes = (XRRScreenSize*(*)(Display*,int,int*))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRSizes" );
+ m_pXRRConfigSizes = (XRRScreenSize*(*)(XRRScreenConfiguration*,int*))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRConfigSizes" );
+ m_pXRRConfigCurrentConfiguration = (SizeID(*)(XRRScreenConfiguration*,Rotation*))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRConfigCurrentConfiguration" );
+ m_pXRRRootToScreen = (int(*)(Display*,XLIB_Window))osl_getAsciiFunctionSymbol( m_pRandRLib, "XRRRootToScreen" );
+
+ m_bValid = m_pXRRQueryExtension &&
+ m_pXRRQueryVersion &&
+ m_pXRRGetScreenInfo &&
+ m_pXRRFreeScreenConfigInfo &&
+ m_pXRRSelectInput &&
+ m_pXRRUpdateConfiguration &&
+ m_pXRRSizes &&
+ m_pXRRConfigSizes &&
+ m_pXRRConfigCurrentConfiguration &&
+ m_pXRRRootToScreen
+ ;
+}
+
+RandRWrapper::RandRWrapper( Display* pDisplay ) :
+ m_pRandRLib( NULL ),
+ m_pXRRQueryExtension( NULL ),
+ m_pXRRQueryVersion( NULL ),
+ m_pXRRGetScreenInfo( NULL ),
+ m_pXRRFreeScreenConfigInfo( NULL ),
+ m_pXRRSelectInput( NULL ),
+ m_pXRRUpdateConfiguration( NULL ),
+ m_pXRRSizes( NULL ),
+ m_pXRRConfigSizes( NULL ),
+ m_pXRRConfigCurrentConfiguration( NULL ),
+ m_pXRRRootToScreen( NULL ),
+ m_bValid( false )
+{
+ // first try in process space (e.g. gtk links that ?)
+ initFromModule();
+ if( ! m_bValid )
+ {
+ rtl::OUString aLibName( RTL_CONSTASCII_USTRINGPARAM( "libXrandr.so.2" ) );
+ // load and resolve dependencies immediately
+ // rationale: there are older distributions where libXrandr.so.2 is not linked
+ // with libXext.so, resulting in a missing symbol and terminating the office
+ // obviously they expected libXext to be linked in global symbolspace (that is
+ // linked by the application), which is not the case with us (because we want
+ // to be able to run in headless mode even without an installed X11 library)
+ m_pRandRLib = osl_loadModule( aLibName.pData, SAL_LOADMODULE_DEFAULT | SAL_LOADMODULE_NOW );
+ initFromModule();
+ }
+ if( m_bValid )
+ {
+ int nEventBase = 0, nErrorBase = 0;
+ if( ! m_pXRRQueryExtension( pDisplay, &nEventBase, &nErrorBase ) )
+ m_bValid = false;
+ }
+}
+
+RandRWrapper::~RandRWrapper()
+{
+ if( m_pRandRLib )
+ osl_unloadModule( m_pRandRLib );
+}
+
+static RandRWrapper* pWrapper = NULL;
+
+RandRWrapper& RandRWrapper::get( Display* i_pDisplay )
+{
+ if( ! pWrapper )
+ pWrapper = new RandRWrapper( i_pDisplay );
+ return *pWrapper;
+}
+
+void RandRWrapper::releaseWrapper()
+{
+ delete pWrapper;
+ pWrapper = NULL;
+}
+
+# else
+
+class RandRWrapper
+{
+ bool m_bValid;
+
+ RandRWrapper(Display*);
+public:
+ static RandRWrapper& get(Display*);
+ static void releaseWrapper();
+
+ Bool XRRQueryExtension(Display* i_pDisp, int* o_event_base, int* o_error_base )
+ {
+ Bool bRet = False;
+ if( m_bValid )
+ bRet = ::XRRQueryExtension( i_pDisp, o_event_base, o_error_base );
+ return bRet;
+ }
+ Status XRRQueryVersion( Display* i_pDisp, int* o_major, int* o_minor )
+ {
+ return m_bValid ? ::XRRQueryVersion( i_pDisp, o_major, o_minor ) : 0;
+ }
+ XRRScreenConfiguration* XRRGetScreenInfo( Display* i_pDisp, Drawable i_aDrawable )
+ {
+ return m_bValid ? ::XRRGetScreenInfo( i_pDisp, i_aDrawable ) : NULL;
+ }
+ void XRRFreeScreenConfigInfo( XRRScreenConfiguration* i_pConfig )
+ {
+ if( m_bValid )
+ ::XRRFreeScreenConfigInfo( i_pConfig );
+ }
+ void XRRSelectInput( Display* i_pDisp, XLIB_Window i_window, int i_nMask )
+ {
+ if( m_bValid )
+ ::XRRSelectInput( i_pDisp, i_window, i_nMask );
+ }
+ int XRRUpdateConfiguration( XEvent* i_pEvent )
+ {
+ return m_bValid ? ::XRRUpdateConfiguration( i_pEvent ) : 0;
+ }
+ XRRScreenSize* XRRSizes( Display* i_pDisp, int i_screen, int* o_nscreens )
+ {
+ return m_bValid ? ::XRRSizes( i_pDisp, i_screen, o_nscreens ) : NULL;
+ }
+ XRRScreenSize* XRRConfigSizes( XRRScreenConfiguration* i_pConfig, int* o_nSizes )
+ {
+ return m_bValid ? ::XRRConfigSizes( i_pConfig, o_nSizes ) : NULL;
+ }
+ SizeID XRRConfigCurrentConfiguration( XRRScreenConfiguration* i_pConfig, Rotation* o_pRot )
+ {
+ return m_bValid ? ::XRRConfigCurrentConfiguration( i_pConfig, o_pRot ) : 0;
+ }
+ int XRRRootToScreen( Display *dpy, XLIB_Window root )
+ {
+ return m_bValid ? ::XRRRootToScreen( dpy, root ) : -1;
+ }
+};
+
+RandRWrapper::RandRWrapper( Display* pDisplay ) :
+ m_bValid( true )
+{
+ int nEventBase = 0, nErrorBase = 0;
+ if( !XRRQueryExtension( pDisplay, &nEventBase, &nErrorBase ) )
+ m_bValid = false;
+}
+
+static RandRWrapper* pWrapper = NULL;
+
+RandRWrapper& RandRWrapper::get( Display* i_pDisplay )
+{
+ if( ! pWrapper )
+ pWrapper = new RandRWrapper( i_pDisplay );
+ return *pWrapper;
+}
+
+void RandRWrapper::releaseWrapper()
+{
+ delete pWrapper;
+ pWrapper = NULL;
+}
+
+#endif
+
+} // namespace
+
+#endif
+
+#include "saldisp.hxx"
+#include "salframe.h"
+#if OSL_DEBUG_LEVEL > 1
+#include <cstdio>
+#endif
+
+void SalDisplay::InitRandR( XLIB_Window aRoot ) const
+{
+ #ifdef USE_RANDR
+ if( m_bUseRandRWrapper )
+ RandRWrapper::get( GetDisplay() ).XRRSelectInput( GetDisplay(), aRoot, RRScreenChangeNotifyMask );
+ #else
+ (void)aRoot;
+ #endif
+}
+
+void SalDisplay::DeInitRandR()
+{
+ #ifdef USE_RANDR
+ if( m_bUseRandRWrapper )
+ RandRWrapper::releaseWrapper();
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "SalDisplay::DeInitRandR()\n" );
+#endif
+ #endif
+}
+
+int SalDisplay::processRandREvent( XEvent* pEvent )
+{
+ int nRet = 0;
+ #ifdef USE_RANDR
+ XConfigureEvent* pCnfEvent=(XConfigureEvent*)pEvent;
+ if( m_bUseRandRWrapper && pWrapper && pWrapper->XRRRootToScreen(GetDisplay(),pCnfEvent->window) != -1 )
+ {
+ nRet = pWrapper->XRRUpdateConfiguration( pEvent );
+ if( nRet == 1 && pEvent->type != ConfigureNotify) // this should then be a XRRScreenChangeNotifyEvent
+ {
+ // update screens
+ bool bNotify = false;
+ for( size_t i = 0; i < m_aScreens.size(); i++ )
+ {
+ if( m_aScreens[i].m_bInit )
+ {
+ XRRScreenConfiguration *pConfig = NULL;
+ XRRScreenSize *pSizes = NULL;
+ int nSizes = 0;
+ Rotation nRot = 0;
+ SizeID nId = 0;
+
+ pConfig = pWrapper->XRRGetScreenInfo( GetDisplay(), m_aScreens[i].m_aRoot );
+ nId = pWrapper->XRRConfigCurrentConfiguration( pConfig, &nRot );
+ pSizes = pWrapper->XRRConfigSizes( pConfig, &nSizes );
+ XRRScreenSize *pTargetSize = pSizes + nId;
+
+ bNotify = bNotify ||
+ m_aScreens[i].m_aSize.Width() != pTargetSize->width ||
+ m_aScreens[i].m_aSize.Height() != pTargetSize->height;
+
+ m_aScreens[i].m_aSize = Size( pTargetSize->width, pTargetSize->height );
+
+ pWrapper->XRRFreeScreenConfigInfo( pConfig );
+
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "screen %d changed to size %dx%d\n", (int)i, (int)pTargetSize->width, (int)pTargetSize->height );
+ #endif
+ }
+ }
+ if( bNotify && ! m_aFrames.empty() )
+ m_aFrames.front()->CallCallback( SALEVENT_DISPLAYCHANGED, 0 );
+ }
+ }
+ #else
+ (void)pEvent;
+ #endif
+ return nRet;
+}
diff --git a/vcl/unx/source/app/saldata.cxx b/vcl/unx/source/app/saldata.cxx
new file mode 100644
index 000000000000..50ef71df8619
--- /dev/null
+++ b/vcl/unx/source/app/saldata.cxx
@@ -0,0 +1,871 @@
+/*************************************************************************
+ *
+ * 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 USE_XTOOLKIT
+# define SAL_XT
+#endif
+
+// -=-= #includes =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <cstdio>
+#include <cstring>
+#include <cstdlib>
+#include <stdio.h> // snprintf, seems not to be in namespace std on every platform
+#include <limits.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sys/resource.h>
+#ifdef SUN
+#include <sys/systeminfo.h>
+#endif
+#ifdef AIX
+#include <strings.h>
+#endif
+#ifdef FREEBSD
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#endif
+#include <vos/process.hxx>
+#ifndef _VOS_MUTEX_HXX
+#include <vos/mutex.hxx>
+#endif
+
+#include "Xproto.h"
+#include <saldisp.hxx>
+#include <saldata.hxx>
+#include <vcl/salinst.hxx>
+#include <salframe.h>
+#include <osl/signal.h>
+#include <osl/thread.h>
+#include <osl/process.h>
+#include <rtl/strbuf.hxx>
+#ifndef _RTL_BOOTSTRAP_HXX
+#include <rtl/bootstrap.hxx>
+#endif
+
+#include <tools/debug.hxx>
+#include <sm.hxx>
+#include <vcl/svapp.hxx>
+#include "i18n_im.hxx"
+#include "i18n_xkb.hxx"
+
+// -=-= <signal.h> -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#ifndef UNX
+#ifndef SIGBUS
+#define SIGBUS 10
+#endif
+#ifndef SIGSEGV
+#define SIGSEGV 11
+#endif
+#ifndef SIGIOT
+#define SIGIOT SIGABRT
+#endif
+#endif
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+static const struct timeval noyield__ = { 0, 0 };
+static const struct timeval yield__ = { 0, 10000 };
+
+static const char* XRequest[] = {
+ // see /usr/lib/X11/XErrorDB, /usr/openwin/lib/XErrorDB ...
+ NULL,
+ "X_CreateWindow",
+ "X_ChangeWindowAttributes",
+ "X_GetWindowAttributes",
+ "X_DestroyWindow",
+ "X_DestroySubwindows",
+ "X_ChangeSaveSet",
+ "X_ReparentWindow",
+ "X_MapWindow",
+ "X_MapSubwindows",
+ "X_UnmapWindow",
+ "X_UnmapSubwindows",
+ "X_ConfigureWindow",
+ "X_CirculateWindow",
+ "X_GetGeometry",
+ "X_QueryTree",
+ "X_InternAtom",
+ "X_GetAtomName",
+ "X_ChangeProperty",
+ "X_DeleteProperty",
+ "X_GetProperty",
+ "X_ListProperties",
+ "X_SetSelectionOwner",
+ "X_GetSelectionOwner",
+ "X_ConvertSelection",
+ "X_SendEvent",
+ "X_GrabPointer",
+ "X_UngrabPointer",
+ "X_GrabButton",
+ "X_UngrabButton",
+ "X_ChangeActivePointerGrab",
+ "X_GrabKeyboard",
+ "X_UngrabKeyboard",
+ "X_GrabKey",
+ "X_UngrabKey",
+ "X_AllowEvents",
+ "X_GrabServer",
+ "X_UngrabServer",
+ "X_QueryPointer",
+ "X_GetMotionEvents",
+ "X_TranslateCoords",
+ "X_WarpPointer",
+ "X_SetInputFocus",
+ "X_GetInputFocus",
+ "X_QueryKeymap",
+ "X_OpenFont",
+ "X_CloseFont",
+ "X_QueryFont",
+ "X_QueryTextExtents",
+ "X_ListFonts",
+ "X_ListFontsWithInfo",
+ "X_SetFontPath",
+ "X_GetFontPath",
+ "X_CreatePixmap",
+ "X_FreePixmap",
+ "X_CreateGC",
+ "X_ChangeGC",
+ "X_CopyGC",
+ "X_SetDashes",
+ "X_SetClipRectangles",
+ "X_FreeGC",
+ "X_ClearArea",
+ "X_CopyArea",
+ "X_CopyPlane",
+ "X_PolyPoint",
+ "X_PolyLine",
+ "X_PolySegment",
+ "X_PolyRectangle",
+ "X_PolyArc",
+ "X_FillPoly",
+ "X_PolyFillRectangle",
+ "X_PolyFillArc",
+ "X_PutImage",
+ "X_GetImage",
+ "X_PolyText8",
+ "X_PolyText16",
+ "X_ImageText8",
+ "X_ImageText16",
+ "X_CreateColormap",
+ "X_FreeColormap",
+ "X_CopyColormapAndFree",
+ "X_InstallColormap",
+ "X_UninstallColormap",
+ "X_ListInstalledColormaps",
+ "X_AllocColor",
+ "X_AllocNamedColor",
+ "X_AllocColorCells",
+ "X_AllocColorPlanes",
+ "X_FreeColors",
+ "X_StoreColors",
+ "X_StoreNamedColor",
+ "X_QueryColors",
+ "X_LookupColor",
+ "X_CreateCursor",
+ "X_CreateGlyphCursor",
+ "X_FreeCursor",
+ "X_RecolorCursor",
+ "X_QueryBestSize",
+ "X_QueryExtension",
+ "X_ListExtensions",
+ "X_ChangeKeyboardMapping",
+ "X_GetKeyboardMapping",
+ "X_ChangeKeyboardControl",
+ "X_GetKeyboardControl",
+ "X_Bell",
+ "X_ChangePointerControl",
+ "X_GetPointerControl",
+ "X_SetScreenSaver",
+ "X_GetScreenSaver",
+ "X_ChangeHosts",
+ "X_ListHosts",
+ "X_SetAccessControl",
+ "X_SetCloseDownMode",
+ "X_KillClient",
+ "X_RotateProperties",
+ "X_ForceScreenSaver",
+ "X_SetPointerMapping",
+ "X_GetPointerMapping",
+ "X_SetModifierMapping",
+ "X_GetModifierMapping",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "X_NoOperation"
+};
+
+// -=-= C statics =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+int X11SalData::XErrorHdl( Display *pDisplay, XErrorEvent *pEvent )
+{
+ GetX11SalData()->XError( pDisplay, pEvent );
+ return 0;
+}
+
+int X11SalData::XIOErrorHdl( Display * )
+{
+ /* #106197# hack: until a real shutdown procedure exists
+ * _exit ASAP
+ */
+ if( ImplGetSVData()->maAppData.mbAppQuit )
+ _exit(1);
+
+ // really bad hack
+ if( ! SessionManagerClient::checkDocumentsSaved() )
+ /* oslSignalAction eToDo = */ osl_raiseSignal (OSL_SIGNAL_USER_X11SUBSYSTEMERROR, NULL);
+
+ std::fprintf( stderr, "X IO Error\n" );
+ std::fflush( stdout );
+ std::fflush( stderr );
+
+ /* #106197# the same reasons to use _exit instead of exit in salmain
+ * do apply here. Since there is nothing to be done after an XIO
+ * error we have to _exit immediately.
+ */
+ _exit(0);
+ return 0;
+}
+
+// -=-= SalData =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#include <pthread.h>
+
+X11SalData::X11SalData()
+{
+ bNoExceptions_ = !!getenv( "SAL_NOSEGV" );
+
+ pXLib_ = NULL;
+ m_pSalDisplay = NULL;
+ m_pInstance = NULL;
+ m_pPlugin = NULL;
+
+ hMainThread_ = pthread_self();
+ osl_getLocalHostname( &maLocalHostName.pData );
+}
+
+X11SalData::~X11SalData()
+{
+ DeleteDisplay();
+}
+
+void X11SalData::DeleteDisplay()
+{
+ delete m_pSalDisplay;
+ m_pSalDisplay = NULL;
+ delete pXLib_;
+ pXLib_ = NULL;
+}
+
+void X11SalData::Init()
+{
+ pXLib_ = new SalXLib();
+ pXLib_->Init();
+}
+
+void X11SalData::initNWF( void )
+{
+}
+
+void X11SalData::deInitNWF( void )
+{
+}
+
+// -=-= SalXLib =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+SalXLib::SalXLib()
+{
+ m_aTimeout.tv_sec = 0;
+ m_aTimeout.tv_usec = 0;
+ m_nTimeoutMS = 0;
+
+ nFDs_ = 0;
+ FD_ZERO( &aReadFDS_ );
+ FD_ZERO( &aExceptionFDS_ );
+
+ m_pTimeoutFDS[0] = m_pTimeoutFDS[1] = -1;
+ if (pipe (m_pTimeoutFDS) != -1)
+ {
+ // initialize 'wakeup' pipe.
+ int flags;
+
+ // set close-on-exec descriptor flag.
+ if ((flags = fcntl (m_pTimeoutFDS[0], F_GETFD)) != -1)
+ {
+ flags |= FD_CLOEXEC;
+ fcntl (m_pTimeoutFDS[0], F_SETFD, flags);
+ }
+ if ((flags = fcntl (m_pTimeoutFDS[1], F_GETFD)) != -1)
+ {
+ flags |= FD_CLOEXEC;
+ fcntl (m_pTimeoutFDS[1], F_SETFD, flags);
+ }
+
+ // set non-blocking I/O flag.
+ if ((flags = fcntl (m_pTimeoutFDS[0], F_GETFL)) != -1)
+ {
+ flags |= O_NONBLOCK;
+ fcntl (m_pTimeoutFDS[0], F_SETFL, flags);
+ }
+ if ((flags = fcntl (m_pTimeoutFDS[1], F_GETFL)) != -1)
+ {
+ flags |= O_NONBLOCK;
+ fcntl (m_pTimeoutFDS[1], F_SETFL, flags);
+ }
+
+ // insert [0] into read descriptor set.
+ FD_SET( m_pTimeoutFDS[0], &aReadFDS_ );
+ nFDs_ = m_pTimeoutFDS[0] + 1;
+ }
+
+ m_bHaveSystemChildFrames = false;
+ m_aOrigXIOErrorHandler = XSetIOErrorHandler ( (XIOErrorHandler)X11SalData::XIOErrorHdl );
+ PushXErrorLevel( !!getenv( "SAL_IGNOREXERRORS" ) );
+}
+
+SalXLib::~SalXLib()
+{
+ // close 'wakeup' pipe.
+ close (m_pTimeoutFDS[0]);
+ close (m_pTimeoutFDS[1]);
+
+ PopXErrorLevel();
+ XSetIOErrorHandler (m_aOrigXIOErrorHandler);
+}
+
+void SalXLib::PushXErrorLevel( bool bIgnore )
+{
+ m_aXErrorHandlerStack.push_back( XErrorStackEntry() );
+ XErrorStackEntry& rEnt = m_aXErrorHandlerStack.back();
+ rEnt.m_bWas = false;
+ rEnt.m_bIgnore = bIgnore;
+ rEnt.m_nLastErrorRequest = 0;
+ rEnt.m_aHandler = XSetErrorHandler( (XErrorHandler)X11SalData::XErrorHdl );
+}
+
+void SalXLib::PopXErrorLevel()
+{
+ if( m_aXErrorHandlerStack.size() )
+ {
+ XSetErrorHandler( m_aXErrorHandlerStack.back().m_aHandler );
+ m_aXErrorHandlerStack.pop_back();
+ }
+}
+
+void SalXLib::Init()
+{
+ SalI18N_InputMethod* pInputMethod = new SalI18N_InputMethod;
+ pInputMethod->SetLocale();
+ XrmInitialize();
+
+ /*
+ * open connection to X11 Display
+ * try in this order:
+ * o -display command line parameter,
+ * o $DISPLAY environment variable
+ * o default display
+ */
+
+ Display *pDisp = NULL;
+
+ // is there a -display command line parameter?
+ vos::OExtCommandLine aCommandLine;
+ sal_uInt32 nParams = aCommandLine.getCommandArgCount();
+ rtl::OUString aParam;
+ rtl::OString aDisplay;
+ for (USHORT i=0; i<nParams; i++)
+ {
+ aCommandLine.getCommandArg(i, aParam);
+ if (aParam.equalsAscii("-display"))
+ {
+ aCommandLine.getCommandArg(i+1, aParam);
+ aDisplay = rtl::OUStringToOString(
+ aParam, osl_getThreadTextEncoding());
+
+ if ((pDisp = XOpenDisplay(aDisplay.getStr()))!=NULL)
+ {
+ /*
+ * if a -display switch was used, we need
+ * to set the environment accoringly since
+ * the clipboard build another connection
+ * to the xserver using $DISPLAY
+ */
+ const char envpre[] = "DISPLAY=";
+ char *envstr = new char[sizeof(envpre)+aDisplay.getLength()];
+ snprintf(envstr, sizeof(envpre)+aDisplay.getLength(), "DISPLAY=%s", aDisplay.getStr());
+ putenv(envstr);
+ }
+ break;
+ }
+ }
+
+ if (!pDisp && !aDisplay.getLength())
+ {
+ // Open $DISPLAY or default...
+ char *pDisplay = getenv("DISPLAY");
+ if (pDisplay != NULL)
+ aDisplay = rtl::OString(pDisplay);
+ pDisp = XOpenDisplay(pDisplay);
+ }
+
+ if ( !pDisp )
+ {
+ rtl::OUString aProgramFileURL;
+ osl_getExecutableFile( &aProgramFileURL.pData );
+ rtl::OUString aProgramSystemPath;
+ osl_getSystemPathFromFileURL (aProgramFileURL.pData, &aProgramSystemPath.pData);
+ rtl::OString aProgramName = rtl::OUStringToOString(
+ aProgramSystemPath,
+ osl_getThreadTextEncoding() );
+ std::fprintf( stderr, "%s X11 error: Can't open display: %s\n",
+ aProgramName.getStr(), aDisplay.getStr());
+ std::fprintf( stderr, " Set DISPLAY environment variable, use -display option\n");
+ std::fprintf( stderr, " or check permissions of your X-Server\n");
+ std::fprintf( stderr, " (See \"man X\" resp. \"man xhost\" for details)\n");
+ std::fflush( stderr );
+ exit(0);
+ }
+
+ SalDisplay *pSalDisplay = new SalX11Display( pDisp );
+
+ pInputMethod->CreateMethod( pDisp );
+ pInputMethod->AddConnectionWatch( pDisp, (void*)this );
+ pSalDisplay->SetInputMethod( pInputMethod );
+
+ PushXErrorLevel( true );
+ SalI18N_KeyboardExtension *pKbdExtension = new SalI18N_KeyboardExtension( pDisp );
+ XSync( pDisp, False );
+
+ pKbdExtension->UseExtension( ! HasXErrorOccured() );
+ PopXErrorLevel();
+
+ pSalDisplay->SetKbdExtension( pKbdExtension );
+}
+
+extern "C" {
+void EmitFontpathWarning( void )
+{
+ static Bool bOnce = False;
+ if ( !bOnce )
+ {
+ bOnce = True;
+ std::fprintf( stderr, "Please verify your fontpath settings\n"
+ "\t(See \"man xset\" for details"
+ " or ask your system administrator)\n" );
+ }
+}
+
+} /* extern "C" */
+
+static void PrintXError( Display *pDisplay, XErrorEvent *pEvent )
+{
+ char msg[ 120 ] = "";
+#if ! ( defined LINUX && defined PPC )
+ XGetErrorText( pDisplay, pEvent->error_code, msg, sizeof( msg ) );
+#endif
+ std::fprintf( stderr, "X-Error: %s\n", msg );
+ if( pEvent->request_code < capacityof( XRequest ) )
+ {
+ const char* pName = XRequest[pEvent->request_code];
+ if( !pName )
+ pName = "BadRequest?";
+ std::fprintf( stderr, "\tMajor opcode: %d (%s)\n", pEvent->request_code, pName );
+ }
+ else
+ {
+ std::fprintf( stderr, "\tMajor opcode: %d\n", pEvent->request_code );
+ // TODO: also display extension name?
+ std::fprintf( stderr, "\tMinor opcode: %d\n", pEvent->minor_code );
+ }
+
+ std::fprintf( stderr, "\tResource ID: 0x%lx\n",
+ pEvent->resourceid );
+ std::fprintf( stderr, "\tSerial No: %ld (%ld)\n",
+ pEvent->serial, LastKnownRequestProcessed(pDisplay) );
+
+ if( !getenv( "SAL_SYNCHRONIZE" ) )
+ {
+ std::fprintf( stderr, "These errors are reported asynchronously,\n");
+ std::fprintf( stderr, "set environment variable SAL_SYNCHRONIZE to 1 to help debugging\n");
+ }
+
+ std::fflush( stdout );
+ std::fflush( stderr );
+}
+
+void SalXLib::XError( Display *pDisplay, XErrorEvent *pEvent )
+{
+ if( m_bHaveSystemChildFrames )
+ return;
+
+ if( ! m_aXErrorHandlerStack.back().m_bIgnore )
+ {
+ if ( (pEvent->error_code == BadAlloc)
+ && (pEvent->request_code == X_OpenFont) )
+ {
+ static Bool bOnce = False;
+ if ( !bOnce )
+ {
+ std::fprintf(stderr, "X-Error occured in a request for X_OpenFont\n");
+ EmitFontpathWarning();
+
+ bOnce = True ;
+ }
+ return;
+ }
+ /* ignore
+ * X_SetInputFocus: it's a hint only anyway
+ * X_GetProperty: this is part of the XGetWindowProperty call and will
+ * be handled by the return value of that function
+ */
+ else if( pEvent->request_code == X_SetInputFocus ||
+ pEvent->request_code == X_GetProperty
+ )
+ return;
+
+
+ if( pDisplay != GetX11SalData()->GetDisplay()->GetDisplay() )
+ return;
+
+ PrintXError( pDisplay, pEvent );
+
+ oslSignalAction eToDo = osl_raiseSignal (OSL_SIGNAL_USER_X11SUBSYSTEMERROR, NULL);
+ switch (eToDo)
+ {
+ case osl_Signal_ActIgnore :
+ return;
+ case osl_Signal_ActAbortApp :
+ abort();
+ case osl_Signal_ActKillApp :
+ exit(0);
+ case osl_Signal_ActCallNextHdl :
+ break;
+ default :
+ break;
+ }
+
+ }
+
+ m_aXErrorHandlerStack.back().m_bWas = true;
+}
+
+struct YieldEntry
+{
+ YieldEntry* next; // pointer to next entry
+ int fd; // file descriptor for reading
+ void* data; // data for predicate and callback
+ YieldFunc pending; // predicate (determins pending events)
+ YieldFunc queued; // read and queue up events
+ YieldFunc handle; // handle pending events
+
+ inline int HasPendingEvent() const { return pending( fd, data ); }
+ inline int IsEventQueued() const { return queued( fd, data ); }
+ inline void HandleNextEvent() const { handle( fd, data ); }
+};
+
+#define MAX_NUM_DESCRIPTORS 128
+
+static YieldEntry yieldTable[ MAX_NUM_DESCRIPTORS ];
+
+void SalXLib::Insert( int nFD, void* data,
+ YieldFunc pending,
+ YieldFunc queued,
+ YieldFunc handle )
+{
+ DBG_ASSERT( nFD, "can not insert stdin descriptor" );
+ DBG_ASSERT( !yieldTable[nFD].fd, "SalXLib::Insert fd twice" );
+
+ yieldTable[nFD].fd = nFD;
+ yieldTable[nFD].data = data;
+ yieldTable[nFD].pending = pending;
+ yieldTable[nFD].queued = queued;
+ yieldTable[nFD].handle = handle;
+
+ FD_SET( nFD, &aReadFDS_ );
+ FD_SET( nFD, &aExceptionFDS_ );
+
+ if( nFD >= nFDs_ )
+ nFDs_ = nFD + 1;
+}
+
+void SalXLib::Remove( int nFD )
+{
+ FD_CLR( nFD, &aReadFDS_ );
+ FD_CLR( nFD, &aExceptionFDS_ );
+
+ yieldTable[nFD].fd = 0;
+
+ if ( nFD == nFDs_ )
+ {
+ for ( nFD = nFDs_ - 1;
+ nFD >= 0 && !yieldTable[nFD].fd;
+ nFD-- ) ;
+
+ nFDs_ = nFD + 1;
+ }
+}
+
+bool SalXLib::CheckTimeout( bool bExecuteTimers )
+{
+ bool bRet = false;
+ if( m_aTimeout.tv_sec ) // timer is started
+ {
+ timeval aTimeOfDay;
+ gettimeofday( &aTimeOfDay, 0 );
+ if( aTimeOfDay >= m_aTimeout )
+ {
+ bRet = true;
+ if( bExecuteTimers )
+ {
+ // timed out, update timeout
+ m_aTimeout = aTimeOfDay;
+ /*
+ * #107827# autorestart immediately, will be stopped (or set
+ * to different value in notify hdl if necessary;
+ * CheckTimeout should return false while
+ * timers are being dispatched.
+ */
+ m_aTimeout += m_nTimeoutMS;
+ // notify
+ GetX11SalData()->Timeout();
+ }
+ }
+ }
+ return bRet;
+}
+
+void SalXLib::Yield( bool bWait, bool bHandleAllCurrentEvents )
+{
+ // check for timeouts here if you want to make screenshots
+ static char* p_prioritize_timer = getenv ("SAL_HIGHPRIORITY_REPAINT");
+ if (p_prioritize_timer != NULL)
+ CheckTimeout();
+
+ // first, check for already queued events.
+ for ( int nFD = 0; nFD < nFDs_; nFD++ )
+ {
+ YieldEntry* pEntry = &(yieldTable[nFD]);
+ if ( pEntry->fd )
+ {
+ DBG_ASSERT( nFD == pEntry->fd, "wrong fd in Yield()" );
+ if ( pEntry->HasPendingEvent() )
+ {
+ pEntry->HandleNextEvent();
+ // #63862# da jetzt alle user-events ueber die interne
+ // queue kommen, wird die Kontrolle analog zum select
+ // gesteuerten Zweig einmal bei bWait abgegeben
+
+ /* #i9277# do not reschedule since performance gets down the
+ the drain under heavy load
+ YieldMutexReleaser aReleaser;
+ if ( bWait ) osl_yieldThread();
+ */
+
+ return;
+ }
+ }
+ }
+
+ // next, select with or without timeout according to bWait.
+ int nFDs = nFDs_;
+ fd_set ReadFDS = aReadFDS_;
+ fd_set ExceptionFDS = aExceptionFDS_;
+ int nFound = 0;
+
+ timeval Timeout = noyield__;
+ timeval *pTimeout = &Timeout;
+
+ if (bWait)
+ {
+ pTimeout = 0;
+ if (m_aTimeout.tv_sec) // Timer is started.
+ {
+ // determine remaining timeout.
+ gettimeofday (&Timeout, 0);
+ Timeout = m_aTimeout - Timeout;
+ if (yield__ >= Timeout)
+ {
+ // guard against micro timeout.
+ Timeout = yield__;
+ }
+ pTimeout = &Timeout;
+ }
+ }
+
+ {
+ // release YieldMutex (and re-acquire at block end)
+ YieldMutexReleaser aReleaser;
+ nFound = select( nFDs, &ReadFDS, NULL, &ExceptionFDS, pTimeout );
+ }
+ if( nFound < 0 ) // error
+ {
+#ifdef DBG_UTIL
+ std::fprintf( stderr, "SalXLib::Yield e=%d f=%d\n", errno, nFound );
+#endif
+ if( EINTR == errno )
+ {
+ errno = 0;
+ }
+ }
+
+ // usually handle timeouts here (as in 5.2)
+ if (p_prioritize_timer == NULL)
+ CheckTimeout();
+
+ // handle wakeup events.
+ if ((nFound > 0) && (FD_ISSET(m_pTimeoutFDS[0], &ReadFDS)))
+ {
+ int buffer;
+ while (read (m_pTimeoutFDS[0], &buffer, sizeof(buffer)) > 0)
+ continue;
+ nFound -= 1;
+ }
+
+ // handle other events.
+ if( nFound > 0 )
+ {
+ // now we are in the protected section !
+ // recall select if we have acquired fd's, ready for reading,
+
+ struct timeval noTimeout = { 0, 0 };
+ nFound = select( nFDs_, &ReadFDS, NULL,
+ &ExceptionFDS, &noTimeout );
+
+ // someone-else has done the job for us
+ if (nFound == 0)
+ return;
+
+ for ( int nFD = 0; nFD < nFDs_; nFD++ )
+ {
+ YieldEntry* pEntry = &(yieldTable[nFD]);
+ if ( pEntry->fd )
+ {
+ if ( FD_ISSET( nFD, &ExceptionFDS ) ) {
+#if OSL_DEBUG_LEVEL > 1
+ std::fprintf( stderr, "SalXLib::Yield exception\n" );
+#endif
+ nFound--;
+ }
+ if ( FD_ISSET( nFD, &ReadFDS ) )
+ {
+ int nMaxEvents = bHandleAllCurrentEvents ? 100 : 1;
+ for( int i = 0; pEntry->IsEventQueued() && i < nMaxEvents; i++ )
+ {
+ pEntry->HandleNextEvent();
+ // if a recursive call has done the job
+ // so abort here
+ }
+ nFound--;
+ }
+ }
+ }
+ }
+}
+
+void SalXLib::Wakeup()
+{
+ write (m_pTimeoutFDS[1], "", 1);
+}
+
+void SalXLib::PostUserEvent()
+{
+ Wakeup();
+}
+
+const char* X11SalData::getFrameResName()
+{
+ /* according to ICCCM:
+ * first search command line for -name parameter
+ * then try RESOURCE_NAME environment variable
+ * then use argv[0] stripped by directories
+ */
+ static rtl::OStringBuffer aResName;
+ if( !aResName.getLength() )
+ {
+ int nArgs = osl_getCommandArgCount();
+ for( int n = 0; n < nArgs-1; n++ )
+ {
+ rtl::OUString aArg;
+ if( ! osl_getCommandArg( n, &aArg.pData ) &&
+ aArg.equalsIgnoreAsciiCaseAscii( "-name" ) &&
+ ! osl_getCommandArg( n+1, &aArg.pData ) )
+ {
+ aResName.append( rtl::OUStringToOString( aArg, osl_getThreadTextEncoding() ) );
+ break;
+ }
+ }
+ if( !aResName.getLength() )
+ {
+ const char* pEnv = getenv( "RESOURCE_NAME" );
+ if( pEnv && *pEnv )
+ aResName.append( pEnv );
+ }
+ if( !aResName.getLength() )
+ aResName.append( "VCLSalFrame" );
+ }
+ return aResName.getStr();
+}
+
+const char* X11SalData::getFrameClassName()
+{
+ static rtl::OStringBuffer aClassName;
+ if( !aClassName.getLength() )
+ {
+ rtl::OUString aIni, aProduct;
+ rtl::Bootstrap::get( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "BRAND_BASE_DIR" ) ), aIni );
+ aIni += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/program/" SAL_CONFIGFILE( "bootstrap" ) ) );
+ rtl::Bootstrap aBootstrap( aIni );
+ aBootstrap.getFrom( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ProductKey" ) ), aProduct );
+
+ if( aProduct.getLength() )
+ aClassName.append( rtl::OUStringToOString( aProduct, osl_getThreadTextEncoding() ) );
+ else
+ aClassName.append( "VCLSalFrame" );
+ }
+ return aClassName.getStr();
+}
+
+rtl::OString X11SalData::getFrameResName( SalExtStyle nStyle )
+{
+ rtl::OStringBuffer aBuf( 64 );
+ aBuf.append( getFrameResName() );
+ if( (nStyle & SAL_FRAME_EXT_STYLE_DOCUMENT) )
+ aBuf.append( ".DocumentWindow" );
+
+ return aBuf.makeStringAndClear();
+}
diff --git a/vcl/unx/source/app/saldisp.cxx b/vcl/unx/source/app/saldisp.cxx
new file mode 100644
index 000000000000..aa2afab93657
--- /dev/null
+++ b/vcl/unx/source/app/saldisp.cxx
@@ -0,0 +1,3446 @@
+/*************************************************************************
+ *
+ * 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 SAL_XT
+
+// -=-= #includes =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <sys/time.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+
+#if defined(SOLARIS)
+#include <sal/alloca.h>
+#include <osl/module.h>
+#endif
+
+#include <tools/prex.h>
+#include <X11/cursorfont.h>
+#include "salcursors.h"
+#include "invert50.h"
+#ifdef SOLARIS
+#define XK_KOREAN
+#endif
+#include <X11/keysym.h>
+
+#include <X11/Xatom.h>
+
+#ifdef USE_XINERAMA
+#ifdef USE_XINERAMA_XORG
+#if defined(X86) || defined(X86_64)
+#include <X11/extensions/Xinerama.h>
+#endif
+#elif defined USE_XINERAMA_XSUN
+#if defined(SOLARIS) && defined(INTEL) // missing extension header in standard installation
+#define MAXFRAMEBUFFERS 16
+Bool XineramaGetState(Display*, int);
+Status XineramaGetInfo(Display*, int, XRectangle*, unsigned char*, int*);
+#else
+#include <X11/extensions/xinerama.h>
+#endif
+#else
+#error USE_XINERAMA but no xinerama version
+#endif
+#endif
+
+#include <tools/postx.h>
+
+#include <salunx.h>
+#include <sal/types.h>
+#include "i18n_im.hxx"
+#include "i18n_xkb.hxx"
+#include <saldisp.hxx>
+#include <saldata.hxx>
+#include <vcl/salinst.hxx>
+#include <salgdi.h>
+#include <salframe.h>
+#include <vcl/keycodes.hxx>
+#include <vcl/salbtype.hxx>
+#include <salbmp.h>
+#ifndef _OSL_THREADMUTEX_H_
+#include <osl/mutex.h>
+#endif
+#include <salobj.h>
+#include <sm.hxx>
+#include <wmadaptor.hxx>
+#include <dtint.hxx>
+
+#include <osl/socket.h>
+#include <poll.h>
+
+using namespace rtl;
+using namespace vcl_sal;
+
+// -=-= #defines -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#define PSEUDOCOLOR12
+#define PSEUDOCOLOR8
+#define TRUECOLOR24
+#define TRUECOLOR16
+#define TRUECOLOR15
+#define TRUECOLOR12
+#define TRUECOLOR8
+
+#define SALCOLOR_WHITE MAKE_SALCOLOR( 0xFF, 0xFF, 0xFF )
+#define SALCOLOR_BLACK MAKE_SALCOLOR( 0x00, 0x00, 0x00 )
+
+// -=-= Prototyps =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-= static variables -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+static const char* const VisualClassName[] = {
+ "StaticGray",
+ "GrayScale",
+ "StaticColor",
+ "PseudoColor",
+ "TrueColor",
+ "DirectColor"
+};
+
+static const char* const EventNames[] =
+{
+ NULL,
+ NULL,
+ "KeyPress",
+ "KeyRelease",
+ "ButtonPress",
+ "ButtonRelease",
+ "MotionNotify",
+ "EnterNotify",
+ "LeaveNotify",
+ "FocusIn",
+ "FocusOut",
+ "KeymapNotify",
+ "Expose",
+ "GraphicsExpose",
+ "NoExpose",
+ "VisibilityNotify",
+ "CreateNotify",
+ "DestroyNotify",
+ "UnmapNotify",
+ "MapNotify",
+ "MapRequest",
+ "ReparentNotify",
+ "ConfigureNotify",
+ "ConfigureRequest",
+ "GravityNotify",
+ "ResizeRequest",
+ "CirculateNotify",
+ "CirculateRequest",
+ "PropertyNotify",
+ "SelectionClear",
+ "SelectionRequest",
+ "SelectionNotify",
+ "ColormapNotify",
+ "ClientMessage",
+ "MappingNotify"
+};
+
+// -=-= global inline =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+inline const char *Null( const char *p ) { return p ? p : ""; }
+inline const char *GetEnv( const char *p ) { return Null( getenv( p ) ); }
+inline const char *KeyStr( KeySym n ) { return Null( XKeysymToString( n ) ); }
+
+inline const char *GetAtomName( Display *d, Atom a )
+{ return Null( XGetAtomName( d, a ) ); }
+
+inline double Hypothenuse( long w, long h )
+{ return sqrt( (double)((w*w)+(h*h)) ); }
+
+inline int ColorDiff( int r, int g, int b )
+{ return (r*r)+(g*g)+(b*b); }
+
+inline int ColorDiff( SalColor c1, int r, int g, int b )
+{ return ColorDiff( (int)SALCOLOR_RED (c1)-r,
+ (int)SALCOLOR_GREEN(c1)-g,
+ (int)SALCOLOR_BLUE (c1)-b ); }
+
+// -=-= global functions -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+static int sal_Shift( Pixel nMask )
+{
+ int i = 24;
+ if( nMask < 0x00010000 ) { nMask <<= 16; i -= 16; }
+ if( nMask < 0x01000000 ) { nMask <<= 8; i -= 8; }
+ if( nMask < 0x10000000 ) { nMask <<= 4; i -= 4; }
+ if( nMask < 0x40000000 ) { nMask <<= 2; i -= 2; }
+ if( nMask < 0x80000000 ) { nMask <<= 1; i -= 1; }
+ return i;
+}
+
+static int sal_significantBits( Pixel nMask )
+{
+ int nRotate = sizeof(Pixel)*4;
+ int nBits = 0;
+ while( nRotate-- )
+ {
+ if( nMask & 1 )
+ nBits++;
+ nMask >>= 1;
+ }
+ return nBits;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+static BOOL sal_GetVisualInfo( Display *pDisplay, XID nVID, XVisualInfo &rVI )
+{
+ int nInfos;
+ XVisualInfo aTemplate;
+ XVisualInfo*pInfos;
+
+ aTemplate.visualid = nVID;
+
+ pInfos = XGetVisualInfo( pDisplay, VisualIDMask, &aTemplate, &nInfos );
+ if( !pInfos )
+ return FALSE;
+
+ rVI = *pInfos;
+ XFree( pInfos );
+
+ DBG_ASSERT( rVI.visualid == nVID,
+ "sal_GetVisualInfo: could not get correct visual by visualId" );
+ return TRUE;
+}
+
+// ---------------------------------------------------------------------------
+
+// check wether displaystring is in format N.M or N. or just N
+// with N and M beeing natural numbers
+static BOOL
+sal_IsDisplayNumber( const char *pDisplayString )
+{
+ if ( ! isdigit(*pDisplayString) )
+ return FALSE;
+ while ( isdigit(*(++pDisplayString)) )
+ ; /* do nothing */
+
+ if ( *pDisplayString == '.' )
+ {
+ while ( isdigit(*(++pDisplayString)) )
+ ; /* do nothing */
+ }
+
+ return (*pDisplayString == '\0');
+}
+
+// check whether host1 and host2 point to the same ip address
+static BOOL
+sal_EqualHosts( const OUString& Host1, const OUString& Host2)
+{
+ oslSocketAddr pHostAddr1;
+ oslSocketAddr pHostAddr2;
+ BOOL bEqualAddress = FALSE;
+
+ if ( Host1.toChar() >= '0' && Host1.toChar() <= '9' )
+ pHostAddr1 = osl_createInetSocketAddr( Host1.pData, 0 );
+ else
+ pHostAddr1 = osl_resolveHostname( Host1.pData );
+
+ if ( Host2.toChar() >= '0' && Host2.toChar() <= '9' )
+ pHostAddr2 = osl_createInetSocketAddr( Host2.pData, 0 );
+ else
+ pHostAddr2 = osl_resolveHostname( Host2.pData );
+
+ if( pHostAddr1 && pHostAddr2 )
+ bEqualAddress = osl_isEqualSocketAddr( pHostAddr1, pHostAddr2 ) ? TRUE : FALSE;
+
+ if( pHostAddr1 )
+ osl_destroySocketAddr( pHostAddr1 );
+ if( pHostAddr2 )
+ osl_destroySocketAddr( pHostAddr2 );
+
+ return bEqualAddress;
+}
+
+static BOOL
+sal_IsLocalDisplay( Display *pDisplay )
+{
+ const char *pDisplayString = DisplayString( pDisplay );
+
+ // no string, no idea
+ if ( pDisplayString == NULL || pDisplayString[ 0 ] == '\0')
+ return FALSE;
+
+ // check for ":x.y"
+ if ( pDisplayString[ 0 ] == ':' )
+ return sal_IsDisplayNumber( pDisplayString + 1 );
+
+ // check for fixed token which all mean localhost:x.y
+ const char pLocal[] = "localhost:";
+ const int nLocalLen = sizeof(pLocal) - 1;
+ if ( strncmp(pDisplayString, pLocal, nLocalLen) == 0 )
+ return sal_IsDisplayNumber( pDisplayString + nLocalLen );
+
+ const char pUnix[] = "unix:";
+ const int nUnixLen = sizeof(pUnix) - 1;
+ if ( strncmp(pDisplayString, pUnix, nUnixLen) == 0 )
+ return sal_IsDisplayNumber( pDisplayString + nUnixLen );
+
+ const char pLoopback[] = "127.0.0.1:";
+ const int nLoopbackLen= sizeof(pLoopback) - 1;
+ if ( strncmp(pDisplayString, pLoopback, nLoopbackLen) == 0 )
+ return sal_IsDisplayNumber( pDisplayString + nLoopbackLen );
+
+ // compare local hostname to displaystring, both may be ip address or
+ // hostname
+ BOOL bEqual = FALSE;
+ char *pDisplayHost = strdup( pDisplayString );
+ char *pPtr = strrchr( pDisplayHost, ':' );
+
+ if( pPtr != NULL )
+ {
+ const OUString& rLocalHostname( GetX11SalData()->GetLocalHostName() );
+ if( rLocalHostname.getLength() )
+ {
+ *pPtr = '\0';
+ OUString aDisplayHostname( pDisplayHost, strlen( pDisplayHost ), osl_getThreadTextEncoding() );
+ bEqual = sal_EqualHosts( rLocalHostname, aDisplayHostname );
+ bEqual = bEqual && sal_IsDisplayNumber( pPtr + 1 );
+ }
+ }
+ free( pDisplayHost );
+
+ return bEqual;
+}
+
+// ---------------------------------------------------------------------------
+// IsLocal means soffice is running on the same host as the xserver
+// since it is not called very often and sal_IsLocalDisplay() is relative
+// expensive bLocal_ is initialized on first call
+
+BOOL SalDisplay::IsLocal()
+{
+ if ( ! mbLocalIsValid )
+ {
+ bLocal_ = sal_IsLocalDisplay( pDisp_ );
+ mbLocalIsValid = TRUE;
+ }
+ return (BOOL)bLocal_;
+}
+
+// ---------------------------------------------------------------------------
+extern "C" srv_vendor_t
+sal_GetServerVendor( Display *p_display )
+{
+ typedef struct {
+ srv_vendor_t e_vendor; // vendor as enum
+ const char *p_name; // vendor name as returned by VendorString()
+ unsigned int n_len; // number of chars to compare
+ } vendor_t;
+
+ const vendor_t p_vendorlist[] = {
+ { vendor_xfree, "The XFree86 Project, Inc", 13 },
+ { vendor_sun, "Sun Microsystems, Inc.", 10 },
+ { vendor_attachmate, "Attachmate Corporation", 10 },
+ { vendor_excursion,
+ "DECWINDOWS DigitalEquipmentCorporation, eXcursion", 42 },
+ { vendor_hp, "Hewlett-Packard Company", 17 },
+ { vendor_hummingbird, "Hummingbird Communications Ltd.", 11 },
+ { vendor_ibm, "International Business Machines", 24 },
+ { vendor_sgi, "Silicon Graphics", 9 },
+ { vendor_sco, "The Santa Cruz Operation", 16 },
+ { vendor_xinside, "X Inside Inc.", 10 },
+ // allways the last entry: vendor_none to indicate eol
+ { vendor_none, NULL, 0 },
+ };
+
+#ifdef _USE_PRINT_EXTENSION_
+ if ( ! XSalIsDisplay( p_display ) )
+ return vendor_xprinter;
+#endif
+
+ // handle regular server vendors
+ char *p_name = ServerVendor( p_display );
+ vendor_t *p_vendor;
+ for (p_vendor = const_cast<vendor_t*>(p_vendorlist); p_vendor->e_vendor != vendor_none; p_vendor++)
+ {
+ if ( strncmp (p_name, p_vendor->p_name, p_vendor->n_len) == 0 )
+ return p_vendor->e_vendor;
+ }
+
+ // vendor not found in list
+ return vendor_unknown;
+}
+
+static sal_Bool sal_IsTrustedSolaris (Display *p_display)
+{
+ int n_numextensions = 0;
+ char **p_extensions = XListExtensions (p_display, &n_numextensions);
+ sal_Bool b_is = sal_False;
+
+ if (p_extensions != NULL)
+ {
+ for (int i = 0; !b_is && i < n_numextensions; i++)
+ b_is = (strcmp (p_extensions[i], "SUN_TSOL") == 0);
+ XFreeExtensionList (p_extensions);
+ }
+
+ return b_is;
+}
+
+// -=-= SalDisplay -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+BOOL SalDisplay::BestVisual( Display *pDisplay,
+ int nScreen,
+ XVisualInfo &rVI )
+{
+ VisualID nDefVID = XVisualIDFromVisual( DefaultVisual( pDisplay, nScreen ) );
+ VisualID nVID = 0;
+ char *pVID = getenv( "SAL_VISUAL" );
+ if( pVID )
+ sscanf( pVID, "%li", &nVID );
+
+ if( nVID && sal_GetVisualInfo( pDisplay, nVID, rVI ) )
+ return rVI.visualid == nDefVID;
+
+ XVisualInfo aVI;
+ aVI.screen = nScreen;
+ // get all visuals
+ int nVisuals;
+ XVisualInfo* pVInfos = XGetVisualInfo( pDisplay, VisualScreenMask,
+ &aVI, &nVisuals );
+ // pVInfos should contain at least one visual, otherwise
+ // we're in trouble
+ int* pWeight = (int*)alloca( sizeof(int)*nVisuals );
+ int i;
+ for( i = 0; i < nVisuals; i++ )
+ {
+ BOOL bUsable = FALSE;
+ int nTrueColor = 1;
+
+ if ( pVInfos[i].screen != nScreen )
+ {
+ bUsable = FALSE;
+ }
+ else
+ if( pVInfos[i].c_class == TrueColor )
+ {
+ nTrueColor = 2048;
+ if( pVInfos[i].depth == 24 )
+ bUsable = TRUE;
+#ifdef TRUECOLOR8
+ else if( pVInfos[i].depth == 8 )
+ {
+ nTrueColor = -1; // strongly discourage 8 bit true color
+ bUsable = TRUE;
+ }
+#endif
+#ifdef TRUECOLOR15
+ else if( pVInfos[i].depth == 15 )
+ bUsable = TRUE;
+#endif
+#ifdef TRUECOLOR16
+ else if( pVInfos[i].depth == 16 )
+ bUsable = TRUE;
+#endif
+#ifdef TRUECOLOR32
+ else if( pVInfos[i].depth == 32 )
+ {
+ nTrueColor = 256;
+ // we do not have use for an alpha channel
+ // better use a 24 or 16 bit truecolor visual if possible
+ bUsable = TRUE;
+ }
+#endif
+ }
+ else if( pVInfos[i].c_class == PseudoColor )
+ {
+ if( pVInfos[i].depth <= 8 )
+ bUsable = TRUE;
+#ifdef PSEUDOCOLOR12
+ else if( pVInfos[i].depth == 12 )
+ bUsable = TRUE;
+#endif
+ }
+ pWeight[ i ] = bUsable ? nTrueColor*pVInfos[i].depth : -1024;
+ pWeight[ i ] -= pVInfos[ i ].visualid;
+ }
+
+ int nBestVisual = 0;
+ int nBestWeight = -1024;
+ for( i = 0; i < nVisuals; i++ )
+ {
+ if( pWeight[ i ] > nBestWeight )
+ {
+ nBestWeight = pWeight[ i ];
+ nBestVisual = i;
+ }
+ }
+
+ rVI = pVInfos[ nBestVisual ];
+
+ XFree( pVInfos );
+ return rVI.visualid == nDefVID;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+SalDisplay::SalDisplay( Display *display ) :
+ mpInputMethod( NULL ),
+ mpFallbackFactory ( NULL ),
+ pDisp_( display ),
+ m_pWMAdaptor( NULL ),
+ m_pDtIntegrator( NULL ),
+ m_bUseRandRWrapper( true ),
+ m_nLastUserEventTime( CurrentTime )
+{
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "SalDisplay::SalDisplay()\n" );
+#endif
+ X11SalData *pSalData = GetX11SalData();
+
+ DBG_ASSERT( ! pSalData->GetDisplay(), "Second SalDisplay created !!!\n" );
+ pSalData->SetSalDisplay( this );
+
+ pXLib_ = pSalData->GetLib();
+ m_nDefaultScreen = DefaultScreen( pDisp_ );
+
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+SalDisplay::~SalDisplay( )
+{
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "SalDisplay::~SalDisplay()\n" );
+#endif
+ if( pDisp_ )
+ {
+ doDestruct();
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "display %p closed\n", pDisp_ );
+#endif
+ pDisp_ = NULL;
+ }
+ // don't do this in doDestruct since RandR extension adds hooks into Display
+ // that is XCloseDisplay still needs the RandR library if it was used
+ DeInitRandR();
+}
+
+void SalDisplay::doDestruct()
+{
+ X11SalData *pSalData = GetX11SalData();
+
+ delete m_pWMAdaptor;
+ m_pWMAdaptor = NULL;
+ delete m_pDtIntegrator;
+ m_pDtIntegrator = NULL;
+ X11SalBitmap::ImplDestroyCache();
+ X11SalGraphics::releaseGlyphPeer();
+ DestroyFontCache();
+
+ if( IsDisplay() )
+ {
+ delete mpInputMethod, mpInputMethod = (SalI18N_InputMethod*)ILLEGAL_POINTER;
+ delete mpKbdExtension, mpKbdExtension = (SalI18N_KeyboardExtension*)ILLEGAL_POINTER;
+
+ // do not call anything that could implicitly call back into
+ // this object after this point
+ osl_destroyMutex( hEventGuard_ );
+
+ for( unsigned int i = 0; i < m_aScreens.size(); i++ )
+ {
+ ScreenData& rData = m_aScreens[i];
+ if( rData.m_bInit )
+ {
+ if( rData.m_aMonoGC != rData.m_aCopyGC )
+ XFreeGC( pDisp_, rData.m_aMonoGC );
+ XFreeGC( pDisp_, rData.m_aCopyGC );
+ XFreeGC( pDisp_, rData.m_aAndInvertedGC );
+ XFreeGC( pDisp_, rData.m_aAndGC );
+ XFreeGC( pDisp_, rData.m_aOrGC );
+ XFreeGC( pDisp_, rData.m_aStippleGC );
+ XFreePixmap( pDisp_, rData.m_hInvert50 );
+ XDestroyWindow( pDisp_, rData.m_aRefWindow );
+ Colormap aColMap = rData.m_aColormap.GetXColormap();
+ if( aColMap != None && aColMap != DefaultColormap( pDisp_, i ) )
+ XFreeColormap( pDisp_, aColMap );
+ }
+ }
+
+ hEventGuard_ = (oslMutex)ILLEGAL_POINTER;
+
+ for( size_t i = 0; i < POINTER_COUNT; i++ )
+ {
+ if( aPointerCache_[i] )
+ XFreeCursor( pDisp_, aPointerCache_[i] );
+ }
+
+ pXLib_->Remove( ConnectionNumber( pDisp_ ) );
+ }
+
+ if( pSalData->GetDisplay() == this )
+ pSalData->SetSalDisplay( NULL );
+}
+
+static int DisplayHasEvent( int
+#ifdef DBG_UTIL
+fd
+#endif
+, SalX11Display *pDisplay )
+{
+ DBG_ASSERT( ConnectionNumber( pDisplay->GetDisplay() ) == fd,
+ "wrong fd in DisplayHasEvent" );
+ if( ! pDisplay->IsDisplay() )
+ return 0;
+
+ vos::IMutex* pSalInstYieldMutex =
+ GetSalData()->m_pInstance->GetYieldMutex();
+ ::vos::OGuard aGuard( *pSalInstYieldMutex );
+ return pDisplay->IsEvent();
+}
+static int DisplayQueue( int
+#ifdef DBG_UTIL
+fd
+#endif
+, SalX11Display *pDisplay )
+{
+ DBG_ASSERT( ConnectionNumber( pDisplay->GetDisplay() ) == fd,
+ "wrong fd in DisplayHasEvent" );
+ vos::IMutex* pSalInstYieldMutex =
+ GetSalData()->m_pInstance->GetYieldMutex();
+ ::vos::OGuard aGuard( *pSalInstYieldMutex );
+ return XEventsQueued( pDisplay->GetDisplay(),
+ QueuedAfterReading );
+}
+static int DisplayYield( int
+#ifdef DBG_UTIL
+fd
+#endif
+, SalX11Display *pDisplay )
+{
+ DBG_ASSERT( ConnectionNumber( pDisplay->GetDisplay() ) == fd,
+ "wrong fd in DisplayHasEvent" );
+ vos::IMutex* pSalInstYieldMutex =
+ GetSalData()->m_pInstance->GetYieldMutex();
+ ::vos::OGuard aGuard( *pSalInstYieldMutex );
+ pDisplay->Yield();
+ return TRUE;
+}
+
+SalX11Display::SalX11Display( Display *display )
+ : SalDisplay( display )
+{
+ Init();
+
+ pXLib_->Insert( ConnectionNumber( pDisp_ ),
+ this,
+ (YieldFunc) DisplayHasEvent,
+ (YieldFunc) DisplayQueue,
+ (YieldFunc) DisplayYield );
+}
+
+SalX11Display::~SalX11Display()
+{
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "SalX11Display::~SalX11Display()\n" );
+#endif
+ if( pDisp_ )
+ {
+ doDestruct();
+ XCloseDisplay( pDisp_ );
+ pDisp_ = NULL;
+ }
+}
+
+void SalDisplay::initScreen( int nScreen ) const
+{
+ if( nScreen < 0 || nScreen >= static_cast<int>(m_aScreens.size()) )
+ nScreen = m_nDefaultScreen;
+ ScreenData& rSD = const_cast<ScreenData&>(m_aScreens[nScreen]);
+ if( rSD.m_bInit )
+ return;
+ rSD.m_bInit = true;
+
+ XVisualInfo aVI;
+ Colormap aColMap;
+
+ if( SalDisplay::BestVisual( pDisp_, nScreen, aVI ) ) // DefaultVisual
+ aColMap = DefaultColormap( pDisp_, nScreen );
+ else
+ aColMap = XCreateColormap( pDisp_,
+ RootWindow( pDisp_, nScreen ),
+ aVI.visual,
+ AllocNone );
+
+ Screen* pScreen = ScreenOfDisplay( pDisp_, nScreen );
+
+ rSD.m_aSize = Size( WidthOfScreen( pScreen ), HeightOfScreen( pScreen ) );
+ rSD.m_aRoot = RootWindow( pDisp_, nScreen );
+ rSD.m_aVisual = SalVisual( &aVI );
+ rSD.m_aColormap = SalColormap( this, aColMap, nScreen );
+
+ // we're interested in configure notification of root windows
+ InitRandR( rSD.m_aRoot );
+
+ // - - - - - - - - - - Reference Window/Default Drawable - -
+ XSetWindowAttributes aXWAttributes;
+ aXWAttributes.border_pixel = 0;
+ aXWAttributes.background_pixel = 0;
+ aXWAttributes.colormap = aColMap;
+ rSD.m_aRefWindow = XCreateWindow( pDisp_,
+ rSD.m_aRoot,
+ 0,0, 16,16, 0,
+ rSD.m_aVisual.GetDepth(),
+ InputOutput,
+ rSD.m_aVisual.GetVisual(),
+ CWBorderPixel|CWBackPixel|CWColormap,
+ &aXWAttributes );
+
+ // set client leader (session id gets set when session is started)
+ if( rSD.m_aRefWindow )
+ {
+ // client leader must have WM_CLIENT_LEADER pointing to itself
+ XChangeProperty( pDisp_,
+ rSD.m_aRefWindow,
+ XInternAtom( pDisp_, "WM_CLIENT_LEADER", False ),
+ XA_WINDOW,
+ 32,
+ PropModeReplace,
+ (unsigned char*)&rSD.m_aRefWindow,
+ 1
+ );
+
+ ByteString aExec( SessionManagerClient::getExecName(), osl_getThreadTextEncoding() );
+ const char* argv[2];
+ argv[0] = "/bin/sh";
+ argv[1] = aExec.GetBuffer();
+ XSetCommand( pDisp_, rSD.m_aRefWindow, const_cast<char**>(argv), 2 );
+ XSelectInput( pDisp_, rSD.m_aRefWindow, PropertyChangeMask );
+
+ // - - - - - - - - - - GCs - - - - - - - - - - - - - - - - -
+ XGCValues values;
+ values.graphics_exposures = False;
+ values.fill_style = FillOpaqueStippled;
+ values.background = (1<<rSD.m_aVisual.GetDepth())-1;
+ values.foreground = 0;
+
+ rSD.m_aCopyGC = XCreateGC( pDisp_,
+ rSD.m_aRefWindow,
+ GCGraphicsExposures
+ | GCForeground
+ | GCBackground,
+ &values );
+ rSD.m_aAndInvertedGC= XCreateGC( pDisp_,
+ rSD.m_aRefWindow,
+ GCGraphicsExposures
+ | GCForeground
+ | GCBackground,
+ &values );
+ rSD.m_aAndGC = XCreateGC( pDisp_,
+ rSD.m_aRefWindow,
+ GCGraphicsExposures
+ | GCForeground
+ | GCBackground,
+ &values );
+ rSD.m_aOrGC = XCreateGC( pDisp_,
+ rSD.m_aRefWindow,
+ GCGraphicsExposures
+ | GCForeground
+ | GCBackground,
+ &values );
+ rSD.m_aStippleGC = XCreateGC( pDisp_,
+ rSD.m_aRefWindow,
+ GCGraphicsExposures
+ | GCFillStyle
+ | GCForeground
+ | GCBackground,
+ &values );
+
+ XSetFunction( pDisp_, rSD.m_aAndInvertedGC, GXandInverted );
+ XSetFunction( pDisp_, rSD.m_aAndGC, GXand );
+ // #44556# PowerPC Solaris 2.5 (XSun 3500) Bug: GXor = GXnop
+ //XSetFunction( pDisp_, pOrGC_, GXor );
+ XSetFunction( pDisp_, rSD.m_aOrGC, GXxor );
+
+ if( 1 == rSD.m_aVisual.GetDepth() )
+ {
+ XSetFunction( pDisp_, rSD.m_aCopyGC, GXcopyInverted );
+ rSD.m_aMonoGC = rSD.m_aCopyGC;
+ }
+ else
+ {
+ Pixmap hPixmap = XCreatePixmap( pDisp_, rSD.m_aRefWindow, 1, 1, 1 );
+ rSD.m_aMonoGC = XCreateGC( pDisp_,
+ hPixmap,
+ GCGraphicsExposures,
+ &values );
+ XFreePixmap( pDisp_, hPixmap );
+ }
+ rSD.m_hInvert50 = XCreateBitmapFromData( pDisp_,
+ rSD.m_aRefWindow,
+ invert50_bits,
+ invert50_width,
+ invert50_height );
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void SalDisplay::Init()
+{
+ for( size_t i = 0; i < POINTER_COUNT; i++ )
+ aPointerCache_[i] = None;
+
+ eWindowManager_ = otherwm;
+ nProperties_ = PROPERTY_DEFAULT;
+ hEventGuard_ = NULL;
+ m_pFontCache = NULL;
+ mpFontList = (XlfdStorage*)NULL;
+ mpFactory = (AttributeProvider*)NULL;
+ m_pCapture = NULL;
+ m_bXinerama = false;
+
+ int nDisplayScreens = ScreenCount( pDisp_ );
+ m_aScreens = std::vector<ScreenData>(nDisplayScreens);
+
+ mbExactResolution = false;
+ /* #i15507#
+ * Xft resolution should take precedence since
+ * it is what modern desktops use.
+ */
+ const char* pValStr = XGetDefault( pDisp_, "Xft", "dpi" );
+ if( pValStr != NULL )
+ {
+ const rtl::OString aValStr( pValStr );
+ const long nDPI = (long) aValStr.toDouble();
+ // guard against insane resolution
+ if( (nDPI >= 50) && (nDPI <= 500) )
+ {
+ aResolution_ = Pair( nDPI, nDPI );
+ mbExactResolution = true;
+ }
+ }
+ if( mbExactResolution == false )
+ {
+ aResolution_ =
+ Pair( DPI( WidthOfScreen( DefaultScreenOfDisplay( pDisp_ ) ), DisplayWidthMM ( pDisp_, m_nDefaultScreen ) ),
+ DPI( HeightOfScreen( DefaultScreenOfDisplay( pDisp_ ) ), DisplayHeightMM( pDisp_, m_nDefaultScreen ) ) );
+ }
+
+ nMaxRequestSize_ = XExtendedMaxRequestSize( pDisp_ ) * 4;
+ if( !nMaxRequestSize_ )
+ nMaxRequestSize_ = XMaxRequestSize( pDisp_ ) * 4;
+
+ SetServerVendor();
+ X11SalBitmap::ImplCreateCache();
+
+ hEventGuard_ = osl_createMutex();
+ bLocal_ = FALSE; /* dont care, initialize later by
+ calling SalDisplay::IsLocal() */
+ mbLocalIsValid = FALSE; /* bLocal_ is not yet initialized */
+
+ // - - - - - - - - - - Synchronize - - - - - - - - - - - - -
+ if( getenv( "SAL_SYNCHRONIZE" ) )
+ XSynchronize( pDisp_, True );
+
+ // - - - - - - - - - - Keyboardmapping - - - - - - - - - - -
+ ModifierMapping();
+
+ // - - - - - - - - - - Window Manager - - - - - - - - - - -
+ m_pWMAdaptor = ::vcl_sal::WMAdaptor::createWMAdaptor( this );
+ const char *pWM = getenv( "SAL_WM" );
+ if( pWM )
+ {
+ long int nWM = 0;
+ sscanf( pWM, "%li", &nWM );
+ eWindowManager_ = SalWM(nWM);
+ }
+ else if( XInternAtom( pDisp_, "_SGI_TELL_WM", True ) )
+ eWindowManager_ = FourDwm;
+ else if( XInternAtom( pDisp_, "KWM_RUNNING", True ) )
+ eWindowManager_ = mwm; // naja, eigentlich kwm ...
+ else if( XInternAtom( pDisp_, "_OL_WIN_ATTR", True ) )
+ eWindowManager_ = olwm;
+ else if( m_pWMAdaptor->getWindowManagerName().EqualsAscii( "Dtwm" ) )
+ eWindowManager_ = dtwm;
+
+ // - - - - - - - - - - Properties - - - - - - - - - - - - -
+ const char *pProperties = getenv( "SAL_PROPERTIES" );
+ if( pProperties )
+ sscanf( pProperties, "%li", &nProperties_ );
+ else
+ {
+#if defined DBG_UTIL || defined SUN || defined LINUX || defined FREEBSD
+ nProperties_ |= PROPERTY_FEATURE_Maximize;
+#endif
+ // Server Bugs & Properties
+ if( GetServerVendor() == vendor_excursion )
+ {
+ nProperties_ |= PROPERTY_BUG_Stipple;
+ nProperties_ |= PROPERTY_BUG_DrawLine;
+ nProperties_ &= ~PROPERTY_SUPPORT_XSetClipMask;
+ }
+ else
+ if( GetServerVendor() == vendor_attachmate )
+ {
+ nProperties_ |= PROPERTY_BUG_CopyPlane_RevertBWPixel;
+ }
+ else
+ if( GetServerVendor() == vendor_ibm )
+ {
+ nProperties_ |= PROPERTY_BUG_XA_FAMILY_NAME_nil;
+
+ if( otherwm == eWindowManager_ ) eWindowManager_ = mwm;
+ }
+ else
+ if( GetServerVendor() == vendor_xfree )
+ {
+ nProperties_ |= PROPERTY_BUG_XCopyArea_GXxor;
+#if defined LINUX || defined FREEBSD
+ // otherwm and olwm are a kind of default, which are not detected
+ // carefully. if we are running linux (i.e. not netbsd) on an xfree
+ // display, fvwm is most probable the wm to choose, confusing with mwm
+ // doesn't harm. #57791# start maximized if possible
+ if( (otherwm == eWindowManager_)
+ || (olwm == eWindowManager_ ))
+ {
+ eWindowManager_ = fvwm; // ???
+ nProperties_ |= PROPERTY_FEATURE_Maximize;
+ }
+#else
+ if( otherwm == eWindowManager_ ) eWindowManager_ = winmgr;
+#endif
+#if defined SOLARIS && defined SPARC
+ nProperties_ |= PROPERTY_BUG_Bitmap_Bit_Order;
+ // solaris xlib seems to have problems with putting images
+ // in correct bit order to xfree 8 bit displays
+#endif
+ }
+ else
+ if( GetServerVendor() == vendor_sun )
+ {
+ // nicht alle! (bekannt: nur Sparc II CG3, CG6?)
+ nProperties_ &= ~PROPERTY_SUPPORT_XSetClipMask;
+
+ // trusted solaris doesn't allow to change properties on the
+ // wm decoration window
+ if (sal_IsTrustedSolaris (pDisp_))
+ nProperties_ |= PROPERTY_FEATURE_TrustedSolaris;
+
+ // Fehler im Sun-Solaris X86 Server !
+ if (ImageByteOrder(GetDisplay()) == LSBFirst)
+ {
+ nProperties_ |= PROPERTY_BUG_Tile;
+ nProperties_ |= PROPERTY_SUPPORT_3ButtonMouse;
+ }
+ else // MSBFirst Sun-Solaris Sparc Server
+ {
+ // XCopyPlane reverts black and white for 1bit bitmaps
+ // only sun, only 8bit pseudocolor target
+ if ( (GetVisual(m_nDefaultScreen).GetDepth() == 8)
+ && (GetVisual(m_nDefaultScreen).GetClass() == PseudoColor))
+ nProperties_ |= PROPERTY_BUG_CopyPlane_RevertBWPixel;
+ // Fehler in Solaris 2.5.1
+ if (VendorRelease ( GetDisplay() ) < 3600)
+ nProperties_ |= PROPERTY_BUG_FillPolygon_Tile;
+ }
+
+ if( otherwm == eWindowManager_ )
+ eWindowManager_ = olwm;
+ }
+ else
+ if( GetServerVendor() == vendor_sco )
+ {
+ if( otherwm == eWindowManager_ ) eWindowManager_ = pmwm;
+ }
+ else
+ if( GetServerVendor() == vendor_sgi )
+ {
+ if( GetVisual( m_nDefaultScreen ).GetDepth() > 8 && GetVisual( m_nDefaultScreen ).GetDepth() <= 16 )
+ nProperties_ |= PROPERTY_BUG_XCopyArea_GXxor;
+ nProperties_ |= PROPERTY_SUPPORT_XSetClipMask;
+
+ if( otherwm == eWindowManager_ )
+ eWindowManager_ = FourDwm;
+ }
+ else
+ if( GetServerVendor() == vendor_hp )
+ {
+ if( otherwm == eWindowManager_ ) eWindowManager_ = dtwm;
+ }
+ else
+ if( GetServerVendor() == vendor_hummingbird )
+ {
+ if (GetVisual(m_nDefaultScreen).GetDepth() == 24)
+ nProperties_ |= PROPERTY_BUG_CopyArea_OnlySmallSlices;
+ }
+
+ if( otherwm == eWindowManager_ )
+ {
+ if( !XInternAtom( pDisp_, "_MOTIF_WM_INFO", True ) )
+ eWindowManager_ = olwm;
+ // ???
+ }
+
+ if( winmgr == eWindowManager_ )
+ {
+ nProperties_ &= ~PROPERTY_SUPPORT_WM_SetPos;
+ nProperties_ &= ~PROPERTY_SUPPORT_WM_Screen;
+ nProperties_ |= PROPERTY_FEATURE_Maximize;
+ }
+ else if( dtwm == eWindowManager_ )
+ {
+ nProperties_ &= ~PROPERTY_SUPPORT_WM_ClientPos;
+ }
+ else if( pmwm == eWindowManager_ )
+ {
+ nProperties_ &= ~PROPERTY_SUPPORT_WM_ClientPos;
+ }
+ }
+
+ InitXinerama();
+
+ // initialize system settings update
+ m_pDtIntegrator = DtIntegrator::CreateDtIntegrator();
+
+#ifdef DBG_UTIL
+ PrintInfo();
+#endif
+}
+
+// Sound
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void SalDisplay::Beep() const
+{
+ XBell( pDisp_, 0 );
+}
+
+// Keyboard
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+String SalDisplay::GetKeyNameFromKeySym( KeySym nKeySym ) const
+{
+ String aRet;
+
+ // return an empty string for keysyms that are not bound to
+ // any key code
+ XLIB_KeyCode aKeyCode = XKeysymToKeycode( GetDisplay(), nKeySym );
+ if( aKeyCode != 0 && aKeyCode != NoSymbol )
+ {
+ if( !nKeySym )
+ aRet = String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "???" ) );
+ else
+ {
+ aRet = ::vcl_sal::getKeysymReplacementName( const_cast<SalDisplay*>(this)->GetKeyboardName(), nKeySym );
+ if( ! aRet.Len() )
+ {
+ const char *pString = XKeysymToString( nKeySym );
+ int n = strlen( pString );
+ if( n > 2 && pString[n-2] == '_' )
+ aRet = String( pString, n-2, RTL_TEXTENCODING_ISO_8859_1 );
+ else
+ aRet = String( pString, n, RTL_TEXTENCODING_ISO_8859_1 );
+ }
+ }
+ }
+ return aRet;
+}
+
+inline KeySym sal_XModifier2Keysym( Display *pDisplay,
+ XModifierKeymap *pXModMap,
+ int n )
+{
+ return XKeycodeToKeysym( pDisplay,
+ pXModMap->modifiermap[n*pXModMap->max_keypermod],
+ 0 );
+}
+
+void SalDisplay::ModifierMapping()
+{
+ XModifierKeymap *pXModMap = XGetModifierMapping( pDisp_ );
+
+ bNumLockFromXS_ = True;
+ nShiftKeySym_ = sal_XModifier2Keysym( pDisp_, pXModMap, ShiftMapIndex );
+ nCtrlKeySym_ = sal_XModifier2Keysym( pDisp_, pXModMap, ControlMapIndex );
+ nMod1KeySym_ = sal_XModifier2Keysym( pDisp_, pXModMap, Mod1MapIndex );
+ // Auf Sun-Servern und SCO-Severn beruecksichtigt XLookupString
+ // nicht den NumLock Modifier.
+ if( (GetServerVendor() == vendor_sun)
+ || (GetServerVendor() == vendor_sco) )
+ {
+ XLIB_KeyCode aNumLock = XKeysymToKeycode( pDisp_, XK_Num_Lock );
+
+ if( aNumLock ) for( int i = ShiftMapIndex; i <= Mod5MapIndex; i++ )
+ {
+ if( pXModMap->modifiermap[i*pXModMap->max_keypermod] == aNumLock )
+ {
+ bNumLockFromXS_ = False;
+ nNumLockIndex_ = i;
+ nNumLockMask_ = 1<<i;
+ break;
+ }
+ }
+ }
+
+ XFreeModifiermap( pXModMap );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+XubString SalDisplay::GetKeyName( USHORT nKeyCode ) const
+{
+ String aStrMap;
+
+ if( nKeyCode & KEY_MOD1 )
+ aStrMap += GetKeyNameFromKeySym( nCtrlKeySym_ );
+
+ if( nKeyCode & KEY_MOD2 )
+ {
+ if( aStrMap.Len() )
+ aStrMap += '+';
+ aStrMap += GetKeyNameFromKeySym( nMod1KeySym_ );
+ }
+
+ if( nKeyCode & KEY_SHIFT )
+ {
+ if( aStrMap.Len() )
+ aStrMap += '+';
+ aStrMap += GetKeyNameFromKeySym( nShiftKeySym_ );
+ }
+ nKeyCode &= 0x0FFF;
+
+ KeySym nKeySym = 0;
+
+ if( KEY_0 <= nKeyCode && nKeyCode <= KEY_9 )
+ nKeySym = XK_0 + (nKeyCode - KEY_0);
+ else if( KEY_A <= nKeyCode && nKeyCode <= KEY_Z )
+ nKeySym = XK_A + (nKeyCode - KEY_A);
+ else if( KEY_F1 <= nKeyCode && nKeyCode <= KEY_F26 ) // Existiert die Taste
+ nKeySym = XK_F1 + (nKeyCode - KEY_F1);
+ else switch( nKeyCode )
+ {
+ case KEY_DOWN:
+ nKeySym = XK_Down;
+ break;
+ case KEY_UP:
+ nKeySym = XK_Up;
+ break;
+ case KEY_LEFT:
+ nKeySym = XK_Left;
+ break;
+ case KEY_RIGHT:
+ nKeySym = XK_Right;
+ break;
+ case KEY_HOME:
+ nKeySym = XK_Home;
+ break;
+ case KEY_END:
+ nKeySym = XK_End;
+ break;
+ case KEY_PAGEUP:
+ nKeySym = XK_Prior;
+ break;
+ case KEY_PAGEDOWN:
+ nKeySym = XK_Next;
+ break;
+ case KEY_RETURN:
+ nKeySym = XK_Return;
+ break;
+ case KEY_ESCAPE:
+ nKeySym = XK_Escape;
+ break;
+ case KEY_TAB:
+ nKeySym = XK_Tab;
+ break;
+ case KEY_BACKSPACE:
+ nKeySym = XK_BackSpace;
+ break;
+ case KEY_SPACE:
+ nKeySym = XK_space;
+ break;
+ case KEY_INSERT:
+ nKeySym = XK_Insert;
+ break;
+ case KEY_DELETE:
+ nKeySym = XK_Delete;
+ break;
+
+ #if !defined (SunXK_Undo)
+ #define SunXK_Stop 0x0000FF69 // XK_Cancel
+ #define SunXK_Props 0x1005FF70
+ #define SunXK_Front 0x1005FF71
+ #define SunXK_Copy 0x1005FF72
+ #define SunXK_Open 0x1005FF73
+ #define SunXK_Paste 0x1005FF74
+ #define SunXK_Cut 0x1005FF75
+ #endif
+
+ case KEY_REPEAT:
+ nKeySym = XK_Redo;
+ break;
+ case KEY_PROPERTIES:
+ nKeySym = SunXK_Props;
+ break;
+ case KEY_UNDO:
+ nKeySym = XK_Undo;
+ break;
+ case KEY_FRONT:
+ nKeySym = SunXK_Front;
+ break;
+ case KEY_COPY:
+ nKeySym = SunXK_Copy;
+ break;
+ case KEY_OPEN:
+ nKeySym = SunXK_Open;
+ break;
+ case KEY_PASTE:
+ nKeySym = SunXK_Paste;
+ break;
+ case KEY_FIND:
+ nKeySym = XK_Find;
+ break;
+ case KEY_CUT:
+ nKeySym = GetServerVendor() == vendor_sun ? SunXK_Cut : XK_L10;
+ break;
+ case KEY_ADD:
+ nKeySym = XK_plus;
+ break;
+ case KEY_SUBTRACT:
+ nKeySym = XK_minus;
+ break;
+ case KEY_MULTIPLY:
+ nKeySym = XK_asterisk;
+ break;
+ case KEY_DIVIDE:
+ nKeySym = XK_slash;
+ break;
+ case KEY_POINT:
+ nKeySym = XK_period;
+ break;
+ case KEY_COMMA:
+ nKeySym = XK_comma;
+ break;
+ case KEY_LESS:
+ nKeySym = XK_less;
+ break;
+ case KEY_GREATER:
+ nKeySym = XK_greater;
+ break;
+ case KEY_EQUAL:
+ nKeySym = XK_equal;
+ break;
+ case KEY_HELP:
+ nKeySym = XK_Help;
+ break;
+ case KEY_HANGUL_HANJA:
+ nKeySym = XK_Hangul_Hanja;
+ break;
+ case KEY_TILDE:
+ nKeySym = XK_asciitilde;
+ break;
+ case KEY_QUOTELEFT:
+ nKeySym = XK_grave;
+ break;
+
+ default:
+ nKeySym = 0;
+ break;
+ }
+
+ if( nKeySym )
+ {
+ String aKeyName = GetKeyNameFromKeySym( nKeySym );
+ if( aKeyName.Len() )
+ {
+ if( aStrMap.Len() )
+ aStrMap += '+';
+ aStrMap += aKeyName;
+ }
+ else
+ aStrMap.Erase();
+ }
+ else
+ aStrMap.Erase();
+
+ return aStrMap;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#ifndef IsISOKey
+#define IsISOKey( n ) (0x0000FE00==((n)&0xFFFFFF00))
+#endif
+
+USHORT SalDisplay::GetKeyCode( KeySym keysym, char*pcPrintable ) const
+{
+ USHORT nKey = 0;
+
+ if( XK_a <= keysym && XK_z >= keysym )
+ nKey = (USHORT)(KEY_A + (keysym - XK_a));
+ else if( XK_A <= keysym && XK_Z >= keysym )
+ nKey = (USHORT)(KEY_A + (keysym - XK_A));
+ else if( XK_0 <= keysym && XK_9 >= keysym )
+ nKey = (USHORT)(KEY_0 + (keysym - XK_0));
+ else if( IsModifierKey( keysym ) )
+ ;
+ else if( IsKeypadKey( keysym ) )
+ {
+ if( (keysym >= XK_KP_0) && (keysym <= XK_KP_9) )
+ {
+ nKey = (USHORT)(KEY_0 + (keysym - XK_KP_0));
+ *pcPrintable = '0' + nKey - KEY_0;
+ }
+ else if( IsPFKey( keysym ) )
+ nKey = (USHORT)(KEY_F1 + (keysym - XK_KP_F1));
+ else switch( keysym )
+ {
+ case XK_KP_Space:
+ nKey = KEY_SPACE;
+ *pcPrintable = ' ';
+ break;
+ case XK_KP_Tab:
+ nKey = KEY_TAB;
+ break;
+ case XK_KP_Enter:
+ nKey = KEY_RETURN;
+ break;
+ case XK_KP_Begin:
+ case XK_KP_Home:
+ nKey = KEY_HOME;
+ break;
+ case XK_KP_Left:
+ nKey = KEY_LEFT;
+ break;
+ case XK_KP_Up:
+ nKey = KEY_UP;
+ break;
+ case XK_KP_Right:
+ nKey = KEY_RIGHT;
+ break;
+ case XK_KP_Down:
+ nKey = KEY_DOWN;
+ break;
+ case XK_KP_Prior: // XK_KP_Page_Up
+ nKey = KEY_PAGEUP;
+ break;
+ case XK_KP_Next: // XK_KP_Page_Down
+ nKey = KEY_PAGEDOWN;
+ break;
+ case XK_KP_End:
+ nKey = KEY_END;
+ break;
+ case XK_KP_Insert:
+ nKey = KEY_INSERT;
+ break;
+ case XK_KP_Delete:
+ nKey = KEY_DELETE;
+ break;
+ case XK_KP_Equal:
+ nKey = KEY_EQUAL;
+ *pcPrintable = '=';
+ break;
+ case XK_KP_Multiply:
+ nKey = KEY_MULTIPLY;
+ *pcPrintable = '*';
+ break;
+ case XK_KP_Add:
+ nKey = KEY_ADD;
+ *pcPrintable = '+';
+ break;
+ case XK_KP_Separator:
+ nKey = KEY_DECIMAL;
+ *pcPrintable = ',';
+ break;
+ case XK_KP_Subtract:
+ nKey = KEY_SUBTRACT;
+ *pcPrintable = '-';
+ break;
+ case XK_KP_Decimal:
+ nKey = KEY_DECIMAL;
+ *pcPrintable = '.';
+ break;
+ case XK_KP_Divide:
+ nKey = KEY_DIVIDE;
+ *pcPrintable = '/';
+ break;
+ }
+ }
+ else if( IsFunctionKey( keysym ) )
+ {
+ if( bNumLockFromXS_ )
+ {
+ if( keysym >= XK_F1 && keysym <= XK_F26 )
+ nKey = (USHORT)(KEY_F1 + keysym - XK_F1);
+ }
+ else switch( keysym )
+ {
+ // - - - - - Sun X-Server Tastatur ohne Cursorblock ??? - - -
+ case XK_R7: // XK_F27:
+ nKey = KEY_HOME;
+ break;
+ case XK_R8: // XK_F28:
+ nKey = KEY_UP;
+ break;
+ case XK_R9: // XK_F29:
+ nKey = KEY_PAGEUP;
+ break;
+ case XK_R10: // XK_F30:
+ nKey = KEY_LEFT;
+ break;
+ case XK_R11: // XK_F31:
+ nKey = 0; // KEY_F31
+ break;
+ case XK_R12: // XK_F32:
+ nKey = KEY_RIGHT;
+ break;
+ case XK_R13: // XK_F33:
+ nKey = KEY_END;
+ break;
+ case XK_R14: // XK_F34:
+ nKey = KEY_DOWN;
+ break;
+ case XK_R15: // XK_F35:
+ nKey = KEY_PAGEDOWN;
+ break;
+ // - - - - - Sun X-Server Tastatur ??? - - - - - - - - - - - -
+ case XK_L1: // XK_F11:
+ nKey = KEY_F11; // on a sun keyboard this actually is usally SunXK_Stop,
+ // but VCL doesn't have a key defintion for that
+ break;
+ case XK_L2: // XK_F12:
+ if ( GetServerVendor() == vendor_sun )
+ nKey = KEY_REPEAT;
+ else
+ nKey = KEY_F12;
+ break;
+ case XK_L3: // XK_F13:
+ nKey = KEY_PROPERTIES; // KEY_F13
+ break;
+ case XK_L4: // XK_F14:
+ nKey = KEY_UNDO; // KEY_F14
+ break;
+ case XK_L5: // XK_F15:
+ nKey = KEY_F15; // KEY_FRONT
+ break;
+ case XK_L6: // XK_F16:
+ nKey = KEY_COPY; // KEY_F16
+ break;
+ case XK_L7: // XK_F17:
+ nKey = KEY_F17; // KEY_OPEN
+ break;
+ case XK_L8: // XK_F18:
+ nKey = KEY_PASTE; // KEY_F18
+ break;
+ case XK_L9: // XK_F19:
+ nKey = KEY_F19; // KEY_FIND
+ break;
+ case XK_L10: // XK_F20:
+ nKey = KEY_CUT; // KEY_F20
+ break;
+ default:
+ if( keysym >= XK_F1 && keysym <= XK_F26 )
+ nKey = (USHORT)(KEY_F1 + keysym - XK_F1);
+ break;
+ }
+ }
+ else if( IsCursorKey( keysym ) )
+ {
+ switch( keysym )
+ {
+ case XK_Begin:
+ case XK_Home:
+ nKey = KEY_HOME;
+ break;
+ case XK_Left:
+ nKey = KEY_LEFT;
+ break;
+ case XK_Up:
+ nKey = KEY_UP;
+ break;
+ case XK_Right:
+ nKey = KEY_RIGHT;
+ break;
+ case XK_Down:
+ nKey = KEY_DOWN;
+ break;
+ case XK_Prior: // XK_Page_Up
+ nKey = KEY_PAGEUP;
+ break;
+ case XK_Next: // XK_Page_Down
+ nKey = KEY_PAGEDOWN;
+ break;
+ case XK_End:
+ nKey = KEY_END;
+ break;
+ }
+ }
+ else if( IsMiscFunctionKey( keysym ) )
+ {
+ switch( keysym )
+ {
+ case XK_Insert:
+ nKey = KEY_INSERT;
+ break;
+ case XK_Redo:
+ nKey = KEY_REPEAT;
+ break;
+ case XK_Undo:
+ nKey = KEY_UNDO;
+ break;
+ case XK_Find:
+ nKey = KEY_FIND;
+ break;
+ case XK_Help:
+ nKey = KEY_HELP;
+ break;
+ case XK_Menu:
+ nKey = KEY_CONTEXTMENU;
+ break;
+/*
+ case XK_Break:
+ case XK_Select:
+ case XK_Execute:
+ case XK_Print:
+ case XK_Cancel:
+*/
+ }
+ }
+ else if( IsISOKey( keysym ) ) // XK_ISO_
+ {
+ switch( keysym )
+ {
+ case 0xFE20: // XK_ISO_Left_Tab:
+ nKey = KEY_TAB;
+ break;
+ }
+ }
+ else switch( keysym )
+ {
+ case XK_Return:
+ nKey = KEY_RETURN;
+ break;
+ case XK_BackSpace:
+ nKey = KEY_BACKSPACE;
+ break;
+ case XK_Delete:
+ nKey = KEY_DELETE;
+ break;
+ case XK_space:
+ nKey = KEY_SPACE;
+ break;
+ case XK_Tab:
+ nKey = KEY_TAB;
+ break;
+ case XK_Escape:
+ nKey = KEY_ESCAPE;
+ break;
+ case XK_plus:
+ nKey = KEY_ADD;
+ break;
+ case XK_minus:
+ nKey = KEY_SUBTRACT;
+ break;
+ case XK_asterisk:
+ nKey = KEY_MULTIPLY;
+ break;
+ case XK_slash:
+ nKey = KEY_DIVIDE;
+ break;
+ case XK_period:
+ nKey = KEY_POINT;
+ break;
+ case XK_comma:
+ nKey = KEY_COMMA;
+ break;
+ case XK_less:
+ nKey = KEY_LESS;
+ break;
+ case XK_greater:
+ nKey = KEY_GREATER;
+ break;
+ case XK_equal:
+ nKey = KEY_EQUAL;
+ break;
+ case XK_Hangul_Hanja:
+ nKey = KEY_HANGUL_HANJA;
+ break;
+ case XK_asciitilde:
+ nKey = KEY_TILDE;
+ *pcPrintable = '~';
+ break;
+ case XK_grave:
+ nKey = KEY_QUOTELEFT;
+ *pcPrintable = '`';
+ break;
+// case XK_Linefeed:
+// *pcPrintable = '\n';
+// break;
+ // - - - - - - - - - - - - - Apollo - - - - - - - - - - - - - 0x1000
+ case 0x1000FF02: // apXK_Copy
+ nKey = KEY_COPY;
+ break;
+ case 0x1000FF03: // apXK_Cut
+ nKey = KEY_CUT;
+ break;
+ case 0x1000FF04: // apXK_Paste
+ nKey = KEY_PASTE;
+ break;
+ case 0x1000FF14: // apXK_Repeat
+ nKey = KEY_REPEAT;
+ break;
+ // Exit, Save
+ // - - - - - - - - - - - - - - D E C - - - - - - - - - - - - - 0x1000
+ case 0x1000FF00:
+ nKey = KEY_DELETE;
+ break;
+ // - - - - - - - - - - - - - - H P - - - - - - - - - - - - - 0x1000
+ case 0x1000FF73: // hpXK_DeleteChar
+ nKey = KEY_DELETE;
+ break;
+ case 0x1000FF74: // hpXK_BackTab
+ case 0x1000FF75: // hpXK_KP_BackTab
+ nKey = KEY_TAB;
+ break;
+ // - - - - - - - - - - - - - - I B M - - - - - - - - - - - - -
+ // - - - - - - - - - - - - - - O S F - - - - - - - - - - - - - 0x1004
+ case 0x1004FF02: // osfXK_Copy
+ nKey = KEY_COPY;
+ break;
+ case 0x1004FF03: // osfXK_Cut
+ nKey = KEY_CUT;
+ break;
+ case 0x1004FF04: // osfXK_Paste
+ nKey = KEY_PASTE;
+ break;
+ case 0x1004FF07: // osfXK_BackTab
+ nKey = KEY_TAB;
+ break;
+ case 0x1004FF08: // osfXK_BackSpace
+ nKey = KEY_BACKSPACE;
+ break;
+ case 0x1004FF1B: // osfXK_Escape
+ nKey = KEY_ESCAPE;
+ break;
+ // Up, Down, Left, Right, PageUp, PageDown
+ // - - - - - - - - - - - - - - S C O - - - - - - - - - - - - -
+ // - - - - - - - - - - - - - - S G I - - - - - - - - - - - - - 0x1007
+ // - - - - - - - - - - - - - - S N I - - - - - - - - - - - - -
+ // - - - - - - - - - - - - - - S U N - - - - - - - - - - - - - 0x1005
+ case 0x1005FF10: // SunXK_F36
+ nKey = KEY_F11;
+ break;
+ case 0x1005FF11: // SunXK_F37
+ nKey = KEY_F12;
+ break;
+ case 0x1005FF70: // SunXK_Props
+ nKey = KEY_PROPERTIES;
+ break;
+ case 0x1005FF71: // SunXK_Front
+ nKey = KEY_FRONT;
+ break;
+ case 0x1005FF72: // SunXK_Copy
+ nKey = KEY_COPY;
+ break;
+ case 0x1005FF73: // SunXK_Open
+ nKey = KEY_OPEN;
+ break;
+ case 0x1005FF74: // SunXK_Paste
+ nKey = KEY_PASTE;
+ break;
+ case 0x1005FF75: // SunXK_Cut
+ nKey = KEY_CUT;
+ break;
+ }
+ return nKey;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+KeySym SalDisplay::GetKeySym( XKeyEvent *pEvent,
+ unsigned char *pPrintable,
+ int *pLen,
+ KeySym *pUnmodifiedKeySym,
+ Status *pStatusReturn,
+ XIC aInputContext ) const
+{
+ KeySym nKeySym = 0;
+ memset( pPrintable, 0, *pLen );
+ *pStatusReturn = 0;
+
+ // first get the printable of the possibly modified KeySym
+ if ( (aInputContext == 0)
+ || (pEvent->type == KeyRelease)
+ || (mpInputMethod != NULL && mpInputMethod->PosixLocale()) )
+ {
+ // XmbLookupString must not be called for KeyRelease events
+ // Cannot enter space in c locale problem #89616# #88978# btraq #4478197
+ *pLen = XLookupString( pEvent, (char*)pPrintable, 1, &nKeySym, NULL );
+ }
+ else
+ {
+ *pLen = XmbLookupString( aInputContext,
+ pEvent, (char*)pPrintable, *pLen - 1, &nKeySym, pStatusReturn );
+
+ // Lookup the string again, now with appropriate size
+ if ( *pStatusReturn == XBufferOverflow )
+ {
+ pPrintable[ 0 ] = (char)0;
+ return 0;
+ }
+
+ switch ( *pStatusReturn )
+ {
+ case XBufferOverflow:
+ /* unhandled error */
+ break;
+ case XLookupNone:
+ /* unhandled error */
+ break;
+ case XLookupKeySym:
+ /* #72223# this is a strange one: on exceed sometimes
+ * no printable is returned for the first char entered,
+ * just to retry lookup solves the problem. The problem
+ * is not yet fully understood, so restrict 2nd lookup
+ * to 7bit ascii chars */
+ if ( (XK_space <= nKeySym) && (XK_asciitilde >= nKeySym) )
+ {
+ *pLen = 1;
+ pPrintable[ 0 ] = (char)nKeySym;
+ }
+ break;
+ case XLookupBoth:
+ case XLookupChars:
+
+ /* nothing to, char allready in pPrintable */
+ break;
+ }
+ }
+
+ if( !bNumLockFromXS_
+ && (IsCursorKey(nKeySym)
+ || IsFunctionKey(nKeySym)
+ || IsKeypadKey(nKeySym)
+ || XK_Delete == nKeySym ) )
+ {
+ // Bei einigen X-Servern muss man bei den Keypadtasten
+ // schon sehr genau hinschauen. ZB. Solaris XServer:
+ // 2, 4, 6, 8 werden als Cursorkeys klassifiziert (Up, Down, Left, Right
+ // 1, 3, 5, 9 werden als Functionkeys klassifiziert (F27,F29,F33,F35)
+ // 0 als Keypadkey und der Dezimalpunkt gar nicht (KP_Insert)
+ KeySym nNewKeySym = XLookupKeysym( pEvent, nNumLockIndex_ );
+ if( nNewKeySym != NoSymbol )
+ nKeySym = nNewKeySym;
+ }
+
+ // Now get the unmodified KeySym for KeyCode retrieval
+ // try to strip off modifiers, e.g. Ctrl-$ becomes Ctrl-Shift-4
+ *pUnmodifiedKeySym = XKeycodeToKeysym( GetDisplay(), pEvent->keycode, 0);
+
+ return nKeySym;
+}
+
+// Pointer
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#define MAKE_BITMAP( name ) \
+ XCreateBitmapFromData( pDisp_, \
+ DefaultRootWindow( pDisp_ ), \
+ name##_bits, \
+ name##_width, \
+ name##_height )
+
+#define MAKE_CURSOR( name ) \
+ aCursBitmap = MAKE_BITMAP( name##curs ); \
+ aMaskBitmap = MAKE_BITMAP( name##mask ); \
+ nXHot = name##curs_x_hot; \
+ nYHot = name##curs_y_hot
+
+XLIB_Cursor SalDisplay::GetPointer( int ePointerStyle )
+{
+ if( ePointerStyle >= POINTER_COUNT )
+ return 0;
+
+ XLIB_Cursor &aCur = aPointerCache_[ePointerStyle];
+
+ if( aCur != None )
+ return aCur;
+
+ Pixmap aCursBitmap = None, aMaskBitmap = None;
+ unsigned int nXHot = 0, nYHot = 0;
+
+ switch( ePointerStyle )
+ {
+ case POINTER_NULL:
+ MAKE_CURSOR( null );
+ break;
+ case POINTER_ARROW:
+ aCur = XCreateFontCursor( pDisp_, XC_left_ptr );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_WAIT:
+ aCur = XCreateFontCursor( pDisp_, XC_watch );
+ break;
+ case POINTER_TEXT: // Mouse Pointer ist ein "I" Beam
+ aCur = XCreateFontCursor( pDisp_, XC_xterm );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_HELP:
+ aCur = XCreateFontCursor( pDisp_, XC_question_arrow );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_CROSS: // Mouse Pointer ist ein Kreuz
+ aCur = XCreateFontCursor( pDisp_, XC_crosshair );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_NSIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_sb_v_double_arrow );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_SSIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_sb_v_double_arrow );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_WSIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_sb_h_double_arrow );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_ESIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_sb_h_double_arrow );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_WINDOW_NSIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_top_side );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_WINDOW_SSIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_bottom_side );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_WINDOW_WSIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_left_side );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_WINDOW_ESIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_right_side );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_NWSIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_top_left_corner );
+ break;
+ case POINTER_NESIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_top_right_corner );
+ break;
+ case POINTER_SWSIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_bottom_left_corner );
+ break;
+ case POINTER_SESIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_bottom_right_corner );
+ break;
+ case POINTER_WINDOW_NWSIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_top_left_corner );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_WINDOW_NESIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_top_right_corner );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_WINDOW_SWSIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_bottom_left_corner );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_WINDOW_SESIZE:
+ aCur = XCreateFontCursor( pDisp_, XC_bottom_right_corner );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_HSPLIT:
+ aCur = XCreateFontCursor( pDisp_, XC_sb_h_double_arrow );
+ break;
+ case POINTER_VSPLIT:
+ aCur = XCreateFontCursor( pDisp_, XC_sb_v_double_arrow );
+ break;
+ case POINTER_HSIZEBAR:
+ aCur = XCreateFontCursor( pDisp_, XC_sb_h_double_arrow ); // ???
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_VSIZEBAR:
+ aCur = XCreateFontCursor( pDisp_, XC_sb_v_double_arrow ); // ???
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_REFHAND:
+ aCur = XCreateFontCursor( pDisp_, XC_hand1 );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_HAND:
+ aCur = XCreateFontCursor( pDisp_, XC_hand2 );
+ break;
+ case POINTER_MAGNIFY:
+ MAKE_CURSOR( magnify_ );
+ break;
+ case POINTER_FILL:
+ MAKE_CURSOR( fill_ );
+ break;
+ case POINTER_MOVE:
+ aCur = XCreateFontCursor( pDisp_, XC_fleur );
+ break;
+ case POINTER_MOVEDATA:
+ MAKE_CURSOR( movedata_ );
+ break;
+ case POINTER_COPYDATA:
+ MAKE_CURSOR( copydata_ );
+ break;
+ case POINTER_MOVEFILE:
+ MAKE_CURSOR( movefile_ );
+ break;
+ case POINTER_COPYFILE:
+ MAKE_CURSOR( copyfile_ );
+ break;
+ case POINTER_MOVEFILES:
+ MAKE_CURSOR( movefiles_ );
+ break;
+ case POINTER_COPYFILES:
+ MAKE_CURSOR( copyfiles_ );
+ break;
+ case POINTER_NOTALLOWED:
+ MAKE_CURSOR( nodrop_ );
+ break;
+ case POINTER_ROTATE:
+ MAKE_CURSOR( rotate_ );
+ break;
+ case POINTER_HSHEAR:
+ MAKE_CURSOR( hshear_ );
+ break;
+ case POINTER_VSHEAR:
+ MAKE_CURSOR( vshear_ );
+ break;
+ case POINTER_DRAW_LINE:
+ MAKE_CURSOR( drawline_ );
+ break;
+ case POINTER_DRAW_RECT:
+ MAKE_CURSOR( drawrect_ );
+ break;
+ case POINTER_DRAW_POLYGON:
+ MAKE_CURSOR( drawpolygon_ );
+ break;
+ case POINTER_DRAW_BEZIER:
+ MAKE_CURSOR( drawbezier_ );
+ break;
+ case POINTER_DRAW_ARC:
+ MAKE_CURSOR( drawarc_ );
+ break;
+ case POINTER_DRAW_PIE:
+ MAKE_CURSOR( drawpie_ );
+ break;
+ case POINTER_DRAW_CIRCLECUT:
+ MAKE_CURSOR( drawcirclecut_ );
+ break;
+ case POINTER_DRAW_ELLIPSE:
+ MAKE_CURSOR( drawellipse_ );
+ break;
+ case POINTER_DRAW_CONNECT:
+ MAKE_CURSOR( drawconnect_ );
+ break;
+ case POINTER_DRAW_TEXT:
+ MAKE_CURSOR( drawtext_ );
+ break;
+ case POINTER_MIRROR:
+ MAKE_CURSOR( mirror_ );
+ break;
+ case POINTER_CROOK:
+ MAKE_CURSOR( crook_ );
+ break;
+ case POINTER_CROP:
+ MAKE_CURSOR( crop_ );
+ break;
+ case POINTER_MOVEPOINT:
+ MAKE_CURSOR( movepoint_ );
+ break;
+ case POINTER_MOVEBEZIERWEIGHT:
+ MAKE_CURSOR( movebezierweight_ );
+ break;
+ case POINTER_DRAW_FREEHAND:
+ MAKE_CURSOR( drawfreehand_ );
+ break;
+ case POINTER_DRAW_CAPTION:
+ MAKE_CURSOR( drawcaption_ );
+ break;
+ case POINTER_PEN: // Mouse Pointer ist ein Stift
+ aCur = XCreateFontCursor( pDisp_, XC_pencil );
+ DBG_ASSERT( aCur != None, "GetPointer: Could not define cursor" );
+ break;
+ case POINTER_LINKDATA:
+ MAKE_CURSOR( linkdata_ );
+ break;
+ case POINTER_MOVEDATALINK:
+ MAKE_CURSOR( movedlnk_ );
+ break;
+ case POINTER_COPYDATALINK:
+ MAKE_CURSOR( copydlnk_ );
+ break;
+ case POINTER_LINKFILE:
+ MAKE_CURSOR( linkfile_ );
+ break;
+ case POINTER_MOVEFILELINK:
+ MAKE_CURSOR( moveflnk_ );
+ break;
+ case POINTER_COPYFILELINK:
+ MAKE_CURSOR( copyflnk_ );
+ break;
+ case POINTER_CHART:
+ MAKE_CURSOR( chart_ );
+ break;
+ case POINTER_DETECTIVE:
+ MAKE_CURSOR( detective_ );
+ break;
+ case POINTER_PIVOT_COL:
+ MAKE_CURSOR( pivotcol_ );
+ break;
+ case POINTER_PIVOT_ROW:
+ MAKE_CURSOR( pivotrow_ );
+ break;
+ case POINTER_PIVOT_FIELD:
+ MAKE_CURSOR( pivotfld_ );
+ break;
+ case POINTER_PIVOT_DELETE:
+ MAKE_CURSOR( pivotdel_ );
+ break;
+ case POINTER_CHAIN:
+ MAKE_CURSOR( chain_ );
+ break;
+ case POINTER_CHAIN_NOTALLOWED:
+ MAKE_CURSOR( chainnot_ );
+ break;
+ case POINTER_TIMEEVENT_MOVE:
+ MAKE_CURSOR( timemove_ );
+ break;
+ case POINTER_TIMEEVENT_SIZE:
+ MAKE_CURSOR( timesize_ );
+ break;
+ case POINTER_AUTOSCROLL_N:
+ MAKE_CURSOR(asn_ );
+ break;
+ case POINTER_AUTOSCROLL_S:
+ MAKE_CURSOR( ass_ );
+ break;
+ case POINTER_AUTOSCROLL_W:
+ MAKE_CURSOR( asw_ );
+ break;
+ case POINTER_AUTOSCROLL_E:
+ MAKE_CURSOR( ase_ );
+ break;
+ case POINTER_AUTOSCROLL_NW:
+ MAKE_CURSOR( asnw_ );
+ break;
+ case POINTER_AUTOSCROLL_NE:
+ MAKE_CURSOR( asne_ );
+ break;
+ case POINTER_AUTOSCROLL_SW:
+ MAKE_CURSOR( assw_ );
+ break;
+ case POINTER_AUTOSCROLL_SE:
+ MAKE_CURSOR( asse_ );
+ break;
+ case POINTER_AUTOSCROLL_NS:
+ MAKE_CURSOR( asns_ );
+ break;
+ case POINTER_AUTOSCROLL_WE:
+ MAKE_CURSOR( aswe_ );
+ break;
+ case POINTER_AUTOSCROLL_NSWE:
+ MAKE_CURSOR( asnswe_ );
+ break;
+ case POINTER_AIRBRUSH:
+ MAKE_CURSOR( airbrush_ );
+ break;
+ case POINTER_TEXT_VERTICAL:
+ MAKE_CURSOR( vertcurs_ );
+ break;
+
+ // --> FME 2004-07-30 #i32329# Enhanced table selection
+ case POINTER_TAB_SELECT_S:
+ MAKE_CURSOR( tblsels_ );
+ break;
+ case POINTER_TAB_SELECT_E:
+ MAKE_CURSOR( tblsele_ );
+ break;
+ case POINTER_TAB_SELECT_SE:
+ MAKE_CURSOR( tblselse_ );
+ break;
+ case POINTER_TAB_SELECT_W:
+ MAKE_CURSOR( tblselw_ );
+ break;
+ case POINTER_TAB_SELECT_SW:
+ MAKE_CURSOR( tblselsw_ );
+ break;
+ // <--
+
+ // --> FME 2004-08-16 #i20119# Paintbrush tool
+ case POINTER_PAINTBRUSH :
+ MAKE_CURSOR( paintbrush_ );
+ break;
+ // <--
+
+ default:
+ DBG_ERROR("pointer not implemented");
+ aCur = XCreateFontCursor( pDisp_, XC_arrow );
+ break;
+ }
+
+ if( None == aCur )
+ {
+ XColor aBlack, aWhite, aDummy;
+ Colormap hColormap = GetColormap(m_nDefaultScreen).GetXColormap();
+
+ XAllocNamedColor( pDisp_, hColormap, "black", &aBlack, &aDummy );
+ XAllocNamedColor( pDisp_, hColormap, "white", &aWhite, &aDummy );
+
+ aCur = XCreatePixmapCursor( pDisp_,
+ aCursBitmap, aMaskBitmap,
+ &aBlack, &aWhite,
+ nXHot, nYHot );
+
+ XFreePixmap( pDisp_, aCursBitmap );
+ XFreePixmap( pDisp_, aMaskBitmap );
+ }
+
+ return aCur;
+}
+
+int SalDisplay::CaptureMouse( SalFrame *pCapture )
+{
+ if( !pCapture )
+ {
+ m_pCapture = NULL;
+ XUngrabPointer( GetDisplay(), CurrentTime );
+ XFlush( GetDisplay() );
+ return 0;
+ }
+
+ m_pCapture = NULL;
+
+ // FIXME: get rid of X11SalFrame
+ const SystemEnvData* pEnvData = pCapture->GetSystemData();
+ int ret = XGrabPointer( GetDisplay(),
+ (XLIB_Window)pEnvData->aWindow,
+ False,
+ PointerMotionMask| ButtonPressMask|ButtonReleaseMask,
+ GrabModeAsync,
+ GrabModeAsync,
+ None,
+ static_cast<X11SalFrame*>(pCapture)->GetCursor(),
+ CurrentTime );
+
+ if( ret != GrabSuccess )
+ {
+ DBG_ASSERT( 1, "SalDisplay::CaptureMouse could not grab pointer\n");
+ return -1;
+ }
+
+ m_pCapture = pCapture;
+ return 1;
+}
+
+// Events
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void SalDisplay::SendInternalEvent( SalFrame* pFrame, void* pData, USHORT nEvent )
+{
+ if( osl_acquireMutex( hEventGuard_ ) )
+ {
+ m_aUserEvents.push_back( SalUserEvent( pFrame, pData, nEvent ) );
+
+ // Notify SalXLib::Yield() of a pending event.
+ pXLib_->PostUserEvent();
+
+ osl_releaseMutex( hEventGuard_ );
+ }
+ else {
+ DBG_ASSERT( 1, "SalDisplay::SendInternalEvent !acquireMutex\n" );
+ }
+}
+
+void SalDisplay::CancelInternalEvent( SalFrame* pFrame, void* pData, USHORT nEvent )
+{
+ if( osl_acquireMutex( hEventGuard_ ) )
+ {
+ if( ! m_aUserEvents.empty() )
+ {
+ std::list< SalUserEvent >::iterator it, next;
+ next = m_aUserEvents.begin();
+ do
+ {
+ it = next++;
+ if( it->m_pFrame == pFrame &&
+ it->m_pData == pData &&
+ it->m_nEvent == nEvent )
+ {
+ m_aUserEvents.erase( it );
+ }
+ } while( next != m_aUserEvents.end() );
+ }
+
+ osl_releaseMutex( hEventGuard_ );
+ }
+ else {
+ DBG_ASSERT( 1, "SalDisplay::CancelInternalEvent !acquireMutex\n" );
+ }
+}
+
+BOOL SalX11Display::IsEvent()
+{
+ BOOL bRet = FALSE;
+
+ if( osl_acquireMutex( hEventGuard_ ) )
+ {
+ if( m_aUserEvents.begin() != m_aUserEvents.end() )
+ bRet = TRUE;
+ osl_releaseMutex( hEventGuard_ );
+ }
+
+ if( bRet || XEventsQueued( pDisp_, QueuedAlready ) )
+ return TRUE;
+
+ XFlush( pDisp_ );
+ return FALSE;
+}
+
+bool SalDisplay::DispatchInternalEvent()
+{
+ SalFrame* pFrame = NULL;
+ void* pData = NULL;
+ USHORT nEvent = 0;
+
+ if( osl_acquireMutex( hEventGuard_ ) )
+ {
+ if( m_aUserEvents.begin() != m_aUserEvents.end() )
+ {
+ pFrame = m_aUserEvents.front().m_pFrame;
+ pData = m_aUserEvents.front().m_pData;
+ nEvent = m_aUserEvents.front().m_nEvent;
+
+ m_aUserEvents.pop_front();
+ }
+ osl_releaseMutex( hEventGuard_ );
+ }
+ else {
+ DBG_ASSERT( 1, "SalDisplay::Yield !acquireMutex\n" );
+ }
+
+ if( pFrame )
+ pFrame->CallCallback( nEvent, pData );
+
+ return pFrame != NULL;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void SalX11Display::Yield()
+{
+ if( DispatchInternalEvent() )
+ return;
+
+ XEvent aEvent;
+ DBG_ASSERT( static_cast<SalYieldMutex*>(GetSalData()->m_pInstance->GetYieldMutex())->GetThreadId() ==
+ NAMESPACE_VOS(OThread)::getCurrentIdentifier(),
+ "will crash soon since solar mutex not locked in SalDisplay::Yield" );
+
+ XNextEvent( pDisp_, &aEvent );
+
+ Dispatch( &aEvent );
+
+#ifdef DBG_UTIL
+ if( pXLib_->HasXErrorOccured() )
+ {
+ XFlush( pDisp_ );
+ PrintEvent( "SalDisplay::Yield (WasXError)", &aEvent );
+ }
+#endif
+ pXLib_->ResetXErrorOccured();
+}
+
+long SalX11Display::Dispatch( XEvent *pEvent )
+{
+ if( pEvent->type == XLIB_KeyPress || pEvent->type == KeyRelease )
+ {
+ XLIB_Window aWindow = pEvent->xkey.window;
+
+ std::list< SalFrame* >::const_iterator it;
+ for( it = m_aFrames.begin(); it != m_aFrames.end(); ++it )
+ {
+ const X11SalFrame* pFrame = static_cast< const X11SalFrame* >(*it);
+ if( pFrame->GetWindow() == aWindow || pFrame->GetShellWindow() == aWindow )
+ {
+ aWindow = pFrame->GetWindow();
+ break;
+ }
+ }
+ if( it != m_aFrames.end() )
+ {
+ if ( mpInputMethod->FilterEvent( pEvent , aWindow ) )
+ return 0;
+ }
+ }
+ else
+ if ( mpInputMethod->FilterEvent( pEvent, None ) )
+ return 0;
+
+ SalInstance* pInstance = GetSalData()->m_pInstance;
+ pInstance->CallEventCallback( pEvent, sizeof( XEvent ) );
+
+ switch( pEvent->type )
+ {
+ case MotionNotify:
+ while( XCheckWindowEvent( pEvent->xany.display,
+ pEvent->xany.window,
+ ButtonMotionMask,
+ pEvent ) )
+ ;
+ m_nLastUserEventTime = pEvent->xmotion.time;
+ break;
+ case PropertyNotify:
+ if( pEvent->xproperty.atom == getWMAdaptor()->getAtom( WMAdaptor::VCL_SYSTEM_SETTINGS ) )
+ {
+ for( unsigned int i = 0; i < m_aScreens.size(); i++ )
+ {
+ if( pEvent->xproperty.window == m_aScreens[i].m_aRefWindow )
+ {
+ std::list< SalFrame* >::const_iterator it;
+ for( it = m_aFrames.begin(); it != m_aFrames.end(); ++it )
+ (*it)->CallCallback( SALEVENT_SETTINGSCHANGED, NULL );
+ return 0;
+ }
+ }
+ }
+ break;
+ case MappingNotify:
+ if( MappingKeyboard == pEvent->xmapping.request ||
+ MappingModifier == pEvent->xmapping.request )
+ {
+ XRefreshKeyboardMapping( &pEvent->xmapping );
+ if( MappingModifier == pEvent->xmapping.request )
+ ModifierMapping();
+ if( MappingKeyboard == pEvent->xmapping.request ) // refresh mapping
+ GetKeyboardName( TRUE );
+ }
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ m_nLastUserEventTime = pEvent->xbutton.time;
+ break;
+ case XLIB_KeyPress:
+ case KeyRelease:
+ m_nLastUserEventTime = pEvent->xkey.time;
+ break;
+ default:
+
+ if ( GetKbdExtension()->UseExtension()
+ && GetKbdExtension()->GetEventBase() == pEvent->type )
+ {
+ GetKbdExtension()->Dispatch( pEvent );
+ return 1;
+ }
+ break;
+ }
+
+ std::list< SalFrame* >::iterator it;
+ for( it = m_aFrames.begin(); it != m_aFrames.end(); ++it )
+ {
+ X11SalFrame* pFrame = static_cast< X11SalFrame* >(*it);
+ XLIB_Window aDispatchWindow = pEvent->xany.window;
+ if( pFrame->GetWindow() == aDispatchWindow
+ || pFrame->GetShellWindow() == aDispatchWindow
+ || pFrame->GetForeignParent() == aDispatchWindow
+ )
+ {
+ return pFrame->Dispatch( pEvent );
+ }
+ if( pEvent->type == ConfigureNotify && pEvent->xconfigure.window == pFrame->GetStackingWindow() )
+ {
+ return pFrame->Dispatch( pEvent );
+ }
+ }
+
+ // dispatch to salobjects
+ X11SalObject::Dispatch( pEvent );
+
+ // is this perhaps a root window that changed size ?
+ processRandREvent( pEvent );
+
+ return 0;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void SalDisplay::PrintEvent( const ByteString &rComment,
+ XEvent *pEvent ) const
+{
+ if( pEvent->type <= MappingNotify )
+ {
+ fprintf( stderr, "[%s] %s s=%d w=%ld\n",
+ rComment.GetBuffer(),
+ EventNames[pEvent->type],
+ pEvent->xany.send_event,
+ pEvent->xany.window );
+
+ switch( pEvent->type )
+ {
+ case XLIB_KeyPress:
+ case KeyRelease:
+ fprintf( stderr, "\t\ts=%d c=%d\n",
+ pEvent->xkey.state,
+ pEvent->xkey.keycode );
+ break;
+
+ case ButtonPress:
+ case ButtonRelease:
+ fprintf( stderr, "\t\ts=%d b=%d x=%d y=%d rx=%d ry=%d\n",
+ pEvent->xbutton.state,
+ pEvent->xbutton.button,
+ pEvent->xbutton.x,
+ pEvent->xbutton.y,
+ pEvent->xbutton.x_root,
+ pEvent->xbutton.y_root );
+ break;
+
+ case MotionNotify:
+ fprintf( stderr, "\t\ts=%d x=%d y=%d\n",
+ pEvent->xmotion.state,
+ pEvent->xmotion.x,
+ pEvent->xmotion.y );
+ break;
+
+ case EnterNotify:
+ case LeaveNotify:
+ fprintf( stderr, "\t\tm=%d f=%d x=%d y=%d\n",
+ pEvent->xcrossing.mode,
+ pEvent->xcrossing.focus,
+ pEvent->xcrossing.x,
+ pEvent->xcrossing.y );
+ break;
+
+ case FocusIn:
+ case FocusOut:
+ fprintf( stderr, "\t\tm=%d d=%d\n",
+ pEvent->xfocus.mode,
+ pEvent->xfocus.detail );
+ break;
+
+ case Expose:
+ case GraphicsExpose:
+ fprintf( stderr, "\t\tc=%d %d*%d %d+%d\n",
+ pEvent->xexpose.count,
+ pEvent->xexpose.width,
+ pEvent->xexpose.height,
+ pEvent->xexpose.x,
+ pEvent->xexpose.y );
+ break;
+
+ case VisibilityNotify:
+ fprintf( stderr, "\t\ts=%d\n",
+ pEvent->xvisibility.state );
+ break;
+
+ case CreateNotify:
+ case DestroyNotify:
+ break;
+
+ case MapNotify:
+ case UnmapNotify:
+ break;
+
+ case ReparentNotify:
+ fprintf( stderr, "\t\tp=%d x=%d y=%d\n",
+ sal::static_int_cast< int >(pEvent->xreparent.parent),
+ pEvent->xreparent.x,
+ pEvent->xreparent.y );
+ break;
+
+ case ConfigureNotify:
+ fprintf( stderr, "\t\tb=%d %d*%d %d+%d\n",
+ pEvent->xconfigure.border_width,
+ pEvent->xconfigure.width,
+ pEvent->xconfigure.height,
+ pEvent->xconfigure.x,
+ pEvent->xconfigure.y );
+ break;
+
+ case PropertyNotify:
+ fprintf( stderr, "\t\ta=%s (0x%X)\n",
+ GetAtomName( pDisp_, pEvent->xproperty.atom ),
+ sal::static_int_cast< unsigned int >(
+ pEvent->xproperty.atom) );
+ break;
+
+ case ColormapNotify:
+ fprintf( stderr, "\t\tc=%ld n=%d s=%d\n",
+ pEvent->xcolormap.colormap,
+ pEvent->xcolormap.c_new,
+ pEvent->xcolormap.state );
+ break;
+
+ case ClientMessage:
+ fprintf( stderr, "\t\ta=%s (0x%X) f=%i [0x%lX,0x%lX,0x%lX,0x%lX,0x%lX])\n",
+ GetAtomName( pDisp_, pEvent->xclient.message_type ),
+ sal::static_int_cast< unsigned int >(
+ pEvent->xclient.message_type),
+ pEvent->xclient.format,
+ pEvent->xclient.data.l[0],
+ pEvent->xclient.data.l[1],
+ pEvent->xclient.data.l[2],
+ pEvent->xclient.data.l[3],
+ pEvent->xclient.data.l[4] );
+ break;
+
+ case MappingNotify:
+ fprintf( stderr, "\t\tr=%sd\n",
+ MappingModifier == pEvent->xmapping.request
+ ? "MappingModifier"
+ : MappingKeyboard == pEvent->xmapping.request
+ ? "MappingKeyboard"
+ : "MappingPointer" );
+
+ break;
+ }
+ }
+ else
+ fprintf( stderr, "[%s] %d s=%d w=%ld\n",
+ rComment.GetBuffer(),
+ pEvent->type,
+ pEvent->xany.send_event,
+ pEvent->xany.window );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void SalDisplay::PrintInfo() const
+{
+ if( IsDisplay() )
+ {
+ fprintf( stderr, "\n" );
+ fprintf( stderr, "Environment\n" );
+ fprintf( stderr, "\t$XENVIRONMENT \t\"%s\"\n",
+ GetEnv( "XENVIRONMENT" ) );
+ fprintf( stderr, "\t$DISPLAY \t\"%s\"\n",
+ GetEnv( "DISPLAY" ) );
+ fprintf( stderr, "\t$SAL_VISUAL \t\"%s\"\n",
+ GetEnv( "SAL_VISUAL" ) );
+ fprintf( stderr, "\t$SAL_FONTPATH \t\"%s\"\n",
+ GetEnv( "SAL_FONTPATH" ) );
+ fprintf( stderr, "\t$SAL_NOSEGV \t\"%s\"\n",
+ GetEnv( "SAL_NOSEGV" ) );
+ fprintf( stderr, "\t$SAL_IGNOREXERRORS\t\"%s\"\n",
+ GetEnv( "SAL_IGNOREXERRORS" ) );
+ fprintf( stderr, "\t$SAL_PROPERTIES \t\"%s\"\n",
+ GetEnv( "SAL_PROPERTIES" ) );
+ fprintf( stderr, "\t$SAL_WM \t\"%s\"\n",
+ GetEnv( "SAL_WM" ) );
+ fprintf( stderr, "\t$SAL_SYNCHRONIZE \t\"%s\"\n",
+ GetEnv( "SAL_SYNCHRONIZE" ) );
+
+ char sHostname[ 120 ];
+ gethostname (sHostname, 120 );
+ fprintf( stderr, "Client\n" );
+ fprintf( stderr, "\tHost \t\"%s\"\n",
+ sHostname );
+
+ fprintf( stderr, "Display\n" );
+ fprintf( stderr, "\tHost \t\"%s\"\n",
+ DisplayString(pDisp_) );
+ fprintf( stderr, "\tVendor (Release) \t\"%s (%d)\"\n",
+ ServerVendor(pDisp_), VendorRelease(pDisp_) );
+ fprintf( stderr, "\tProtocol \t%d.%d\n",
+ ProtocolVersion(pDisp_), ProtocolRevision(pDisp_) );
+ fprintf( stderr, "\tScreen (count,def)\t%d (%d,%d)\n",
+ m_nDefaultScreen, ScreenCount(pDisp_), DefaultScreen(pDisp_) );
+ fprintf( stderr, "\tshift ctrl alt \t%s (0x%X) %s (0x%X) %s (0x%X)\n",
+ KeyStr( nShiftKeySym_ ), sal::static_int_cast< unsigned int >(nShiftKeySym_),
+ KeyStr( nCtrlKeySym_ ), sal::static_int_cast< unsigned int >(nCtrlKeySym_),
+ KeyStr( nMod1KeySym_ ), sal::static_int_cast< unsigned int >(nMod1KeySym_) );
+ if( XExtendedMaxRequestSize(pDisp_) * 4 )
+ fprintf( stderr, "\tXMaxRequestSize \t%ld %ld [bytes]\n",
+ XMaxRequestSize(pDisp_) * 4, XExtendedMaxRequestSize(pDisp_) * 4 );
+ if( GetProperties() != PROPERTY_DEFAULT )
+ fprintf( stderr, "\tProperties \t0x%lX\n", GetProperties() );
+ if( eWindowManager_ != otherwm )
+ fprintf( stderr, "\tWindowmanager \t%d\n", eWindowManager_ );
+ }
+ fprintf( stderr, "Screen\n" );
+ fprintf( stderr, "\tResolution/Size \t%ld*%ld %ld*%ld %.1lf\"\n",
+ aResolution_.A(), aResolution_.B(),
+ m_aScreens[m_nDefaultScreen].m_aSize.Width(), m_aScreens[m_nDefaultScreen].m_aSize.Height(),
+ Hypothenuse( DisplayWidthMM ( pDisp_, m_nDefaultScreen ),
+ DisplayHeightMM( pDisp_, m_nDefaultScreen ) ) / 25.4 );
+ fprintf( stderr, "\tBlack&White \t%lu %lu\n",
+ GetColormap(m_nDefaultScreen).GetBlackPixel(), GetColormap(m_nDefaultScreen).GetWhitePixel() );
+ fprintf( stderr, "\tRGB \t0x%lx 0x%lx 0x%lx\n",
+ GetVisual(m_nDefaultScreen).red_mask, GetVisual(m_nDefaultScreen).green_mask, GetVisual(m_nDefaultScreen).blue_mask );
+ fprintf( stderr, "\tVisual \t%d-bit %s ID=0x%x\n",
+ GetVisual(m_nDefaultScreen).GetDepth(),
+ VisualClassName[ GetVisual(m_nDefaultScreen).GetClass() ],
+ sal::static_int_cast< unsigned int >(GetVisual(m_nDefaultScreen).GetVisualId()) );
+}
+
+void SalDisplay::addXineramaScreenUnique( long i_nX, long i_nY, long i_nWidth, long i_nHeight )
+{
+ // see if any frame buffers are at the same coordinates
+ // this can happen with weird configuration e.g. on
+ // XFree86 and Clone displays
+ const size_t nScreens = m_aXineramaScreens.size();
+ for( size_t n = 0; n < nScreens; n++ )
+ {
+ if( m_aXineramaScreens[n].Left() == i_nX &&
+ m_aXineramaScreens[n].Top() == i_nY )
+ {
+ if( m_aXineramaScreens[n].GetWidth() < i_nWidth ||
+ m_aXineramaScreens[n].GetHeight() < i_nHeight )
+ {
+ m_aXineramaScreens[n].SetSize( Size( i_nWidth, i_nHeight ) );
+ }
+ return;
+ }
+ }
+ m_aXineramaScreens.push_back( Rectangle( Point( i_nX, i_nY ), Size( i_nWidth, i_nHeight ) ) );
+}
+
+void SalDisplay::InitXinerama()
+{
+ if( m_aScreens.size() > 1 )
+ {
+ m_bXinerama = false;
+ return; // multiple screens mean no xinerama
+ }
+#ifdef USE_XINERAMA
+#if defined(USE_XINERAMA_XSUN)
+ int nFramebuffers = 1;
+ if( XineramaGetState( pDisp_, m_nDefaultScreen ) )
+ {
+ XRectangle pFramebuffers[MAXFRAMEBUFFERS];
+ unsigned char hints[MAXFRAMEBUFFERS];
+ int result = XineramaGetInfo( pDisp_,
+ m_nDefaultScreen,
+ pFramebuffers,
+ hints,
+ &nFramebuffers );
+ if( result > 0 && nFramebuffers > 1 )
+ {
+ m_bXinerama = true;
+ m_aXineramaScreens = std::vector<Rectangle>( nFramebuffers );
+ for( int i = 0; i < nFramebuffers; i++ )
+ addXineramaScreenUnique( pFramebuffers[i].x,
+ pFramebuffers[i].y,
+ pFramebuffers[i].width,
+ pFramebuffers[i].height );
+ }
+ }
+#elif defined(USE_XINERAMA_XORG)
+#if defined( X86 ) || defined( X86_64 )
+if( XineramaIsActive( pDisp_ ) )
+{
+ int nFramebuffers = 1;
+ XineramaScreenInfo* pScreens = XineramaQueryScreens( pDisp_, &nFramebuffers );
+ if( pScreens )
+ {
+ if( nFramebuffers > 1 )
+ {
+ m_aXineramaScreens = std::vector<Rectangle>();
+ for( int i = 0; i < nFramebuffers; i++ )
+ {
+ addXineramaScreenUnique( pScreens[i].x_org,
+ pScreens[i].y_org,
+ pScreens[i].width,
+ pScreens[i].height );
+ }
+ m_bXinerama = m_aXineramaScreens.size() > 1;
+ }
+ XFree( pScreens );
+ }
+}
+#endif
+#endif
+#if OSL_DEBUG_LEVEL > 1
+ if( m_bXinerama )
+ {
+ for( std::vector< Rectangle >::const_iterator it = m_aXineramaScreens.begin(); it != m_aXineramaScreens.end(); ++it )
+ fprintf( stderr, "Xinerama screen: %ldx%ld+%ld+%ld\n", it->GetWidth(), it->GetHeight(), it->Left(), it->Top() );
+ }
+#endif
+#endif // USE_XINERAMA
+}
+
+void SalDisplay::registerFrame( SalFrame* pFrame )
+{
+ m_aFrames.push_front( pFrame );
+}
+
+void SalDisplay::deregisterFrame( SalFrame* pFrame )
+{
+ if( osl_acquireMutex( hEventGuard_ ) )
+ {
+ std::list< SalUserEvent >::iterator it = m_aUserEvents.begin();
+ while ( it != m_aUserEvents.end() )
+ {
+ if( it->m_pFrame == pFrame )
+ it = m_aUserEvents.erase( it );
+ else
+ ++it;
+ }
+ osl_releaseMutex( hEventGuard_ );
+ }
+ else {
+ DBG_ERROR( "SalDisplay::deregisterFrame !acquireMutex\n" );
+ }
+
+ m_aFrames.remove( pFrame );
+}
+
+
+extern "C"
+{
+ static Bool timestamp_predicate( Display*, XEvent* i_pEvent, XPointer i_pArg )
+ {
+ SalDisplay* pSalDisplay = reinterpret_cast<SalDisplay*>(i_pArg);
+ if( i_pEvent->type == PropertyNotify &&
+ i_pEvent->xproperty.window == pSalDisplay->GetDrawable( pSalDisplay->GetDefaultScreenNumber() ) &&
+ i_pEvent->xproperty.atom == pSalDisplay->getWMAdaptor()->getAtom( WMAdaptor::SAL_GETTIMEEVENT )
+ )
+ return True;
+
+ return False;
+ }
+}
+
+XLIB_Time SalDisplay::GetLastUserEventTime( bool i_bAlwaysReget ) const
+{
+ if( m_nLastUserEventTime == CurrentTime || i_bAlwaysReget )
+ {
+ // get current server time
+ unsigned char c = 0;
+ XEvent aEvent;
+ Atom nAtom = getWMAdaptor()->getAtom( WMAdaptor::SAL_GETTIMEEVENT );
+ XChangeProperty( GetDisplay(), GetDrawable( GetDefaultScreenNumber() ),
+ nAtom, nAtom, 8, PropModeReplace, &c, 1 );
+ XFlush( GetDisplay() );
+
+ if( ! XIfEventWithTimeout( &aEvent, (XPointer)this, timestamp_predicate ) )
+ {
+ // this should not happen at all; still sometimes it happens
+ aEvent.xproperty.time = CurrentTime;
+ }
+
+ m_nLastUserEventTime = aEvent.xproperty.time;
+ }
+ return m_nLastUserEventTime;
+}
+
+bool SalDisplay::XIfEventWithTimeout( XEvent* o_pEvent, XPointer i_pPredicateData,
+ X_if_predicate i_pPredicate, long i_nTimeout ) const
+{
+ /* #i99360# ugly workaround an X11 library bug
+ this replaces the following call:
+ XIfEvent( GetDisplay(), o_pEvent, i_pPredicate, i_pPredicateData );
+ */
+ bool bRet = true;
+
+ if( ! XCheckIfEvent( GetDisplay(), o_pEvent, i_pPredicate, i_pPredicateData ) )
+ {
+ // wait for some event to arrive
+ struct pollfd aFD;
+ aFD.fd = ConnectionNumber(GetDisplay());
+ aFD.events = POLLIN;
+ aFD.revents = 0;
+ poll( &aFD, 1, i_nTimeout );
+ if( ! XCheckIfEvent( GetDisplay(), o_pEvent, i_pPredicate, i_pPredicateData ) )
+ {
+ poll( &aFD, 1, i_nTimeout ); // try once more for a packet of events from the Xserver
+ if( ! XCheckIfEvent( GetDisplay(), o_pEvent, i_pPredicate, i_pPredicateData ) )
+ {
+ bRet = false;
+ }
+ }
+ }
+ return bRet;
+}
+
+// -=-= SalVisual -=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+SalVisual::SalVisual()
+{
+ rtl_zeroMemory( this, sizeof( SalVisual ) );
+}
+
+SalVisual::SalVisual( const XVisualInfo* pXVI )
+{
+ *(XVisualInfo*)this = *pXVI;
+ if( GetClass() == TrueColor )
+ {
+ nRedShift_ = sal_Shift( red_mask );
+ nGreenShift_ = sal_Shift( green_mask );
+ nBlueShift_ = sal_Shift( blue_mask );
+
+ nRedBits_ = sal_significantBits( red_mask );
+ nGreenBits_ = sal_significantBits( green_mask );
+ nBlueBits_ = sal_significantBits( blue_mask );
+
+ if( GetDepth() == 24 )
+ if( red_mask == 0xFF0000 )
+ if( green_mask == 0xFF00 )
+ if( blue_mask == 0xFF )
+ eRGBMode_ = RGB;
+ else
+ eRGBMode_ = other;
+ else if( blue_mask == 0xFF00 )
+ if( green_mask == 0xFF )
+ eRGBMode_ = RBG;
+ else
+ eRGBMode_ = other;
+ else
+ eRGBMode_ = other;
+ else if( green_mask == 0xFF0000 )
+ if( red_mask == 0xFF00 )
+ if( blue_mask == 0xFF )
+ eRGBMode_ = GRB;
+ else
+ eRGBMode_ = other;
+ else if( blue_mask == 0xFF00 )
+ if( red_mask == 0xFF )
+ eRGBMode_ = GBR;
+ else
+ eRGBMode_ = other;
+ else
+ eRGBMode_ = other;
+ else if( blue_mask == 0xFF0000 )
+ if( red_mask == 0xFF00 )
+ if( green_mask == 0xFF )
+ eRGBMode_ = BRG;
+ else
+ eRGBMode_ = other;
+ else if( green_mask == 0xFF00 )
+ if( red_mask == 0xFF )
+ eRGBMode_ = BGR;
+ else
+ eRGBMode_ = other;
+ else
+ eRGBMode_ = other;
+ else
+ eRGBMode_ = other;
+ else
+ eRGBMode_ = other;
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+SalVisual::~SalVisual()
+{
+ if( -1 == screen && VisualID(-1) == visualid ) delete visual;
+}
+
+// Konvertiert die Reihenfolge der Bytes eines Pixel in Bytes eines SalColors
+// fuer die 6 XXXA ist das nicht reversibel
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// SalColor is RGB (ABGR) a=0xFF000000, r=0xFF0000, g=0xFF00, b=0xFF
+
+#define SALCOLOR RGB
+#define SALCOLORREVERSE BGR
+
+BOOL SalVisual::Convert( int &n0, int &n1, int &n2, int &n3 )
+{
+ int n;
+
+ switch( GetMode() )
+ {
+ case other:
+ return FALSE;
+ case SALCOLOR:
+ break;
+ case SALCOLORREVERSE:
+ case RBG:
+ case BRG:
+ case GBR:
+ case GRB:
+ return Convert( n0, n1, n2 );
+ case RGBA:
+ n = n0;
+ n0 = n1;
+ n1 = n2;
+ n2 = n3;
+ n3 = n;
+ break;
+ case BGRA:
+ case RBGA:
+ case BRGA:
+ case GBRA:
+ case GRBA:
+ default:
+ fprintf( stderr, "SalVisual::Convert %d\n", GetMode() );
+ abort();
+ }
+ return TRUE;
+}
+
+BOOL SalVisual::Convert( int &n0, int &n1, int &n2 )
+{
+ int n;
+
+ switch( GetMode() )
+ {
+ case other:
+ return FALSE;
+ case SALCOLOR:
+ break;
+ case RBG:
+ n = n0;
+ n0 = n1;
+ n1 = n;
+ break;
+ case GRB:
+ n = n1;
+ n1 = n2;
+ n2 = n;
+ break;
+ case SALCOLORREVERSE:
+ n = n0;
+ n0 = n2;
+ n2 = n;
+ break;
+ case BRG:
+ n = n0;
+ n0 = n1;
+ n1 = n2;
+ n2 = n;
+ break;
+ case GBR:
+ n = n2;
+ n2 = n1;
+ n1 = n0;
+ n0 = n;
+ break;
+ default:
+ fprintf( stderr, "SalVisual::Convert %d\n", GetMode() );
+ abort();
+ }
+ return TRUE;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+SalColor SalVisual::GetTCColor( Pixel nPixel ) const
+{
+ if( SALCOLOR == eRGBMode_ )
+ return (SalColor)nPixel;
+
+ if( SALCOLORREVERSE == eRGBMode_ )
+ return MAKE_SALCOLOR( (nPixel & 0x0000FF),
+ (nPixel & 0x00FF00) >> 8,
+ (nPixel & 0xFF0000) >> 16);
+
+ Pixel r = nPixel & red_mask;
+ Pixel g = nPixel & green_mask;
+ Pixel b = nPixel & blue_mask;
+
+ if( other != eRGBMode_ ) // 8+8+8=24
+ return MAKE_SALCOLOR( r >> nRedShift_,
+ g >> nGreenShift_,
+ b >> nBlueShift_ );
+
+ if( nRedShift_ > 0 ) r >>= nRedShift_; else r <<= -nRedShift_;
+ if( nGreenShift_ > 0 ) g >>= nGreenShift_; else g <<= -nGreenShift_;
+ if( nBlueShift_ > 0 ) b >>= nBlueShift_; else b <<= -nBlueShift_;
+
+ if( nRedBits_ != 8 )
+ r |= (r & 0xff) >> (8-nRedBits_);
+ if( nGreenBits_ != 8 )
+ g |= (g & 0xff) >> (8-nGreenBits_);
+ if( nBlueBits_ != 8 )
+ b |= (b & 0xff) >> (8-nBlueBits_);
+
+ return MAKE_SALCOLOR( r, g, b );
+}
+
+Pixel SalVisual::GetTCPixel( SalColor nSalColor ) const
+{
+ if( SALCOLOR == eRGBMode_ )
+ return (Pixel)nSalColor;
+
+ Pixel r = (Pixel)SALCOLOR_RED( nSalColor );
+ Pixel g = (Pixel)SALCOLOR_GREEN( nSalColor );
+ Pixel b = (Pixel)SALCOLOR_BLUE( nSalColor );
+
+ if( SALCOLORREVERSE == eRGBMode_ )
+ return (b << 16) | (g << 8) | (r);
+
+ if( other != eRGBMode_ ) // 8+8+8=24
+ return (r << nRedShift_) | (g << nGreenShift_) | (b << nBlueShift_);
+
+ if( nRedShift_ > 0 ) r <<= nRedShift_; else r >>= -nRedShift_;
+ if( nGreenShift_ > 0 ) g <<= nGreenShift_; else g >>= -nGreenShift_;
+ if( nBlueShift_ > 0 ) b <<= nBlueShift_; else b >>= -nBlueShift_;
+
+ return (r&red_mask) | (g&green_mask) | (b&blue_mask);
+}
+
+// -=-= SalColormap -=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+SalColormap::SalColormap( const SalDisplay *pDisplay, Colormap hColormap, int nScreen )
+ : m_pDisplay( pDisplay ),
+ m_hColormap( hColormap ),
+ m_nScreen( nScreen )
+{
+ m_aVisual = m_pDisplay->GetVisual( m_nScreen );
+
+ XColor aColor;
+
+ GetXPixel( aColor, 0x00, 0x00, 0x00 );
+ m_nBlackPixel = aColor.pixel;
+
+ GetXPixel( aColor, 0xFF, 0xFF, 0xFF );
+ m_nWhitePixel = aColor.pixel;
+
+ m_nUsed = 1 << m_aVisual.GetDepth();
+
+ if( m_aVisual.GetClass() == PseudoColor )
+ {
+ int r, g, b;
+
+ // black, white, gray, ~gray = 4
+ GetXPixels( aColor, 0xC0, 0xC0, 0xC0 );
+
+ // light colors: 3 * 2 = 6
+// GetXPixels( aColor, 0x00, 0x00, 0x00 );
+ GetXPixels( aColor, 0x00, 0x00, 0xFF );
+ GetXPixels( aColor, 0x00, 0xFF, 0x00 );
+ GetXPixels( aColor, 0x00, 0xFF, 0xFF );
+// GetXPixels( aColor, 0xFF, 0x00, 0x00 );
+// GetXPixels( aColor, 0xFF, 0x00, 0xFF );
+// GetXPixels( aColor, 0xFF, 0xFF, 0x00 );
+// GetXPixels( aColor, 0xFF, 0xFF, 0xFF );
+
+ // standard colors: 7 * 2 = 14
+// GetXPixels( aColor, 0x00, 0x00, 0x00 );
+ GetXPixels( aColor, 0x00, 0x00, 0x80 );
+ GetXPixels( aColor, 0x00, 0x80, 0x00 );
+ GetXPixels( aColor, 0x00, 0x80, 0x80 );
+ GetXPixels( aColor, 0x80, 0x00, 0x00 );
+ GetXPixels( aColor, 0x80, 0x00, 0x80 );
+ GetXPixels( aColor, 0x80, 0x80, 0x00 );
+ GetXPixels( aColor, 0x80, 0x80, 0x80 );
+ GetXPixels( aColor, 0x00, 0xB8, 0xFF ); // Blau 7
+
+ // cube: 6*6*6 - 8 = 208
+ for( r = 0; r < 0x100; r += 0x33 ) // 0x33, 0x66, 0x99, 0xCC, 0xFF
+ for( g = 0; g < 0x100; g += 0x33 )
+ for( b = 0; b < 0x100; b += 0x33 )
+ GetXPixels( aColor, r, g, b );
+
+ // gray: 16 - 6 = 10
+ for( g = 0x11; g < 0xFF; g += 0x11 )
+ GetXPixels( aColor, g, g, g );
+
+ // green: 16 - 6 = 10
+ for( g = 0x11; g < 0xFF; g += 0x11 )
+ GetXPixels( aColor, 0, g, 0 );
+
+ // red: 16 - 6 = 10
+ for( r = 0x11; r < 0xFF; r += 0x11 )
+ GetXPixels( aColor, r, 0, 0 );
+
+ // blue: 16 - 6 = 10
+ for( b = 0x11; b < 0xFF; b += 0x11 )
+ GetXPixels( aColor, 0, 0, b );
+ }
+}
+
+// PseudoColor
+SalColormap::SalColormap( const BitmapPalette &rPalette )
+ : m_pDisplay( GetX11SalData()->GetDisplay() ),
+ m_hColormap( None ),
+ m_nWhitePixel( SALCOLOR_NONE ),
+ m_nBlackPixel( SALCOLOR_NONE ),
+ m_nUsed( rPalette.GetEntryCount() ),
+ m_nScreen( GetX11SalData()->GetDisplay()->GetDefaultScreenNumber() )
+{
+ m_aPalette = std::vector<SalColor>(m_nUsed);
+
+ for( unsigned int i = 0; i < m_nUsed; i++ )
+ {
+ const BitmapColor &rColor = rPalette[i];
+ m_aPalette[i] = MAKE_SALCOLOR( rColor.GetRed(),
+ rColor.GetGreen(),
+ rColor.GetBlue() );
+ if( (m_nBlackPixel == SALCOLOR_NONE) && (SALCOLOR_BLACK == m_aPalette[i]) )
+ m_nBlackPixel = i;
+ else if( (m_nWhitePixel == SALCOLOR_NONE) && (SALCOLOR_WHITE == m_aPalette[i]) )
+ m_nWhitePixel = i;
+ }
+}
+
+// MonoChrome
+SalColormap::SalColormap()
+ : m_pDisplay( GetX11SalData()->GetDisplay() ),
+ m_hColormap( None ),
+ m_nWhitePixel( 1 ),
+ m_nBlackPixel( 0 ),
+ m_nUsed( 2 ),
+ m_nScreen( 0 )
+{
+ if( m_pDisplay )
+ m_nScreen = m_pDisplay->GetDefaultScreenNumber();
+ m_aPalette = std::vector<SalColor>(m_nUsed);
+
+ m_aPalette[m_nBlackPixel] = SALCOLOR_BLACK;
+ m_aPalette[m_nWhitePixel] = SALCOLOR_WHITE;
+}
+
+// TrueColor
+SalColormap::SalColormap( USHORT nDepth )
+ : m_pDisplay( GetX11SalData()->GetDisplay() ),
+ m_hColormap( None ),
+ m_nWhitePixel( (1 << nDepth) - 1 ),
+ m_nBlackPixel( 0x00000000 ),
+ m_nUsed( 1 << nDepth ),
+ m_nScreen( GetX11SalData()->GetDisplay()->GetDefaultScreenNumber() )
+{
+ const SalVisual *pVisual = &m_pDisplay->GetVisual( m_nScreen );
+
+ if( pVisual->GetClass() == TrueColor && pVisual->GetDepth() == nDepth )
+ m_aVisual = *pVisual;
+ else
+ {
+ XVisualInfo aVI;
+
+ if( !XMatchVisualInfo( m_pDisplay->GetDisplay(),
+ m_pDisplay->GetDefaultScreenNumber(),
+ nDepth,
+ TrueColor,
+ &aVI ) )
+ {
+ aVI.visual = new Visual();
+ aVI.visualid = (VisualID)0; // beware of temporary destructor below
+ aVI.screen = 0;
+ aVI.depth = nDepth;
+ aVI.c_class = TrueColor;
+ if( 24 == nDepth ) // 888
+ {
+ aVI.red_mask = 0xFF0000;
+ aVI.green_mask = 0x00FF00;
+ aVI.blue_mask = 0x0000FF;
+ }
+ else if( 16 == nDepth ) // 565
+ {
+ aVI.red_mask = 0x00F800;
+ aVI.green_mask = 0x0007E0;
+ aVI.blue_mask = 0x00001F;
+ }
+ else if( 15 == nDepth ) // 555
+ {
+ aVI.red_mask = 0x007C00;
+ aVI.green_mask = 0x0003E0;
+ aVI.blue_mask = 0x00001F;
+ }
+ else if( 12 == nDepth ) // 444
+ {
+ aVI.red_mask = 0x000F00;
+ aVI.green_mask = 0x0000F0;
+ aVI.blue_mask = 0x00000F;
+ }
+ else if( 8 == nDepth ) // 332
+ {
+ aVI.red_mask = 0x0000E0;
+ aVI.green_mask = 0x00001C;
+ aVI.blue_mask = 0x000003;
+ }
+ else
+ {
+ aVI.red_mask = 0x000000;
+ aVI.green_mask = 0x000000;
+ aVI.blue_mask = 0x000000;
+ }
+ aVI.colormap_size = 0;
+ aVI.bits_per_rgb = 8;
+
+ aVI.visual->ext_data = NULL;
+ aVI.visual->visualid = aVI.visualid;
+ aVI.visual->c_class = aVI.c_class;
+ aVI.visual->red_mask = aVI.red_mask;
+ aVI.visual->green_mask = aVI.green_mask;
+ aVI.visual->blue_mask = aVI.blue_mask;
+ aVI.visual->bits_per_rgb = aVI.bits_per_rgb;
+ aVI.visual->map_entries = aVI.colormap_size;
+
+ m_aVisual = SalVisual( &aVI );
+ // give ownership of constructed Visual() to m_aVisual
+ // see SalVisual destructor
+ m_aVisual.visualid = (VisualID)-1;
+ m_aVisual.screen = -1;
+ }
+ else
+ m_aVisual = SalVisual( &aVI );
+ }
+}
+
+SalColormap::~SalColormap()
+{
+#ifdef DBG_UTIL
+ m_hColormap = (Colormap)ILLEGAL_POINTER;
+ m_pDisplay = (SalDisplay*)ILLEGAL_POINTER;
+#endif
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void SalColormap::SetPalette( const BitmapPalette &rPalette )
+{
+ if( this != &GetX11SalData()->GetDisplay()->GetColormap(m_nScreen) )
+ {
+ m_nBlackPixel = SALCOLOR_NONE;
+ m_nWhitePixel = SALCOLOR_NONE;
+ }
+
+ if( rPalette.GetEntryCount() > m_nUsed )
+ {
+ m_nBlackPixel = SALCOLOR_NONE;
+ m_nWhitePixel = SALCOLOR_NONE;
+ m_nUsed = rPalette.GetEntryCount();
+ m_aPalette = std::vector<SalColor>(m_nUsed);
+ }
+
+ for( int i = 0; i < rPalette.GetEntryCount(); i++ )
+ {
+ const BitmapColor &rColor = rPalette[i];
+ m_aPalette[i] = MAKE_SALCOLOR( rColor.GetRed(),
+ rColor.GetGreen(),
+ rColor.GetBlue() );
+ if( (m_nBlackPixel == SALCOLOR_NONE) && (SALCOLOR_BLACK == m_aPalette[i]) )
+ m_nBlackPixel = i;
+ else if( (m_nWhitePixel == SALCOLOR_NONE) && (SALCOLOR_WHITE == m_aPalette[i]) )
+ m_nWhitePixel = i;
+ }
+}
+
+void SalColormap::GetPalette()
+{
+ Pixel i;
+ m_aPalette = std::vector<SalColor>(m_nUsed);
+
+ XColor *aColor = new XColor[m_nUsed];
+
+ for( i = 0; i < m_nUsed; i++ )
+ {
+ aColor[i].red = aColor[i].green = aColor[i].blue = 0;
+ aColor[i].pixel = i;
+ }
+
+ XQueryColors( m_pDisplay->GetDisplay(), m_hColormap, aColor, m_nUsed );
+
+ for( i = 0; i < m_nUsed; i++ )
+ {
+ m_aPalette[i] = MAKE_SALCOLOR( aColor[i].red >> 8,
+ aColor[i].green >> 8,
+ aColor[i].blue >> 8 );
+ }
+
+ delete [] aColor;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+static USHORT sal_Lookup( const std::vector<SalColor>& rPalette,
+ int r, int g, int b,
+ Pixel nUsed )
+{
+ USHORT nPixel = 0;
+ int nBest = ColorDiff( rPalette[0], r, g, b );
+
+ for( USHORT i = 1; i < nUsed; i++ )
+ {
+ int n = ColorDiff( rPalette[i], r, g, b );
+
+ if( n < nBest )
+ {
+ if( !n )
+ return i;
+
+ nPixel = i;
+ nBest = n;
+ }
+ }
+ return nPixel;
+}
+
+void SalColormap::GetLookupTable()
+{
+ m_aLookupTable = std::vector<USHORT>(16*16*16);
+
+ int i = 0;
+ for( int r = 0; r < 256; r += 17 )
+ for( int g = 0; g < 256; g += 17 )
+ for( int b = 0; b < 256; b += 17 )
+ m_aLookupTable[i++] = sal_Lookup( m_aPalette, r, g, b, m_nUsed );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+SalColor SalColormap::GetColor( Pixel nPixel ) const
+{
+ if( m_nBlackPixel == nPixel ) return SALCOLOR_BLACK;
+ if( m_nWhitePixel == nPixel ) return SALCOLOR_WHITE;
+
+ if( m_aVisual.GetVisual() )
+ {
+ if( m_aVisual.GetClass() == TrueColor )
+ return m_aVisual.GetTCColor( nPixel );
+
+ if( m_aPalette.empty()
+ && m_hColormap
+#ifdef PSEUDOCOLOR12
+ && m_aVisual.GetDepth() <= 12
+#else
+ && m_aVisual.GetDepth() <= 8
+#endif
+ && m_aVisual.GetClass() == PseudoColor )
+ ((SalColormap*)this)->GetPalette();
+ }
+
+ if( !m_aPalette.empty() && nPixel < m_nUsed )
+ return m_aPalette[nPixel];
+
+ if( m_hColormap )
+ {
+ DBG_ASSERT( 1, "SalColormap::GetColor() !hColormap_\n" );
+ return nPixel;
+ }
+
+ // DirectColor, StaticColor, StaticGray, GrayScale
+ XColor aColor;
+
+ aColor.pixel = nPixel;
+
+ XQueryColor( m_pDisplay->GetDisplay(), m_hColormap, &aColor );
+
+ return MAKE_SALCOLOR( aColor.red>>8, aColor.green>>8, aColor.blue>>8 );
+}
+
+inline BOOL SalColormap::GetXPixel( XColor &rColor,
+ int r,
+ int g,
+ int b ) const
+{
+ rColor.red = r * 257;
+ rColor.green = g * 257;
+ rColor.blue = b * 257;
+ return XAllocColor( GetXDisplay(), m_hColormap, &rColor );
+}
+
+BOOL SalColormap::GetXPixels( XColor &rColor,
+ int r,
+ int g,
+ int b ) const
+{
+ if( !GetXPixel( rColor, r, g, b ) )
+ return FALSE;
+ if( rColor.pixel & 1 )
+ return TRUE;
+ return GetXPixel( rColor, r^0xFF, g^0xFF, b^0xFF );
+}
+
+Pixel SalColormap::GetPixel( SalColor nSalColor ) const
+{
+ if( SALCOLOR_NONE == nSalColor ) return 0;
+ if( SALCOLOR_BLACK == nSalColor ) return m_nBlackPixel;
+ if( SALCOLOR_WHITE == nSalColor ) return m_nWhitePixel;
+
+ if( m_aVisual.GetClass() == TrueColor )
+ return m_aVisual.GetTCPixel( nSalColor );
+
+ if( m_aLookupTable.empty() )
+ {
+ if( m_aPalette.empty()
+ && m_hColormap
+#ifdef PSEUDOCOLOR12
+ && m_aVisual.GetDepth() <= 12
+#else
+ && m_aVisual.GetDepth() <= 8
+#endif
+ && m_aVisual.GetClass() == PseudoColor ) // what else ???
+ ((SalColormap*)this)->GetPalette();
+
+ if( !m_aPalette.empty() )
+ for( Pixel i = 0; i < m_nUsed; i++ )
+ if( m_aPalette[i] == nSalColor )
+ return i;
+
+ if( m_hColormap )
+ {
+ // DirectColor, StaticColor, StaticGray, GrayScale (PseudoColor)
+ XColor aColor;
+
+ if( GetXPixel( aColor,
+ SALCOLOR_RED ( nSalColor ),
+ SALCOLOR_GREEN( nSalColor ),
+ SALCOLOR_BLUE ( nSalColor ) ) )
+ {
+ if( !m_aPalette.empty() && !m_aPalette[aColor.pixel] )
+ {
+ const_cast<SalColormap*>(this)->m_aPalette[aColor.pixel] = nSalColor;
+
+ if( !(aColor.pixel & 1) && !m_aPalette[aColor.pixel+1] )
+ {
+ XColor aInversColor;
+
+ SalColor nInversColor = nSalColor ^ 0xFFFFFF;
+
+ GetXPixel( aInversColor,
+ SALCOLOR_RED ( nInversColor ),
+ SALCOLOR_GREEN( nInversColor ),
+ SALCOLOR_BLUE ( nInversColor ) );
+
+ if( !m_aPalette[aInversColor.pixel] )
+ const_cast<SalColormap*>(this)->m_aPalette[aInversColor.pixel] = nInversColor;
+#ifdef DBG_UTIL
+ else
+ fprintf( stderr, "SalColormap::GetPixel() 0x%06lx=%lu 0x%06lx=%lu\n",
+ static_cast< unsigned long >(nSalColor), aColor.pixel,
+ static_cast< unsigned long >(nInversColor), aInversColor.pixel);
+#endif
+ }
+ }
+
+ return aColor.pixel;
+ }
+
+#ifdef DBG_UTIL
+ fprintf( stderr, "SalColormap::GetPixel() !XAllocColor %lx\n",
+ static_cast< unsigned long >(nSalColor) );
+#endif
+ }
+
+ if( m_aPalette.empty() )
+ {
+#ifdef DBG_UTIL
+ fprintf( stderr, "SalColormap::GetPixel() Palette empty %lx\n",
+ static_cast< unsigned long >(nSalColor));
+#endif
+ return nSalColor;
+ }
+
+ ((SalColormap*)this)->GetLookupTable();
+ }
+
+ // Colormatching ueber Palette
+ USHORT r = SALCOLOR_RED ( nSalColor );
+ USHORT g = SALCOLOR_GREEN( nSalColor );
+ USHORT b = SALCOLOR_BLUE ( nSalColor );
+ return m_aLookupTable[ (((r+8)/17) << 8)
+ + (((g+8)/17) << 4)
+ + ((b+8)/17) ];
+}
+
diff --git a/vcl/unx/source/app/salinst.cxx b/vcl/unx/source/app/salinst.cxx
new file mode 100644
index 000000000000..8a8db44cefcd
--- /dev/null
+++ b/vcl/unx/source/app/salinst.cxx
@@ -0,0 +1,433 @@
+/*************************************************************************
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+
+#include <osl/module.hxx>
+
+#include "salunx.h"
+
+#include "saldata.hxx"
+#include "saldisp.hxx"
+#include "salinst.h"
+#include "salframe.h"
+#include "dtint.hxx"
+#include "salprn.h"
+#include "sm.hxx"
+
+#include "vcl/salwtype.hxx"
+#include "vcl/salatype.hxx"
+#include "vcl/helper.hxx"
+#include <tools/solarmutex.hxx>
+#include "vos/mutex.hxx"
+
+// -------------------------------------------------------------------------
+//
+// SalYieldMutex
+//
+// -------------------------------------------------------------------------
+
+SalYieldMutex::SalYieldMutex()
+{
+ mnCount = 0;
+ mnThreadId = 0;
+ ::tools::SolarMutex::SetSolarMutex( this );
+}
+
+void SalYieldMutex::acquire()
+{
+ OMutex::acquire();
+ mnThreadId = NAMESPACE_VOS(OThread)::getCurrentIdentifier();
+ mnCount++;
+}
+
+void SalYieldMutex::release()
+{
+ if ( mnThreadId == NAMESPACE_VOS(OThread)::getCurrentIdentifier() )
+ {
+ if ( mnCount == 1 )
+ mnThreadId = 0;
+ mnCount--;
+ }
+ OMutex::release();
+}
+
+sal_Bool SalYieldMutex::tryToAcquire()
+{
+ if ( OMutex::tryToAcquire() )
+ {
+ mnThreadId = NAMESPACE_VOS(OThread)::getCurrentIdentifier();
+ mnCount++;
+ return True;
+ }
+ else
+ return False;
+}
+
+//----------------------------------------------------------------------------
+
+// -=-= SalInstance =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+// plugin factory function
+extern "C"
+{
+ VCL_DLLPUBLIC SalInstance* create_SalInstance()
+ {
+ /* #i92121# workaround deadlocks in the X11 implementation
+ */
+ static const char* pNoXInitThreads = getenv( "SAL_NO_XINITTHREADS" );
+ /* #i90094#
+ from now on we know that an X connection will be
+ established, so protect X against itself
+ */
+ if( ! ( pNoXInitThreads && *pNoXInitThreads ) )
+ XInitThreads();
+
+ X11SalInstance* pInstance = new X11SalInstance( new SalYieldMutex() );
+
+ // initialize SalData
+ X11SalData *pSalData = new X11SalData;
+ SetSalData( pSalData );
+ pSalData->m_pInstance = pInstance;
+ pSalData->Init();
+
+ return pInstance;
+ }
+}
+
+X11SalInstance::~X11SalInstance()
+{
+ // close session management
+ SessionManagerClient::close();
+
+ // dispose SalDisplay list from SalData
+ // would be done in a static destructor else which is
+ // a little late
+
+ X11SalData *pSalData = GetX11SalData();
+ pSalData->deInitNWF();
+ delete pSalData;
+ SetSalData( NULL );
+
+ ::tools::SolarMutex::SetSolarMutex( 0 );
+ delete mpSalYieldMutex;
+}
+
+
+// --------------------------------------------------------
+// AnyInput from sv/mow/source/app/svapp.cxx
+
+struct PredicateReturn
+{
+ USHORT nType;
+ BOOL bRet;
+};
+
+extern "C" {
+Bool ImplPredicateEvent( Display *, XEvent *pEvent, char *pData )
+{
+ PredicateReturn *pPre = (PredicateReturn *)pData;
+
+ if ( pPre->bRet )
+ return False;
+
+ USHORT nType;
+
+ switch( pEvent->type )
+ {
+ case ButtonPress:
+ case ButtonRelease:
+ case MotionNotify:
+ case EnterNotify:
+ case LeaveNotify:
+ nType = INPUT_MOUSE;
+ break;
+
+ case XLIB_KeyPress:
+ //case KeyRelease:
+ nType = INPUT_KEYBOARD;
+ break;
+ case Expose:
+ case GraphicsExpose:
+ case NoExpose:
+ nType = INPUT_PAINT;
+ break;
+ default:
+ nType = 0;
+ }
+
+ if ( (nType & pPre->nType) || ( ! nType && (pPre->nType & INPUT_OTHER) ) )
+ pPre->bRet = TRUE;
+
+ return False;
+}
+}
+
+bool X11SalInstance::AnyInput(USHORT nType)
+{
+ X11SalData *pSalData = GetX11SalData();
+ Display *pDisplay = pSalData->GetDisplay()->GetDisplay();
+ BOOL bRet = FALSE;
+
+ if( (nType & INPUT_TIMER) &&
+ pSalData->GetDisplay()->GetXLib()->CheckTimeout( false ) )
+ {
+ bRet = TRUE;
+ }
+ else if (XPending(pDisplay) )
+ {
+ PredicateReturn aInput;
+ XEvent aEvent;
+
+ aInput.bRet = FALSE;
+ aInput.nType = nType;
+
+ XCheckIfEvent(pDisplay, &aEvent, ImplPredicateEvent,
+ (char *)&aInput );
+
+ bRet = aInput.bRet;
+ }
+ return bRet;
+}
+
+vos::IMutex* X11SalInstance::GetYieldMutex()
+{
+ return mpSalYieldMutex;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG X11SalInstance::ReleaseYieldMutex()
+{
+ SalYieldMutex* pYieldMutex = mpSalYieldMutex;
+ if ( pYieldMutex->GetThreadId() ==
+ NAMESPACE_VOS(OThread)::getCurrentIdentifier() )
+ {
+ ULONG nCount = pYieldMutex->GetAcquireCount();
+ ULONG n = nCount;
+ while ( n )
+ {
+ pYieldMutex->release();
+ n--;
+ }
+
+ return nCount;
+ }
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalInstance::AcquireYieldMutex( ULONG nCount )
+{
+ SalYieldMutex* pYieldMutex = mpSalYieldMutex;
+ while ( nCount )
+ {
+ pYieldMutex->acquire();
+ nCount--;
+ }
+}
+
+void X11SalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents )
+{ GetX11SalData()->GetLib()->Yield( bWait, bHandleAllCurrentEvents ); }
+
+void* X11SalInstance::GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes )
+{
+ static const char* pDisplay = getenv( "DISPLAY" );
+ rReturnedType = AsciiCString;
+ rReturnedBytes = pDisplay ? strlen( pDisplay )+1 : 1;
+ return pDisplay ? (void*)pDisplay : (void*)"";
+}
+
+SalFrame *X11SalInstance::CreateFrame( SalFrame *pParent, ULONG nSalFrameStyle )
+{
+ SalFrame *pFrame = new X11SalFrame( pParent, nSalFrameStyle );
+
+ return pFrame;
+}
+
+SalFrame* X11SalInstance::CreateChildFrame( SystemParentData* pParentData, ULONG nStyle )
+{
+ SalFrame* pFrame = new X11SalFrame( NULL, nStyle, pParentData );
+
+ return pFrame;
+}
+
+void X11SalInstance::DestroyFrame( SalFrame* pFrame )
+{
+ delete pFrame;
+}
+
+static void getServerDirectories( std::list< rtl::OString >& o_rFontPaths )
+{
+#ifdef LINUX
+ /*
+ * chkfontpath exists on some (RH derived) Linux distributions
+ */
+ static const char* pCommands[] = {
+ "/usr/sbin/chkfontpath 2>/dev/null", "chkfontpath 2>/dev/null"
+ };
+ ::std::list< ByteString > aLines;
+
+ for( unsigned int i = 0; i < sizeof(pCommands)/sizeof(pCommands[0]); i++ )
+ {
+ FILE* pPipe = popen( pCommands[i], "r" );
+ aLines.clear();
+ if( pPipe )
+ {
+ char line[1024];
+ char* pSearch;
+ while( fgets( line, sizeof(line), pPipe ) )
+ {
+ int nLen = strlen( line );
+ if( line[nLen-1] == '\n' )
+ line[nLen-1] = 0;
+ pSearch = strstr( line, ": " );
+ if( pSearch )
+ aLines.push_back( pSearch+2 );
+ }
+ if( ! pclose( pPipe ) )
+ break;
+ }
+ }
+
+ for( ::std::list< ByteString >::iterator it = aLines.begin(); it != aLines.end(); ++it )
+ {
+ if( ! access( it->GetBuffer(), F_OK ) )
+ {
+ o_rFontPaths.push_back( *it );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "adding fs dir %s\n", it->GetBuffer() );
+#endif
+ }
+ }
+#else
+ (void)o_rFontPaths;
+#endif
+}
+
+
+
+void X11SalInstance::FillFontPathList( std::list< rtl::OString >& o_rFontPaths )
+{
+ Display *pDisplay = GetX11SalData()->GetDisplay()->GetDisplay();
+
+ DBG_ASSERT( pDisplay, "No Display !" );
+ if( pDisplay )
+ {
+ // get font paths to look for fonts
+ int nPaths = 0, i;
+ char** pPaths = XGetFontPath( pDisplay, &nPaths );
+
+ bool bServerDirs = false;
+ for( i = 0; i < nPaths; i++ )
+ {
+ OString aPath( pPaths[i] );
+ sal_Int32 nPos = 0;
+ if( ! bServerDirs
+ && ( nPos = aPath.indexOf( ':' ) ) > 0
+ && ( !aPath.copy(nPos).equals( ":unscaled" ) ) )
+ {
+ bServerDirs = true;
+ getServerDirectories( o_rFontPaths );
+ }
+ else
+ {
+ psp::normPath( aPath );
+ o_rFontPaths.push_back( aPath );
+ }
+ }
+
+ if( nPaths )
+ XFreeFontPath( pPaths );
+ }
+
+ // insert some standard directories
+ o_rFontPaths.push_back( "/usr/openwin/lib/X11/fonts/TrueType" );
+ o_rFontPaths.push_back( "/usr/openwin/lib/X11/fonts/Type1" );
+ o_rFontPaths.push_back( "/usr/openwin/lib/X11/fonts/Type1/sun" );
+ o_rFontPaths.push_back( "/usr/X11R6/lib/X11/fonts/truetype" );
+ o_rFontPaths.push_back( "/usr/X11R6/lib/X11/fonts/Type1" );
+
+ #ifdef SOLARIS
+ /* cde specials, from /usr/dt/bin/Xsession: here are the good fonts,
+ the OWfontpath file may contain as well multiple lines as a comma
+ separated list of fonts in each line. to make it even more weird
+ environment variables are allowed as well */
+
+ const char* lang = getenv("LANG");
+ if ( lang != NULL )
+ {
+ String aOpenWinDir( String::CreateFromAscii( "/usr/openwin/lib/locale/" ) );
+ aOpenWinDir.AppendAscii( lang );
+ aOpenWinDir.AppendAscii( "/OWfontpath" );
+
+ SvFileStream aStream( aOpenWinDir, STREAM_READ );
+
+ // TODO: replace environment variables
+ while( aStream.IsOpen() && ! aStream.IsEof() )
+ {
+ ByteString aLine;
+ aStream.ReadLine( aLine );
+ // need an OString for normpath
+ OString aNLine( aLine );
+ psp::normPath( aNLine );
+ aLine = aNLine;
+ // try to avoid bad fonts in some cases
+ static bool bAvoid = (strncasecmp( lang, "ar", 2 ) == 0) || (strncasecmp( lang, "he", 2 ) == 0) || strncasecmp( lang, "iw", 2 ) == 0 || (strncasecmp( lang, "hi", 2 ) == 0);
+ if( bAvoid && aLine.Search( "iso_8859" ) != STRING_NOTFOUND )
+ continue;
+ o_rFontPaths.push_back( aLine );
+ }
+ }
+ #endif /* SOLARIS */
+}
+
+extern "C" { static void SAL_CALL thisModule() {} }
+
+void X11SalInstance::AddToRecentDocumentList(const rtl::OUString& rFileUrl, const rtl::OUString& rMimeType)
+{
+ const rtl::OUString SYM_ADD_TO_RECENTLY_USED_FILE_LIST(RTL_CONSTASCII_USTRINGPARAM("add_to_recently_used_file_list"));
+ const rtl::OUString LIB_RECENT_FILE(RTL_CONSTASCII_USTRINGPARAM("librecentfile.so"));
+ typedef void (*PFUNC_ADD_TO_RECENTLY_USED_LIST)(const rtl::OUString&, const rtl::OUString&);
+
+ PFUNC_ADD_TO_RECENTLY_USED_LIST add_to_recently_used_file_list = 0;
+
+ osl::Module module;
+ module.loadRelative( &thisModule, LIB_RECENT_FILE );
+ if (module.is())
+ add_to_recently_used_file_list = (PFUNC_ADD_TO_RECENTLY_USED_LIST)module.getFunctionSymbol(SYM_ADD_TO_RECENTLY_USED_FILE_LIST);
+ if (add_to_recently_used_file_list)
+ add_to_recently_used_file_list(rFileUrl, rMimeType);
+}
diff --git a/vcl/unx/source/app/salsys.cxx b/vcl/unx/source/app/salsys.cxx
new file mode 100644
index 000000000000..1ccb214df4ed
--- /dev/null
+++ b/vcl/unx/source/app/salsys.cxx
@@ -0,0 +1,225 @@
+/*************************************************************************
+ *
+ * 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 <salunx.h>
+#include <vcl/salsys.hxx>
+#include <dtint.hxx>
+#include <vcl/msgbox.hxx>
+#include <vcl/button.hxx>
+#include <vcl/svdata.hxx>
+#include <saldata.hxx>
+#include <salinst.h>
+#include <saldisp.hxx>
+#include <salsys.h>
+
+#include <rtl/ustrbuf.hxx>
+#include <osl/thread.h>
+
+
+SalSystem* X11SalInstance::CreateSalSystem()
+{
+ return new X11SalSystem();
+}
+
+// -----------------------------------------------------------------------
+
+X11SalSystem::~X11SalSystem()
+{
+}
+
+// for the moment only handle xinerama case
+unsigned int X11SalSystem::GetDisplayScreenCount()
+{
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ return pSalDisp->IsXinerama() ? pSalDisp->GetXineramaScreens().size() : pSalDisp->GetScreenCount();
+}
+
+bool X11SalSystem::IsMultiDisplay()
+{
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ unsigned int nScreenCount = pSalDisp->GetScreenCount();
+ return pSalDisp->IsXinerama() ? false : (nScreenCount > 1);
+}
+
+unsigned int X11SalSystem::GetDefaultDisplayNumber()
+{
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ return pSalDisp->GetDefaultScreenNumber();
+}
+
+Rectangle X11SalSystem::GetDisplayScreenPosSizePixel( unsigned int nScreen )
+{
+ Rectangle aRet;
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ if( pSalDisp->IsXinerama() )
+ {
+ const std::vector< Rectangle >& rScreens = pSalDisp->GetXineramaScreens();
+ if( nScreen < rScreens.size() )
+ aRet = rScreens[nScreen];
+ }
+ else
+ {
+ const SalDisplay::ScreenData& rScreen = pSalDisp->getDataForScreen( nScreen );
+ aRet = Rectangle( Point( 0, 0 ), rScreen.m_aSize );
+ }
+
+ return aRet;
+}
+
+Rectangle X11SalSystem::GetDisplayWorkAreaPosSizePixel( unsigned int nScreen )
+{
+ // FIXME: workareas
+ return GetDisplayScreenPosSizePixel( nScreen );
+}
+
+rtl::OUString X11SalSystem::GetScreenName( unsigned int nScreen )
+{
+ rtl::OUString aScreenName;
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ if( pSalDisp->IsXinerama() )
+ {
+ const std::vector< Rectangle >& rScreens = pSalDisp->GetXineramaScreens();
+ if( nScreen >= rScreens.size() )
+ nScreen = 0;
+ rtl::OUStringBuffer aBuf( 256 );
+ aBuf.append( rtl::OStringToOUString( rtl::OString( DisplayString( pSalDisp->GetDisplay() ) ), osl_getThreadTextEncoding() ) );
+ aBuf.appendAscii( " [" );
+ aBuf.append( static_cast<sal_Int32>(nScreen) );
+ aBuf.append( sal_Unicode(']') );
+ aScreenName = aBuf.makeStringAndClear();
+ }
+ else
+ {
+ if( nScreen >= static_cast<unsigned int>(pSalDisp->GetScreenCount()) )
+ nScreen = 0;
+ rtl::OUStringBuffer aBuf( 256 );
+ aBuf.append( rtl::OStringToOUString( rtl::OString( DisplayString( pSalDisp->GetDisplay() ) ), osl_getThreadTextEncoding() ) );
+ // search backwards for ':'
+ int nPos = aBuf.getLength();
+ if( nPos > 0 )
+ nPos--;
+ while( nPos > 0 && aBuf.charAt( nPos ) != ':' )
+ nPos--;
+ // search forward to '.'
+ while( nPos < aBuf.getLength() && aBuf.charAt( nPos ) != '.' )
+ nPos++;
+ if( nPos < aBuf.getLength() )
+ aBuf.setLength( nPos+1 );
+ else
+ aBuf.append( sal_Unicode('.') );
+ aBuf.append( static_cast<sal_Int32>(nScreen) );
+ aScreenName = aBuf.makeStringAndClear();
+ }
+ return aScreenName;
+}
+
+int X11SalSystem::ShowNativeDialog( const String& rTitle, const String& rMessage, const std::list< String >& rButtons, int nDefButton )
+{
+ int nRet = -1;
+
+ ImplSVData* pSVData = ImplGetSVData();
+ if( pSVData->mpIntroWindow )
+ pSVData->mpIntroWindow->Hide();
+
+ WarningBox aWarn( NULL, WB_STDWORK, rMessage );
+ aWarn.SetText( rTitle );
+ aWarn.Clear();
+
+ USHORT nButton = 0;
+ for( std::list< String >::const_iterator it = rButtons.begin(); it != rButtons.end(); ++it )
+ {
+ aWarn.AddButton( *it, nButton+1, nButton == (USHORT)nDefButton ? BUTTONDIALOG_DEFBUTTON : 0 );
+ nButton++;
+ }
+ aWarn.SetFocusButton( (USHORT)nDefButton+1 );
+
+ nRet = ((int)aWarn.Execute()) - 1;
+
+ // normalize behaviour, actually this should never happen
+ if( nRet < -1 || nRet >= int(rButtons.size()) )
+ nRet = -1;
+
+ return nRet;
+}
+
+int X11SalSystem::ShowNativeMessageBox(const String& rTitle, const String& rMessage, int nButtonCombination, int nDefaultButton)
+{
+ int nDefButton = 0;
+ std::list< String > aButtons;
+ int nButtonIds[5], nBut = 0;
+
+ if( nButtonCombination == SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_OK ||
+ nButtonCombination == SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_OK_CANCEL )
+ {
+ aButtons.push_back( Button::GetStandardText( BUTTON_OK ) );
+ nButtonIds[nBut++] = SALSYSTEM_SHOWNATIVEMSGBOX_BTN_OK;
+ }
+ if( nButtonCombination == SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_YES_NO_CANCEL ||
+ nButtonCombination == SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_YES_NO )
+ {
+ aButtons.push_back( Button::GetStandardText( BUTTON_YES ) );
+ nButtonIds[nBut++] = SALSYSTEM_SHOWNATIVEMSGBOX_BTN_YES;
+ aButtons.push_back( Button::GetStandardText( BUTTON_NO ) );
+ nButtonIds[nBut++] = SALSYSTEM_SHOWNATIVEMSGBOX_BTN_NO;
+ if( nDefaultButton == SALSYSTEM_SHOWNATIVEMSGBOX_BTN_NO )
+ nDefButton = 1;
+ }
+ if( nButtonCombination == SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_OK_CANCEL ||
+ nButtonCombination == SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_YES_NO_CANCEL ||
+ nButtonCombination == SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_RETRY_CANCEL )
+ {
+ if( nButtonCombination == SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_RETRY_CANCEL )
+ {
+ aButtons.push_back( Button::GetStandardText( BUTTON_RETRY ) );
+ nButtonIds[nBut++] = SALSYSTEM_SHOWNATIVEMSGBOX_BTN_RETRY;
+ }
+ aButtons.push_back( Button::GetStandardText( BUTTON_CANCEL ) );
+ nButtonIds[nBut++] = SALSYSTEM_SHOWNATIVEMSGBOX_BTN_CANCEL;
+ if( nDefaultButton == SALSYSTEM_SHOWNATIVEMSGBOX_BTN_CANCEL )
+ nDefButton = aButtons.size()-1;
+ }
+ if( nButtonCombination == SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_ABORT_RETRY_IGNORE )
+ {
+ aButtons.push_back( Button::GetStandardText( BUTTON_ABORT ) );
+ nButtonIds[nBut++] = SALSYSTEM_SHOWNATIVEMSGBOX_BTN_ABORT;
+ aButtons.push_back( Button::GetStandardText( BUTTON_RETRY ) );
+ nButtonIds[nBut++] = SALSYSTEM_SHOWNATIVEMSGBOX_BTN_RETRY;
+ aButtons.push_back( Button::GetStandardText( BUTTON_IGNORE ) );
+ nButtonIds[nBut++] = SALSYSTEM_SHOWNATIVEMSGBOX_BTN_IGNORE;
+ switch( nDefaultButton )
+ {
+ case SALSYSTEM_SHOWNATIVEMSGBOX_BTN_RETRY: nDefButton = 1;break;
+ case SALSYSTEM_SHOWNATIVEMSGBOX_BTN_IGNORE: nDefButton = 2;break;
+ }
+ }
+ int nResult = ShowNativeDialog( rTitle, rMessage, aButtons, nDefButton );
+
+ return nResult != -1 ? nButtonIds[ nResult ] : 0;
+}
diff --git a/vcl/unx/source/app/saltimer.cxx b/vcl/unx/source/app/saltimer.cxx
new file mode 100644
index 000000000000..431470935d9e
--- /dev/null
+++ b/vcl/unx/source/app/saltimer.cxx
@@ -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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <salunx.h>
+#include <saldata.hxx>
+#include <saldisp.hxx>
+#include <saltimer.h>
+#include <salinst.h>
+
+// -=-= SalData =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalData::Timeout() const
+{
+ ImplSVData* pSVData = ImplGetSVData();
+ if( pSVData->mpSalTimer )
+ pSVData->mpSalTimer->CallCallback();
+}
+
+// -=-= SalXLib =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void SalXLib::StopTimer()
+{
+ m_aTimeout.tv_sec = 0;
+ m_aTimeout.tv_usec = 0;
+ m_nTimeoutMS = 0;
+}
+
+void SalXLib::StartTimer( ULONG nMS )
+{
+ timeval Timeout (m_aTimeout); // previous timeout.
+ gettimeofday (&m_aTimeout, 0);
+
+ m_nTimeoutMS = nMS;
+ m_aTimeout += m_nTimeoutMS;
+
+ if ((Timeout > m_aTimeout) || (Timeout.tv_sec == 0))
+ {
+ // Wakeup from previous timeout (or stopped timer).
+ Wakeup();
+ }
+}
+
+// -=-= SalTimer -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+SalTimer* X11SalInstance::CreateSalTimer()
+{
+ return new X11SalTimer();
+}
+
+X11SalTimer::~X11SalTimer()
+{
+}
+
+void X11SalTimer::Stop()
+{
+ GetX11SalData()->GetLib()->StopTimer();
+}
+
+void X11SalTimer::Start( ULONG nMS )
+{
+ GetX11SalData()->GetLib()->StartTimer( nMS );
+}
+
diff --git a/vcl/unx/source/app/sm.cxx b/vcl/unx/source/app/sm.cxx
new file mode 100644
index 000000000000..959d6af5912d
--- /dev/null
+++ b/vcl/unx/source/app/sm.cxx
@@ -0,0 +1,800 @@
+/*************************************************************************
+ *
+ * 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 <unistd.h>
+#include <sys/poll.h>
+#include <fcntl.h>
+
+#include <stdio.h>
+
+#include <osl/process.h>
+#include <osl/security.h>
+
+#include <tools/prex.h>
+#include <X11/Xatom.h>
+#include <tools/postx.h>
+#include <sm.hxx>
+#include <saldata.hxx>
+#include <saldisp.hxx>
+#include <salframe.h>
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+#include <salinst.h>
+
+#include <osl/conditn.h>
+
+#define USE_SM_EXTENSION
+
+#if OSL_DEBUG_LEVEL > 1
+#include <cstdarg>
+static bool bFirstAssert = true;
+#endif
+
+#if OSL_DEBUG_LEVEL > 1
+inline void SMprintf( const char* pFormat, ... )
+#else
+inline void SMprintf( const char*, ... )
+#endif
+{
+#if OSL_DEBUG_LEVEL > 1
+ FILE* fp = fopen( "/tmp/sessionlog.txt", bFirstAssert ? "w" : "a" );
+ if(!fp) return;
+ bFirstAssert = false;
+ std::va_list ap;
+ va_start( ap, pFormat );
+ vfprintf( fp, pFormat, ap );
+ fclose( fp );
+ va_end( ap );
+#endif
+};
+
+static IceSalSession* pOneInstance = NULL;
+
+SalSession* X11SalInstance::CreateSalSession()
+{
+ if( ! pOneInstance )
+ pOneInstance = new IceSalSession();
+ return pOneInstance;
+}
+
+/*
+ * class IceSalSession
+ */
+
+static X11SalFrame* pOldStyleSaveFrame = NULL;
+
+IceSalSession::IceSalSession()
+{
+}
+
+IceSalSession::~IceSalSession()
+{
+ if( pOneInstance == this )
+ pOneInstance = NULL;
+}
+
+void IceSalSession::queryInteraction()
+{
+ if( ! SessionManagerClient::queryInteraction() )
+ {
+ SalSessionInteractionEvent aEvent( false );
+ CallCallback( &aEvent );
+ }
+}
+
+void IceSalSession::interactionDone()
+{
+ SessionManagerClient::interactionDone( false );
+}
+
+void IceSalSession::saveDone()
+{
+ SessionManagerClient::saveDone();
+ if( pOldStyleSaveFrame )
+ {
+ // note: does nothing if not running in generic plugin
+ X11SalFrame::SaveYourselfDone( pOldStyleSaveFrame );
+ }
+}
+
+bool IceSalSession::cancelShutdown()
+{
+ SessionManagerClient::interactionDone( true );
+ return false;
+}
+
+void IceSalSession::handleOldX11SaveYourself( SalFrame* pFrame )
+{
+ // do this only once
+ if( ! pOldStyleSaveFrame )
+ {
+ pOldStyleSaveFrame = static_cast<X11SalFrame*>(pFrame);
+ if( pOneInstance )
+ {
+ SalSessionSaveRequestEvent aEvent( true, false );
+ pOneInstance->CallCallback( &aEvent );
+ }
+ }
+}
+
+extern "C" void SAL_CALL ICEConnectionWorker( void* );
+
+class ICEConnectionObserver
+{
+ friend void SAL_CALL ICEConnectionWorker(void*);
+ static BOOL bIsWatching;
+ static void ICEWatchProc( IceConn connection, IcePointer client_data,
+ Bool opening, IcePointer* watch_data );
+
+ static struct pollfd* pFilehandles;
+ static IceConn* pConnections;
+ static int nConnections;
+ static int nWakeupFiles[2];
+ static oslMutex ICEMutex;
+ static oslThread ICEThread;
+#ifdef USE_SM_EXTENSION
+ static IceIOErrorHandler origIOErrorHandler;
+ static IceErrorHandler origErrorHandler;
+#endif
+public:
+
+ static void activate();
+ static void deactivate();
+ static void lock();
+ static void unlock();
+ static void wakeup();
+};
+
+
+SmcConn SessionManagerClient::aSmcConnection = NULL;
+ByteString SessionManagerClient::aClientID;
+BOOL ICEConnectionObserver::bIsWatching = FALSE;
+struct pollfd* ICEConnectionObserver::pFilehandles = NULL;
+IceConn* ICEConnectionObserver::pConnections = NULL;
+int ICEConnectionObserver::nConnections = 0;
+oslMutex ICEConnectionObserver::ICEMutex = NULL;
+oslThread ICEConnectionObserver::ICEThread = NULL;
+int ICEConnectionObserver::nWakeupFiles[2] = { 0, 0 };
+
+#ifdef USE_SM_EXTENSION
+IceIOErrorHandler ICEConnectionObserver::origIOErrorHandler = NULL;
+IceErrorHandler ICEConnectionObserver::origErrorHandler = NULL;
+
+static void IgnoreIceErrors(IceConn, Bool, int, unsigned long, int, int, IcePointer)
+{
+}
+
+static void IgnoreIceIOErrors(IceConn)
+{
+}
+#endif
+
+// HACK
+bool SessionManagerClient::bDocSaveDone = false;
+
+
+static SmProp* pSmProps = NULL;
+static SmProp** ppSmProps = NULL;
+static int nSmProps = 0;
+static unsigned char *pSmRestartHint = NULL;
+
+
+static void BuildSmPropertyList()
+{
+ if( ! pSmProps )
+ {
+ ByteString aExec( SessionManagerClient::getExecName(), osl_getThreadTextEncoding() );
+
+ nSmProps = 5;
+ pSmProps = new SmProp[ nSmProps ];
+
+ pSmProps[ 0 ].name = const_cast<char*>(SmCloneCommand);
+ pSmProps[ 0 ].type = const_cast<char*>(SmLISTofARRAY8);
+ pSmProps[ 0 ].num_vals = 1;
+ pSmProps[ 0 ].vals = new SmPropValue;
+ pSmProps[ 0 ].vals->length = aExec.Len()+1;
+ pSmProps[ 0 ].vals->value = strdup( aExec.GetBuffer() );
+
+ pSmProps[ 1 ].name = const_cast<char*>(SmProgram);
+ pSmProps[ 1 ].type = const_cast<char*>(SmARRAY8);
+ pSmProps[ 1 ].num_vals = 1;
+ pSmProps[ 1 ].vals = new SmPropValue;
+ pSmProps[ 1 ].vals->length = aExec.Len()+1;
+ pSmProps[ 1 ].vals->value = strdup( aExec.GetBuffer() );
+
+ pSmProps[ 2 ].name = const_cast<char*>(SmRestartCommand);
+ pSmProps[ 2 ].type = const_cast<char*>(SmLISTofARRAY8);
+ pSmProps[ 2 ].num_vals = 3;
+ pSmProps[ 2 ].vals = new SmPropValue[3];
+ pSmProps[ 2 ].vals[0].length = aExec.Len()+1;
+ pSmProps[ 2 ].vals[0].value = strdup( aExec.GetBuffer() );
+ ByteString aRestartOption( "-session=" );
+ aRestartOption.Append( SessionManagerClient::getSessionID() );
+ pSmProps[ 2 ].vals[1].length = aRestartOption.Len()+1;
+ pSmProps[ 2 ].vals[1].value = strdup( aRestartOption.GetBuffer() );
+ ByteString aRestartOptionNoLogo( "-nologo" );
+ pSmProps[ 2 ].vals[2].length = aRestartOptionNoLogo.Len()+1;
+ pSmProps[ 2 ].vals[2].value = strdup( aRestartOptionNoLogo.GetBuffer() );
+
+ rtl::OUString aUserName;
+ rtl::OString aUser;
+ oslSecurity aSec = osl_getCurrentSecurity();
+ if( aSec )
+ {
+ osl_getUserName( aSec, &aUserName.pData );
+ aUser = rtl::OUStringToOString( aUserName, osl_getThreadTextEncoding() );
+ osl_freeSecurityHandle( aSec );
+ }
+
+ pSmProps[ 3 ].name = const_cast<char*>(SmUserID);
+ pSmProps[ 3 ].type = const_cast<char*>(SmARRAY8);
+ pSmProps[ 3 ].num_vals = 1;
+ pSmProps[ 3 ].vals = new SmPropValue;
+ pSmProps[ 3 ].vals->value = strdup( aUser.getStr() );
+ pSmProps[ 3 ].vals->length = strlen( (char *)pSmProps[ 3 ].vals->value )+1;
+
+ pSmProps[ 4 ].name = const_cast<char*>(SmRestartStyleHint);
+ pSmProps[ 4 ].type = const_cast<char*>(SmCARD8);
+ pSmProps[ 4 ].num_vals = 1;
+ pSmProps[ 4 ].vals = new SmPropValue;
+ pSmProps[ 4 ].vals->value = malloc(1);
+ pSmRestartHint = (unsigned char *)pSmProps[ 4 ].vals->value;
+ *pSmRestartHint = SmRestartIfRunning;
+ pSmProps[ 4 ].vals->length = 1;
+
+ ppSmProps = new SmProp*[ nSmProps ];
+ for( int i = 0; i < nSmProps; i++ )
+ ppSmProps[ i ] = &pSmProps[i];
+ }
+}
+
+bool SessionManagerClient::checkDocumentsSaved()
+{
+ return bDocSaveDone;
+}
+
+IMPL_STATIC_LINK( SessionManagerClient, SaveYourselfHdl, void*, EMPTYARG )
+{
+ SMprintf( "posting save documents event shutdown = %s\n", (pThis!=0) ? "true" : "false" );
+
+ static bool bFirstShutdown=true;
+ if (pThis != 0 && bFirstShutdown) //first shutdown request
+ {
+ bFirstShutdown = false;
+ /*
+ If we have no actual frames open, e.g. we launched a quickstarter,
+ and then shutdown all our frames leaving just a quickstarter running,
+ then we don't want to launch an empty toplevel frame on the next
+ start. (The job of scheduling the restart of the quick-starter is a
+ task of the quick-starter)
+ */
+ *pSmRestartHint = SmRestartNever;
+ const std::list< SalFrame* >& rFrames = GetX11SalData()->GetDisplay()->getFrames();
+ for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it )
+ {
+ Window *pWindow = (*it)->GetWindow();
+ if (pWindow && pWindow->IsVisible())
+ {
+ *pSmRestartHint = SmRestartIfRunning;
+ break;
+ }
+ }
+ }
+
+ if( pOneInstance )
+ {
+ SalSessionSaveRequestEvent aEvent( pThis != 0, false );
+ pOneInstance->CallCallback( &aEvent );
+ }
+ else
+ saveDone();
+
+ return 0;
+}
+
+IMPL_STATIC_LINK_NOINSTANCE( SessionManagerClient, InteractionHdl, void*, EMPTYARG )
+{
+ SMprintf( "interaction link\n" );
+ if( pOneInstance )
+ {
+ SalSessionInteractionEvent aEvent( true );
+ pOneInstance->CallCallback( &aEvent );
+ }
+
+ return 0;
+}
+
+IMPL_STATIC_LINK_NOINSTANCE( SessionManagerClient, ShutDownCancelHdl, void*, EMPTYARG )
+{
+ SMprintf( "shutdown cancel\n" );
+ if( pOneInstance )
+ {
+ SalSessionShutdownCancelEvent aEvent;
+ pOneInstance->CallCallback( &aEvent );
+ }
+
+ return 0;
+}
+
+void SessionManagerClient::SaveYourselfProc(
+ SmcConn,
+ SmPointer,
+ int save_type,
+ Bool shutdown,
+ int interact_style,
+ Bool
+ )
+{
+ SMprintf( "Session: save yourself, save_type = %s, shutdown = %s, interact_style = %s, fast = %s\n",
+ save_type == SmSaveLocal ? "SmcSaveLocal" :
+ ( save_type == SmSaveGlobal ? "SmcSaveGlobal" :
+ ( save_type == SmSaveBoth ? "SmcSaveBoth" : "<unknown>" ) ),
+ shutdown ? "true" : "false",
+ interact_style == SmInteractStyleNone ? "SmInteractStyleNone" :
+ ( interact_style == SmInteractStyleErrors ? "SmInteractStyleErrors" :
+ ( interact_style == SmInteractStyleAny ? "SmInteractStyleAny" : "<unknown>" ) ),
+ false ? "true" : "false"
+ );
+ BuildSmPropertyList();
+#ifdef USE_SM_EXTENSION
+ bDocSaveDone = false;
+ /* #i49875# some session managers send a "die" message if the
+ * saveDone does not come early enough for their convenience
+ * this can occasionally happen on startup, especially the first
+ * startup. So shortcut the "not shutting down" case since the
+ * upper layers are currently not interested in that event anyway.
+ */
+ if( ! shutdown )
+ {
+ SessionManagerClient::saveDone();
+ return;
+ }
+ Application::PostUserEvent( STATIC_LINK( (void*)(shutdown ? 0xffffffff : 0x0), SessionManagerClient, SaveYourselfHdl ) );
+ SMprintf( "waiting for save yourself event to be processed\n" );
+#endif
+}
+
+IMPL_STATIC_LINK_NOINSTANCE( SessionManagerClient, ShutDownHdl, void*, EMPTYARG )
+{
+ if( pOneInstance )
+ {
+ SalSessionQuitEvent aEvent;
+ pOneInstance->CallCallback( &aEvent );
+ }
+
+ const std::list< SalFrame* >& rFrames = GetX11SalData()->GetDisplay()->getFrames();
+ SMprintf( rFrames.begin() != rFrames.end() ? "shutdown on first frame\n" : "shutdown event but no frame\n" );
+ if( rFrames.begin() != rFrames.end() )
+ rFrames.front()->CallCallback( SALEVENT_SHUTDOWN, 0 );
+ return 0;
+}
+
+void SessionManagerClient::DieProc(
+ SmcConn connection,
+ SmPointer
+ )
+{
+ SMprintf( "Session: die\n" );
+ if( connection == aSmcConnection )
+ {
+ Application::PostUserEvent( STATIC_LINK( NULL, SessionManagerClient, ShutDownHdl ) );
+ SMprintf( "waiting for shutdown event to be processed\n" );
+ }
+}
+
+void SessionManagerClient::SaveCompleteProc(
+ SmcConn,
+ SmPointer
+ )
+{
+ SMprintf( "Session: save complete\n" );
+}
+
+void SessionManagerClient::ShutdownCanceledProc(
+ SmcConn connection,
+ SmPointer )
+{
+ SMprintf( "Session: shutdown canceled\n" );
+ if( connection == aSmcConnection )
+ Application::PostUserEvent( STATIC_LINK( NULL, SessionManagerClient, ShutDownCancelHdl ) );
+}
+
+void SessionManagerClient::InteractProc(
+ SmcConn connection,
+ SmPointer )
+{
+ SMprintf( "Session: interaction request completed\n" );
+ if( connection == aSmcConnection )
+ Application::PostUserEvent( STATIC_LINK( NULL, SessionManagerClient, InteractionHdl ) );
+}
+
+void SessionManagerClient::saveDone()
+{
+ if( aSmcConnection )
+ {
+ ICEConnectionObserver::lock();
+ SmcSetProperties( aSmcConnection, nSmProps, ppSmProps );
+ SmcSaveYourselfDone( aSmcConnection, True );
+ SMprintf( "sent SaveYourselfDone SmRestartHint of %d\n", *pSmRestartHint );
+ bDocSaveDone = true;
+ ICEConnectionObserver::unlock();
+ }
+}
+
+
+void SessionManagerClient::open()
+{
+ static SmcCallbacks aCallbacks;
+
+#ifdef USE_SM_EXTENSION
+ // this is the way Xt does it, so we can too
+ if( ! aSmcConnection && getenv( "SESSION_MANAGER" ) )
+ {
+ char aErrBuf[1024];
+ ICEConnectionObserver::activate();
+ ICEConnectionObserver::lock();
+
+ char* pClientID = NULL;
+ const ByteString& rPrevId( getPreviousSessionID() );
+
+ aCallbacks.save_yourself.callback = SaveYourselfProc;
+ aCallbacks.save_yourself.client_data = NULL;
+ aCallbacks.die.callback = DieProc;
+ aCallbacks.die.client_data = NULL;
+ aCallbacks.save_complete.callback = SaveCompleteProc;
+ aCallbacks.save_complete.client_data = NULL;
+ aCallbacks.shutdown_cancelled.callback = ShutdownCanceledProc;
+ aCallbacks.shutdown_cancelled.client_data = NULL;
+ aSmcConnection = SmcOpenConnection( NULL,
+ NULL,
+ SmProtoMajor,
+ SmProtoMinor,
+ SmcSaveYourselfProcMask |
+ SmcDieProcMask |
+ SmcSaveCompleteProcMask |
+ SmcShutdownCancelledProcMask ,
+ &aCallbacks,
+ rPrevId.Len() ? const_cast<char*>(rPrevId.GetBuffer()) : NULL,
+ &pClientID,
+ sizeof( aErrBuf ),
+ aErrBuf );
+ if( ! aSmcConnection )
+ SMprintf( "SmcOpenConnection failed: %s\n", aErrBuf );
+ else
+ SMprintf( "SmcOpenConnection succeeded, client ID is \"%s\"\n", pClientID );
+ aClientID = ByteString( pClientID );
+ free( pClientID );
+ pClientID = NULL;
+ ICEConnectionObserver::unlock();
+
+ SalDisplay* pDisp = GetX11SalData()->GetDisplay();
+ if( pDisp->GetDrawable( pDisp->GetDefaultScreenNumber() ) && aClientID.Len() )
+ {
+ XChangeProperty( pDisp->GetDisplay(),
+ pDisp->GetDrawable( pDisp->GetDefaultScreenNumber() ),
+ XInternAtom( pDisp->GetDisplay(), "SM_CLIENT_ID", False ),
+ XA_STRING,
+ 8,
+ PropModeReplace,
+ (unsigned char*)aClientID.GetBuffer(),
+ aClientID.Len()
+ );
+ }
+ }
+ else if( ! aSmcConnection )
+ SMprintf( "no SESSION_MANAGER\n" );
+#endif
+}
+
+const ByteString& SessionManagerClient::getSessionID()
+{
+ return aClientID;
+}
+
+void SessionManagerClient::close()
+{
+ if( aSmcConnection )
+ {
+#ifdef USE_SM_EXTENSION
+ ICEConnectionObserver::lock();
+ SMprintf( "attempting SmcCloseConnection\n" );
+ SmcCloseConnection( aSmcConnection, 0, NULL );
+ SMprintf( "SmcConnection closed\n" );
+ ICEConnectionObserver::unlock();
+ ICEConnectionObserver::deactivate();
+#endif
+ aSmcConnection = NULL;
+ }
+}
+
+bool SessionManagerClient::queryInteraction()
+{
+ bool bRet = false;
+ if( aSmcConnection )
+ {
+ ICEConnectionObserver::lock();
+ if( SmcInteractRequest( aSmcConnection, SmDialogNormal, InteractProc, NULL ) )
+ bRet = true;
+ ICEConnectionObserver::unlock();
+ }
+ return bRet;
+}
+
+void SessionManagerClient::interactionDone( bool bCancelShutdown )
+{
+ if( aSmcConnection )
+ {
+ ICEConnectionObserver::lock();
+ SmcInteractDone( aSmcConnection, bCancelShutdown ? True : False );
+ ICEConnectionObserver::unlock();
+ }
+}
+
+
+String SessionManagerClient::getExecName()
+{
+ rtl::OUString aExec, aSysExec;
+ osl_getExecutableFile( &aExec.pData );
+ osl_getSystemPathFromFileURL( aExec.pData, &aSysExec.pData );
+
+ int nPos = aSysExec.indexOf( rtl::OUString::createFromAscii( ".bin" ) );
+ if( nPos != -1 )
+ aSysExec = aSysExec.copy( 0, nPos );
+ return aSysExec;
+}
+
+
+const ByteString& SessionManagerClient::getPreviousSessionID()
+{
+ static ByteString aPrevId;
+
+ int nCommands = osl_getCommandArgCount();
+ for( int i = 0; i < nCommands; i++ )
+ {
+ ::rtl::OUString aArg;
+ osl_getCommandArg( i, &aArg.pData );
+ if( aArg.compareToAscii( "-session=", 9 ) == 0 )
+ {
+ aPrevId = ByteString( ::rtl::OUStringToOString( aArg.copy( 9 ), osl_getThreadTextEncoding() ) );
+ break;
+ }
+ }
+ SMprintf( "previous ID = \"%s\"\n", aPrevId.GetBuffer() );
+ return aPrevId;
+}
+
+void ICEConnectionObserver::lock()
+{
+ osl_acquireMutex( ICEMutex );
+}
+
+void ICEConnectionObserver::unlock()
+{
+ osl_releaseMutex( ICEMutex );
+}
+
+void ICEConnectionObserver::activate()
+{
+ if( ! bIsWatching )
+ {
+ nWakeupFiles[0] = nWakeupFiles[1] = 0;
+ ICEMutex = osl_createMutex();
+ bIsWatching = TRUE;
+#ifdef USE_SM_EXTENSION
+ /*
+ * Default handlers call exit, we don't care that strongly if something
+ * happens to fail
+ */
+ origIOErrorHandler = IceSetIOErrorHandler( IgnoreIceIOErrors );
+ origErrorHandler = IceSetErrorHandler( IgnoreIceErrors );
+ IceAddConnectionWatch( ICEWatchProc, NULL );
+#endif
+ }
+}
+
+void ICEConnectionObserver::deactivate()
+{
+ if( bIsWatching )
+ {
+ lock();
+ bIsWatching = FALSE;
+#ifdef USE_SM_EXTENSION
+ IceRemoveConnectionWatch( ICEWatchProc, NULL );
+ IceSetErrorHandler( origErrorHandler );
+ IceSetIOErrorHandler( origIOErrorHandler );
+#endif
+ nConnections = 0;
+ if( ICEThread )
+ {
+ osl_terminateThread( ICEThread );
+ wakeup();
+ }
+ unlock();
+ if( ICEThread )
+ {
+ osl_joinWithThread( ICEThread );
+ osl_destroyThread( ICEThread );
+ close( nWakeupFiles[1] );
+ close( nWakeupFiles[0] );
+ ICEThread = NULL;
+ }
+ osl_destroyMutex( ICEMutex );
+ ICEMutex = NULL;
+ }
+}
+
+void ICEConnectionObserver::wakeup()
+{
+ char cChar = 'w';
+ write( nWakeupFiles[1], &cChar, 1 );
+}
+
+void ICEConnectionWorker( void* )
+{
+#ifdef USE_SM_EXTENSION
+ while( osl_scheduleThread(ICEConnectionObserver::ICEThread) && ICEConnectionObserver::nConnections )
+ {
+ ICEConnectionObserver::lock();
+ int nConnectionsBefore = ICEConnectionObserver::nConnections;
+ int nBytes = sizeof( struct pollfd )*(nConnectionsBefore+1);
+ struct pollfd* pLocalFD = (struct pollfd*)rtl_allocateMemory( nBytes );
+ rtl_copyMemory( pLocalFD, ICEConnectionObserver::pFilehandles, nBytes );
+ ICEConnectionObserver::unlock();
+
+ int nRet = poll( pLocalFD,nConnectionsBefore+1,-1 );
+ bool bWakeup = (pLocalFD[0].revents & POLLIN);
+ rtl_freeMemory( pLocalFD );
+
+ if( nRet < 1 )
+ continue;
+
+ // clear wakeup pipe
+ if( bWakeup )
+ {
+ char buf[4];
+ while( read( ICEConnectionObserver::nWakeupFiles[0], buf, sizeof( buf ) ) > 0 )
+ ;
+ SMprintf( "file handles active in wakeup: %d\n", nRet );
+ if( nRet == 1 )
+ continue;
+ }
+
+ // check fd's after we obtained the lock
+ ICEConnectionObserver::lock();
+ if( ICEConnectionObserver::nConnections > 0 && ICEConnectionObserver::nConnections == nConnectionsBefore )
+ {
+ nRet = poll( ICEConnectionObserver::pFilehandles+1, ICEConnectionObserver::nConnections, 0 );
+ if( nRet > 0 )
+ {
+ SMprintf( "IceProcessMessages\n" );
+ Bool bReply;
+ for( int i = 0; i < ICEConnectionObserver::nConnections; i++ )
+ if( ICEConnectionObserver::pFilehandles[i+1].revents & POLLIN )
+ IceProcessMessages( ICEConnectionObserver::pConnections[i], NULL, &bReply );
+ }
+ }
+ ICEConnectionObserver::unlock();
+ }
+#endif
+ SMprintf( "shutting donw ICE dispatch thread\n" );
+}
+
+void ICEConnectionObserver::ICEWatchProc(
+ IceConn connection,
+ IcePointer,
+ Bool opening,
+ IcePointer*
+ )
+{
+ // note: this is a callback function for ICE
+ // this implicitly means that a call into ICE lib is calling this
+ // so the ICEMutex MUST already be locked by the caller
+
+#ifdef USE_SM_EXTENSION
+ if( opening )
+ {
+ int fd = IceConnectionNumber( connection );
+ nConnections++;
+ pConnections = (IceConn*)rtl_reallocateMemory( pConnections, sizeof( IceConn )*nConnections );
+ pFilehandles = (struct pollfd*)rtl_reallocateMemory( pFilehandles, sizeof( struct pollfd )*(nConnections+1) );
+ pConnections[ nConnections-1 ] = connection;
+ pFilehandles[ nConnections ].fd = fd;
+ pFilehandles[ nConnections ].events = POLLIN;
+ if( nConnections == 1 )
+ {
+ if( ! pipe( nWakeupFiles ) )
+ {
+ int flags;
+ pFilehandles[0].fd = nWakeupFiles[0];
+ pFilehandles[0].events = POLLIN;
+ // set close-on-exec and nonblock descriptor flag.
+ if ((flags = fcntl (nWakeupFiles[0], F_GETFD)) != -1)
+ {
+ flags |= FD_CLOEXEC;
+ fcntl (nWakeupFiles[0], F_SETFD, flags);
+ }
+ if ((flags = fcntl (nWakeupFiles[0], F_GETFL)) != -1)
+ {
+ flags |= O_NONBLOCK;
+ fcntl (nWakeupFiles[0], F_SETFL, flags);
+ }
+ // set close-on-exec and nonblock descriptor flag.
+ if ((flags = fcntl (nWakeupFiles[1], F_GETFD)) != -1)
+ {
+ flags |= FD_CLOEXEC;
+ fcntl (nWakeupFiles[1], F_SETFD, flags);
+ }
+ if ((flags = fcntl (nWakeupFiles[1], F_GETFL)) != -1)
+ {
+ flags |= O_NONBLOCK;
+ fcntl (nWakeupFiles[1], F_SETFL, flags);
+ }
+ ICEThread = osl_createSuspendedThread( ICEConnectionWorker, NULL );
+ osl_resumeThread( ICEThread );
+ }
+ }
+ }
+ else
+ {
+ for( int i = 0; i < nConnections; i++ )
+ {
+ if( pConnections[i] == connection )
+ {
+ if( i < nConnections-1 )
+ {
+ rtl_moveMemory( pConnections+i, pConnections+i+1, sizeof( IceConn )*(nConnections-i-1) );
+ rtl_moveMemory( pFilehandles+i+1, pFilehandles+i+2, sizeof( struct pollfd )*(nConnections-i-1) );
+ }
+ nConnections--;
+ pConnections = (IceConn*)rtl_reallocateMemory( pConnections, sizeof( IceConn )*nConnections );
+ pFilehandles = (struct pollfd*)rtl_reallocateMemory( pFilehandles, sizeof( struct pollfd )*(nConnections+1) );
+ break;
+ }
+ }
+ if( nConnections == 0 && ICEThread )
+ {
+ SMprintf( "terminating ICEThread\n" );
+ osl_terminateThread( ICEThread );
+ wakeup();
+ // must release the mutex here
+ osl_releaseMutex( ICEMutex );
+ osl_joinWithThread( ICEThread );
+ osl_destroyThread( ICEThread );
+ close( nWakeupFiles[1] );
+ close( nWakeupFiles[0] );
+ ICEThread = NULL;
+ }
+ }
+ SMprintf( "ICE connection on %d %s\n",
+ IceConnectionNumber( connection ),
+ opening ? "inserted" : "removed" );
+ SMprintf( "Display connection is %d\n", ConnectionNumber( GetX11SalData()->GetDisplay()->GetDisplay() ) );
+#endif
+}
diff --git a/vcl/unx/source/app/soicon.cxx b/vcl/unx/source/app/soicon.cxx
new file mode 100644
index 000000000000..2bf9e55731d1
--- /dev/null
+++ b/vcl/unx/source/app/soicon.cxx
@@ -0,0 +1,115 @@
+/*************************************************************************
+ *
+ * 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 <salunx.h>
+#include <saldisp.hxx>
+#include <vcl/salbmp.hxx>
+#include <vcl/salbtype.hxx>
+#include <vcl/impbmp.hxx>
+#include <vcl/bitmap.hxx>
+#ifndef _SV_BITMAP_HXX
+#include <vcl/bitmapex.hxx>
+#endif
+#include <vcl/graph.hxx>
+#include <soicon.hxx>
+#include <vcl/svdata.hxx>
+#include <salbmp.h>
+#include <vcl/svids.hrc>
+
+BOOL SelectAppIconPixmap( SalDisplay *pDisplay, int nScreen,USHORT nIcon, USHORT iconSize,
+ Pixmap& icon_pixmap, Pixmap& icon_mask)
+{
+ if( ! ImplGetResMgr() )
+ return FALSE;
+
+ USHORT nIconSizeOffset;
+
+ if( iconSize >= 48 )
+ nIconSizeOffset = SV_ICON_SIZE48_START;
+ else if( iconSize >= 32 )
+ nIconSizeOffset = SV_ICON_SIZE32_START;
+ else if( iconSize >= 16 )
+ nIconSizeOffset = SV_ICON_SIZE16_START;
+ else
+ return FALSE;
+
+ BitmapEx aIcon( ResId(nIconSizeOffset + nIcon, *ImplGetResMgr()));
+ if( TRUE == aIcon.IsEmpty() )
+ return FALSE;
+
+ SalTwoRect aRect;
+ aRect.mnSrcX = 0; aRect.mnSrcY = 0;
+ aRect.mnSrcWidth = iconSize; aRect.mnSrcHeight = iconSize;
+ aRect.mnDestX = 0; aRect.mnDestY = 0;
+ aRect.mnDestWidth = iconSize; aRect.mnDestHeight = iconSize;
+
+ X11SalBitmap *pBitmap = static_cast < X11SalBitmap * >
+ (aIcon.ImplGetBitmapImpBitmap()->ImplGetSalBitmap());
+
+ icon_pixmap = XCreatePixmap( pDisplay->GetDisplay(),
+ pDisplay->GetRootWindow( nScreen ),
+ iconSize, iconSize,
+ DefaultDepth( pDisplay->GetDisplay(), nScreen )
+ );
+
+ pBitmap->ImplDraw( icon_pixmap,
+ nScreen,
+ DefaultDepth( pDisplay->GetDisplay(), nScreen ),
+ aRect,
+ DefaultGC(pDisplay->GetDisplay(), nScreen ) );
+
+ icon_mask = None;
+
+ if( TRANSPARENT_BITMAP == aIcon.GetTransparentType() )
+ {
+ icon_mask = XCreatePixmap( pDisplay->GetDisplay(),
+ pDisplay->GetRootWindow( pDisplay->GetDefaultScreenNumber() ),
+ iconSize, iconSize, 1);
+
+ XGCValues aValues;
+ aValues.foreground = 0xffffffff;
+ aValues.background = 0;
+ aValues.function = GXcopy;
+ GC aMonoGC = XCreateGC( pDisplay->GetDisplay(), icon_mask,
+ GCFunction|GCForeground|GCBackground, &aValues );
+
+ Bitmap aMask = aIcon.GetMask();
+ aMask.Invert();
+
+ X11SalBitmap *pMask = static_cast < X11SalBitmap * >
+ (aMask.ImplGetImpBitmap()->ImplGetSalBitmap());
+
+ pMask->ImplDraw(icon_mask, nScreen, 1, aRect, aMonoGC);
+ XFreeGC( pDisplay->GetDisplay(), aMonoGC );
+ }
+
+ return TRUE;
+}
+
diff --git a/vcl/unx/source/app/wmadaptor.cxx b/vcl/unx/source/app/wmadaptor.cxx
new file mode 100644
index 000000000000..1a116fcbe8d6
--- /dev/null
+++ b/vcl/unx/source/app/wmadaptor.cxx
@@ -0,0 +1,2504 @@
+/*************************************************************************
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <sal/alloca.h>
+#include <wmadaptor.hxx>
+#include <saldisp.hxx>
+#include <saldata.hxx>
+#include <salframe.h>
+#include <vcl/salgdi.hxx>
+#include <osl/thread.h>
+#include <rtl/locale.h>
+#include <osl/process.h>
+
+#include <tools/prex.h>
+#include <X11/X.h>
+#include <X11/Xatom.h>
+#include <X11/Xresource.h>
+#include <tools/postx.h>
+
+#if OSL_DEBUG_LEVEL > 1
+#include <stdio.h>
+#endif
+
+namespace vcl_sal {
+
+class NetWMAdaptor : public WMAdaptor
+{
+ void setNetWMState( X11SalFrame* pFrame ) const;
+ void initAtoms();
+ virtual bool isValid() const;
+public:
+ NetWMAdaptor( SalDisplay* );
+ virtual ~NetWMAdaptor();
+
+ virtual void setWMName( X11SalFrame* pFrame, const String& rWMName ) const;
+ virtual void maximizeFrame( X11SalFrame* pFrame, bool bHorizontal = true, bool bVertical = true ) const;
+ virtual void shade( X11SalFrame* pFrame, bool bToShaded ) const;
+ virtual void setFrameTypeAndDecoration( X11SalFrame* pFrame, WMWindowType eType, int nDecorationFlags, X11SalFrame* pTransientFrame = NULL ) const;
+ virtual bool supportsICCCMPos() const;
+ virtual void enableAlwaysOnTop( X11SalFrame* pFrame, bool bEnable ) const;
+ virtual int handlePropertyNotify( X11SalFrame* pFrame, XPropertyEvent* pEvent ) const;
+ virtual void showFullScreen( X11SalFrame* pFrame, bool bFullScreen ) const;
+ virtual void frameIsMapping( X11SalFrame* pFrame ) const;
+ virtual void setFrameStruts( X11SalFrame* pFrame,
+ int left, int right, int top, int bottom,
+ int left_start_y, int left_end_y,
+ int right_start_y, int right_end_y,
+ int top_start_x, int top_end_x,
+ int bottom_start_x, int bottom_end_x ) const;
+ virtual void setUserTime( X11SalFrame* i_pFrame, long i_nUserTime ) const;
+};
+
+class GnomeWMAdaptor : public WMAdaptor
+{
+ bool m_bValid;
+
+ void setGnomeWMState( X11SalFrame* pFrame ) const;
+ void initAtoms();
+ virtual bool isValid() const;
+public:
+ GnomeWMAdaptor( SalDisplay * );
+ virtual ~GnomeWMAdaptor();
+
+ virtual void maximizeFrame( X11SalFrame* pFrame, bool bHorizontal = true, bool bVertical = true ) const;
+ virtual void shade( X11SalFrame* pFrame, bool bToShaded ) const;
+ virtual void enableAlwaysOnTop( X11SalFrame* pFrame, bool bEnable ) const;
+ virtual int handlePropertyNotify( X11SalFrame* pFrame, XPropertyEvent* pEvent ) const;
+};
+
+}
+
+using namespace vcl_sal;
+
+struct WMAdaptorProtocol
+{
+ const char* pProtocol;
+ int nProtocol;
+};
+
+
+/*
+ * table must be sorted ascending in strings
+ * since it is use with bsearch
+ */
+static const WMAdaptorProtocol aProtocolTab[] =
+{
+ { "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE", WMAdaptor::KDE_NET_WM_WINDOW_TYPE_OVERRIDE },
+ { "_NET_CURRENT_DESKTOP", WMAdaptor::NET_CURRENT_DESKTOP },
+ { "_NET_NUMBER_OF_DESKTOPS", WMAdaptor::NET_NUMBER_OF_DESKTOPS },
+ { "_NET_WM_DESKTOP", WMAdaptor::NET_WM_DESKTOP },
+ { "_NET_WM_ICON_NAME", WMAdaptor::NET_WM_ICON_NAME },
+ { "_NET_WM_PING", WMAdaptor::NET_WM_PING },
+ { "_NET_WM_STATE", WMAdaptor::NET_WM_STATE },
+ { "_NET_WM_STATE_ABOVE", WMAdaptor::NET_WM_STATE_STAYS_ON_TOP },
+ { "_NET_WM_STATE_FULLSCREEN", WMAdaptor::NET_WM_STATE_FULLSCREEN },
+ { "_NET_WM_STATE_MAXIMIZED_HORIZ", WMAdaptor::NET_WM_STATE_MAXIMIZED_HORZ }, // common bug in e.g. older kwin and sawfish implementations
+ { "_NET_WM_STATE_MAXIMIZED_HORZ", WMAdaptor::NET_WM_STATE_MAXIMIZED_HORZ },
+ { "_NET_WM_STATE_MAXIMIZED_VERT", WMAdaptor::NET_WM_STATE_MAXIMIZED_VERT },
+ { "_NET_WM_STATE_MODAL", WMAdaptor::NET_WM_STATE_MODAL },
+ { "_NET_WM_STATE_SHADED", WMAdaptor::NET_WM_STATE_SHADED },
+ { "_NET_WM_STATE_SKIP_PAGER", WMAdaptor::NET_WM_STATE_SKIP_PAGER },
+ { "_NET_WM_STATE_SKIP_TASKBAR", WMAdaptor::NET_WM_STATE_SKIP_TASKBAR },
+ { "_NET_WM_STATE_STAYS_ON_TOP", WMAdaptor::NET_WM_STATE_STAYS_ON_TOP },
+ { "_NET_WM_STATE_STICKY", WMAdaptor::NET_WM_STATE_STICKY },
+ { "_NET_WM_STRUT", WMAdaptor::NET_WM_STRUT },
+ { "_NET_WM_STRUT_PARTIAL", WMAdaptor::NET_WM_STRUT_PARTIAL },
+ { "_NET_WM_WINDOW_TYPE", WMAdaptor::NET_WM_WINDOW_TYPE },
+ { "_NET_WM_WINDOW_TYPE_DESKTOP", WMAdaptor::NET_WM_WINDOW_TYPE_DESKTOP },
+ { "_NET_WM_WINDOW_TYPE_DIALOG", WMAdaptor::NET_WM_WINDOW_TYPE_DIALOG },
+ { "_NET_WM_WINDOW_TYPE_DOCK", WMAdaptor::NET_WM_WINDOW_TYPE_DOCK },
+ { "_NET_WM_WINDOW_TYPE_MENU", WMAdaptor::NET_WM_WINDOW_TYPE_MENU },
+ { "_NET_WM_WINDOW_TYPE_NORMAL", WMAdaptor::NET_WM_WINDOW_TYPE_NORMAL },
+ { "_NET_WM_WINDOW_TYPE_SPLASH", WMAdaptor::NET_WM_WINDOW_TYPE_SPLASH },
+ { "_NET_WM_WINDOW_TYPE_SPLASHSCREEN", WMAdaptor::NET_WM_WINDOW_TYPE_SPLASH }, // bug in Metacity 2.4.1
+ { "_NET_WM_WINDOW_TYPE_TOOLBAR", WMAdaptor::NET_WM_WINDOW_TYPE_TOOLBAR },
+ { "_NET_WM_WINDOW_TYPE_UTILITY", WMAdaptor::NET_WM_WINDOW_TYPE_UTILITY },
+ { "_NET_WORKAREA", WMAdaptor::NET_WORKAREA },
+ { "_WIN_APP_STATE", WMAdaptor::WIN_APP_STATE },
+ { "_WIN_CLIENT_LIST", WMAdaptor::WIN_CLIENT_LIST },
+ { "_WIN_EXPANDED_SIZE", WMAdaptor::WIN_EXPANDED_SIZE },
+ { "_WIN_HINTS", WMAdaptor::WIN_HINTS },
+ { "_WIN_ICONS", WMAdaptor::WIN_ICONS },
+ { "_WIN_LAYER", WMAdaptor::WIN_LAYER },
+ { "_WIN_STATE", WMAdaptor::WIN_STATE },
+ { "_WIN_WORKSPACE", WMAdaptor::WIN_WORKSPACE },
+ { "_WIN_WORKSPACE_COUNT", WMAdaptor::WIN_WORKSPACE_COUNT }
+};
+
+/*
+ * table containing atoms to get anyway
+ */
+
+static const WMAdaptorProtocol aAtomTab[] =
+{
+ { "WM_STATE", WMAdaptor::WM_STATE },
+ { "_MOTIF_WM_HINTS", WMAdaptor::MOTIF_WM_HINTS },
+ { "WM_PROTOCOLS", WMAdaptor::WM_PROTOCOLS },
+ { "WM_DELETE_WINDOW", WMAdaptor::WM_DELETE_WINDOW },
+ { "WM_TAKE_FOCUS", WMAdaptor::WM_TAKE_FOCUS },
+ { "WM_SAVE_YOURSELF", WMAdaptor::WM_SAVE_YOURSELF },
+ { "WM_COMMAND", WMAdaptor::WM_COMMAND },
+ { "WM_CLIENT_LEADER", WMAdaptor::WM_CLIENT_LEADER },
+ { "WM_LOCALE_NAME", WMAdaptor::WM_LOCALE_NAME },
+ { "WM_TRANSIENT_FOR", WMAdaptor::WM_TRANSIENT_FOR },
+ { "SAL_QUITEVENT", WMAdaptor::SAL_QUITEVENT },
+ { "SAL_USEREVENT", WMAdaptor::SAL_USEREVENT },
+ { "SAL_EXTTEXTEVENT", WMAdaptor::SAL_EXTTEXTEVENT },
+ { "SAL_GETTIMEEVENT", WMAdaptor::SAL_GETTIMEEVENT },
+ { "VCL_SYSTEM_SETTINGS", WMAdaptor::VCL_SYSTEM_SETTINGS },
+ { "DTWM_IS_RUNNING", WMAdaptor::DTWM_IS_RUNNING },
+ { "_XSETTINGS_SETTINGS", WMAdaptor::XSETTINGS },
+ { "_XEMBED", WMAdaptor::XEMBED },
+ { "_XEMBED_INFO", WMAdaptor::XEMBED_INFO },
+ { "_NET_WM_USER_TIME", WMAdaptor::NET_WM_USER_TIME },
+ { "_NET_WM_PID", WMAdaptor::NET_WM_PID }
+};
+
+extern "C" {
+static int compareProtocol( const void* pLeft, const void* pRight )
+{
+ return strcmp( ((const WMAdaptorProtocol*)pLeft)->pProtocol, ((const WMAdaptorProtocol*)pRight)->pProtocol );
+}
+}
+
+WMAdaptor* WMAdaptor::createWMAdaptor( SalDisplay* pSalDisplay )
+{
+ WMAdaptor* pAdaptor = NULL;
+
+ // try a NetWM
+ pAdaptor = new NetWMAdaptor( pSalDisplay );
+ if( ! pAdaptor->isValid() )
+ delete pAdaptor, pAdaptor = NULL;
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "WM supports extended WM hints\n" );
+#endif
+
+ // try a GnomeWM
+ if( ! pAdaptor )
+ {
+ pAdaptor = new GnomeWMAdaptor( pSalDisplay );
+ if( ! pAdaptor->isValid() )
+ delete pAdaptor, pAdaptor = NULL;
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "WM supports GNOME WM hints\n" );
+#endif
+ }
+
+ if( ! pAdaptor )
+ pAdaptor = new WMAdaptor( pSalDisplay );
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "Window Manager's name is \"%s\"\n",
+ ByteString( pAdaptor->getWindowManagerName(), RTL_TEXTENCODING_ISO_8859_1 ).GetBuffer() );
+#endif
+ return pAdaptor;
+}
+
+
+/*
+ * WMAdaptor constructor
+ */
+
+WMAdaptor::WMAdaptor( SalDisplay* pDisplay ) :
+ m_pSalDisplay( pDisplay ),
+ m_bTransientBehaviour( true ),
+ m_bEnableAlwaysOnTopWorks( false ),
+ m_bLegacyPartialFullscreen( false ),
+ m_nWinGravity( StaticGravity ),
+ m_nInitWinGravity( StaticGravity )
+{
+ Atom aRealType = None;
+ int nFormat = 8;
+ unsigned long nItems = 0;
+ unsigned long nBytesLeft = 0;
+ unsigned char* pProperty = NULL;
+
+ // default desktops
+ m_nDesktops = 1;
+ m_aWMWorkAreas = ::std::vector< Rectangle >
+ ( 1, Rectangle( Point(), m_pSalDisplay->GetScreenSize( m_pSalDisplay->GetDefaultScreenNumber() ) ) );
+ m_bEqualWorkAreas = true;
+
+ memset( m_aWMAtoms, 0, sizeof( m_aWMAtoms ) );
+ m_pDisplay = m_pSalDisplay->GetDisplay();
+
+ initAtoms();
+ getNetWmName(); // try to discover e.g. Sawfish
+
+ // check for dtwm running
+ if( m_aWMAtoms[ DTWM_IS_RUNNING ] )
+ {
+ if ( (XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ m_aWMAtoms[ DTWM_IS_RUNNING ],
+ 0, 1,
+ False,
+ XA_INTEGER,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty) == 0
+ && nItems)
+ || (XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ m_aWMAtoms[ DTWM_IS_RUNNING ],
+ 0, 1,
+ False,
+ m_aWMAtoms[ DTWM_IS_RUNNING ],
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty) == 0
+ && nItems))
+ {
+ if (*pProperty)
+ {
+ m_aWMName = String(RTL_CONSTASCII_USTRINGPARAM("Dtwm"));
+ m_bTransientBehaviour = false;
+ m_nWinGravity = CenterGravity;
+ }
+ XFree (pProperty);
+ }
+ else if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ }
+ if( m_aWMName.Len() == 0 )
+ {
+ // check for window maker - needs different gravity
+ Atom aWMakerRunning = XInternAtom( m_pDisplay, "_WINDOWMAKER_WM_PROTOCOLS", True );
+ if( aWMakerRunning != None &&
+ XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ aWMakerRunning,
+ 0, 32,
+ False,
+ XA_ATOM,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0 )
+ {
+ if( aRealType == XA_ATOM )
+ m_aWMName = String( RTL_CONSTASCII_USTRINGPARAM("Windowmaker" ) );
+ XFree( pProperty );
+ m_nInitWinGravity = NorthWestGravity;
+ }
+ else if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ }
+ if( m_aWMName.Len() == 0 )
+ {
+ if( XInternAtom( m_pDisplay, "_OL_WIN_ATTR", True ) )
+ {
+ m_aWMName = String( RTL_CONSTASCII_USTRINGPARAM( "Olwm" ) );
+ m_nInitWinGravity = NorthWestGravity;
+ }
+ }
+ if( m_aWMName.Len() == 0 )
+ {
+ // check for ReflectionX wm (as it needs a workaround in Windows mode
+ Atom aRwmRunning = XInternAtom( m_pDisplay, "RWM_RUNNING", True );
+ if( aRwmRunning != None &&
+ XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ aRwmRunning,
+ 0, 32,
+ False,
+ aRwmRunning,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0 )
+ {
+ if( aRealType == aRwmRunning )
+ m_aWMName = String( RTL_CONSTASCII_USTRINGPARAM("ReflectionX" ) );
+ XFree( pProperty );
+ }
+ else if( (aRwmRunning = XInternAtom( m_pDisplay, "_WRQ_WM_RUNNING", True )) != None &&
+ XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ aRwmRunning,
+ 0, 32,
+ False,
+ XA_STRING,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0 )
+ {
+ if( aRealType == XA_STRING )
+ m_aWMName = String( RTL_CONSTASCII_USTRINGPARAM( "ReflectionX Windows" ) );
+ XFree( pProperty );
+ }
+ }
+ if( m_aWMName.Len() == 0 )
+ {
+ Atom aTTAPlatform = XInternAtom( m_pDisplay, "TTA_CLIENT_PLATFORM", True );
+ if( aTTAPlatform != None &&
+ XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ aTTAPlatform,
+ 0, 32,
+ False,
+ XA_STRING,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0 )
+ {
+ if( aRealType == XA_STRING )
+ {
+ m_aWMName = String( RTL_CONSTASCII_USTRINGPARAM("Tarantella" ) );
+ // #i62319# pretend that AlwaysOnTop works since
+ // the alwaysontop workaround in salframe.cxx results
+ // in a raise/lower loop on a Windows tarantella client
+ // FIXME: this property contains an identification string that
+ // in theory should be good enough to recognize running on a
+ // Windows client; however this string does not seem to be
+ // documented as well as the property itself.
+ m_bEnableAlwaysOnTopWorks = true;
+ }
+ XFree( pProperty );
+ }
+ }
+}
+
+/*
+ * WMAdaptor destructor
+ */
+
+WMAdaptor::~WMAdaptor()
+{
+}
+
+/*
+ * NetWMAdaptor constructor
+ */
+
+NetWMAdaptor::NetWMAdaptor( SalDisplay* pSalDisplay ) :
+ WMAdaptor( pSalDisplay )
+{
+ // currently all _NET WMs do transient like expected
+ m_bTransientBehaviour = true;
+
+ Atom aRealType = None;
+ int nFormat = 8;
+ unsigned long nItems = 0;
+ unsigned long nBytesLeft = 0;
+ unsigned char* pProperty = NULL;
+ bool bNetWM = false;
+
+ initAtoms();
+
+ // check for NetWM
+ bNetWM = getNetWmName();
+ if( bNetWM
+ && XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ m_aWMAtoms[ NET_SUPPORTED ],
+ 0, 0,
+ False,
+ XA_ATOM,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0
+ && aRealType == XA_ATOM
+ && nFormat == 32
+ )
+ {
+ if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ // collect supported protocols
+ if( XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ m_aWMAtoms[ NET_SUPPORTED ],
+ 0, nBytesLeft/4,
+ False,
+ XA_ATOM,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0
+ && nItems
+ )
+ {
+ Atom* pAtoms = (Atom*)pProperty;
+ char** pAtomNames = (char**)alloca( sizeof(char*)*nItems );
+ if( XGetAtomNames( m_pDisplay, pAtoms, nItems, pAtomNames ) )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "supported protocols:\n" );
+#endif
+ for( unsigned int i = 0; i < nItems; i++ )
+ {
+ // #i80971# protect against invalid atoms
+ if( pAtomNames[i] == NULL )
+ continue;
+
+ int nProtocol = -1;
+ WMAdaptorProtocol aSearch;
+ aSearch.pProtocol = pAtomNames[i];
+ WMAdaptorProtocol* pMatch = (WMAdaptorProtocol*)
+ bsearch( &aSearch,
+ aProtocolTab,
+ sizeof( aProtocolTab )/sizeof( aProtocolTab[0] ),
+ sizeof( struct WMAdaptorProtocol ),
+ compareProtocol );
+ if( pMatch )
+ {
+ nProtocol = pMatch->nProtocol;
+ m_aWMAtoms[ nProtocol ] = pAtoms[ i ];
+ if( pMatch->nProtocol == NET_WM_STATE_STAYS_ON_TOP )
+ m_bEnableAlwaysOnTopWorks = true;
+ }
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, " %s%s\n", pAtomNames[i], nProtocol != -1 ? "" : " (unsupported)" );
+#endif
+
+ XFree( pAtomNames[i] );
+ }
+ }
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ else if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+
+ // get number of desktops
+ if( m_aWMAtoms[ NET_NUMBER_OF_DESKTOPS ]
+ && XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ m_aWMAtoms[ NET_NUMBER_OF_DESKTOPS ],
+ 0, 1,
+ False,
+ XA_CARDINAL,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0
+ && pProperty
+ )
+ {
+ m_nDesktops = *(long*)pProperty;
+ XFree( pProperty );
+ pProperty = NULL;
+ // get work areas
+ if( m_aWMAtoms[ NET_WORKAREA ]
+ && XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ m_aWMAtoms[ NET_WORKAREA ],
+ 0, 4*m_nDesktops,
+ False,
+ XA_CARDINAL,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty
+ ) == 0
+ && nItems == 4*(unsigned)m_nDesktops
+ )
+ {
+ m_aWMWorkAreas = ::std::vector< Rectangle > ( m_nDesktops );
+ long* pValues = (long*)pProperty;
+ for( int i = 0; i < m_nDesktops; i++ )
+ {
+ Point aPoint( pValues[4*i],
+ pValues[4*i+1] );
+ Size aSize( pValues[4*i+2],
+ pValues[4*i+3] );
+ Rectangle aWorkArea( aPoint, aSize );
+ m_aWMWorkAreas[i] = aWorkArea;
+ if( aWorkArea != m_aWMWorkAreas[0] )
+ m_bEqualWorkAreas = false;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "workarea %d: %ldx%ld+%ld+%ld\n",
+ i,
+ m_aWMWorkAreas[i].GetWidth(),
+ m_aWMWorkAreas[i].GetHeight(),
+ m_aWMWorkAreas[i].Left(),
+ m_aWMWorkAreas[i].Top() );
+#endif
+ }
+ XFree( pProperty );
+ }
+ else
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%ld workareas for %d desktops !\n", nItems/4, m_nDesktops );
+#endif
+ if( pProperty )
+ {
+ XFree(pProperty);
+ pProperty = NULL;
+ }
+ }
+ }
+ else if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ }
+ else if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+}
+
+/*
+ * NetWMAdaptor destructor
+ */
+NetWMAdaptor::~NetWMAdaptor()
+{
+}
+
+/*
+ * GnomeWMAdaptor constructor
+ */
+
+GnomeWMAdaptor::GnomeWMAdaptor( SalDisplay* pSalDisplay ) :
+ WMAdaptor( pSalDisplay ),
+ m_bValid( false )
+{
+ // currently all Gnome WMs do transient like expected
+ m_bTransientBehaviour = true;
+
+ Atom aRealType = None;
+ int nFormat = 8;
+ unsigned long nItems = 0;
+ unsigned long nBytesLeft = 0;
+ unsigned char* pProperty = NULL;
+
+ initAtoms();
+
+ // check for GnomeWM
+ if( m_aWMAtoms[ WIN_SUPPORTING_WM_CHECK ] && m_aWMAtoms[ WIN_PROTOCOLS ] )
+ {
+ XLIB_Window aWMChild = None;
+ if( XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ m_aWMAtoms[ WIN_SUPPORTING_WM_CHECK ],
+ 0, 1,
+ False,
+ XA_CARDINAL,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0
+ && aRealType == XA_CARDINAL
+ && nFormat == 32
+ && nItems != 0
+ )
+ {
+ aWMChild = *(XLIB_Window*)pProperty;
+ XFree( pProperty );
+ pProperty = NULL;
+ XLIB_Window aCheckWindow = None;
+ m_pSalDisplay->GetXLib()->PushXErrorLevel( true );
+ if( XGetWindowProperty( m_pDisplay,
+ aWMChild,
+ m_aWMAtoms[ WIN_SUPPORTING_WM_CHECK ],
+ 0, 1,
+ False,
+ XA_CARDINAL,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0
+ && aRealType == XA_CARDINAL
+ && nFormat == 32
+ && nItems != 0
+ && ! m_pSalDisplay->GetXLib()->HasXErrorOccured()
+ )
+ {
+ aCheckWindow = *(XLIB_Window*)pProperty;
+ XFree( pProperty );
+ pProperty = NULL;
+ if( aCheckWindow == aWMChild )
+ {
+ m_bValid = true;
+ /*
+ * get name of WM
+ * this is NOT part of the GNOME WM hints, but e.g. Sawfish
+ * already supports this part of the extended WM hints
+ */
+ m_aWMAtoms[ UTF8_STRING ] = XInternAtom( m_pDisplay, "UTF8_STRING", False );
+ getNetWmName();
+ }
+ }
+ m_pSalDisplay->GetXLib()->PopXErrorLevel();
+ }
+ else if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ }
+ if( m_bValid
+ && XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ m_aWMAtoms[ WIN_PROTOCOLS ],
+ 0, 0,
+ False,
+ XA_ATOM,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0
+ && aRealType == XA_ATOM
+ && nFormat == 32
+ )
+ {
+ if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ // collect supported protocols
+ if( XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ m_aWMAtoms[ WIN_PROTOCOLS ],
+ 0, nBytesLeft/4,
+ False,
+ XA_ATOM,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0
+ && pProperty
+ )
+ {
+ Atom* pAtoms = (Atom*)pProperty;
+ char** pAtomNames = (char**)alloca( sizeof(char*)*nItems );
+ if( XGetAtomNames( m_pDisplay, pAtoms, nItems, pAtomNames ) )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "supported protocols:\n" );
+#endif
+ for( unsigned int i = 0; i < nItems; i++ )
+ {
+ // #i80971# protect against invalid atoms
+ if( pAtomNames[i] == NULL )
+ continue;
+
+ int nProtocol = -1;
+ WMAdaptorProtocol aSearch;
+ aSearch.pProtocol = pAtomNames[i];
+ WMAdaptorProtocol* pMatch = (WMAdaptorProtocol*)
+ bsearch( &aSearch,
+ aProtocolTab,
+ sizeof( aProtocolTab )/sizeof( aProtocolTab[0] ),
+ sizeof( struct WMAdaptorProtocol ),
+ compareProtocol );
+ if( pMatch )
+ {
+ nProtocol = pMatch->nProtocol;
+ m_aWMAtoms[ nProtocol ] = pAtoms[ i ];
+ if( pMatch->nProtocol == WIN_LAYER )
+ m_bEnableAlwaysOnTopWorks = true;
+ }
+ if( strncmp( "_ICEWM_TRAY", pAtomNames[i], 11 ) == 0 )
+ {
+ m_aWMName = String(RTL_CONSTASCII_USTRINGPARAM("IceWM" ));
+ m_nWinGravity = NorthWestGravity;
+ m_nInitWinGravity = NorthWestGravity;
+ }
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, " %s%s\n", pAtomNames[i], nProtocol != -1 ? "" : " (unsupported)" );
+#endif
+
+ XFree( pAtomNames[i] );
+ }
+ }
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ else if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+
+ // get number of desktops
+ if( m_aWMAtoms[ WIN_WORKSPACE_COUNT ]
+ && XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ m_aWMAtoms[ WIN_WORKSPACE_COUNT ],
+ 0, 1,
+ False,
+ XA_CARDINAL,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0
+ && pProperty
+ )
+ {
+ m_nDesktops = *(long*)pProperty;
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ else if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ }
+ else if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+}
+
+/*
+ * GnomeWMAdaptor destructor
+ */
+GnomeWMAdaptor::~GnomeWMAdaptor()
+{
+}
+
+/*
+ * getNetWmName()
+ */
+bool WMAdaptor::getNetWmName()
+{
+ Atom aRealType = None;
+ int nFormat = 8;
+ unsigned long nItems = 0;
+ unsigned long nBytesLeft = 0;
+ unsigned char* pProperty = NULL;
+ bool bNetWM = false;
+
+ if( m_aWMAtoms[ NET_SUPPORTING_WM_CHECK ] && m_aWMAtoms[ NET_WM_NAME ] )
+ {
+ XLIB_Window aWMChild = None;
+ if( XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ m_aWMAtoms[ NET_SUPPORTING_WM_CHECK ],
+ 0, 1,
+ False,
+ XA_WINDOW,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0
+ && aRealType == XA_WINDOW
+ && nFormat == 32
+ && nItems != 0
+ )
+ {
+ aWMChild = *(XLIB_Window*)pProperty;
+ XFree( pProperty );
+ pProperty = NULL;
+ XLIB_Window aCheckWindow = None;
+ m_pSalDisplay->GetXLib()->PushXErrorLevel( true );
+ if( XGetWindowProperty( m_pDisplay,
+ aWMChild,
+ m_aWMAtoms[ NET_SUPPORTING_WM_CHECK ],
+ 0, 1,
+ False,
+ XA_WINDOW,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0
+ && aRealType == XA_WINDOW
+ && nFormat == 32
+ && nItems != 0
+ && ! m_pSalDisplay->GetXLib()->HasXErrorOccured()
+ )
+ {
+ aCheckWindow = *(XLIB_Window*)pProperty;
+ XFree( pProperty );
+ pProperty = NULL;
+ if( aCheckWindow == aWMChild )
+ {
+ bNetWM = true;
+ // get name of WM
+ m_aWMAtoms[ UTF8_STRING ] = XInternAtom( m_pDisplay, "UTF8_STRING", False );
+ if( XGetWindowProperty( m_pDisplay,
+ aWMChild,
+ m_aWMAtoms[ NET_WM_NAME ],
+ 0, 256,
+ False,
+ AnyPropertyType, /* m_aWMAtoms[ UTF8_STRING ],*/
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0
+ && nItems != 0
+ )
+ {
+ if (aRealType == m_aWMAtoms[ UTF8_STRING ])
+ {
+ m_aWMName = String( (sal_Char*)pProperty, nItems, RTL_TEXTENCODING_UTF8 );
+ }
+ else
+ if (aRealType == XA_STRING)
+ {
+ m_aWMName = String( (sal_Char*)pProperty, nItems, RTL_TEXTENCODING_ISO_8859_1 );
+ }
+
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ else if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ // if this is metacity, check for version to enable a legacy workaround
+ if( m_aWMName.EqualsAscii( "Metacity" ) )
+ {
+ int nVersionMajor = 0, nVersionMinor = 0;
+ Atom nVersionAtom = XInternAtom( m_pDisplay, "_METACITY_VERSION", True );
+ if( nVersionAtom )
+ {
+ if( XGetWindowProperty( m_pDisplay,
+ aWMChild,
+ nVersionAtom,
+ 0, 256,
+ False,
+ m_aWMAtoms[ UTF8_STRING ],
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0
+ && nItems != 0
+ )
+ {
+ String aMetaVersion( (sal_Char*)pProperty, nItems, RTL_TEXTENCODING_UTF8 );
+ nVersionMajor = aMetaVersion.GetToken( 0, '.' ).ToInt32();
+ nVersionMinor = aMetaVersion.GetToken( 1, '.' ).ToInt32();
+ }
+ if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ }
+ if( nVersionMajor < 2 || (nVersionMajor == 2 && nVersionMinor < 12) )
+ m_bLegacyPartialFullscreen = true;
+ }
+ }
+ }
+ else if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ m_pSalDisplay->GetXLib()->PopXErrorLevel();
+ }
+ else if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ }
+ return bNetWM;
+}
+
+/*
+ * WMAdaptor::isValid()
+ */
+bool WMAdaptor::isValid() const
+{
+ return true;
+}
+
+/*
+ * NetWMAdaptor::isValid()
+ */
+bool NetWMAdaptor::isValid() const
+{
+ // some necessary sanity checks; there are WMs out there
+ // which implement some of the WM hints spec without
+ // real functionality
+ return
+ m_aWMAtoms[ NET_SUPPORTED ]
+ && m_aWMAtoms[ NET_SUPPORTING_WM_CHECK ]
+ && m_aWMAtoms[ NET_WM_NAME ]
+ && m_aWMAtoms[ NET_WM_WINDOW_TYPE_NORMAL ]
+ && m_aWMAtoms[ NET_WM_WINDOW_TYPE_DIALOG ]
+ ;
+}
+
+/*
+ * GnomeWMAdaptor::isValid()
+ */
+bool GnomeWMAdaptor::isValid() const
+{
+ return m_bValid;
+}
+
+/*
+ * WMAdaptor::initAtoms
+ */
+
+void WMAdaptor::initAtoms()
+{
+ // get basic atoms
+ for( unsigned int i = 0; i < sizeof( aAtomTab )/sizeof( aAtomTab[0] ); i++ )
+ m_aWMAtoms[ aAtomTab[i].nProtocol ] = XInternAtom( m_pDisplay, aAtomTab[i].pProtocol, False );
+ m_aWMAtoms[ NET_SUPPORTING_WM_CHECK ] = XInternAtom( m_pDisplay, "_NET_SUPPORTING_WM_CHECK", True );
+ m_aWMAtoms[ NET_WM_NAME ] = XInternAtom( m_pDisplay, "_NET_WM_NAME", True );
+}
+
+/*
+ * NetWMAdaptor::initAtoms
+ */
+
+void NetWMAdaptor::initAtoms()
+{
+ WMAdaptor::initAtoms();
+
+ m_aWMAtoms[ NET_SUPPORTED ] = XInternAtom( m_pDisplay, "_NET_SUPPORTED", True );
+}
+
+/*
+ * GnomeWMAdaptor::initAtoms
+ */
+
+void GnomeWMAdaptor::initAtoms()
+{
+ WMAdaptor::initAtoms();
+
+ m_aWMAtoms[ WIN_PROTOCOLS ] = XInternAtom( m_pDisplay, "_WIN_PROTOCOLS", True );
+ m_aWMAtoms[ WIN_SUPPORTING_WM_CHECK ] = XInternAtom( m_pDisplay, "_WIN_SUPPORTING_WM_CHECK", True );
+}
+
+/*
+ * WMAdaptor::setWMName
+ * sets WM_NAME
+ * WM_ICON_NAME
+ */
+
+void WMAdaptor::setWMName( X11SalFrame* pFrame, const String& rWMName ) const
+{
+ ByteString aTitle( rWMName, osl_getThreadTextEncoding() );
+
+ if( ! rWMName.Len() && m_aWMName.EqualsAscii( "Dtwm" ) )
+ aTitle = " ";
+
+ ::rtl::OString aWMLocale;
+ rtl_Locale* pLocale = NULL;
+ osl_getProcessLocale( &pLocale );
+ if( pLocale )
+ {
+ ::rtl::OUString aLocaleString( pLocale->Language );
+ ::rtl::OUString aCountry( pLocale->Country );
+ ::rtl::OUString aVariant( pLocale->Variant );
+
+ if( aCountry.getLength() )
+ {
+ aLocaleString += ::rtl::OUString::createFromAscii( "_" );
+ aLocaleString += aCountry;
+ }
+ if( aVariant.getLength() )
+ aLocaleString += aVariant;
+ aWMLocale = ::rtl::OUStringToOString( aLocaleString, RTL_TEXTENCODING_ISO_8859_1 );
+ }
+ else
+ {
+ static const char* pLang = getenv( "LANG" );
+ aWMLocale = pLang ? pLang : "C";
+ }
+
+ static bool bTrustXmb = true;
+ #ifdef SOLARIS
+ /* #i64273# there are some weird cases when using IIIMP on Solaris
+ * where for unknown reasons XmbTextListToTextProperty results in
+ * garbage. Test one string once to ensure safety.
+ *
+ * FIXME: This must be a bug in xiiimp.so.2 somewhere. However
+ * it was not possible to recreate this in a small sample program.
+ * This reeks of memory corruption somehow.
+ */
+ static bool bOnce = true;
+ if( bOnce )
+ {
+ bOnce = false;
+ XTextProperty aTestProp = { NULL, None, 0, 0 };
+ const char *pText = "trustme";
+ XmbTextListToTextProperty( m_pDisplay,
+ &const_cast<char*>(pText),
+ 1,
+ XStdICCTextStyle,
+ &aTestProp );
+ bTrustXmb = (aTestProp.nitems == 7) &&
+ (aTestProp.value != NULL ) &&
+ (strncmp( (char*)aTestProp.value, pText, 7 ) == 0) &&
+ (aTestProp.encoding == XA_STRING);
+ if( aTestProp.value )
+ XFree( aTestProp.value );
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%s\n",
+ bTrustXmb ?
+ "XmbTextListToTextProperty seems to work" :
+ "XmbTextListToTextProperty does not seem to work" );
+ #endif
+ }
+ #endif
+
+ char* pT = const_cast<char*>(aTitle.GetBuffer());
+ XTextProperty aProp = { NULL, None, 0, 0 };
+ if( bTrustXmb )
+ {
+ XmbTextListToTextProperty( m_pDisplay,
+ &pT,
+ 1,
+ XStdICCTextStyle,
+ &aProp );
+ }
+
+ unsigned char* pData = aProp.nitems ? aProp.value : (unsigned char*)aTitle.GetBuffer();
+ Atom nType = aProp.nitems ? aProp.encoding : XA_STRING;
+ int nFormat = aProp.nitems ? aProp.format : 8;
+ int nBytes = aProp.nitems ? aProp.nitems : aTitle.Len();
+ const SystemEnvData* pEnv = pFrame->GetSystemData();
+ XChangeProperty( m_pDisplay,
+ (XLIB_Window)pEnv->aShellWindow,
+ XA_WM_NAME,
+ nType,
+ nFormat,
+ PropModeReplace,
+ pData,
+ nBytes );
+ XChangeProperty( m_pDisplay,
+ (XLIB_Window)pEnv->aShellWindow,
+ XA_WM_ICON_NAME,
+ nType,
+ nFormat,
+ PropModeReplace,
+ pData,
+ nBytes );
+ XChangeProperty( m_pDisplay,
+ (XLIB_Window)pEnv->aShellWindow,
+ m_aWMAtoms[ WM_LOCALE_NAME ],
+ XA_STRING,
+ 8,
+ PropModeReplace,
+ (unsigned char*)aWMLocale.getStr(),
+ aWMLocale.getLength() );
+ if (aProp.value != NULL)
+ XFree( aProp.value );
+}
+
+/*
+ * NetWMAdaptor::setWMName
+ * sets WM_NAME
+ * _NET_WM_NAME
+ * WM_ICON_NAME
+ * _NET_WM_ICON_NAME
+ */
+void NetWMAdaptor::setWMName( X11SalFrame* pFrame, const String& rWMName ) const
+{
+ WMAdaptor::setWMName( pFrame, rWMName );
+
+ ByteString aTitle( rWMName, RTL_TEXTENCODING_UTF8 );
+ const SystemEnvData* pEnv = pFrame->GetSystemData();
+ if( m_aWMAtoms[ NET_WM_NAME ] )
+ XChangeProperty( m_pDisplay,
+ (XLIB_Window)pEnv->aShellWindow,
+ m_aWMAtoms[ NET_WM_NAME ],
+ m_aWMAtoms[ UTF8_STRING ],
+ 8,
+ PropModeReplace,
+ (unsigned char*)aTitle.GetBuffer(),
+ aTitle.Len()+1 );
+ if( m_aWMAtoms[ NET_WM_ICON_NAME ] )
+ XChangeProperty( m_pDisplay,
+ (XLIB_Window)pEnv->aShellWindow,
+ m_aWMAtoms[ NET_WM_ICON_NAME ],
+ m_aWMAtoms[ UTF8_STRING ],
+ 8,
+ PropModeReplace,
+ (unsigned char*)aTitle.GetBuffer(),
+ aTitle.Len()+1 );
+ // The +1 copies the terminating null byte. Although
+ // the spec says, this should not be necessary
+ // at least the kwin implementation seems to depend
+ // on the null byte
+}
+
+/*
+ * NetWMAdaptor::setNetWMState
+ * sets _NET_WM_STATE
+ */
+void NetWMAdaptor::setNetWMState( X11SalFrame* pFrame ) const
+{
+ if( m_aWMAtoms[ NET_WM_STATE ] )
+ {
+ Atom aStateAtoms[ 10 ];
+ int nStateAtoms = 0;
+
+ // set NET_WM_STATE_MODAL
+ if( m_aWMAtoms[ NET_WM_STATE_MODAL ]
+ && pFrame->meWindowType == windowType_ModalDialogue )
+ {
+ aStateAtoms[ nStateAtoms++ ] = m_aWMAtoms[ NET_WM_STATE_MODAL ];
+ /*
+ * #90998# NET_WM_STATE_SKIP_TASKBAR set on a frame will
+ * cause kwin not to give it the focus on map request
+ * this seems to be a bug in kwin
+ * aStateAtoms[ nStateAtoms++ ] = m_aWMAtoms[ NET_WM_STATE_SKIP_TASKBAR ];
+ */
+ }
+ if( pFrame->mbMaximizedVert
+ && m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_VERT ] )
+ aStateAtoms[ nStateAtoms++ ] = m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_VERT ];
+ if( pFrame->mbMaximizedHorz
+ && m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_HORZ ] )
+ aStateAtoms[ nStateAtoms++ ] = m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_HORZ ];
+ if( pFrame->bAlwaysOnTop_ && m_aWMAtoms[ NET_WM_STATE_STAYS_ON_TOP ] )
+ aStateAtoms[ nStateAtoms++ ] = m_aWMAtoms[ NET_WM_STATE_STAYS_ON_TOP ];
+ if( pFrame->mbShaded && m_aWMAtoms[ NET_WM_STATE_SHADED ] )
+ aStateAtoms[ nStateAtoms++ ] = m_aWMAtoms[ NET_WM_STATE_SHADED ];
+ if( pFrame->mbFullScreen && m_aWMAtoms[ NET_WM_STATE_FULLSCREEN ] )
+ aStateAtoms[ nStateAtoms++ ] = m_aWMAtoms[ NET_WM_STATE_FULLSCREEN ];
+ if( pFrame->meWindowType == windowType_Utility && m_aWMAtoms[ NET_WM_STATE_SKIP_TASKBAR ] )
+ aStateAtoms[ nStateAtoms++ ] = m_aWMAtoms[ NET_WM_STATE_SKIP_TASKBAR ];
+
+ if( nStateAtoms )
+ {
+ XChangeProperty( m_pDisplay,
+ pFrame->GetShellWindow(),
+ m_aWMAtoms[ NET_WM_STATE ],
+ XA_ATOM,
+ 32,
+ PropModeReplace,
+ (unsigned char*)aStateAtoms,
+ nStateAtoms
+ );
+ }
+ else
+ XDeleteProperty( m_pDisplay,
+ pFrame->GetShellWindow(),
+ m_aWMAtoms[ NET_WM_STATE ] );
+ if( pFrame->mbMaximizedHorz
+ && pFrame->mbMaximizedVert
+ && ! ( pFrame->nStyle_ & SAL_FRAME_STYLE_SIZEABLE ) )
+ {
+ /*
+ * for maximizing use NorthWestGravity (including decoration)
+ */
+ XSizeHints hints;
+ long supplied;
+ bool bHint = false;
+ if( XGetWMNormalHints( m_pDisplay,
+ pFrame->GetShellWindow(),
+ &hints,
+ &supplied ) )
+ {
+ bHint = true;
+ hints.flags |= PWinGravity;
+ hints.win_gravity = NorthWestGravity;
+ XSetWMNormalHints( m_pDisplay,
+ pFrame->GetShellWindow(),
+ &hints );
+ XSync( m_pDisplay, False );
+ }
+
+ // SetPosSize necessary to set width/height, min/max w/h
+ sal_Int32 nCurrent = 0;
+ /*
+ * get current desktop here if work areas have different size
+ * (does this happen on any platform ?)
+ */
+ if( ! m_bEqualWorkAreas )
+ {
+ nCurrent = getCurrentWorkArea();
+ if( nCurrent < 0 )
+ nCurrent = 0;
+ }
+ Rectangle aPosSize = m_aWMWorkAreas[nCurrent];
+ const SalFrameGeometry& rGeom( pFrame->GetUnmirroredGeometry() );
+ aPosSize = Rectangle( Point( aPosSize.Left() + rGeom.nLeftDecoration,
+ aPosSize.Top() + rGeom.nTopDecoration ),
+ Size( aPosSize.GetWidth()
+ - rGeom.nLeftDecoration
+ - rGeom.nRightDecoration,
+ aPosSize.GetHeight()
+ - rGeom.nTopDecoration
+ - rGeom.nBottomDecoration )
+ );
+ pFrame->SetPosSize( aPosSize );
+
+ /*
+ * reset gravity hint to static gravity
+ * (this should not move window according to ICCCM)
+ */
+ if( bHint && pFrame->nShowState_ != SHOWSTATE_UNKNOWN )
+ {
+ hints.win_gravity = StaticGravity;
+ XSetWMNormalHints( m_pDisplay,
+ pFrame->GetShellWindow(),
+ &hints );
+ }
+ }
+ }
+}
+
+/*
+ * GnomeWMAdaptor::setNetWMState
+ * sets _WIN_STATE
+ */
+void GnomeWMAdaptor::setGnomeWMState( X11SalFrame* pFrame ) const
+{
+ if( m_aWMAtoms[ WIN_STATE ] )
+ {
+ sal_uInt32 nWinWMState = 0;
+
+ if( pFrame->mbMaximizedVert )
+ nWinWMState |= 1 << 2;
+ if( pFrame->mbMaximizedHorz )
+ nWinWMState |= 1 << 3;
+ if( pFrame->mbShaded )
+ nWinWMState |= 1 << 5;
+
+ XChangeProperty( m_pDisplay,
+ pFrame->GetShellWindow(),
+ m_aWMAtoms[ WIN_STATE ],
+ XA_CARDINAL,
+ 32,
+ PropModeReplace,
+ (unsigned char*)&nWinWMState,
+ 1
+ );
+ if( pFrame->mbMaximizedHorz
+ && pFrame->mbMaximizedVert
+ && ! ( pFrame->nStyle_ & SAL_FRAME_STYLE_SIZEABLE ) )
+ {
+ /*
+ * for maximizing use NorthWestGravity (including decoration)
+ */
+ XSizeHints hints;
+ long supplied;
+ bool bHint = false;
+ if( XGetWMNormalHints( m_pDisplay,
+ pFrame->GetShellWindow(),
+ &hints,
+ &supplied ) )
+ {
+ bHint = true;
+ hints.flags |= PWinGravity;
+ hints.win_gravity = NorthWestGravity;
+ XSetWMNormalHints( m_pDisplay,
+ pFrame->GetShellWindow(),
+ &hints );
+ XSync( m_pDisplay, False );
+ }
+
+ // SetPosSize necessary to set width/height, min/max w/h
+ sal_Int32 nCurrent = 0;
+ /*
+ * get current desktop here if work areas have different size
+ * (does this happen on any platform ?)
+ */
+ if( ! m_bEqualWorkAreas )
+ {
+ nCurrent = getCurrentWorkArea();
+ if( nCurrent < 0 )
+ nCurrent = 0;
+ }
+ Rectangle aPosSize = m_aWMWorkAreas[nCurrent];
+ const SalFrameGeometry& rGeom( pFrame->GetUnmirroredGeometry() );
+ aPosSize = Rectangle( Point( aPosSize.Left() + rGeom.nLeftDecoration,
+ aPosSize.Top() + rGeom.nTopDecoration ),
+ Size( aPosSize.GetWidth()
+ - rGeom.nLeftDecoration
+ - rGeom.nRightDecoration,
+ aPosSize.GetHeight()
+ - rGeom.nTopDecoration
+ - rGeom.nBottomDecoration )
+ );
+ pFrame->SetPosSize( aPosSize );
+
+ /*
+ * reset gravity hint to static gravity
+ * (this should not move window according to ICCCM)
+ */
+ if( bHint && pFrame->nShowState_ != SHOWSTATE_UNKNOWN )
+ {
+ hints.win_gravity = StaticGravity;
+ XSetWMNormalHints( m_pDisplay,
+ pFrame->GetShellWindow(),
+ &hints );
+ }
+ }
+ }
+}
+
+/*
+ * WMAdaptor::setFrameDecoration
+ * sets _MOTIF_WM_HINTS
+ * WM_TRANSIENT_FOR
+ */
+
+void WMAdaptor::setFrameTypeAndDecoration( X11SalFrame* pFrame, WMWindowType eType, int nDecorationFlags, X11SalFrame* pReferenceFrame ) const
+{
+ pFrame->meWindowType = eType;
+ pFrame->mnDecorationFlags = nDecorationFlags;
+
+ if( ! pFrame->mbFullScreen )
+ {
+ // set mwm hints
+ struct _mwmhints {
+ unsigned long flags, func, deco;
+ long input_mode;
+ unsigned long status;
+ } aHint;
+
+ aHint.flags = 15; /* flags for functions, decoration, input mode and status */
+ aHint.deco = 0;
+ aHint.func = 1L << 2;
+ aHint.status = 0;
+ aHint.input_mode = 0;
+
+ // evaluate decoration flags
+ if( nDecorationFlags & decoration_All )
+ aHint.deco = 1, aHint.func = 1;
+ else
+ {
+ if( nDecorationFlags & decoration_Title )
+ aHint.deco |= 1L << 3;
+ if( nDecorationFlags & decoration_Border )
+ aHint.deco |= 1L << 1;
+ if( nDecorationFlags & decoration_Resize )
+ aHint.deco |= 1L << 2, aHint.func |= 1L << 1;
+ if( nDecorationFlags & decoration_MinimizeBtn )
+ aHint.deco |= 1L << 5, aHint.func |= 1L << 3;
+ if( nDecorationFlags & decoration_MaximizeBtn )
+ aHint.deco |= 1L << 6, aHint.func |= 1L << 4;
+ if( nDecorationFlags & decoration_CloseBtn )
+ aHint.deco |= 1L << 4, aHint.func |= 1L << 5;
+ }
+ // evaluate window type
+ switch( eType )
+ {
+ case windowType_ModalDialogue:
+ aHint.input_mode = 1;
+ break;
+ default:
+ break;
+ }
+
+ // set the hint
+ XChangeProperty( m_pDisplay,
+ pFrame->GetShellWindow(),
+ m_aWMAtoms[ MOTIF_WM_HINTS ],
+ m_aWMAtoms[ MOTIF_WM_HINTS ],
+ 32,
+ PropModeReplace,
+ (unsigned char*)&aHint,
+ 5 );
+ }
+
+ // set transientFor hint
+ /* #91030# dtwm will not map a dialogue if the transient
+ * window is iconified. This is deemed undesireable because
+ * message boxes do not get mapped, so use the root as transient
+ * instead.
+ */
+ if( pReferenceFrame )
+ {
+ XSetTransientForHint( m_pDisplay,
+ pFrame->GetShellWindow(),
+ pReferenceFrame->bMapped_ ?
+ pReferenceFrame->GetShellWindow() :
+ m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() )
+ );
+ if( ! pReferenceFrame->bMapped_ )
+ pFrame->mbTransientForRoot = true;
+ }
+ // #110333# in case no one ever sets a title prevent
+ // the Dtwm taking the class instead
+ if( m_aWMName.EqualsAscii( "Dtwm" ) )
+ setWMName( pFrame, String() );
+}
+
+/*
+ * NetWMAdaptor::setFrameDecoration
+ * sets _MOTIF_WM_HINTS
+ * _NET_WM_WINDOW_TYPE
+ * _NET_WM_STATE
+ * WM_TRANSIENT_FOR
+ */
+
+void NetWMAdaptor::setFrameTypeAndDecoration( X11SalFrame* pFrame, WMWindowType eType, int nDecorationFlags, X11SalFrame* pReferenceFrame ) const
+{
+ WMAdaptor::setFrameTypeAndDecoration( pFrame, eType, nDecorationFlags, pReferenceFrame );
+
+ setNetWMState( pFrame );
+
+ // set NET_WM_WINDOW_TYPE
+ if( m_aWMAtoms[ NET_WM_WINDOW_TYPE ] )
+ {
+ Atom aWindowTypes[4];
+ int nWindowTypes = 0;
+ switch( eType )
+ {
+ case windowType_Utility:
+ aWindowTypes[nWindowTypes++] =
+ m_aWMAtoms[ NET_WM_WINDOW_TYPE_UTILITY ] ?
+ m_aWMAtoms[ NET_WM_WINDOW_TYPE_UTILITY ] :
+ m_aWMAtoms[ NET_WM_WINDOW_TYPE_DIALOG ];
+ break;
+ case windowType_ModelessDialogue:
+ case windowType_ModalDialogue:
+ aWindowTypes[nWindowTypes++] =
+ m_aWMAtoms[ NET_WM_WINDOW_TYPE_DIALOG ];
+ break;
+ case windowType_Splash:
+ aWindowTypes[nWindowTypes++] =
+ m_aWMAtoms[ NET_WM_WINDOW_TYPE_SPLASH ] ?
+ m_aWMAtoms[ NET_WM_WINDOW_TYPE_SPLASH ] :
+ m_aWMAtoms[ NET_WM_WINDOW_TYPE_NORMAL ];
+ break;
+ case windowType_Toolbar:
+ if( m_aWMAtoms[ KDE_NET_WM_WINDOW_TYPE_OVERRIDE ] )
+ aWindowTypes[nWindowTypes++] = m_aWMAtoms[ KDE_NET_WM_WINDOW_TYPE_OVERRIDE ];
+ aWindowTypes[nWindowTypes++] =
+ m_aWMAtoms[ NET_WM_WINDOW_TYPE_TOOLBAR ] ?
+ m_aWMAtoms[ NET_WM_WINDOW_TYPE_TOOLBAR ] :
+ m_aWMAtoms[ NET_WM_WINDOW_TYPE_NORMAL];
+ break;
+ case windowType_Dock:
+ aWindowTypes[nWindowTypes++] =
+ m_aWMAtoms[ NET_WM_WINDOW_TYPE_DOCK ] ?
+ m_aWMAtoms[ NET_WM_WINDOW_TYPE_DOCK ] :
+ m_aWMAtoms[ NET_WM_WINDOW_TYPE_NORMAL];
+ break;
+ default:
+ aWindowTypes[nWindowTypes++] = m_aWMAtoms[ NET_WM_WINDOW_TYPE_NORMAL ];
+ break;
+ }
+ XChangeProperty( m_pDisplay,
+ pFrame->GetShellWindow(),
+ m_aWMAtoms[ NET_WM_WINDOW_TYPE ],
+ XA_ATOM,
+ 32,
+ PropModeReplace,
+ (unsigned char*)aWindowTypes,
+ nWindowTypes );
+ }
+ if( ( eType == windowType_ModalDialogue ||
+ eType == windowType_ModelessDialogue )
+ && ! pReferenceFrame )
+ {
+ XSetTransientForHint( m_pDisplay,
+ pFrame->GetShellWindow(),
+ m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ) );
+ pFrame->mbTransientForRoot = true;
+ }
+}
+
+/*
+ * WMAdaptor::maximizeFrame
+ */
+
+void WMAdaptor::maximizeFrame( X11SalFrame* pFrame, bool bHorizontal, bool bVertical ) const
+{
+ pFrame->mbMaximizedVert = bVertical;
+ pFrame->mbMaximizedHorz = bHorizontal;
+
+ const SalFrameGeometry& rGeom( pFrame->GetUnmirroredGeometry() );
+
+ // discard pending configure notifies for this frame
+ XSync( m_pDisplay, False );
+ XEvent aDiscard;
+ while( XCheckTypedWindowEvent( m_pDisplay,
+ pFrame->GetShellWindow(),
+ ConfigureNotify,
+ &aDiscard ) )
+ ;
+ while( XCheckTypedWindowEvent( m_pDisplay,
+ pFrame->GetWindow(),
+ ConfigureNotify,
+ &aDiscard ) )
+ ;
+
+ if( bHorizontal || bVertical )
+ {
+ Size aScreenSize( m_pSalDisplay->GetScreenSize( pFrame->GetScreenNumber() ) );
+ Point aTL( rGeom.nLeftDecoration, rGeom.nTopDecoration );
+ if( m_pSalDisplay->IsXinerama() )
+ {
+ Point aMed( aTL.X() + rGeom.nWidth/2, aTL.Y() + rGeom.nHeight/2 );
+ const std::vector< Rectangle >& rScreens = m_pSalDisplay->GetXineramaScreens();
+ for( unsigned int i = 0; i < rScreens.size(); i++ )
+ if( rScreens[i].IsInside( aMed ) )
+ {
+ aTL += rScreens[i].TopLeft();
+ aScreenSize = rScreens[i].GetSize();
+ break;
+ }
+ }
+ Rectangle aTarget( aTL,
+ Size( aScreenSize.Width() - rGeom.nLeftDecoration - rGeom.nTopDecoration,
+ aScreenSize.Height() - rGeom.nTopDecoration - rGeom.nBottomDecoration )
+ );
+ if( ! bHorizontal )
+ {
+ aTarget.SetSize(
+ Size(
+ pFrame->maRestorePosSize.IsEmpty() ?
+ rGeom.nWidth : pFrame->maRestorePosSize.GetWidth(),
+ aTarget.GetHeight()
+ )
+ );
+ aTarget.Left() =
+ pFrame->maRestorePosSize.IsEmpty() ?
+ rGeom.nX : pFrame->maRestorePosSize.Left();
+ }
+ else if( ! bVertical )
+ {
+ aTarget.SetSize(
+ Size(
+ aTarget.GetWidth(),
+ pFrame->maRestorePosSize.IsEmpty() ?
+ rGeom.nHeight : pFrame->maRestorePosSize.GetHeight()
+ )
+ );
+ aTarget.Top() =
+ pFrame->maRestorePosSize.IsEmpty() ?
+ rGeom.nY : pFrame->maRestorePosSize.Top();
+ }
+
+ Rectangle aRestore( Point( rGeom.nX, rGeom.nY ), Size( rGeom.nWidth, rGeom.nHeight ) );
+ if( pFrame->bMapped_ )
+ {
+ XSetInputFocus( m_pDisplay,
+ pFrame->GetShellWindow(),
+ RevertToNone,
+ CurrentTime
+ );
+ if( m_aWMName.EqualsAscii( "Dtwm" ) )
+ {
+ /*
+ * Dtwm will only position correctly with center gravity
+ * and in this case the request actually changes the frame
+ * not the shell window
+ */
+ aTarget = Rectangle( Point( 0, 0 ), aScreenSize );
+ aRestore.Move( -rGeom.nLeftDecoration, -rGeom.nTopDecoration );
+ }
+ }
+
+ if( pFrame->maRestorePosSize.IsEmpty() )
+ pFrame->maRestorePosSize = aRestore;
+
+ pFrame->SetPosSize( aTarget );
+ pFrame->nWidth_ = aTarget.GetWidth();
+ pFrame->nHeight_ = aTarget.GetHeight();
+ XRaiseWindow( m_pDisplay,
+ pFrame->GetShellWindow()
+ );
+ if( pFrame->GetStackingWindow() )
+ XRaiseWindow( m_pDisplay,
+ pFrame->GetStackingWindow()
+ );
+
+ }
+ else
+ {
+ pFrame->SetPosSize( pFrame->maRestorePosSize );
+ pFrame->maRestorePosSize = Rectangle();
+ pFrame->nWidth_ = rGeom.nWidth;
+ pFrame->nHeight_ = rGeom.nHeight;
+ if( m_aWMName.EqualsAscii( "Dtwm" ) && pFrame->bMapped_ )
+ {
+ pFrame->maGeometry.nX += rGeom.nLeftDecoration;
+ pFrame->maGeometry.nY += rGeom.nTopDecoration;
+ }
+ }
+}
+
+/*
+ * NetWMAdaptor::maximizeFrame
+ * changes _NET_WM_STATE by sending a client message
+ */
+
+void NetWMAdaptor::maximizeFrame( X11SalFrame* pFrame, bool bHorizontal, bool bVertical ) const
+{
+ pFrame->mbMaximizedVert = bVertical;
+ pFrame->mbMaximizedHorz = bHorizontal;
+
+ if( m_aWMAtoms[ NET_WM_STATE ]
+ && m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_VERT ]
+ && m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_HORZ ]
+ && ( pFrame->nStyle_ & ~SAL_FRAME_STYLE_DEFAULT )
+ )
+ {
+ if( pFrame->bMapped_ )
+ {
+ // window already mapped, send WM a message
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.window = pFrame->GetShellWindow();
+ aEvent.xclient.message_type = m_aWMAtoms[ NET_WM_STATE ];
+ aEvent.xclient.format = 32;
+ aEvent.xclient.data.l[0] = bHorizontal ? 1 : 0;
+ aEvent.xclient.data.l[1] = m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_HORZ ];
+ aEvent.xclient.data.l[2] = bHorizontal == bVertical ? m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_VERT ] : 0;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = 0;
+ XSendEvent( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ),
+ False,
+ SubstructureNotifyMask | SubstructureRedirectMask,
+ &aEvent
+ );
+ if( bHorizontal != bVertical )
+ {
+ aEvent.xclient.data.l[0]= bVertical ? 1 : 0;
+ aEvent.xclient.data.l[1]= m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_VERT ];
+ aEvent.xclient.data.l[2]= 0;
+ XSendEvent( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ),
+ False,
+ SubstructureNotifyMask | SubstructureRedirectMask,
+ &aEvent
+ );
+ }
+ }
+ else
+ {
+ // window not mapped yet, set _NET_WM_STATE directly
+ setNetWMState( pFrame );
+ }
+ if( !bHorizontal && !bVertical )
+ pFrame->maRestorePosSize = Rectangle();
+ else if( pFrame->maRestorePosSize.IsEmpty() )
+ {
+ const SalFrameGeometry& rGeom( pFrame->GetUnmirroredGeometry() );
+ pFrame->maRestorePosSize =
+ Rectangle( Point( rGeom.nX, rGeom.nY ), Size( rGeom.nWidth, rGeom.nHeight ) );
+ }
+ }
+ else
+ WMAdaptor::maximizeFrame( pFrame, bHorizontal, bVertical );
+}
+
+/*
+ * GnomeWMAdaptor::maximizeFrame
+ * changes _WIN_STATE by sending a client message
+ */
+
+void GnomeWMAdaptor::maximizeFrame( X11SalFrame* pFrame, bool bHorizontal, bool bVertical ) const
+{
+ pFrame->mbMaximizedVert = bVertical;
+ pFrame->mbMaximizedHorz = bHorizontal;
+
+ if( m_aWMAtoms[ WIN_STATE ]
+ && ( pFrame->nStyle_ & ~SAL_FRAME_STYLE_DEFAULT )
+ )
+ {
+ if( pFrame->bMapped_ )
+ {
+ // window already mapped, send WM a message
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.window = pFrame->GetShellWindow();
+ aEvent.xclient.message_type = m_aWMAtoms[ WIN_STATE ];
+ aEvent.xclient.format = 32;
+ aEvent.xclient.data.l[0] = (1<<2)|(1<<3);
+ aEvent.xclient.data.l[1] =
+ (bVertical ? (1<<2) : 0)
+ | (bHorizontal ? (1<<3) : 0);
+ aEvent.xclient.data.l[2] = 0;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = 0;
+ XSendEvent( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ),
+ False,
+ SubstructureNotifyMask,
+ &aEvent
+ );
+ }
+ else
+ // window not mapped yet, set _WIN_STATE directly
+ setGnomeWMState( pFrame );
+
+ if( !bHorizontal && !bVertical )
+ pFrame->maRestorePosSize = Rectangle();
+ else if( pFrame->maRestorePosSize.IsEmpty() )
+ {
+ const SalFrameGeometry& rGeom( pFrame->GetUnmirroredGeometry() );
+ pFrame->maRestorePosSize =
+ Rectangle( Point( rGeom.nX, rGeom.nY ), Size( rGeom.nWidth, rGeom.nHeight ) );
+ }
+ }
+ else
+ WMAdaptor::maximizeFrame( pFrame, bHorizontal, bVertical );
+}
+
+/*
+ * WMAdaptor::supportsICCCMPos
+ */
+
+bool WMAdaptor::supportsICCCMPos() const
+{
+ return
+ m_aWMName.EqualsAscii( "Sawfish" )
+ || m_aWMName.EqualsAscii( "Dtwm" );
+}
+
+/*
+ * NetWMAdaptor::supportsICCCMPos
+ */
+
+bool NetWMAdaptor::supportsICCCMPos() const
+{
+ return true;
+}
+
+
+/*
+ * WMAdaptor::enableAlwaysOnTop
+ */
+void WMAdaptor::enableAlwaysOnTop( X11SalFrame*, bool /*bEnable*/ ) const
+{
+}
+
+/*
+ * NetWMAdaptor::enableAlwaysOnTop
+ */
+void NetWMAdaptor::enableAlwaysOnTop( X11SalFrame* pFrame, bool bEnable ) const
+{
+ pFrame->bAlwaysOnTop_ = bEnable;
+ if( m_aWMAtoms[ NET_WM_STATE_STAYS_ON_TOP ] )
+ {
+ if( pFrame->bMapped_ )
+ {
+ // window already mapped, send WM a message
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.window = pFrame->GetShellWindow();
+ aEvent.xclient.message_type = m_aWMAtoms[ NET_WM_STATE ];
+ aEvent.xclient.format = 32;
+ aEvent.xclient.data.l[0] = bEnable ? 1 : 0;
+ aEvent.xclient.data.l[1] = m_aWMAtoms[ NET_WM_STATE_STAYS_ON_TOP ];
+ aEvent.xclient.data.l[2] = 0;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = 0;
+ XSendEvent( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ),
+ False,
+ SubstructureNotifyMask | SubstructureRedirectMask,
+ &aEvent
+ );
+ }
+ else
+ setNetWMState( pFrame );
+ }
+}
+
+/*
+ * GnomeWMAdaptor::enableAlwaysOnTop
+ */
+void GnomeWMAdaptor::enableAlwaysOnTop( X11SalFrame* pFrame, bool bEnable ) const
+{
+ pFrame->bAlwaysOnTop_ = bEnable;
+ if( m_aWMAtoms[ WIN_LAYER ] )
+ {
+ if( pFrame->bMapped_ )
+ {
+ // window already mapped, send WM a message
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.window = pFrame->GetShellWindow();
+ aEvent.xclient.message_type = m_aWMAtoms[ WIN_LAYER ];
+ aEvent.xclient.format = 32;
+ aEvent.xclient.data.l[0] = bEnable ? 6 : 4;
+ aEvent.xclient.data.l[1] = 0;
+ aEvent.xclient.data.l[2] = 0;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = 0;
+ XSendEvent( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ),
+ False,
+ SubstructureNotifyMask | SubstructureRedirectMask,
+ &aEvent
+ );
+ }
+ else
+ {
+ sal_uInt32 nNewLayer = bEnable ? 6 : 4;
+ XChangeProperty( m_pDisplay,
+ pFrame->GetShellWindow(),
+ m_aWMAtoms[ WIN_LAYER ],
+ XA_CARDINAL,
+ 32,
+ PropModeReplace,
+ (unsigned char*)&nNewLayer,
+ 1
+ );
+ }
+ }
+}
+
+/*
+ * WMAdaptor::changeReferenceFrame
+ */
+void WMAdaptor::changeReferenceFrame( X11SalFrame* pFrame, X11SalFrame* pReferenceFrame ) const
+{
+ if( ! ( pFrame->nStyle_ & SAL_FRAME_STYLE_PLUG )
+ && ! pFrame->IsOverrideRedirect()
+ && ! pFrame->IsFloatGrabWindow()
+ )
+ {
+ XLIB_Window aTransient = pFrame->pDisplay_->GetRootWindow( pFrame->GetScreenNumber() );
+ pFrame->mbTransientForRoot = true;
+ if( pReferenceFrame )
+ {
+ aTransient = pReferenceFrame->GetShellWindow();
+ pFrame->mbTransientForRoot = false;
+ }
+ XSetTransientForHint( m_pDisplay,
+ pFrame->GetShellWindow(),
+ aTransient );
+ }
+}
+
+/*
+ * WMAdaptor::handlePropertyNotify
+ */
+int WMAdaptor::handlePropertyNotify( X11SalFrame*, XPropertyEvent* ) const
+{
+ return 0;
+}
+
+/*
+ * NetWMAdaptor::handlePropertyNotify
+ */
+int NetWMAdaptor::handlePropertyNotify( X11SalFrame* pFrame, XPropertyEvent* pEvent ) const
+{
+ int nHandled = 1;
+ if( pEvent->atom == m_aWMAtoms[ NET_WM_STATE ] )
+ {
+ pFrame->mbMaximizedHorz = pFrame->mbMaximizedVert = false;
+ pFrame->mbShaded = false;
+
+ if( pEvent->state == PropertyNewValue )
+ {
+ Atom nType, *pStates;
+ int nFormat;
+ unsigned long nItems, nBytesLeft;
+ unsigned char* pData = NULL;
+ long nOffset = 0;
+ do
+ {
+ XGetWindowProperty( m_pDisplay,
+ pEvent->window,
+ m_aWMAtoms[ NET_WM_STATE ],
+ nOffset, 64,
+ False,
+ XA_ATOM,
+ &nType,
+ &nFormat,
+ &nItems, &nBytesLeft,
+ &pData );
+ if( pData )
+ {
+ if( nType == XA_ATOM && nFormat == 32 && nItems > 0 )
+ {
+ pStates = (Atom*)pData;
+ for( unsigned long i = 0; i < nItems; i++ )
+ {
+ if( pStates[i] == m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_VERT ] && m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_VERT ] )
+ pFrame->mbMaximizedVert = true;
+ else if( pStates[i] == m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_HORZ ] && m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_HORZ ] )
+ pFrame->mbMaximizedHorz = true;
+ else if( pStates[i] == m_aWMAtoms[ NET_WM_STATE_SHADED ] && m_aWMAtoms[ NET_WM_STATE_SHADED ] )
+ pFrame->mbShaded = true;
+ }
+ }
+ XFree( pData );
+ pData = NULL;
+ nOffset += nItems * nFormat / 32;
+ }
+ else
+ break;
+ } while( nBytesLeft > 0 );
+ }
+
+ if( ! (pFrame->mbMaximizedHorz || pFrame->mbMaximizedVert ) )
+ pFrame->maRestorePosSize = Rectangle();
+ else
+ {
+ const SalFrameGeometry& rGeom = pFrame->GetUnmirroredGeometry();
+ // the current geometry may already be changed by the corresponding
+ // ConfigureNotify, but this cannot be helped
+ pFrame->maRestorePosSize =
+ Rectangle( Point( rGeom.nX, rGeom.nY ),
+ Size( rGeom.nWidth, rGeom.nHeight ) );
+ }
+ }
+ else if( pEvent->atom == m_aWMAtoms[ NET_WM_DESKTOP ] )
+ {
+ pFrame->m_nWorkArea = getWindowWorkArea( pFrame->GetShellWindow() );
+ }
+ else
+ nHandled = 0;
+
+ return nHandled;
+}
+
+/*
+ * GnomeWMAdaptor::handlePropertyNotify
+ */
+int GnomeWMAdaptor::handlePropertyNotify( X11SalFrame* pFrame, XPropertyEvent* pEvent ) const
+{
+ int nHandled = 1;
+ if( pEvent->atom == m_aWMAtoms[ WIN_STATE ] )
+ {
+ pFrame->mbMaximizedHorz = pFrame->mbMaximizedVert = false;
+ pFrame->mbShaded = false;
+
+ if( pEvent->state == PropertyNewValue )
+ {
+ Atom nType;
+ int nFormat = 0;
+ unsigned long nItems = 0;
+ unsigned long nBytesLeft = 0;
+ unsigned char* pData = 0;
+ XGetWindowProperty( m_pDisplay,
+ pEvent->window,
+ m_aWMAtoms[ WIN_STATE ],
+ 0, 1,
+ False,
+ XA_CARDINAL,
+ &nType,
+ &nFormat,
+ &nItems, &nBytesLeft,
+ &pData );
+ if( pData )
+ {
+ if( nType == XA_CARDINAL && nFormat == 32 && nItems == 1 )
+ {
+ sal_uInt32 nWinState = *(sal_uInt32*)pData;
+ if( nWinState & (1<<2) )
+ pFrame->mbMaximizedVert = true;
+ if( nWinState & (1<<3) )
+ pFrame->mbMaximizedHorz = true;
+ if( nWinState & (1<<5) )
+ pFrame->mbShaded = true;
+ }
+ XFree( pData );
+ }
+ }
+
+ if( ! (pFrame->mbMaximizedHorz || pFrame->mbMaximizedVert ) )
+ pFrame->maRestorePosSize = Rectangle();
+ else
+ {
+ const SalFrameGeometry& rGeom = pFrame->GetUnmirroredGeometry();
+ // the current geometry may already be changed by the corresponding
+ // ConfigureNotify, but this cannot be helped
+ pFrame->maRestorePosSize =
+ Rectangle( Point( rGeom.nX, rGeom.nY ),
+ Size( rGeom.nWidth, rGeom.nHeight ) );
+ }
+ }
+ else if( pEvent->atom == m_aWMAtoms[ NET_WM_DESKTOP ] )
+ {
+ pFrame->m_nWorkArea = getWindowWorkArea( pFrame->GetShellWindow() );
+ }
+ else
+ nHandled = 0;
+
+ return nHandled;
+}
+
+/*
+ * WMAdaptor::shade
+ */
+void WMAdaptor::shade( X11SalFrame*, bool /*bToShaded*/ ) const
+{
+}
+
+/*
+ * NetWMAdaptor::shade
+ */
+void NetWMAdaptor::shade( X11SalFrame* pFrame, bool bToShaded ) const
+{
+ if( m_aWMAtoms[ NET_WM_STATE ]
+ && m_aWMAtoms[ NET_WM_STATE_SHADED ]
+ && ( pFrame->nStyle_ & ~SAL_FRAME_STYLE_DEFAULT )
+ )
+ {
+ pFrame->mbShaded = bToShaded;
+ if( pFrame->bMapped_ )
+ {
+ // window already mapped, send WM a message
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.window = pFrame->GetShellWindow();
+ aEvent.xclient.message_type = m_aWMAtoms[ NET_WM_STATE ];
+ aEvent.xclient.format = 32;
+ aEvent.xclient.data.l[0] = bToShaded ? 1 : 0;
+ aEvent.xclient.data.l[1] = m_aWMAtoms[ NET_WM_STATE_SHADED ];
+ aEvent.xclient.data.l[2] = 0;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = 0;
+ XSendEvent( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ),
+ False,
+ SubstructureNotifyMask | SubstructureRedirectMask,
+ &aEvent
+ );
+ }
+ else
+ {
+ // window not mapped yet, set _NET_WM_STATE directly
+ setNetWMState( pFrame );
+ }
+ }
+}
+
+/*
+ * GnomeWMAdaptor::shade
+ */
+void GnomeWMAdaptor::shade( X11SalFrame* pFrame, bool bToShaded ) const
+{
+ if( m_aWMAtoms[ WIN_STATE ] )
+ {
+ pFrame->mbShaded = bToShaded;
+ if( pFrame->bMapped_ )
+ {
+ // window already mapped, send WM a message
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.window = pFrame->GetShellWindow();
+ aEvent.xclient.message_type = m_aWMAtoms[ WIN_STATE ];
+ aEvent.xclient.format = 32;
+ aEvent.xclient.data.l[0] = (1<<5);
+ aEvent.xclient.data.l[1] = bToShaded ? (1<<5) : 0;
+ aEvent.xclient.data.l[2] = 0;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = 0;
+ XSendEvent( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ),
+ False,
+ SubstructureNotifyMask | SubstructureRedirectMask,
+ &aEvent
+ );
+ }
+ else
+ setGnomeWMState( pFrame );
+ }
+}
+
+/*
+ * WMAdaptor::showFullScreen
+ */
+void WMAdaptor::showFullScreen( X11SalFrame* pFrame, bool bFullScreen ) const
+{
+ pFrame->mbFullScreen = bFullScreen;
+ maximizeFrame( pFrame, bFullScreen, bFullScreen );
+}
+
+/*
+ * NetWMAdaptor::showFullScreen
+ */
+void NetWMAdaptor::showFullScreen( X11SalFrame* pFrame, bool bFullScreen ) const
+{
+ if( m_aWMAtoms[ NET_WM_STATE_FULLSCREEN ] )
+ {
+ pFrame->mbFullScreen = bFullScreen;
+ if( pFrame->bMapped_ )
+ {
+ // window already mapped, send WM a message
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.window = pFrame->GetShellWindow();
+ aEvent.xclient.message_type = m_aWMAtoms[ NET_WM_STATE ];
+ aEvent.xclient.format = 32;
+ aEvent.xclient.data.l[0] = bFullScreen ? 1 : 0;
+ aEvent.xclient.data.l[1] = m_aWMAtoms[ NET_WM_STATE_FULLSCREEN ];
+ aEvent.xclient.data.l[2] = 0;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = 0;
+ XSendEvent( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ),
+ False,
+ SubstructureNotifyMask | SubstructureRedirectMask,
+ &aEvent
+ );
+ }
+ else
+ {
+ // window not mapped yet, set _NET_WM_STATE directly
+ setNetWMState( pFrame );
+ }
+ // #i42750# guess size before resize event shows up
+ if( bFullScreen )
+ {
+ if( m_pSalDisplay->IsXinerama() )
+ {
+ XLIB_Window aRoot, aChild;
+ int root_x = 0, root_y = 0, lx, ly;
+ unsigned int mask;
+ XQueryPointer( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ),
+ &aRoot, &aChild,
+ &root_x, &root_y, &lx, &ly, &mask );
+ const std::vector< Rectangle >& rScreens = m_pSalDisplay->GetXineramaScreens();
+ Point aMousePoint( root_x, root_y );
+ for( unsigned int i = 0; i < rScreens.size(); i++ )
+ {
+ if( rScreens[i].IsInside( aMousePoint ) )
+ {
+ pFrame->maGeometry.nX = rScreens[i].Left();
+ pFrame->maGeometry.nY = rScreens[i].Top();
+ pFrame->maGeometry.nWidth = rScreens[i].GetWidth();
+ pFrame->maGeometry.nHeight = rScreens[i].GetHeight();
+ break;
+ }
+ }
+ }
+ else
+ {
+ Size aSize = m_pSalDisplay->GetScreenSize( pFrame->GetScreenNumber() );
+ pFrame->maGeometry.nX = 0;
+ pFrame->maGeometry.nY = 0;
+ pFrame->maGeometry.nWidth = aSize.Width();
+ pFrame->maGeometry.nHeight = aSize.Height();
+ }
+ pFrame->CallCallback( SALEVENT_MOVERESIZE, NULL );
+ }
+ }
+ else WMAdaptor::showFullScreen( pFrame, bFullScreen );
+}
+
+/*
+ * WMAdaptor::getCurrentWorkArea
+ */
+// FIXME: multiscreen case
+int WMAdaptor::getCurrentWorkArea() const
+{
+ int nCurrent = -1;
+ if( m_aWMAtoms[ NET_CURRENT_DESKTOP ] )
+ {
+ Atom aRealType = None;
+ int nFormat = 8;
+ unsigned long nItems = 0;
+ unsigned long nBytesLeft = 0;
+ unsigned char* pProperty = NULL;
+ if( XGetWindowProperty( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ m_aWMAtoms[ NET_CURRENT_DESKTOP ],
+ 0, 1,
+ False,
+ XA_CARDINAL,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0
+ && pProperty
+ )
+ {
+ nCurrent = int(*(sal_Int32*)pProperty);
+ XFree( pProperty );
+ }
+ else if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ }
+ return nCurrent;
+}
+
+/*
+ * WMAdaptor::getWindowWorkArea
+ */
+int WMAdaptor::getWindowWorkArea( XLIB_Window aWindow ) const
+{
+ int nCurrent = -1;
+ if( m_aWMAtoms[ NET_WM_DESKTOP ] )
+ {
+ Atom aRealType = None;
+ int nFormat = 8;
+ unsigned long nItems = 0;
+ unsigned long nBytesLeft = 0;
+ unsigned char* pProperty = NULL;
+ if( XGetWindowProperty( m_pDisplay,
+ aWindow,
+ m_aWMAtoms[ NET_WM_DESKTOP ],
+ 0, 1,
+ False,
+ XA_CARDINAL,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty ) == 0
+ && pProperty
+ )
+ {
+ nCurrent = int(*(sal_Int32*)pProperty);
+ XFree( pProperty );
+ }
+ else if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ }
+ return nCurrent;
+}
+
+/*
+ * WMAdaptor::getCurrentWorkArea
+ */
+// fixme: multi screen case
+void WMAdaptor::switchToWorkArea( int nWorkArea ) const
+{
+ if( m_aWMAtoms[ NET_CURRENT_DESKTOP ] )
+ {
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.window = m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() );
+ aEvent.xclient.message_type = m_aWMAtoms[ NET_CURRENT_DESKTOP ];
+ aEvent.xclient.format = 32;
+ aEvent.xclient.data.l[0] = nWorkArea;
+ aEvent.xclient.data.l[1] = 0;
+ aEvent.xclient.data.l[2] = 0;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = 0;
+ XSendEvent( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ),
+ False,
+ SubstructureNotifyMask | SubstructureRedirectMask,
+ &aEvent
+ );
+ }
+}
+
+/*
+ * WMAdaptor::frameIsMapping
+ */
+void WMAdaptor::frameIsMapping( X11SalFrame* ) const
+{
+}
+
+/*
+ * NetWMAdaptor::frameIsMapping
+ */
+void NetWMAdaptor::frameIsMapping( X11SalFrame* pFrame ) const
+{
+ setNetWMState( pFrame );
+}
+
+/*
+ * WMAdaptor::setFrameStruts
+ */
+void WMAdaptor::setFrameStruts( X11SalFrame*,
+ int, int, int, int,
+ int, int, int, int,
+ int, int, int, int ) const
+{
+}
+
+/*
+ * NetWMAdaptor::setFrameStruts
+ */
+void NetWMAdaptor::setFrameStruts( X11SalFrame* pFrame,
+ int left, int right, int top, int bottom,
+ int left_start_y, int left_end_y,
+ int right_start_y, int right_end_y,
+ int top_start_x, int top_end_x,
+ int bottom_start_x, int bottom_end_x ) const
+{
+ long nData[12];
+ nData[0] = left;
+ nData[1] = right;
+ nData[2] = top;
+ nData[3] = bottom;
+ nData[4] = left_start_y;
+ nData[5] = left_end_y;
+ nData[6] = right_start_y;
+ nData[7] = right_end_y;
+ nData[8] = top_start_x;
+ nData[9] = top_end_x;
+ nData[10]= bottom_start_x;
+ nData[11]= bottom_end_x;
+ Atom aProperty = None;
+ int nSetData = 0;
+
+ if( m_aWMAtoms[NET_WM_STRUT_PARTIAL] )
+ {
+ aProperty = m_aWMAtoms[NET_WM_STRUT_PARTIAL];
+ nSetData = 12;
+ }
+ else if( m_aWMAtoms[NET_WM_STRUT] )
+ {
+ aProperty = m_aWMAtoms[NET_WM_STRUT];
+ nSetData = 4;
+ }
+ if( nSetData )
+ {
+ XChangeProperty( m_pDisplay,
+ pFrame->GetShellWindow(),
+ aProperty,
+ XA_CARDINAL,
+ 32,
+ PropModeReplace,
+ (unsigned char*)&nData,
+ nSetData
+ );
+ }
+}
+
+/*
+ * WMAdaptor::setUserTime
+ */
+void WMAdaptor::setUserTime( X11SalFrame*, long ) const
+{
+}
+
+/*
+ * NetWMAdaptor::setUserTime
+ */
+void NetWMAdaptor::setUserTime( X11SalFrame* i_pFrame, long i_nUserTime ) const
+{
+ if( m_aWMAtoms[NET_WM_USER_TIME] )
+ {
+ XChangeProperty( m_pDisplay,
+ i_pFrame->GetShellWindow(),
+ m_aWMAtoms[NET_WM_USER_TIME],
+ XA_CARDINAL,
+ 32,
+ PropModeReplace,
+ (unsigned char*)&i_nUserTime,
+ 1
+ );
+ }
+}
+
+/*
+ * WMAdaptor::setPID
+ */
+void WMAdaptor::setPID( X11SalFrame* i_pFrame ) const
+{
+ if( m_aWMAtoms[NET_WM_PID] )
+ {
+ long nPID = (long)getpid();
+ XChangeProperty( m_pDisplay,
+ i_pFrame->GetShellWindow(),
+ m_aWMAtoms[NET_WM_PID],
+ XA_CARDINAL,
+ 32,
+ PropModeReplace,
+ (unsigned char*)&nPID,
+ 1
+ );
+ }
+}
+
+/*
+* WMAdaptor::setClientMachine
+*/
+void WMAdaptor::setClientMachine( X11SalFrame* i_pFrame ) const
+{
+ rtl::OString aWmClient( rtl::OUStringToOString( GetX11SalData()->GetLocalHostName(), RTL_TEXTENCODING_ASCII_US ) );
+ XTextProperty aClientProp = { (unsigned char*)aWmClient.getStr(), XA_STRING, 8, aWmClient.getLength() };
+ XSetWMClientMachine( m_pDisplay, i_pFrame->GetShellWindow(), &aClientProp );
+}
+
+void WMAdaptor::answerPing( X11SalFrame* i_pFrame, XClientMessageEvent* i_pEvent ) const
+{
+ if( m_aWMAtoms[NET_WM_PING] &&
+ i_pEvent->message_type == m_aWMAtoms[ WM_PROTOCOLS ] &&
+ (Atom)i_pEvent->data.l[0] == m_aWMAtoms[ NET_WM_PING ] )
+ {
+ XEvent aEvent;
+ aEvent.xclient = *i_pEvent;
+ aEvent.xclient.window = m_pSalDisplay->GetRootWindow( i_pFrame->GetScreenNumber() );
+ XSendEvent( m_pDisplay,
+ m_pSalDisplay->GetRootWindow( i_pFrame->GetScreenNumber() ),
+ False,
+ SubstructureNotifyMask | SubstructureRedirectMask,
+ &aEvent
+ );
+ XFlush( m_pDisplay );
+ }
+}
diff --git a/vcl/unx/source/desktopdetect/desktopdetector.cxx b/vcl/unx/source/desktopdetect/desktopdetector.cxx
new file mode 100644
index 000000000000..74ab2e2c3ea2
--- /dev/null
+++ b/vcl/unx/source/desktopdetect/desktopdetector.cxx
@@ -0,0 +1,343 @@
+/*************************************************************************
+ *
+ * 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 <svunx.h>
+#include <tools/prex.h>
+#include <X11/Xatom.h>
+#include <tools/postx.h>
+
+#include "vcl/dllapi.h"
+
+#include "rtl/ustrbuf.hxx"
+#include "osl/module.h"
+#include "osl/process.h"
+#include "osl/thread.h"
+
+#include <unistd.h>
+
+using namespace rtl;
+
+enum {
+ DESKTOP_NONE = 0,
+ DESKTOP_UNKNOWN,
+ DESKTOP_GNOME,
+ DESKTOP_KDE,
+ DESKTOP_KDE4,
+ DESKTOP_CDE
+};
+
+static const char * desktop_strings[] = { "none", "unknown", "GNOME", "KDE", "KDE4", "CDE" };
+
+static bool is_gnome_desktop( Display* pDisplay )
+{
+ bool ret = false;
+
+ // warning: these checks are coincidental, GNOME does not
+ // explicitly advertise itself
+
+ if ( NULL != getenv( "GNOME_DESKTOP_SESSION_ID" ) )
+ ret = true;
+
+ if( ! ret )
+ {
+ Atom nAtom1 = XInternAtom( pDisplay, "GNOME_SM_PROXY", True );
+ Atom nAtom2 = XInternAtom( pDisplay, "NAUTILUS_DESKTOP_WINDOW_ID", True );
+ if( nAtom1 || nAtom2 )
+ {
+ int nProperties = 0;
+ Atom* pProperties = XListProperties( pDisplay, DefaultRootWindow( pDisplay ), &nProperties );
+ if( pProperties && nProperties )
+ {
+ for( int i = 0; i < nProperties; i++ )
+ if( pProperties[ i ] == nAtom1 ||
+ pProperties[ i ] == nAtom2 )
+ {
+ ret = true;
+ }
+ XFree( pProperties );
+ }
+ }
+ }
+
+ if( ! ret )
+ {
+ Atom nUTFAtom = XInternAtom( pDisplay, "UTF8_STRING", True );
+ Atom nNetWMNameAtom = XInternAtom( pDisplay, "_NET_WM_NAME", True );
+ if( nUTFAtom && nNetWMNameAtom )
+ {
+ // another, more expensive check: search for a gnome-panel
+ XLIB_Window aRoot, aParent, *pChildren = NULL;
+ unsigned int nChildren = 0;
+ XQueryTree( pDisplay, DefaultRootWindow( pDisplay ),
+ &aRoot, &aParent, &pChildren, &nChildren );
+ if( pChildren && nChildren )
+ {
+ for( unsigned int i = 0; i < nChildren && ! ret; i++ )
+ {
+ Atom nType = None;
+ int nFormat = 0;
+ unsigned long nItems = 0, nBytes = 0;
+ unsigned char* pProp = NULL;
+ XGetWindowProperty( pDisplay,
+ pChildren[i],
+ nNetWMNameAtom,
+ 0, 8,
+ False,
+ nUTFAtom,
+ &nType,
+ &nFormat,
+ &nItems,
+ &nBytes,
+ &pProp );
+ if( pProp && nType == nUTFAtom )
+ {
+ OString aWMName( (sal_Char*)pProp );
+ if( aWMName.equalsIgnoreAsciiCase( "gnome-panel" ) )
+ ret = true;
+ }
+ if( pProp )
+ XFree( pProp );
+ }
+ XFree( pChildren );
+ }
+ }
+ }
+
+ return ret;
+}
+
+static bool bWasXError = false;
+
+static inline bool WasXError()
+{
+ bool bRet = bWasXError;
+ bWasXError = false;
+ return bRet;
+}
+
+extern "C"
+{
+ static int autodect_error_handler( Display*, XErrorEvent* )
+ {
+ bWasXError = true;
+ return 0;
+ }
+
+ typedef int(* XErrorHandler)(Display*,XErrorEvent*);
+}
+
+static int KDEVersion( Display* pDisplay )
+{
+ int nRet = 0;
+
+ Atom nFullSession = XInternAtom( pDisplay, "KDE_FULL_SESSION", True );
+ Atom nKDEVersion = XInternAtom( pDisplay, "KDE_SESSION_VERSION", True );
+
+ if( nFullSession )
+ {
+ if( !nKDEVersion )
+ return 3;
+
+ Atom aRealType = None;
+ int nFormat = 8;
+ unsigned long nItems = 0;
+ unsigned long nBytesLeft = 0;
+ unsigned char* pProperty = NULL;
+ XGetWindowProperty( pDisplay,
+ DefaultRootWindow( pDisplay ),
+ nKDEVersion,
+ 0, 1,
+ False,
+ AnyPropertyType,
+ &aRealType,
+ &nFormat,
+ &nItems,
+ &nBytesLeft,
+ &pProperty );
+ if( !WasXError() && nItems != 0 && pProperty )
+ {
+ nRet = *reinterpret_cast< sal_Int32* >( pProperty );
+ }
+ if( pProperty )
+ {
+ XFree( pProperty );
+ pProperty = NULL;
+ }
+ }
+ return nRet;
+}
+
+static bool is_kde_desktop( Display* pDisplay )
+{
+ if ( NULL != getenv( "KDE_FULL_SESSION" ) )
+ {
+ const char *pVer = getenv( "KDE_SESSION_VERSION" );
+ if ( !pVer || pVer[0] == '0' )
+ {
+ return true; // does not exist => KDE3
+ }
+
+ rtl::OUString aVer( RTL_CONSTASCII_USTRINGPARAM( "3" ) );
+ if ( aVer.equalsIgnoreAsciiCaseAscii( pVer ) )
+ {
+ return true;
+ }
+ }
+
+ if ( KDEVersion( pDisplay ) == 3 )
+ return true;
+
+ return false;
+}
+
+static bool is_kde4_desktop( Display* pDisplay )
+{
+ if ( NULL != getenv( "KDE_FULL_SESSION" ) )
+ {
+ rtl::OUString aVer( RTL_CONSTASCII_USTRINGPARAM( "4" ) );
+
+ const char *pVer = getenv( "KDE_SESSION_VERSION" );
+ if ( pVer && aVer.equalsIgnoreAsciiCaseAscii( pVer ) )
+ return true;
+ }
+
+ if ( KDEVersion( pDisplay ) == 4 )
+ return true;
+
+ return false;
+}
+
+static bool is_cde_desktop( Display* pDisplay )
+{
+ void* pLibrary = NULL;
+
+ Atom nDtAtom = XInternAtom( pDisplay, "_DT_WM_READY", True );
+ OUString aPathName( RTL_CONSTASCII_USTRINGPARAM( "file:///usr/dt/lib/libDtSvc.so" ) );
+ if( nDtAtom && ( pLibrary = osl_loadModule( aPathName.pData, SAL_LOADMODULE_DEFAULT ) ) )
+ {
+ osl_unloadModule( (oslModule)pLibrary );
+ return true;
+ }
+
+ return false;
+}
+
+
+extern "C"
+{
+
+VCL_DLLPUBLIC rtl::OUString get_desktop_environment()
+{
+ rtl::OUStringBuffer aRet( 8 );
+ static const char *pOverride = getenv( "OOO_FORCE_DESKTOP" );
+
+ if ( pOverride && *pOverride )
+ {
+ OString aOver( pOverride );
+
+ if ( aOver.equalsIgnoreAsciiCase( "cde" ) )
+ aRet.appendAscii( desktop_strings[DESKTOP_CDE] );
+ if ( aOver.equalsIgnoreAsciiCase( "kde4" ) )
+ aRet.appendAscii( desktop_strings[DESKTOP_KDE4] );
+ if ( aOver.equalsIgnoreAsciiCase( "gnome" ) )
+ aRet.appendAscii( desktop_strings[DESKTOP_GNOME] );
+ if ( aOver.equalsIgnoreAsciiCase( "kde" ) )
+ aRet.appendAscii( desktop_strings[DESKTOP_KDE] );
+ if ( aOver.equalsIgnoreAsciiCase( "none" ) )
+ aRet.appendAscii( desktop_strings[DESKTOP_UNKNOWN] );
+ }
+
+ if( aRet.getLength() == 0 )
+ {
+ // get display to connect to
+ const char* pDisplayStr = getenv( "DISPLAY" );
+ int nParams = osl_getCommandArgCount();
+ OUString aParam;
+ OString aBParm;
+ for( int i = 0; i < nParams; i++ )
+ {
+ osl_getCommandArg( i, &aParam.pData );
+ if( aParam.equalsAscii( "-headless" ) )
+ {
+ pDisplayStr = NULL;
+ break;
+ }
+ if( i < nParams-1 && (aParam.equalsAscii( "-display" ) || aParam.equalsAscii( "--display" )) )
+ {
+ osl_getCommandArg( i+1, &aParam.pData );
+ aBParm = OUStringToOString( aParam, osl_getThreadTextEncoding() );
+ pDisplayStr = aBParm.getStr();
+ break;
+ }
+ }
+
+ // no server at all
+ if( ! pDisplayStr || !*pDisplayStr )
+ aRet.appendAscii( desktop_strings[DESKTOP_NONE] );
+ else
+ {
+ /* #i92121# workaround deadlocks in the X11 implementation
+ */
+ static const char* pNoXInitThreads = getenv( "SAL_NO_XINITTHREADS" );
+ /* #i90094#
+ from now on we know that an X connection will be
+ established, so protect X against itself
+ */
+ if( ! ( pNoXInitThreads && *pNoXInitThreads ) )
+ XInitThreads();
+
+ Display* pDisplay = XOpenDisplay( pDisplayStr );
+ if( pDisplay )
+ {
+ XErrorHandler pOldHdl = XSetErrorHandler( autodect_error_handler );
+
+ if ( is_kde4_desktop( pDisplay ) )
+ aRet.appendAscii( desktop_strings[DESKTOP_KDE4] );
+ else if ( is_gnome_desktop( pDisplay ) )
+ aRet.appendAscii( desktop_strings[DESKTOP_GNOME] );
+ else if ( is_cde_desktop( pDisplay ) )
+ aRet.appendAscii( desktop_strings[DESKTOP_CDE] );
+ else if ( is_kde_desktop( pDisplay ) )
+ aRet.appendAscii( desktop_strings[DESKTOP_KDE] );
+ else
+ aRet.appendAscii( desktop_strings[DESKTOP_UNKNOWN] );
+
+ // set the default handler again
+ XSetErrorHandler( pOldHdl );
+
+ XCloseDisplay( pDisplay );
+ }
+ }
+ }
+
+ return aRet.makeStringAndClear();
+}
+
+}
diff --git a/vcl/unx/source/desktopdetect/makefile.mk b/vcl/unx/source/desktopdetect/makefile.mk
new file mode 100644
index 000000000000..83d5d29f4b71
--- /dev/null
+++ b/vcl/unx/source/desktopdetect/makefile.mk
@@ -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.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+
+PRJNAME=vcl
+TARGET=dtdetect
+
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)"!="unx"
+
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+
+.ELSE # "$(GUIBASE)"!="unx"
+
+SLOFILES=$(SLO)$/desktopdetector.obj
+
+.ENDIF # "$(GUIBASE)"!="unx"
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
+.INCLUDE : $(PRJ)$/util$/target.pmk
diff --git a/vcl/unx/source/dtrans/X11_clipboard.cxx b/vcl/unx/source/dtrans/X11_clipboard.cxx
new file mode 100644
index 000000000000..a08a9481b8e8
--- /dev/null
+++ b/vcl/unx/source/dtrans/X11_clipboard.cxx
@@ -0,0 +1,293 @@
+/*************************************************************************
+ *
+ * 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 <X11/Xatom.h>
+#include <X11_clipboard.hxx>
+#include <X11_transferable.hxx>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/datatransfer/clipboard/RenderingCapabilities.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#include <uno/dispatcher.h> // declaration of generic uno interface
+#include <uno/mapping.hxx> // mapping stuff
+#include <cppuhelper/factory.hxx>
+#include <rtl/tencinfo.h>
+
+#if OSL_DEBUG_LEVEL > 1
+#include <stdio.h>
+#endif
+
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::datatransfer::clipboard;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::awt;
+using namespace cppu;
+using namespace osl;
+using namespace rtl;
+using namespace x11;
+
+X11Clipboard::X11Clipboard( SelectionManager& rManager, Atom aSelection ) :
+ ::cppu::WeakComponentImplHelper4<
+ ::com::sun::star::datatransfer::clipboard::XClipboardEx,
+ ::com::sun::star::datatransfer::clipboard::XClipboardNotifier,
+ ::com::sun::star::lang::XServiceInfo,
+ ::com::sun::star::lang::XInitialization
+ >( rManager.getMutex() ),
+
+ m_rSelectionManager( rManager ),
+ m_xSelectionManager( & rManager ),
+ m_aSelection( aSelection )
+{
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "creating instance of X11Clipboard (this=%p)\n", this );
+#endif
+
+ if( m_aSelection != None )
+ {
+ m_rSelectionManager.registerHandler( m_aSelection, *this );
+ }
+ else
+ {
+ m_rSelectionManager.registerHandler( XA_PRIMARY, *this );
+ m_rSelectionManager.registerHandler( m_rSelectionManager.getAtom( OUString::createFromAscii( "CLIPBOARD" ) ), *this );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+X11Clipboard::~X11Clipboard()
+{
+ MutexGuard aGuard( *Mutex::getGlobalMutex() );
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "shutting down instance of X11Clipboard (this=%p, Selecttion=\"%s\")\n", this, OUStringToOString( m_rSelectionManager.getString( m_aSelection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+ if( m_aSelection != None )
+ m_rSelectionManager.deregisterHandler( m_aSelection );
+ else
+ {
+ m_rSelectionManager.deregisterHandler( XA_PRIMARY );
+ m_rSelectionManager.deregisterHandler( m_rSelectionManager.getAtom( OUString::createFromAscii( "CLIPBOARD" ) ) );
+ }
+}
+
+
+// ------------------------------------------------------------------------
+
+void X11Clipboard::fireChangedContentsEvent()
+{
+ ClearableMutexGuard aGuard( m_rSelectionManager.getMutex() );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "X11Clipboard::fireChangedContentsEvent for %s (%d listeners)\n",
+ OUStringToOString( m_rSelectionManager.getString( m_aSelection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(), m_aListeners.size() );
+#endif
+ ::std::list< Reference< XClipboardListener > > listeners( m_aListeners );
+ aGuard.clear();
+
+ ClipboardEvent aEvent( static_cast<OWeakObject*>(this), m_aContents);
+ while( listeners.begin() != listeners.end() )
+ {
+ if( listeners.front().is() )
+ listeners.front()->changedContents(aEvent);
+ listeners.pop_front();
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void X11Clipboard::clearContents()
+{
+ ClearableMutexGuard aGuard(m_rSelectionManager.getMutex());
+ // protect against deletion during outside call
+ Reference< XClipboard > xThis( static_cast<XClipboard*>(this));
+ // copy member references on stack so they can be called
+ // without having the mutex
+ Reference< XClipboardOwner > xOwner( m_aOwner );
+ Reference< XTransferable > xTrans( m_aContents );
+ // clear members
+ m_aOwner.clear();
+ m_aContents.clear();
+
+ // release the mutex
+ aGuard.clear();
+
+ // inform previous owner of lost ownership
+ if ( xOwner.is() )
+ xOwner->lostOwnership(xThis, m_aContents);
+}
+
+// ------------------------------------------------------------------------
+
+Reference< XTransferable > SAL_CALL X11Clipboard::getContents()
+ throw(RuntimeException)
+{
+ MutexGuard aGuard(m_rSelectionManager.getMutex());
+
+ if( ! m_aContents.is() )
+ m_aContents = new X11Transferable( SelectionManager::get(), static_cast< OWeakObject* >(this), m_aSelection );
+ return m_aContents;
+}
+
+// ------------------------------------------------------------------------
+
+void SAL_CALL X11Clipboard::setContents(
+ const Reference< XTransferable >& xTrans,
+ const Reference< XClipboardOwner >& xClipboardOwner )
+ throw(RuntimeException)
+{
+ // remember old values for callbacks before setting the new ones.
+ ClearableMutexGuard aGuard(m_rSelectionManager.getMutex());
+
+ Reference< XClipboardOwner > oldOwner( m_aOwner );
+ m_aOwner = xClipboardOwner;
+
+ Reference< XTransferable > oldContents( m_aContents );
+ m_aContents = xTrans;
+
+ aGuard.clear();
+
+ // for now request ownership for both selections
+ if( m_aSelection != None )
+ m_rSelectionManager.requestOwnership( m_aSelection );
+ else
+ {
+ m_rSelectionManager.requestOwnership( XA_PRIMARY );
+ m_rSelectionManager.requestOwnership( m_rSelectionManager.getAtom( OUString::createFromAscii( "CLIPBOARD" ) ) );
+ }
+
+ // notify old owner on loss of ownership
+ if( oldOwner.is() )
+ oldOwner->lostOwnership(static_cast < XClipboard * > (this), oldContents);
+
+ // notify all listeners on content changes
+ fireChangedContentsEvent();
+}
+
+// ------------------------------------------------------------------------
+
+OUString SAL_CALL X11Clipboard::getName()
+ throw(RuntimeException)
+{
+ return m_rSelectionManager.getString( m_aSelection );
+}
+
+// ------------------------------------------------------------------------
+
+sal_Int8 SAL_CALL X11Clipboard::getRenderingCapabilities()
+ throw(RuntimeException)
+{
+ return RenderingCapabilities::Delayed;
+}
+
+
+// ------------------------------------------------------------------------
+void SAL_CALL X11Clipboard::addClipboardListener( const Reference< XClipboardListener >& listener )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( m_rSelectionManager.getMutex() );
+ m_aListeners.push_back( listener );
+}
+
+// ------------------------------------------------------------------------
+
+void SAL_CALL X11Clipboard::removeClipboardListener( const Reference< XClipboardListener >& listener )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( m_rSelectionManager.getMutex() );
+ m_aListeners.remove( listener );
+}
+
+
+// ------------------------------------------------------------------------
+
+Reference< XTransferable > X11Clipboard::getTransferable()
+{
+ return getContents();
+}
+
+// ------------------------------------------------------------------------
+
+void X11Clipboard::clearTransferable()
+{
+ clearContents();
+}
+
+// ------------------------------------------------------------------------
+
+void X11Clipboard::fireContentsChanged()
+{
+ fireChangedContentsEvent();
+}
+
+// ------------------------------------------------------------------------
+
+Reference< XInterface > X11Clipboard::getReference() throw()
+{
+ return Reference< XInterface >( static_cast< OWeakObject* >(this) );
+}
+
+// ------------------------------------------------------------------------
+
+OUString SAL_CALL X11Clipboard::getImplementationName( )
+ throw(RuntimeException)
+{
+ return OUString::createFromAscii(X11_CLIPBOARD_IMPLEMENTATION_NAME);
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool SAL_CALL X11Clipboard::supportsService( const OUString& ServiceName )
+ throw(RuntimeException)
+{
+ Sequence < OUString > SupportedServicesNames = X11Clipboard_getSupportedServiceNames();
+
+ for ( sal_Int32 n = SupportedServicesNames.getLength(); n--; )
+ if (SupportedServicesNames[n].compareTo(ServiceName) == 0)
+ return sal_True;
+
+ return sal_False;
+}
+
+// ------------------------------------------------------------------------
+
+void SAL_CALL X11Clipboard::initialize( const Sequence< Any >& ) throw( ::com::sun::star::uno::Exception )
+{
+}
+
+// ------------------------------------------------------------------------
+
+Sequence< OUString > SAL_CALL X11Clipboard::getSupportedServiceNames( )
+ throw(RuntimeException)
+{
+ return X11Clipboard_getSupportedServiceNames();
+}
+
diff --git a/vcl/unx/source/dtrans/X11_clipboard.hxx b/vcl/unx/source/dtrans/X11_clipboard.hxx
new file mode 100644
index 000000000000..21bf547a9cb7
--- /dev/null
+++ b/vcl/unx/source/dtrans/X11_clipboard.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _DTRANS_X11_CLIPBOARD_HXX_
+#define _DTRANS_X11_CLIPBOARD_HXX_
+
+#include <X11_selection.hxx>
+
+#ifndef _COM_SUN_STAR_DATATRANSFER_CLIPBAORD_XCLIPBOARDEX_HPP_
+#include <com/sun/star/datatransfer/clipboard/XClipboardEx.hpp>
+#endif
+
+#ifndef _COM_SUN_STAR_DATATRANSFER_CLIPBAORD_XCLIPBOARDNOTIFIER_HPP_
+#include <com/sun/star/datatransfer/clipboard/XClipboardNotifier.hpp>
+#endif
+#include <cppuhelper/compbase4.hxx>
+
+// ------------------------------------------------------------------------
+
+#define X11_CLIPBOARD_IMPLEMENTATION_NAME "com.sun.star.datatransfer.X11ClipboardSupport"
+
+namespace x11 {
+
+ class X11Clipboard :
+ public ::cppu::WeakComponentImplHelper4 <
+ ::com::sun::star::datatransfer::clipboard::XClipboardEx,
+ ::com::sun::star::datatransfer::clipboard::XClipboardNotifier,
+ ::com::sun::star::lang::XServiceInfo,
+ ::com::sun::star::lang::XInitialization
+ >,
+ public SelectionAdaptor
+ {
+ Reference< ::com::sun::star::datatransfer::XTransferable > m_aContents;
+ Reference< ::com::sun::star::datatransfer::clipboard::XClipboardOwner > m_aOwner;
+
+ SelectionManager& m_rSelectionManager;
+ Reference< ::com::sun::star::lang::XInitialization > m_xSelectionManager;
+ ::std::list< Reference< ::com::sun::star::datatransfer::clipboard::XClipboardListener > > m_aListeners;
+ Atom m_aSelection;
+
+ protected:
+
+
+ friend class SelectionManager;
+ friend class X11_Transferable;
+
+ void fireChangedContentsEvent();
+ void clearContents();
+
+ public:
+
+ X11Clipboard( SelectionManager& rManager, Atom aSelection );
+ virtual ~X11Clipboard();
+
+ static X11Clipboard* get( const ::rtl::OUString& rDisplayName, Atom aSelection );
+
+ /*
+ * XInitialization
+ */
+ virtual void SAL_CALL initialize( const Sequence< Any >& arguments ) throw( ::com::sun::star::uno::Exception );
+
+ /*
+ * 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);
+
+ /*
+ * 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);
+
+ /*
+ * SelectionAdaptor
+ */
+ virtual Reference< ::com::sun::star::datatransfer::XTransferable > getTransferable();
+ virtual void clearTransferable();
+ virtual void fireContentsChanged();
+ virtual Reference< XInterface > getReference() throw();
+ };
+
+// ------------------------------------------------------------------------
+
+ Sequence< ::rtl::OUString > SAL_CALL X11Clipboard_getSupportedServiceNames();
+ Reference< XInterface > SAL_CALL X11Clipboard_createInstance(
+ const Reference< ::com::sun::star::lang::XMultiServiceFactory > & xMultiServiceFactory);
+
+// ------------------------------------------------------------------------
+
+} // namepspace
+
+#endif
diff --git a/vcl/unx/source/dtrans/X11_dndcontext.cxx b/vcl/unx/source/dtrans/X11_dndcontext.cxx
new file mode 100644
index 000000000000..e6fc3dd8a532
--- /dev/null
+++ b/vcl/unx/source/dtrans/X11_dndcontext.cxx
@@ -0,0 +1,138 @@
+/*************************************************************************
+ *
+ * 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 <X11_dndcontext.hxx>
+#include <X11_selection.hxx>
+
+using namespace cppu;
+using namespace x11;
+
+/*
+ * DropTargetDropContext
+ */
+
+DropTargetDropContext::DropTargetDropContext(
+ XLIB_Window aDropWindow,
+ XLIB_Time aTimestamp,
+ SelectionManager& rManager ) :
+ m_aDropWindow( aDropWindow ),
+ m_nTimestamp( aTimestamp ),
+ m_rManager( rManager ),
+ m_xManagerRef( static_cast< OWeakObject* >(&rManager) )
+{
+}
+
+DropTargetDropContext::~DropTargetDropContext()
+{
+}
+
+void DropTargetDropContext::acceptDrop( sal_Int8 dragOperation ) throw()
+{
+ m_rManager.accept( dragOperation, m_aDropWindow, m_nTimestamp );
+}
+
+void DropTargetDropContext::rejectDrop() throw()
+{
+ m_rManager.reject( m_aDropWindow, m_nTimestamp );
+}
+
+void DropTargetDropContext::dropComplete( sal_Bool success ) throw()
+{
+ m_rManager.dropComplete( success, m_aDropWindow, m_nTimestamp );
+}
+
+
+/*
+ * DropTargetDragContext
+ */
+
+DropTargetDragContext::DropTargetDragContext(
+ XLIB_Window aDropWindow,
+ XLIB_Time aTimestamp,
+ SelectionManager& rManager ) :
+ m_aDropWindow( aDropWindow ),
+ m_nTimestamp( aTimestamp ),
+ m_rManager( rManager ),
+ m_xManagerRef( static_cast< OWeakObject* >(&rManager) )
+{
+}
+
+DropTargetDragContext::~DropTargetDragContext()
+{
+}
+
+void DropTargetDragContext::acceptDrag( sal_Int8 dragOperation ) throw()
+{
+ m_rManager.accept( dragOperation, m_aDropWindow, m_nTimestamp );
+}
+
+void DropTargetDragContext::rejectDrag() throw()
+{
+ m_rManager.reject( m_aDropWindow, m_nTimestamp );
+}
+
+/*
+ * DragSourceContext
+ */
+
+DragSourceContext::DragSourceContext(
+ XLIB_Window aDropWindow,
+ XLIB_Time aTimestamp,
+ SelectionManager& rManager ) :
+ m_aDropWindow( aDropWindow ),
+ m_nTimestamp( aTimestamp ),
+ m_rManager( rManager ),
+ m_xManagerRef( static_cast< OWeakObject* >(&rManager) )
+{
+}
+
+DragSourceContext::~DragSourceContext()
+{
+}
+
+sal_Int32 DragSourceContext::getCurrentCursor() throw()
+{
+ return m_rManager.getCurrentCursor();
+}
+
+void DragSourceContext::setCursor( sal_Int32 cursorId ) throw()
+{
+ m_rManager.setCursor( cursorId, m_aDropWindow, m_nTimestamp );
+}
+
+void DragSourceContext::setImage( sal_Int32 imageId ) throw()
+{
+ m_rManager.setImage( imageId, m_aDropWindow, m_nTimestamp );
+}
+
+void DragSourceContext::transferablesFlavorsChanged() throw()
+{
+ m_rManager.transferablesFlavorsChanged();
+}
diff --git a/vcl/unx/source/dtrans/X11_dndcontext.hxx b/vcl/unx/source/dtrans/X11_dndcontext.hxx
new file mode 100644
index 000000000000..9b48d346f03b
--- /dev/null
+++ b/vcl/unx/source/dtrans/X11_dndcontext.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _DTRANS_X11_DNDCONTEXT_HXX
+#define _DTRANS_X11_DNDCONTEXT_HXX
+
+#include <com/sun/star/datatransfer/dnd/XDragSourceContext.hpp>
+#include <com/sun/star/datatransfer/dnd/XDropTargetDropContext.hpp>
+#include <com/sun/star/datatransfer/dnd/XDropTargetDragContext.hpp>
+#include <cppuhelper/implbase1.hxx>
+
+#include "tools/prex.h"
+#include <X11/Xlib.h>
+#include "tools/postx.h"
+
+using namespace com::sun::star::uno;
+
+namespace x11 {
+
+ class SelectionManager;
+
+ class DropTargetDropContext :
+ public ::cppu::WeakImplHelper1<
+ ::com::sun::star::datatransfer::dnd::XDropTargetDropContext
+ >
+ {
+ XLIB_Window m_aDropWindow;
+ XLIB_Time m_nTimestamp;
+ SelectionManager& m_rManager;
+ Reference< XInterface > m_xManagerRef;
+ public:
+ DropTargetDropContext( XLIB_Window, XLIB_Time, SelectionManager& );
+ virtual ~DropTargetDropContext();
+
+ // XDropTargetDropContext
+ virtual void SAL_CALL acceptDrop( sal_Int8 dragOperation ) throw();
+ virtual void SAL_CALL rejectDrop() throw();
+ virtual void SAL_CALL dropComplete( sal_Bool success ) throw();
+ };
+
+ class DropTargetDragContext :
+ public ::cppu::WeakImplHelper1<
+ ::com::sun::star::datatransfer::dnd::XDropTargetDragContext
+ >
+ {
+ XLIB_Window m_aDropWindow;
+ XLIB_Time m_nTimestamp;
+ SelectionManager& m_rManager;
+ Reference< XInterface > m_xManagerRef;
+ public:
+ DropTargetDragContext( XLIB_Window, XLIB_Time, SelectionManager& );
+ virtual ~DropTargetDragContext();
+
+ // XDropTargetDragContext
+ virtual void SAL_CALL acceptDrag( sal_Int8 dragOperation ) throw();
+ virtual void SAL_CALL rejectDrag() throw();
+ };
+
+ class DragSourceContext :
+ public ::cppu::WeakImplHelper1<
+ ::com::sun::star::datatransfer::dnd::XDragSourceContext
+ >
+ {
+ XLIB_Window m_aDropWindow;
+ XLIB_Time m_nTimestamp;
+ SelectionManager& m_rManager;
+ Reference< XInterface > m_xManagerRef;
+ public:
+ DragSourceContext( XLIB_Window, XLIB_Time, SelectionManager& );
+ virtual ~DragSourceContext();
+
+ // XDragSourceContext
+ virtual sal_Int32 SAL_CALL getCurrentCursor() throw();
+ virtual void SAL_CALL setCursor( sal_Int32 cursorId ) throw();
+ virtual void SAL_CALL setImage( sal_Int32 imageId ) throw();
+ virtual void SAL_CALL transferablesFlavorsChanged() throw();
+ };
+} // namespace
+
+#endif // _DTRANS_X11_DNDCONTEXT_HXX
diff --git a/vcl/unx/source/dtrans/X11_droptarget.cxx b/vcl/unx/source/dtrans/X11_droptarget.cxx
new file mode 100644
index 000000000000..5db23329abd8
--- /dev/null
+++ b/vcl/unx/source/dtrans/X11_droptarget.cxx
@@ -0,0 +1,228 @@
+/*************************************************************************
+ *
+ * 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 <X11_selection.hxx>
+
+using namespace x11;
+using namespace rtl;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::awt;
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::datatransfer::dnd;
+
+DropTarget::DropTarget() :
+ ::cppu::WeakComponentImplHelper3<
+ XDropTarget,
+ XInitialization,
+ XServiceInfo
+ >( m_aMutex ),
+ m_bActive( false ),
+ m_nDefaultActions( 0 ),
+ m_aTargetWindow( None ),
+ m_pSelectionManager( NULL )
+{
+}
+
+DropTarget::~DropTarget()
+{
+ if( m_pSelectionManager )
+ m_pSelectionManager->deregisterDropTarget( m_aTargetWindow );
+}
+
+// --------------------------------------------------------------------------
+
+void DropTarget::initialize( const Sequence< Any >& arguments ) throw( ::com::sun::star::uno::Exception )
+{
+ if( arguments.getLength() > 1 )
+ {
+ OUString aDisplayName;
+ Reference< XDisplayConnection > xConn;
+ arguments.getConstArray()[0] >>= xConn;
+ if( xConn.is() )
+ {
+ Any aIdentifier;
+ aIdentifier >>= aDisplayName;
+ }
+
+ m_pSelectionManager = &SelectionManager::get( aDisplayName );
+ m_xSelectionManager = static_cast< XDragSource* >(m_pSelectionManager);
+ m_pSelectionManager->initialize( arguments );
+
+ if( m_pSelectionManager->getDisplay() ) // #136582# sanity check
+ {
+ sal_Size aWindow = None;
+ arguments.getConstArray()[1] >>= aWindow;
+ m_pSelectionManager->registerDropTarget( aWindow, this );
+ m_aTargetWindow = aWindow;
+ m_bActive = true;
+ }
+ }
+}
+
+// --------------------------------------------------------------------------
+
+void DropTarget::addDropTargetListener( const Reference< XDropTargetListener >& xListener ) throw()
+{
+ ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex );
+
+ m_aListeners.push_back( xListener );
+}
+
+// --------------------------------------------------------------------------
+
+void DropTarget::removeDropTargetListener( const Reference< XDropTargetListener >& xListener ) throw()
+{
+ ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex );
+
+ m_aListeners.remove( xListener );
+}
+
+// --------------------------------------------------------------------------
+
+sal_Bool DropTarget::isActive() throw()
+{
+ return m_bActive;
+}
+
+// --------------------------------------------------------------------------
+
+void DropTarget::setActive( sal_Bool active ) throw()
+{
+ ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex );
+
+ m_bActive = active;
+}
+
+// --------------------------------------------------------------------------
+
+sal_Int8 DropTarget::getDefaultActions() throw()
+{
+ return m_nDefaultActions;
+}
+
+// --------------------------------------------------------------------------
+
+void DropTarget::setDefaultActions( sal_Int8 actions ) throw()
+{
+ ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex );
+
+ m_nDefaultActions = actions;
+}
+
+// --------------------------------------------------------------------------
+
+void DropTarget::drop( const DropTargetDropEvent& dtde ) throw()
+{
+ osl::ClearableGuard< ::osl::Mutex > aGuard( m_aMutex );
+ std::list< Reference< XDropTargetListener > > aListeners( m_aListeners );
+ aGuard.clear();
+
+ for( std::list< Reference< XDropTargetListener > >::iterator it = aListeners.begin(); it!= aListeners.end(); ++it )
+ {
+ (*it)->drop( dtde );
+ }
+}
+
+// --------------------------------------------------------------------------
+
+void DropTarget::dragEnter( const DropTargetDragEnterEvent& dtde ) throw()
+{
+ osl::ClearableGuard< ::osl::Mutex > aGuard( m_aMutex );
+ std::list< Reference< XDropTargetListener > > aListeners( m_aListeners );
+ aGuard.clear();
+
+ for( std::list< Reference< XDropTargetListener > >::iterator it = aListeners.begin(); it!= aListeners.end(); ++it )
+ {
+ (*it)->dragEnter( dtde );
+ }
+}
+
+// --------------------------------------------------------------------------
+
+void DropTarget::dragExit( const DropTargetEvent& dte ) throw()
+{
+ osl::ClearableGuard< ::osl::Mutex > aGuard( m_aMutex );
+ std::list< Reference< XDropTargetListener > > aListeners( m_aListeners );
+ aGuard.clear();
+
+ for( std::list< Reference< XDropTargetListener > >::iterator it = aListeners.begin(); it!= aListeners.end(); ++it )
+ {
+ (*it)->dragExit( dte );
+ }
+}
+
+// --------------------------------------------------------------------------
+
+void DropTarget::dragOver( const DropTargetDragEvent& dtde ) throw()
+{
+ osl::ClearableGuard< ::osl::Mutex > aGuard( m_aMutex );
+ std::list< Reference< XDropTargetListener > > aListeners( m_aListeners );
+ aGuard.clear();
+
+ for( std::list< Reference< XDropTargetListener > >::iterator it = aListeners.begin(); it!= aListeners.end(); ++it )
+ {
+ (*it)->dragOver( dtde );
+ }
+}
+
+// --------------------------------------------------------------------------
+
+/*
+ * XServiceInfo
+ */
+
+// ------------------------------------------------------------------------
+
+OUString DropTarget::getImplementationName() throw()
+{
+ return OUString::createFromAscii(XDND_DROPTARGET_IMPLEMENTATION_NAME);
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool DropTarget::supportsService( const OUString& ServiceName ) throw()
+{
+ Sequence < OUString > SupportedServicesNames = Xdnd_dropTarget_getSupportedServiceNames();
+
+ for ( sal_Int32 n = SupportedServicesNames.getLength(); n--; )
+ if (SupportedServicesNames[n].compareTo(ServiceName) == 0)
+ return sal_True;
+
+ return sal_False;
+}
+
+// ------------------------------------------------------------------------
+
+Sequence< OUString > DropTarget::getSupportedServiceNames() throw()
+{
+ return Xdnd_dropTarget_getSupportedServiceNames();
+}
+
+
diff --git a/vcl/unx/source/dtrans/X11_selection.cxx b/vcl/unx/source/dtrans/X11_selection.cxx
new file mode 100644
index 000000000000..7f205407b21b
--- /dev/null
+++ b/vcl/unx/source/dtrans/X11_selection.cxx
@@ -0,0 +1,4129 @@
+/*************************************************************************
+ *
+ * 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 <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include "tools/prex.h"
+#include <X11/Xatom.h>
+#include <X11/keysym.h>
+#include <X11/Xlib.h>
+#include <X11/X.h>
+#include <X11/Xutil.h>
+#include "tools/postx.h"
+#if defined(LINUX) || defined(NETBSD) || defined (FREEBSD)
+#include <sys/poll.h>
+#else
+#include <poll.h>
+#endif
+#include <sal/alloca.h>
+
+#include <X11_selection.hxx>
+#include <X11_clipboard.hxx>
+#include <X11_transferable.hxx>
+#include <X11_dndcontext.hxx>
+#include <bmp.hxx>
+
+#include "vcl/svapp.hxx"
+
+// pointer bitmaps
+#include <copydata_curs.h>
+#include <copydata_mask.h>
+#include <movedata_curs.h>
+#include <movedata_mask.h>
+#include <linkdata_curs.h>
+#include <linkdata_mask.h>
+#include <nodrop_curs.h>
+#include <nodrop_mask.h>
+#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
+#include <com/sun/star/awt/MouseEvent.hpp>
+#include <com/sun/star/awt/MouseButton.hpp>
+#include <rtl/tencinfo.h>
+#include <osl/process.h>
+
+#include <comphelper/processfactory.hxx>
+#include <vos/mutex.hxx>
+
+#define DRAG_EVENT_MASK ButtonPressMask |\
+ ButtonReleaseMask |\
+ PointerMotionMask |\
+ EnterWindowMask |\
+ LeaveWindowMask
+
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::datatransfer::dnd;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::awt;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::frame;
+using namespace cppu;
+using namespace osl;
+using namespace rtl;
+
+using namespace x11;
+
+// stubs to satisfy solaris compiler's rather rigid linking warning
+extern "C"
+{
+ static void call_SelectionManager_run( void * pMgr )
+ {
+ SelectionManager::run( pMgr );
+ }
+
+ static void call_SelectionManager_runDragExecute( void * pMgr )
+ {
+ SelectionManager::runDragExecute( pMgr );
+ }
+}
+
+
+static const long nXdndProtocolRevision = 5;
+
+// mapping between mime types (or what the office thinks of mime types)
+// and X convention types
+struct NativeTypeEntry
+{
+ Atom nAtom;
+ const char* pType; // Mime encoding on our side
+ const char* pNativeType; // string corresponding to nAtom for the case of nAtom being uninitialized
+ int nFormat; // the corresponding format
+};
+
+// the convention for Xdnd is mime types as specified by the corresponding
+// RFC's with the addition that text/plain without charset tag contains iso8859-1
+// sadly some applications (e.g. gtk) do not honor the mimetype only rule,
+// so for compatibility add UTF8_STRING
+static NativeTypeEntry aXdndConversionTab[] =
+{
+ { 0, "text/plain;charset=iso8859-1", "text/plain", 8 },
+ { 0, "text/plain;charset=utf-8", "UTF8_STRING", 8 }
+};
+
+// for clipboard and primary selections there is only a convention for text
+// that the encoding name of the text is taken as type in all capitalized letters
+static NativeTypeEntry aNativeConversionTab[] =
+{
+ { 0, "text/plain;charset=utf-16", "ISO10646-1", 16 },
+ { 0, "text/plain;charset=utf-8", "UTF8_STRING", 8 },
+ { 0, "text/plain;charset=utf-8", "UTF-8", 8 },
+ { 0, "text/plain;charset=utf-8", "text/plain;charset=UTF-8", 8 },
+ // ISO encodings
+ { 0, "text/plain;charset=iso8859-2", "ISO8859-2", 8 },
+ { 0, "text/plain;charset=iso8859-3", "ISO8859-3", 8 },
+ { 0, "text/plain;charset=iso8859-4", "ISO8859-4", 8 },
+ { 0, "text/plain;charset=iso8859-5", "ISO8859-5", 8 },
+ { 0, "text/plain;charset=iso8859-6", "ISO8859-6", 8 },
+ { 0, "text/plain;charset=iso8859-7", "ISO8859-7", 8 },
+ { 0, "text/plain;charset=iso8859-8", "ISO8859-8", 8 },
+ { 0, "text/plain;charset=iso8859-9", "ISO8859-9", 8 },
+ { 0, "text/plain;charset=iso8859-10", "ISO8859-10", 8 },
+ { 0, "text/plain;charset=iso8859-13", "ISO8859-13", 8 },
+ { 0, "text/plain;charset=iso8859-14", "ISO8859-14", 8 },
+ { 0, "text/plain;charset=iso8859-15", "ISO8859-15", 8 },
+ // asian encodings
+ { 0, "text/plain;charset=jisx0201.1976-0", "JISX0201.1976-0", 8 },
+ { 0, "text/plain;charset=jisx0208.1983-0", "JISX0208.1983-0", 8 },
+ { 0, "text/plain;charset=jisx0208.1990-0", "JISX0208.1990-0", 8 },
+ { 0, "text/plain;charset=jisx0212.1990-0", "JISX0212.1990-0", 8 },
+ { 0, "text/plain;charset=gb2312.1980-0", "GB2312.1980-0", 8 },
+ { 0, "text/plain;charset=ksc5601.1992-0", "KSC5601.1992-0", 8 },
+ // eastern european encodings
+ { 0, "text/plain;charset=koi8-r", "KOI8-R", 8 },
+ { 0, "text/plain;charset=koi8-u", "KOI8-U", 8 },
+ // String (== iso8859-1)
+ { XA_STRING, "text/plain;charset=iso8859-1", "STRING", 8 },
+ // special for compound text
+ { 0, "text/plain;charset=compound_text", "COMPOUND_TEXT", 8 },
+
+ // PIXMAP
+ { XA_PIXMAP, "image/bmp", "PIXMAP", 32 }
+};
+
+rtl_TextEncoding x11::getTextPlainEncoding( const OUString& rMimeType )
+{
+ rtl_TextEncoding aEncoding = RTL_TEXTENCODING_DONTKNOW;
+ OUString aMimeType( rMimeType.toAsciiLowerCase() );
+ sal_Int32 nIndex = 0;
+ if( aMimeType.getToken( 0, ';', nIndex ).equalsAsciiL( "text/plain" , 10 ) )
+ {
+ if( aMimeType.getLength() == 10 ) // only "text/plain"
+ aEncoding = RTL_TEXTENCODING_ISO_8859_1;
+ else
+ {
+ while( nIndex != -1 )
+ {
+ OUString aToken = aMimeType.getToken( 0, ';', nIndex );
+ sal_Int32 nPos = 0;
+ if( aToken.getToken( 0, '=', nPos ).equalsAsciiL( "charset", 7 ) )
+ {
+ OString aEncToken = OUStringToOString( aToken.getToken( 0, '=', nPos ), RTL_TEXTENCODING_ISO_8859_1 );
+ aEncoding = rtl_getTextEncodingFromUnixCharset( aEncToken.getStr() );
+ if( aEncoding == RTL_TEXTENCODING_DONTKNOW )
+ {
+ if( aEncToken.equalsIgnoreAsciiCase( "utf-8" ) )
+ aEncoding = RTL_TEXTENCODING_UTF8;
+ }
+ if( aEncoding != RTL_TEXTENCODING_DONTKNOW )
+ break;
+ }
+ }
+ }
+ }
+#if OSL_DEBUG_LEVEL > 1
+ if( aEncoding == RTL_TEXTENCODING_DONTKNOW )
+ fprintf( stderr, "getTextPlainEncoding( %s ) failed\n", OUStringToOString( rMimeType, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+ return aEncoding;
+}
+
+// ------------------------------------------------------------------------
+
+::std::hash_map< OUString, SelectionManager*, OUStringHash >& SelectionManager::getInstances()
+{
+ static ::std::hash_map< OUString, SelectionManager*, OUStringHash > aInstances;
+ return aInstances;
+}
+
+// ------------------------------------------------------------------------
+
+SelectionManager::SelectionManager() :
+ m_nIncrementalThreshold( 15*1024 ),
+ m_pDisplay( NULL ),
+ m_aThread( NULL ),
+ m_aDragExecuteThread( NULL ),
+ m_aWindow( None ),
+ m_nSelectionTimeout( 0 ),
+ m_nSelectionTimestamp( CurrentTime ),
+ m_bDropEnterSent( true ),
+ m_aCurrentDropWindow( None ),
+ m_nDropTime( None ),
+ m_nLastDropAction( 0 ),
+ m_nLastX( 0 ),
+ m_nLastY( 0 ),
+ m_nDropTimestamp( 0 ),
+ m_bDropWaitingForCompletion( false ),
+ m_aDropWindow( None ),
+ m_aDropProxy( None ),
+ m_aDragSourceWindow( None ),
+ m_nLastDragX( 0 ),
+ m_nLastDragY( 0 ),
+ m_nNoPosX( 0 ),
+ m_nNoPosY( 0 ),
+ m_nNoPosWidth( 0 ),
+ m_nNoPosHeight( 0 ),
+ m_nDragButton( 0 ),
+ m_nUserDragAction( 0 ),
+ m_nTargetAcceptAction( 0 ),
+ m_nSourceActions( 0 ),
+ m_bLastDropAccepted( false ),
+ m_bDropSuccess( false ),
+ m_bDropSent( false ),
+ m_bWaitingForPrimaryConversion( false ),
+ m_nDragTimestamp( None ),
+ m_aMoveCursor( None ),
+ m_aCopyCursor( None ),
+ m_aLinkCursor( None ),
+ m_aNoneCursor( None ),
+ m_aCurrentCursor( None ),
+ m_nCurrentProtocolVersion( nXdndProtocolRevision ),
+ m_nCLIPBOARDAtom( None ),
+ m_nTARGETSAtom( None ),
+ m_nTIMESTAMPAtom( None ),
+ m_nTEXTAtom( None ),
+ m_nINCRAtom( None ),
+ m_nCOMPOUNDAtom( None ),
+ m_nMULTIPLEAtom( None ),
+ m_nUTF16Atom( None ),
+ m_nImageBmpAtom( None ),
+ m_nXdndAware( None ),
+ m_nXdndEnter( None ),
+ m_nXdndLeave( None ),
+ m_nXdndPosition( None ),
+ m_nXdndStatus( None ),
+ m_nXdndDrop( None ),
+ m_nXdndFinished( None ),
+ m_nXdndSelection( None ),
+ m_nXdndTypeList( None ),
+ m_nXdndProxy( None ),
+ m_nXdndActionCopy( None ),
+ m_nXdndActionMove( None ),
+ m_nXdndActionLink( None ),
+ m_nXdndActionAsk( None ),
+ m_nXdndActionPrivate( None )
+{
+ m_aDropEnterEvent.data.l[0] = None;
+ m_aDragRunning.reset();
+}
+
+XLIB_Cursor SelectionManager::createCursor( const char* pPointerData, const char* pMaskData, int width, int height, int hotX, int hotY )
+{
+ Pixmap aPointer;
+ Pixmap aMask;
+ XColor aBlack, aWhite;
+
+ aBlack.pixel = BlackPixel( m_pDisplay, 0 );
+ aBlack.red = aBlack.green = aBlack.blue = 0;
+ aBlack.flags = DoRed | DoGreen | DoBlue;
+
+ aWhite.pixel = WhitePixel( m_pDisplay, 0 );
+ aWhite.red = aWhite.green = aWhite.blue = 0xffff;
+ aWhite.flags = DoRed | DoGreen | DoBlue;
+
+ aPointer =
+ XCreateBitmapFromData( m_pDisplay,
+ m_aWindow,
+ pPointerData,
+ width,
+ height );
+ aMask
+ = XCreateBitmapFromData( m_pDisplay,
+ m_aWindow,
+ pMaskData,
+ width,
+ height );
+ XLIB_Cursor aCursor =
+ XCreatePixmapCursor( m_pDisplay, aPointer, aMask,
+ &aBlack, &aWhite,
+ hotX,
+ hotY );
+ XFreePixmap( m_pDisplay, aPointer );
+ XFreePixmap( m_pDisplay, aMask );
+
+ return aCursor;
+}
+
+void SelectionManager::initialize( const Sequence< Any >& arguments ) throw (::com::sun::star::uno::Exception)
+{
+ MutexGuard aGuard(m_aMutex);
+
+ if( ! m_xDisplayConnection.is() )
+ {
+ /*
+ * first argument must be a ::com::sun::star::awt::XDisplayConnection
+ * from this we will get the XEvents of the vcl event loop by
+ * registering us as XEventHandler on it.
+ *
+ * implementor's note:
+ * FIXME:
+ * finally the clipboard and XDND service is back in the module it belongs
+ * now cleanup and sharing of resources with the normal vcl event loop
+ * needs to be added. The display used whould be that of the normal event loop
+ * and synchronization should be done via the SolarMutex.
+ */
+ if( arguments.getLength() > 0 )
+ arguments.getConstArray()[0] >>= m_xDisplayConnection;
+ if( ! m_xDisplayConnection.is() )
+ {
+#if 0
+ // for the time being try to live without XDisplayConnection
+ // for the sake of clipboard service
+ // clipboard service should be initialized with a XDisplayConnection
+ // in the future
+ Exception aExc;
+ aExc.Message = OUString::createFromAscii( "initialize me with a valid XDisplayConnection" );
+ aExc.Context = static_cast< OWeakObject* >(this);
+ throw aExc;
+#endif
+ }
+ else
+ m_xDisplayConnection->addEventHandler( Any(), this, ~0 );
+ }
+
+ if( !m_xBitmapConverter.is() )
+ {
+ if( arguments.getLength() > 2 )
+ arguments.getConstArray()[2] >>= m_xBitmapConverter;
+ }
+
+ OUString aParam;
+ if( ! m_pDisplay )
+ {
+ OUString aUDisplay;
+ if( m_xDisplayConnection.is() )
+ {
+ Any aIdentifier;
+ aIdentifier = m_xDisplayConnection->getIdentifier();
+ aIdentifier >>= aUDisplay;
+ }
+
+ OString aDisplayName( OUStringToOString( aUDisplay, RTL_TEXTENCODING_ISO_8859_1 ) );
+
+ m_pDisplay = XOpenDisplay( aDisplayName.getLength() ? aDisplayName.getStr() : NULL );
+
+ if( m_pDisplay )
+ {
+#ifdef SYNCHRONIZE
+ XSynchronize( m_pDisplay, True );
+#endif
+ // clipboard selection
+ m_nCLIPBOARDAtom = getAtom( OUString::createFromAscii( "CLIPBOARD" ) );
+
+ // special targets
+ m_nTARGETSAtom = getAtom( OUString::createFromAscii( "TARGETS" ) );
+ m_nTIMESTAMPAtom = getAtom( OUString::createFromAscii( "TIMESTAMP" ) );
+ m_nTEXTAtom = getAtom( OUString::createFromAscii( "TEXT" ) );
+ m_nINCRAtom = getAtom( OUString::createFromAscii( "INCR" ) );
+ m_nCOMPOUNDAtom = getAtom( OUString::createFromAscii( "COMPOUND_TEXT" ) );
+ m_nMULTIPLEAtom = getAtom( OUString::createFromAscii( "MULTIPLE" ) );
+ m_nUTF16Atom = getAtom( OUString::createFromAscii( "ISO10646-1" ) );
+// m_nUTF16Atom = getAtom( OUString::createFromAscii( "text/plain;charset=ISO-10646-UCS-2" ) );
+ m_nImageBmpAtom = getAtom( OUString::createFromAscii( "image/bmp" ) );
+
+ // Atoms for Xdnd protocol
+ m_nXdndAware = getAtom( OUString::createFromAscii( "XdndAware" ) );
+ m_nXdndEnter = getAtom( OUString::createFromAscii( "XdndEnter" ) );
+ m_nXdndLeave = getAtom( OUString::createFromAscii( "XdndLeave" ) );
+ m_nXdndPosition = getAtom( OUString::createFromAscii( "XdndPosition" ) );
+ m_nXdndStatus = getAtom( OUString::createFromAscii( "XdndStatus" ) );
+ m_nXdndDrop = getAtom( OUString::createFromAscii( "XdndDrop" ) );
+ m_nXdndFinished = getAtom( OUString::createFromAscii( "XdndFinished" ) );
+ m_nXdndSelection = getAtom( OUString::createFromAscii( "XdndSelection" ) );
+ m_nXdndTypeList = getAtom( OUString::createFromAscii( "XdndTypeList" ) );
+ m_nXdndProxy = getAtom( OUString::createFromAscii( "XdndProxy" ) );
+ m_nXdndActionCopy = getAtom( OUString::createFromAscii( "XdndActionCopy" ) );
+ m_nXdndActionMove = getAtom( OUString::createFromAscii( "XdndActionMove" ) );
+ m_nXdndActionLink = getAtom( OUString::createFromAscii( "XdndActionLink" ) );
+ m_nXdndActionAsk = getAtom( OUString::createFromAscii( "XdndActionAsk" ) );
+ m_nXdndActionPrivate= getAtom( OUString::createFromAscii( "XdndActionPrivate" ) );
+
+ // initialize map with member none
+ m_aAtomToString[ 0 ]= OUString::createFromAscii( "None" );
+ m_aAtomToString[ XA_PRIMARY ] = OUString::createFromAscii( "PRIMARY" );
+
+ // create a (invisible) message window
+ m_aWindow = XCreateSimpleWindow( m_pDisplay, DefaultRootWindow( m_pDisplay ),
+ 10, 10, 10, 10, 0, 0, 1 );
+
+ // initialize threshold for incremetal transfers
+ // ICCCM says it should be smaller that the max request size
+ // which in turn is guaranteed to be at least 16k bytes
+ m_nIncrementalThreshold = XMaxRequestSize( m_pDisplay ) - 1024;
+
+ if( m_aWindow )
+ {
+ // initialize default cursors
+ m_aMoveCursor = createCursor( movedata_curs_bits,
+ movedata_mask_bits,
+ movedata_curs_width,
+ movedata_curs_height,
+ movedata_curs_x_hot,
+ movedata_curs_y_hot );
+ m_aCopyCursor = createCursor( copydata_curs_bits,
+ copydata_mask_bits,
+ copydata_curs_width,
+ copydata_curs_height,
+ copydata_curs_x_hot,
+ copydata_curs_y_hot );
+ m_aLinkCursor = createCursor( linkdata_curs_bits,
+ linkdata_mask_bits,
+ linkdata_curs_width,
+ linkdata_curs_height,
+ linkdata_curs_x_hot,
+ linkdata_curs_y_hot );
+ m_aNoneCursor = createCursor( nodrop_curs_bits,
+ nodrop_mask_bits,
+ nodrop_curs_width,
+ nodrop_curs_height,
+ nodrop_curs_x_hot,
+ nodrop_curs_y_hot );
+
+
+
+
+ // just interested in SelectionClear/Notify/Request and PropertyChange
+ XSelectInput( m_pDisplay, m_aWindow, PropertyChangeMask );
+ // create the transferable for Drag operations
+ m_xDropTransferable = new X11Transferable( *this, static_cast< OWeakObject* >(this), m_nXdndSelection );
+ registerHandler( m_nXdndSelection, *this );
+
+ m_aThread = osl_createSuspendedThread( call_SelectionManager_run, this );
+ if( m_aThread )
+ osl_resumeThread( m_aThread );
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "SelectionManager::initialize: creation of dispatch thread failed !\n" );
+#endif
+ }
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+SelectionManager::~SelectionManager()
+{
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "SelectionManager::~SelectionManager (%s)\n", m_pDisplay ? DisplayString(m_pDisplay) : "no display" );
+#endif
+ {
+ MutexGuard aGuard( *Mutex::getGlobalMutex() );
+
+ ::std::hash_map< OUString, SelectionManager*, OUStringHash >::iterator it;
+ for( it = getInstances().begin(); it != getInstances().end(); ++it )
+ if( it->second == this )
+ {
+ getInstances().erase( it );
+ break;
+ }
+ }
+
+ if( m_aThread )
+ {
+ osl_terminateThread( m_aThread );
+ osl_joinWithThread( m_aThread );
+ osl_destroyThread( m_aThread );
+ }
+
+ if( m_aDragExecuteThread )
+ {
+ osl_terminateThread( m_aDragExecuteThread );
+ osl_joinWithThread( m_aDragExecuteThread );
+ m_aDragExecuteThread = NULL;
+ // thread handle is freed in dragDoDispatch()
+ }
+
+ MutexGuard aGuard(m_aMutex);
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "shutting down SelectionManager\n" );
+#endif
+
+ if( m_xDisplayConnection.is() )
+ {
+ m_xDisplayConnection->removeEventHandler( Any(), this );
+ m_xDisplayConnection.clear();
+ }
+
+ if( m_pDisplay )
+ {
+ deregisterHandler( m_nXdndSelection );
+ // destroy message window
+ if( m_aWindow )
+ XDestroyWindow( m_pDisplay, m_aWindow );
+ // release cursors
+ if (m_aMoveCursor != None)
+ XFreeCursor(m_pDisplay, m_aMoveCursor);
+ if (m_aCopyCursor != None)
+ XFreeCursor(m_pDisplay, m_aCopyCursor);
+ if (m_aLinkCursor != None)
+ XFreeCursor(m_pDisplay, m_aLinkCursor);
+ if (m_aNoneCursor != None)
+ XFreeCursor(m_pDisplay, m_aNoneCursor);
+
+ // paranoia setting, the drag thread should have
+ // done that already
+ XUngrabPointer( m_pDisplay, CurrentTime );
+ XUngrabKeyboard( m_pDisplay, CurrentTime );
+
+ XCloseDisplay( m_pDisplay );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+SelectionAdaptor* SelectionManager::getAdaptor( Atom selection )
+{
+ ::std::hash_map< Atom, Selection* >::iterator it =
+ m_aSelections.find( selection );
+ return it != m_aSelections.end() ? it->second->m_pAdaptor : NULL;
+}
+
+// ------------------------------------------------------------------------
+
+OUString SelectionManager::convertFromCompound( const char* pText, int nLen )
+{
+ MutexGuard aGuard( m_aMutex );
+ OUString aRet;
+ if( nLen < 0 )
+ nLen = strlen( pText );
+
+ char** pTextList = NULL;
+ int nTexts = 0;
+
+ XTextProperty aProp;
+ aProp.value = (unsigned char*)pText;
+ aProp.encoding = m_nCOMPOUNDAtom;
+ aProp.format = 8;
+ aProp.nitems = nLen;
+ XmbTextPropertyToTextList( m_pDisplay,
+ &aProp,
+ &pTextList,
+ &nTexts );
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ for( int i = 0; i < nTexts; i++ )
+ aRet += OStringToOUString( pTextList[i], aEncoding );
+
+ if( pTextList )
+ XFreeStringList( pTextList );
+
+ return aRet;
+}
+
+// ------------------------------------------------------------------------
+
+OString SelectionManager::convertToCompound( const OUString& rText )
+{
+ MutexGuard aGuard( m_aMutex );
+ XTextProperty aProp;
+ aProp.value = NULL;
+ aProp.encoding = XA_STRING;
+ aProp.format = 8;
+ aProp.nitems = 0;
+
+ OString aRet( rText.getStr(), rText.getLength(), osl_getThreadTextEncoding() );
+ char* pT = const_cast<char*>(aRet.getStr());
+
+ XmbTextListToTextProperty( m_pDisplay,
+ &pT,
+ 1,
+ XCompoundTextStyle,
+ &aProp );
+ if( aProp.value )
+ {
+ aRet = (char*)aProp.value;
+ XFree( aProp.value );
+#ifdef SOLARIS
+ /* #97070#
+ * for currently unknown reasons XmbTextListToTextProperty on Solaris returns
+ * no data in ISO8859-n encodings (at least for n = 1, 15)
+ * in these encodings the directly converted text does the
+ * trick, also.
+ */
+ if( ! aRet.getLength() && rText.getLength() )
+ aRet = OUStringToOString( rText, osl_getThreadTextEncoding() );
+#endif
+ }
+ else
+ aRet = OString();
+
+ return aRet;
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::convertData(
+ const Reference< XTransferable >& xTransferable,
+ Atom nType,
+ Atom nSelection,
+ int& rFormat,
+ Sequence< sal_Int8 >& rData )
+{
+ bool bSuccess = false;
+
+ if( ! xTransferable.is() )
+ return bSuccess;
+
+ try
+ {
+
+ DataFlavor aFlavor;
+ aFlavor.MimeType = convertTypeFromNative( nType, nSelection, rFormat );
+
+ sal_Int32 nIndex = 0;
+ if( aFlavor.MimeType.getToken( 0, ';', nIndex ).compareToAscii( "text/plain" ) == 0 )
+ {
+ if( aFlavor.MimeType.getToken( 0, ';', nIndex ).compareToAscii( "charset=utf-16" ) == 0 )
+ aFlavor.DataType = getCppuType( (OUString *) 0 );
+ else
+ aFlavor.DataType = getCppuType( (Sequence< sal_Int8 >*)0 );
+ }
+ else
+ aFlavor.DataType = getCppuType( (Sequence< sal_Int8 >*)0 );
+
+ if( xTransferable->isDataFlavorSupported( aFlavor ) )
+ {
+ Any aValue( xTransferable->getTransferData( aFlavor ) );
+ if( aValue.getValueTypeClass() == TypeClass_STRING )
+ {
+ OUString aString;
+ aValue >>= aString;
+ rData = Sequence< sal_Int8 >( (sal_Int8*)aString.getStr(), aString.getLength() * sizeof( sal_Unicode ) );
+ bSuccess = true;
+ }
+ else if( aValue.getValueType() == getCppuType( (Sequence< sal_Int8 >*)0 ) )
+ {
+ aValue >>= rData;
+ bSuccess = true;
+ }
+ }
+ else if( aFlavor.MimeType.compareToAscii( "text/plain", 10 ) == 0 )
+ {
+ rtl_TextEncoding aEncoding = RTL_TEXTENCODING_DONTKNOW;
+ bool bCompoundText = false;
+ if( nType == m_nCOMPOUNDAtom )
+ bCompoundText = true;
+ else
+ aEncoding = getTextPlainEncoding( aFlavor.MimeType );
+ if( aEncoding != RTL_TEXTENCODING_DONTKNOW || bCompoundText )
+ {
+ aFlavor.MimeType = OUString::createFromAscii( "text/plain;charset=utf-16" );
+ aFlavor.DataType = getCppuType( (OUString *) 0 );
+ if( xTransferable->isDataFlavorSupported( aFlavor ) )
+ {
+ Any aValue( xTransferable->getTransferData( aFlavor ) );
+ OUString aString;
+ aValue >>= aString;
+ OString aByteString( bCompoundText ? convertToCompound( aString ) : OUStringToOString( aString, aEncoding ) );
+ rData = Sequence< sal_Int8 >( (sal_Int8*)aByteString.getStr(), aByteString.getLength() * sizeof( sal_Char ) );
+ bSuccess = true;
+ }
+ }
+ }
+ }
+ // various exceptions possible ... which all lead to a failed conversion
+ // so simplify here to a catch all
+ catch(...)
+ {
+ }
+
+ return bSuccess;
+}
+
+// ------------------------------------------------------------------------
+
+SelectionManager& SelectionManager::get( const OUString& rDisplayName )
+{
+ MutexGuard aGuard( *Mutex::getGlobalMutex() );
+
+ OUString aDisplayName( rDisplayName );
+ if( ! aDisplayName.getLength() )
+ aDisplayName = OStringToOUString( getenv( "DISPLAY" ), RTL_TEXTENCODING_ISO_8859_1 );
+ SelectionManager* pInstance = NULL;
+
+ ::std::hash_map< OUString, SelectionManager*, OUStringHash >::iterator it = getInstances().find( aDisplayName );
+ if( it != getInstances().end() )
+ pInstance = it->second;
+ else pInstance = getInstances()[ aDisplayName ] = new SelectionManager();
+
+ return *pInstance;
+}
+
+// ------------------------------------------------------------------------
+
+const OUString& SelectionManager::getString( Atom aAtom )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ ::std::hash_map< Atom, OUString >::const_iterator it;
+ if( ( it = m_aAtomToString.find( aAtom ) ) == m_aAtomToString.end() )
+ {
+ static OUString aEmpty;
+ char* pAtom = m_pDisplay ? XGetAtomName( m_pDisplay, aAtom ) : NULL;
+ if( ! pAtom )
+ return aEmpty;
+ OUString aString( OStringToOUString( pAtom, RTL_TEXTENCODING_ISO_8859_1 ) );
+ XFree( pAtom );
+ m_aStringToAtom[ aString ] = aAtom;
+ m_aAtomToString[ aAtom ] = aString;
+ }
+ return m_aAtomToString[ aAtom ];
+}
+
+// ------------------------------------------------------------------------
+
+Atom SelectionManager::getAtom( const OUString& rString )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ ::std::hash_map< OUString, Atom, OUStringHash >::const_iterator it;
+ if( ( it = m_aStringToAtom.find( rString ) ) == m_aStringToAtom.end() )
+ {
+ static Atom nNoDisplayAtoms = 1;
+ Atom aAtom = m_pDisplay ? XInternAtom( m_pDisplay, OUStringToOString( rString, RTL_TEXTENCODING_ISO_8859_1 ), False ) : nNoDisplayAtoms++;
+ m_aStringToAtom[ rString ] = aAtom;
+ m_aAtomToString[ aAtom ] = rString;
+ }
+ return m_aStringToAtom[ rString ];
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::requestOwnership( Atom selection )
+{
+ bool bSuccess = false;
+ if( m_pDisplay && m_aWindow )
+ {
+ MutexGuard aGuard(m_aMutex);
+
+ SelectionAdaptor* pAdaptor = getAdaptor( selection );
+ if( pAdaptor )
+ {
+ XSetSelectionOwner( m_pDisplay, selection, m_aWindow, CurrentTime );
+ if( XGetSelectionOwner( m_pDisplay, selection ) == m_aWindow )
+ bSuccess = true;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%s ownership for selection %s\n",
+ bSuccess ? "acquired" : "failed to acquire",
+ OUStringToOString( getString( selection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+ Selection* pSel = m_aSelections[ selection ];
+ pSel->m_bOwner = bSuccess;
+ delete pSel->m_pPixmap;
+ pSel->m_pPixmap = NULL;
+ pSel->m_nOrigTimestamp = m_nSelectionTimestamp;
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "no adaptor for selection %s\n",
+ OUStringToOString( getString( selection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+
+ if( pAdaptor->getTransferable().is() )
+ {
+ Sequence< DataFlavor > aTypes = pAdaptor->getTransferable()->getTransferDataFlavors();
+ for( int i = 0; i < aTypes.getLength(); i++ )
+ {
+ fprintf( stderr, " %s\n", OUStringToOString( aTypes.getConstArray()[i].MimeType, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+ }
+ }
+#endif
+ }
+ return bSuccess;
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::convertTypeToNative( const OUString& rType, Atom selection, int& rFormat, ::std::list< Atom >& rConversions, bool bPushFront )
+{
+ NativeTypeEntry* pTab = selection == m_nXdndSelection ? aXdndConversionTab : aNativeConversionTab;
+ int nTabEntries = selection == m_nXdndSelection
+ ? sizeof(aXdndConversionTab)/sizeof(aXdndConversionTab[0]) :
+ sizeof(aNativeConversionTab)/sizeof(aNativeConversionTab[0]);
+
+ OString aType( OUStringToOString( rType, RTL_TEXTENCODING_ISO_8859_1 ) );
+ rFormat = 0;
+ for( int i = 0; i < nTabEntries; i++ )
+ {
+ if( aType.equalsIgnoreAsciiCase( pTab[i].pType ) )
+ {
+ if( ! pTab[i].nAtom )
+ pTab[i].nAtom = getAtom( OStringToOUString( pTab[i].pNativeType, RTL_TEXTENCODING_ISO_8859_1 ) );
+ rFormat = pTab[i].nFormat;
+ if( bPushFront )
+ rConversions.push_front( pTab[i].nAtom );
+ else
+ rConversions.push_back( pTab[i].nAtom );
+ if( pTab[i].nFormat == XA_PIXMAP )
+ {
+ if( bPushFront )
+ {
+ rConversions.push_front( XA_VISUALID );
+ rConversions.push_front( XA_COLORMAP );
+ }
+ else
+ {
+ rConversions.push_back( XA_VISUALID );
+ rConversions.push_back( XA_COLORMAP );
+ }
+ }
+ }
+ }
+ if( ! rFormat )
+ rFormat = 8; // byte buffer
+ if( bPushFront )
+ rConversions.push_front( getAtom( rType ) );
+ else
+ rConversions.push_back( getAtom( rType ) );
+};
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::getNativeTypeList( const Sequence< DataFlavor >& rTypes, std::list< Atom >& rOutTypeList, Atom targetselection )
+{
+ rOutTypeList.clear();
+
+ int nFormat;
+ int nFlavors = rTypes.getLength();
+ const DataFlavor* pFlavors = rTypes.getConstArray();
+ bool bHaveText = false;
+ for( int i = 0; i < nFlavors; i++ )
+ {
+ if( pFlavors[i].MimeType.compareToAscii( "text/plain", 10 ) == 0)
+ bHaveText = true;
+ else
+ convertTypeToNative( pFlavors[i].MimeType, targetselection, nFormat, rOutTypeList );
+ }
+ if( bHaveText )
+ {
+ if( targetselection != m_nXdndSelection )
+ {
+ // only mimetypes should go into Xdnd type list
+ rOutTypeList.push_front( XA_STRING );
+ rOutTypeList.push_front( m_nCOMPOUNDAtom );
+ }
+ convertTypeToNative( OUString::createFromAscii( "text/plain;charset=utf-8" ), targetselection, nFormat, rOutTypeList, true );
+ }
+ if( targetselection != m_nXdndSelection )
+ rOutTypeList.push_back( m_nMULTIPLEAtom );
+}
+
+// ------------------------------------------------------------------------
+
+OUString SelectionManager::convertTypeFromNative( Atom nType, Atom selection, int& rFormat )
+{
+ NativeTypeEntry* pTab = selection == m_nXdndSelection ? aXdndConversionTab : aNativeConversionTab;
+ int nTabEntries = selection == m_nXdndSelection
+ ? sizeof(aXdndConversionTab)/sizeof(aXdndConversionTab[0]) :
+ sizeof(aNativeConversionTab)/sizeof(aNativeConversionTab[0]);
+
+ for( int i = 0; i < nTabEntries; i++ )
+ {
+ if( ! pTab[i].nAtom )
+ pTab[i].nAtom = getAtom( OStringToOUString( pTab[i].pNativeType, RTL_TEXTENCODING_ISO_8859_1 ) );
+ if( nType == pTab[i].nAtom )
+ {
+ rFormat = pTab[i].nFormat;
+ return OStringToOUString( pTab[i].pType, RTL_TEXTENCODING_ISO_8859_1 );
+ }
+ }
+ rFormat = 8;
+ return getString( nType );
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::getPasteData( Atom selection, Atom type, Sequence< sal_Int8 >& rData )
+{
+ ResettableMutexGuard aGuard(m_aMutex);
+ ::std::hash_map< Atom, Selection* >::iterator it;
+ bool bSuccess = false;
+
+#if OSL_DEBUG_LEVEL > 1
+ OUString aSelection( getString( selection ) );
+ OUString aType( getString( type ) );
+ fprintf( stderr, "getPasteData( %s, native: %s )\n",
+ OUStringToOString( aSelection, RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( aType, RTL_TEXTENCODING_ISO_8859_1 ).getStr()
+ );
+#endif
+
+ if( ! m_pDisplay )
+ return false;
+
+ it = m_aSelections.find( selection );
+ if( it == m_aSelections.end() )
+ return false;
+
+ XLIB_Window aSelectionOwner = XGetSelectionOwner( m_pDisplay, selection );
+ if( aSelectionOwner == None )
+ return false;
+ if( aSelectionOwner == m_aWindow )
+ {
+ // probably bad timing led us here
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "Innere Nabelschau\n" );
+#endif
+ return false;
+ }
+
+ // ICCCM recommends to destroy property before convert request unless
+ // parameters are transported; we do only in case of MULTIPLE,
+ // so destroy property unless target is MULTIPLE
+ if( type != m_nMULTIPLEAtom )
+ XDeleteProperty( m_pDisplay, m_aWindow, selection );
+
+ XConvertSelection( m_pDisplay, selection, type, selection, m_aWindow, selection == m_nXdndSelection ? m_nDropTime : CurrentTime );
+ it->second->m_eState = Selection::WaitingForResponse;
+ it->second->m_aRequestedType = type;
+ it->second->m_aData = Sequence< sal_Int8 >();
+ it->second->m_aDataArrived.reset();
+ // really start the request; if we don't flush the
+ // queue the request won't leave it because there are no more
+ // X calls after this until the data arrived or timeout
+ XFlush( m_pDisplay );
+
+ // do a reschedule
+ struct timeval tv_last, tv_current;
+ gettimeofday( &tv_last, NULL );
+ tv_current = tv_last;
+
+ XEvent aEvent;
+ do
+ {
+ bool bAdjustTime = false;
+ {
+ bool bHandle = false;
+
+ if( XCheckTypedEvent( m_pDisplay,
+ PropertyNotify,
+ &aEvent
+ ) )
+ {
+ bHandle = true;
+ if( aEvent.xproperty.window == m_aWindow
+ && aEvent.xproperty.atom == selection )
+ bAdjustTime = true;
+ }
+ else
+ if( XCheckTypedEvent( m_pDisplay,
+ SelectionClear,
+ &aEvent
+ ) )
+ {
+ bHandle = true;
+ }
+ else
+ if( XCheckTypedEvent( m_pDisplay,
+ SelectionRequest,
+ &aEvent
+ ) )
+ bHandle = true;
+ else
+ if( XCheckTypedEvent( m_pDisplay,
+ SelectionNotify,
+ &aEvent
+ ) )
+ {
+ bHandle = true;
+ if( aEvent.xselection.selection == selection
+ && ( aEvent.xselection.requestor == m_aWindow ||
+ aEvent.xselection.requestor == m_aCurrentDropWindow )
+ )
+ bAdjustTime = true;
+ }
+ else
+ {
+ TimeValue aTVal;
+ aTVal.Seconds = 0;
+ aTVal.Nanosec = 100000000;
+ aGuard.clear();
+ osl_waitThread( &aTVal );
+ aGuard.reset();
+ }
+ if( bHandle )
+ {
+ aGuard.clear();
+ handleXEvent( aEvent );
+ aGuard.reset();
+ }
+ }
+ gettimeofday( &tv_current, NULL );
+ if( bAdjustTime )
+ tv_last = tv_current;
+ } while( ! it->second->m_aDataArrived.check() && (tv_current.tv_sec - tv_last.tv_sec) < getSelectionTimeout() );
+
+#if OSL_DEBUG_LEVEL > 1
+ if( (tv_current.tv_sec - tv_last.tv_sec) > getSelectionTimeout() )
+ fprintf( stderr, "timed out\n" );
+#endif
+ if( it->second->m_aDataArrived.check() &&
+ it->second->m_aData.getLength() )
+ {
+ rData = it->second->m_aData;
+ bSuccess = true;
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "conversion unsuccessfull\n" );
+#endif
+ return bSuccess;
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::getPasteData( Atom selection, const ::rtl::OUString& rType, Sequence< sal_Int8 >& rData )
+{
+ int nFormat;
+ bool bSuccess = false;
+
+ ::std::hash_map< Atom, Selection* >::iterator it;
+ {
+ MutexGuard aGuard(m_aMutex);
+
+ it = m_aSelections.find( selection );
+ if( it == m_aSelections.end() )
+ return false;
+ }
+
+ if( it->second->m_aTypes.getLength() == 0 )
+ {
+ Sequence< DataFlavor > aFlavors;
+ getPasteDataTypes( selection, aFlavors );
+ if( it->second->m_aTypes.getLength() == 0 )
+ return false;
+ }
+
+ const Sequence< DataFlavor >& rTypes( it->second->m_aTypes );
+ const std::vector< Atom >& rNativeTypes( it->second->m_aNativeTypes );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "getPasteData( \"%s\", \"%s\" )\n",
+ OUStringToOString( getString( selection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( rType, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+
+ if( rType.equalsAsciiL( "text/plain;charset=utf-16", 25 ) )
+ {
+ // lets see if we have UTF16 else try to find something convertible
+ if( it->second->m_aTypes.getLength() && ! it->second->m_bHaveUTF16 )
+ {
+ Sequence< sal_Int8 > aData;
+ if( it->second->m_aUTF8Type != None &&
+ getPasteData( selection,
+ it->second->m_aUTF8Type,
+ aData )
+ )
+ {
+ OUString aRet( (const sal_Char*)aData.getConstArray(), aData.getLength(), RTL_TEXTENCODING_UTF8 );
+ rData = Sequence< sal_Int8 >( (sal_Int8*)aRet.getStr(), (aRet.getLength()+1)*sizeof( sal_Unicode ) );
+ bSuccess = true;
+ }
+ else if( it->second->m_bHaveCompound &&
+ getPasteData( selection,
+ m_nCOMPOUNDAtom,
+ aData )
+ )
+ {
+ OUString aRet( convertFromCompound( (const char*)aData.getConstArray(), aData.getLength() ) );
+ rData = Sequence< sal_Int8 >( (sal_Int8*)aRet.getStr(), (aRet.getLength()+1)*sizeof( sal_Unicode ) );
+ bSuccess = true;
+ }
+ else
+ {
+ for( int i = 0; i < rTypes.getLength(); i++ )
+ {
+ rtl_TextEncoding aEncoding = getTextPlainEncoding( rTypes.getConstArray()[i].MimeType );
+ if( aEncoding != RTL_TEXTENCODING_DONTKNOW &&
+ aEncoding != RTL_TEXTENCODING_UNICODE &&
+ getPasteData( selection,
+ rNativeTypes[i],
+ aData )
+ )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "using \"%s\" instead of \"%s\"\n",
+ OUStringToOString( rTypes.getConstArray()[i].MimeType, RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( rType, RTL_TEXTENCODING_ISO_8859_1 ).getStr()
+ );
+#endif
+ OString aConvert( (sal_Char*)aData.getConstArray(), aData.getLength() );
+ OUString aUTF( OStringToOUString( aConvert, aEncoding ) );
+ rData = Sequence< sal_Int8 >( (sal_Int8*)aUTF.getStr(), (aUTF.getLength()+1)*sizeof( sal_Unicode ) );
+ bSuccess = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else if( rType.equalsAsciiL( "image/bmp", 9 ) )
+ {
+ // #i83376# try if someone has the data in image/bmp already before
+ // doing the PIXMAP stuff (e.g. the gimp has this)
+ bSuccess = getPasteData( selection, m_nImageBmpAtom, rData );
+ #if OSL_DEBUG_LEVEL > 1
+ if( bSuccess )
+ fprintf( stderr, "got %d bytes of image/bmp\n", (int)rData.getLength() );
+ #endif
+ if( ! bSuccess )
+ {
+ Pixmap aPixmap = None;
+ Colormap aColormap = None;
+
+ // prepare property for MULTIPLE request
+ Sequence< sal_Int8 > aData;
+ Atom pTypes[4] = { XA_PIXMAP, XA_PIXMAP,
+ XA_COLORMAP, XA_COLORMAP };
+ {
+ MutexGuard aGuard(m_aMutex);
+
+ XChangeProperty( m_pDisplay,
+ m_aWindow,
+ selection,
+ XA_ATOM,
+ 32,
+ PropModeReplace,
+ (unsigned char*)pTypes,
+ 4 );
+ }
+
+ // try MULTIPLE request
+ if( getPasteData( selection, m_nMULTIPLEAtom, aData ) )
+ {
+ Atom* pReturnedTypes = (Atom*)aData.getArray();
+ if( pReturnedTypes[0] == XA_PIXMAP && pReturnedTypes[1] == XA_PIXMAP )
+ {
+ MutexGuard aGuard(m_aMutex);
+
+ Atom type = None;
+ int format = 0;
+ unsigned long nItems = 0;
+ unsigned long nBytes = 0;
+ unsigned char* pReturn = NULL;
+ XGetWindowProperty( m_pDisplay, m_aWindow, XA_PIXMAP, 0, 1, True, XA_PIXMAP, &type, &format, &nItems, &nBytes, &pReturn );
+ if( pReturn )
+ {
+ if( type == XA_PIXMAP )
+ aPixmap = *(Pixmap*)pReturn;
+ XFree( pReturn );
+ pReturn = NULL;
+ if( pReturnedTypes[2] == XA_COLORMAP && pReturnedTypes[3] == XA_COLORMAP )
+ {
+ XGetWindowProperty( m_pDisplay, m_aWindow, XA_COLORMAP, 0, 1, True, XA_COLORMAP, &type, &format, &nItems, &nBytes, &pReturn );
+ if( pReturn )
+ {
+ if( type == XA_COLORMAP )
+ aColormap = *(Colormap*)pReturn;
+ XFree( pReturn );
+ }
+ }
+ }
+ #if OSL_DEBUG_LEVEL > 1
+ else
+ {
+ fprintf( stderr, "could not get PIXMAP property: type=%s, format=%d, items=%ld, bytes=%ld, ret=0x%p\n", OUStringToOString( getString( type ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(), format, nItems, nBytes, pReturn );
+ }
+ #endif
+ }
+ }
+
+ if( aPixmap == None )
+ {
+ // perhaps two normal requests will work
+ if( getPasteData( selection, XA_PIXMAP, aData ) )
+ {
+ aPixmap = *(Pixmap*)aData.getArray();
+ if( aColormap == None && getPasteData( selection, XA_COLORMAP, aData ) )
+ aColormap = *(Colormap*)aData.getArray();
+ }
+ }
+
+ // convert data if possible
+ if( aPixmap != None )
+ {
+ MutexGuard aGuard(m_aMutex);
+
+ sal_Int32 nOutSize = 0;
+ sal_uInt8* pBytes = X11_getBmpFromPixmap( m_pDisplay, aPixmap, aColormap, nOutSize );
+ if( pBytes && nOutSize )
+ {
+ rData = Sequence< sal_Int8 >( nOutSize );
+ memcpy( rData.getArray(), pBytes, nOutSize );
+ X11_freeBmp( pBytes );
+ bSuccess = true;
+ }
+ }
+ }
+ }
+
+ if( ! bSuccess )
+ {
+ ::std::list< Atom > aTypes;
+ convertTypeToNative( rType, selection, nFormat, aTypes );
+ ::std::list< Atom >::const_iterator type_it;
+ Atom nSelectedType = None;
+ for( type_it = aTypes.begin(); type_it != aTypes.end() && nSelectedType == None; ++type_it )
+ {
+ for( unsigned int i = 0; i < rNativeTypes.size() && nSelectedType == None; i++ )
+ if( rNativeTypes[i] == *type_it )
+ nSelectedType = *type_it;
+ }
+ if( nSelectedType != None )
+ bSuccess = getPasteData( selection, nSelectedType, rData );
+ }
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "getPasteData for selection %s and data type %s returns %s, returned sequence has length %ld\n",
+ OUStringToOString( getString( selection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( rType, RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ bSuccess ? "true" : "false",
+ rData.getLength()
+ );
+#endif
+ return bSuccess;
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::getPasteDataTypes( Atom selection, Sequence< DataFlavor >& rTypes )
+{
+ ::std::hash_map< Atom, Selection* >::iterator it;
+ {
+ MutexGuard aGuard(m_aMutex);
+
+ it = m_aSelections.find( selection );
+ if( it != m_aSelections.end() &&
+ it->second->m_aTypes.getLength() &&
+ abs( it->second->m_nLastTimestamp - time( NULL ) ) < 2
+ )
+ {
+ rTypes = it->second->m_aTypes;
+ return true;
+ }
+ }
+
+ bool bSuccess = false;
+ bool bHaveUTF16 = false;
+ Atom aUTF8Type = None;
+ bool bHaveCompound = false;
+ bool bHaveText = false;
+ Sequence< sal_Int8 > aAtoms;
+
+ if( selection == m_nXdndSelection )
+ {
+ // xdnd sends first three types with XdndEnter
+ // if more than three types are supported then the XDndTypeList
+ // property on the source window is used
+ if( m_aDropEnterEvent.data.l[0] && m_aCurrentDropWindow )
+ {
+ if( m_aDropEnterEvent.data.l[1] & 1 )
+ {
+ const unsigned int atomcount = 256;
+ // more than three types; look in property
+ MutexGuard aGuard(m_aMutex);
+
+ Atom nType;
+ int nFormat;
+ unsigned long nItems, nBytes;
+ unsigned char* pBytes = NULL;
+
+ XGetWindowProperty( m_pDisplay, m_aDropEnterEvent.data.l[0],
+ m_nXdndTypeList, 0, atomcount, False,
+ XA_ATOM,
+ &nType, &nFormat, &nItems, &nBytes, &pBytes );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "have %ld data types in XdndTypeList\n", nItems );
+#endif
+ if( nItems == atomcount && nBytes > 0 )
+ {
+ // wow ... more than 256 types !
+ aAtoms.realloc( sizeof( Atom )*atomcount+nBytes );
+ memcpy( aAtoms.getArray(), pBytes, sizeof( Atom )*atomcount );
+ XFree( pBytes );
+ pBytes = NULL;
+ XGetWindowProperty( m_pDisplay, m_aDropEnterEvent.data.l[0],
+ m_nXdndTypeList, atomcount, nBytes/sizeof(Atom),
+ False, XA_ATOM,
+ &nType, &nFormat, &nItems, &nBytes, &pBytes );
+ {
+ memcpy( aAtoms.getArray()+atomcount*sizeof(Atom), pBytes, nItems*sizeof(Atom) );
+ XFree( pBytes );
+ }
+ }
+ else
+ {
+ aAtoms.realloc( sizeof(Atom)*nItems );
+ memcpy( aAtoms.getArray(), pBytes, nItems*sizeof(Atom) );
+ XFree( pBytes );
+ }
+ }
+ else
+ {
+ // one to three types
+ int n = 0, i;
+ for( i = 0; i < 3; i++ )
+ if( m_aDropEnterEvent.data.l[2+i] )
+ n++;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "have %d data types in XdndEnter\n", n );
+#endif
+ aAtoms.realloc( sizeof(Atom)*n );
+ for( i = 0, n = 0; i < 3; i++ )
+ if( m_aDropEnterEvent.data.l[2+i] )
+ ((Atom*)aAtoms.getArray())[n++] = m_aDropEnterEvent.data.l[2+i];
+ }
+ }
+ }
+ // get data of type TARGETS
+ else if( ! getPasteData( selection, m_nTARGETSAtom, aAtoms ) )
+ aAtoms = Sequence< sal_Int8 >();
+
+ std::vector< Atom > aNativeTypes;
+ if( aAtoms.getLength() )
+ {
+ sal_Int32 nAtoms = aAtoms.getLength() / sizeof(Atom);
+ Atom* pAtoms = (Atom*)aAtoms.getArray();
+ rTypes.realloc( nAtoms );
+ aNativeTypes.resize( nAtoms );
+ DataFlavor* pFlavors = rTypes.getArray();
+ sal_Int32 nNativeTypesIndex = 0;
+ while( nAtoms-- )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ if( *pAtoms && *pAtoms < 0x01000000 )
+ fprintf( stderr, "native type: %s\n", OUStringToOString( getString( *pAtoms ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+ if( *pAtoms == m_nCOMPOUNDAtom )
+ bHaveText = bHaveCompound = true;
+ else if( *pAtoms && *pAtoms < 0x01000000 )
+ {
+ int nFormat;
+ pFlavors->MimeType = convertTypeFromNative( *pAtoms, selection, nFormat );
+ pFlavors->DataType = getCppuType( (Sequence< sal_Int8 >*)0 );
+ sal_Int32 nIndex = 0;
+ if( pFlavors->MimeType.getToken( 0, ';', nIndex ).equalsAsciiL( "text/plain", 10 ) )
+ {
+ OUString aToken(pFlavors->MimeType.getToken( 0, ';', nIndex ));
+ // omit text/plain;charset=unicode since it is not well defined
+ if( aToken.compareToAscii( "charset=unicode" ) == 0 )
+ {
+ pAtoms++;
+ continue;
+ }
+ bHaveText = true;
+ if( aToken.compareToAscii( "charset=utf-16" ) == 0 )
+ {
+ bHaveUTF16 = true;
+ pFlavors->DataType = getCppuType( (OUString*)0 );
+ }
+ else if( aToken.compareToAscii( "charset=utf-8" ) == 0 )
+ {
+ aUTF8Type = *pAtoms;
+ }
+ }
+ pFlavors++;
+ aNativeTypes[ nNativeTypesIndex ] = *pAtoms;
+ nNativeTypesIndex++;
+ }
+ pAtoms++;
+ }
+ if( (pFlavors - rTypes.getArray()) < rTypes.getLength() )
+ rTypes.realloc(pFlavors - rTypes.getArray());
+ bSuccess = rTypes.getLength() ? true : false;
+ if( bHaveText && ! bHaveUTF16 )
+ {
+ int i = 0;
+
+ int nNewFlavors = rTypes.getLength()+1;
+ Sequence< DataFlavor > aTemp( nNewFlavors );
+ for( i = 0; i < nNewFlavors-1; i++ )
+ aTemp.getArray()[i+1] = rTypes.getConstArray()[i];
+ aTemp.getArray()[0].MimeType = OUString::createFromAscii( "text/plain;charset=utf-16" );
+ aTemp.getArray()[0].DataType = getCppuType( (OUString*)0 );
+ rTypes = aTemp;
+
+ std::vector< Atom > aNativeTemp( nNewFlavors );
+ for( i = 0; i < nNewFlavors-1; i++ )
+ aNativeTemp[ i + 1 ] = aNativeTypes[ i ];
+ aNativeTemp[0] = None;
+ aNativeTypes = aNativeTemp;
+ }
+ }
+
+ {
+ MutexGuard aGuard(m_aMutex);
+
+ it = m_aSelections.find( selection );
+ if( it != m_aSelections.end() )
+ {
+ if( bSuccess )
+ {
+ it->second->m_aTypes = rTypes;
+ it->second->m_aNativeTypes = aNativeTypes;
+ it->second->m_nLastTimestamp = time( NULL );
+ it->second->m_bHaveUTF16 = bHaveUTF16;
+ it->second->m_aUTF8Type = aUTF8Type;
+ it->second->m_bHaveCompound = bHaveCompound;
+ }
+ else
+ {
+ it->second->m_aTypes = Sequence< DataFlavor >();
+ it->second->m_aNativeTypes = std::vector< Atom >();
+ it->second->m_nLastTimestamp = 0;
+ it->second->m_bHaveUTF16 = false;
+ it->second->m_aUTF8Type = None;
+ it->second->m_bHaveCompound = false;
+ }
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+// if( selection != m_nCLIPBOARDAtom )
+ {
+ fprintf( stderr, "SelectionManager::getPasteDataTypes( %s ) = %s\n", OUStringToOString( getString( selection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(), bSuccess ? "true" : "false" );
+ for( int i = 0; i < rTypes.getLength(); i++ )
+ fprintf( stderr, "type: %s\n", OUStringToOString( rTypes.getConstArray()[i].MimeType, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+ }
+#endif
+
+ return bSuccess;
+}
+
+// ------------------------------------------------------------------------
+
+PixmapHolder* SelectionManager::getPixmapHolder( Atom selection )
+{
+ std::hash_map< Atom, Selection* >::const_iterator it = m_aSelections.find( selection );
+ if( it == m_aSelections.end() )
+ return NULL;
+ if( ! it->second->m_pPixmap )
+ it->second->m_pPixmap = new PixmapHolder( m_pDisplay );
+ return it->second->m_pPixmap;
+}
+
+static sal_Size GetTrueFormatSize(int nFormat)
+{
+ // http://mail.gnome.org/archives/wm-spec-list/2003-March/msg00067.html
+ return nFormat == 32 ? sizeof(long) : nFormat/8;
+}
+
+bool SelectionManager::sendData( SelectionAdaptor* pAdaptor,
+ XLIB_Window requestor,
+ Atom target,
+ Atom property,
+ Atom selection )
+{
+ ResettableMutexGuard aGuard( m_aMutex );
+
+ // handle targets related to image/bmp
+ if( target == XA_COLORMAP || target == XA_PIXMAP || target == XA_BITMAP || target == XA_VISUALID )
+ {
+ PixmapHolder* pPixmap = getPixmapHolder( selection );
+ if( ! pPixmap ) return false;
+ XID nValue = None;
+
+ // handle colormap request
+ if( target == XA_COLORMAP )
+ nValue = (XID)pPixmap->getColormap();
+ else if( target == XA_VISUALID )
+ nValue = (XID)pPixmap->getVisualID();
+ else if( target == XA_PIXMAP || target == XA_BITMAP )
+ {
+ nValue = (XID)pPixmap->getPixmap();
+ if( nValue == None )
+ {
+ // first conversion
+ Sequence< sal_Int8 > aData;
+ int nFormat;
+ aGuard.clear();
+ bool bConverted = convertData( pAdaptor->getTransferable(), target, selection, nFormat, aData );
+ aGuard.reset();
+ if( bConverted )
+ {
+ // get pixmap again since clearing the guard could have invalidated
+ // the pixmap in another thread
+ pPixmap = getPixmapHolder( selection );
+ // conversion succeeded, so aData contains image/bmp now
+ if( pPixmap->needsConversion( (const sal_uInt8*)aData.getConstArray() )
+ && m_xBitmapConverter.is() )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "trying bitmap conversion\n" );
+#endif
+ Reference<XBitmap> xBM( new BmpTransporter( aData ) );
+ Sequence<Any> aArgs(2), aOutArgs;
+ Sequence<sal_Int16> aOutIndex;
+ aArgs.getArray()[0] = makeAny( xBM );
+ aArgs.getArray()[1] = makeAny( (sal_uInt16)pPixmap->getDepth() );
+ aGuard.clear();
+ try
+ {
+ Any aResult =
+ m_xBitmapConverter->invoke( OUString::createFromAscii( "convert-bitmap-depth" ),
+ aArgs, aOutIndex, aOutArgs );
+ if( aResult >>= xBM )
+ aData = xBM->getDIB();
+ }
+ catch(...)
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "exception in bitmap converter\n" );
+#endif
+ }
+ aGuard.reset();
+ }
+ // get pixmap again since clearing the guard could have invalidated
+ // the pixmap in another thread
+ pPixmap = getPixmapHolder( selection );
+ nValue = (XID)pPixmap->setBitmapData( (const sal_uInt8*)aData.getConstArray() );
+ }
+ if( nValue == None )
+ return false;
+ }
+ if( target == XA_BITMAP )
+ nValue = (XID)pPixmap->getBitmap();
+ }
+
+ XChangeProperty( m_pDisplay,
+ requestor,
+ property,
+ target,
+ 32,
+ PropModeReplace,
+ (const unsigned char*)&nValue,
+ 1);
+ return true;
+ }
+
+ /*
+ * special target TEXT allows us to transfer
+ * the data in an encoding of our choice
+ * COMPOUND_TEXT will work with most applications
+ */
+ if( target == m_nTEXTAtom )
+ target = m_nCOMPOUNDAtom;
+
+ Sequence< sal_Int8 > aData;
+ int nFormat;
+ aGuard.clear();
+ bool bConverted = convertData( pAdaptor->getTransferable(), target, selection, nFormat, aData );
+ aGuard.reset();
+ if( bConverted )
+ {
+ // conversion succeeded
+ if( aData.getLength() > m_nIncrementalThreshold )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "using INCR protocol\n" );
+ std::hash_map< XLIB_Window, std::hash_map< Atom, IncrementalTransfer > >::const_iterator win_it = m_aIncrementals.find( requestor );
+ if( win_it != m_aIncrementals.end() )
+ {
+ std::hash_map< Atom, IncrementalTransfer >::const_iterator inc_it = win_it->second.find( property );
+ if( inc_it != win_it->second.end() )
+ {
+ const IncrementalTransfer& rInc = inc_it->second;
+ fprintf( stderr, "premature end and new start for INCR transfer for window 0x%lx, property %s, type %s\n",
+ rInc.m_aRequestor,
+ OUStringToOString( getString( rInc.m_aProperty ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( getString( rInc.m_aTarget ), RTL_TEXTENCODING_ISO_8859_1 ).getStr()
+ );
+ }
+ }
+#endif
+
+ // insert IncrementalTransfer
+ IncrementalTransfer& rInc = m_aIncrementals[ requestor ][ property ];
+ rInc.m_aData = aData;
+ rInc.m_nBufferPos = 0;
+ rInc.m_aRequestor = requestor;
+ rInc.m_aProperty = property;
+ rInc.m_aTarget = target;
+ rInc.m_nFormat = nFormat;
+ rInc.m_nTransferStartTime = time( NULL );
+
+ // use incr protocol, signal start to requestor
+ long nMinSize = m_nIncrementalThreshold;
+ XSelectInput( m_pDisplay, requestor, PropertyChangeMask );
+ XChangeProperty( m_pDisplay, requestor, property,
+ m_nINCRAtom, 32, PropModeReplace, (unsigned char*)&nMinSize, 1 );
+ XFlush( m_pDisplay );
+ }
+ else
+ {
+ sal_Size nUnitSize = GetTrueFormatSize(nFormat);
+ XChangeProperty( m_pDisplay,
+ requestor,
+ property,
+ target,
+ nFormat,
+ PropModeReplace,
+ (const unsigned char*)aData.getConstArray(),
+ aData.getLength()/nUnitSize );
+ }
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "convertData failed for type: %s \n",
+ OUStringToOString( convertTypeFromNative( target, selection, nFormat ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+ return bConverted;
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::handleSelectionRequest( XSelectionRequestEvent& rRequest )
+{
+ ResettableMutexGuard aGuard( m_aMutex );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "handleSelectionRequest for selection %s and target %s\n",
+ OUStringToOString( getString( rRequest.selection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( getString( rRequest.target ), RTL_TEXTENCODING_ISO_8859_1 ).getStr()
+ );
+#endif
+
+ XEvent aNotify;
+
+ aNotify.type = SelectionNotify;
+ aNotify.xselection.display = rRequest.display;
+ aNotify.xselection.send_event = True;
+ aNotify.xselection.requestor = rRequest.requestor;
+ aNotify.xselection.selection = rRequest.selection;
+ aNotify.xselection.time = rRequest.time;
+ aNotify.xselection.target = rRequest.target;
+ aNotify.xselection.property = None;
+
+ SelectionAdaptor* pAdaptor = getAdaptor( rRequest.selection );
+ // ensure that we still own that selection
+ if( pAdaptor &&
+ XGetSelectionOwner( m_pDisplay, rRequest.selection ) == m_aWindow )
+ {
+ Reference< XTransferable > xTrans( pAdaptor->getTransferable() );
+ if( rRequest.target == m_nTARGETSAtom )
+ {
+ // someone requests our types
+ if( xTrans.is() )
+ {
+ aGuard.clear();
+ Sequence< DataFlavor > aFlavors = xTrans->getTransferDataFlavors();
+ aGuard.reset();
+
+ ::std::list< Atom > aConversions;
+ getNativeTypeList( aFlavors, aConversions, rRequest.selection );
+
+ int i, nTypes = aConversions.size();
+ Atom* pTypes = (Atom*)alloca( nTypes * sizeof( Atom ) );
+ std::list< Atom >::const_iterator it;
+ for( i = 0, it = aConversions.begin(); i < nTypes; i++, ++it )
+ pTypes[i] = *it;
+ XChangeProperty( m_pDisplay, rRequest.requestor, rRequest.property,
+ XA_ATOM, 32, PropModeReplace, (const unsigned char*)pTypes, nTypes );
+ aNotify.xselection.property = rRequest.property;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "sending type list:\n" );
+ for( int k = 0; k < nTypes; k++ )
+ fprintf( stderr, " %s\n", pTypes[k] ? XGetAtomName( m_pDisplay, pTypes[k] ) : "<None>" );
+#endif
+ }
+ }
+ else if( rRequest.target == m_nTIMESTAMPAtom )
+ {
+ long nTimeStamp = (long)m_aSelections[rRequest.selection]->m_nOrigTimestamp;
+ XChangeProperty( m_pDisplay, rRequest.requestor, rRequest.property,
+ XA_INTEGER, 32, PropModeReplace, (const unsigned char*)&nTimeStamp, 1 );
+ aNotify.xselection.property = rRequest.property;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "sending timestamp: %d\n", (int)nTimeStamp );
+#endif
+ }
+ else
+ {
+ bool bEventSuccess = false;
+ if( rRequest.target == m_nMULTIPLEAtom )
+ {
+ // get all targets
+ Atom nType = None;
+ int nFormat = 0;
+ unsigned long nItems = 0, nBytes = 0;
+ unsigned char* pData = NULL;
+
+ // get number of atoms
+ XGetWindowProperty( m_pDisplay,
+ rRequest.requestor,
+ rRequest.property,
+ 0, 0,
+ False,
+ AnyPropertyType,
+ &nType, &nFormat,
+ &nItems, &nBytes,
+ &pData );
+ if( nFormat == 32 && nBytes/4 )
+ {
+ if( pData ) // ?? should not happen
+ {
+ XFree( pData );
+ pData = NULL;
+ }
+ XGetWindowProperty( m_pDisplay,
+ rRequest.requestor,
+ rRequest.property,
+ 0, nBytes/4,
+ False,
+ nType,
+ &nType, &nFormat,
+ &nItems, &nBytes,
+ &pData );
+ if( pData && nItems )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "found %ld atoms in MULTIPLE request\n", nItems );
+#endif
+ bEventSuccess = true;
+ bool bResetAtoms = false;
+ Atom* pAtoms = (Atom*)pData;
+ aGuard.clear();
+ for( unsigned int i = 0; i < nItems; i += 2 )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, " %s => %s: ",
+ OUStringToOString( getString( pAtoms[i] ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( getString( pAtoms[i+1] ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+ bool bSuccess = sendData( pAdaptor, rRequest.requestor, pAtoms[i], pAtoms[i+1], rRequest.selection );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%s\n", bSuccess ? "succeeded" : "failed" );
+#endif
+ if( ! bSuccess )
+ {
+ pAtoms[i] = None;
+ bResetAtoms = true;
+ }
+ }
+ aGuard.reset();
+ if( bResetAtoms )
+ XChangeProperty( m_pDisplay,
+ rRequest.requestor,
+ rRequest.property,
+ XA_ATOM,
+ 32,
+ PropModeReplace,
+ pData,
+ nBytes/4 );
+ }
+ if( pData )
+ XFree( pData );
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ {
+ fprintf( stderr, "could not get type list from \"%s\" of type \"%s\" on requestor 0x%lx, requestor has properties:",
+ OUStringToOString( getString( rRequest.property ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( getString( nType ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ rRequest.requestor );
+ int nProps = 0;
+ Atom* pProps = XListProperties( m_pDisplay, rRequest.requestor, &nProps );
+ if( pProps )
+ {
+ for( int i = 0; i < nProps; i++ )
+ fprintf( stderr, " \"%s\"", OUStringToOString( getString( pProps[i]), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+ XFree( pProps );
+ }
+ }
+#endif
+ }
+ else
+ {
+ aGuard.clear();
+ bEventSuccess = sendData( pAdaptor, rRequest.requestor, rRequest.target, rRequest.property, rRequest.selection );
+ aGuard.reset();
+ }
+ if( bEventSuccess )
+ {
+ aNotify.xselection.target = rRequest.target;
+ aNotify.xselection.property = rRequest.property;
+ }
+ }
+ aGuard.clear();
+ xTrans.clear();
+ aGuard.reset();
+ }
+ XSendEvent( m_pDisplay, rRequest.requestor, False, 0, &aNotify );
+
+ if( rRequest.selection == XA_PRIMARY &&
+ m_bWaitingForPrimaryConversion &&
+ m_xDragSourceListener.is() )
+ {
+ DragSourceDropEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, rRequest.time, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ if( aNotify.xselection.property != None )
+ {
+ dsde.DropAction = DNDConstants::ACTION_COPY;
+ dsde.DropSuccess = sal_True;
+ }
+ else
+ {
+ dsde.DropAction = DNDConstants::ACTION_NONE;
+ dsde.DropSuccess = sal_False;
+ }
+ Reference< XDragSourceListener > xListener( m_xDragSourceListener );
+ m_xDragSourceListener.clear();
+ aGuard.clear();
+ if( xListener.is() )
+ xListener->dragDropEnd( dsde );
+ }
+
+ // we handled the event in any case by answering
+ return true;
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::handleReceivePropertyNotify( XPropertyEvent& rNotify )
+{
+ MutexGuard aGuard( m_aMutex );
+ // data we requested arrived
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "handleReceivePropertyNotify for property %s\n",
+ OUStringToOString( getString( rNotify.atom ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+ bool bHandled = false;
+
+ ::std::hash_map< Atom, Selection* >::iterator it =
+ m_aSelections.find( rNotify.atom );
+ if( it != m_aSelections.end() &&
+ rNotify.state == PropertyNewValue &&
+ ( it->second->m_eState == Selection::WaitingForResponse ||
+ it->second->m_eState == Selection::WaitingForData ||
+ it->second->m_eState == Selection::IncrementalTransfer
+ )
+ )
+ {
+ // MULTIPLE requests are only complete after selection notify
+ if( it->second->m_aRequestedType == m_nMULTIPLEAtom &&
+ ( it->second->m_eState == Selection::WaitingForResponse ||
+ it->second->m_eState == Selection::WaitingForData ) )
+ return false;
+
+ bHandled = true;
+
+ Atom nType = None;
+ int nFormat = 0;
+ unsigned long nItems = 0, nBytes = 0;
+ unsigned char* pData = NULL;
+
+ // get type and length
+ XGetWindowProperty( m_pDisplay,
+ rNotify.window,
+ rNotify.atom,
+ 0, 0,
+ False,
+ AnyPropertyType,
+ &nType, &nFormat,
+ &nItems, &nBytes,
+ &pData );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "found %ld bytes data of type %s and format %d, items = %ld\n",
+ nBytes,
+ OUStringToOString( getString( nType ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ nFormat, nItems );
+#endif
+ if( pData )
+ {
+ XFree( pData );
+ pData = NULL;
+ }
+
+ if( nType == m_nINCRAtom )
+ {
+ // start data transfer
+ XDeleteProperty( m_pDisplay, rNotify.window, rNotify.atom );
+ it->second->m_eState = Selection::IncrementalTransfer;
+ }
+ else if( nType != None )
+ {
+ XGetWindowProperty( m_pDisplay,
+ rNotify.window,
+ rNotify.atom,
+ 0, nBytes/4 +1,
+ True,
+ nType,
+ &nType, &nFormat,
+ &nItems, &nBytes,
+ &pData );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "read %ld items data of type %s and format %d, %ld bytes left in property\n",
+ nItems,
+ OUStringToOString( getString( nType ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ nFormat, nBytes );
+#endif
+
+ sal_Size nUnitSize = GetTrueFormatSize(nFormat);
+
+ if( it->second->m_eState == Selection::WaitingForData ||
+ it->second->m_eState == Selection::WaitingForResponse )
+ {
+ // copy data
+ it->second->m_aData = Sequence< sal_Int8 >( (sal_Int8*)pData, nItems*nUnitSize );
+ it->second->m_eState = Selection::Inactive;
+ it->second->m_aDataArrived.set();
+ }
+ else if( it->second->m_eState == Selection::IncrementalTransfer )
+ {
+ if( nItems )
+ {
+ // append data
+ Sequence< sal_Int8 > aData( it->second->m_aData.getLength() + nItems*nUnitSize );
+ memcpy( aData.getArray(), it->second->m_aData.getArray(), it->second->m_aData.getLength() );
+ memcpy( aData.getArray() + it->second->m_aData.getLength(), pData, nItems*nUnitSize );
+ it->second->m_aData = aData;
+ }
+ else
+ {
+ it->second->m_eState = Selection::Inactive;
+ it->second->m_aDataArrived.set();
+ }
+ }
+ if( pData )
+ XFree( pData );
+ }
+ else if( it->second->m_eState == Selection::IncrementalTransfer )
+ {
+ it->second->m_eState = Selection::Inactive;
+ it->second->m_aDataArrived.set();
+ }
+ }
+ return bHandled;
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::handleSendPropertyNotify( XPropertyEvent& rNotify )
+{
+ MutexGuard aGuard( m_aMutex );
+
+ // ready for next part of a IncrementalTransfer
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "handleSendPropertyNotify for property %s (%s)\n",
+ OUStringToOString( getString( rNotify.atom ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ rNotify.state == PropertyNewValue ? "new value" : ( rNotify.state == PropertyDelete ? "deleted" : "unknown")
+ );
+#endif
+
+ bool bHandled = false;
+ // feed incrementals
+ if( rNotify.state == PropertyDelete )
+ {
+ std::hash_map< XLIB_Window, std::hash_map< Atom, IncrementalTransfer > >::iterator it;
+ it = m_aIncrementals.find( rNotify.window );
+ if( it != m_aIncrementals.end() )
+ {
+ bHandled = true;
+ int nCurrentTime = time( NULL );
+ std::hash_map< Atom, IncrementalTransfer >::iterator inc_it;
+ // throw out aborted transfers
+ std::list< Atom > aTimeouts;
+ for( inc_it = it->second.begin(); inc_it != it->second.end(); ++inc_it )
+ {
+ if( (nCurrentTime - inc_it->second.m_nTransferStartTime) > (getSelectionTimeout()+2) )
+ {
+ aTimeouts.push_back( inc_it->first );
+#if OSL_DEBUG_LEVEL > 1
+ const IncrementalTransfer& rInc = inc_it->second;
+ fprintf( stderr, "timeout on INCR transfer for window 0x%lx, property %s, type %s\n",
+ rInc.m_aRequestor,
+ OUStringToOString( getString( rInc.m_aProperty ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( getString( rInc.m_aTarget ), RTL_TEXTENCODING_ISO_8859_1 ).getStr()
+ );
+#endif
+ }
+ }
+
+ while( aTimeouts.begin() != aTimeouts.end() )
+ {
+ // transfer broken, might even be a new client with the
+ // same window id
+ it->second.erase( aTimeouts.front() );
+ aTimeouts.pop_front();
+ }
+
+ inc_it = it->second.find( rNotify.atom );
+ if( inc_it != it->second.end() )
+ {
+ IncrementalTransfer& rInc = inc_it->second;
+
+ int nBytes = rInc.m_aData.getLength() - rInc.m_nBufferPos;
+ nBytes = (nBytes > m_nIncrementalThreshold) ? m_nIncrementalThreshold : nBytes;
+ if( nBytes < 0 ) // sanity check
+ nBytes = 0;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "pushing %d bytes: \"%.*s\"...\n",
+ nBytes, nBytes > 32 ? 32 : nBytes,
+ (const unsigned char*)rInc.m_aData.getConstArray()+rInc.m_nBufferPos );
+#endif
+
+ sal_Size nUnitSize = GetTrueFormatSize(rInc.m_nFormat);
+
+ XChangeProperty( m_pDisplay,
+ rInc.m_aRequestor,
+ rInc.m_aProperty,
+ rInc.m_aTarget,
+ rInc.m_nFormat,
+ PropModeReplace,
+ (const unsigned char*)rInc.m_aData.getConstArray()+rInc.m_nBufferPos,
+ nBytes/nUnitSize );
+ rInc.m_nBufferPos += nBytes;
+ rInc.m_nTransferStartTime = nCurrentTime;
+
+ if( nBytes == 0 ) // transfer finished
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "finished INCR transfer for window 0x%lx, property %s, type %s\n",
+ rInc.m_aRequestor,
+ OUStringToOString( getString( rInc.m_aProperty ), RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( getString( rInc.m_aTarget ), RTL_TEXTENCODING_ISO_8859_1 ).getStr()
+ );
+#endif
+ it->second.erase( inc_it );
+ }
+
+ }
+ // eventually clean up the hash map
+ if( it->second.begin() == it->second.end() )
+ m_aIncrementals.erase( it );
+ }
+ }
+ return bHandled;
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::handleSelectionNotify( XSelectionEvent& rNotify )
+{
+ MutexGuard aGuard( m_aMutex );
+
+ bool bHandled = false;
+
+ // notification about success/failure of one of our conversion requests
+#if OSL_DEBUG_LEVEL > 1
+ OUString aSelection( getString( rNotify.selection ) );
+ OUString aProperty( OUString::createFromAscii( "None" ) );
+ if( rNotify.property )
+ aProperty = getString( rNotify.property );
+ fprintf( stderr, "handleSelectionNotify for selection %s and property %s (0x%lx)\n",
+ OUStringToOString( aSelection, RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( aProperty, RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ rNotify.property
+ );
+ if( rNotify.requestor != m_aWindow && rNotify.requestor != m_aCurrentDropWindow )
+ fprintf( stderr, "Warning: selection notify for unknown window 0x%lx\n", rNotify.requestor );
+#endif
+ ::std::hash_map< Atom, Selection* >::iterator it =
+ m_aSelections.find( rNotify.selection );
+ if (
+ (rNotify.requestor == m_aWindow || rNotify.requestor == m_aCurrentDropWindow) &&
+ it != m_aSelections.end() &&
+ (
+ (it->second->m_eState == Selection::WaitingForResponse) ||
+ (it->second->m_eState == Selection::WaitingForData)
+ )
+ )
+ {
+ bHandled = true;
+ if( it->second->m_aRequestedType == m_nMULTIPLEAtom )
+ {
+ Atom nType = None;
+ int nFormat = 0;
+ unsigned long nItems = 0, nBytes = 0;
+ unsigned char* pData = NULL;
+
+ // get type and length
+ XGetWindowProperty( m_pDisplay,
+ rNotify.requestor,
+ rNotify.property,
+ 0, 256,
+ False,
+ AnyPropertyType,
+ &nType, &nFormat,
+ &nItems, &nBytes,
+ &pData );
+ if( nBytes ) // HUGE request !!!
+ {
+ if( pData )
+ XFree( pData );
+ XGetWindowProperty( m_pDisplay,
+ rNotify.requestor,
+ rNotify.property,
+ 0, 256+(nBytes+3)/4,
+ False,
+ AnyPropertyType,
+ &nType, &nFormat,
+ &nItems, &nBytes,
+ &pData );
+ }
+ it->second->m_eState = Selection::Inactive;
+ sal_Size nUnitSize = GetTrueFormatSize(nFormat);
+ it->second->m_aData = Sequence< sal_Int8 >((sal_Int8*)pData, nItems * nUnitSize);
+ it->second->m_aDataArrived.set();
+ if( pData )
+ XFree( pData );
+ }
+ // WaitingForData can actually happen; some
+ // applications (e.g. cmdtool on Solaris) first send
+ // a success and then cancel it. Weird !
+ else if( rNotify.property == None )
+ {
+ // conversion failed, stop transfer
+ it->second->m_eState = Selection::Inactive;
+ it->second->m_aData = Sequence< sal_Int8 >();
+ it->second->m_aDataArrived.set();
+ }
+ // get the bytes, by INCR if necessary
+ else
+ it->second->m_eState = Selection::WaitingForData;
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else if( it != m_aSelections.end() )
+ fprintf( stderr, "Warning: selection in state %d\n", it->second->m_eState );
+#endif
+ return bHandled;
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::handleDropEvent( XClientMessageEvent& rMessage )
+{
+ ResettableMutexGuard aGuard(m_aMutex);
+
+ // handle drop related events
+ XLIB_Window aSource = rMessage.data.l[0];
+ XLIB_Window aTarget = rMessage.window;
+
+ bool bHandled = false;
+
+ ::std::hash_map< XLIB_Window, DropTargetEntry >::iterator it =
+ m_aDropTargets.find( aTarget );
+
+#if OSL_DEBUG_LEVEL > 1
+ if( rMessage.message_type == m_nXdndEnter ||
+ rMessage.message_type == m_nXdndLeave ||
+ rMessage.message_type == m_nXdndDrop ||
+ rMessage.message_type == m_nXdndPosition )
+ {
+ fprintf( stderr, "got drop event %s, ", OUStringToOString( getString( rMessage.message_type ), RTL_TEXTENCODING_ASCII_US).getStr() );
+ if( it == m_aDropTargets.end() )
+ fprintf( stderr, "but no target found\n" );
+ else if( ! it->second.m_pTarget->m_bActive )
+ fprintf( stderr, "but target is inactive\n" );
+ else if( m_aDropEnterEvent.data.l[0] != None && (XLIB_Window)m_aDropEnterEvent.data.l[0] != aSource )
+ fprintf( stderr, "but source 0x%lx is unknown (expected 0x%lx or 0)\n", aSource, m_aDropEnterEvent.data.l[0] );
+ else
+ fprintf( stderr, "processing.\n" );
+ }
+#endif
+
+ if( it != m_aDropTargets.end() && it->second.m_pTarget->m_bActive &&
+ m_bDropWaitingForCompletion && m_aDropEnterEvent.data.l[0] )
+ {
+ bHandled = true;
+ OSL_ENSURE( 0, "someone forgot to call dropComplete ?" );
+ // some listener forgot to call dropComplete in the last operation
+ // let us end it now and accept the new enter event
+ aGuard.clear();
+ dropComplete( sal_False, m_aCurrentDropWindow, m_nDropTime );
+ aGuard.reset();
+ }
+
+ if( it != m_aDropTargets.end() &&
+ it->second.m_pTarget->m_bActive &&
+ ( m_aDropEnterEvent.data.l[0] == None || XLIB_Window(m_aDropEnterEvent.data.l[0]) == aSource )
+ )
+ {
+ if( rMessage.message_type == m_nXdndEnter )
+ {
+ bHandled = true;
+ m_aDropEnterEvent = rMessage;
+ m_bDropEnterSent = false;
+ m_aCurrentDropWindow = aTarget;
+ m_nCurrentProtocolVersion = m_aDropEnterEvent.data.l[1] >> 24;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "received XdndEnter on 0x%lx\n", aTarget );
+#endif
+ }
+ else if(
+ rMessage.message_type == m_nXdndPosition &&
+ aSource == XLIB_Window(m_aDropEnterEvent.data.l[0])
+ )
+ {
+ bHandled = true;
+ m_nDropTime = m_nCurrentProtocolVersion > 0 ? rMessage.data.l[3] : CurrentTime;
+ if( ! m_bDropEnterSent )
+ m_nDropTimestamp = m_nDropTime;
+
+ XLIB_Window aChild;
+ XTranslateCoordinates( m_pDisplay,
+ it->second.m_aRootWindow,
+ it->first,
+ rMessage.data.l[2] >> 16,
+ rMessage.data.l[2] & 0xffff,
+ &m_nLastX, &m_nLastY,
+ &aChild );
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "received XdndPosition on 0x%lx (%d, %d)\n", aTarget, m_nLastX, m_nLastY );
+#endif
+ DropTargetDragEnterEvent aEvent;
+ aEvent.Source = static_cast< XDropTarget* >(it->second.m_pTarget);
+ aEvent.Context = new DropTargetDragContext( m_aCurrentDropWindow, m_nDropTimestamp, *this );
+ aEvent.LocationX = m_nLastX;
+ aEvent.LocationY = m_nLastY;
+ aEvent.SourceActions = m_nSourceActions;
+ if( m_nCurrentProtocolVersion < 2 )
+ aEvent.DropAction = DNDConstants::ACTION_COPY;
+ else if( Atom(rMessage.data.l[4]) == m_nXdndActionCopy )
+ aEvent.DropAction = DNDConstants::ACTION_COPY;
+ else if( Atom(rMessage.data.l[4]) == m_nXdndActionMove )
+ aEvent.DropAction = DNDConstants::ACTION_MOVE;
+ else if( Atom(rMessage.data.l[4]) == m_nXdndActionLink )
+ aEvent.DropAction = DNDConstants::ACTION_LINK;
+ else if( Atom(rMessage.data.l[4]) == m_nXdndActionAsk )
+ // currently no interface to implement ask
+ aEvent.DropAction = ~0;
+ else
+ aEvent.DropAction = DNDConstants::ACTION_NONE;
+
+ m_nLastDropAction = aEvent.DropAction;
+ if( ! m_bDropEnterSent )
+ {
+ m_bDropEnterSent = true;
+ aEvent.SupportedDataFlavors = m_xDropTransferable->getTransferDataFlavors();
+ aGuard.clear();
+ it->second->dragEnter( aEvent );
+ }
+ else
+ {
+ aGuard.clear();
+ it->second->dragOver( aEvent );
+ }
+ }
+ else if(
+ rMessage.message_type == m_nXdndLeave &&
+ aSource == XLIB_Window(m_aDropEnterEvent.data.l[0])
+ )
+ {
+ bHandled = true;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "received XdndLeave on 0x%lx\n", aTarget );
+#endif
+ DropTargetEvent aEvent;
+ aEvent.Source = static_cast< XDropTarget* >(it->second.m_pTarget);
+ m_aDropEnterEvent.data.l[0] = None;
+ if( m_aCurrentDropWindow == aTarget )
+ m_aCurrentDropWindow = None;
+ m_nCurrentProtocolVersion = nXdndProtocolRevision;
+ aGuard.clear();
+ it->second->dragExit( aEvent );
+ }
+ else if(
+ rMessage.message_type == m_nXdndDrop &&
+ aSource == XLIB_Window(m_aDropEnterEvent.data.l[0])
+ )
+ {
+ bHandled = true;
+ m_nDropTime = m_nCurrentProtocolVersion > 0 ? rMessage.data.l[2] : CurrentTime;
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "received XdndDrop on 0x%lx (%d, %d)\n", aTarget, m_nLastX, m_nLastY );
+#endif
+ if( m_bLastDropAccepted )
+ {
+ DropTargetDropEvent aEvent;
+ aEvent.Source = static_cast< XDropTarget* >(it->second.m_pTarget);
+ aEvent.Context = new DropTargetDropContext( m_aCurrentDropWindow, m_nDropTimestamp, *this );
+ aEvent.LocationX = m_nLastX;
+ aEvent.LocationY = m_nLastY;
+ aEvent.DropAction = m_nLastDropAction;
+ // there is nothing corresponding to source supported actions
+ // every source can do link, copy and move
+ aEvent.SourceActions= m_nLastDropAction;
+ aEvent.Transferable = m_xDropTransferable;
+
+ m_bDropWaitingForCompletion = true;
+ aGuard.clear();
+ it->second->drop( aEvent );
+ }
+ else
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "XdndDrop canceled due to m_bLastDropAccepted = fale\n" );
+#endif
+ DropTargetEvent aEvent;
+ aEvent.Source = static_cast< XDropTarget* >(it->second.m_pTarget);
+ aGuard.clear();
+ it->second->dragExit( aEvent );
+ // reset the drop status, notify source
+ dropComplete( sal_False, m_aCurrentDropWindow, m_nDropTime );
+ }
+ }
+ }
+ return bHandled;
+}
+
+/*
+ * methods for XDropTargetDropContext
+ */
+
+void SelectionManager::dropComplete( sal_Bool bSuccess, XLIB_Window aDropWindow, XLIB_Time )
+{
+ ClearableMutexGuard aGuard(m_aMutex);
+
+ if( aDropWindow == m_aCurrentDropWindow )
+ {
+ if( m_xDragSourceListener.is() )
+ {
+ DragSourceDropEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ dsde.DropAction = getUserDragAction();
+ dsde.DropSuccess = bSuccess;
+ Reference< XDragSourceListener > xListener = m_xDragSourceListener;
+ m_xDragSourceListener.clear();
+
+ aGuard.clear();
+ xListener->dragDropEnd( dsde );
+ }
+ else if( m_aDropEnterEvent.data.l[0] && m_aCurrentDropWindow )
+ {
+ XEvent aEvent;
+ aEvent.xclient.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.window = m_aDropEnterEvent.data.l[0];
+ aEvent.xclient.message_type = m_nXdndFinished;
+ aEvent.xclient.format = 32;
+ aEvent.xclient.data.l[0] = m_aCurrentDropWindow;
+ aEvent.xclient.data.l[1] = bSuccess ? 1 : 0;
+ aEvent.xclient.data.l[2] = 0;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = 0;
+ if( bSuccess )
+ {
+ if( m_nLastDropAction & DNDConstants::ACTION_MOVE )
+ aEvent.xclient.data.l[2] = m_nXdndActionMove;
+ else if( m_nLastDropAction & DNDConstants::ACTION_COPY )
+ aEvent.xclient.data.l[2] = m_nXdndActionCopy;
+ else if( m_nLastDropAction & DNDConstants::ACTION_LINK )
+ aEvent.xclient.data.l[2] = m_nXdndActionLink;
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "Sending XdndFinished to 0x%lx\n",
+ m_aDropEnterEvent.data.l[0]
+ );
+#endif
+
+ XSendEvent( m_pDisplay, m_aDropEnterEvent.data.l[0],
+ False, NoEventMask, & aEvent );
+
+ m_aDropEnterEvent.data.l[0] = None;
+ m_aCurrentDropWindow = None;
+ m_nCurrentProtocolVersion = nXdndProtocolRevision;
+ }
+ m_bDropWaitingForCompletion = false;
+ }
+ else
+ OSL_ASSERT( "dropComplete from invalid DropTargetDropContext" );
+}
+
+/*
+ * methods for XDropTargetDragContext
+ */
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::sendDragStatus( Atom nDropAction )
+{
+ ClearableMutexGuard aGuard(m_aMutex);
+
+ if( m_xDragSourceListener.is() )
+ {
+ sal_Int8 nNewDragAction;
+ if( nDropAction == m_nXdndActionMove )
+ nNewDragAction = DNDConstants::ACTION_MOVE;
+ else if( nDropAction == m_nXdndActionCopy )
+ nNewDragAction = DNDConstants::ACTION_COPY;
+ else if( nDropAction == m_nXdndActionLink )
+ nNewDragAction = DNDConstants::ACTION_LINK;
+ else
+ nNewDragAction = DNDConstants::ACTION_NONE;
+ nNewDragAction &= m_nSourceActions;
+
+ if( nNewDragAction != m_nTargetAcceptAction )
+ {
+ setCursor( getDefaultCursor( nNewDragAction ), m_aDropWindow, m_nDragTimestamp );
+ m_nTargetAcceptAction = nNewDragAction;
+ }
+
+ DragSourceDragEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ dsde.DropAction = m_nSourceActions;
+ dsde.UserAction = getUserDragAction();
+
+ Reference< XDragSourceListener > xListener( m_xDragSourceListener );
+ // caution: do not change anything after this
+ aGuard.clear();
+ if( xListener.is() )
+ xListener->dragOver( dsde );
+ }
+ else if( m_aDropEnterEvent.data.l[0] && m_aCurrentDropWindow )
+ {
+ XEvent aEvent;
+ aEvent.xclient.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.window = m_aDropEnterEvent.data.l[0];
+ aEvent.xclient.message_type = m_nXdndStatus;
+ aEvent.xclient.format = 32;
+ aEvent.xclient.data.l[0] = m_aCurrentDropWindow;
+ aEvent.xclient.data.l[1] = 2;
+ if( nDropAction == m_nXdndActionMove ||
+ nDropAction == m_nXdndActionLink ||
+ nDropAction == m_nXdndActionCopy )
+ aEvent.xclient.data.l[1] |= 1;
+ aEvent.xclient.data.l[2] = 0;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = m_nCurrentProtocolVersion > 1 ? nDropAction : 0;
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "Sending XdndStatus to 0x%lx with action %s\n",
+ m_aDropEnterEvent.data.l[0],
+ OUStringToOString( getString( nDropAction ), RTL_TEXTENCODING_ISO_8859_1 ).getStr()
+ );
+#endif
+
+ XSendEvent( m_pDisplay, m_aDropEnterEvent.data.l[0],
+ False, NoEventMask, & aEvent );
+ XFlush( m_pDisplay );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+sal_Int8 SelectionManager::getUserDragAction() const
+{
+ return (m_nTargetAcceptAction != DNDConstants::ACTION_DEFAULT) ? m_nTargetAcceptAction : m_nUserDragAction;
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::updateDragAction( int modifierState )
+{
+ bool bRet = false;
+
+ sal_Int8 nNewDropAction = DNDConstants::ACTION_MOVE;
+ if( ( modifierState & ShiftMask ) && ! ( modifierState & ControlMask ) )
+ nNewDropAction = DNDConstants::ACTION_MOVE;
+ else if( ( modifierState & ControlMask ) && ! ( modifierState & ShiftMask ) )
+ nNewDropAction = DNDConstants::ACTION_COPY;
+ else if( ( modifierState & ShiftMask ) && ( modifierState & ControlMask ) )
+ nNewDropAction = DNDConstants::ACTION_LINK;
+ if( m_nCurrentProtocolVersion < 0 && m_aDropWindow != None )
+ nNewDropAction = DNDConstants::ACTION_COPY;
+ nNewDropAction &= m_nSourceActions;
+
+ if( ! ( modifierState & ( ControlMask | ShiftMask ) ) )
+ {
+ if( ! nNewDropAction )
+ {
+ // default to an action so the user does not have to press
+ // keys explicitly
+ if( m_nSourceActions & DNDConstants::ACTION_MOVE )
+ nNewDropAction = DNDConstants::ACTION_MOVE;
+ else if( m_nSourceActions & DNDConstants::ACTION_COPY )
+ nNewDropAction = DNDConstants::ACTION_COPY;
+ else if( m_nSourceActions & DNDConstants::ACTION_LINK )
+ nNewDropAction = DNDConstants::ACTION_LINK;
+ }
+ nNewDropAction |= DNDConstants::ACTION_DEFAULT;
+ }
+
+ if( nNewDropAction != m_nUserDragAction || m_nTargetAcceptAction != DNDConstants::ACTION_DEFAULT )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "updateDragAction: %x -> %x\n", (int)m_nUserDragAction, (int)nNewDropAction );
+#endif
+ bRet = true;
+ m_nUserDragAction = nNewDropAction;
+
+ DragSourceDragEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ dsde.DropAction = m_nUserDragAction;
+ dsde.UserAction = m_nUserDragAction;
+ m_nTargetAcceptAction = DNDConstants::ACTION_DEFAULT; // invalidate last accept
+ m_xDragSourceListener->dropActionChanged( dsde );
+ }
+ return bRet;
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::sendDropPosition( bool bForce, XLIB_Time eventTime )
+{
+ ClearableMutexGuard aGuard(m_aMutex);
+
+ if( m_bDropSent )
+ return;
+
+ ::std::hash_map< XLIB_Window, DropTargetEntry >::const_iterator it =
+ m_aDropTargets.find( m_aDropWindow );
+ if( it != m_aDropTargets.end() )
+ {
+ if( it->second.m_pTarget->m_bActive )
+ {
+ int x, y;
+ XLIB_Window aChild;
+ XTranslateCoordinates( m_pDisplay, it->second.m_aRootWindow, m_aDropWindow, m_nLastDragX, m_nLastDragY, &x, &y, &aChild );
+ DropTargetDragEvent dtde;
+ dtde.Source = static_cast< OWeakObject* >(it->second.m_pTarget );
+ dtde.Context = new DropTargetDragContext( m_aCurrentDropWindow, m_nDropTimestamp, *this );
+ dtde.LocationX = x;
+ dtde.LocationY = y;
+ dtde.DropAction = getUserDragAction();
+ dtde.SourceActions = m_nSourceActions;
+ aGuard.clear();
+ it->second->dragOver( dtde );
+ }
+ }
+ else if( bForce ||
+
+ m_nLastDragX < m_nNoPosX || m_nLastDragX >= m_nNoPosX+m_nNoPosWidth ||
+ m_nLastDragY < m_nNoPosY || m_nLastDragY >= m_nNoPosY+m_nNoPosHeight
+ )
+ {
+ // send XdndPosition
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.format = 32;
+ aEvent.xclient.message_type = m_nXdndPosition;
+ aEvent.xclient.window = m_aDropWindow;
+ aEvent.xclient.data.l[0] = m_aWindow;
+ aEvent.xclient.data.l[1] = 0;
+ aEvent.xclient.data.l[2] = m_nLastDragX << 16 | (m_nLastDragY&0xffff);
+ aEvent.xclient.data.l[3] = eventTime;
+
+ if( m_nUserDragAction & DNDConstants::ACTION_COPY )
+ aEvent.xclient.data.l[4]=m_nXdndActionCopy;
+ else if( m_nUserDragAction & DNDConstants::ACTION_MOVE )
+ aEvent.xclient.data.l[4]=m_nXdndActionMove;
+ else if( m_nUserDragAction & DNDConstants::ACTION_LINK )
+ aEvent.xclient.data.l[4]=m_nXdndActionLink;
+ else
+ aEvent.xclient.data.l[4]=m_nXdndActionCopy;
+ XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
+ m_nNoPosX = m_nNoPosY = m_nNoPosWidth = m_nNoPosHeight = 0;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::handleDragEvent( XEvent& rMessage )
+{
+ if( ! m_xDragSourceListener.is() )
+ return false;
+
+ ResettableMutexGuard aGuard(m_aMutex);
+
+ bool bHandled = false;
+
+ // for shortcut
+ ::std::hash_map< XLIB_Window, DropTargetEntry >::const_iterator it =
+ m_aDropTargets.find( m_aDropWindow );
+#if OSL_DEBUG_LEVEL > 1
+ switch( rMessage.type )
+ {
+ case ClientMessage:
+ fprintf( stderr, "handleDragEvent: %s\n", OUStringToOString( getString( rMessage.xclient.message_type ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+ break;
+ case MotionNotify:
+// fprintf( stderr, "handleDragEvent: MotionNotify\n" );
+ break;
+ case EnterNotify:
+ fprintf( stderr, "handleDragEvent: EnterNotify\n" );
+ break;
+ case LeaveNotify:
+ fprintf( stderr, "handleDragEvent: LeaveNotify\n" );
+ break;
+ case ButtonPress:
+ fprintf( stderr, "handleDragEvent: ButtonPress %d (m_nDragButton = %d)\n", rMessage.xbutton.button, m_nDragButton );
+ break;
+ case ButtonRelease:
+ fprintf( stderr, "handleDragEvent: ButtonRelease %d (m_nDragButton = %d)\n", rMessage.xbutton.button, m_nDragButton );
+ break;
+ case XLIB_KeyPress:
+ fprintf( stderr, "handleDragEvent: KeyPress\n" );
+ break;
+ case KeyRelease:
+ fprintf( stderr, "handleDragEvent: KeyRelease\n" );
+ break;
+ default:
+ fprintf( stderr, "handleDragEvent: <unknown type %d>\n", rMessage.type );
+ break;
+ }
+#endif
+
+ // handle drag related events
+ if( rMessage.type == ClientMessage )
+ {
+ if( Atom(rMessage.xclient.message_type) == m_nXdndStatus && Atom(rMessage.xclient.data.l[0]) == m_aDropWindow )
+ {
+ bHandled = true;
+ DragSourceDragEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >( this );
+ dsde.UserAction = getUserDragAction();
+ dsde.DropAction = DNDConstants::ACTION_NONE;
+ m_bDropSuccess = rMessage.xclient.data.l[1] & 1 ? true : false;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "status drop action: accept = %s, %s\n",
+ m_bDropSuccess ? "true" : "false",
+ OUStringToOString( getString( rMessage.xclient.data.l[4] ), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+ if( rMessage.xclient.data.l[1] & 1 )
+ {
+ if( m_nCurrentProtocolVersion > 1 )
+ {
+ if( Atom(rMessage.xclient.data.l[4]) == m_nXdndActionCopy )
+ dsde.DropAction = DNDConstants::ACTION_COPY;
+ else if( Atom(rMessage.xclient.data.l[4]) == m_nXdndActionMove )
+ dsde.DropAction = DNDConstants::ACTION_MOVE;
+ else if( Atom(rMessage.xclient.data.l[4]) == m_nXdndActionLink )
+ dsde.DropAction = DNDConstants::ACTION_LINK;
+ }
+ else
+ dsde.DropAction = DNDConstants::ACTION_COPY;
+ }
+ m_nTargetAcceptAction = dsde.DropAction;
+
+ if( ! ( rMessage.xclient.data.l[1] & 2 ) )
+ {
+ m_nNoPosX = rMessage.xclient.data.l[2] >> 16;
+ m_nNoPosY = rMessage.xclient.data.l[2] & 0xffff;
+ m_nNoPosWidth = rMessage.xclient.data.l[3] >> 16;
+ m_nNoPosHeight = rMessage.xclient.data.l[3] & 0xffff;
+ }
+ else
+ m_nNoPosX = m_nNoPosY = m_nNoPosWidth = m_nNoPosHeight = 0;
+
+ setCursor( getDefaultCursor( dsde.DropAction ), m_aDropWindow, m_nDragTimestamp );
+ aGuard.clear();
+ m_xDragSourceListener->dragOver( dsde );
+ }
+ else if( Atom(rMessage.xclient.message_type) == m_nXdndFinished && m_aDropWindow == Atom(rMessage.xclient.data.l[0]) )
+ {
+ bHandled = true;
+ // notify the listener
+ DragSourceDropEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ dsde.DropAction = m_nTargetAcceptAction;
+ dsde.DropSuccess = m_bDropSuccess;
+ Reference< XDragSourceListener > xListener( m_xDragSourceListener );
+ m_xDragSourceListener.clear();
+ aGuard.clear();
+ xListener->dragDropEnd( dsde );
+ }
+ }
+ else if( rMessage.type == MotionNotify ||
+ rMessage.type == EnterNotify || rMessage.type == LeaveNotify
+ )
+ {
+ bHandled = true;
+ bool bForce = false;
+ int root_x = rMessage.type == MotionNotify ? rMessage.xmotion.x_root : rMessage.xcrossing.x_root;
+ int root_y = rMessage.type == MotionNotify ? rMessage.xmotion.y_root : rMessage.xcrossing.y_root;
+ XLIB_Window root = rMessage.type == MotionNotify ? rMessage.xmotion.root : rMessage.xcrossing.root;
+ m_nDragTimestamp = rMessage.type == MotionNotify ? rMessage.xmotion.time : rMessage.xcrossing.time;
+
+ aGuard.clear();
+ if( rMessage.type == MotionNotify )
+ {
+ bForce = updateDragAction( rMessage.xmotion.state );
+ }
+ updateDragWindow( root_x, root_y, root );
+ aGuard.reset();
+
+ if( m_nCurrentProtocolVersion >= 0 && m_aDropProxy != None )
+ {
+ aGuard.clear();
+ sendDropPosition( bForce, rMessage.type == MotionNotify ? rMessage.xmotion.time : rMessage.xcrossing.time );
+ }
+ }
+ else if( rMessage.type == XLIB_KeyPress || rMessage.type == KeyRelease )
+ {
+ bHandled = true;
+ KeySym aKey = XKeycodeToKeysym( m_pDisplay, rMessage.xkey.keycode, 0 );
+ if( aKey == XK_Escape )
+ {
+ // abort drag
+ if( it != m_aDropTargets.end() )
+ {
+ DropTargetEvent dte;
+ dte.Source = static_cast< OWeakObject* >( it->second.m_pTarget );
+ aGuard.clear();
+ it->second.m_pTarget->dragExit( dte );
+ }
+ else if( m_aDropProxy != None && m_nCurrentProtocolVersion >= 0 )
+ {
+ // send XdndLeave
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.format = 32;
+ aEvent.xclient.message_type = m_nXdndLeave;
+ aEvent.xclient.window = m_aDropWindow;
+ aEvent.xclient.data.l[0] = m_aWindow;
+ memset( aEvent.xclient.data.l+1, 0, sizeof(long)*4);
+ m_aDropWindow = m_aDropProxy = None;
+ XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
+ }
+ // notify the listener
+ DragSourceDropEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ dsde.DropAction = DNDConstants::ACTION_NONE;
+ dsde.DropSuccess = sal_False;
+ Reference< XDragSourceListener > xListener( m_xDragSourceListener );
+ m_xDragSourceListener.clear();
+ aGuard.clear();
+ xListener->dragDropEnd( dsde );
+ }
+ else
+ {
+ /*
+ * man page says: state is state immediate PRIOR to the
+ * event. It would seem that this is a somewhat arguable
+ * design decision.
+ */
+ int nState = rMessage.xkey.state;
+ int nNewState = 0;
+ switch( aKey )
+ {
+ case XK_Shift_R:
+ case XK_Shift_L: nNewState = ShiftMask;break;
+ case XK_Control_R:
+ case XK_Control_L: nNewState = ControlMask;break;
+ // just interested in shift and ctrl for dnd
+ }
+ if( rMessage.type == XLIB_KeyPress )
+ nState |= nNewState;
+ else
+ nState &= ~nNewState;
+ aGuard.clear();
+ if( updateDragAction( nState ) )
+ sendDropPosition( true, rMessage.xkey.time );
+ }
+ }
+ else if(
+ ( rMessage.type == ButtonPress || rMessage.type == ButtonRelease ) &&
+ rMessage.xbutton.button == m_nDragButton )
+ {
+ bool bCancel = true;
+ if( m_aDropWindow != None )
+ {
+ if( it != m_aDropTargets.end() )
+ {
+ if( it->second.m_pTarget->m_bActive && m_nUserDragAction != DNDConstants::ACTION_NONE && m_bLastDropAccepted )
+ {
+ bHandled = true;
+ int x, y;
+ XLIB_Window aChild;
+ XTranslateCoordinates( m_pDisplay, rMessage.xbutton.root, m_aDropWindow, rMessage.xbutton.x_root, rMessage.xbutton.y_root, &x, &y, &aChild );
+ DropTargetDropEvent dtde;
+ dtde.Source = static_cast< OWeakObject* >(it->second.m_pTarget );
+ dtde.Context = new DropTargetDropContext( m_aCurrentDropWindow, m_nDropTimestamp, *this );
+ dtde.LocationX = x;
+ dtde.LocationY = y;
+ dtde.DropAction = m_nUserDragAction;
+ dtde.SourceActions = m_nSourceActions;
+ dtde.Transferable = m_xDragSourceTransferable;
+ m_bDropSent = true;
+ m_nDropTimeout = time( NULL );
+ m_bDropWaitingForCompletion = true;
+ aGuard.clear();
+ it->second->drop( dtde );
+ bCancel = false;
+ }
+ else bCancel = true;
+ }
+ else if( m_nCurrentProtocolVersion >= 0 )
+ {
+ bHandled = true;
+
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.format = 32;
+ aEvent.xclient.message_type = m_nXdndDrop;
+ aEvent.xclient.window = m_aDropWindow;
+ aEvent.xclient.data.l[0] = m_aWindow;
+ aEvent.xclient.data.l[1] = 0;
+ aEvent.xclient.data.l[2] = rMessage.xbutton.time;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = 0;
+
+ m_bDropSent = true;
+ m_nDropTimeout = time( NULL );
+ XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
+ bCancel = false;
+ }
+ else
+ {
+ // dropping on non XdndWindows: acquire ownership of
+ // PRIMARY and send a middle mouse button click down/up to
+ // target window
+ SelectionAdaptor* pAdaptor = getAdaptor( XA_PRIMARY );
+ if( pAdaptor )
+ {
+ bHandled = true;
+
+ XLIB_Window aDummy;
+ XEvent aEvent;
+ aEvent.type = ButtonPress;
+ aEvent.xbutton.display = m_pDisplay;
+ aEvent.xbutton.window = m_aDropWindow;
+ aEvent.xbutton.root = rMessage.xbutton.root;
+ aEvent.xbutton.subwindow = m_aDropWindow;
+ aEvent.xbutton.time = rMessage.xbutton.time+1;
+ aEvent.xbutton.x_root = rMessage.xbutton.x_root;
+ aEvent.xbutton.y_root = rMessage.xbutton.y_root;
+ aEvent.xbutton.state = rMessage.xbutton.state;
+ aEvent.xbutton.button = Button2;
+ aEvent.xbutton.same_screen = True;
+ XTranslateCoordinates( m_pDisplay,
+ rMessage.xbutton.root, m_aDropWindow,
+ rMessage.xbutton.x_root, rMessage.xbutton.y_root,
+ &aEvent.xbutton.x, &aEvent.xbutton.y,
+ &aDummy );
+ XSendEvent( m_pDisplay, m_aDropWindow, False, ButtonPressMask, &aEvent );
+ aEvent.xbutton.type = ButtonRelease;
+ aEvent.xbutton.time++;
+ aEvent.xbutton.state |= Button2Mask;
+ XSendEvent( m_pDisplay, m_aDropWindow, False, ButtonReleaseMask, &aEvent );
+
+ m_bDropSent = true;
+ m_nDropTimeout = time( NULL );
+ XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
+ m_bWaitingForPrimaryConversion = true;
+ m_bDropSent = true;
+ m_nDropTimeout = time( NULL );
+ // HACK :-)
+ aGuard.clear();
+ static_cast< X11Clipboard* >( pAdaptor )->setContents( m_xDragSourceTransferable, Reference< ::com::sun::star::datatransfer::clipboard::XClipboardOwner >() );
+ aGuard.reset();
+ bCancel = false;
+ }
+ }
+ }
+ if( bCancel )
+ {
+ // cancel drag
+ DragSourceDropEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ dsde.DropAction = DNDConstants::ACTION_NONE;
+ dsde.DropSuccess = sal_False;
+ Reference< XDragSourceListener > xListener( m_xDragSourceListener );
+ m_xDragSourceListener.clear();
+ aGuard.clear();
+ xListener->dragDropEnd( dsde );
+ bHandled = true;
+ }
+ }
+ return bHandled;
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::accept( sal_Int8 dragOperation, XLIB_Window aDropWindow, XLIB_Time )
+{
+ if( aDropWindow == m_aCurrentDropWindow )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "accept: %x\n", dragOperation );
+#endif
+ Atom nAction = None;
+ dragOperation &= (DNDConstants::ACTION_MOVE | DNDConstants::ACTION_COPY | DNDConstants::ACTION_LINK);
+ if( dragOperation & DNDConstants::ACTION_MOVE )
+ nAction = m_nXdndActionMove;
+ else if( dragOperation & DNDConstants::ACTION_COPY )
+ nAction = m_nXdndActionCopy;
+ else if( dragOperation & DNDConstants::ACTION_LINK )
+ nAction = m_nXdndActionLink;
+ m_bLastDropAccepted = true;
+ sendDragStatus( nAction );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::reject( XLIB_Window aDropWindow, XLIB_Time )
+{
+ if( aDropWindow == m_aCurrentDropWindow )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "reject\n" );
+#endif
+ m_bLastDropAccepted = false;
+ sendDragStatus( None );
+ if( m_bDropSent && m_xDragSourceListener.is() )
+ {
+ DragSourceDropEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ dsde.DropAction = DNDConstants::ACTION_NONE;
+ dsde.DropSuccess = sal_False;
+ m_xDragSourceListener->dragDropEnd( dsde );
+ m_xDragSourceListener.clear();
+ }
+ }
+}
+
+/*
+ * XDragSource
+ */
+
+sal_Bool SelectionManager::isDragImageSupported() throw()
+{
+ return sal_False;
+}
+
+// ------------------------------------------------------------------------
+
+sal_Int32 SelectionManager::getDefaultCursor( sal_Int8 dragAction ) throw()
+{
+ XLIB_Cursor aCursor = m_aNoneCursor;
+ if( dragAction & DNDConstants::ACTION_MOVE )
+ aCursor = m_aMoveCursor;
+ else if( dragAction & DNDConstants::ACTION_COPY )
+ aCursor = m_aCopyCursor;
+ else if( dragAction & DNDConstants::ACTION_LINK )
+ aCursor = m_aLinkCursor;
+ return aCursor;
+}
+
+// ------------------------------------------------------------------------
+
+int SelectionManager::getXdndVersion( XLIB_Window aWindow, XLIB_Window& rProxy )
+{
+ Atom* pProperties = NULL;
+ int nProperties = 0;
+ Atom nType;
+ int nFormat;
+ unsigned long nItems, nBytes;
+ unsigned char* pBytes = NULL;
+
+ int nVersion = -1;
+ rProxy = None;
+
+ /*
+ * XListProperties is used here to avoid unnecessary XGetWindowProperty calls
+ * and therefore reducing latency penalty
+ */
+ pProperties = XListProperties( m_pDisplay, aWindow, &nProperties );
+ // first look for proxy
+ int i;
+ for( i = 0; i < nProperties; i++ )
+ {
+ if( pProperties[i] == m_nXdndProxy )
+ {
+ XGetWindowProperty( m_pDisplay, aWindow, m_nXdndProxy, 0, 1, False, XA_WINDOW,
+ &nType, &nFormat, &nItems, &nBytes, &pBytes );
+ if( pBytes )
+ {
+ if( nType == XA_WINDOW )
+ rProxy = *(XLIB_Window*)pBytes;
+ XFree( pBytes );
+ pBytes = NULL;
+ if( rProxy != None )
+ {
+ // now check proxy wether it points to itself
+ XGetWindowProperty( m_pDisplay, rProxy, m_nXdndProxy, 0, 1, False, XA_WINDOW,
+ &nType, &nFormat, &nItems, &nBytes, &pBytes );
+ if( pBytes )
+ {
+ if( nType == XA_WINDOW && *(XLIB_Window*)pBytes != rProxy )
+ rProxy = None;
+ XFree( pBytes );
+ pBytes = NULL;
+ }
+ else
+ rProxy = None;
+ }
+ }
+ break;
+ }
+ }
+ XLIB_Window aAwareWindow = rProxy != None ? rProxy : aWindow;
+
+ XGetWindowProperty( m_pDisplay, aAwareWindow, m_nXdndAware, 0, 1, False, XA_ATOM,
+ &nType, &nFormat, &nItems, &nBytes, &pBytes );
+ if( pBytes )
+ {
+ if( nType == XA_ATOM )
+ nVersion = *(Atom*)pBytes;
+ XFree( pBytes );
+ }
+
+ nVersion = nVersion > nXdndProtocolRevision ? nXdndProtocolRevision : nVersion;
+
+ return nVersion;
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::updateDragWindow( int nX, int nY, XLIB_Window aRoot )
+{
+ ResettableMutexGuard aGuard( m_aMutex );
+
+ Reference< XDragSourceListener > xListener( m_xDragSourceListener );
+
+ m_nLastDragX = nX;
+ m_nLastDragY = nY;
+
+ XLIB_Window aParent = aRoot;
+ XLIB_Window aChild;
+ XLIB_Window aNewProxy = None, aNewCurrentWindow = None;
+ int nNewProtocolVersion = -1;
+ int nWinX, nWinY;
+
+ // find the first XdndAware window or check if root window is
+ // XdndAware or has XdndProxy
+ do
+ {
+ XTranslateCoordinates( m_pDisplay, aRoot, aParent, nX, nY, &nWinX, &nWinY, &aChild );
+ if( aChild != None )
+ {
+ if( aChild == m_aCurrentDropWindow && aChild != aRoot && m_nCurrentProtocolVersion >= 0 )
+ {
+ aParent = aChild;
+ break;
+ }
+ nNewProtocolVersion = getXdndVersion( aChild, aNewProxy );
+ aParent = aChild;
+ }
+ } while( aChild != None && nNewProtocolVersion < 0 );
+
+ aNewCurrentWindow = aParent;
+ if( aNewCurrentWindow == aRoot )
+ {
+ // no children, try root drop
+ nNewProtocolVersion = getXdndVersion( aNewCurrentWindow, aNewProxy );
+ if( nNewProtocolVersion < 3 )
+ {
+ aNewCurrentWindow = aNewProxy = None;
+ nNewProtocolVersion = nXdndProtocolRevision;
+ }
+ }
+
+
+ DragSourceDragEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ dsde.DropAction = nNewProtocolVersion >= 0 ? m_nUserDragAction : DNDConstants::ACTION_COPY;
+ dsde.UserAction = nNewProtocolVersion >= 0 ? m_nUserDragAction : DNDConstants::ACTION_COPY;
+
+ ::std::hash_map< XLIB_Window, DropTargetEntry >::const_iterator it;
+ if( aNewCurrentWindow != m_aDropWindow )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "drag left window 0x%lx (rev. %d), entered window 0x%lx (rev %d)\n", m_aDropWindow, m_nCurrentProtocolVersion, aNewCurrentWindow, nNewProtocolVersion );
+#endif
+
+ if( m_aDropWindow != None )
+ {
+ it = m_aDropTargets.find( m_aDropWindow );
+ if( it != m_aDropTargets.end() )
+ // shortcut for own drop targets
+ {
+ DropTargetEvent dte;
+ dte.Source = static_cast< OWeakObject* >( it->second.m_pTarget );
+ aGuard.clear();
+ it->second.m_pTarget->dragExit( dte );
+ aGuard.reset();
+ }
+ else
+ {
+ // send old drop target a XdndLeave
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.format = 32;
+ aEvent.xclient.message_type = m_nXdndLeave;
+ aEvent.xclient.window = m_aDropWindow;
+ aEvent.xclient.data.l[0] = m_aWindow;
+ aEvent.xclient.data.l[1] = 0;
+ XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
+ }
+ if( xListener.is() )
+ {
+ aGuard.clear();
+ xListener->dragExit( dsde );
+ aGuard.reset();
+ }
+ }
+
+ m_nCurrentProtocolVersion = nNewProtocolVersion;
+ m_aDropWindow = aNewCurrentWindow;
+ m_aDropProxy = aNewProxy != None ? aNewProxy : m_aDropWindow;
+
+ it = m_aDropTargets.find( m_aDropWindow );
+ if( it != m_aDropTargets.end() && ! it->second.m_pTarget->m_bActive )
+ m_aDropProxy = None;
+
+ if( m_aDropProxy != None && xListener.is() )
+ {
+ aGuard.clear();
+ xListener->dragEnter( dsde );
+ aGuard.reset();
+ }
+ // send XdndEnter
+ if( m_aDropProxy != None && m_nCurrentProtocolVersion >= 0 )
+ {
+ it = m_aDropTargets.find( m_aDropWindow );
+ if( it != m_aDropTargets.end() )
+ {
+ XTranslateCoordinates( m_pDisplay, aRoot, m_aDropWindow, nX, nY, &nWinX, &nWinY, &aChild );
+ DropTargetDragEnterEvent dtde;
+ dtde.Source = static_cast< OWeakObject* >( it->second.m_pTarget );
+ dtde.Context = new DropTargetDragContext( m_aCurrentDropWindow, m_nDropTimestamp, *this );
+ dtde.LocationX = nWinX;
+ dtde.LocationY = nWinY;
+ dtde.DropAction = m_nUserDragAction;
+ dtde.SourceActions = m_nSourceActions;
+ dtde.SupportedDataFlavors = m_xDragSourceTransferable->getTransferDataFlavors();
+ aGuard.clear();
+ it->second.m_pTarget->dragEnter( dtde );
+ aGuard.reset();
+ }
+ else
+ {
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.format = 32;
+ aEvent.xclient.message_type = m_nXdndEnter;
+ aEvent.xclient.window = m_aDropWindow;
+ aEvent.xclient.data.l[0] = m_aWindow;
+ aEvent.xclient.data.l[1] = m_nCurrentProtocolVersion << 24;
+ memset( aEvent.xclient.data.l + 2, 0, sizeof( long )*3 );
+ // fill in data types
+ ::std::list< Atom > aConversions;
+ getNativeTypeList( m_aDragFlavors, aConversions, m_nXdndSelection );
+ if( aConversions.size() > 3 )
+ aEvent.xclient.data.l[1] |= 1;
+ ::std::list< Atom >::const_iterator type_it = aConversions.begin();
+ for( int i = 0; type_it != aConversions.end() && i < 3; i++, ++type_it )
+ aEvent.xclient.data.l[i+2] = *type_it;
+ XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
+ }
+ }
+ m_nNoPosX = m_nNoPosY = m_nNoPosWidth = m_nNoPosHeight = 0;
+ }
+ else if( m_aDropProxy != None && xListener.is() )
+ {
+ aGuard.clear();
+ // drag over for XdndAware windows comes when receiving XdndStatus
+ xListener->dragOver( dsde );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::startDrag(
+ const DragGestureEvent& trigger,
+ sal_Int8 sourceActions,
+ sal_Int32,
+ sal_Int32,
+ const Reference< XTransferable >& transferable,
+ const Reference< XDragSourceListener >& listener
+ ) throw()
+{
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "startDrag( sourceActions = %x )\n", (int)sourceActions );
+#endif
+
+ DragSourceDropEvent aDragFailedEvent;
+ aDragFailedEvent.Source = static_cast< OWeakObject* >(this);
+ aDragFailedEvent.DragSource = static_cast< XDragSource* >(this);
+ aDragFailedEvent.DragSourceContext = new DragSourceContext( None, CurrentTime, *this );
+ aDragFailedEvent.DropAction = DNDConstants::ACTION_NONE;
+ aDragFailedEvent.DropSuccess = sal_False;
+
+ if( m_aDragRunning.check() )
+ {
+ if( listener.is() )
+ listener->dragDropEnd( aDragFailedEvent );
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "*** ERROR *** second drag and drop started.\n" );
+ if( m_xDragSourceListener.is() )
+ fprintf( stderr, "*** ERROR *** drag source listener already set.\n" );
+ else
+ fprintf( stderr, "*** ERROR *** drag thread already running.\n" );
+#endif
+ return;
+ }
+
+ {
+ ClearableMutexGuard aGuard(m_aMutex);
+
+ // first get the current pointer position and the window that
+ // the pointer is located in. since said window should be one
+ // of our DropTargets at the time of executeDrag we can use
+ // them for a start
+ XLIB_Window aRoot, aParent, aChild;
+ int root_x, root_y, win_x, win_y;
+ unsigned int mask;
+
+ ::std::hash_map< XLIB_Window, DropTargetEntry >::const_iterator it;
+ it = m_aDropTargets.begin();
+ while( it != m_aDropTargets.end() )
+ {
+ if( XQueryPointer( m_pDisplay, it->second.m_aRootWindow,
+ &aRoot, &aParent,
+ &root_x, &root_y,
+ &win_x, &win_y,
+ &mask ) )
+ {
+ aParent = it->second.m_aRootWindow;
+ break;
+ }
+ ++it;
+ }
+
+ // don't start DnD if there is none of our windows on the same screen as
+ // the pointer or if no mouse button is pressed
+ if( it == m_aDropTargets.end() || (mask & (Button1Mask|Button2Mask|Button3Mask)) == 0 )
+ {
+ aGuard.clear();
+ if( listener.is() )
+ listener->dragDropEnd( aDragFailedEvent );
+ return;
+ }
+
+ // try to find which of our drop targets is the drag source
+ // if that drop target is deregistered we should stop executing
+ // the drag (actually this is a poor substitute for an "endDrag"
+ // method ).
+ m_aDragSourceWindow = None;
+ aParent = aRoot = it->second.m_aRootWindow;
+ do
+ {
+ XTranslateCoordinates( m_pDisplay, aRoot, aParent, root_x, root_y, &win_x, &win_y, &aChild );
+ if( aChild != None && m_aDropTargets.find( aChild ) != m_aDropTargets.end() )
+ {
+ m_aDragSourceWindow = aChild;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "found drag source window 0x%lx\n", m_aDragSourceWindow );
+#endif
+ break;
+ }
+ aParent = aChild;
+ } while( aChild != None );
+
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "try to grab pointer ... " );
+#endif
+ int nPointerGrabSuccess =
+ XGrabPointer( m_pDisplay, it->second.m_aRootWindow, True,
+ DRAG_EVENT_MASK,
+ GrabModeAsync, GrabModeAsync,
+ None,
+ None,
+ CurrentTime );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%d\n", nPointerGrabSuccess );
+#endif
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "try to grab keyboard ... " );
+#endif
+ int nKeyboardGrabSuccess =
+ XGrabKeyboard( m_pDisplay, it->second.m_aRootWindow, True,
+ GrabModeAsync, GrabModeAsync, CurrentTime );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%d\n", nKeyboardGrabSuccess );
+#endif
+ if( nPointerGrabSuccess != GrabSuccess || nKeyboardGrabSuccess != GrabSuccess )
+ {
+ if( nPointerGrabSuccess == GrabSuccess )
+ XUngrabPointer( m_pDisplay, CurrentTime );
+ if( nKeyboardGrabSuccess == GrabSuccess )
+ XUngrabKeyboard( m_pDisplay, CurrentTime );
+ XFlush( m_pDisplay );
+ aGuard.clear();
+ if( listener.is() )
+ listener->dragDropEnd( aDragFailedEvent );
+ return;
+ }
+
+ m_xDragSourceTransferable = transferable;
+ m_xDragSourceListener = listener;
+ m_aDragFlavors = transferable->getTransferDataFlavors();
+ m_aCurrentCursor = None;
+
+ requestOwnership( m_nXdndSelection );
+
+ ::std::list< Atom > aConversions;
+ ::std::list< Atom >::const_iterator type_it;
+ getNativeTypeList( m_aDragFlavors, aConversions, m_nXdndSelection );
+
+ int nTypes = aConversions.size();
+ Atom* pTypes = (Atom*)alloca( sizeof(Atom)*nTypes );
+ type_it = aConversions.begin();
+ for( int n = 0; n < nTypes; n++, ++type_it )
+ pTypes[n] = *type_it;
+
+ XChangeProperty( m_pDisplay, m_aWindow, m_nXdndTypeList, XA_ATOM, 32, PropModeReplace, (unsigned char*)pTypes, nTypes );
+
+ m_nSourceActions = sourceActions | DNDConstants::ACTION_DEFAULT;
+ m_nUserDragAction = DNDConstants::ACTION_MOVE & m_nSourceActions;
+ if( ! m_nUserDragAction )
+ m_nUserDragAction = DNDConstants::ACTION_COPY & m_nSourceActions;
+ if( ! m_nUserDragAction )
+ m_nUserDragAction = DNDConstants::ACTION_LINK & m_nSourceActions;
+ m_nTargetAcceptAction = DNDConstants::ACTION_DEFAULT;
+ m_bDropSent = false;
+ m_bDropSuccess = false;
+ m_bWaitingForPrimaryConversion = false;
+ m_nDragButton = Button1; // default to left button
+ com::sun::star::awt::MouseEvent aEvent;
+ if( trigger.Event >>= aEvent )
+ {
+ if( aEvent.Buttons & MouseButton::LEFT )
+ m_nDragButton = Button1;
+ else if( aEvent.Buttons & MouseButton::RIGHT )
+ m_nDragButton = Button3;
+ else if( aEvent.Buttons & MouseButton::MIDDLE )
+ m_nDragButton = Button2;
+ }
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "m_nUserDragAction = %x\n", (int)m_nUserDragAction );
+#endif
+ updateDragWindow( root_x, root_y, aRoot );
+ m_nUserDragAction = ~0;
+ updateDragAction( mask );
+ }
+
+ m_aDragRunning.set();
+ m_aDragExecuteThread = osl_createSuspendedThread( call_SelectionManager_runDragExecute, this );
+ if( m_aDragExecuteThread )
+ osl_resumeThread( m_aDragExecuteThread );
+ else
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "osl_createSuspendedThread failed for drag execute\n" );
+#endif
+ m_xDragSourceListener.clear();
+ m_xDragSourceTransferable.clear();
+
+ m_bDropSent = false;
+ m_bDropSuccess = false;
+ m_bWaitingForPrimaryConversion = false;
+ m_aDropWindow = None;
+ m_aDropProxy = None;
+ m_nCurrentProtocolVersion = nXdndProtocolRevision;
+ m_nNoPosX = 0;
+ m_nNoPosY = 0;
+ m_nNoPosWidth = 0;
+ m_nNoPosHeight = 0;
+ m_aCurrentCursor = None;
+
+ XUngrabPointer( m_pDisplay, CurrentTime );
+ XUngrabKeyboard( m_pDisplay, CurrentTime );
+ XFlush( m_pDisplay );
+
+ m_aDragRunning.reset();
+
+ if( listener.is() )
+ listener->dragDropEnd( aDragFailedEvent );
+ }
+}
+
+void SelectionManager::runDragExecute( void* pThis )
+{
+ SelectionManager* This = (SelectionManager*)pThis;
+ This->dragDoDispatch();
+}
+
+void SelectionManager::dragDoDispatch()
+{
+
+ // do drag
+ // m_xDragSourceListener will be cleared on finished drop
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "begin executeDrag dispatching\n" );
+#endif
+ TimeValue aTVal;
+ aTVal.Seconds = 0;
+ aTVal.Nanosec = 200000000;
+ oslThread aThread = m_aDragExecuteThread;
+ while( m_xDragSourceListener.is() && ( ! m_bDropSent || time(NULL)-m_nDropTimeout < 5 ) && osl_scheduleThread( aThread ) )
+ {
+ // let the thread in the run method do the dispatching
+ // just look occasionally here whether drop timed out or is completed
+ osl_waitThread( &aTVal );
+ }
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "end executeDrag dispatching\n" );
+#endif
+ {
+ ClearableMutexGuard aGuard(m_aMutex);
+
+ Reference< XDragSourceListener > xListener( m_xDragSourceListener );
+ Reference< XTransferable > xTransferable( m_xDragSourceTransferable );
+ m_xDragSourceListener.clear();
+ m_xDragSourceTransferable.clear();
+
+ DragSourceDropEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ dsde.DropAction = DNDConstants::ACTION_NONE;
+ dsde.DropSuccess = sal_False;
+
+ // cleanup after drag
+ if( m_bWaitingForPrimaryConversion )
+ getAdaptor( XA_PRIMARY )->clearTransferable();
+
+ m_bDropSent = false;
+ m_bDropSuccess = false;
+ m_bWaitingForPrimaryConversion = false;
+ m_aDropWindow = None;
+ m_aDropProxy = None;
+ m_nCurrentProtocolVersion = nXdndProtocolRevision;
+ m_nNoPosX = 0;
+ m_nNoPosY = 0;
+ m_nNoPosWidth = 0;
+ m_nNoPosHeight = 0;
+ m_aCurrentCursor = None;
+
+ XUngrabPointer( m_pDisplay, CurrentTime );
+ XUngrabKeyboard( m_pDisplay, CurrentTime );
+ XFlush( m_pDisplay );
+
+ m_aDragExecuteThread = NULL;
+ m_aDragRunning.reset();
+
+ aGuard.clear();
+ if( xListener.is() )
+ {
+ xTransferable.clear();
+ xListener->dragDropEnd( dsde );
+ }
+ }
+ osl_destroyThread( aThread );
+}
+
+/*
+ * XDragSourceContext
+ */
+
+sal_Int32 SelectionManager::getCurrentCursor()
+{
+ return m_aCurrentCursor;
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::setCursor( sal_Int32 cursor, XLIB_Window aDropWindow, XLIB_Time )
+{
+ MutexGuard aGuard( m_aMutex );
+ if( aDropWindow == m_aDropWindow && XLIB_Cursor(cursor) != m_aCurrentCursor )
+ {
+ if( m_xDragSourceListener.is() && ! m_bDropSent )
+ {
+ m_aCurrentCursor = cursor;
+ XChangeActivePointerGrab( m_pDisplay, DRAG_EVENT_MASK, cursor, CurrentTime );
+ XFlush( m_pDisplay );
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::setImage( sal_Int32, XLIB_Window, XLIB_Time )
+{
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::transferablesFlavorsChanged()
+{
+ MutexGuard aGuard(m_aMutex);
+
+ m_aDragFlavors = m_xDragSourceTransferable->getTransferDataFlavors();
+ int i;
+
+ std::list< Atom > aConversions;
+ std::list< Atom >::const_iterator type_it;
+
+ getNativeTypeList( m_aDragFlavors, aConversions, m_nXdndSelection );
+
+ int nTypes = aConversions.size();
+ Atom* pTypes = (Atom*)alloca( sizeof(Atom)*aConversions.size() );
+ for( i = 0, type_it = aConversions.begin(); type_it != aConversions.end(); ++type_it, i++ )
+ pTypes[i] = *type_it;
+ XChangeProperty( m_pDisplay, m_aWindow, m_nXdndTypeList, XA_ATOM, 32, PropModeReplace, (unsigned char*)pTypes, nTypes );
+
+ if( m_aCurrentDropWindow != None && m_nCurrentProtocolVersion >= 0 )
+ {
+ // send synthetic leave and enter events
+
+ XEvent aEvent;
+
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.format = 32;
+ aEvent.xclient.window = m_aDropWindow;
+ aEvent.xclient.data.l[0] = m_aWindow;
+
+ aEvent.xclient.message_type = m_nXdndLeave;
+ aEvent.xclient.data.l[1] = 0;
+ XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
+
+ aEvent.xclient.message_type = m_nXdndEnter;
+ aEvent.xclient.data.l[1] = m_nCurrentProtocolVersion << 24;
+ memset( aEvent.xclient.data.l + 2, 0, sizeof( long )*3 );
+ // fill in data types
+ if( nTypes > 3 )
+ aEvent.xclient.data.l[1] |= 1;
+ for( int j = 0; j < nTypes && j < 3; j++ )
+ aEvent.xclient.data.l[j+2] = pTypes[j];
+
+ XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
+ }
+}
+
+/*
+ * dispatch loop
+ */
+
+// ------------------------------------------------------------------------
+
+bool SelectionManager::handleXEvent( XEvent& rEvent )
+{
+ /*
+ * since we are XConnectionListener to a second X display
+ * to get client messages it is essential not to dispatch
+ * events twice that we get on both connections
+ *
+ * #95201# between dispatching ButtonPress and startDrag
+ * the user can already have released the mouse. The ButtonRelease
+ * will then be dispatched in VCLs queue and never turn up here.
+ * Which is not so good, since startDrag will XGrabPointer and
+ * XGrabKeyboard -> solid lock.
+ */
+ if( rEvent.xany.display != m_pDisplay
+ && rEvent.type != ClientMessage
+ && rEvent.type != ButtonPress
+ && rEvent.type != ButtonRelease
+ )
+ return false;
+
+ bool bHandled = false;
+ switch (rEvent.type)
+ {
+ case SelectionClear:
+ {
+ ClearableMutexGuard aGuard(m_aMutex);
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "SelectionClear for selection %s\n",
+ OUStringToOString( getString( rEvent.xselectionclear.selection ), RTL_TEXTENCODING_ISO_8859_1 ).getStr()
+ );
+#endif
+ SelectionAdaptor* pAdaptor = getAdaptor( rEvent.xselectionclear.selection );
+ std::hash_map< Atom, Selection* >::iterator it( m_aSelections.find( rEvent.xselectionclear.selection ) );
+ if( it != m_aSelections.end() )
+ it->second->m_bOwner = false;
+ aGuard.clear();
+ if ( pAdaptor )
+ pAdaptor->clearTransferable();
+ }
+ break;
+
+ case SelectionRequest:
+ bHandled = handleSelectionRequest( rEvent.xselectionrequest );
+ break;
+ case PropertyNotify:
+ if( rEvent.xproperty.window == m_aWindow ||
+ rEvent.xproperty.window == m_aCurrentDropWindow
+ )
+ bHandled = handleReceivePropertyNotify( rEvent.xproperty );
+ else
+ bHandled = handleSendPropertyNotify( rEvent.xproperty );
+ break;
+ case SelectionNotify:
+ bHandled = handleSelectionNotify( rEvent.xselection );
+ break;
+ case ClientMessage:
+ // messages from drag target
+ if( rEvent.xclient.message_type == m_nXdndStatus ||
+ rEvent.xclient.message_type == m_nXdndFinished )
+ bHandled = handleDragEvent( rEvent );
+ // messages from drag source
+ else if(
+ rEvent.xclient.message_type == m_nXdndEnter ||
+ rEvent.xclient.message_type == m_nXdndLeave ||
+ rEvent.xclient.message_type == m_nXdndPosition ||
+ rEvent.xclient.message_type == m_nXdndDrop
+ )
+ bHandled = handleDropEvent( rEvent.xclient );
+ break;
+ case EnterNotify:
+ case LeaveNotify:
+ case MotionNotify:
+ case ButtonPress:
+ case ButtonRelease:
+ case XLIB_KeyPress:
+ case KeyRelease:
+ bHandled = handleDragEvent( rEvent );
+ break;
+ default:
+ ;
+ }
+ return bHandled;
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::dispatchEvent( int millisec )
+{
+ pollfd aPollFD;
+ XEvent event;
+
+ // query socket handle to poll on
+ aPollFD.fd = ConnectionNumber( m_pDisplay );
+ aPollFD.events = POLLIN;
+ aPollFD.revents = 0;
+
+ // wait for activity (outside the xlib)
+ if( poll( &aPollFD, 1, millisec ) > 0 )
+ {
+ // now acquire the mutex to prevent other threads
+ // from using the same X connection
+ ResettableMutexGuard aGuard(m_aMutex);
+
+ // prevent that another thread already ate the input
+ // this can happen if e.g. another thread does
+ // an X request getting a response. the response
+ // would be removed from the queue and we would end up
+ // with an empty socket here
+ if( poll( &aPollFD, 1, 0 ) > 0 )
+ {
+ int nPending = 1;
+ while( nPending )
+ {
+ nPending = XPending( m_pDisplay );
+ if( nPending )
+ {
+ XNextEvent( m_pDisplay, &event );
+ aGuard.clear();
+ handleXEvent( event );
+ aGuard.reset();
+ }
+ }
+ }
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::run( void* pThis )
+{
+#if OSL_DEBUG_LEVEL > 1
+ fprintf(stderr, "SelectionManager::run\n" );
+#endif
+ // dispatch until the cows come home
+
+ SelectionManager* This = (SelectionManager*)pThis;
+
+ timeval aLast;
+ gettimeofday( &aLast, 0 );
+
+ Reference< XMultiServiceFactory > xFact( ::comphelper::getProcessServiceFactory() );
+ if( xFact.is() )
+ {
+ Reference< XDesktop > xDesktop( xFact->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.frame.Desktop" ) ), UNO_QUERY );
+ if( xDesktop.is() )
+ xDesktop->addTerminateListener(This);
+ }
+
+ while( osl_scheduleThread(This->m_aThread) )
+ {
+ This->dispatchEvent( 1000 );
+
+ timeval aNow;
+ gettimeofday( &aNow, 0 );
+
+ if( (aNow.tv_sec - aLast.tv_sec) > 0 )
+ {
+ ClearableMutexGuard aGuard(This->m_aMutex);
+ std::list< std::pair< SelectionAdaptor*, Reference< XInterface > > > aChangeList;
+
+ for( std::hash_map< Atom, Selection* >::iterator it = This->m_aSelections.begin(); it != This->m_aSelections.end(); ++it )
+ {
+ if( it->first != This->m_nXdndSelection && ! it->second->m_bOwner )
+ {
+ XLIB_Window aOwner = XGetSelectionOwner( This->m_pDisplay, it->first );
+ if( aOwner != it->second->m_aLastOwner )
+ {
+ it->second->m_aLastOwner = aOwner;
+ std::pair< SelectionAdaptor*, Reference< XInterface > >
+ aKeep( it->second->m_pAdaptor, it->second->m_pAdaptor->getReference() );
+ aChangeList.push_back( aKeep );
+ }
+ }
+ }
+ aGuard.clear();
+ while( aChangeList.begin() != aChangeList.end() )
+ {
+ aChangeList.front().first->fireContentsChanged();
+ aChangeList.pop_front();
+ }
+ aLast = aNow;
+ }
+ }
+#if OSL_DEBUG_LEVEL > 1
+ fprintf(stderr, "SelectionManager::run end\n" );
+#endif
+}
+
+void SelectionManager::shutdown() throw()
+{
+ ResettableMutexGuard aGuard(m_aMutex);
+ // stop dispatching
+ if( m_aThread )
+ {
+ osl_terminateThread( m_aThread );
+ /*
+ * Allow thread to finish before app exits to avoid pulling the carpet
+ * out from under it if pasting is occuring during shutdown
+ *
+ * a) allow it to have the Mutex and
+ * b) reschedule to allow it to complete callbacks to any
+ * Application::GetSolarMutex protected regions, etc. e.g.
+ * TransferableHelper::getTransferDataFlavors (via
+ * SelectionManager::handleSelectionRequest) which it might
+ * currently be trying to enter.
+ *
+ * Otherwise the thread may be left still waiting on a GlobalMutex
+ * when that gets destroyed, letting the thread blow up and die
+ * when enters the section in a now dead OOo instance.
+ */
+ aGuard.clear();
+ while (osl_isThreadRunning(m_aThread))
+ {
+ vos::OGuard guard2(Application::GetSolarMutex());
+ Application::Reschedule();
+ }
+ osl_joinWithThread( m_aThread );
+ osl_destroyThread( m_aThread );
+ m_aThread = NULL;
+ aGuard.reset();
+ }
+ m_xDisplayConnection->removeEventHandler( Any(), this );
+ m_xDisplayConnection.clear();
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool SelectionManager::handleEvent( const Any& event ) throw()
+{
+ Sequence< sal_Int8 > aSeq;
+ if( (event >>= aSeq) )
+ {
+ XEvent* pEvent = (XEvent*)aSeq.getArray();
+ XLIB_Time nTimestamp = CurrentTime;
+ if( pEvent->type == ButtonPress || pEvent->type == ButtonRelease )
+ nTimestamp = pEvent->xbutton.time;
+ else if( pEvent->type == XLIB_KeyPress || pEvent->type == KeyRelease )
+ nTimestamp = pEvent->xkey.time;
+ else if( pEvent->type == MotionNotify )
+ nTimestamp = pEvent->xmotion.time;
+ else if( pEvent->type == PropertyNotify )
+ nTimestamp = pEvent->xproperty.time;
+
+ if( nTimestamp != CurrentTime )
+ {
+ MutexGuard aGuard(m_aMutex);
+
+ m_nSelectionTimestamp = nTimestamp;
+ }
+
+ return sal_Bool( handleXEvent( *pEvent ) );
+ }
+ else
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "SelectionManager got downing event\n" );
+ #endif
+ shutdown();
+ }
+ return sal_True;
+}
+
+void SAL_CALL SelectionManager::disposing( const ::com::sun::star::lang::EventObject& )
+ throw( ::com::sun::star::uno::RuntimeException )
+{
+}
+
+void SAL_CALL SelectionManager::queryTermination( const ::com::sun::star::lang::EventObject& )
+ throw( ::com::sun::star::frame::TerminationVetoException, ::com::sun::star::uno::RuntimeException )
+{
+}
+
+/*
+ * To be safe, shutdown needs to be called before the ~SfxApplication is called, waiting until
+ * the downing event can be too late if paste are requested during shutdown and ~SfxApplication
+ * has been called before vcl is shutdown
+ */
+void SAL_CALL SelectionManager::notifyTermination( const ::com::sun::star::lang::EventObject& rEvent )
+ throw( ::com::sun::star::uno::RuntimeException )
+{
+ Reference< XDesktop > xDesktop( rEvent.Source, UNO_QUERY );
+ if( xDesktop.is() == sal_True )
+ xDesktop->removeTerminateListener( this );
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "SelectionManager got app termination event\n" );
+ #endif
+ shutdown();
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::registerHandler( Atom selection, SelectionAdaptor& rAdaptor )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ Selection* pNewSelection = new Selection();
+ pNewSelection->m_pAdaptor = &rAdaptor;
+ pNewSelection->m_aAtom = selection;
+ m_aSelections[ selection ] = pNewSelection;
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::deregisterHandler( Atom selection )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ ::std::hash_map< Atom, Selection* >::iterator it =
+ m_aSelections.find( selection );
+ if( it != m_aSelections.end() )
+ {
+ delete it->second->m_pPixmap;
+ delete it->second;
+ m_aSelections.erase( it );
+ }
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::registerDropTarget( XLIB_Window aWindow, DropTarget* pTarget )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ // sanity check
+ ::std::hash_map< XLIB_Window, DropTargetEntry >::const_iterator it =
+ m_aDropTargets.find( aWindow );
+ if( it != m_aDropTargets.end() )
+ OSL_ASSERT( "attempt to register window as drop target twice" );
+ else if( aWindow && m_pDisplay )
+ {
+ XSelectInput( m_pDisplay, aWindow, PropertyChangeMask );
+
+ // set XdndAware
+ XChangeProperty( m_pDisplay, aWindow, m_nXdndAware, XA_ATOM, 32, PropModeReplace, (unsigned char*)&nXdndProtocolRevision, 1 );
+
+ DropTargetEntry aEntry( pTarget );
+ // get root window of window (in 99.999% of all cases this will be
+ // DefaultRootWindow( m_pDisplay )
+ int x, y;
+ unsigned int w, h, bw, d;
+ XGetGeometry( m_pDisplay, aWindow, &aEntry.m_aRootWindow,
+ &x, &y, &w, &h, &bw, &d );
+ m_aDropTargets[ aWindow ] = aEntry;
+ }
+ else
+ OSL_ASSERT( "attempt to register None as drop target" );
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::deregisterDropTarget( XLIB_Window aWindow )
+{
+ ClearableMutexGuard aGuard(m_aMutex);
+
+ m_aDropTargets.erase( aWindow );
+ if( aWindow == m_aDragSourceWindow && m_aDragRunning.check() )
+ {
+ // abort drag
+ std::hash_map< XLIB_Window, DropTargetEntry >::const_iterator it =
+ m_aDropTargets.find( m_aDropWindow );
+ if( it != m_aDropTargets.end() )
+ {
+ DropTargetEvent dte;
+ dte.Source = static_cast< OWeakObject* >( it->second.m_pTarget );
+ aGuard.clear();
+ it->second.m_pTarget->dragExit( dte );
+ }
+ else if( m_aDropProxy != None && m_nCurrentProtocolVersion >= 0 )
+ {
+ // send XdndLeave
+ XEvent aEvent;
+ aEvent.type = ClientMessage;
+ aEvent.xclient.display = m_pDisplay;
+ aEvent.xclient.format = 32;
+ aEvent.xclient.message_type = m_nXdndLeave;
+ aEvent.xclient.window = m_aDropWindow;
+ aEvent.xclient.data.l[0] = m_aWindow;
+ memset( aEvent.xclient.data.l+1, 0, sizeof(long)*4);
+ m_aDropWindow = m_aDropProxy = None;
+ XSendEvent( m_pDisplay, m_aDropProxy, False, NoEventMask, &aEvent );
+ }
+ // notify the listener
+ DragSourceDropEvent dsde;
+ dsde.Source = static_cast< OWeakObject* >(this);
+ dsde.DragSourceContext = new DragSourceContext( m_aDropWindow, m_nDragTimestamp, *this );
+ dsde.DragSource = static_cast< XDragSource* >(this);
+ dsde.DropAction = DNDConstants::ACTION_NONE;
+ dsde.DropSuccess = sal_False;
+ Reference< XDragSourceListener > xListener( m_xDragSourceListener );
+ m_xDragSourceListener.clear();
+ aGuard.clear();
+ xListener->dragDropEnd( dsde );
+ }
+}
+
+/*
+ * SelectionAdaptor
+ */
+
+Reference< XTransferable > SelectionManager::getTransferable() throw()
+{
+ return m_xDragSourceTransferable;
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::clearTransferable() throw()
+{
+ m_xDragSourceTransferable.clear();
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManager::fireContentsChanged() throw()
+{
+}
+
+// ------------------------------------------------------------------------
+
+Reference< XInterface > SelectionManager::getReference() throw()
+{
+ return Reference< XInterface >( static_cast<OWeakObject*>(this) );
+}
+
+// ------------------------------------------------------------------------
+
+/*
+ * SelectionManagerHolder
+ */
+
+SelectionManagerHolder::SelectionManagerHolder() :
+ ::cppu::WeakComponentImplHelper3<
+ XDragSource,
+ XInitialization,
+ XServiceInfo > (m_aMutex)
+{
+}
+
+// ------------------------------------------------------------------------
+
+SelectionManagerHolder::~SelectionManagerHolder()
+{
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManagerHolder::initialize( const Sequence< Any >& arguments ) throw( ::com::sun::star::uno::Exception )
+{
+ OUString aDisplayName;
+
+ if( arguments.getLength() > 0 )
+ {
+ Reference< XDisplayConnection > xConn;
+ arguments.getConstArray()[0] >>= xConn;
+ if( xConn.is() )
+ {
+ Any aIdentifier;
+ aIdentifier >>= aDisplayName;
+ }
+ }
+
+ SelectionManager& rManager = SelectionManager::get( aDisplayName );
+ rManager.initialize( arguments );
+ m_xRealDragSource = static_cast< XDragSource* >(&rManager);
+}
+
+/*
+ * XDragSource
+ */
+
+sal_Bool SelectionManagerHolder::isDragImageSupported() throw()
+{
+ return m_xRealDragSource.is() ? m_xRealDragSource->isDragImageSupported() : sal_False;
+}
+
+// ------------------------------------------------------------------------
+
+sal_Int32 SelectionManagerHolder::getDefaultCursor( sal_Int8 dragAction ) throw()
+{
+ return m_xRealDragSource.is() ? m_xRealDragSource->getDefaultCursor( dragAction ) : 0;
+}
+
+// ------------------------------------------------------------------------
+
+void SelectionManagerHolder::startDrag(
+ const ::com::sun::star::datatransfer::dnd::DragGestureEvent& trigger,
+ sal_Int8 sourceActions, sal_Int32 cursor, sal_Int32 image,
+ const Reference< ::com::sun::star::datatransfer::XTransferable >& transferable,
+ const Reference< ::com::sun::star::datatransfer::dnd::XDragSourceListener >& listener
+ ) throw()
+{
+ if( m_xRealDragSource.is() )
+ m_xRealDragSource->startDrag( trigger, sourceActions, cursor, image, transferable, listener );
+}
+
+// ------------------------------------------------------------------------
+
+/*
+ * XServiceInfo
+ */
+
+// ------------------------------------------------------------------------
+
+OUString SelectionManagerHolder::getImplementationName() throw()
+{
+ return OUString::createFromAscii(XDND_IMPLEMENTATION_NAME);
+}
+
+// ------------------------------------------------------------------------
+
+sal_Bool SelectionManagerHolder::supportsService( const OUString& ServiceName ) throw()
+{
+ Sequence < OUString > SupportedServicesNames = Xdnd_getSupportedServiceNames();
+
+ for ( sal_Int32 n = SupportedServicesNames.getLength(); n--; )
+ if (SupportedServicesNames[n].compareTo(ServiceName) == 0)
+ return sal_True;
+
+ return sal_False;
+}
+
+// ------------------------------------------------------------------------
+
+Sequence< OUString > SelectionManagerHolder::getSupportedServiceNames() throw()
+{
+ return Xdnd_getSupportedServiceNames();
+}
+
+
+// ------------------------------------------------------------------------
+
diff --git a/vcl/unx/source/dtrans/X11_selection.hxx b/vcl/unx/source/dtrans/X11_selection.hxx
new file mode 100644
index 000000000000..47baa1776d1a
--- /dev/null
+++ b/vcl/unx/source/dtrans/X11_selection.hxx
@@ -0,0 +1,531 @@
+/*************************************************************************
+ *
+ * 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 _DTRANS_X11_SELECTION_HXX_
+#define _DTRANS_X11_SELECTION_HXX_
+
+#include <cppuhelper/compbase3.hxx>
+#include <cppuhelper/compbase4.hxx>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <com/sun/star/datatransfer/dnd/XDropTarget.hpp>
+#include <com/sun/star/datatransfer/dnd/XDragSource.hpp>
+#include <com/sun/star/awt/XDisplayConnection.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/script/XInvocation.hpp>
+#include <com/sun/star/frame/XDesktop.hpp>
+#include <osl/thread.h>
+
+#ifndef _OSL_CONDITION_HXX_
+#include <osl/conditn.hxx>
+#endif
+
+#include <hash_map>
+#include <list>
+
+#include "tools/prex.h"
+#include <X11/Xlib.h>
+#include "tools/postx.h"
+
+#define XDND_IMPLEMENTATION_NAME "com.sun.star.datatransfer.dnd.XdndSupport"
+#define XDND_DROPTARGET_IMPLEMENTATION_NAME "com.sun.star.datatransfer.dnd.XdndDropTarget"
+
+using namespace ::com::sun::star::uno;
+
+namespace x11 {
+
+ class PixmapHolder; // in bmp.hxx
+
+// ------------------------------------------------------------------------
+ rtl_TextEncoding getTextPlainEncoding( const ::rtl::OUString& rMimeType );
+
+ class SelectionAdaptor
+ {
+ public:
+ virtual Reference< ::com::sun::star::datatransfer::XTransferable > getTransferable() = 0;
+ virtual void clearTransferable() = 0;
+ virtual void fireContentsChanged() = 0;
+ virtual Reference< XInterface > getReference() = 0;
+ // returns a reference that will keep the SelectionAdaptor alive until the
+ // refernce is released
+ };
+
+ class DropTarget :
+ public ::cppu::WeakComponentImplHelper3<
+ ::com::sun::star::datatransfer::dnd::XDropTarget,
+ ::com::sun::star::lang::XInitialization,
+ ::com::sun::star::lang::XServiceInfo
+ >
+ {
+ public:
+ ::osl::Mutex m_aMutex;
+ bool m_bActive;
+ sal_Int8 m_nDefaultActions;
+ XLIB_Window m_aTargetWindow;
+ class SelectionManager* m_pSelectionManager;
+ Reference< ::com::sun::star::datatransfer::dnd::XDragSource >
+ m_xSelectionManager;
+ ::std::list< Reference< ::com::sun::star::datatransfer::dnd::XDropTargetListener > >
+ m_aListeners;
+
+ DropTarget();
+ virtual ~DropTarget();
+
+ // convenience functions that loop over listeners
+ void dragEnter( const ::com::sun::star::datatransfer::dnd::DropTargetDragEnterEvent& dtde ) throw();
+ void dragExit( const ::com::sun::star::datatransfer::dnd::DropTargetEvent& dte ) throw();
+ void dragOver( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& dtde ) throw();
+ void drop( const ::com::sun::star::datatransfer::dnd::DropTargetDropEvent& dtde ) throw();
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const Sequence< Any >& args ) throw ( ::com::sun::star::uno::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();
+
+ // XServiceInfo
+ virtual ::rtl::OUString SAL_CALL getImplementationName() throw();
+ virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw();
+ virtual ::com::sun::star::uno::Sequence< ::rtl::OUString >
+ SAL_CALL getSupportedServiceNames() throw();
+ };
+
+ class SelectionManagerHolder :
+ public ::cppu::WeakComponentImplHelper3<
+ ::com::sun::star::datatransfer::dnd::XDragSource,
+ ::com::sun::star::lang::XInitialization,
+ ::com::sun::star::lang::XServiceInfo
+ >
+ {
+ ::osl::Mutex m_aMutex;
+ Reference< ::com::sun::star::datatransfer::dnd::XDragSource >
+ m_xRealDragSource;
+ public:
+ SelectionManagerHolder();
+ virtual ~SelectionManagerHolder();
+
+ // XServiceInfo
+ virtual ::rtl::OUString SAL_CALL getImplementationName() throw();
+ virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw();
+ virtual ::com::sun::star::uno::Sequence< ::rtl::OUString >
+ SAL_CALL getSupportedServiceNames() throw();
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const Sequence< Any >& arguments ) throw( ::com::sun::star::uno::Exception );
+
+ // XDragSource
+ virtual sal_Bool SAL_CALL isDragImageSupported() throw();
+ virtual sal_Int32 SAL_CALL getDefaultCursor( sal_Int8 dragAction ) throw();
+ virtual void SAL_CALL startDrag(
+ const ::com::sun::star::datatransfer::dnd::DragGestureEvent& trigger,
+ sal_Int8 sourceActions, sal_Int32 cursor, sal_Int32 image,
+ const Reference< ::com::sun::star::datatransfer::XTransferable >& transferable,
+ const Reference< ::com::sun::star::datatransfer::dnd::XDragSourceListener >& listener
+ ) throw();
+
+ };
+
+
+ class SelectionManager :
+ public ::cppu::WeakImplHelper4<
+ ::com::sun::star::datatransfer::dnd::XDragSource,
+ ::com::sun::star::lang::XInitialization,
+ ::com::sun::star::awt::XEventHandler,
+ ::com::sun::star::frame::XTerminateListener
+ >,
+ public SelectionAdaptor
+ {
+ static ::std::hash_map< ::rtl::OUString, SelectionManager*, ::rtl::OUStringHash >& getInstances();
+
+ // for INCR type selection transfer
+ // INCR protocol is used if the data cannot
+ // be transported at once but in parts
+ // IncrementalTransfer holds the bytes to be transmitted
+ // as well a the current position
+ // INCR triggers the delivery of the next part by deleting the
+ // property used to transfer the data
+ struct IncrementalTransfer
+ {
+ Sequence< sal_Int8 > m_aData;
+ int m_nBufferPos;
+ XLIB_Window m_aRequestor;
+ Atom m_aProperty;
+ Atom m_aTarget;
+ int m_nFormat;
+ int m_nTransferStartTime;
+ };
+ int m_nIncrementalThreshold;
+
+ // a struct to hold the data associated with a selection
+ struct Selection
+ {
+ enum State
+ {
+ Inactive, WaitingForResponse, WaitingForData, IncrementalTransfer
+ };
+
+ State m_eState;
+ SelectionAdaptor* m_pAdaptor;
+ Atom m_aAtom;
+ ::osl::Condition m_aDataArrived;
+ Sequence< sal_Int8 > m_aData;
+ Sequence< ::com::sun::star::datatransfer::DataFlavor >
+ m_aTypes;
+ std::vector< Atom > m_aNativeTypes;
+ // this is used for caching
+ // m_aTypes is invalid after 2 seconds
+ // m_aNativeTypes contains the corresponding original atom
+ Atom m_aRequestedType;
+ // m_aRequestedType is only valid while WaitingForResponse and WaitingFotData
+ int m_nLastTimestamp;
+ bool m_bHaveUTF16;
+ Atom m_aUTF8Type;
+ bool m_bHaveCompound;
+ bool m_bOwner;
+ XLIB_Window m_aLastOwner;
+ PixmapHolder* m_pPixmap;
+ // m_nOrigXLIB_Timestamp contains the XLIB_Timestamp at which the seclection
+ // was acquired; needed for XLIB_TimeSTAMP target
+ XLIB_Time m_nOrigTimestamp;
+
+ Selection() : m_eState( Inactive ),
+ m_pAdaptor( NULL ),
+ m_aAtom( None ),
+ m_aRequestedType( None ),
+ m_nLastTimestamp( 0 ),
+ m_bHaveUTF16( false ),
+ m_aUTF8Type( None ),
+ m_bHaveCompound( false ),
+ m_bOwner( false ),
+ m_aLastOwner( None ),
+ m_pPixmap( NULL ),
+ m_nOrigTimestamp( CurrentTime )
+ {}
+ };
+
+ // a struct to hold data associated with a XDropTarget
+ struct DropTargetEntry
+ {
+ DropTarget* m_pTarget;
+ XLIB_Window m_aRootWindow;
+
+ DropTargetEntry() : m_pTarget( NULL ), m_aRootWindow( None ) {}
+ DropTargetEntry( DropTarget* pTarget ) :
+ m_pTarget( pTarget ),
+ m_aRootWindow( None )
+ {}
+ DropTargetEntry( const DropTargetEntry& rEntry ) :
+ m_pTarget( rEntry.m_pTarget ),
+ m_aRootWindow( rEntry.m_aRootWindow )
+ {}
+ ~DropTargetEntry() {}
+
+ DropTarget* operator->() const { return m_pTarget; }
+ DropTargetEntry& operator=(const DropTargetEntry& rEntry)
+ { m_pTarget = rEntry.m_pTarget; m_aRootWindow = rEntry.m_aRootWindow; return *this; }
+ };
+
+ // internal data
+ Display* m_pDisplay;
+ oslThread m_aThread;
+ oslThread m_aDragExecuteThread;
+ ::osl::Condition m_aDragRunning;
+ XLIB_Window m_aWindow;
+ Reference< ::com::sun::star::awt::XDisplayConnection >
+ m_xDisplayConnection;
+ Reference< com::sun::star::script::XInvocation >
+ m_xBitmapConverter;
+ sal_Int32 m_nSelectionTimeout;
+ XLIB_Time m_nSelectionTimestamp;
+
+
+ // members used for Xdnd
+
+ // drop only
+
+ // contains the XdndEnterEvent of a drop action running
+ // with one of our targets. The data.l[0] member
+ // (conatining the drag source XLIB_Window) is set
+ // to None while that is not the case
+ XClientMessageEvent m_aDropEnterEvent;
+ // set to false on XdndEnter
+ // set to true on first XdndPosition or XdndLeave
+ bool m_bDropEnterSent;
+ XLIB_Window m_aCurrentDropWindow;
+ // XLIB_Time code of XdndDrop
+ XLIB_Time m_nDropTime;
+ sal_Int8 m_nLastDropAction;
+ // XTransferable for Xdnd with foreign drag source
+ Reference< ::com::sun::star::datatransfer::XTransferable >
+ m_xDropTransferable;
+ int m_nLastX, m_nLastY;
+ XLIB_Time m_nDropTimestamp;
+ // set to true when calling drop()
+ // if another XdndEnter is received this shows that
+ // someone forgot to call dropComplete - we should reset
+ // and react to the new drop
+ bool m_bDropWaitingForCompletion;
+
+ // drag only
+
+ // None if no Dnd action is running with us as source
+ XLIB_Window m_aDropWindow;
+ // either m_aDropXLIB_Window or its XdndProxy
+ XLIB_Window m_aDropProxy;
+ XLIB_Window m_aDragSourceWindow;
+ // XTransferable for Xdnd when we are drag source
+ Reference< ::com::sun::star::datatransfer::XTransferable >
+ m_xDragSourceTransferable;
+ Reference< ::com::sun::star::datatransfer::dnd::XDragSourceListener >
+ m_xDragSourceListener;
+ // root coordinates
+ int m_nLastDragX, m_nLastDragY;
+ Sequence< ::com::sun::star::datatransfer::DataFlavor >
+ m_aDragFlavors;
+ // the rectangle the pointer must leave until a new XdndPosition should
+ // be sent. empty unless the drop target told to fill
+ int m_nNoPosX, m_nNoPosY, m_nNoPosWidth, m_nNoPosHeight;
+ unsigned int m_nDragButton;
+ sal_Int8 m_nUserDragAction;
+ sal_Int8 m_nTargetAcceptAction;
+ sal_Int8 m_nSourceActions;
+ bool m_bLastDropAccepted;
+ bool m_bDropSuccess;
+ bool m_bDropSent;
+ time_t m_nDropTimeout;
+ bool m_bWaitingForPrimaryConversion;
+ XLIB_Time m_nDragTimestamp;
+
+ // drag cursors
+ XLIB_Cursor m_aMoveCursor;
+ XLIB_Cursor m_aCopyCursor;
+ XLIB_Cursor m_aLinkCursor;
+ XLIB_Cursor m_aNoneCursor;
+ XLIB_Cursor m_aCurrentCursor;
+
+
+ // drag and drop
+
+ int m_nCurrentProtocolVersion;
+ ::std::hash_map< XLIB_Window, DropTargetEntry >
+ m_aDropTargets;
+
+
+ // some special atoms that are needed often
+ Atom m_nCLIPBOARDAtom;
+ Atom m_nTARGETSAtom;
+ Atom m_nTIMESTAMPAtom;
+ Atom m_nTEXTAtom;
+ Atom m_nINCRAtom;
+ Atom m_nCOMPOUNDAtom;
+ Atom m_nMULTIPLEAtom;
+ Atom m_nUTF16Atom;
+ Atom m_nImageBmpAtom;
+ Atom m_nXdndAware;
+ Atom m_nXdndEnter;
+ Atom m_nXdndLeave;
+ Atom m_nXdndPosition;
+ Atom m_nXdndStatus;
+ Atom m_nXdndDrop;
+ Atom m_nXdndFinished;
+ Atom m_nXdndSelection;
+ Atom m_nXdndTypeList;
+ Atom m_nXdndProxy;
+ Atom m_nXdndActionCopy;
+ Atom m_nXdndActionMove;
+ Atom m_nXdndActionLink;
+ Atom m_nXdndActionAsk;
+ Atom m_nXdndActionPrivate;
+
+ // caching for atoms
+ ::std::hash_map< Atom, ::rtl::OUString >
+ m_aAtomToString;
+ ::std::hash_map< ::rtl::OUString, Atom, ::rtl::OUStringHash >
+ m_aStringToAtom;
+
+ // the registered selections
+ ::std::hash_map< Atom, Selection* >
+ m_aSelections;
+ // IncrementalTransfers in progress
+ std::hash_map< XLIB_Window, std::hash_map< Atom, IncrementalTransfer > >
+ m_aIncrementals;
+
+ // do not use X11 multithreading capabilities
+ // since this leads to deadlocks in different Xlib implentations
+ // (XFree as well as Xsun) use an own mutex instead
+ ::osl::Mutex m_aMutex;
+
+ SelectionManager();
+ ~SelectionManager();
+
+ SelectionAdaptor* getAdaptor( Atom selection );
+ PixmapHolder* getPixmapHolder( Atom selection );
+
+ // handle various events
+ bool handleSelectionRequest( XSelectionRequestEvent& rRequest );
+ bool handleSendPropertyNotify( XPropertyEvent& rNotify );
+ bool handleReceivePropertyNotify( XPropertyEvent& rNotify );
+ bool handleSelectionNotify( XSelectionEvent& rNotify );
+ bool handleDragEvent( XEvent& rMessage );
+ bool handleDropEvent( XClientMessageEvent& rMessage );
+
+ // dnd helpers
+ void sendDragStatus( Atom nDropAction );
+ void sendDropPosition( bool bForce, XLIB_Time eventXLIB_Time );
+ bool updateDragAction( int modifierState );
+ int getXdndVersion( XLIB_Window aXLIB_Window, XLIB_Window& rProxy );
+ XLIB_Cursor createCursor( const char* pPointerData, const char* pMaskData, int width, int height, int hotX, int hotY );
+ // coordinates on root XLIB_Window
+ void updateDragWindow( int nX, int nY, XLIB_Window aRoot );
+
+ bool getPasteData( Atom selection, Atom type, Sequence< sal_Int8 >& rData );
+ // returns true if conversion was successful
+ bool convertData( const Reference< ::com::sun::star::datatransfer::XTransferable >& xTransferable,
+ Atom nType,
+ Atom nSelection,
+ int & rFormat,
+ Sequence< sal_Int8 >& rData );
+ bool sendData( SelectionAdaptor* pAdaptor, XLIB_Window requestor, Atom target, Atom property, Atom selection );
+
+ // thread dispatch loop
+ public:
+ // public for extern "C" stub
+ static void run( void* );
+ private:
+ void dispatchEvent( int millisec );
+ // drag thread dispatch
+ public:
+ // public for extern "C" stub
+ static void runDragExecute( void* );
+ private:
+ void dragDoDispatch();
+ bool handleXEvent( XEvent& rEvent );
+
+ // compound text conversion
+ ::rtl::OString convertToCompound( const ::rtl::OUString& rText );
+ ::rtl::OUString convertFromCompound( const char* pText, int nLen = -1 );
+
+ sal_Int8 getUserDragAction() const;
+ sal_Int32 getSelectionTimeout();
+ public:
+ static SelectionManager& get( const ::rtl::OUString& rDisplayName = ::rtl::OUString() );
+
+ Display * getDisplay() { return m_pDisplay; };
+ XLIB_Window getWindow() { return m_aWindow; };
+
+
+ void registerHandler( Atom selection, SelectionAdaptor& rAdaptor );
+ void deregisterHandler( Atom selection );
+ bool requestOwnership( Atom selection );
+
+ // allow for synchronization over one mutex for XClipboard
+ osl::Mutex& getMutex() { return m_aMutex; }
+
+
+ Atom getAtom( const ::rtl::OUString& rString );
+ const ::rtl::OUString& getString( Atom nAtom );
+
+ // type conversion
+ // note: convertTypeToNative does NOT clear the list, so you can append
+ // multiple types to the same list
+ void convertTypeToNative( const ::rtl::OUString& rType, Atom selection, int& rFormat, ::std::list< Atom >& rConversions, bool bPushFront = false );
+ ::rtl::OUString convertTypeFromNative( Atom nType, Atom selection, int& rFormat );
+ void getNativeTypeList( const Sequence< com::sun::star::datatransfer::DataFlavor >& rTypes, std::list< Atom >& rOutTypeList, Atom targetselection );
+
+ // methods for transferable
+ bool getPasteDataTypes( Atom selection, Sequence< ::com::sun::star::datatransfer::DataFlavor >& rTypes );
+ bool getPasteData( Atom selection, const ::rtl::OUString& rType, Sequence< sal_Int8 >& rData );
+
+ // for XDropTarget to register/deregister itself
+ void registerDropTarget( XLIB_Window aXLIB_Window, DropTarget* pTarget );
+ void deregisterDropTarget( XLIB_Window aXLIB_Window );
+
+ // for XDropTarget{Drag|Drop}Context
+ void accept( sal_Int8 dragOperation, XLIB_Window aDropXLIB_Window, XLIB_Time aXLIB_Timestamp );
+ void reject( XLIB_Window aDropXLIB_Window, XLIB_Time aXLIB_Timestamp );
+ void dropComplete( sal_Bool success, XLIB_Window aDropXLIB_Window, XLIB_Time aXLIB_Timestamp );
+
+ // for XDragSourceContext
+ sal_Int32 getCurrentCursor();
+ void setCursor( sal_Int32 cursor, XLIB_Window aDropXLIB_Window, XLIB_Time aXLIB_Timestamp );
+ void setImage( sal_Int32 image, XLIB_Window aDropXLIB_Window, XLIB_Time aXLIB_Timestamp );
+ void transferablesFlavorsChanged();
+
+ void shutdown() throw();
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const Sequence< Any >& arguments ) throw( ::com::sun::star::uno::Exception );
+
+ // XEventHandler
+ virtual sal_Bool SAL_CALL handleEvent( const Any& event ) throw();
+
+ // XDragSource
+ virtual sal_Bool SAL_CALL isDragImageSupported() throw();
+ virtual sal_Int32 SAL_CALL getDefaultCursor( sal_Int8 dragAction ) throw();
+ virtual void SAL_CALL startDrag(
+ const ::com::sun::star::datatransfer::dnd::DragGestureEvent& trigger,
+ sal_Int8 sourceActions, sal_Int32 cursor, sal_Int32 image,
+ const Reference< ::com::sun::star::datatransfer::XTransferable >& transferable,
+ const Reference< ::com::sun::star::datatransfer::dnd::XDragSourceListener >& listener
+ ) throw();
+
+ // SelectionAdaptor for XdndSelection Drag (we are drag source)
+ virtual Reference< ::com::sun::star::datatransfer::XTransferable > getTransferable() throw();
+ virtual void clearTransferable() throw();
+ virtual void fireContentsChanged() throw();
+ virtual Reference< XInterface > getReference() throw();
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw( ::com::sun::star::uno::RuntimeException );
+
+ // XTerminateListener
+ virtual void SAL_CALL queryTermination( const ::com::sun::star::lang::EventObject& aEvent )
+ throw( ::com::sun::star::frame::TerminationVetoException, ::com::sun::star::uno::RuntimeException );
+ virtual void SAL_CALL notifyTermination( const ::com::sun::star::lang::EventObject& aEvent )
+ throw( ::com::sun::star::uno::RuntimeException );
+ };
+
+// ------------------------------------------------------------------------
+
+ ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL Xdnd_getSupportedServiceNames();
+ ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL Xdnd_createInstance(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > & xMultiServiceFactory);
+
+ ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL Xdnd_dropTarget_getSupportedServiceNames();
+ ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL Xdnd_dropTarget_createInstance(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > & xMultiServiceFactory);
+
+// ------------------------------------------------------------------------
+
+}
+
+#endif
diff --git a/vcl/unx/source/dtrans/X11_service.cxx b/vcl/unx/source/dtrans/X11_service.cxx
new file mode 100644
index 000000000000..e14d81643553
--- /dev/null
+++ b/vcl/unx/source/dtrans/X11_service.cxx
@@ -0,0 +1,135 @@
+/*************************************************************************
+ *
+ * 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 "salinst.h"
+
+#include <X11_clipboard.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#include <uno/dispatcher.h> // declaration of generic uno interface
+#include <uno/mapping.hxx> // mapping stuff
+#include <cppuhelper/factory.hxx>
+#include <cppuhelper/compbase1.hxx>
+
+using namespace rtl;
+using namespace cppu;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::datatransfer::clipboard;
+using namespace com::sun::star::awt;
+using namespace x11;
+
+Sequence< OUString > SAL_CALL x11::X11Clipboard_getSupportedServiceNames()
+{
+ Sequence< OUString > aRet(1);
+ aRet[0] = OUString::createFromAscii("com.sun.star.datatransfer.clipboard.SystemClipboard");
+ return aRet;
+}
+
+Sequence< OUString > SAL_CALL x11::Xdnd_getSupportedServiceNames()
+{
+ Sequence< OUString > aRet(1);
+ aRet[0] = OUString::createFromAscii("com.sun.star.datatransfer.dnd.X11DragSource");
+ return aRet;
+}
+
+Sequence< OUString > SAL_CALL x11::Xdnd_dropTarget_getSupportedServiceNames()
+{
+ Sequence< OUString > aRet(1);
+ aRet[0] = OUString::createFromAscii("com.sun.star.datatransfer.dnd.X11DropTarget");
+ return aRet;
+}
+
+// ------------------------------------------------------------------------
+
+Reference< XInterface > X11SalInstance::CreateClipboard( const Sequence< Any >& arguments )
+{
+ static std::hash_map< OUString, ::std::hash_map< Atom, Reference< XClipboard > >, ::rtl::OUStringHash > m_aInstances;
+
+ OUString aDisplayName;
+ Atom nSelection;
+
+ // extract display name from connection argument. An exception is thrown
+ // by SelectionManager.initialize() if no display connection is given.
+ if( arguments.getLength() > 0 )
+ {
+ Reference< XDisplayConnection > xConn;
+ arguments.getConstArray()[0] >>= xConn;
+
+ if( xConn.is() )
+ {
+ Any aIdentifier = xConn->getIdentifier();
+ aIdentifier >>= aDisplayName;
+ }
+ }
+
+ SelectionManager& rManager = SelectionManager::get( aDisplayName );
+ rManager.initialize( arguments );
+
+ // check if any other selection than clipboard selection is specified
+ if( arguments.getLength() > 1 )
+ {
+ OUString aSelectionName;
+
+ arguments.getConstArray()[1] >>= aSelectionName;
+ nSelection = rManager.getAtom( aSelectionName );
+ }
+ else
+ {
+ // default atom is clipboard selection
+ nSelection = rManager.getAtom( OUString::createFromAscii( "CLIPBOARD" ) );
+ }
+
+ ::std::hash_map< Atom, Reference< XClipboard > >& rMap( m_aInstances[ aDisplayName ] );
+ ::std::hash_map< Atom, Reference< XClipboard > >::iterator it = rMap.find( nSelection );
+ if( it != rMap.end() )
+ return it->second;
+
+ X11Clipboard* pClipboard = new X11Clipboard( rManager, nSelection );
+ rMap[ nSelection ] = pClipboard;
+
+ return static_cast<OWeakObject*>(pClipboard);
+}
+
+// ------------------------------------------------------------------------
+
+Reference< XInterface > X11SalInstance::CreateDragSource()
+{
+ return Reference < XInterface >( ( OWeakObject * ) new SelectionManagerHolder() );
+}
+
+// ------------------------------------------------------------------------
+
+Reference< XInterface > X11SalInstance::CreateDropTarget()
+{
+ return Reference < XInterface >( ( OWeakObject * ) new DropTarget() );
+}
+
+
diff --git a/vcl/unx/source/dtrans/X11_transferable.cxx b/vcl/unx/source/dtrans/X11_transferable.cxx
new file mode 100644
index 000000000000..16518f0b2864
--- /dev/null
+++ b/vcl/unx/source/dtrans/X11_transferable.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"
+
+#if OSL_DEBUG_LEVEL > 1
+#include <stdio.h>
+#endif
+
+#include <X11_transferable.hxx>
+#include <X11/Xatom.h>
+#include <com/sun/star/io/IOException.hpp>
+
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::io;
+using namespace com::sun::star::uno;
+using namespace cppu;
+using namespace osl;
+using namespace rtl;
+
+
+using namespace x11;
+
+
+X11Transferable::X11Transferable(
+ SelectionManager& rManager,
+ const Reference< XInterface >& xCreator,
+ Atom selection
+ ) :
+ m_rManager( rManager ),
+ m_xCreator( xCreator ),
+ m_aSelection( selection )
+{
+}
+
+//==================================================================================================
+
+X11Transferable::~X11Transferable()
+{
+}
+
+//==================================================================================================
+
+Any SAL_CALL X11Transferable::getTransferData( const DataFlavor& rFlavor )
+ throw(UnsupportedFlavorException, IOException, RuntimeException)
+{
+ Any aRet;
+ Sequence< sal_Int8 > aData;
+ bool bSuccess = m_rManager.getPasteData( m_aSelection ? m_aSelection : XA_PRIMARY, rFlavor.MimeType, aData );
+ if( ! bSuccess && m_aSelection == 0 )
+ bSuccess = m_rManager.getPasteData( m_rManager.getAtom( OUString::createFromAscii( "CLIPBOARD" ) ), rFlavor.MimeType, aData );
+
+ if( ! bSuccess )
+ {
+ throw UnsupportedFlavorException( rFlavor.MimeType, static_cast < XTransferable * > ( this ) );
+ }
+ if( rFlavor.MimeType.equalsIgnoreAsciiCase( OUString::createFromAscii( "text/plain;charset=utf-16" ) ) )
+ {
+ int nLen = aData.getLength()/2;
+ if( ((sal_Unicode*)aData.getConstArray())[nLen-1] == 0 )
+ nLen--;
+ OUString aString( (sal_Unicode*)aData.getConstArray(), nLen );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "X11Transferable::getTransferData( \"%s\" )\n -> \"%s\"\n",
+ OUStringToOString( rFlavor.MimeType, RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ OUStringToOString( aString, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+ aRet <<= aString;
+ }
+ else
+ aRet <<= aData;
+ return aRet;
+}
+
+//==================================================================================================
+
+Sequence< DataFlavor > SAL_CALL X11Transferable::getTransferDataFlavors()
+ throw(RuntimeException)
+{
+ Sequence< DataFlavor > aFlavorList;
+ bool bSuccess = m_rManager.getPasteDataTypes( m_aSelection ? m_aSelection : XA_PRIMARY, aFlavorList );
+ if( ! bSuccess && m_aSelection == 0 )
+ bSuccess = m_rManager.getPasteDataTypes( m_rManager.getAtom( OUString::createFromAscii( "CLIPBOARD" ) ), aFlavorList );
+
+ return aFlavorList;
+}
+
+//==================================================================================================
+
+sal_Bool SAL_CALL X11Transferable::isDataFlavorSupported( const DataFlavor& aFlavor )
+ throw(RuntimeException)
+{
+ if( aFlavor.DataType != getCppuType( (Sequence< sal_Int8 >*)0 ) )
+ {
+ if( ! aFlavor.MimeType.equalsIgnoreAsciiCase( OUString::createFromAscii( "text/plain;charset=utf-16" ) ) &&
+ aFlavor.DataType == getCppuType( (OUString*)0 ) )
+ return false;
+ }
+
+ Sequence< DataFlavor > aFlavors( getTransferDataFlavors() );
+ for( int i = 0; i < aFlavors.getLength(); i++ )
+ if( aFlavor.MimeType.equalsIgnoreAsciiCase( aFlavors.getConstArray()[i].MimeType ) &&
+ aFlavor.DataType == aFlavors.getConstArray()[i].DataType )
+ return sal_True;
+
+ return sal_False;
+}
+
diff --git a/vcl/unx/source/dtrans/X11_transferable.hxx b/vcl/unx/source/dtrans/X11_transferable.hxx
new file mode 100644
index 000000000000..57f0d6682cab
--- /dev/null
+++ b/vcl/unx/source/dtrans/X11_transferable.hxx
@@ -0,0 +1,72 @@
+/*************************************************************************
+ *
+ * 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 _DTRANS_X11_TRANSFERABLE_HXX_
+#define _DTRANS_X11_TRANSFERABLE_HXX_
+
+#include <X11_selection.hxx>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+
+#ifndef _COM_SUN_STAR_LANG_XEVENTLISTENER_HDL_
+#include <com/sun/star/lang/XEventListener.hpp>
+#endif
+#include <cppuhelper/implbase1.hxx>
+
+namespace x11 {
+
+ class X11Transferable : public ::cppu::WeakImplHelper1 <
+ ::com::sun::star::datatransfer::XTransferable >
+ {
+ ::osl::Mutex m_aMutex;
+
+ SelectionManager& m_rManager;
+ Reference< XInterface > m_xCreator;
+ Atom m_aSelection;
+ public:
+ X11Transferable( SelectionManager& rManager, const Reference< XInterface >& xCreator, Atom selection = None );
+ virtual ~X11Transferable();
+
+ /*
+ * XTransferable
+ */
+
+ virtual ::com::sun::star::uno::Any SAL_CALL getTransferData( const ::com::sun::star::datatransfer::DataFlavor& aFlavor )
+ throw(::com::sun::star::datatransfer::UnsupportedFlavorException,
+ ::com::sun::star::io::IOException,
+ ::com::sun::star::uno::RuntimeException
+ );
+
+ virtual ::com::sun::star::uno::Sequence< ::com::sun::star::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors( )
+ throw(::com::sun::star::uno::RuntimeException);
+
+ virtual sal_Bool SAL_CALL isDataFlavorSupported( const ::com::sun::star::datatransfer::DataFlavor& aFlavor )
+ throw(::com::sun::star::uno::RuntimeException);
+ };
+
+} // namespace
+
+#endif
diff --git a/vcl/unx/source/dtrans/bmp.cxx b/vcl/unx/source/dtrans/bmp.cxx
new file mode 100644
index 000000000000..1ccd04eba725
--- /dev/null
+++ b/vcl/unx/source/dtrans/bmp.cxx
@@ -0,0 +1,739 @@
+/*************************************************************************
+ *
+ * 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 <unistd.h>
+#include <cstdio>
+#include <cstring>
+
+#include <bmp.hxx>
+
+#include <X11_selection.hxx>
+
+using namespace x11;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::script;
+using namespace com::sun::star::awt;
+using namespace rtl;
+
+/*
+ * helper functions
+ */
+
+inline void writeLE( sal_uInt16 nNumber, sal_uInt8* pBuffer )
+{
+ pBuffer[ 0 ] = (nNumber & 0xff);
+ pBuffer[ 1 ] = ((nNumber>>8)&0xff);
+}
+
+inline void writeLE( sal_uInt32 nNumber, sal_uInt8* pBuffer )
+{
+ pBuffer[ 0 ] = (nNumber & 0xff);
+ pBuffer[ 1 ] = ((nNumber>>8)&0xff);
+ pBuffer[ 2 ] = ((nNumber>>16)&0xff);
+ pBuffer[ 3 ] = ((nNumber>>24)&0xff);
+}
+
+inline sal_uInt16 readLE16( const sal_uInt8* pBuffer )
+{
+ return (((sal_uInt16)pBuffer[1]) << 8 ) | pBuffer[0];
+}
+
+inline sal_uInt16 readLE32( const sal_uInt8* pBuffer )
+{
+ return
+ (((sal_uInt32)pBuffer[3]) << 24 ) |
+ (((sal_uInt32)pBuffer[2]) << 16 ) |
+ (((sal_uInt32)pBuffer[1]) << 8 ) |
+ pBuffer[0];
+}
+
+
+/*
+ * BmpTransporter
+ */
+
+BmpTransporter::BmpTransporter( const Sequence<sal_Int8>& rBmp ) :
+ m_aBM( rBmp )
+{
+ const sal_uInt8* pData = (const sal_uInt8*)rBmp.getConstArray();
+
+ if( pData[0] == 'B' || pData[1] == 'M' )
+ {
+ pData = pData+14;
+ m_aSize.Width = readLE32( pData+4 );
+ m_aSize.Height = readLE32( pData+8 );
+ }
+ else
+ m_aSize.Width = m_aSize.Height = 0;
+}
+
+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 >();
+}
+
+/*
+ * scanline helpers
+ */
+
+inline void X11_writeScanlinePixel( unsigned long nColor, sal_uInt8* pScanline, int depth, int x )
+{
+ switch( depth )
+ {
+ case 1:
+ pScanline[ x/8 ] &= ~(1 << (x&7));
+ pScanline[ x/8 ] |= ((nColor & 1) << (x&7));
+ break;
+ case 4:
+ pScanline[ x/2 ] &= ((x&1) ? 0x0f : 0xf0);
+ pScanline[ x/2 ] |= ((x&1) ? (nColor & 0x0f) : ((nColor & 0x0f) << 4));
+ break;
+ default:
+ case 8:
+ pScanline[ x ] = (nColor & 0xff);
+ break;
+ }
+}
+
+static sal_uInt8* X11_getPaletteBmpFromImage(
+ Display* pDisplay,
+ XImage* pImage,
+ Colormap aColormap,
+ sal_Int32& rOutSize
+ )
+{
+ sal_uInt32 nColors = 0;
+
+ rOutSize = 0;
+
+ sal_uInt8* pBuffer = 0;
+ sal_uInt32 nHeaderSize, nScanlineSize;
+ sal_uInt16 nBitCount;
+ // determine header and scanline size
+ switch( pImage->depth )
+ {
+ case 1:
+ nHeaderSize = 64;
+ nScanlineSize = (pImage->width+31)/32;
+ nBitCount = 1;
+ break;
+ case 4:
+ nHeaderSize = 72;
+ nScanlineSize = (pImage->width+1)/2;
+ nBitCount = 4;
+ break;
+ default:
+ case 8:
+ nHeaderSize = 1084;
+ nScanlineSize = pImage->width;
+ nBitCount = 8;
+ break;
+ }
+ // adjust scan lines to begin on %4 boundaries
+ if( nScanlineSize & 3 )
+ {
+ nScanlineSize &= 0xfffffffc;
+ nScanlineSize += 4;
+ }
+
+ // allocate buffer to hold header and scanlines, initialize to zero
+ rOutSize = nHeaderSize + nScanlineSize*pImage->height;
+ pBuffer = (sal_uInt8*)rtl_allocateZeroMemory( rOutSize );
+ for( int y = 0; y < pImage->height; y++ )
+ {
+ sal_uInt8* pScanline = pBuffer + nHeaderSize + (pImage->height-1-y)*nScanlineSize;
+ for( int x = 0; x < pImage->width; x++ )
+ {
+ unsigned long nPixel = XGetPixel( pImage, x, y );
+ if( nPixel >= nColors )
+ nColors = nPixel+1;
+ X11_writeScanlinePixel( nPixel, pScanline, pImage->depth, x );
+ }
+ }
+
+ // fill in header fields
+ pBuffer[ 0 ] = 'B';
+ pBuffer[ 1 ] = 'M';
+
+ writeLE( nHeaderSize, pBuffer+10 );
+ writeLE( (sal_uInt32)40, pBuffer+14 );
+ writeLE( (sal_uInt32)pImage->width, pBuffer+18 );
+ writeLE( (sal_uInt32)pImage->height, pBuffer+22 );
+ writeLE( (sal_uInt16)1, pBuffer+26 );
+ writeLE( nBitCount, pBuffer+28 );
+ writeLE( (sal_uInt32)(DisplayWidth(pDisplay,DefaultScreen(pDisplay))*1000/DisplayWidthMM(pDisplay,DefaultScreen(pDisplay))), pBuffer+38);
+ writeLE( (sal_uInt32)(DisplayHeight(pDisplay,DefaultScreen(pDisplay))*1000/DisplayHeightMM(pDisplay,DefaultScreen(pDisplay))), pBuffer+42);
+ writeLE( nColors, pBuffer+46 );
+ writeLE( nColors, pBuffer+50 );
+
+ XColor aColors[256];
+ if( nColors > (1U << nBitCount) ) // paranoia
+ nColors = (1U << nBitCount);
+ for( unsigned long nPixel = 0; nPixel < nColors; nPixel++ )
+ {
+ aColors[nPixel].flags = DoRed | DoGreen | DoBlue;
+ aColors[nPixel].pixel = nPixel;
+ }
+ XQueryColors( pDisplay, aColormap, aColors, nColors );
+ for( sal_uInt32 i = 0; i < nColors; i++ )
+ {
+ pBuffer[ 54 + i*4 ] = (sal_uInt8)(aColors[i].blue >> 8);
+ pBuffer[ 55 + i*4 ] = (sal_uInt8)(aColors[i].green >> 8);
+ pBuffer[ 56 + i*4 ] = (sal_uInt8)(aColors[i].red >> 8);
+ }
+
+ // done
+
+ return pBuffer;
+}
+
+inline unsigned long doRightShift( unsigned long nValue, int nShift )
+{
+ return (nShift > 0) ? (nValue >> nShift) : (nValue << (-nShift));
+}
+
+inline unsigned long doLeftShift( unsigned long nValue, int nShift )
+{
+ return (nShift > 0) ? (nValue << nShift) : (nValue >> (-nShift));
+}
+
+static void getShift( unsigned long nMask, int& rShift, int& rSigBits, int& rShift2 )
+{
+ unsigned long nUseMask = nMask;
+ rShift = 0;
+ while( nMask & 0xffffff00 )
+ {
+ rShift++;
+ nMask >>= 1;
+ }
+ if( rShift == 0 )
+ while( ! (nMask & 0x00000080) )
+ {
+ rShift--;
+ nMask <<= 1;
+ }
+
+ int nRotate = sizeof(unsigned long)*8 - rShift;
+ rSigBits = 0;
+ nMask = doRightShift( nUseMask, rShift) ;
+ while( nRotate-- )
+ {
+ if( nMask & 1 )
+ rSigBits++;
+ nMask >>= 1;
+ }
+
+ rShift2 = 0;
+ if( rSigBits < 8 )
+ rShift2 = 8-rSigBits;
+}
+
+static sal_uInt8* X11_getTCBmpFromImage(
+ Display* pDisplay,
+ XImage* pImage,
+ sal_Int32& rOutSize,
+ int nScreenNo
+ )
+{
+ // get masks from visual info (guesswork)
+ XVisualInfo aVInfo;
+ if( ! XMatchVisualInfo( pDisplay, nScreenNo, pImage->depth, TrueColor, &aVInfo ) )
+ return NULL;
+
+ rOutSize = 0;
+
+ sal_uInt8* pBuffer = 0;
+ sal_uInt32 nHeaderSize = 60;
+ sal_uInt32 nScanlineSize = pImage->width*3;
+
+ // adjust scan lines to begin on %4 boundaries
+ if( nScanlineSize & 3 )
+ {
+ nScanlineSize &= 0xfffffffc;
+ nScanlineSize += 4;
+ }
+ int nRedShift, nRedSig, nRedShift2 = 0;
+ getShift( aVInfo.red_mask, nRedShift, nRedSig, nRedShift2 );
+ int nGreenShift, nGreenSig, nGreenShift2 = 0;
+ getShift( aVInfo.green_mask, nGreenShift, nGreenSig, nGreenShift2 );
+ int nBlueShift, nBlueSig, nBlueShift2 = 0;
+ getShift( aVInfo.blue_mask, nBlueShift, nBlueSig, nBlueShift2 );
+
+ // allocate buffer to hold header and scanlines, initialize to zero
+ rOutSize = nHeaderSize + nScanlineSize*pImage->height;
+ pBuffer = (sal_uInt8*)rtl_allocateZeroMemory( rOutSize );
+ for( int y = 0; y < pImage->height; y++ )
+ {
+ sal_uInt8* pScanline = pBuffer + nHeaderSize + (pImage->height-1-y)*nScanlineSize;
+ for( int x = 0; x < pImage->width; x++ )
+ {
+ unsigned long nPixel = XGetPixel( pImage, x, y );
+
+ sal_uInt8 nValue = (sal_uInt8)doRightShift( nPixel&aVInfo.blue_mask, nBlueShift);
+ if( nBlueShift2 )
+ nValue |= (nValue >> nBlueShift2 );
+ *pScanline++ = nValue;
+
+ nValue = (sal_uInt8)doRightShift( nPixel&aVInfo.green_mask, nGreenShift);
+ if( nGreenShift2 )
+ nValue |= (nValue >> nGreenShift2 );
+ *pScanline++ = nValue;
+
+ nValue = (sal_uInt8)doRightShift( nPixel&aVInfo.red_mask, nRedShift);
+ if( nRedShift2 )
+ nValue |= (nValue >> nRedShift2 );
+ *pScanline++ = nValue;
+ }
+ }
+
+ // fill in header fields
+ pBuffer[ 0 ] = 'B';
+ pBuffer[ 1 ] = 'M';
+
+ writeLE( nHeaderSize, pBuffer+10 );
+ writeLE( (sal_uInt32)40, pBuffer+14 );
+ writeLE( (sal_uInt32)pImage->width, pBuffer+18 );
+ writeLE( (sal_uInt32)pImage->height, pBuffer+22 );
+ writeLE( (sal_uInt16)1, pBuffer+26 );
+ writeLE( (sal_uInt16)24, pBuffer+28 );
+ writeLE( (sal_uInt32)(DisplayWidth(pDisplay,DefaultScreen(pDisplay))*1000/DisplayWidthMM(pDisplay,DefaultScreen(pDisplay))), pBuffer+38);
+ writeLE( (sal_uInt32)(DisplayHeight(pDisplay,DefaultScreen(pDisplay))*1000/DisplayHeightMM(pDisplay,DefaultScreen(pDisplay))), pBuffer+42);
+
+ // done
+
+ return pBuffer;
+}
+
+sal_uInt8* x11::X11_getBmpFromPixmap(
+ Display* pDisplay,
+ Drawable aDrawable,
+ Colormap aColormap,
+ sal_Int32& rOutSize
+ )
+{
+ // get geometry of drawable
+ XLIB_Window aRoot;
+ int x,y;
+ unsigned int w, h, bw, d;
+ XGetGeometry( pDisplay, aDrawable, &aRoot, &x, &y, &w, &h, &bw, &d );
+
+ // find which screen we are on
+ int nScreenNo = ScreenCount( pDisplay );
+ while( nScreenNo-- )
+ {
+ if( RootWindow( pDisplay, nScreenNo ) == aRoot )
+ break;
+ }
+ if( nScreenNo < 0 )
+ return NULL;
+
+ if( aColormap == None )
+ aColormap = DefaultColormap( pDisplay, nScreenNo );
+
+ // get the image
+ XImage* pImage = XGetImage( pDisplay, aDrawable, 0, 0, w, h, AllPlanes, ZPixmap );
+ if( ! pImage )
+ return NULL;
+
+ sal_uInt8* pBmp = d <= 8 ?
+ X11_getPaletteBmpFromImage( pDisplay, pImage, aColormap, rOutSize ) :
+ X11_getTCBmpFromImage( pDisplay, pImage, rOutSize, nScreenNo );
+ XDestroyImage( pImage );
+
+ return pBmp;
+}
+
+void x11::X11_freeBmp( sal_uInt8* pBmp )
+{
+ rtl_freeMemory( pBmp );
+}
+
+/*
+ * PixmapHolder
+ */
+
+PixmapHolder::PixmapHolder( Display* pDisplay ) :
+ m_pDisplay( pDisplay ),
+ m_aColormap( None ),
+ m_aPixmap( None ),
+ m_aBitmap( None )
+{
+ /* try to get a 24 bit true color visual, if that fails,
+ * revert to default visual
+ */
+ if( ! XMatchVisualInfo( m_pDisplay, DefaultScreen( m_pDisplay ), 24, TrueColor, &m_aInfo ) )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "PixmapHolder reverting to default visual\n" );
+#endif
+ Visual* pVisual = DefaultVisual( m_pDisplay, DefaultScreen( m_pDisplay ) );
+ m_aInfo.screen = DefaultScreen( m_pDisplay );
+ m_aInfo.visual = pVisual;
+ m_aInfo.visualid = pVisual->visualid;
+ m_aInfo.c_class = pVisual->c_class;
+ m_aInfo.red_mask = pVisual->red_mask;
+ m_aInfo.green_mask = pVisual->green_mask;
+ m_aInfo.blue_mask = pVisual->blue_mask;
+ m_aInfo.depth = DefaultDepth( m_pDisplay, m_aInfo.screen );
+ }
+ m_aColormap = DefaultColormap( m_pDisplay, m_aInfo.screen );
+#if OSL_DEBUG_LEVEL > 1
+ static const char* pClasses[] =
+ { "StaticGray", "GrayScale", "StaticColor", "PseudoColor", "TrueColor", "DirectColor" };
+ fprintf( stderr, "PixmapHolder visual: id = 0x%lx, class = %s (%d), depth=%d; color map = 0x%lx\n",
+ m_aInfo.visualid,
+ (m_aInfo.c_class >= 0 && unsigned(m_aInfo.c_class) < sizeof(pClasses)/sizeof(pClasses[0])) ? pClasses[m_aInfo.c_class] : "<unknown>",
+ m_aInfo.c_class,
+ m_aInfo.depth,
+ m_aColormap );
+#endif
+ if( m_aInfo.c_class == TrueColor )
+ {
+ int nRedSig, nGreenSig, nBlueSig;
+ m_nRedShift = m_nRedShift2 = 0;
+ getShift( m_aInfo.red_mask, m_nRedShift, nRedSig, m_nRedShift2 );
+ m_nGreenShift = m_nGreenShift2 = 0;
+ getShift( m_aInfo.green_mask, m_nGreenShift, nGreenSig, m_nGreenShift2 );
+ m_nBlueShift = m_nBlueShift2 = 0;
+ getShift( m_aInfo.blue_mask, m_nBlueShift, nBlueSig, m_nBlueShift2 );
+
+ m_nBlueShift2Mask = m_nBlueShift2 ? ~((unsigned long)((1<<m_nBlueShift2)-1)) : ~0L;
+ m_nGreenShift2Mask = m_nGreenShift2 ? ~((unsigned long)((1<<m_nGreenShift2)-1)) : ~0L;
+ m_nRedShift2Mask = m_nRedShift2 ? ~((unsigned long)((1<<m_nRedShift2)-1)) : ~0L;
+ }
+}
+
+PixmapHolder::~PixmapHolder()
+{
+ if( m_aPixmap != None )
+ XFreePixmap( m_pDisplay, m_aPixmap );
+ if( m_aBitmap != None )
+ XFreePixmap( m_pDisplay, m_aBitmap );
+}
+
+unsigned long PixmapHolder::getTCPixel( sal_uInt8 r, sal_uInt8 g, sal_uInt8 b ) const
+{
+ unsigned long nPixel = 0;
+ unsigned long nValue = (unsigned long)b;
+ nValue &= m_nBlueShift2Mask;
+ nPixel |= doLeftShift( nValue, m_nBlueShift );
+
+ nValue = (unsigned long)g;
+ nValue &= m_nGreenShift2Mask;
+ nPixel |= doLeftShift( nValue, m_nGreenShift );
+
+ nValue = (unsigned long)r;
+ nValue &= m_nRedShift2Mask;
+ nPixel |= doLeftShift( nValue, m_nRedShift );
+
+ return nPixel;
+}
+
+void PixmapHolder::setBitmapDataPalette( const sal_uInt8* pData, XImage* pImage )
+{
+ // setup palette
+ XColor aPalette[256];
+
+ sal_uInt32 nColors = readLE32( pData+32 );
+ sal_uInt32 nWidth = readLE32( pData+4 );
+ sal_uInt32 nHeight = readLE32( pData+8 );
+ sal_uInt16 nDepth = readLE16( pData+14 );
+
+ for( sal_uInt16 i = 0 ; i < nColors; i++ )
+ {
+ if( m_aInfo.c_class != TrueColor )
+ {
+ aPalette[i].red = ((unsigned short)pData[42 + i*4]) << 8 | ((unsigned short)pData[42 + i*4]);
+ aPalette[i].green = ((unsigned short)pData[41 + i*4]) << 8 | ((unsigned short)pData[41 + i*4]);
+ aPalette[i].blue = ((unsigned short)pData[40 + i*4]) << 8 | ((unsigned short)pData[40 + i*4]);
+ XAllocColor( m_pDisplay, m_aColormap, aPalette+i );
+ }
+ else
+ aPalette[i].pixel = getTCPixel( pData[42+i*4], pData[41+i*4], pData[40+i*4] );
+ }
+ const sal_uInt8* pBMData = pData + readLE32( pData ) + 4*nColors;
+
+ sal_uInt32 nScanlineSize = 0;
+ switch( nDepth )
+ {
+ case 1:
+ nScanlineSize = (nWidth+31)/32;
+ break;
+ case 4:
+ nScanlineSize = (nWidth+1)/2;
+ break;
+ case 8:
+ nScanlineSize = nWidth;
+ break;
+ }
+ // adjust scan lines to begin on %4 boundaries
+ if( nScanlineSize & 3 )
+ {
+ nScanlineSize &= 0xfffffffc;
+ nScanlineSize += 4;
+ }
+
+ // allocate buffer to hold header and scanlines, initialize to zero
+ for( unsigned int y = 0; y < nHeight; y++ )
+ {
+ const sal_uInt8* pScanline = pBMData + (nHeight-1-y)*nScanlineSize;
+ for( unsigned int x = 0; x < nWidth; x++ )
+ {
+ int nCol = 0;
+ switch( nDepth )
+ {
+ case 1: nCol = (pScanline[ x/8 ] & (0x80 >> (x&7))) != 0 ? 0 : 1; break;
+ case 4:
+ if( x & 1 )
+ nCol = (int)(pScanline[ x/2 ] >> 4);
+ else
+ nCol = (int)(pScanline[ x/2 ] & 0x0f);
+ break;
+ case 8: nCol = (int)pScanline[x];
+ }
+ XPutPixel( pImage, x, y, aPalette[nCol].pixel );
+ }
+ }
+}
+
+void PixmapHolder::setBitmapDataTCDither( const sal_uInt8* pData, XImage* pImage )
+{
+ XColor aPalette[216];
+
+ int nNonAllocs = 0;
+
+ for( int r = 0; r < 6; r++ )
+ {
+ for( int g = 0; g < 6; g++ )
+ {
+ for( int b = 0; b < 6; b++ )
+ {
+ int i = r*36+g*6+b;
+ aPalette[i].red = r == 5 ? 0xffff : r*10922;
+ aPalette[i].green = g == 5 ? 0xffff : g*10922;
+ aPalette[i].blue = b == 5 ? 0xffff : b*10922;
+ aPalette[i].pixel = 0;
+ if( ! XAllocColor( m_pDisplay, m_aColormap, aPalette+i ) )
+ nNonAllocs++;
+ }
+ }
+ }
+
+ if( nNonAllocs )
+ {
+ XColor aRealPalette[256];
+ int nColors = 1 << m_aInfo.depth;
+ int i;
+ for( i = 0; i < nColors; i++ )
+ aRealPalette[i].pixel = (unsigned long)i;
+ XQueryColors( m_pDisplay, m_aColormap, aRealPalette, nColors );
+ for( i = 0; i < nColors; i++ )
+ {
+ sal_uInt8 nIndex =
+ 36*(sal_uInt8)(aRealPalette[i].red/10923) +
+ 6*(sal_uInt8)(aRealPalette[i].green/10923) +
+ (sal_uInt8)(aRealPalette[i].blue/10923);
+ if( aPalette[nIndex].pixel == 0 )
+ aPalette[nIndex] = aRealPalette[i];
+ }
+ }
+
+ sal_uInt32 nWidth = readLE32( pData+4 );
+ sal_uInt32 nHeight = readLE32( pData+8 );
+
+ const sal_uInt8* pBMData = pData + readLE32( pData );
+ sal_uInt32 nScanlineSize = nWidth*3;
+ // adjust scan lines to begin on %4 boundaries
+ if( nScanlineSize & 3 )
+ {
+ nScanlineSize &= 0xfffffffc;
+ nScanlineSize += 4;
+ }
+
+ for( int y = 0; y < (int)nHeight; y++ )
+ {
+ const sal_uInt8* pScanline = pBMData + (nHeight-1-(sal_uInt32)y)*nScanlineSize;
+ for( int x = 0; x < (int)nWidth; x++ )
+ {
+ sal_uInt8 b = pScanline[3*x];
+ sal_uInt8 g = pScanline[3*x+1];
+ sal_uInt8 r = pScanline[3*x+2];
+ sal_uInt8 i = 36*(r/43) + 6*(g/43) + (b/43);
+
+ XPutPixel( pImage, x, y, aPalette[ i ].pixel );
+ }
+ }
+}
+
+void PixmapHolder::setBitmapDataTC( const sal_uInt8* pData, XImage* pImage )
+{
+ sal_uInt32 nWidth = readLE32( pData+4 );
+ sal_uInt32 nHeight = readLE32( pData+8 );
+
+ const sal_uInt8* pBMData = pData + readLE32( pData );
+ sal_uInt32 nScanlineSize = nWidth*3;
+ // adjust scan lines to begin on %4 boundaries
+ if( nScanlineSize & 3 )
+ {
+ nScanlineSize &= 0xfffffffc;
+ nScanlineSize += 4;
+ }
+
+ for( int y = 0; y < (int)nHeight; y++ )
+ {
+ const sal_uInt8* pScanline = pBMData + (nHeight-1-(sal_uInt32)y)*nScanlineSize;
+ for( int x = 0; x < (int)nWidth; x++ )
+ {
+ unsigned long nPixel = getTCPixel( pScanline[3*x+2], pScanline[3*x+1], pScanline[3*x] );
+ XPutPixel( pImage, x, y, nPixel );
+ }
+ }
+}
+
+bool PixmapHolder::needsConversion( const sal_uInt8* pData )
+{
+ if( pData[0] != 'B' || pData[1] != 'M' )
+ return true;
+
+ pData = pData+14;
+ sal_uInt32 nDepth = readLE32( pData+14 );
+ if( nDepth == 24 )
+ {
+ if( m_aInfo.c_class != TrueColor )
+ return true;
+ }
+ else if( nDepth != (sal_uInt32)m_aInfo.depth )
+ {
+ if( m_aInfo.c_class != TrueColor )
+ return true;
+ }
+
+ return false;
+}
+
+Pixmap PixmapHolder::setBitmapData( const sal_uInt8* pData )
+{
+ if( pData[0] != 'B' || pData[1] != 'M' )
+ return None;
+
+ pData = pData+14;
+
+ // reject compressed data
+ if( readLE32( pData + 16 ) != 0 )
+ return None;
+
+ sal_uInt32 nWidth = readLE32( pData+4 );
+ sal_uInt32 nHeight = readLE32( pData+8 );
+
+ if( m_aPixmap != None )
+ XFreePixmap( m_pDisplay, m_aPixmap ), m_aPixmap = None;
+ if( m_aBitmap != None )
+ XFreePixmap( m_pDisplay, m_aBitmap ), m_aBitmap = None;
+
+ m_aPixmap = XCreatePixmap( m_pDisplay,
+ RootWindow( m_pDisplay, m_aInfo.screen ),
+ nWidth, nHeight, m_aInfo.depth );
+
+ if( m_aPixmap != None )
+ {
+ XImage aImage;
+ aImage.width = (int)nWidth;
+ aImage.height = (int)nHeight;
+ aImage.xoffset = 0;
+ aImage.format = ZPixmap;
+ aImage.data = NULL;
+ aImage.byte_order = ImageByteOrder( m_pDisplay );
+ aImage.bitmap_unit = BitmapUnit( m_pDisplay );
+ aImage.bitmap_bit_order = BitmapBitOrder( m_pDisplay );
+ aImage.bitmap_pad = BitmapPad( m_pDisplay );
+ aImage.depth = m_aInfo.depth;
+ aImage.red_mask = m_aInfo.red_mask;
+ aImage.green_mask = m_aInfo.green_mask;
+ aImage.blue_mask = m_aInfo.blue_mask;
+ aImage.bytes_per_line = 0; // filled in by XInitImage
+ if( m_aInfo.depth <= 8 )
+ aImage.bits_per_pixel = m_aInfo.depth;
+ else
+ aImage.bits_per_pixel = 8*((m_aInfo.depth+7)/8);
+ aImage.obdata = NULL;
+
+ XInitImage( &aImage );
+ aImage.data = (char*)rtl_allocateMemory( nHeight*aImage.bytes_per_line );
+
+ if( readLE32( pData+14 ) == 24 )
+ {
+ if( m_aInfo.c_class == TrueColor )
+ setBitmapDataTC( pData, &aImage );
+ else
+ setBitmapDataTCDither( pData, &aImage );
+ }
+ else
+ setBitmapDataPalette( pData, &aImage );
+
+ // put the image
+ XPutImage( m_pDisplay,
+ m_aPixmap,
+ DefaultGC( m_pDisplay, m_aInfo.screen ),
+ &aImage,
+ 0, 0,
+ 0, 0,
+ nWidth, nHeight );
+
+ // clean up
+ rtl_freeMemory( aImage.data );
+
+ // prepare bitmap (mask)
+ m_aBitmap = XCreatePixmap( m_pDisplay,
+ RootWindow( m_pDisplay, m_aInfo.screen ),
+ nWidth, nHeight, 1 );
+ XGCValues aVal;
+ aVal.function = GXcopy;
+ aVal.foreground = 0xffffffff;
+ GC aGC = XCreateGC( m_pDisplay, m_aBitmap, GCFunction | GCForeground, &aVal );
+ XFillRectangle( m_pDisplay, m_aBitmap, aGC, 0, 0, nWidth, nHeight );
+ XFreeGC( m_pDisplay, aGC );
+ }
+
+ return m_aPixmap;
+}
diff --git a/vcl/unx/source/dtrans/bmp.hxx b/vcl/unx/source/dtrans/bmp.hxx
new file mode 100644
index 000000000000..b59b4417ca69
--- /dev/null
+++ b/vcl/unx/source/dtrans/bmp.hxx
@@ -0,0 +1,105 @@
+/*************************************************************************
+ *
+ * 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 _DTRANS_BMP_HXX_
+#define _DTRANS_BMP_HXX_
+
+#include "tools/prex.h"
+#include <X11/Xatom.h>
+#include <X11/keysym.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include "tools/postx.h"
+
+#include <sal/types.h>
+#include <com/sun/star/awt/XBitmap.hpp>
+#include <cppuhelper/compbase1.hxx>
+
+
+
+namespace x11 {
+
+// helper methods
+sal_uInt8* X11_getBmpFromPixmap( Display* pDisplay,
+ Drawable aDrawable,
+ Colormap aColormap,
+ sal_Int32& rOutSize );
+
+void X11_freeBmp( sal_uInt8* pBmp );
+
+class PixmapHolder
+{
+ Display* m_pDisplay;
+ Colormap m_aColormap;
+ Pixmap m_aPixmap;
+ Pixmap m_aBitmap;
+ XVisualInfo m_aInfo;
+
+ int m_nRedShift, m_nRedShift2;
+ int m_nGreenShift, m_nGreenShift2;
+ int m_nBlueShift, m_nBlueShift2;
+ unsigned long m_nBlueShift2Mask, m_nRedShift2Mask, m_nGreenShift2Mask;
+
+ // these expect data pointers to bitmapinfo header
+ void setBitmapDataTC( const sal_uInt8* pData, XImage* pImage );
+ void setBitmapDataTCDither( const sal_uInt8* pData, XImage* pImage );
+ void setBitmapDataPalette( const sal_uInt8* pData, XImage* pImage );
+
+ unsigned long getTCPixel( sal_uInt8 r, sal_uInt8 g, sal_uInt8 b ) const;
+public:
+ PixmapHolder( Display* pDisplay );
+ ~PixmapHolder();
+
+ // accepts bitmap file (including bitmap file header)
+ Pixmap setBitmapData( const sal_uInt8* pData );
+ bool needsConversion( const sal_uInt8* pData );
+
+ Colormap getColormap() const { return m_aColormap; }
+ Pixmap getPixmap() const { return m_aPixmap; }
+ Pixmap getBitmap() const { return m_aBitmap; }
+ VisualID getVisualID() const { return m_aInfo.visualid; }
+ int getClass() const { return m_aInfo.c_class; }
+ int getDepth() const { return m_aInfo.depth; }
+};
+
+class BmpTransporter :
+ public cppu::WeakImplHelper1< com::sun::star::awt::XBitmap >
+{
+ com::sun::star::uno::Sequence<sal_Int8> m_aBM;
+ com::sun::star::awt::Size m_aSize;
+public:
+ BmpTransporter( const com::sun::star::uno::Sequence<sal_Int8>& rBmp );
+ virtual ~BmpTransporter();
+
+ virtual com::sun::star::awt::Size SAL_CALL getSize() throw();
+ virtual com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL getDIB() throw();
+ virtual com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL getMaskDIB() throw();
+};
+
+}
+
+#endif
diff --git a/vcl/unx/source/dtrans/config.cxx b/vcl/unx/source/dtrans/config.cxx
new file mode 100644
index 000000000000..001da3900bb7
--- /dev/null
+++ b/vcl/unx/source/dtrans/config.cxx
@@ -0,0 +1,148 @@
+/*************************************************************************
+ *
+ * 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 <unotools/configitem.hxx>
+
+#include "X11_selection.hxx"
+
+#define SETTINGS_CONFIGNODE "VCL/Settings/Transfer"
+#define SELECTION_PROPERTY "SelectionTimeout"
+
+namespace x11
+{
+
+class DtransX11ConfigItem : public ::utl::ConfigItem
+{
+ sal_Int32 m_nSelectionTimeout;
+
+ virtual void Notify( const ::com::sun::star::uno::Sequence< ::rtl::OUString >& rPropertyNames );
+ virtual void Commit();
+public:
+ DtransX11ConfigItem();
+ virtual ~DtransX11ConfigItem();
+
+ sal_Int32 getSelectionTimeout() const { return m_nSelectionTimeout; }
+};
+
+}
+
+using namespace com::sun::star::lang;
+using namespace com::sun::star::uno;
+using namespace rtl;
+using namespace x11;
+
+sal_Int32 SelectionManager::getSelectionTimeout()
+{
+ if( m_nSelectionTimeout < 1 )
+ {
+ DtransX11ConfigItem aCfg;
+ m_nSelectionTimeout = aCfg.getSelectionTimeout();
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "initialized selection timeout to %ld seconds\n", m_nSelectionTimeout );
+#endif
+ }
+ return m_nSelectionTimeout;
+}
+
+/*
+ * DtransX11ConfigItem constructor
+ */
+
+DtransX11ConfigItem::DtransX11ConfigItem() :
+ ConfigItem( OUString( RTL_CONSTASCII_USTRINGPARAM( SETTINGS_CONFIGNODE ) ),
+ CONFIG_MODE_DELAYED_UPDATE ),
+ m_nSelectionTimeout( 3 )
+{
+ if( IsValidConfigMgr() )
+ {
+ Sequence< OUString > aKeys( 1 );
+ aKeys.getArray()[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( SELECTION_PROPERTY ) );
+ Sequence< Any > aValues = GetProperties( aKeys );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "found %ld properties for %s\n", aValues.getLength(), SELECTION_PROPERTY );
+#endif
+ Any* pValue = aValues.getArray();
+ 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_nSelectionTimeout = pLine->toInt32();
+ if( m_nSelectionTimeout < 1 )
+ m_nSelectionTimeout = 1;
+ }
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "found SelectionTimeout \"%s\"\n",
+ OUStringToOString( *pLine, osl_getThreadTextEncoding() ).getStr() );
+#endif
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "found SelectionTimeout of type \"%s\"\n",
+ OUStringToOString( pValue->getValueType().getTypeName(), osl_getThreadTextEncoding() ).getStr() );
+#endif
+ }
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "no valid configmanager, could not read timeout setting\n" );
+#endif
+}
+
+/*
+ * DtransX11ConfigItem destructor
+ */
+
+DtransX11ConfigItem::~DtransX11ConfigItem()
+{
+}
+
+/*
+ * DtransX11ConfigItem::Commit
+ */
+
+void DtransX11ConfigItem::Commit()
+{
+ // for the clipboard service this is readonly, so
+ // there is nothing to commit
+}
+
+/*
+ * DtransX11ConfigItem::Notify
+ */
+
+void DtransX11ConfigItem::Notify( const Sequence< OUString >& /*rPropertyNames*/ )
+{
+}
+
+
diff --git a/vcl/unx/source/dtrans/copydata_curs.h b/vcl/unx/source/dtrans/copydata_curs.h
new file mode 100644
index 000000000000..e3d0e3e76530
--- /dev/null
+++ b/vcl/unx/source/dtrans/copydata_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 copydata_curs_width 32
+#define copydata_curs_height 32
+#define copydata_curs_x_hot 1
+#define copydata_curs_y_hot 1
+static char copydata_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00,
+ 0xfe, 0x03, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00,
+ 0x66, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x10, 0x53, 0x00, 0x00,
+ 0x28, 0xa3, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x10, 0xf0, 0x1f, 0x00, 0x08, 0xf0, 0x1f, 0x00, 0x10, 0xf0, 0x1e, 0x00,
+ 0xa8, 0xf2, 0x1e, 0x00, 0x50, 0x35, 0x18, 0x00, 0x00, 0xf0, 0x1e, 0x00,
+ 0x00, 0xf0, 0x1e, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf0, 0x1f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/dtrans/copydata_mask.h b/vcl/unx/source/dtrans/copydata_mask.h
new file mode 100644
index 000000000000..f25b0863d807
--- /dev/null
+++ b/vcl/unx/source/dtrans/copydata_mask.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 copydata_mask_width 32
+#define copydata_mask_height 32
+#define copydata_mask_x_hot 1
+#define copydata_mask_y_hot 1
+static char copydata_mask_bits[] = {
+ 0x07, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
+ 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00,
+ 0xff, 0x07, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0xe7, 0x03, 0x00, 0x00,
+ 0xe0, 0x03, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00,
+ 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0x3c, 0xf8, 0x3f, 0x00,
+ 0x3c, 0xf8, 0x3f, 0x00, 0x3c, 0xf8, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00,
+ 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0x3f, 0x00,
+ 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x3f, 0x00,
+ 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/dtrans/linkdata_curs.h b/vcl/unx/source/dtrans/linkdata_curs.h
new file mode 100644
index 000000000000..c60edc3b99d0
--- /dev/null
+++ b/vcl/unx/source/dtrans/linkdata_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 linkdata_curs_width 32
+#define linkdata_curs_height 32
+#define linkdata_curs_x_hot 1
+#define linkdata_curs_y_hot 1
+static char linkdata_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00,
+ 0xfe, 0x03, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00,
+ 0x66, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x10, 0x53, 0x00, 0x00,
+ 0x28, 0xa3, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x10, 0xf0, 0x1f, 0x00, 0x08, 0x70, 0x18, 0x00, 0x10, 0xf0, 0x18, 0x00,
+ 0xa8, 0x72, 0x18, 0x00, 0x50, 0x35, 0x1a, 0x00, 0x00, 0x30, 0x1f, 0x00,
+ 0x00, 0xb0, 0x1f, 0x00, 0x00, 0x70, 0x1f, 0x00, 0x00, 0xf0, 0x1f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/dtrans/linkdata_mask.h b/vcl/unx/source/dtrans/linkdata_mask.h
new file mode 100644
index 000000000000..cf0f89f63b1b
--- /dev/null
+++ b/vcl/unx/source/dtrans/linkdata_mask.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 linkdata_mask_width 32
+#define linkdata_mask_height 32
+#define linkdata_mask_x_hot 1
+#define linkdata_mask_y_hot 1
+static char linkdata_mask_bits[] = {
+ 0x07, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
+ 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00,
+ 0xff, 0x07, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0xe7, 0x03, 0x00, 0x00,
+ 0xe0, 0x03, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00,
+ 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0x3c, 0xf8, 0x3f, 0x00,
+ 0x3c, 0xf8, 0x3f, 0x00, 0x3c, 0xf8, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00,
+ 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0x3f, 0x00,
+ 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x3f, 0x00,
+ 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/dtrans/makefile.mk b/vcl/unx/source/dtrans/makefile.mk
new file mode 100644
index 000000000000..6f5caccfd734
--- /dev/null
+++ b/vcl/unx/source/dtrans/makefile.mk
@@ -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.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+
+PRJNAME=vcl
+TARGET=dtransX11
+TARGETTYPE=GUI
+
+ENABLE_EXCEPTIONS=TRUE
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+
+# ------------------------------------------------------------------
+
+.IF "$(GUIBASE)"=="aqua"
+
+dummy:
+ @echo "Nothing to build for Mac OS X"
+
+.ELSE # "$(GUIBASE)"=="aqua"
+
+.IF "$(COM)$(CPU)" == "C50I" || "$(COM)$(CPU)" == "C52I"
+NOOPTFILES=\
+ $(SLO)$/X11_selection.obj
+.ENDIF
+
+SLOFILES=\
+ $(SLO)$/X11_dndcontext.obj \
+ $(SLO)$/X11_transferable.obj \
+ $(SLO)$/X11_clipboard.obj \
+ $(SLO)$/X11_selection.obj \
+ $(SLO)$/X11_droptarget.obj \
+ $(SLO)$/X11_service.obj \
+ $(SLO)$/bmp.obj \
+ $(SLO)$/config.obj
+
+.ENDIF # "$(OS)"=="MACOSX"
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
diff --git a/vcl/unx/source/dtrans/movedata_curs.h b/vcl/unx/source/dtrans/movedata_curs.h
new file mode 100644
index 000000000000..b79412bc3f41
--- /dev/null
+++ b/vcl/unx/source/dtrans/movedata_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 movedata_curs_width 32
+#define movedata_curs_height 32
+#define movedata_curs_x_hot 1
+#define movedata_curs_y_hot 1
+static char movedata_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00,
+ 0xfe, 0x03, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00,
+ 0x66, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x10, 0x53, 0x00, 0x00,
+ 0x28, 0xa3, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00,
+ 0x10, 0x40, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00,
+ 0xa8, 0xaa, 0x00, 0x00, 0x50, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/dtrans/movedata_mask.h b/vcl/unx/source/dtrans/movedata_mask.h
new file mode 100644
index 000000000000..e25d0837d8dc
--- /dev/null
+++ b/vcl/unx/source/dtrans/movedata_mask.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 movedata_mask_width 32
+#define movedata_mask_height 32
+#define movedata_mask_x_hot 1
+#define movedata_mask_y_hot 1
+static char movedata_mask_bits[] = {
+ 0x07, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
+ 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00,
+ 0xff, 0x07, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0xe7, 0x03, 0x00, 0x00,
+ 0xe0, 0x03, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00,
+ 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0x3c, 0xe0, 0x01, 0x00,
+ 0x3c, 0xe0, 0x01, 0x00, 0x3c, 0xe0, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00,
+ 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/dtrans/nodrop_curs.h b/vcl/unx/source/dtrans/nodrop_curs.h
new file mode 100644
index 000000000000..8e208e32f293
--- /dev/null
+++ b/vcl/unx/source/dtrans/nodrop_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 nodrop_curs_width 32
+#define nodrop_curs_height 32
+#define nodrop_curs_x_hot 9
+#define nodrop_curs_y_hot 9
+static char nodrop_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00,
+ 0xf8, 0x7f, 0x00, 0x00, 0x7c, 0xf8, 0x00, 0x00, 0x1c, 0xfc, 0x00, 0x00,
+ 0x1e, 0xfe, 0x01, 0x00, 0x0e, 0xdf, 0x01, 0x00, 0x8e, 0xcf, 0x01, 0x00,
+ 0xce, 0xc7, 0x01, 0x00, 0xee, 0xc3, 0x01, 0x00, 0xfe, 0xe1, 0x01, 0x00,
+ 0xfc, 0xe0, 0x00, 0x00, 0x7c, 0xf8, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00,
+ 0xf0, 0x3f, 0x00, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/dtrans/nodrop_mask.h b/vcl/unx/source/dtrans/nodrop_mask.h
new file mode 100644
index 000000000000..7cbecef2c60f
--- /dev/null
+++ b/vcl/unx/source/dtrans/nodrop_mask.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 nodrop_mask_width 32
+#define nodrop_mask_height 32
+#define nodrop_mask_x_hot 9
+#define nodrop_mask_y_hot 9
+static char nodrop_mask_bits[] = {
+ 0xc0, 0x0f, 0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00,
+ 0xfc, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0x7e, 0xfe, 0x01, 0x00,
+ 0x3f, 0xff, 0x03, 0x00, 0x9f, 0xff, 0x03, 0x00, 0xdf, 0xff, 0x03, 0x00,
+ 0xff, 0xef, 0x03, 0x00, 0xff, 0xe7, 0x03, 0x00, 0xff, 0xf3, 0x03, 0x00,
+ 0xfe, 0xf9, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00,
+ 0xf8, 0x7f, 0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00, 0xc0, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/fontmanager/adobeenc.tab b/vcl/unx/source/fontmanager/adobeenc.tab
new file mode 100644
index 000000000000..492e92f3fcf2
--- /dev/null
+++ b/vcl/unx/source/fontmanager/adobeenc.tab
@@ -0,0 +1,1087 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+struct AdobeEncEntry {
+ sal_Unicode aUnicode;
+ sal_uInt8 aAdobeStandardCode;
+ const char* const pAdobename;
+};
+
+static const AdobeEncEntry aAdobeCodes[]=
+{
+ { 0x0041, 0101, "A" },
+ { 0x00C6, 0341, "AE" },
+ { 0x01FC, 0, "AEacute" },
+ { 0xF7E6, 0, "AEsmall" },
+ { 0x00C1, 0, "Aacute" },
+ { 0xF7E1, 0, "Aacutesmall" },
+ { 0x0102, 0, "Abreve" },
+ { 0x00C2, 0, "Acircumflex" },
+ { 0xF7E2, 0, "Acircumflexsmall" },
+ { 0xF6C9, 0, "Acute" },
+ { 0xF7B4, 0, "Acutesmall" },
+ { 0x00C4, 0, "Adieresis" },
+ { 0xF7E4, 0, "Adieresissmall" },
+ { 0x00C0, 0, "Agrave" },
+ { 0xF7E0, 0, "Agravesmall" },
+ { 0x0391, 0, "Alpha" },
+ { 0x0386, 0, "Alphatonos" },
+ { 0x0100, 0, "Amacron" },
+ { 0x0104, 0, "Aogonek" },
+ { 0x00C5, 0, "Aring" },
+ { 0x01FA, 0, "Aringacute" },
+ { 0xF7E5, 0, "Aringsmall" },
+ { 0xF761, 0, "Asmall" },
+ { 0x00C3, 0, "Atilde" },
+ { 0xF7E3, 0, "Atildesmall" },
+ { 0x0042, 0102, "B" },
+ { 0x0392, 0, "Beta" },
+ { 0xF6F4, 0, "Brevesmall" },
+ { 0xF762, 0, "Bsmall" },
+ { 0x0043, 0103, "C" },
+ { 0x0106, 0, "Cacute" },
+ { 0xF6CA, 0, "Caron" },
+ { 0xF6F5, 0, "Caronsmall" },
+ { 0x010C, 0, "Ccaron" },
+ { 0x00C7, 0, "Ccedilla" },
+ { 0xF7E7, 0, "Ccedillasmall" },
+ { 0x0108, 0, "Ccircumflex" },
+ { 0x010A, 0, "Cdotaccent" },
+ { 0xF7B8, 0, "Cedillasmall" },
+ { 0x03A7, 0, "Chi" },
+ { 0xF6F6, 0, "Circumflexsmall" },
+ { 0xF763, 0, "Csmall" },
+ { 0x0044, 0104, "D" },
+ { 0x010E, 0, "Dcaron" },
+ { 0x0110, 0, "Dcroat" },
+ { 0x2206, 0, "Delta" },
+ { 0x0394, 0, "Delta" },
+ { 0xF6CB, 0, "Dieresis" },
+ { 0xF6CC, 0, "DieresisAcute" },
+ { 0xF6CD, 0, "DieresisGrave" },
+ { 0xF7A8, 0, "Dieresissmall" },
+ { 0xF6F7, 0, "Dotaccentsmall" },
+ { 0xF764, 0, "Dsmall" },
+ { 0x0045, 0105, "E" },
+ { 0x00C9, 0, "Eacute" },
+ { 0xF7E9, 0, "Eacutesmall" },
+ { 0x0114, 0, "Ebreve" },
+ { 0x011A, 0, "Ecaron" },
+ { 0x00CA, 0, "Ecircumflex" },
+ { 0xF7EA, 0, "Ecircumflexsmall" },
+ { 0x00CB, 0, "Edieresis" },
+ { 0xF7EB, 0, "Edieresissmall" },
+ { 0x0116, 0, "Edotaccent" },
+ { 0x00C8, 0, "Egrave" },
+ { 0xF7E8, 0, "Egravesmall" },
+ { 0x0112, 0, "Emacron" },
+ { 0x014A, 0, "Eng" },
+ { 0x0118, 0, "Eogonek" },
+ { 0x0395, 0, "Epsilon" },
+ { 0x0388, 0, "Epsilontonos" },
+ { 0xF765, 0, "Esmall" },
+ { 0x0397, 0, "Eta" },
+ { 0x0389, 0, "Etatonos" },
+ { 0x00D0, 0, "Eth" },
+ { 0xF7F0, 0, "Ethsmall" },
+ { 0x20AC, 0, "Euro" },
+ { 0x0046, 0106, "F" },
+ { 0xF766, 0, "Fsmall" },
+ { 0x0047, 0107, "G" },
+ { 0x0393, 0, "Gamma" },
+ { 0x011E, 0, "Gbreve" },
+ { 0x01E6, 0, "Gcaron" },
+ { 0x011C, 0, "Gcircumflex" },
+ { 0x0122, 0, "Gcommaaccent" },
+ { 0x0120, 0, "Gdotaccent" },
+ { 0xF6CE, 0, "Grave" },
+ { 0xF760, 0, "Gravesmall" },
+ { 0xF767, 0, "Gsmall" },
+ { 0x0048, 0110, "H" },
+ { 0x25CF, 0, "H18533" },
+ { 0x25AA, 0, "H18543" },
+ { 0x25AB, 0, "H18551" },
+ { 0x25A1, 0, "H22073" },
+ { 0x0126, 0, "Hbar" },
+ { 0x0124, 0, "Hcircumflex" },
+ { 0xF768, 0, "Hsmall" },
+ { 0xF6CF, 0, "Hungarumlaut" },
+ { 0xF6F8, 0, "Hungarumlautsmall" },
+ { 0x0049, 0111, "I" },
+ { 0x0132, 0, "IJ" },
+ { 0x00CD, 0, "Iacute" },
+ { 0xF7ED, 0, "Iacutesmall" },
+ { 0x012C, 0, "Ibreve" },
+ { 0x00CE, 0, "Icircumflex" },
+ { 0xF7EE, 0, "Icircumflexsmall" },
+ { 0x00CF, 0, "Idieresis" },
+ { 0xF7EF, 0, "Idieresissmall" },
+ { 0x0130, 0, "Idotaccent" },
+ { 0x2111, 0, "Ifraktur" },
+ { 0x00CC, 0, "Igrave" },
+ { 0xF7EC, 0, "Igravesmall" },
+ { 0x012A, 0, "Imacron" },
+ { 0x012E, 0, "Iogonek" },
+ { 0x0399, 0, "Iota" },
+ { 0x03AA, 0, "Iotadieresis" },
+ { 0x038A, 0, "Iotatonos" },
+ { 0xF769, 0, "Ismall" },
+ { 0x0128, 0, "Itilde" },
+ { 0x004A, 0112, "J" },
+ { 0x0134, 0, "Jcircumflex" },
+ { 0xF76A, 0, "Jsmall" },
+ { 0x004B, 0113, "K" },
+ { 0x039A, 0, "Kappa" },
+ { 0x0136, 0, "Kcommaaccent" },
+ { 0xF76B, 0, "Ksmall" },
+ { 0x004C, 0114, "L" },
+ { 0xF6BF, 0, "LL" },
+ { 0x0139, 0, "Lacute" },
+ { 0x039B, 0, "Lambda" },
+ { 0x013D, 0, "Lcaron" },
+ { 0x013B, 0, "Lcommaaccent" },
+ { 0x013F, 0, "Ldot" },
+ { 0x0141, 0350, "Lslash" },
+ { 0xF6F9, 0, "Lslashsmall" },
+ { 0xF76C, 0, "Lsmall" },
+ { 0x004D, 0115, "M" },
+ { 0xF6D0, 0, "Macron" },
+ { 0xF7AF, 0, "Macronsmall" },
+ { 0xF76D, 0, "Msmall" },
+ { 0x039C, 0, "Mu" },
+ { 0x004E, 0116, "N" },
+ { 0x0143, 0, "Nacute" },
+ { 0x0147, 0, "Ncaron" },
+ { 0x0145, 0, "Ncommaaccent" },
+ { 0xF76E, 0, "Nsmall" },
+ { 0x00D1, 0, "Ntilde" },
+ { 0xF7F1, 0, "Ntildesmall" },
+ { 0x039D, 0, "Nu" },
+ { 0x004F, 0117, "O" },
+ { 0x0152, 0, "OE" },
+ { 0xF6FA, 0, "OEsmall" },
+ { 0x00D3, 0, "Oacute" },
+ { 0xF7F3, 0, "Oacutesmall" },
+ { 0x014E, 0, "Obreve" },
+ { 0x00D4, 0, "Ocircumflex" },
+ { 0xF7F4, 0, "Ocircumflexsmall" },
+ { 0x00D6, 0, "Odieresis" },
+ { 0xF7F6, 0, "Odieresissmall" },
+ { 0xF6FB, 0, "Ogoneksmall" },
+ { 0x00D2, 0, "Ograve" },
+ { 0xF7F2, 0, "Ogravesmall" },
+ { 0x01A0, 0, "Ohorn" },
+ { 0x0150, 0, "Ohungarumlaut" },
+ { 0x014C, 0, "Omacron" },
+ { 0x2126, 0, "Omega" },
+ { 0x03A9, 0, "Omega" },
+ { 0x038F, 0, "Omegatonos" },
+ { 0x039F, 0, "Omicron" },
+ { 0x038C, 0, "Omicrontonos" },
+ { 0x00D8, 0351, "Oslash" },
+ { 0x01FE, 0, "Oslashacute" },
+ { 0xF7F8, 0, "Oslashsmall" },
+ { 0xF76F, 0, "Osmall" },
+ { 0x00D5, 0, "Otilde" },
+ { 0xF7F5, 0, "Otildesmall" },
+ { 0x0050, 0120, "P" },
+ { 0x03A6, 0, "Phi" },
+ { 0x03A0, 0, "Pi" },
+ { 0x03A8, 0, "Psi" },
+ { 0xF770, 0, "Psmall" },
+ { 0x0051, 0121, "Q" },
+ { 0xF771, 0, "Qsmall" },
+ { 0x0052, 0122, "R" },
+ { 0x0154, 0, "Racute" },
+ { 0x0158, 0, "Rcaron" },
+ { 0x0156, 0, "Rcommaaccent" },
+ { 0x211C, 0, "Rfraktur" },
+ { 0x03A1, 0, "Rho" },
+ { 0xF6FC, 0, "Ringsmall" },
+ { 0xF772, 0, "Rsmall" },
+ { 0x0053, 0123, "S" },
+ { 0x250C, 0, "SF010000" },
+ { 0x2514, 0, "SF020000" },
+ { 0x2510, 0, "SF030000" },
+ { 0x2518, 0, "SF040000" },
+ { 0x253C, 0, "SF050000" },
+ { 0x252C, 0, "SF060000" },
+ { 0x2534, 0, "SF070000" },
+ { 0x251C, 0, "SF080000" },
+ { 0x2524, 0, "SF090000" },
+ { 0x2500, 0, "SF100000" },
+ { 0x2502, 0, "SF110000" },
+ { 0x2561, 0, "SF190000" },
+ { 0x2562, 0, "SF200000" },
+ { 0x2556, 0, "SF210000" },
+ { 0x2555, 0, "SF220000" },
+ { 0x2563, 0, "SF230000" },
+ { 0x2551, 0, "SF240000" },
+ { 0x2557, 0, "SF250000" },
+ { 0x255D, 0, "SF260000" },
+ { 0x255C, 0, "SF270000" },
+ { 0x255B, 0, "SF280000" },
+ { 0x255E, 0, "SF360000" },
+ { 0x255F, 0, "SF370000" },
+ { 0x255A, 0, "SF380000" },
+ { 0x2554, 0, "SF390000" },
+ { 0x2569, 0, "SF400000" },
+ { 0x2566, 0, "SF410000" },
+ { 0x2560, 0, "SF420000" },
+ { 0x2550, 0, "SF430000" },
+ { 0x256C, 0, "SF440000" },
+ { 0x2567, 0, "SF450000" },
+ { 0x2568, 0, "SF460000" },
+ { 0x2564, 0, "SF470000" },
+ { 0x2565, 0, "SF480000" },
+ { 0x2559, 0, "SF490000" },
+ { 0x2558, 0, "SF500000" },
+ { 0x2552, 0, "SF510000" },
+ { 0x2553, 0, "SF520000" },
+ { 0x256B, 0, "SF530000" },
+ { 0x256A, 0, "SF540000" },
+ { 0x015A, 0, "Sacute" },
+ { 0x0160, 0, "Scaron" },
+ { 0xF6FD, 0, "Scaronsmall" },
+ { 0x015E, 0, "Scedilla" },
+ { 0xF6C1, 0, "Scedilla" },
+ { 0x015C, 0, "Scircumflex" },
+ { 0x0218, 0, "Scommaaccent" },
+ { 0x03A3, 0, "Sigma" },
+ { 0xF773, 0, "Ssmall" },
+ { 0x0054, 0124, "T" },
+ { 0x03A4, 0, "Tau" },
+ { 0x0166, 0, "Tbar" },
+ { 0x0164, 0, "Tcaron" },
+ { 0x0162, 0, "Tcommaaccent" },
+ { 0x021A, 0, "Tcommaaccent" },
+ { 0x0398, 0, "Theta" },
+ { 0x00DE, 0, "Thorn" },
+ { 0xF7FE, 0, "Thornsmall" },
+ { 0xF6FE, 0, "Tildesmall" },
+ { 0xF774, 0, "Tsmall" },
+ { 0x0055, 0125, "U" },
+ { 0x00DA, 0, "Uacute" },
+ { 0xF7FA, 0, "Uacutesmall" },
+ { 0x016C, 0, "Ubreve" },
+ { 0x00DB, 0, "Ucircumflex" },
+ { 0xF7FB, 0, "Ucircumflexsmall" },
+ { 0x00DC, 0, "Udieresis" },
+ { 0xF7FC, 0, "Udieresissmall" },
+ { 0x00D9, 0, "Ugrave" },
+ { 0xF7F9, 0, "Ugravesmall" },
+ { 0x01AF, 0, "Uhorn" },
+ { 0x0170, 0, "Uhungarumlaut" },
+ { 0x016A, 0, "Umacron" },
+ { 0x0172, 0, "Uogonek" },
+ { 0x03A5, 0, "Upsilon" },
+ { 0x03D2, 0, "Upsilon1" },
+ { 0x03AB, 0, "Upsilondieresis" },
+ { 0x038E, 0, "Upsilontonos" },
+ { 0x016E, 0, "Uring" },
+ { 0xF775, 0, "Usmall" },
+ { 0x0168, 0, "Utilde" },
+ { 0x0056, 0126, "V" },
+ { 0xF776, 0, "Vsmall" },
+ { 0x0057, 0127, "W" },
+ { 0x1E82, 0, "Wacute" },
+ { 0x0174, 0, "Wcircumflex" },
+ { 0x1E84, 0, "Wdieresis" },
+ { 0x1E80, 0, "Wgrave" },
+ { 0xF777, 0, "Wsmall" },
+ { 0x0058, 0130, "X" },
+ { 0x039E, 0, "Xi" },
+ { 0xF778, 0, "Xsmall" },
+ { 0x0059, 0131, "Y" },
+ { 0x00DD, 0, "Yacute" },
+ { 0xF7FD, 0, "Yacutesmall" },
+ { 0x0176, 0, "Ycircumflex" },
+ { 0x0178, 0, "Ydieresis" },
+ { 0xF7FF, 0, "Ydieresissmall" },
+ { 0x1EF2, 0, "Ygrave" },
+ { 0xF779, 0, "Ysmall" },
+ { 0x005A, 0132, "Z" },
+ { 0x0179, 0, "Zacute" },
+ { 0x017D, 0, "Zcaron" },
+ { 0xF6FF, 0, "Zcaronsmall" },
+ { 0x017B, 0, "Zdotaccent" },
+ { 0x0396, 0, "Zeta" },
+ { 0xF77A, 0, "Zsmall" },
+ { 0x0061, 0141, "a" },
+ { 0x00E1, 0, "aacute" },
+ { 0x0103, 0, "abreve" },
+ { 0x00E2, 0, "acircumflex" },
+ { 0x00B4, 0302, "acute" },
+ { 0x0301, 0, "acutecomb" },
+ { 0x00E4, 0, "adieresis" },
+ { 0x00E6, 0361, "ae" },
+ { 0x01FD, 0, "aeacute" },
+ { 0x2015, 0, "afii00208" },
+ { 0x0410, 0, "afii10017" },
+ { 0x0411, 0, "afii10018" },
+ { 0x0412, 0, "afii10019" },
+ { 0x0413, 0, "afii10020" },
+ { 0x0414, 0, "afii10021" },
+ { 0x0415, 0, "afii10022" },
+ { 0x0401, 0, "afii10023" },
+ { 0x0416, 0, "afii10024" },
+ { 0x0417, 0, "afii10025" },
+ { 0x0418, 0, "afii10026" },
+ { 0x0419, 0, "afii10027" },
+ { 0x041A, 0, "afii10028" },
+ { 0x041B, 0, "afii10029" },
+ { 0x041C, 0, "afii10030" },
+ { 0x041D, 0, "afii10031" },
+ { 0x041E, 0, "afii10032" },
+ { 0x041F, 0, "afii10033" },
+ { 0x0420, 0, "afii10034" },
+ { 0x0421, 0, "afii10035" },
+ { 0x0422, 0, "afii10036" },
+ { 0x0423, 0, "afii10037" },
+ { 0x0424, 0, "afii10038" },
+ { 0x0425, 0, "afii10039" },
+ { 0x0426, 0, "afii10040" },
+ { 0x0427, 0, "afii10041" },
+ { 0x0428, 0, "afii10042" },
+ { 0x0429, 0, "afii10043" },
+ { 0x042A, 0, "afii10044" },
+ { 0x042B, 0, "afii10045" },
+ { 0x042C, 0, "afii10046" },
+ { 0x042D, 0, "afii10047" },
+ { 0x042E, 0, "afii10048" },
+ { 0x042F, 0, "afii10049" },
+ { 0x0490, 0, "afii10050" },
+ { 0x0402, 0, "afii10051" },
+ { 0x0403, 0, "afii10052" },
+ { 0x0404, 0, "afii10053" },
+ { 0x0405, 0, "afii10054" },
+ { 0x0406, 0, "afii10055" },
+ { 0x0407, 0, "afii10056" },
+ { 0x0408, 0, "afii10057" },
+ { 0x0409, 0, "afii10058" },
+ { 0x040A, 0, "afii10059" },
+ { 0x040B, 0, "afii10060" },
+ { 0x040C, 0, "afii10061" },
+ { 0x040E, 0, "afii10062" },
+ { 0xF6C4, 0, "afii10063" },
+ { 0xF6C5, 0, "afii10064" },
+ { 0x0430, 0, "afii10065" },
+ { 0x0431, 0, "afii10066" },
+ { 0x0432, 0, "afii10067" },
+ { 0x0433, 0, "afii10068" },
+ { 0x0434, 0, "afii10069" },
+ { 0x0435, 0, "afii10070" },
+ { 0x0451, 0, "afii10071" },
+ { 0x0436, 0, "afii10072" },
+ { 0x0437, 0, "afii10073" },
+ { 0x0438, 0, "afii10074" },
+ { 0x0439, 0, "afii10075" },
+ { 0x043A, 0, "afii10076" },
+ { 0x043B, 0, "afii10077" },
+ { 0x043C, 0, "afii10078" },
+ { 0x043D, 0, "afii10079" },
+ { 0x043E, 0, "afii10080" },
+ { 0x043F, 0, "afii10081" },
+ { 0x0440, 0, "afii10082" },
+ { 0x0441, 0, "afii10083" },
+ { 0x0442, 0, "afii10084" },
+ { 0x0443, 0, "afii10085" },
+ { 0x0444, 0, "afii10086" },
+ { 0x0445, 0, "afii10087" },
+ { 0x0446, 0, "afii10088" },
+ { 0x0447, 0, "afii10089" },
+ { 0x0448, 0, "afii10090" },
+ { 0x0449, 0, "afii10091" },
+ { 0x044A, 0, "afii10092" },
+ { 0x044B, 0, "afii10093" },
+ { 0x044C, 0, "afii10094" },
+ { 0x044D, 0, "afii10095" },
+ { 0x044E, 0, "afii10096" },
+ { 0x044F, 0, "afii10097" },
+ { 0x0491, 0, "afii10098" },
+ { 0x0452, 0, "afii10099" },
+ { 0x0453, 0, "afii10100" },
+ { 0x0454, 0, "afii10101" },
+ { 0x0455, 0, "afii10102" },
+ { 0x0456, 0, "afii10103" },
+ { 0x0457, 0, "afii10104" },
+ { 0x0458, 0, "afii10105" },
+ { 0x0459, 0, "afii10106" },
+ { 0x045A, 0, "afii10107" },
+ { 0x045B, 0, "afii10108" },
+ { 0x045C, 0, "afii10109" },
+ { 0x045E, 0, "afii10110" },
+ { 0x040F, 0, "afii10145" },
+ { 0x0462, 0, "afii10146" },
+ { 0x0472, 0, "afii10147" },
+ { 0x0474, 0, "afii10148" },
+ { 0xF6C6, 0, "afii10192" },
+ { 0x045F, 0, "afii10193" },
+ { 0x0463, 0, "afii10194" },
+ { 0x0473, 0, "afii10195" },
+ { 0x0475, 0, "afii10196" },
+ { 0xF6C7, 0, "afii10831" },
+ { 0xF6C8, 0, "afii10832" },
+ { 0x04D9, 0, "afii10846" },
+ { 0x200E, 0, "afii299" },
+ { 0x200F, 0, "afii300" },
+ { 0x200D, 0, "afii301" },
+ { 0x066A, 0, "afii57381" },
+ { 0x060C, 0, "afii57388" },
+ { 0x0660, 0, "afii57392" },
+ { 0x0661, 0, "afii57393" },
+ { 0x0662, 0, "afii57394" },
+ { 0x0663, 0, "afii57395" },
+ { 0x0664, 0, "afii57396" },
+ { 0x0665, 0, "afii57397" },
+ { 0x0666, 0, "afii57398" },
+ { 0x0667, 0, "afii57399" },
+ { 0x0668, 0, "afii57400" },
+ { 0x0669, 0, "afii57401" },
+ { 0x061B, 0, "afii57403" },
+ { 0x061F, 0, "afii57407" },
+ { 0x0621, 0, "afii57409" },
+ { 0x0622, 0, "afii57410" },
+ { 0x0623, 0, "afii57411" },
+ { 0x0624, 0, "afii57412" },
+ { 0x0625, 0, "afii57413" },
+ { 0x0626, 0, "afii57414" },
+ { 0x0627, 0, "afii57415" },
+ { 0x0628, 0, "afii57416" },
+ { 0x0629, 0, "afii57417" },
+ { 0x062A, 0, "afii57418" },
+ { 0x062B, 0, "afii57419" },
+ { 0x062C, 0, "afii57420" },
+ { 0x062D, 0, "afii57421" },
+ { 0x062E, 0, "afii57422" },
+ { 0x062F, 0, "afii57423" },
+ { 0x0630, 0, "afii57424" },
+ { 0x0631, 0, "afii57425" },
+ { 0x0632, 0, "afii57426" },
+ { 0x0633, 0, "afii57427" },
+ { 0x0634, 0, "afii57428" },
+ { 0x0635, 0, "afii57429" },
+ { 0x0636, 0, "afii57430" },
+ { 0x0637, 0, "afii57431" },
+ { 0x0638, 0, "afii57432" },
+ { 0x0639, 0, "afii57433" },
+ { 0x063A, 0, "afii57434" },
+ { 0x0640, 0, "afii57440" },
+ { 0x0641, 0, "afii57441" },
+ { 0x0642, 0, "afii57442" },
+ { 0x0643, 0, "afii57443" },
+ { 0x0644, 0, "afii57444" },
+ { 0x0645, 0, "afii57445" },
+ { 0x0646, 0, "afii57446" },
+ { 0x0648, 0, "afii57448" },
+ { 0x0649, 0, "afii57449" },
+ { 0x064A, 0, "afii57450" },
+ { 0x064B, 0, "afii57451" },
+ { 0x064C, 0, "afii57452" },
+ { 0x064D, 0, "afii57453" },
+ { 0x064E, 0, "afii57454" },
+ { 0x064F, 0, "afii57455" },
+ { 0x0650, 0, "afii57456" },
+ { 0x0651, 0, "afii57457" },
+ { 0x0652, 0, "afii57458" },
+ { 0x0647, 0, "afii57470" },
+ { 0x06A4, 0, "afii57505" },
+ { 0x067E, 0, "afii57506" },
+ { 0x0686, 0, "afii57507" },
+ { 0x0698, 0, "afii57508" },
+ { 0x06AF, 0, "afii57509" },
+ { 0x0679, 0, "afii57511" },
+ { 0x0688, 0, "afii57512" },
+ { 0x0691, 0, "afii57513" },
+ { 0x06BA, 0, "afii57514" },
+ { 0x06D2, 0, "afii57519" },
+ { 0x06D5, 0, "afii57534" },
+ { 0x20AA, 0, "afii57636" },
+ { 0x05BE, 0, "afii57645" },
+ { 0x05C3, 0, "afii57658" },
+ { 0x05D0, 0, "afii57664" },
+ { 0x05D1, 0, "afii57665" },
+ { 0x05D2, 0, "afii57666" },
+ { 0x05D3, 0, "afii57667" },
+ { 0x05D4, 0, "afii57668" },
+ { 0x05D5, 0, "afii57669" },
+ { 0x05D6, 0, "afii57670" },
+ { 0x05D7, 0, "afii57671" },
+ { 0x05D8, 0, "afii57672" },
+ { 0x05D9, 0, "afii57673" },
+ { 0x05DA, 0, "afii57674" },
+ { 0x05DB, 0, "afii57675" },
+ { 0x05DC, 0, "afii57676" },
+ { 0x05DD, 0, "afii57677" },
+ { 0x05DE, 0, "afii57678" },
+ { 0x05DF, 0, "afii57679" },
+ { 0x05E0, 0, "afii57680" },
+ { 0x05E1, 0, "afii57681" },
+ { 0x05E2, 0, "afii57682" },
+ { 0x05E3, 0, "afii57683" },
+ { 0x05E4, 0, "afii57684" },
+ { 0x05E5, 0, "afii57685" },
+ { 0x05E6, 0, "afii57686" },
+ { 0x05E7, 0, "afii57687" },
+ { 0x05E8, 0, "afii57688" },
+ { 0x05E9, 0, "afii57689" },
+ { 0x05EA, 0, "afii57690" },
+ { 0xFB2A, 0, "afii57694" },
+ { 0xFB2B, 0, "afii57695" },
+ { 0xFB4B, 0, "afii57700" },
+ { 0xFB1F, 0, "afii57705" },
+ { 0x05F0, 0, "afii57716" },
+ { 0x05F1, 0, "afii57717" },
+ { 0x05F2, 0, "afii57718" },
+ { 0xFB35, 0, "afii57723" },
+ { 0x05B4, 0, "afii57793" },
+ { 0x05B5, 0, "afii57794" },
+ { 0x05B6, 0, "afii57795" },
+ { 0x05BB, 0, "afii57796" },
+ { 0x05B8, 0, "afii57797" },
+ { 0x05B7, 0, "afii57798" },
+ { 0x05B0, 0, "afii57799" },
+ { 0x05B2, 0, "afii57800" },
+ { 0x05B1, 0, "afii57801" },
+ { 0x05B3, 0, "afii57802" },
+ { 0x05C2, 0, "afii57803" },
+ { 0x05C1, 0, "afii57804" },
+ { 0x05B9, 0, "afii57806" },
+ { 0x05BC, 0, "afii57807" },
+ { 0x05BD, 0, "afii57839" },
+ { 0x05BF, 0, "afii57841" },
+ { 0x05C0, 0, "afii57842" },
+ { 0x02BC, 0, "afii57929" },
+ { 0x2105, 0, "afii61248" },
+ { 0x2113, 0, "afii61289" },
+ { 0x2116, 0, "afii61352" },
+ { 0x202C, 0, "afii61573" },
+ { 0x202D, 0, "afii61574" },
+ { 0x202E, 0, "afii61575" },
+ { 0x200C, 0, "afii61664" },
+ { 0x066D, 0, "afii63167" },
+ { 0x02BD, 0, "afii64937" },
+ { 0x00E0, 0, "agrave" },
+ { 0x2135, 0, "aleph" },
+ { 0x03B1, 0, "alpha" },
+ { 0x03AC, 0, "alphatonos" },
+ { 0x0101, 0, "amacron" },
+ { 0x0026, 046, "ampersand" },
+ { 0xF726, 0, "ampersandsmall" },
+ { 0x2220, 0, "angle" },
+ { 0x2329, 0, "angleleft" },
+ { 0x232A, 0, "angleright" },
+ { 0x0387, 0, "anoteleia" },
+ { 0x0105, 0, "aogonek" },
+ { 0x2248, 0, "approxequal" },
+ { 0x00E5, 0, "aring" },
+ { 0x01FB, 0, "aringacute" },
+ { 0x2194, 0, "arrowboth" },
+ { 0x21D4, 0, "arrowdblboth" },
+ { 0x21D3, 0, "arrowdbldown" },
+ { 0x21D0, 0, "arrowdblleft" },
+ { 0x21D2, 0, "arrowdblright" },
+ { 0x21D1, 0, "arrowdblup" },
+ { 0x2193, 0, "arrowdown" },
+ { 0xF8E7, 0, "arrowhorizex" },
+ { 0x2190, 0, "arrowleft" },
+ { 0x2192, 0, "arrowright" },
+ { 0x2191, 0, "arrowup" },
+ { 0x2195, 0, "arrowupdn" },
+ { 0x21A8, 0, "arrowupdnbse" },
+ { 0xF8E6, 0, "arrowvertex" },
+ { 0x005E, 0136, "asciicircum" },
+ { 0x007E, 0176, "asciitilde" },
+ { 0x002A, 052, "asterisk" },
+ { 0x2217, 0, "asteriskmath" },
+ { 0xF6E9, 0, "asuperior" },
+ { 0x0040, 0100, "at" },
+ { 0x00E3, 0, "atilde" },
+ { 0x0062, 0142, "b" },
+ { 0x005C, 0134, "backslash" },
+ { 0x007C, 0174, "bar" },
+ { 0x03B2, 0, "beta" },
+ { 0x2588, 0, "block" },
+ { 0xF8F4, 0, "braceex" },
+ { 0x007B, 0173, "braceleft" },
+ { 0xF8F3, 0, "braceleftbt" },
+ { 0xF8F2, 0, "braceleftmid" },
+ { 0xF8F1, 0, "bracelefttp" },
+ { 0x007D, 0175, "braceright" },
+ { 0xF8FE, 0, "bracerightbt" },
+ { 0xF8FD, 0, "bracerightmid" },
+ { 0xF8FC, 0, "bracerighttp" },
+ { 0x005B, 0133, "bracketleft" },
+ { 0xF8F0, 0, "bracketleftbt" },
+ { 0xF8EF, 0, "bracketleftex" },
+ { 0xF8EE, 0, "bracketlefttp" },
+ { 0x005D, 0135, "bracketright" },
+ { 0xF8FB, 0, "bracketrightbt" },
+ { 0xF8FA, 0, "bracketrightex" },
+ { 0xF8F9, 0, "bracketrighttp" },
+ { 0x02D8, 0306, "breve" },
+ { 0x00A6, 0, "brokenbar" },
+ { 0xF6EA, 0, "bsuperior" },
+ { 0x2022, 0267, "bullet" },
+ { 0x0063, 0143, "c" },
+ { 0x0107, 0, "cacute" },
+ { 0x02C7, 0317, "caron" },
+ { 0x21B5, 0, "carriagereturn" },
+ { 0x010D, 0, "ccaron" },
+ { 0x00E7, 0, "ccedilla" },
+ { 0x0109, 0, "ccircumflex" },
+ { 0x010B, 0, "cdotaccent" },
+ { 0x00B8, 0313, "cedilla" },
+ { 0x00A2, 0242, "cent" },
+ { 0xF6DF, 0, "centinferior" },
+ { 0xF7A2, 0, "centoldstyle" },
+ { 0xF6E0, 0, "centsuperior" },
+ { 0x03C7, 0, "chi" },
+ { 0x25CB, 0, "circle" },
+ { 0x2297, 0, "circlemultiply" },
+ { 0x2295, 0, "circleplus" },
+ { 0x02C6, 0303, "circumflex" },
+ { 0x2663, 0, "club" },
+ { 0x003A, 072, "colon" },
+ { 0x20A1, 0, "colonmonetary" },
+ { 0x002C, 054, "comma" },
+ { 0xF6C3, 0, "commaaccent" },
+ { 0xF6E1, 0, "commainferior" },
+ { 0xF6E2, 0, "commasuperior" },
+ { 0x2245, 0, "congruent" },
+ { 0x00A9, 0, "copyright" },
+ { 0xF8E9, 0, "copyrightsans" },
+ { 0xF6D9, 0, "copyrightserif" },
+ { 0x00A4, 0250, "currency" },
+ { 0xF6D1, 0, "cyrBreve" },
+ { 0xF6D2, 0, "cyrFlex" },
+ { 0xF6D4, 0, "cyrbreve" },
+ { 0xF6D5, 0, "cyrflex" },
+ { 0x0064, 0144, "d" },
+ { 0x2020, 0262, "dagger" },
+ { 0x2021, 0263, "daggerdbl" },
+ { 0xF6D3, 0, "dblGrave" },
+ { 0xF6D6, 0, "dblgrave" },
+ { 0x010F, 0, "dcaron" },
+ { 0x0111, 0, "dcroat" },
+ { 0x00B0, 0, "degree" },
+ { 0x03B4, 0, "delta" },
+ { 0x2666, 0, "diamond" },
+ { 0x00A8, 0310, "dieresis" },
+ { 0xF6D7, 0, "dieresisacute" },
+ { 0xF6D8, 0, "dieresisgrave" },
+ { 0x0385, 0, "dieresistonos" },
+ { 0x00F7, 0, "divide" },
+ { 0x2593, 0, "dkshade" },
+ { 0x2584, 0, "dnblock" },
+ { 0x0024, 044, "dollar" },
+ { 0xF6E3, 0, "dollarinferior" },
+ { 0xF724, 0, "dollaroldstyle" },
+ { 0xF6E4, 0, "dollarsuperior" },
+ { 0x20AB, 0, "dong" },
+ { 0x02D9, 0307, "dotaccent" },
+ { 0x0323, 0, "dotbelowcomb" },
+ { 0x0131, 0365, "dotlessi" },
+ { 0xF6BE, 0, "dotlessj" },
+ { 0x22C5, 0, "dotmath" },
+ { 0xF6EB, 0, "dsuperior" },
+ { 0x0065, 0145, "e" },
+ { 0x00E9, 0, "eacute" },
+ { 0x0115, 0, "ebreve" },
+ { 0x011B, 0, "ecaron" },
+ { 0x00EA, 0, "ecircumflex" },
+ { 0x00EB, 0, "edieresis" },
+ { 0x0117, 0, "edotaccent" },
+ { 0x00E8, 0, "egrave" },
+ { 0x0038, 070, "eight" },
+ { 0x2088, 0, "eightinferior" },
+ { 0xF738, 0, "eightoldstyle" },
+ { 0x2078, 0, "eightsuperior" },
+ { 0x2208, 0, "element" },
+ { 0x2026, 0274, "ellipsis" },
+ { 0x0113, 0, "emacron" },
+ { 0x2014, 0320, "emdash" },
+ { 0x2205, 0, "emptyset" },
+ { 0x2013, 0261, "endash" },
+ { 0x014B, 0, "eng" },
+ { 0x0119, 0, "eogonek" },
+ { 0x03B5, 0, "epsilon" },
+ { 0x03AD, 0, "epsilontonos" },
+ { 0x003D, 075, "equal" },
+ { 0x2261, 0, "equivalence" },
+ { 0x212E, 0, "estimated" },
+ { 0xF6EC, 0, "esuperior" },
+ { 0x03B7, 0, "eta" },
+ { 0x03AE, 0, "etatonos" },
+ { 0x00F0, 0, "eth" },
+ { 0x0021, 041, "exclam" },
+ { 0x203C, 0, "exclamdbl" },
+ { 0x00A1, 0241, "exclamdown" },
+ { 0xF7A1, 0, "exclamdownsmall" },
+ { 0xF721, 0, "exclamsmall" },
+ { 0x2203, 0, "existential" },
+ { 0x0066, 0146, "f" },
+ { 0x2640, 0, "female" },
+ { 0xFB00, 0, "ff" },
+ { 0xFB03, 0, "ffi" },
+ { 0xFB04, 0, "ffl" },
+ { 0xFB01, 0256, "fi" },
+ { 0x2012, 0, "figuredash" },
+ { 0x25A0, 0, "filledbox" },
+ { 0x25AC, 0, "filledrect" },
+ { 0x0035, 065, "five" },
+ { 0x215D, 0, "fiveeighths" },
+ { 0x2085, 0, "fiveinferior" },
+ { 0xF735, 0, "fiveoldstyle" },
+ { 0x2075, 0, "fivesuperior" },
+ { 0xFB02, 0257, "fl" },
+ { 0x0192, 0246, "florin" },
+ { 0x0034, 064, "four" },
+ { 0x2084, 0, "fourinferior" },
+ { 0xF734, 0, "fouroldstyle" },
+ { 0x2074, 0, "foursuperior" },
+ { 0x2044, 0244, "fraction" },
+ { 0x2215, 0244, "fraction" },
+ { 0x20A3, 0, "franc" },
+ { 0x0067, 0147, "g" },
+ { 0x03B3, 0, "gamma" },
+ { 0x011F, 0, "gbreve" },
+ { 0x01E7, 0, "gcaron" },
+ { 0x011D, 0, "gcircumflex" },
+ { 0x0123, 0, "gcommaaccent" },
+ { 0x0121, 0, "gdotaccent" },
+ { 0x00DF, 0373, "germandbls" },
+ { 0x2207, 0, "gradient" },
+ { 0x0060, 0301, "grave" },
+ { 0x0300, 0, "gravecomb" },
+ { 0x003E, 076, "greater" },
+ { 0x2265, 0, "greaterequal" },
+ { 0x00AB, 0253, "guillemotleft" },
+ { 0x00BB, 0273, "guillemotright" },
+ { 0x2039, 0254, "guilsinglleft" },
+ { 0x203A, 0255, "guilsinglright" },
+ { 0x0068, 0150, "h" },
+ { 0x0127, 0, "hbar" },
+ { 0x0125, 0, "hcircumflex" },
+ { 0x2665, 0, "heart" },
+ { 0x0309, 0, "hookabovecomb" },
+ { 0x2302, 0, "house" },
+ { 0x02DD, 0315, "hungarumlaut" },
+ { 0x002D, 055, "hyphen" },
+ { 0x00AD, 0, "hyphen" },
+ { 0xF6E5, 0, "hypheninferior" },
+ { 0xF6E6, 0, "hyphensuperior" },
+ { 0x0069, 0151, "i" },
+ { 0x00ED, 0, "iacute" },
+ { 0x012D, 0, "ibreve" },
+ { 0x00EE, 0, "icircumflex" },
+ { 0x00EF, 0, "idieresis" },
+ { 0x00EC, 0, "igrave" },
+ { 0x0133, 0, "ij" },
+ { 0x012B, 0, "imacron" },
+ { 0x221E, 0, "infinity" },
+ { 0x222B, 0, "integral" },
+ { 0x2321, 0, "integralbt" },
+ { 0xF8F5, 0, "integralex" },
+ { 0x2320, 0, "integraltp" },
+ { 0x2229, 0, "intersection" },
+ { 0x25D8, 0, "invbullet" },
+ { 0x25D9, 0, "invcircle" },
+ { 0x263B, 0, "invsmileface" },
+ { 0x012F, 0, "iogonek" },
+ { 0x03B9, 0, "iota" },
+ { 0x03CA, 0, "iotadieresis" },
+ { 0x0390, 0, "iotadieresistonos" },
+ { 0x03AF, 0, "iotatonos" },
+ { 0xF6ED, 0, "isuperior" },
+ { 0x0129, 0, "itilde" },
+ { 0x006A, 0152, "j" },
+ { 0x0135, 0, "jcircumflex" },
+ { 0x006B, 0153, "k" },
+ { 0x03BA, 0, "kappa" },
+ { 0x0137, 0, "kcommaaccent" },
+ { 0x0138, 0, "kgreenlandic" },
+ { 0x006C, 0154, "l" },
+ { 0x013A, 0, "lacute" },
+ { 0x03BB, 0, "lambda" },
+ { 0x013E, 0, "lcaron" },
+ { 0x013C, 0, "lcommaaccent" },
+ { 0x0140, 0, "ldot" },
+ { 0x003C, 074, "less" },
+ { 0x2264, 0, "lessequal" },
+ { 0x258C, 0, "lfblock" },
+ { 0x20A4, 0, "lira" },
+ { 0xF6C0, 0, "ll" },
+ { 0x2227, 0, "logicaland" },
+ { 0x00AC, 0, "logicalnot" },
+ { 0x2228, 0, "logicalor" },
+ { 0x017F, 0, "longs" },
+ { 0x25CA, 0, "lozenge" },
+ { 0x0142, 0370, "lslash" },
+ { 0xF6EE, 0, "lsuperior" },
+ { 0x2591, 0, "ltshade" },
+ { 0x006D, 0155, "m" },
+ { 0x00AF, 0305, "macron" },
+ { 0x02C9, 0305, "macron" },
+ { 0x2642, 0, "male" },
+ { 0x2212, 0, "minus" },
+ { 0x2032, 0, "minute" },
+ { 0xF6EF, 0, "msuperior" },
+ { 0x00B5, 0, "mu" },
+ { 0x03BC, 0, "mu" },
+ { 0x00D7, 0, "multiply" },
+ { 0x266A, 0, "musicalnote" },
+ { 0x266B, 0, "musicalnotedbl" },
+ { 0x006E, 0156, "n" },
+ { 0x0144, 0, "nacute" },
+ { 0x0149, 0, "napostrophe" },
+ { 0x0148, 0, "ncaron" },
+ { 0x0146, 0, "ncommaaccent" },
+ { 0x0039, 071, "nine" },
+ { 0x2089, 0, "nineinferior" },
+ { 0xF739, 0, "nineoldstyle" },
+ { 0x2079, 0, "ninesuperior" },
+ { 0x2209, 0, "notelement" },
+ { 0x2260, 0, "notequal" },
+ { 0x2284, 0, "notsubset" },
+ { 0x207F, 0, "nsuperior" },
+ { 0x00F1, 0, "ntilde" },
+ { 0x03BD, 0, "nu" },
+ { 0x0023, 043, "numbersign" },
+ { 0x006F, 0157, "o" },
+ { 0x00F3, 0, "oacute" },
+ { 0x014F, 0, "obreve" },
+ { 0x00F4, 0, "ocircumflex" },
+ { 0x00F6, 0, "odieresis" },
+ { 0x0153, 0372, "oe" },
+ { 0x02DB, 0316, "ogonek" },
+ { 0x00F2, 0, "ograve" },
+ { 0x01A1, 0, "ohorn" },
+ { 0x0151, 0, "ohungarumlaut" },
+ { 0x014D, 0, "omacron" },
+ { 0x03C9, 0, "omega" },
+ { 0x03D6, 0, "omega1" },
+ { 0x03CE, 0, "omegatonos" },
+ { 0x03BF, 0, "omicron" },
+ { 0x03CC, 0, "omicrontonos" },
+ { 0x0031, 061, "one" },
+ { 0x2024, 0, "onedotenleader" },
+ { 0x215B, 0, "oneeighth" },
+ { 0xF6DC, 0, "onefitted" },
+ { 0x00BD, 0, "onehalf" },
+ { 0x2081, 0, "oneinferior" },
+ { 0xF731, 0, "oneoldstyle" },
+ { 0x00BC, 0, "onequarter" },
+ { 0x00B9, 0, "onesuperior" },
+ { 0x2153, 0, "onethird" },
+ { 0x25E6, 0, "openbullet" },
+ { 0x00AA, 0343, "ordfeminine" },
+ { 0x00BA, 0353, "ordmasculine" },
+ { 0x221F, 0, "orthogonal" },
+ { 0x00F8, 0371, "oslash" },
+ { 0x01FF, 0, "oslashacute" },
+ { 0xF6F0, 0, "osuperior" },
+ { 0x00F5, 0, "otilde" },
+ { 0x0070, 0160, "p" },
+ { 0x00B6, 0266, "paragraph" },
+ { 0x0028, 050, "parenleft" },
+ { 0xF8ED, 0, "parenleftbt" },
+ { 0xF8EC, 0, "parenleftex" },
+ { 0x208D, 0, "parenleftinferior" },
+ { 0x207D, 0, "parenleftsuperior" },
+ { 0xF8EB, 0, "parenlefttp" },
+ { 0x0029, 051, "parenright" },
+ { 0xF8F8, 0, "parenrightbt" },
+ { 0xF8F7, 0, "parenrightex" },
+ { 0x208E, 0, "parenrightinferior" },
+ { 0x207E, 0, "parenrightsuperior" },
+ { 0xF8F6, 0, "parenrighttp" },
+ { 0x2202, 0, "partialdiff" },
+ { 0x0025, 045, "percent" },
+ { 0x002E, 056, "period" },
+ { 0x00B7, 0264, "periodcentered" },
+ { 0x2219, 0, "periodcentered" },
+ { 0xF6E7, 0, "periodinferior" },
+ { 0xF6E8, 0, "periodsuperior" },
+ { 0x22A5, 0, "perpendicular" },
+ { 0x2030, 0275, "perthousand" },
+ { 0x20A7, 0, "peseta" },
+ { 0x03C6, 0, "phi" },
+ { 0x03D5, 0, "phi1" },
+ { 0x03C0, 0, "pi" },
+ { 0x002B, 053, "plus" },
+ { 0x00B1, 0, "plusminus" },
+ { 0x211E, 0, "prescription" },
+ { 0x220F, 0, "product" },
+ { 0x2282, 0, "propersubset" },
+ { 0x2283, 0, "propersuperset" },
+ { 0x221D, 0, "proportional" },
+ { 0x03C8, 0, "psi" },
+ { 0x0071, 0161, "q" },
+ { 0x003F, 077, "question" },
+ { 0x00BF, 0277, "questiondown" },
+ { 0xF7BF, 0, "questiondownsmall" },
+ { 0xF73F, 0, "questionsmall" },
+ { 0x0022, 042, "quotedbl" },
+ { 0x201E, 0271, "quotedblbase" },
+ { 0x201C, 0252, "quotedblleft" },
+ { 0x201D, 0272, "quotedblright" },
+ { 0x2018, 0140, "quoteleft" },
+ { 0x201B, 0, "quotereversed" },
+ { 0x2019, 047, "quoteright" },
+ { 0x201A, 0270, "quotesinglbase" },
+ { 0x0027, 0251, "quotesingle" },
+ { 0x0072, 0162, "r" },
+ { 0x0155, 0, "racute" },
+ { 0x221A, 0, "radical" },
+ { 0xF8E5, 0, "radicalex" },
+ { 0x0159, 0, "rcaron" },
+ { 0x0157, 0, "rcommaaccent" },
+ { 0x2286, 0, "reflexsubset" },
+ { 0x2287, 0, "reflexsuperset" },
+ { 0x00AE, 0, "registered" },
+ { 0xF8E8, 0, "registersans" },
+ { 0xF6DA, 0, "registerserif" },
+ { 0x2310, 0, "revlogicalnot" },
+ { 0x03C1, 0, "rho" },
+ { 0x02DA, 0312, "ring" },
+ { 0xF6F1, 0, "rsuperior" },
+ { 0x2590, 0, "rtblock" },
+ { 0xF6DD, 0, "rupiah" },
+ { 0x0073, 0163, "s" },
+ { 0x015B, 0, "sacute" },
+ { 0x0161, 0, "scaron" },
+ { 0x015F, 0, "scedilla" },
+ { 0xF6C2, 0, "scedilla" },
+ { 0x015D, 0, "scircumflex" },
+ { 0x0219, 0, "scommaaccent" },
+ { 0x2033, 0, "second" },
+ { 0x00A7, 0247, "section" },
+ { 0x003B, 073, "semicolon" },
+ { 0x0037, 067, "seven" },
+ { 0x215E, 0, "seveneighths" },
+ { 0x2087, 0, "seveninferior" },
+ { 0xF737, 0, "sevenoldstyle" },
+ { 0x2077, 0, "sevensuperior" },
+ { 0x2592, 0, "shade" },
+ { 0x03C3, 0, "sigma" },
+ { 0x03C2, 0, "sigma1" },
+ { 0x223C, 0, "similar" },
+ { 0x0036, 066, "six" },
+ { 0x2086, 0, "sixinferior" },
+ { 0xF736, 0, "sixoldstyle" },
+ { 0x2076, 0, "sixsuperior" },
+ { 0x002F, 057, "slash" },
+ { 0x263A, 0, "smileface" },
+ { 0x0020, 040, "space" },
+ { 0x00A0, 040, "space" },
+ { 0x2660, 0, "spade" },
+ { 0xF6F2, 0, "ssuperior" },
+ { 0x00A3, 0243, "sterling" },
+ { 0x220B, 0, "suchthat" },
+ { 0x2211, 0, "summation" },
+ { 0x263C, 0, "sun" },
+ { 0x0074, 0164, "t" },
+ { 0x03C4, 0, "tau" },
+ { 0x0167, 0, "tbar" },
+ { 0x0165, 0, "tcaron" },
+ { 0x0163, 0, "tcommaaccent" },
+ { 0x021B, 0, "tcommaaccent" },
+ { 0x2234, 0, "therefore" },
+ { 0x03B8, 0, "theta" },
+ { 0x03D1, 0, "theta1" },
+ { 0x00FE, 0, "thorn" },
+ { 0x0033, 063, "three" },
+ { 0x215C, 0, "threeeighths" },
+ { 0x2083, 0, "threeinferior" },
+ { 0xF733, 0, "threeoldstyle" },
+ { 0x00BE, 0, "threequarters" },
+ { 0xF6DE, 0, "threequartersemdash" },
+ { 0x00B3, 0, "threesuperior" },
+ { 0x02DC, 0304, "tilde" },
+ { 0x0303, 0, "tildecomb" },
+ { 0x0384, 0, "tonos" },
+ { 0x2122, 0, "trademark" },
+ { 0xF8EA, 0, "trademarksans" },
+ { 0xF6DB, 0, "trademarkserif" },
+ { 0x25BC, 0, "triagdn" },
+ { 0x25C4, 0, "triaglf" },
+ { 0x25BA, 0, "triagrt" },
+ { 0x25B2, 0, "triagup" },
+ { 0xF6F3, 0, "tsuperior" },
+ { 0x0032, 062, "two" },
+ { 0x2025, 0, "twodotenleader" },
+ { 0x2082, 0, "twoinferior" },
+ { 0xF732, 0, "twooldstyle" },
+ { 0x00B2, 0, "twosuperior" },
+ { 0x2154, 0, "twothirds" },
+ { 0x0075, 0165, "u" },
+ { 0x00FA, 0, "uacute" },
+ { 0x016D, 0, "ubreve" },
+ { 0x00FB, 0, "ucircumflex" },
+ { 0x00FC, 0, "udieresis" },
+ { 0x00F9, 0, "ugrave" },
+ { 0x01B0, 0, "uhorn" },
+ { 0x0171, 0, "uhungarumlaut" },
+ { 0x016B, 0, "umacron" },
+ { 0x005F, 0137, "underscore" },
+ { 0x2017, 0, "underscoredbl" },
+ { 0x222A, 0, "union" },
+ { 0x2200, 0, "universal" },
+ { 0x0173, 0, "uogonek" },
+ { 0x2580, 0, "upblock" },
+ { 0x03C5, 0, "upsilon" },
+ { 0x03CB, 0, "upsilondieresis" },
+ { 0x03B0, 0, "upsilondieresistonos" },
+ { 0x03CD, 0, "upsilontonos" },
+ { 0x016F, 0, "uring" },
+ { 0x0169, 0, "utilde" },
+ { 0x0076, 0166, "v" },
+ { 0x0077, 0167, "w" },
+ { 0x1E83, 0, "wacute" },
+ { 0x0175, 0, "wcircumflex" },
+ { 0x1E85, 0, "wdieresis" },
+ { 0x2118, 0, "weierstrass" },
+ { 0x1E81, 0, "wgrave" },
+ { 0x0078, 0170, "x" },
+ { 0x03BE, 0, "xi" },
+ { 0x0079, 0171, "y" },
+ { 0x00FD, 0, "yacute" },
+ { 0x0177, 0, "ycircumflex" },
+ { 0x00FF, 0, "ydieresis" },
+ { 0x00A5, 0245, "yen" },
+ { 0x1EF3, 0, "ygrave" },
+ { 0x007A, 0172, "z" },
+ { 0x017A, 0, "zacute" },
+ { 0x017E, 0, "zcaron" },
+ { 0x017C, 0, "zdotaccent" },
+ { 0x0030, 060, "zero" },
+ { 0x2080, 0, "zeroinferior" },
+ { 0xF730, 0, "zerooldstyle" },
+ { 0x2070, 0, "zerosuperior" },
+ { 0x03B6, 0, "zeta" }
+};
diff --git a/vcl/unx/source/fontmanager/afm_hash.cpp b/vcl/unx/source/fontmanager/afm_hash.cpp
new file mode 100755
index 000000000000..de01d8cd0434
--- /dev/null
+++ b/vcl/unx/source/fontmanager/afm_hash.cpp
@@ -0,0 +1,245 @@
+/* C++ code produced by gperf version 3.0.1 */
+/* Command-line: gperf -C -t -l -L C++ -m 20 -Z AfmKeywordHash afm_keyword_list */
+/* Computed positions: -k'1,4,6,$' */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646. */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
+#endif
+
+#line 1 "afm_keyword_list"
+struct hash_entry { const char* name; enum parseKey eKey; };
+
+#define TOTAL_KEYWORDS 56
+#define MIN_WORD_LENGTH 1
+#define MAX_WORD_LENGTH 18
+#define MIN_HASH_VALUE 1
+#define MAX_HASH_VALUE 57
+/* maximum key range = 57, duplicates = 0 */
+
+class AfmKeywordHash
+{
+private:
+ static inline unsigned int hash (const char *str, unsigned int len);
+public:
+ static const struct hash_entry *in_word_set (const char *str, unsigned int len);
+};
+
+inline unsigned int
+AfmKeywordHash::hash (register const char *str, register unsigned int len)
+{
+ static const unsigned char asso_values[] =
+ {
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 28, 1, 0, 9, 0,
+ 19, 58, 2, 10, 58, 0, 28, 0, 20, 58,
+ 44, 58, 58, 0, 16, 10, 24, 2, 3, 58,
+ 58, 58, 58, 58, 58, 58, 58, 6, 58, 0,
+ 19, 0, 58, 25, 14, 6, 58, 58, 17, 11,
+ 0, 17, 39, 58, 0, 0, 10, 58, 58, 58,
+ 13, 4, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58
+ };
+ register int hval = len;
+
+ switch (hval)
+ {
+ default:
+ hval += asso_values[(unsigned char)str[5]];
+ /*FALLTHROUGH*/
+ case 5:
+ case 4:
+ hval += asso_values[(unsigned char)str[3]];
+ /*FALLTHROUGH*/
+ case 3:
+ case 2:
+ case 1:
+ hval += asso_values[(unsigned char)str[0]];
+ break;
+ }
+ return hval + asso_values[(unsigned char)str[len - 1]];
+}
+
+const struct hash_entry *
+AfmKeywordHash::in_word_set (register const char *str, register unsigned int len)
+{
+ static const unsigned char lengthtable[] =
+ {
+ 0, 1, 2, 1, 2, 1, 3, 2, 3, 5, 10, 11, 12, 2,
+ 14, 15, 16, 11, 9, 13, 14, 12, 12, 14, 13, 9, 7, 9,
+ 7, 9, 14, 5, 6, 14, 12, 16, 10, 14, 11, 10, 7, 1,
+ 12, 8, 17, 18, 2, 3, 7, 1, 8, 8, 13, 6, 6, 8,
+ 0, 1
+ };
+ static const struct hash_entry wordlist[] =
+ {
+ {"",NOPE},
+#line 6 "afm_keyword_list"
+ {"C",CODE},
+#line 7 "afm_keyword_list"
+ {"CC",COMPCHAR},
+#line 5 "afm_keyword_list"
+ {"B",CHARBBOX},
+#line 8 "afm_keyword_list"
+ {"CH",CODEHEX},
+#line 54 "afm_keyword_list"
+ {"W",XYWIDTH},
+#line 33 "afm_keyword_list"
+ {"KPX",KERNPAIRXAMT},
+#line 56 "afm_keyword_list"
+ {"WX",XWIDTH},
+#line 55 "afm_keyword_list"
+ {"W0X",X0WIDTH},
+#line 47 "afm_keyword_list"
+ {"StdHW",STDHW},
+#line 12 "afm_keyword_list"
+ {"Characters",CHARACTERS},
+#line 36 "afm_keyword_list"
+ {"MetricsSets",METRICSSETS},
+#line 23 "afm_keyword_list"
+ {"EndKernPairs",ENDKERNPAIRS},
+#line 16 "afm_keyword_list"
+ {"Em",EM},
+#line 45 "afm_keyword_list"
+ {"StartKernPairs",STARTKERNPAIRS},
+#line 41 "afm_keyword_list"
+ {"StartComposites",STARTCOMPOSITES},
+#line 40 "afm_keyword_list"
+ {"StartCharMetrics",STARTCHARMETRICS},
+#line 22 "afm_keyword_list"
+ {"EndKernData",ENDKERNDATA},
+#line 14 "afm_keyword_list"
+ {"Descender",DESCENDER},
+#line 44 "afm_keyword_list"
+ {"StartKernData",STARTKERNDATA},
+#line 18 "afm_keyword_list"
+ {"EndCharMetrics",ENDCHARMETRICS},
+#line 20 "afm_keyword_list"
+ {"EndDirection",ENDDIRECTION},
+#line 11 "afm_keyword_list"
+ {"CharacterSet",CHARACTERSET},
+#line 42 "afm_keyword_list"
+ {"StartDirection",STARTDIRECTION},
+#line 19 "afm_keyword_list"
+ {"EndComposites",ENDCOMPOSITES},
+#line 49 "afm_keyword_list"
+ {"TrackKern",TRACKKERN},
+#line 15 "afm_keyword_list"
+ {"Descent",DESCENT},
+#line 9 "afm_keyword_list"
+ {"CapHeight",CAPHEIGHT},
+#line 13 "afm_keyword_list"
+ {"Comment",COMMENT},
+#line 10 "afm_keyword_list"
+ {"CharWidth",CHARWIDTH},
+#line 46 "afm_keyword_list"
+ {"StartTrackKern",STARTTRACKKERN},
+#line 48 "afm_keyword_list"
+ {"StdVW",STDVW},
+#line 38 "afm_keyword_list"
+ {"Notice",NOTICE},
+#line 21 "afm_keyword_list"
+ {"EndFontMetrics",ENDFONTMETRICS},
+#line 24 "afm_keyword_list"
+ {"EndTrackKern",ENDTRACKKERN},
+#line 43 "afm_keyword_list"
+ {"StartFontMetrics",STARTFONTMETRICS},
+#line 29 "afm_keyword_list"
+ {"IsBaseFont",ISBASEFONT},
+#line 17 "afm_keyword_list"
+ {"EncodingScheme",ENCODINGSCHEME},
+#line 31 "afm_keyword_list"
+ {"ItalicAngle",ITALICANGLE},
+#line 25 "afm_keyword_list"
+ {"FamilyName",FAMILYNAME},
+#line 58 "afm_keyword_list"
+ {"XHeight",XHEIGHT},
+#line 37 "afm_keyword_list"
+ {"N",CHARNAME},
+#line 30 "afm_keyword_list"
+ {"IsFixedPitch",ISFIXEDPITCH},
+#line 27 "afm_keyword_list"
+ {"FontName",FONTNAME},
+#line 50 "afm_keyword_list"
+ {"UnderlinePosition",UNDERLINEPOSITION},
+#line 51 "afm_keyword_list"
+ {"UnderlineThickness",UNDERLINETHICKNESS},
+#line 32 "afm_keyword_list"
+ {"KP",KERNPAIR},
+#line 39 "afm_keyword_list"
+ {"PCC",COMPCHARPIECE},
+#line 53 "afm_keyword_list"
+ {"Version",VERSION},
+#line 52 "afm_keyword_list"
+ {"V",VVECTOR},
+#line 28 "afm_keyword_list"
+ {"FullName",FULLNAME},
+#line 26 "afm_keyword_list"
+ {"FontBBox",FONTBBOX},
+#line 35 "afm_keyword_list"
+ {"MappingScheme",MAPPINGSCHEME},
+#line 57 "afm_keyword_list"
+ {"Weight",WEIGHT},
+#line 4 "afm_keyword_list"
+ {"Ascent",ASCENT},
+#line 3 "afm_keyword_list"
+ {"Ascender",ASCENDER},
+ {"",NOPE},
+#line 34 "afm_keyword_list"
+ {"L",LIGATURE}
+ };
+
+ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+ {
+ register int key = hash (str, len);
+
+ if (key <= MAX_HASH_VALUE && key >= 0)
+ if (len == lengthtable[key])
+ {
+ register const char *s = wordlist[key].name;
+
+ if (*str == *s && !memcmp (str + 1, s + 1, len - 1))
+ return &wordlist[key];
+ }
+ }
+ return 0;
+}
diff --git a/vcl/unx/source/fontmanager/afm_keyword_list b/vcl/unx/source/fontmanager/afm_keyword_list
new file mode 100755
index 000000000000..263d76bca4d3
--- /dev/null
+++ b/vcl/unx/source/fontmanager/afm_keyword_list
@@ -0,0 +1,58 @@
+struct hash_entry { char* name; enum parseKey eKey; };
+%%
+Ascender,ASCENDER
+Ascent,ASCENT
+B,CHARBBOX
+C,CODE
+CC,COMPCHAR
+CH,CODEHEX
+CapHeight,CAPHEIGHT
+CharWidth,CHARWIDTH
+CharacterSet,CHARACTERSET
+Characters,CHARACTERS
+Comment,COMMENT
+Descender,DESCENDER
+Descent,DESCENT
+Em,EM
+EncodingScheme,ENCODINGSCHEME
+EndCharMetrics,ENDCHARMETRICS
+EndComposites,ENDCOMPOSITES
+EndDirection,ENDDIRECTION
+EndFontMetrics,ENDFONTMETRICS
+EndKernData,ENDKERNDATA
+EndKernPairs,ENDKERNPAIRS
+EndTrackKern,ENDTRACKKERN
+FamilyName,FAMILYNAME
+FontBBox,FONTBBOX
+FontName,FONTNAME
+FullName,FULLNAME
+IsBaseFont,ISBASEFONT
+IsFixedPitch,ISFIXEDPITCH
+ItalicAngle,ITALICANGLE
+KP,KERNPAIR
+KPX,KERNPAIRXAMT
+L,LIGATURE
+MappingScheme,MAPPINGSCHEME
+MetricsSets,METRICSSETS
+N,CHARNAME
+Notice,NOTICE
+PCC,COMPCHARPIECE
+StartCharMetrics,STARTCHARMETRICS
+StartComposites,STARTCOMPOSITES
+StartDirection,STARTDIRECTION
+StartFontMetrics,STARTFONTMETRICS
+StartKernData,STARTKERNDATA
+StartKernPairs,STARTKERNPAIRS
+StartTrackKern,STARTTRACKKERN
+StdHW,STDHW
+StdVW,STDVW
+TrackKern,TRACKKERN
+UnderlinePosition,UNDERLINEPOSITION
+UnderlineThickness,UNDERLINETHICKNESS
+V,VVECTOR
+Version,VERSION
+W,XYWIDTH
+W0X,X0WIDTH
+WX,XWIDTH
+Weight,WEIGHT
+XHeight,XHEIGHT
diff --git a/vcl/unx/source/fontmanager/fontcache.cxx b/vcl/unx/source/fontmanager/fontcache.cxx
new file mode 100644
index 000000000000..db4a7d05e5fc
--- /dev/null
+++ b/vcl/unx/source/fontmanager/fontcache.cxx
@@ -0,0 +1,811 @@
+/*************************************************************************
+ *
+ * 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 <cstdlib>
+#include <cstring>
+
+#include "vcl/fontcache.hxx"
+
+#include "osl/thread.h"
+
+#include "unotools/atom.hxx"
+
+#include "tools/stream.hxx"
+
+#include <unistd.h>
+#include <sys/stat.h>
+
+#if OSL_DEBUG_LEVEL >1
+#include <cstdio>
+#endif
+
+#define FONTCACHEFILE "/user/psprint/pspfontcache"
+#define CACHE_MAGIC "PspFontCacheFile format 4"
+
+using namespace std;
+using namespace rtl;
+using namespace psp;
+using namespace utl;
+
+/*
+ * static helpers
+ */
+
+/*
+ * FontCache constructor
+ */
+
+FontCache::FontCache()
+{
+ m_bDoFlush = false;
+ m_aCacheFile = getOfficePath( UserPath );
+ if( m_aCacheFile.Len() )
+ {
+ m_aCacheFile.AppendAscii( FONTCACHEFILE );
+ read();
+ }
+}
+
+/*
+ * FontCache destructor
+ */
+
+FontCache::~FontCache()
+{
+ clearCache();
+}
+
+/*
+ * FontCache::clearCache
+ */
+void FontCache::clearCache()
+{
+ for( FontCacheData::iterator dir_it = m_aCache.begin(); dir_it != m_aCache.end(); ++dir_it )
+ {
+ for( FontDirMap::iterator entry_it = dir_it->second.m_aEntries.begin(); entry_it != dir_it->second.m_aEntries.end(); ++entry_it )
+ {
+ for( FontCacheEntry::iterator font_it = entry_it->second.m_aEntry.begin(); font_it != entry_it->second.m_aEntry.end(); ++font_it )
+ delete *font_it;
+ }
+ }
+ m_aCache.clear();
+}
+
+/*
+ * FontCache::Commit
+ */
+
+void FontCache::flush()
+{
+ if( ! m_bDoFlush || ! m_aCacheFile.Len() )
+ return;
+
+ SvFileStream aStream;
+ aStream.Open( m_aCacheFile, STREAM_WRITE | STREAM_TRUNC );
+ if( ! (aStream.IsOpen() && aStream.IsWritable()) )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "FontCache::flush: opening cache file %s failed\n", ByteString( m_aCacheFile, osl_getThreadTextEncoding() ).GetBuffer() );
+#endif
+ return;
+ }
+
+ aStream.SetLineDelimiter( LINEEND_LF );
+ aStream.WriteLine( ByteString( CACHE_MAGIC ) );
+
+ PrintFontManager& rManager( PrintFontManager::get() );
+ MultiAtomProvider* pAtoms = rManager.m_pAtoms;
+
+ for( FontCacheData::const_iterator dir_it = m_aCache.begin(); dir_it != m_aCache.end(); ++ dir_it )
+ {
+ const FontDirMap& rDir( dir_it->second.m_aEntries );
+
+ ByteString aDirectory( rManager.getDirectory( dir_it->first ) );
+ ByteString aLine( "FontCacheDirectory:" );
+ aLine.Append( ByteString::CreateFromInt64( dir_it->second.m_nTimestamp ) );
+ aLine.Append( ':' );
+ aLine.Append( aDirectory );
+ if( rDir.empty() && dir_it->second.m_bNoFiles )
+ aLine.Insert( "Empty", 0 );
+ aStream.WriteLine( aLine );
+
+ for( FontDirMap::const_iterator entry_it = rDir.begin(); entry_it != rDir.end(); ++entry_it )
+ {
+ // insert cache entries
+ const FontCacheEntry& rEntry( entry_it->second.m_aEntry );
+ if( rEntry.begin() == rEntry.end() )
+ continue;
+
+ aLine = "File:";
+ aLine.Append( ByteString( entry_it->first ) );
+ aStream.WriteLine( aLine );
+
+ int nEntrySize = entry_it->second.m_aEntry.size();
+ // write: type;nfonts
+ aLine = ByteString::CreateFromInt32( rEntry.front()->m_eType );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( nEntrySize ) );
+ aStream.WriteLine( aLine );
+
+ sal_Int32 nSubEntry = 0;
+ for( FontCacheEntry::const_iterator it = rEntry.begin(); it != rEntry.end(); ++it, nSubEntry++ )
+ {
+ /*
+ * for each font entry write:
+ * name[;name[;name]]
+ * fontnr;PSName;italic;weight;width;pitch;encoding;ascend;descend;leading;vsubst;gxw;gxh;gyw;gyh;useroverrride;embed;antialias[;{metricfile,typeflags}][;stylename]
+ */
+ if( nEntrySize > 1 )
+ nSubEntry = static_cast<const PrintFontManager::TrueTypeFontFile*>(*it)->m_nCollectionEntry;
+ else
+ nSubEntry = -1;
+
+ aLine = OUStringToOString( pAtoms->getString( ATOM_FAMILYNAME, (*it)->m_nFamilyName ), RTL_TEXTENCODING_UTF8 );
+ for( ::std::list< int >::const_iterator name_it = (*it)->m_aAliases.begin(); name_it != (*it)->m_aAliases.end(); ++name_it )
+ {
+ const OUString& rAdd( pAtoms->getString( ATOM_FAMILYNAME, *name_it ) );
+ if( rAdd.getLength() )
+ {
+ aLine.Append( ';' );
+ aLine.Append( ByteString( String( rAdd ), RTL_TEXTENCODING_UTF8 ) );
+ }
+ }
+ aStream.WriteLine( aLine );
+
+ const OUString& rPSName( pAtoms->getString( ATOM_PSNAME, (*it)->m_nPSName ) );
+ aLine = ByteString::CreateFromInt32( nSubEntry );
+ aLine.Append( ';' );
+ aLine.Append( ByteString( String( rPSName ), RTL_TEXTENCODING_UTF8 ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_eItalic ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_eWeight ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_eWidth ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_ePitch ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_aEncoding ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_nAscend ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_nDescend ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_nLeading ) );
+ aLine.Append( ';' );
+ aLine.Append( (*it)->m_bHaveVerticalSubstitutedGlyphs ? "1" : "0" );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_aGlobalMetricX.width ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_aGlobalMetricX.height ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_aGlobalMetricY.width ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_aGlobalMetricY.height ) );
+ aLine.Append( ';' );
+ aLine.Append( (*it)->m_bUserOverride ? "1" : "0" );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( 0 ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( 0 ) );
+
+ switch( (*it)->m_eType )
+ {
+ case fonttype::Type1:
+ aLine.Append( ';' );
+ aLine.Append( ByteString( static_cast<const PrintFontManager::Type1FontFile*>(*it)->m_aMetricFile ) );
+ break;
+ case fonttype::TrueType:
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( static_cast<const PrintFontManager::TrueTypeFontFile*>(*it)->m_nTypeFlags ) );
+ break;
+ default: break;
+ }
+ if( (*it)->m_aStyleName.getLength() )
+ {
+ aLine.Append( ';' );
+ aLine.Append( ByteString( String( (*it)->m_aStyleName ), RTL_TEXTENCODING_UTF8 ) );
+ }
+ aStream.WriteLine( aLine );
+ }
+ aStream.WriteLine( ByteString() );
+ }
+ }
+ m_bDoFlush = false;
+}
+
+/*
+ * FontCache::read
+ */
+
+void FontCache::read()
+{
+ PrintFontManager& rManager( PrintFontManager::get() );
+ MultiAtomProvider* pAtoms = rManager.m_pAtoms;
+
+ SvFileStream aStream( m_aCacheFile, STREAM_READ );
+ if( ! aStream.IsOpen() )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "FontCache::read: opening cache file %s failed\n", ByteString( m_aCacheFile, osl_getThreadTextEncoding() ).GetBuffer() );
+#endif
+ return;
+ }
+
+
+ ByteString aLine;
+ aStream.ReadLine( aLine );
+ if( !aLine.Equals( CACHE_MAGIC ) )
+ {
+ #if OSL_DEBUG_LEVEL >1
+ fprintf( stderr, "FontCache::read: cache file %s fails magic test\n", ByteString( m_aCacheFile, osl_getThreadTextEncoding() ).GetBuffer() );
+ #endif
+ return;
+ }
+
+ int nDir = 0;
+ FontDirMap* pDir = NULL;
+ xub_StrLen nIndex;
+ bool bKeepOnlyUserOverridden = false;
+ do
+ {
+ aStream.ReadLine( aLine );
+ if( aLine.CompareTo( "FontCacheDirectory:", 19 ) == COMPARE_EQUAL ||
+ aLine.CompareTo( "EmptyFontCacheDirectory:", 24 ) == COMPARE_EQUAL )
+ {
+ bool bEmpty = (aLine.CompareTo( "Empty", 5 ) == COMPARE_EQUAL);
+ xub_StrLen nSearchIndex = bEmpty ? 24 : 19;
+
+ OString aDir;
+ sal_Int64 nTimestamp = 0;
+ xub_StrLen nTEnd = aLine.Search( ':', nSearchIndex );
+ if( nTEnd != STRING_NOTFOUND )
+ {
+ nTimestamp = aLine.Copy( nSearchIndex, nTEnd - nSearchIndex ).ToInt64();
+ aDir = aLine.Copy( nTEnd+1 );
+ }
+ else
+ {
+ // invalid format, remove
+ pDir = NULL;
+ nDir = 0;
+ m_bDoFlush = true;
+ continue;
+ }
+
+ // is the directory modified ?
+ struct stat aStat;
+ if( stat( aDir.getStr(), &aStat ) ||
+ ! S_ISDIR(aStat.st_mode) )
+ {
+ // remove outdated cache data
+ pDir = NULL;
+ nDir = 0;
+ m_bDoFlush = true;
+ continue;
+ }
+ else
+ {
+ nDir = rManager.getDirectoryAtom( aDir, true );
+ m_aCache[ nDir ].m_nTimestamp = (sal_Int64)aStat.st_mtime;
+ m_aCache[ nDir ].m_bNoFiles = bEmpty;
+ pDir = bEmpty ? NULL : &m_aCache[ nDir ].m_aEntries;
+ bKeepOnlyUserOverridden = ((sal_Int64)aStat.st_mtime != nTimestamp);
+ m_aCache[ nDir ].m_bUserOverrideOnly = bKeepOnlyUserOverridden;
+ }
+ }
+ else if( pDir && aLine.CompareTo( "File:", 5 ) == COMPARE_EQUAL )
+ {
+ OString aFile( aLine.Copy( 5 ) );
+ aStream.ReadLine( aLine );
+
+ const char* pLine = aLine.GetBuffer();
+
+ fonttype::type eType = (fonttype::type)atoi( pLine );
+ if( eType != fonttype::TrueType &&
+ eType != fonttype::Type1 &&
+ eType != fonttype::Builtin
+ )
+ continue;
+ while( *pLine && *pLine != ';' )
+ pLine++;
+ if( *pLine != ';' )
+ continue;
+
+ pLine++;
+ sal_Int32 nFonts = atoi( pLine );
+ for( int n = 0; n < nFonts; n++ )
+ {
+ aStream.ReadLine( aLine );
+ pLine = aLine.GetBuffer();
+ int nLen = aLine.Len();
+
+ PrintFontManager::PrintFont* pFont = NULL;
+ switch( eType )
+ {
+ case fonttype::TrueType:
+ pFont = new PrintFontManager::TrueTypeFontFile();
+ break;
+ case fonttype::Type1:
+ pFont = new PrintFontManager::Type1FontFile();
+ break;
+ case fonttype::Builtin:
+ pFont = new PrintFontManager::BuiltinFont();
+ break;
+ default: break;
+ }
+
+ for( nIndex = 0; nIndex < nLen && pLine[nIndex] != ';'; nIndex++ )
+ ;
+
+ pFont->m_nFamilyName = pAtoms->getAtom( ATOM_FAMILYNAME,
+ OUString( pLine, nIndex, RTL_TEXTENCODING_UTF8 ),
+ sal_True );
+ while( nIndex < nLen )
+ {
+ xub_StrLen nLastIndex = nIndex+1;
+ for( nIndex = nLastIndex ; nIndex < nLen && pLine[nIndex] != ';'; nIndex++ )
+ ;
+ if( nIndex - nLastIndex > 1 )
+ {
+ OUString aAlias( pLine+nLastIndex, nIndex-nLastIndex-1, RTL_TEXTENCODING_UTF8 );
+ pFont->m_aAliases.push_back( pAtoms->getAtom( ATOM_FAMILYNAME, aAlias, sal_True ) );
+ }
+ }
+ aStream.ReadLine( aLine );
+ pLine = aLine.GetBuffer();
+ nLen = aLine.Len();
+
+ // get up to 20 token positions
+ const int nMaxTokens = 20;
+ int nTokenPos[nMaxTokens];
+ nTokenPos[0] = 0;
+ int nTokens = 1;
+ for( int i = 0; i < nLen; i++ )
+ {
+ if( pLine[i] == ';' )
+ {
+ nTokenPos[nTokens++] = i+1;
+ if( nTokens == nMaxTokens )
+ break;
+ }
+ }
+ if( nTokens < 18 )
+ {
+ delete pFont;
+ continue;
+ }
+ int nCollEntry = atoi( pLine );
+ pFont->m_nPSName = pAtoms->getAtom( ATOM_PSNAME, OUString( pLine + nTokenPos[1], nTokenPos[2]-nTokenPos[1]-1, RTL_TEXTENCODING_UTF8 ), sal_True );
+ pFont->m_eItalic = (italic::type)atoi( pLine+nTokenPos[2] );
+ pFont->m_eWeight = (weight::type)atoi( pLine+nTokenPos[3] );
+ pFont->m_eWidth = (width::type)atoi( pLine+nTokenPos[4] );
+ pFont->m_ePitch = (pitch::type)atoi( pLine+nTokenPos[5] );
+ pFont->m_aEncoding = (rtl_TextEncoding)atoi( pLine+nTokenPos[6] );
+ pFont->m_nAscend = atoi( pLine + nTokenPos[7] );
+ pFont->m_nDescend = atoi( pLine + nTokenPos[8] );
+ pFont->m_nLeading = atoi( pLine + nTokenPos[9] );
+ pFont->m_bHaveVerticalSubstitutedGlyphs
+ = (atoi( pLine + nTokenPos[10] ) != 0);
+ pFont->m_aGlobalMetricX.width
+ = atoi( pLine + nTokenPos[11] );
+ pFont->m_aGlobalMetricX.height
+ = atoi( pLine + nTokenPos[12] );
+ pFont->m_aGlobalMetricY.width
+ = atoi( pLine + nTokenPos[13] );
+ pFont->m_aGlobalMetricY.height
+ = atoi( pLine + nTokenPos[14] );
+ pFont->m_bUserOverride
+ = (atoi( pLine + nTokenPos[15] ) != 0);
+ int nStyleTokenNr = 18;
+ switch( eType )
+ {
+ case fonttype::TrueType:
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pFont)->m_nTypeFlags = atoi( pLine + nTokenPos[18] );
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pFont)->m_nCollectionEntry = nCollEntry;
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pFont)->m_nDirectory = nDir;
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pFont)->m_aFontFile = aFile;
+ nStyleTokenNr++;
+ break;
+ case fonttype::Type1:
+ {
+ int nTokLen = (nTokens > 19 ) ? nTokenPos[19]-nTokenPos[18]-1 : nLen - nTokenPos[18];
+ static_cast<PrintFontManager::Type1FontFile*>(pFont)->m_aMetricFile = OString( pLine + nTokenPos[18], nTokLen );
+ static_cast<PrintFontManager::Type1FontFile*>(pFont)->m_nDirectory = nDir;
+ static_cast<PrintFontManager::Type1FontFile*>(pFont)->m_aFontFile = aFile;
+ nStyleTokenNr++;
+ }
+ break;
+ case fonttype::Builtin:
+ static_cast<PrintFontManager::BuiltinFont*>(pFont)->m_nDirectory = nDir;
+ static_cast<PrintFontManager::BuiltinFont*>(pFont)->m_aMetricFile = aFile;
+ break;
+ default: break;
+ }
+ if( nTokens > nStyleTokenNr )
+ pFont->m_aStyleName = OUString::intern( pLine + nTokenPos[nStyleTokenNr],
+ nLen - nTokenPos[nStyleTokenNr],
+ RTL_TEXTENCODING_UTF8 );
+
+ bool bObsolete = false;
+ if( bKeepOnlyUserOverridden )
+ {
+ if( pFont->m_bUserOverride )
+ {
+ ByteString aFilePath = rManager.getDirectory( nDir );
+ aFilePath.Append( '/' );
+ aFilePath.Append( ByteString(aFile) );
+ struct stat aStat;
+ if( stat( aFilePath.GetBuffer(), &aStat ) ||
+ ! S_ISREG( aStat.st_mode ) ||
+ aStat.st_size < 16 )
+ {
+ bObsolete = true;
+ }
+ #if OSL_DEBUG_LEVEL > 2
+ else
+ fprintf( stderr, "keeping file %s in outdated cache entry due to user override\n",
+ aFilePath.GetBuffer() );
+ #endif
+ }
+ else
+ bObsolete = true;
+ }
+ if( bObsolete )
+ {
+ m_bDoFlush = true;
+#if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, "removing obsolete font %s\n", aFile.getStr() );
+#endif
+ delete pFont;
+ continue;
+ }
+
+ FontCacheEntry& rEntry = (*pDir)[aFile].m_aEntry;
+ rEntry.push_back( pFont );
+ }
+ }
+ } while( ! aStream.IsEof() );
+}
+
+/*
+ * FontCache::updateDirTimestamp
+ */
+void FontCache::updateDirTimestamp( int nDirID )
+{
+ PrintFontManager& rManager( PrintFontManager::get() );
+ const OString& rDir = rManager.getDirectory( nDirID );
+
+ struct stat aStat;
+ if( ! stat( rDir.getStr(), &aStat ) )
+ m_aCache[ nDirID ].m_nTimestamp = (sal_Int64)aStat.st_mtime;
+}
+
+
+/*
+ * FontCache::copyPrintFont
+ */
+void FontCache::copyPrintFont( const PrintFontManager::PrintFont* pFrom, PrintFontManager::PrintFont* pTo ) const
+{
+ if( pFrom->m_eType != pTo->m_eType )
+ return;
+ switch( pFrom->m_eType )
+ {
+ case fonttype::TrueType:
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pTo)->m_nDirectory = static_cast<const PrintFontManager::TrueTypeFontFile*>(pFrom)->m_nDirectory;
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pTo)->m_aFontFile = static_cast<const PrintFontManager::TrueTypeFontFile*>(pFrom)->m_aFontFile;
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pTo)->m_nCollectionEntry = static_cast<const PrintFontManager::TrueTypeFontFile*>(pFrom)->m_nCollectionEntry;
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pTo)->m_nTypeFlags = static_cast<const PrintFontManager::TrueTypeFontFile*>(pFrom)->m_nTypeFlags;
+ break;
+ case fonttype::Type1:
+ static_cast<PrintFontManager::Type1FontFile*>(pTo)->m_nDirectory = static_cast<const PrintFontManager::Type1FontFile*>(pFrom)->m_nDirectory;
+ static_cast<PrintFontManager::Type1FontFile*>(pTo)->m_aFontFile = static_cast<const PrintFontManager::Type1FontFile*>(pFrom)->m_aFontFile;
+ static_cast<PrintFontManager::Type1FontFile*>(pTo)->m_aMetricFile = static_cast<const PrintFontManager::Type1FontFile*>(pFrom)->m_aMetricFile;
+ break;
+ case fonttype::Builtin:
+ static_cast<PrintFontManager::BuiltinFont*>(pTo)->m_nDirectory = static_cast<const PrintFontManager::BuiltinFont*>(pFrom)->m_nDirectory;
+ static_cast<PrintFontManager::BuiltinFont*>(pTo)->m_aMetricFile = static_cast<const PrintFontManager::BuiltinFont*>(pFrom)->m_aMetricFile;
+ break;
+ default: break;
+ }
+ pTo->m_nFamilyName = pFrom->m_nFamilyName;
+ pTo->m_aStyleName = pFrom->m_aStyleName;
+ pTo->m_aAliases = pFrom->m_aAliases;
+ pTo->m_nPSName = pFrom->m_nPSName;
+ pTo->m_eItalic = pFrom->m_eItalic;
+ pTo->m_eWeight = pFrom->m_eWeight;
+ pTo->m_eWidth = pFrom->m_eWidth;
+ pTo->m_ePitch = pFrom->m_ePitch;
+ pTo->m_aEncoding = pFrom->m_aEncoding;
+ pTo->m_aGlobalMetricX = pFrom->m_aGlobalMetricX;
+ pTo->m_aGlobalMetricY = pFrom->m_aGlobalMetricY;
+ pTo->m_nAscend = pFrom->m_nAscend;
+ pTo->m_nDescend = pFrom->m_nDescend;
+ pTo->m_nLeading = pFrom->m_nLeading;
+ pTo->m_nXMin = pFrom->m_nXMin;
+ pTo->m_nYMin = pFrom->m_nYMin;
+ pTo->m_nXMax = pFrom->m_nXMax;
+ pTo->m_nYMax = pFrom->m_nYMax;
+ pTo->m_bHaveVerticalSubstitutedGlyphs = pFrom->m_bHaveVerticalSubstitutedGlyphs;
+ pTo->m_bUserOverride = pFrom->m_bUserOverride;
+}
+
+/*
+ * FontCache::equalsPrintFont
+ */
+bool FontCache::equalsPrintFont( const PrintFontManager::PrintFont* pLeft, PrintFontManager::PrintFont* pRight ) const
+{
+ if( pLeft->m_eType != pRight->m_eType )
+ return false;
+ switch( pLeft->m_eType )
+ {
+ case fonttype::TrueType:
+ {
+ const PrintFontManager::TrueTypeFontFile* pLT = static_cast<const PrintFontManager::TrueTypeFontFile*>(pLeft);
+ const PrintFontManager::TrueTypeFontFile* pRT = static_cast<const PrintFontManager::TrueTypeFontFile*>(pRight);
+ if( pRT->m_nDirectory != pLT->m_nDirectory ||
+ pRT->m_aFontFile != pLT->m_aFontFile ||
+ pRT->m_nCollectionEntry != pLT->m_nCollectionEntry ||
+ pRT->m_nTypeFlags != pLT->m_nTypeFlags )
+ return false;
+ }
+ break;
+ case fonttype::Type1:
+ {
+ const PrintFontManager::Type1FontFile* pLT = static_cast<const PrintFontManager::Type1FontFile*>(pLeft);
+ const PrintFontManager::Type1FontFile* pRT = static_cast<const PrintFontManager::Type1FontFile*>(pRight);
+ if( pRT->m_nDirectory != pLT->m_nDirectory ||
+ pRT->m_aFontFile != pLT->m_aFontFile ||
+ pRT->m_aMetricFile != pLT->m_aMetricFile )
+ return false;
+ }
+ break;
+ case fonttype::Builtin:
+ {
+ const PrintFontManager::BuiltinFont* pLT = static_cast<const PrintFontManager::BuiltinFont*>(pLeft);
+ const PrintFontManager::BuiltinFont* pRT = static_cast<const PrintFontManager::BuiltinFont*>(pRight);
+ if( pRT->m_nDirectory != pLT->m_nDirectory ||
+ pRT->m_aMetricFile != pLT->m_aMetricFile )
+ return false;
+ }
+ break;
+ default: break;
+ }
+ if( pRight->m_nFamilyName != pLeft->m_nFamilyName ||
+ pRight->m_aStyleName != pLeft->m_aStyleName ||
+ pRight->m_nPSName != pLeft->m_nPSName ||
+ pRight->m_eItalic != pLeft->m_eItalic ||
+ pRight->m_eWeight != pLeft->m_eWeight ||
+ pRight->m_eWidth != pLeft->m_eWidth ||
+ pRight->m_ePitch != pLeft->m_ePitch ||
+ pRight->m_aEncoding != pLeft->m_aEncoding ||
+ pRight->m_aGlobalMetricX != pLeft->m_aGlobalMetricX ||
+ pRight->m_aGlobalMetricY != pLeft->m_aGlobalMetricY ||
+ pRight->m_nAscend != pLeft->m_nAscend ||
+ pRight->m_nDescend != pLeft->m_nDescend ||
+ pRight->m_nLeading != pLeft->m_nLeading ||
+ pRight->m_nXMin != pLeft->m_nXMin ||
+ pRight->m_nYMin != pLeft->m_nYMin ||
+ pRight->m_nXMax != pLeft->m_nXMax ||
+ pRight->m_nYMax != pLeft->m_nYMax ||
+ pRight->m_bHaveVerticalSubstitutedGlyphs != pLeft->m_bHaveVerticalSubstitutedGlyphs ||
+ pRight->m_bUserOverride != pLeft->m_bUserOverride
+ )
+ return false;
+ std::list< int >::const_iterator lit, rit;
+ for( lit = pLeft->m_aAliases.begin(), rit = pRight->m_aAliases.begin();
+ lit != pLeft->m_aAliases.end() && rit != pRight->m_aAliases.end() && (*lit) == (*rit);
+ ++lit, ++rit )
+ ;
+ return lit == pLeft->m_aAliases.end() && rit == pRight->m_aAliases.end();
+}
+
+/*
+ * FontCache::clonePrintFont
+ */
+PrintFontManager::PrintFont* FontCache::clonePrintFont( const PrintFontManager::PrintFont* pOldFont ) const
+{
+ PrintFontManager::PrintFont* pFont = NULL;
+ switch( pOldFont->m_eType )
+ {
+ case fonttype::TrueType:
+ pFont = new PrintFontManager::TrueTypeFontFile();
+ break;
+ case fonttype::Type1:
+ pFont = new PrintFontManager::Type1FontFile();
+ break;
+ case fonttype::Builtin:
+ pFont = new PrintFontManager::BuiltinFont();
+ break;
+ default: break;
+ }
+ if( pFont )
+ {
+ copyPrintFont( pOldFont, pFont );
+ }
+ return pFont;
+ }
+
+/*
+ * FontCache::getFontCacheFile
+ */
+bool FontCache::getFontCacheFile( int nDirID, const OString& rFile, list< PrintFontManager::PrintFont* >& rNewFonts ) const
+{
+ bool bSuccess = false;
+
+ FontCacheData::const_iterator dir = m_aCache.find( nDirID );
+ if( dir != m_aCache.end() )
+ {
+ FontDirMap::const_iterator entry = dir->second.m_aEntries.find( rFile );
+ if( entry != dir->second.m_aEntries.end() )
+ {
+ for( FontCacheEntry::const_iterator font = entry->second.m_aEntry.begin(); font != entry->second.m_aEntry.end(); ++font )
+ {
+ bSuccess = true;
+ PrintFontManager::PrintFont* pFont = clonePrintFont( *font );
+ rNewFonts.push_back( pFont );
+ }
+ }
+ }
+ return bSuccess;
+}
+
+/*
+ * FontCache::updateFontCacheEntry
+ */
+void FontCache::updateFontCacheEntry( const PrintFontManager::PrintFont* pFont, bool bFlush )
+{
+ PrintFontManager& rManager( PrintFontManager::get() );
+
+ OString aFile;
+ int nDirID = 0;
+ switch( pFont->m_eType )
+ {
+ case fonttype::TrueType:
+ nDirID = static_cast<const PrintFontManager::TrueTypeFontFile*>(pFont)->m_nDirectory;
+ aFile = static_cast<const PrintFontManager::TrueTypeFontFile*>(pFont)->m_aFontFile;
+ break;
+ case fonttype::Type1:
+ nDirID = static_cast<const PrintFontManager::Type1FontFile*>(pFont)->m_nDirectory;
+ aFile = static_cast<const PrintFontManager::Type1FontFile*>(pFont)->m_aFontFile;
+ break;
+ case fonttype::Builtin:
+ nDirID = static_cast<const PrintFontManager::BuiltinFont*>(pFont)->m_nDirectory;
+ aFile = static_cast<const PrintFontManager::BuiltinFont*>(pFont)->m_aMetricFile;
+ break;
+ default:
+ return;
+ }
+ FontCacheData::const_iterator dir = m_aCache.find( nDirID );
+ FontDirMap::const_iterator entry;
+ FontCacheEntry::const_iterator font;
+ PrintFontManager::PrintFont* pCacheFont = NULL;
+
+ if( dir != m_aCache.end() )
+ {
+ entry = dir->second.m_aEntries.find( aFile );
+ if( entry != dir->second.m_aEntries.end() )
+ {
+ for( font = entry->second.m_aEntry.begin(); font != entry->second.m_aEntry.end(); ++font )
+ {
+ if( (*font)->m_eType == pFont->m_eType &&
+ ( (*font)->m_eType != fonttype::TrueType ||
+ static_cast<const PrintFontManager::TrueTypeFontFile*>(*font)->m_nCollectionEntry == static_cast<const PrintFontManager::TrueTypeFontFile*>(pFont)->m_nCollectionEntry
+ ) )
+ break;
+ }
+ if( font != entry->second.m_aEntry.end() )
+ pCacheFont = *font;
+ }
+ }
+ else
+ createCacheDir( nDirID );
+
+ if( pCacheFont )
+ {
+ if( ! equalsPrintFont( pFont, pCacheFont ) )
+ {
+ copyPrintFont( pFont, pCacheFont );
+ m_bDoFlush = true;
+ }
+ }
+ else
+ {
+ pCacheFont = clonePrintFont( pFont );
+ m_aCache[nDirID].m_aEntries[aFile].m_aEntry.push_back( pCacheFont );
+
+ ByteString aPath = rManager.getDirectory( nDirID );
+ aPath.Append( '/' );
+ aPath.Append( ByteString( aFile ) );
+ m_bDoFlush = true;
+ }
+ if( bFlush )
+ flush();
+}
+
+/*
+ * FontCache::listDirectory
+ */
+bool FontCache::listDirectory( const OString& rDir, std::list< PrintFontManager::PrintFont* >& rNewFonts ) const
+{
+ PrintFontManager& rManager( PrintFontManager::get() );
+ int nDirID = rManager.getDirectoryAtom( rDir );
+ FontCacheData::const_iterator dir = m_aCache.find( nDirID );
+ bool bFound = (dir != m_aCache.end());
+
+ if( bFound && !dir->second.m_bNoFiles )
+ {
+ for( FontDirMap::const_iterator file = dir->second.m_aEntries.begin(); file != dir->second.m_aEntries.end(); ++file )
+ {
+ for( FontCacheEntry::const_iterator font = file->second.m_aEntry.begin(); font != file->second.m_aEntry.end(); ++font )
+ {
+ PrintFontManager::PrintFont* pFont = clonePrintFont( *font );
+ rNewFonts.push_back( pFont );
+ }
+ }
+ }
+ return bFound;
+}
+
+/*
+ * FontCache::listDirectory
+ */
+bool FontCache::scanAdditionalFiles( const OString& rDir )
+{
+ PrintFontManager& rManager( PrintFontManager::get() );
+ int nDirID = rManager.getDirectoryAtom( rDir );
+ FontCacheData::const_iterator dir = m_aCache.find( nDirID );
+ bool bFound = (dir != m_aCache.end());
+
+ return (bFound && dir->second.m_bUserOverrideOnly);
+}
+
+/*
+ * FontCache::createCacheDir
+ */
+void FontCache::createCacheDir( int nDirID )
+{
+ PrintFontManager& rManager( PrintFontManager::get() );
+
+ const OString& rDir = rManager.getDirectory( nDirID );
+ struct stat aStat;
+ if( ! stat( rDir.getStr(), &aStat ) )
+ m_aCache[nDirID].m_nTimestamp = (sal_Int64)aStat.st_mtime;
+}
+
+/*
+ * FontCache::markEmptyDir
+ */
+void FontCache::markEmptyDir( int nDirID, bool bNoFiles )
+{
+ createCacheDir( nDirID );
+ m_aCache[nDirID].m_bNoFiles = bNoFiles;
+ m_bDoFlush = true;
+}
diff --git a/vcl/unx/source/fontmanager/fontconfig.cxx b/vcl/unx/source/fontmanager/fontconfig.cxx
new file mode 100644
index 000000000000..3e24cd7c8e45
--- /dev/null
+++ b/vcl/unx/source/fontmanager/fontconfig.cxx
@@ -0,0 +1,1244 @@
+/*************************************************************************
+ *
+ * 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/fontmanager.hxx"
+#include "vcl/fontcache.hxx"
+#include "vcl/impfont.hxx"
+
+using namespace psp;
+
+#ifdef ENABLE_FONTCONFIG
+ #include <fontconfig/fontconfig.h>
+ #include <ft2build.h>
+ #include <fontconfig/fcfreetype.h>
+ // allow compile on baseline (currently with fontconfig 2.2.0)
+ #ifndef FC_WEIGHT_BOOK // TODO: remove when baseline moves to fc>=2.2.1
+ #define FC_WEIGHT_BOOK 75
+ #endif
+ #ifndef FC_EMBEDDED_BITMAP // TODO: remove when baseline moves to fc>=2.3.92
+ #define FC_EMBEDDED_BITMAP "embeddedbitmap"
+ #endif
+ #ifndef FC_FAMILYLANG // TODO: remove when baseline moves to fc>=2.2.97
+ #define FC_FAMILYLANG "familylang"
+ #endif
+ #ifndef FC_HINT_STYLE // TODO: remove when baseline moves to fc>=2.2.91
+ #define FC_HINT_STYLE "hintstyle"
+ #define FC_HINT_NONE 0
+ #define FC_HINT_SLIGHT 1
+ #define FC_HINT_MEDIUM 2
+ #define FC_HINT_FULL 3
+ #endif
+#else
+ typedef void FcConfig;
+ typedef void FcObjectSet;
+ typedef void FcPattern;
+ typedef void FcFontSet;
+ typedef void FcCharSet;
+ typedef int FcResult;
+ typedef int FcBool;
+ typedef int FcMatchKind;
+ typedef char FcChar8;
+ typedef int FcChar32;
+ typedef unsigned int FT_UInt;
+ typedef void* FT_Face;
+ typedef int FcSetName;
+#endif
+
+#include <cstdio>
+#include <cstdarg>
+
+#include "unotools/atom.hxx"
+
+#include "osl/module.h"
+#include "osl/thread.h"
+#include "osl/process.h"
+
+#include "rtl/ustrbuf.hxx"
+#include "rtl/locale.hxx"
+
+#include "sal/alloca.h"
+
+#include <utility>
+#include <algorithm>
+
+using namespace osl;
+using namespace rtl;
+
+class FontCfgWrapper
+{
+ oslModule m_pLib;
+ FcFontSet* m_pOutlineSet;
+
+ int m_nFcVersion;
+ FcBool (*m_pFcInit)();
+ int (*m_pFcGetVersion)();
+ FcConfig* (*m_pFcConfigGetCurrent)();
+ FcObjectSet* (*m_pFcObjectSetVaBuild)(const char*,va_list);
+ void (*m_pFcObjectSetDestroy)(FcObjectSet* pSet);
+ FcPattern* (*m_pFcPatternCreate)();
+ void (*m_pFcPatternDestroy)(FcPattern*);
+ FcFontSet* (*m_pFcFontList)(FcConfig*,FcPattern*,FcObjectSet*);
+ FcFontSet* (*m_pFcConfigGetFonts)(FcConfig*,FcSetName);
+ FcFontSet* (*m_pFcFontSetCreate)();
+ FcCharSet* (*m_pFcCharSetCreate)();
+ FcBool (*m_pFcCharSetAddChar)(FcCharSet *, FcChar32);
+ FcBool (*m_pFcCharSetHasChar)(FcCharSet *, FcChar32);
+ void (*m_pFcCharSetDestroy)(FcCharSet*);
+ void (*m_pFcFontSetDestroy)(FcFontSet*);
+ FcBool (*m_pFcFontSetAdd)(FcFontSet*,FcPattern*);
+ void (*m_pFcPatternReference)(FcPattern*);
+ FcResult (*m_pFcPatternGetCharSet)(const FcPattern*,const char*,int,FcCharSet**);
+ FcResult (*m_pFcPatternGetString)(const FcPattern*,const char*,int,FcChar8**);
+ FcResult (*m_pFcPatternGetInteger)(const FcPattern*,const char*,int,int*);
+ FcResult (*m_pFcPatternGetDouble)(const FcPattern*,const char*,int,double*);
+ FcResult (*m_pFcPatternGetBool)(const FcPattern*,const char*,int,FcBool*);
+ void (*m_pFcDefaultSubstitute)(FcPattern *);
+ FcPattern* (*m_pFcFontSetMatch)(FcConfig*,FcFontSet**, int, FcPattern*,FcResult*);
+ FcBool (*m_pFcConfigAppFontAddFile)(FcConfig*, const FcChar8*);
+ FcBool (*m_pFcConfigAppFontAddDir)(FcConfig*, const FcChar8*);
+ FcBool (*m_pFcConfigParseAndLoad)(FcConfig*,const FcChar8*,FcBool);
+
+ FcBool (*m_pFcConfigSubstitute)(FcConfig*,FcPattern*,FcMatchKind);
+ FcBool (*m_pFcPatternAddInteger)(FcPattern*,const char*,int);
+ FcBool (*m_pFcPatternAddDouble)(FcPattern*,const char*,double);
+ FcBool (*m_pFcPatternAddBool)(FcPattern*,const char*,FcBool);
+ FcBool (*m_pFcPatternAddCharSet)(FcPattern*,const char*,const FcCharSet*);
+ FcBool (*m_pFcPatternAddString)(FcPattern*,const char*,const FcChar8*);
+ FT_UInt (*m_pFcFreeTypeCharIndex)(FT_Face,FcChar32);
+
+ oslGenericFunction loadSymbol( const char* );
+ void addFontSet( FcSetName );
+
+ FontCfgWrapper();
+ ~FontCfgWrapper();
+
+public:
+ static FontCfgWrapper& get();
+ static void release();
+
+ bool isValid() const
+ { return m_pLib != NULL;}
+
+ FcFontSet* getFontSet();
+
+ FcBool FcInit()
+ { return m_pFcInit(); }
+
+ int FcGetVersion()
+ { return m_pFcGetVersion(); }
+
+ FcConfig* FcConfigGetCurrent()
+ { return m_pFcConfigGetCurrent(); }
+
+ FcObjectSet* FcObjectSetBuild( const char* first, ... )
+ {
+ va_list ap;
+ va_start( ap, first );
+ FcObjectSet* pSet = m_pFcObjectSetVaBuild( first, ap );
+ va_end( ap );
+ return pSet;
+ }
+
+ void FcObjectSetDestroy( FcObjectSet* pSet )
+ { m_pFcObjectSetDestroy( pSet ); }
+
+ FcPattern* FcPatternCreate()
+ { return m_pFcPatternCreate(); }
+
+ void FcPatternDestroy( FcPattern* pPattern )
+ { m_pFcPatternDestroy( pPattern ); }
+
+ FcFontSet* FcFontList( FcConfig* pConfig, FcPattern* pPattern, FcObjectSet* pSet )
+ { return m_pFcFontList( pConfig, pPattern, pSet ); }
+
+ FcFontSet* FcConfigGetFonts( FcConfig* pConfig, FcSetName eSet)
+ { return m_pFcConfigGetFonts( pConfig, eSet ); }
+
+ FcFontSet* FcFontSetCreate()
+ { return m_pFcFontSetCreate(); }
+
+ FcCharSet* FcCharSetCreate()
+ { return m_pFcCharSetCreate(); }
+
+ FcBool FcCharSetAddChar(FcCharSet *fcs, FcChar32 ucs4)
+ { return m_pFcCharSetAddChar(fcs, ucs4); }
+
+ FcBool FcCharSetHasChar(FcCharSet *fcs, FcChar32 ucs4)
+ { return m_pFcCharSetHasChar(fcs, ucs4); }
+
+ void FcCharSetDestroy( FcCharSet* pSet )
+ { m_pFcCharSetDestroy( pSet );}
+
+ void FcFontSetDestroy( FcFontSet* pSet )
+ { m_pFcFontSetDestroy( pSet );}
+
+ FcBool FcFontSetAdd( FcFontSet* pSet, FcPattern* pPattern )
+ { return m_pFcFontSetAdd( pSet, pPattern ); }
+
+ void FcPatternReference( FcPattern* pPattern )
+ { m_pFcPatternReference( pPattern ); }
+
+ FcResult FcPatternGetCharSet( const FcPattern* pPattern, const char* object, int n, FcCharSet** s )
+ { return m_pFcPatternGetCharSet( pPattern, object, n, s ); }
+
+ FcResult FcPatternGetString( const FcPattern* pPattern, const char* object, int n, FcChar8** s )
+ { return m_pFcPatternGetString( pPattern, object, n, s ); }
+
+ FcResult FcPatternGetInteger( const FcPattern* pPattern, const char* object, int n, int* s )
+ { return m_pFcPatternGetInteger( pPattern, object, n, s ); }
+
+ FcResult FcPatternGetDouble( const FcPattern* pPattern, const char* object, int n, double* s )
+ { return m_pFcPatternGetDouble( pPattern, object, n, s ); }
+
+ FcResult FcPatternGetBool( const FcPattern* pPattern, const char* object, int n, FcBool* s )
+ { return m_pFcPatternGetBool( pPattern, object, n, s ); }
+ FcBool FcConfigAppFontAddFile( FcConfig* pConfig, const FcChar8* pFileName )
+ { return m_pFcConfigAppFontAddFile( pConfig, pFileName ); }
+ FcBool FcConfigAppFontAddDir(FcConfig* pConfig, const FcChar8* pDirName )
+ { return m_pFcConfigAppFontAddDir( pConfig, pDirName ); }
+ FcBool FcConfigParseAndLoad( FcConfig* pConfig, const FcChar8* pFileName, FcBool bComplain )
+ { return m_pFcConfigParseAndLoad( pConfig, pFileName, bComplain ); }
+
+ void FcDefaultSubstitute( FcPattern* pPattern )
+ { m_pFcDefaultSubstitute( pPattern ); }
+ FcPattern* FcFontSetMatch( FcConfig* pConfig, FcFontSet **ppFontSet, int nset, FcPattern* pPattern, FcResult* pResult )
+ { return m_pFcFontSetMatch ? m_pFcFontSetMatch( pConfig, ppFontSet, nset, pPattern, pResult ) : 0; }
+ FcBool FcConfigSubstitute( FcConfig* pConfig, FcPattern* pPattern, FcMatchKind eKind )
+ { return m_pFcConfigSubstitute( pConfig, pPattern, eKind ); }
+ FcBool FcPatternAddInteger( FcPattern* pPattern, const char* pObject, int nValue )
+ { return m_pFcPatternAddInteger( pPattern, pObject, nValue ); }
+ FcBool FcPatternAddDouble( FcPattern* pPattern, const char* pObject, double nValue )
+ { return m_pFcPatternAddDouble( pPattern, pObject, nValue ); }
+ FcBool FcPatternAddString( FcPattern* pPattern, const char* pObject, const FcChar8* pString )
+ { return m_pFcPatternAddString( pPattern, pObject, pString ); }
+ FcBool FcPatternAddBool( FcPattern* pPattern, const char* pObject, bool nValue )
+ { return m_pFcPatternAddBool( pPattern, pObject, nValue ); }
+ FcBool FcPatternAddCharSet(FcPattern* pPattern,const char* pObject,const FcCharSet*pCharSet)
+ { return m_pFcPatternAddCharSet(pPattern,pObject,pCharSet); }
+
+ FT_UInt FcFreeTypeCharIndex( FT_Face face, FcChar32 ucs4 )
+ { return m_pFcFreeTypeCharIndex ? m_pFcFreeTypeCharIndex( face, ucs4 ) : 0; }
+
+public: // TODO: cleanup
+ FcResult FamilyFromPattern(FcPattern* pPattern, FcChar8 **family);
+ std::hash_map< rtl::OString, rtl::OString, rtl::OStringHash > m_aFontNameToLocalized;
+ std::hash_map< rtl::OString, rtl::OString, rtl::OStringHash > m_aLocalizedToCanonical;
+};
+
+oslGenericFunction FontCfgWrapper::loadSymbol( const char* pSymbol )
+{
+ OUString aSym( OUString::createFromAscii( pSymbol ) );
+ oslGenericFunction pSym = osl_getFunctionSymbol( m_pLib, aSym.pData );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%s %s\n", pSymbol, pSym ? "found" : "not found" );
+#endif
+ return pSym;
+}
+
+FontCfgWrapper::FontCfgWrapper()
+ : m_pLib( NULL ),
+ m_pOutlineSet( NULL ),
+ m_nFcVersion( 0 )
+{
+ OUString aLib( RTL_CONSTASCII_USTRINGPARAM( "libfontconfig.so.1" ) );
+ m_pLib = osl_loadModule( aLib.pData, SAL_LOADMODULE_LAZY );
+ if( !m_pLib )
+ {
+ aLib = OUString( RTL_CONSTASCII_USTRINGPARAM( "libfontconfig.so" ) );
+ m_pLib = osl_loadModule( aLib.pData, SAL_LOADMODULE_LAZY );
+ }
+
+ if( ! m_pLib )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "no libfontconfig\n" );
+#endif
+ return;
+ }
+
+ m_pFcInit = (FcBool(*)())
+ loadSymbol( "FcInit" );
+ m_pFcGetVersion = (int(*)())
+ loadSymbol( "FcGetVersion" );
+ m_pFcConfigGetCurrent = (FcConfig *(*)())
+ loadSymbol( "FcConfigGetCurrent" );
+ m_pFcObjectSetVaBuild = (FcObjectSet*(*)(const char*,va_list))
+ loadSymbol( "FcObjectSetVaBuild" );
+ m_pFcObjectSetDestroy = (void(*)(FcObjectSet*))
+ loadSymbol( "FcObjectSetDestroy" );
+ m_pFcPatternCreate = (FcPattern*(*)())
+ loadSymbol( "FcPatternCreate" );
+ m_pFcPatternDestroy = (void(*)(FcPattern*))
+ loadSymbol( "FcPatternDestroy" );
+ m_pFcFontList = (FcFontSet*(*)(FcConfig*,FcPattern*,FcObjectSet*))
+ loadSymbol( "FcFontList" );
+ m_pFcConfigGetFonts = (FcFontSet*(*)(FcConfig*,FcSetName))
+ loadSymbol( "FcConfigGetFonts" );
+ m_pFcFontSetCreate = (FcFontSet*(*)())
+ loadSymbol( "FcFontSetCreate" );
+ m_pFcCharSetCreate = (FcCharSet*(*)())
+ loadSymbol( "FcCharSetCreate" );
+ m_pFcCharSetAddChar = (FcBool(*)(FcCharSet*, FcChar32))
+ loadSymbol( "FcCharSetAddChar" );
+ m_pFcCharSetHasChar = (FcBool(*)(FcCharSet*, FcChar32))
+ loadSymbol( "FcCharSetHasChar" );
+ m_pFcCharSetDestroy = (void(*)(FcCharSet*))
+ loadSymbol( "FcCharSetDestroy" );
+ m_pFcFontSetDestroy = (void(*)(FcFontSet*))
+ loadSymbol( "FcFontSetDestroy" );
+ m_pFcFontSetAdd = (FcBool(*)(FcFontSet*,FcPattern*))
+ loadSymbol( "FcFontSetAdd" );
+ m_pFcPatternReference = (void(*)(FcPattern*))
+ loadSymbol( "FcPatternReference" );
+ m_pFcPatternGetCharSet = (FcResult(*)(const FcPattern*,const char*,int,FcCharSet**))
+ loadSymbol( "FcPatternGetCharSet" );
+ m_pFcPatternGetString = (FcResult(*)(const FcPattern*,const char*,int,FcChar8**))
+ loadSymbol( "FcPatternGetString" );
+ m_pFcPatternGetInteger = (FcResult(*)(const FcPattern*,const char*,int,int*))
+ loadSymbol( "FcPatternGetInteger" );
+ m_pFcPatternGetDouble = (FcResult(*)(const FcPattern*,const char*,int,double*))
+ loadSymbol( "FcPatternGetDouble" );
+ m_pFcPatternGetBool = (FcResult(*)(const FcPattern*,const char*,int,FcBool*))
+ loadSymbol( "FcPatternGetBool" );
+ m_pFcConfigAppFontAddFile = (FcBool(*)(FcConfig*, const FcChar8*))
+ loadSymbol( "FcConfigAppFontAddFile" );
+ m_pFcConfigAppFontAddDir = (FcBool(*)(FcConfig*, const FcChar8*))
+ loadSymbol( "FcConfigAppFontAddDir" );
+ m_pFcConfigParseAndLoad = (FcBool(*)(FcConfig*, const FcChar8*, FcBool))
+ loadSymbol( "FcConfigParseAndLoad" );
+ m_pFcDefaultSubstitute = (void(*)(FcPattern *))
+ loadSymbol( "FcDefaultSubstitute" );
+ m_pFcFontSetMatch = (FcPattern*(*)(FcConfig*,FcFontSet**,int,FcPattern*,FcResult*))
+ loadSymbol( "FcFontSetMatch" );
+ m_pFcConfigSubstitute = (FcBool(*)(FcConfig*,FcPattern*,FcMatchKind))
+ loadSymbol( "FcConfigSubstitute" );
+ m_pFcPatternAddInteger = (FcBool(*)(FcPattern*,const char*,int))
+ loadSymbol( "FcPatternAddInteger" );
+ m_pFcPatternAddDouble = (FcBool(*)(FcPattern*,const char*,double))
+ loadSymbol( "FcPatternAddDouble" );
+ m_pFcPatternAddBool = (FcBool(*)(FcPattern*,const char*,FcBool))
+ loadSymbol( "FcPatternAddBool" );
+ m_pFcPatternAddCharSet = (FcBool(*)(FcPattern*,const char*,const FcCharSet *))
+ loadSymbol( "FcPatternAddCharSet" );
+ m_pFcPatternAddString = (FcBool(*)(FcPattern*,const char*,const FcChar8*))
+ loadSymbol( "FcPatternAddString" );
+ m_pFcFreeTypeCharIndex = (FT_UInt(*)(FT_Face,FcChar32))
+ loadSymbol( "FcFreeTypeCharIndex" );
+
+ m_nFcVersion = FcGetVersion();
+#if (OSL_DEBUG_LEVEL > 1)
+ fprintf( stderr,"FC_VERSION = %05d\n", m_nFcVersion );
+#endif
+ // make minimum version configurable
+ const char* pMinFcVersion = getenv( "SAL_MIN_FC_VERSION");
+ if( pMinFcVersion )
+ {
+ const int nMinFcVersion = atoi( pMinFcVersion );
+ if( m_nFcVersion < nMinFcVersion )
+ m_pFcInit = NULL;
+ }
+
+ if( ! (
+ m_pFcInit &&
+ m_pFcGetVersion &&
+ m_pFcConfigGetCurrent &&
+ m_pFcObjectSetVaBuild &&
+ m_pFcObjectSetDestroy &&
+ m_pFcPatternCreate &&
+ m_pFcPatternDestroy &&
+ m_pFcFontList &&
+ m_pFcConfigGetFonts &&
+ m_pFcFontSetCreate &&
+ m_pFcCharSetCreate &&
+ m_pFcCharSetAddChar &&
+ m_pFcCharSetHasChar &&
+ m_pFcCharSetDestroy &&
+ m_pFcFontSetDestroy &&
+ m_pFcFontSetAdd &&
+ m_pFcPatternReference &&
+ m_pFcPatternGetCharSet &&
+ m_pFcPatternGetString &&
+ m_pFcPatternGetInteger &&
+ m_pFcPatternGetDouble &&
+ m_pFcPatternGetBool &&
+ m_pFcConfigAppFontAddFile &&
+ m_pFcConfigAppFontAddDir &&
+ m_pFcConfigParseAndLoad &&
+ m_pFcDefaultSubstitute &&
+ m_pFcConfigSubstitute &&
+ m_pFcPatternAddInteger &&
+ m_pFcPatternAddDouble &&
+ m_pFcPatternAddCharSet &&
+ m_pFcPatternAddBool &&
+ m_pFcPatternAddString
+ ) )
+ {
+ osl_unloadModule( (oslModule)m_pLib );
+ m_pLib = NULL;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "not all needed symbols were found in libfontconfig\n" );
+#endif
+ return;
+ }
+
+
+ FcInit();
+ if( ! FcConfigGetCurrent() )
+ {
+ osl_unloadModule( (oslModule)m_pLib );
+ m_pLib = NULL;
+ }
+}
+
+void FontCfgWrapper::addFontSet( FcSetName eSetName )
+{
+ #ifdef ENABLE_FONTCONFIG
+ /*
+ add only acceptable outlined fonts to our config,
+ for future fontconfig use
+ */
+ FcFontSet* pOrig = FcConfigGetFonts( FcConfigGetCurrent(), eSetName );
+ if( !pOrig )
+ return;
+
+ for( int i = 0; i < pOrig->nfont; ++i )
+ {
+ FcBool outline = false;
+ FcPattern *pOutlinePattern = pOrig->fonts[i];
+ FcResult eOutRes =
+ FcPatternGetBool( pOutlinePattern, FC_OUTLINE, 0, &outline );
+ if( (eOutRes != FcResultMatch) || (outline != FcTrue) )
+ continue;
+ FcPatternReference(pOutlinePattern);
+ FcFontSetAdd(m_pOutlineSet, pOutlinePattern);
+ }
+ // TODO: FcFontSetDestroy( pOrig );
+ #else
+ (void)eSetName; // prevent compiler warning about unused parameter
+ #endif
+}
+
+FcFontSet* FontCfgWrapper::getFontSet()
+{
+ #ifdef ENABLE_FONTCONFIG
+ if( !m_pOutlineSet )
+ {
+ m_pOutlineSet = FcFontSetCreate();
+ addFontSet( FcSetSystem );
+ if( m_nFcVersion > 20400 ) // #i85462# prevent crashes
+ addFontSet( FcSetApplication );
+ }
+ #endif
+
+ return m_pOutlineSet;
+}
+
+FontCfgWrapper::~FontCfgWrapper()
+{
+ if( m_pOutlineSet )
+ FcFontSetDestroy( m_pOutlineSet );
+ if( m_pLib )
+ osl_unloadModule( (oslModule)m_pLib );
+}
+
+static FontCfgWrapper* pOneInstance = NULL;
+
+FontCfgWrapper& FontCfgWrapper::get()
+{
+ if( ! pOneInstance )
+ pOneInstance = new FontCfgWrapper();
+ return *pOneInstance;
+}
+
+void FontCfgWrapper::release()
+{
+ if( pOneInstance )
+ {
+ delete pOneInstance;
+ pOneInstance = NULL;
+ }
+}
+
+#ifdef ENABLE_FONTCONFIG
+namespace
+{
+ typedef std::pair<FcChar8*, FcChar8*> lang_and_family;
+
+ class localizedsorter
+ {
+ rtl::OLocale maLoc;
+ public:
+ localizedsorter(rtl_Locale* pLoc) : maLoc(pLoc) {}
+ FcChar8* bestname(const std::vector<lang_and_family> &families);
+ };
+
+ FcChar8* localizedsorter::bestname(const std::vector<lang_and_family> &families)
+ {
+ FcChar8* candidate = families.begin()->second;
+ rtl::OString sLangMatch(rtl::OUStringToOString(maLoc.getLanguage().toAsciiLowerCase(), RTL_TEXTENCODING_UTF8));
+ rtl::OString sFullMatch = sLangMatch;
+ sFullMatch += OString('-');
+ sFullMatch += rtl::OUStringToOString(maLoc.getCountry().toAsciiLowerCase(), RTL_TEXTENCODING_UTF8);
+
+ std::vector<lang_and_family>::const_iterator aEnd = families.end();
+ bool alreadyclosematch = false;
+ for (std::vector<lang_and_family>::const_iterator aIter = families.begin(); aIter != aEnd; ++aIter)
+ {
+ const char *pLang = (const char*)aIter->first;
+ //perfect
+ if( rtl_str_compare(pLang,sFullMatch.getStr() ) == 0)
+ {
+ candidate = aIter->second;
+ break;
+ }
+ else if( (rtl_str_compare(pLang,sLangMatch.getStr()) == 0) && (!alreadyclosematch))
+ {
+ candidate = aIter->second;
+ alreadyclosematch = true;
+ }
+ }
+
+ return candidate;
+ }
+}
+
+FcResult FontCfgWrapper::FamilyFromPattern(FcPattern* pPattern, FcChar8 **family)
+{
+ FcChar8 *origfamily;
+ FcResult eFamilyRes = FcPatternGetString( pPattern, FC_FAMILY, 0, &origfamily );
+ *family = origfamily;
+
+ if( eFamilyRes == FcResultMatch)
+ {
+ FcChar8* familylang = NULL;
+ if (FcPatternGetString( pPattern, FC_FAMILYLANG, 0, &familylang ) == FcResultMatch)
+ {
+ std::vector< lang_and_family > lang_and_families;
+ lang_and_families.push_back(lang_and_family(familylang, *family));
+ int k = 1;
+ while (1)
+ {
+ if (FcPatternGetString( pPattern, FC_FAMILYLANG, k, &familylang ) != FcResultMatch)
+ break;
+ if (FcPatternGetString( pPattern, FC_FAMILY, k, family ) != FcResultMatch)
+ break;
+ lang_and_families.push_back(lang_and_family(familylang, *family));
+ ++k;
+ }
+
+ //possible to-do, sort by UILocale instead of process locale
+ rtl_Locale* pLoc;
+ osl_getProcessLocale(&pLoc);
+ localizedsorter aSorter(pLoc);
+ *family = aSorter.bestname(lang_and_families);
+
+ std::vector<lang_and_family>::const_iterator aEnd = lang_and_families.end();
+ for (std::vector<lang_and_family>::const_iterator aIter = lang_and_families.begin(); aIter != aEnd; ++aIter)
+ {
+ const char *candidate = (const char*)(aIter->second);
+ if (rtl_str_compare(candidate, (const char*)(*family)) != 0)
+ m_aFontNameToLocalized[OString(candidate)] = OString((const char*)(*family));
+ }
+ if (rtl_str_compare((const char*)origfamily, (const char*)(*family)) != 0)
+ m_aLocalizedToCanonical[OString((const char*)(*family))] = OString((const char*)origfamily);
+ }
+ }
+
+ return eFamilyRes;
+}
+
+/*
+ * PrintFontManager::initFontconfig
+ */
+bool PrintFontManager::initFontconfig()
+{
+ FontCfgWrapper& rWrapper = FontCfgWrapper::get();
+ if( ! rWrapper.isValid() )
+ return false;
+ return true;
+}
+
+namespace
+{
+ weight::type convertWeight(int weight)
+ {
+ // set weight
+ if( weight <= FC_WEIGHT_THIN )
+ return weight::Thin;
+ else if( weight <= FC_WEIGHT_ULTRALIGHT )
+ return weight::UltraLight;
+ else if( weight <= FC_WEIGHT_LIGHT )
+ return weight::Light;
+ else if( weight <= FC_WEIGHT_BOOK )
+ return weight::SemiLight;
+ else if( weight <= FC_WEIGHT_NORMAL )
+ return weight::Normal;
+ else if( weight <= FC_WEIGHT_MEDIUM )
+ return weight::Medium;
+ else if( weight <= FC_WEIGHT_SEMIBOLD )
+ return weight::SemiBold;
+ else if( weight <= FC_WEIGHT_BOLD )
+ return weight::Bold;
+ else if( weight <= FC_WEIGHT_ULTRABOLD )
+ return weight::UltraBold;
+ return weight::Black;
+ }
+
+ italic::type convertSlant(int slant)
+ {
+ // set italic
+ if( slant == FC_SLANT_ITALIC )
+ return italic::Italic;
+ else if( slant == FC_SLANT_OBLIQUE )
+ return italic::Oblique;
+ return italic::Upright;
+ }
+
+ pitch::type convertSpacing(int spacing)
+ {
+ // set pitch
+ if( spacing == FC_MONO || spacing == FC_CHARCELL )
+ return pitch::Fixed;
+ return pitch::Variable;
+ }
+
+ width::type convertWidth(int width)
+ {
+ if (width == FC_WIDTH_ULTRACONDENSED)
+ return width::UltraCondensed;
+ else if (width == FC_WIDTH_EXTRACONDENSED)
+ return width::ExtraCondensed;
+ else if (width == FC_WIDTH_CONDENSED)
+ return width::Condensed;
+ else if (width == FC_WIDTH_SEMICONDENSED)
+ return width::SemiCondensed;
+ else if (width == FC_WIDTH_SEMIEXPANDED)
+ return width::SemiExpanded;
+ else if (width == FC_WIDTH_EXPANDED)
+ return width::Expanded;
+ else if (width == FC_WIDTH_EXTRAEXPANDED)
+ return width::ExtraExpanded;
+ else if (width == FC_WIDTH_ULTRAEXPANDED)
+ return width::UltraExpanded;
+ return width::Normal;
+ }
+}
+
+int PrintFontManager::countFontconfigFonts( std::hash_map<rtl::OString, int, rtl::OStringHash>& o_rVisitedPaths )
+{
+ int nFonts = 0;
+
+ FontCfgWrapper& rWrapper = FontCfgWrapper::get();
+ if( !rWrapper.isValid() )
+ return 0;
+
+ FcFontSet* pFSet = rWrapper.getFontSet();
+ if( pFSet )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "found %d entries in fontconfig fontset\n", pFSet->nfont );
+#endif
+ for( int i = 0; i < pFSet->nfont; i++ )
+ {
+ FcChar8* file = NULL;
+ FcChar8* family = NULL;
+ FcChar8* style = NULL;
+ int slant = 0;
+ int weight = 0;
+ int spacing = 0;
+ int nCollectionEntry = -1;
+ FcBool outline = false;
+
+ FcResult eFileRes = rWrapper.FcPatternGetString( pFSet->fonts[i], FC_FILE, 0, &file );
+ FcResult eFamilyRes = rWrapper.FamilyFromPattern( pFSet->fonts[i], &family );
+ FcResult eStyleRes = rWrapper.FcPatternGetString( pFSet->fonts[i], FC_STYLE, 0, &style );
+ FcResult eSlantRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_SLANT, 0, &slant );
+ FcResult eWeightRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_WEIGHT, 0, &weight );
+ FcResult eSpacRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_SPACING, 0, &spacing );
+ FcResult eOutRes = rWrapper.FcPatternGetBool( pFSet->fonts[i], FC_OUTLINE, 0, &outline );
+ FcResult eIndexRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_INDEX, 0, &nCollectionEntry );
+
+ if( eFileRes != FcResultMatch || eFamilyRes != FcResultMatch || eOutRes != FcResultMatch )
+ continue;
+
+#if (OSL_DEBUG_LEVEL > 2)
+ fprintf( stderr, "found font \"%s\" in file %s\n"
+ " weight = %d, slant = %d, style = \"%s\"\n"
+ " spacing = %d, outline = %d\n"
+ , family, file
+ , eWeightRes == FcResultMatch ? weight : -1
+ , eSpacRes == FcResultMatch ? slant : -1
+ , eStyleRes == FcResultMatch ? (const char*) style : "<nil>"
+ , eSpacRes == FcResultMatch ? spacing : -1
+ , eOutRes == FcResultMatch ? outline : -1
+ );
+#endif
+
+ OSL_ASSERT(eOutRes != FcResultMatch || outline);
+
+ // only outline fonts are usable to psprint anyway
+ if( eOutRes == FcResultMatch && ! outline )
+ continue;
+
+ // see if this font is already cached
+ // update attributes
+ std::list< PrintFont* > aFonts;
+ OString aDir, aBase, aOrgPath( (sal_Char*)file );
+ splitPath( aOrgPath, aDir, aBase );
+
+ o_rVisitedPaths[aDir] = 1;
+
+ int nDirID = getDirectoryAtom( aDir, true );
+ if( ! m_pFontCache->getFontCacheFile( nDirID, aBase, aFonts ) )
+ {
+#if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, "file %s not cached\n", aBase.getStr() );
+#endif
+ // not known, analyze font file to get attributes
+ // not described by fontconfig (e.g. alias names, PSName)
+ std::list< OString > aDummy;
+ analyzeFontFile( nDirID, aBase, aDummy, aFonts );
+#if OSL_DEBUG_LEVEL > 1
+ if( aFonts.empty() )
+ fprintf( stderr, "Warning: file \"%s\" is unusable to psprint\n", aOrgPath.getStr() );
+#endif
+ }
+ if( aFonts.empty() )
+ continue;
+
+ int nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, OStringToOUString( OString( (sal_Char*)family ), RTL_TEXTENCODING_UTF8 ), sal_True );
+ PrintFont* pUpdate = aFonts.front();
+ std::list<PrintFont*>::const_iterator second_font = aFonts.begin();
+ ++second_font;
+ if( second_font != aFonts.end() ) // more than one font
+ {
+ // a collection entry, get the correct index
+ if( eIndexRes == FcResultMatch && nCollectionEntry != -1 )
+ {
+ for( std::list< PrintFont* >::iterator it = aFonts.begin(); it != aFonts.end(); ++it )
+ {
+ if( (*it)->m_eType == fonttype::TrueType &&
+ static_cast<TrueTypeFontFile*>(*it)->m_nCollectionEntry == nCollectionEntry )
+ {
+ pUpdate = *it;
+ break;
+ }
+ }
+ // update collection entry
+ // additional entries will be created in the cache
+ // if this is a new index (that is if the loop above
+ // ran to the end of the list)
+ if( pUpdate->m_eType == fonttype::TrueType ) // sanity check, this should always be the case here
+ static_cast<TrueTypeFontFile*>(pUpdate)->m_nCollectionEntry = nCollectionEntry;
+ }
+ else
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "multiple fonts for file, but no index in fontconfig pattern ! (index res = %d collection entry = %d\nfile will not be used\n", eIndexRes, nCollectionEntry );
+#endif
+ // we have found more than one font in this file
+ // but fontconfig will not tell us which index is meant
+ // -> something is in disorder, do not use this font
+ pUpdate = NULL;
+ }
+ }
+
+ if( pUpdate )
+ {
+ // set family name
+ if( pUpdate->m_nFamilyName != nFamilyName )
+ {
+#if 0 // fontconfig prefers nameid=16 for the family name which is all fine
+ // but Writer suffers from #i79878#
+ // the only reasonable workaround for now is to use the classic nameid=1
+ pUpdate->m_aAliases.remove( pUpdate->m_nFamilyName );
+ pUpdate->m_aAliases.push_back( pUpdate->m_nFamilyName );
+ pUpdate->m_aAliases.remove( nFamilyName );
+ pUpdate->m_nFamilyName = nFamilyName;
+#endif
+ }
+ if( eWeightRes == FcResultMatch )
+ pUpdate->m_eWeight = convertWeight(weight);
+ if( eSpacRes == FcResultMatch )
+ pUpdate->m_ePitch = convertSpacing(spacing);
+ if( eSlantRes == FcResultMatch )
+ pUpdate->m_eItalic = convertSlant(slant);
+ if( eStyleRes == FcResultMatch )
+ {
+ pUpdate->m_aStyleName = OStringToOUString( OString( (sal_Char*)style ), RTL_TEXTENCODING_UTF8 );
+ }
+
+ // update font cache
+ m_pFontCache->updateFontCacheEntry( pUpdate, false );
+ // sort into known fonts
+ fontID aFont = m_nNextFontID++;
+ m_aFonts[ aFont ] = pUpdate;
+ m_aFontFileToFontID[ aBase ].insert( aFont );
+ nFonts++;
+#if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, "inserted font %s as fontID %d\n", family, aFont );
+#endif
+ }
+ // clean up the fonts we did not put into the list
+ for( std::list< PrintFont* >::iterator it = aFonts.begin(); it != aFonts.end(); ++it )
+ {
+ if( *it != pUpdate )
+ {
+ m_pFontCache->updateFontCacheEntry( *it, false ); // prepare a cache entry for a collection item
+ delete *it;
+ }
+ }
+ }
+ }
+
+ // how does one get rid of the config ?
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "inserted %d fonts from fontconfig\n", nFonts );
+#endif
+ return nFonts;
+}
+
+void PrintFontManager::deinitFontconfig()
+{
+ FontCfgWrapper::release();
+}
+
+int PrintFontManager::FreeTypeCharIndex( void *pFace, sal_uInt32 aChar )
+{
+ FontCfgWrapper& rWrapper = FontCfgWrapper::get();
+ return rWrapper.isValid() ? rWrapper.FcFreeTypeCharIndex( (FT_Face)pFace, aChar ) : 0;
+}
+
+bool PrintFontManager::addFontconfigDir( const rtl::OString& rDirName )
+{
+ FontCfgWrapper& rWrapper = FontCfgWrapper::get();
+ if( ! rWrapper.isValid() )
+ return false;
+
+ // workaround for a stability problems in older FC versions
+ // when handling application specifc fonts
+ const int nVersion = rWrapper.FcGetVersion();
+ if( nVersion <= 20400 )
+ return false;
+ const char* pDirName = (const char*)rDirName.getStr();
+ bool bDirOk = (rWrapper.FcConfigAppFontAddDir( rWrapper.FcConfigGetCurrent(), (FcChar8*)pDirName ) == FcTrue);
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "FcConfigAppFontAddDir( \"%s\") => %d\n", pDirName, bDirOk );
+#endif
+
+ if( bDirOk )
+ {
+ const rtl::OString aConfFileName = rDirName + "/fc_local.conf";
+ bool bCfgOk = rWrapper.FcConfigParseAndLoad( rWrapper.FcConfigGetCurrent(),
+ (FcChar8*)aConfFileName.getStr(), FcTrue );
+ (void)bCfgOk; // silence compiler warning
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "FcConfigParseAndLoad( \"%s\") => %d\n", aConfFileName.getStr(), bCfgOk );
+#endif
+ }
+
+ return bDirOk;
+}
+
+static void addtopattern(FontCfgWrapper& rWrapper, FcPattern *pPattern,
+ italic::type eItalic, weight::type eWeight, width::type eWidth, pitch::type ePitch)
+{
+ if( eItalic != italic::Unknown )
+ {
+ int nSlant = FC_SLANT_ROMAN;
+ switch( eItalic )
+ {
+ case italic::Italic: nSlant = FC_SLANT_ITALIC;break;
+ case italic::Oblique: nSlant = FC_SLANT_OBLIQUE;break;
+ default:
+ break;
+ }
+ rWrapper.FcPatternAddInteger( pPattern, FC_SLANT, nSlant );
+ }
+ if( eWeight != weight::Unknown )
+ {
+ int nWeight = FC_WEIGHT_NORMAL;
+ switch( eWeight )
+ {
+ case weight::Thin: nWeight = FC_WEIGHT_THIN;break;
+ case weight::UltraLight: nWeight = FC_WEIGHT_ULTRALIGHT;break;
+ case weight::Light: nWeight = FC_WEIGHT_LIGHT;break;
+ case weight::SemiLight: nWeight = FC_WEIGHT_BOOK;break;
+ case weight::Normal: nWeight = FC_WEIGHT_NORMAL;break;
+ case weight::Medium: nWeight = FC_WEIGHT_MEDIUM;break;
+ case weight::SemiBold: nWeight = FC_WEIGHT_SEMIBOLD;break;
+ case weight::Bold: nWeight = FC_WEIGHT_BOLD;break;
+ case weight::UltraBold: nWeight = FC_WEIGHT_ULTRABOLD;break;
+ case weight::Black: nWeight = FC_WEIGHT_BLACK;break;
+ default:
+ break;
+ }
+ rWrapper.FcPatternAddInteger( pPattern, FC_WEIGHT, nWeight );
+ }
+ if( eWidth != width::Unknown )
+ {
+ int nWidth = FC_WIDTH_NORMAL;
+ switch( eWidth )
+ {
+ case width::UltraCondensed: nWidth = FC_WIDTH_ULTRACONDENSED;break;
+ case width::ExtraCondensed: nWidth = FC_WIDTH_EXTRACONDENSED;break;
+ case width::Condensed: nWidth = FC_WIDTH_CONDENSED;break;
+ case width::SemiCondensed: nWidth = FC_WIDTH_SEMICONDENSED;break;
+ case width::Normal: nWidth = FC_WIDTH_NORMAL;break;
+ case width::SemiExpanded: nWidth = FC_WIDTH_SEMIEXPANDED;break;
+ case width::Expanded: nWidth = FC_WIDTH_EXPANDED;break;
+ case width::ExtraExpanded: nWidth = FC_WIDTH_EXTRAEXPANDED;break;
+ case width::UltraExpanded: nWidth = FC_WIDTH_ULTRACONDENSED;break;
+ default:
+ break;
+ }
+ rWrapper.FcPatternAddInteger( pPattern, FC_WIDTH, nWidth );
+ }
+ if( ePitch != pitch::Unknown )
+ {
+ int nSpacing = FC_PROPORTIONAL;
+ switch( ePitch )
+ {
+ case pitch::Fixed: nSpacing = FC_MONO;break;
+ case pitch::Variable: nSpacing = FC_PROPORTIONAL;break;
+ default:
+ break;
+ }
+ rWrapper.FcPatternAddInteger( pPattern, FC_SPACING, nSpacing );
+ if (nSpacing == FC_MONO)
+ rWrapper.FcPatternAddString( pPattern, FC_FAMILY, (FcChar8*)"monospace");
+ }
+}
+
+rtl::OUString PrintFontManager::Substitute(const rtl::OUString& rFontName,
+ rtl::OUString& rMissingCodes, const rtl::OString &rLangAttrib,
+ italic::type &rItalic, weight::type &rWeight,
+ width::type &rWidth, pitch::type &rPitch) const
+{
+ rtl::OUString aName;
+ FontCfgWrapper& rWrapper = FontCfgWrapper::get();
+ if( ! rWrapper.isValid() )
+ return aName;
+
+ // build pattern argument for fontconfig query
+ FcPattern* pPattern = rWrapper.FcPatternCreate();
+
+ // Prefer scalable fonts
+ rWrapper.FcPatternAddBool( pPattern, FC_SCALABLE, FcTrue );
+
+ const rtl::OString aTargetName = rtl::OUStringToOString( rFontName, RTL_TEXTENCODING_UTF8 );
+ const FcChar8* pTargetNameUtf8 = (FcChar8*)aTargetName.getStr();
+ rWrapper.FcPatternAddString( pPattern, FC_FAMILY, pTargetNameUtf8 );
+
+ const FcChar8* pLangAttribUtf8 = (FcChar8*)rLangAttrib.getStr();
+ if( rLangAttrib.getLength() )
+ rWrapper.FcPatternAddString( pPattern, FC_LANG, pLangAttribUtf8 );
+
+ // Add required Unicode characters, if any
+ if ( rMissingCodes.getLength() )
+ {
+ FcCharSet *unicodes = rWrapper.FcCharSetCreate();
+ for( sal_Int32 nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
+ {
+ // also handle unicode surrogates
+ const sal_uInt32 nCode = rMissingCodes.iterateCodePoints( &nStrIndex );
+ rWrapper.FcCharSetAddChar( unicodes, nCode );
+ }
+ rWrapper.FcPatternAddCharSet( pPattern, FC_CHARSET, unicodes);
+ rWrapper.FcCharSetDestroy( unicodes );
+ }
+
+ addtopattern(rWrapper, pPattern, rItalic, rWeight, rWidth, rPitch);
+
+ // query fontconfig for a substitute
+ rWrapper.FcConfigSubstitute( rWrapper.FcConfigGetCurrent(), pPattern, FcMatchPattern );
+ rWrapper.FcDefaultSubstitute( pPattern );
+
+ // process the result of the fontconfig query
+ FcResult eResult = FcResultNoMatch;
+ FcFontSet* pFontSet = rWrapper.getFontSet();
+ FcPattern* pResult = rWrapper.FcFontSetMatch( rWrapper.FcConfigGetCurrent(), &pFontSet, 1, pPattern, &eResult );
+ rWrapper.FcPatternDestroy( pPattern );
+
+ FcFontSet* pSet = NULL;
+ if( pResult )
+ {
+ pSet = rWrapper.FcFontSetCreate();
+ // info: destroying the pSet destroys pResult implicitly
+ // since pResult was "added" to pSet
+ rWrapper.FcFontSetAdd( pSet, pResult );
+ }
+
+ if( pSet )
+ {
+ if( pSet->nfont > 0 )
+ {
+ //extract the closest match
+ FcChar8* family = NULL;
+ FcResult eFileRes = rWrapper.FcPatternGetString( pSet->fonts[0], FC_FAMILY, 0, &family );
+
+ // get the family name
+ if( eFileRes == FcResultMatch )
+ {
+ OString sFamily((sal_Char*)family);
+ std::hash_map< rtl::OString, rtl::OString, rtl::OStringHash >::const_iterator aI = rWrapper.m_aFontNameToLocalized.find(sFamily);
+ if (aI != rWrapper.m_aFontNameToLocalized.end())
+ sFamily = aI->second;
+ aName = rtl::OStringToOUString( sFamily, RTL_TEXTENCODING_UTF8 );
+
+
+ int val = 0;
+ if ( FcResultMatch == rWrapper.FcPatternGetInteger( pSet->fonts[0], FC_WEIGHT, 0, &val))
+ rWeight = convertWeight(val);
+ if ( FcResultMatch == rWrapper.FcPatternGetInteger( pSet->fonts[0], FC_SLANT, 0, &val))
+ rItalic = convertSlant(val);
+ if ( FcResultMatch == rWrapper.FcPatternGetInteger( pSet->fonts[0], FC_SPACING, 0, &val))
+ rPitch = convertSpacing(val);
+ if ( FcResultMatch == rWrapper.FcPatternGetInteger( pSet->fonts[0], FC_WIDTH, 0, &val))
+ rWidth = convertWidth(val);
+ }
+
+ // update rMissingCodes by removing resolved unicodes
+ if( rMissingCodes.getLength() > 0 )
+ {
+ sal_uInt32* pRemainingCodes = (sal_uInt32*)alloca( rMissingCodes.getLength() * sizeof(sal_uInt32) );
+ int nRemainingLen = 0;
+ FcCharSet* unicodes;
+ if( !rWrapper.FcPatternGetCharSet( pSet->fonts[0], FC_CHARSET, 0, &unicodes ) )
+ {
+ for( sal_Int32 nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
+ {
+ // also handle unicode surrogates
+ const sal_uInt32 nCode = rMissingCodes.iterateCodePoints( &nStrIndex );
+ if( rWrapper.FcCharSetHasChar( unicodes, nCode ) != FcTrue )
+ pRemainingCodes[ nRemainingLen++ ] = nCode;
+ }
+ }
+ rMissingCodes = OUString( pRemainingCodes, nRemainingLen );
+ }
+ }
+
+ rWrapper.FcFontSetDestroy( pSet );
+ }
+
+ return aName;
+}
+
+bool PrintFontManager::getFontOptions(
+ const FastPrintFontInfo& rInfo, int nSize, void (*subcallback)(void*),
+ ImplFontOptions& rOptions) const
+{
+#ifndef ENABLE_FONTCONFIG
+ return false;
+#else // ENABLE_FONTCONFIG
+ FontCfgWrapper& rWrapper = FontCfgWrapper::get();
+ if( ! rWrapper.isValid() )
+ return false;
+
+ FcConfig* pConfig = rWrapper.FcConfigGetCurrent();
+ FcPattern* pPattern = rWrapper.FcPatternCreate();
+
+ OString sFamily = OUStringToOString( rInfo.m_aFamilyName, RTL_TEXTENCODING_UTF8 );
+
+ std::hash_map< rtl::OString, rtl::OString, rtl::OStringHash >::const_iterator aI = rWrapper.m_aLocalizedToCanonical.find(sFamily);
+ if (aI != rWrapper.m_aLocalizedToCanonical.end())
+ sFamily = aI->second;
+ if( sFamily.getLength() )
+ rWrapper.FcPatternAddString( pPattern, FC_FAMILY, (FcChar8*)sFamily.getStr() );
+
+ addtopattern(rWrapper, pPattern, rInfo.m_eItalic, rInfo.m_eWeight, rInfo.m_eWidth, rInfo.m_ePitch);
+ rWrapper.FcPatternAddDouble( pPattern, FC_PIXEL_SIZE, nSize);
+
+ FcBool embitmap = true, antialias = true, autohint = true, hinting = true;
+ int hintstyle = FC_HINT_FULL;
+
+ rWrapper.FcConfigSubstitute( pConfig, pPattern, FcMatchPattern );
+ if (subcallback) subcallback(pPattern);
+ rWrapper.FcDefaultSubstitute( pPattern );
+
+ FcResult eResult = FcResultNoMatch;
+ FcFontSet* pFontSet = rWrapper.getFontSet();
+ FcPattern* pResult = rWrapper.FcFontSetMatch( pConfig, &pFontSet, 1, pPattern, &eResult );
+ if( pResult )
+ {
+ FcFontSet* pSet = rWrapper.FcFontSetCreate();
+ rWrapper.FcFontSetAdd( pSet, pResult );
+ if( pSet->nfont > 0 )
+ {
+ FcResult eEmbeddedBitmap = rWrapper.FcPatternGetBool(pSet->fonts[0],
+ FC_EMBEDDED_BITMAP, 0, &embitmap);
+ FcResult eAntialias = rWrapper.FcPatternGetBool(pSet->fonts[0],
+ FC_ANTIALIAS, 0, &antialias);
+ FcResult eAutoHint = rWrapper.FcPatternGetBool(pSet->fonts[0],
+ FC_AUTOHINT, 0, &autohint);
+ FcResult eHinting = rWrapper.FcPatternGetBool(pSet->fonts[0],
+ FC_HINTING, 0, &hinting);
+ /*FcResult eHintStyle =*/ rWrapper.FcPatternGetInteger( pSet->fonts[0],
+ FC_HINT_STYLE, 0, &hintstyle);
+
+ if( eEmbeddedBitmap == FcResultMatch )
+ rOptions.meEmbeddedBitmap = embitmap ? EMBEDDEDBITMAP_TRUE : EMBEDDEDBITMAP_FALSE;
+ if( eAntialias == FcResultMatch )
+ rOptions.meAntiAlias = antialias ? ANTIALIAS_TRUE : ANTIALIAS_FALSE;
+ if( eAutoHint == FcResultMatch )
+ rOptions.meAutoHint = autohint ? AUTOHINT_TRUE : AUTOHINT_FALSE;
+ if( eHinting == FcResultMatch )
+ rOptions.meHinting = hinting ? HINTING_TRUE : HINTING_FALSE;
+ switch (hintstyle)
+ {
+ case FC_HINT_NONE: rOptions.meHintStyle = HINT_NONE; break;
+ case FC_HINT_SLIGHT: rOptions.meHintStyle = HINT_SLIGHT; break;
+ case FC_HINT_MEDIUM: rOptions.meHintStyle = HINT_MEDIUM; break;
+ default: // fall through
+ case FC_HINT_FULL: rOptions.meHintStyle = HINT_FULL; break;
+ }
+ }
+ // info: destroying the pSet destroys pResult implicitly
+ // since pResult was "added" to pSet
+ rWrapper.FcFontSetDestroy( pSet );
+ }
+
+ // cleanup
+ rWrapper.FcPatternDestroy( pPattern );
+
+ // TODO: return true only if non-default font options are set
+ const bool bOK = (pResult != NULL);
+ return bOK;
+#endif
+}
+
+bool PrintFontManager::matchFont( FastPrintFontInfo& rInfo, const com::sun::star::lang::Locale& rLocale )
+{
+ FontCfgWrapper& rWrapper = FontCfgWrapper::get();
+ if( ! rWrapper.isValid() )
+ return false;
+
+ FcConfig* pConfig = rWrapper.FcConfigGetCurrent();
+ FcPattern* pPattern = rWrapper.FcPatternCreate();
+
+ OString aLangAttrib;
+ // populate pattern with font characteristics
+ if( rLocale.Language.getLength() )
+ {
+ OUStringBuffer aLang(6);
+ aLang.append( rLocale.Language );
+ if( rLocale.Country.getLength() )
+ {
+ aLang.append( sal_Unicode('-') );
+ aLang.append( rLocale.Country );
+ }
+ aLangAttrib = OUStringToOString( aLang.makeStringAndClear(), RTL_TEXTENCODING_UTF8 );
+ }
+ if( aLangAttrib.getLength() )
+ rWrapper.FcPatternAddString( pPattern, FC_LANG, (FcChar8*)aLangAttrib.getStr() );
+
+ OString aFamily = OUStringToOString( rInfo.m_aFamilyName, RTL_TEXTENCODING_UTF8 );
+ if( aFamily.getLength() )
+ rWrapper.FcPatternAddString( pPattern, FC_FAMILY, (FcChar8*)aFamily.getStr() );
+
+ addtopattern(rWrapper, pPattern, rInfo.m_eItalic, rInfo.m_eWeight, rInfo.m_eWidth, rInfo.m_ePitch);
+
+ rWrapper.FcConfigSubstitute( pConfig, pPattern, FcMatchPattern );
+ rWrapper.FcDefaultSubstitute( pPattern );
+ FcResult eResult = FcResultNoMatch;
+ FcFontSet *pFontSet = rWrapper.getFontSet();
+ FcPattern* pResult = rWrapper.FcFontSetMatch( pConfig, &pFontSet, 1, pPattern, &eResult );
+ bool bSuccess = false;
+ if( pResult )
+ {
+ FcFontSet* pSet = rWrapper.FcFontSetCreate();
+ rWrapper.FcFontSetAdd( pSet, pResult );
+ if( pSet->nfont > 0 )
+ {
+ //extract the closest match
+ FcChar8* file = NULL;
+ FcResult eFileRes = rWrapper.FcPatternGetString( pSet->fonts[0], FC_FILE, 0, &file );
+ if( eFileRes == FcResultMatch )
+ {
+ OString aDir, aBase, aOrgPath( (sal_Char*)file );
+ splitPath( aOrgPath, aDir, aBase );
+ int nDirID = getDirectoryAtom( aDir, true );
+ fontID aFont = findFontFileID( nDirID, aBase );
+ if( aFont > 0 )
+ bSuccess = getFontFastInfo( aFont, rInfo );
+ }
+ }
+ // info: destroying the pSet destroys pResult implicitly
+ // since pResult was "added" to pSet
+ rWrapper.FcFontSetDestroy( pSet );
+ }
+
+ // cleanup
+ rWrapper.FcPatternDestroy( pPattern );
+
+ return bSuccess;
+}
+
+#else // ENABLE_FONTCONFIG not defined
+
+bool PrintFontManager::initFontconfig()
+{
+ return false;
+}
+
+int PrintFontManager::countFontconfigFonts( std::hash_map<rtl::OString, int, rtl::OStringHash>& )
+{
+ return 0;
+}
+
+void PrintFontManager::deinitFontconfig()
+{}
+
+bool PrintFontManager::addFontconfigDir( const rtl::OString& )
+{
+ return false;
+}
+
+bool PrintFontManager::matchFont( FastPrintFontInfo&, const com::sun::star::lang::Locale& )
+{
+ return false;
+}
+
+int PrintFontManager::FreeTypeCharIndex( void*, sal_uInt32 )
+{
+ return 0;
+}
+
+rtl::OUString PrintFontManager::Substitute( const rtl::OUString&,
+ rtl::OUString&, const rtl::OString&, italic::type, weight::type, width::type, pitch::type) const
+{
+ rtl::OUString aName;
+ return aName;
+}
+
+#endif // ENABLE_FONTCONFIG
+
diff --git a/vcl/unx/source/fontmanager/fontmanager.cxx b/vcl/unx/source/fontmanager/fontmanager.cxx
new file mode 100644
index 000000000000..21183dc567ec
--- /dev/null
+++ b/vcl/unx/source/fontmanager/fontmanager.cxx
@@ -0,0 +1,4099 @@
+/*************************************************************************
+ *
+ * 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 <unistd.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <osl/thread.h>
+
+#include "unotools/atom.hxx"
+
+#include "vcl/fontmanager.hxx"
+#include "vcl/fontcache.hxx"
+#include "vcl/fontcache.hxx"
+#include "vcl/fontsubset.hxx"
+#include "vcl/impfont.hxx"
+#include "vcl/strhelper.hxx"
+#include "vcl/ppdparser.hxx"
+#include "vcl/svdata.hxx"
+#include "vcl/salinst.hxx"
+
+#include "tools/urlobj.hxx"
+#include "tools/stream.hxx"
+#include "tools/debug.hxx"
+#include "tools/config.hxx"
+
+#include "osl/file.hxx"
+#include "osl/process.h"
+
+#include "rtl/tencinfo.h"
+#include "rtl/ustrbuf.hxx"
+#include "rtl/strbuf.hxx"
+
+#include "i18npool/mslangid.hxx"
+
+
+#include "parseAFM.hxx"
+#include "sft.hxx"
+
+#if OSL_DEBUG_LEVEL > 1
+#include <sys/times.h>
+#include <stdio.h>
+#endif
+
+#include "sal/alloca.h"
+
+#include <set>
+#include <hash_set>
+#include <algorithm>
+
+#include "adobeenc.tab" // get encoding table for AFM metrics
+
+#ifdef CALLGRIND_COMPILE
+#include <valgrind/callgrind.h>
+#endif
+
+#include "comphelper/processfactory.hxx"
+#include "com/sun/star/beans/XMaterialHolder.hpp"
+#include "com/sun/star/beans/NamedValue.hpp"
+
+#define PRINTER_METRICDIR "fontmetric"
+
+using namespace vcl;
+using namespace utl;
+using namespace psp;
+using namespace osl;
+using namespace rtl;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::lang;
+
+/*
+ * static helpers
+ */
+
+inline sal_uInt16 getUInt16BE( const sal_uInt8*& pBuffer )
+{
+ sal_uInt16 nRet = (sal_uInt16)pBuffer[1] |
+ (((sal_uInt16)pBuffer[0]) << 8);
+ pBuffer+=2;
+ return nRet;
+}
+
+inline sal_uInt32 getUInt32BE( const sal_uInt8*& pBuffer )
+{
+ sal_uInt32 nRet = (((sal_uInt32)pBuffer[0]) << 24) |
+ (((sal_uInt32)pBuffer[1]) << 16) |
+ (((sal_uInt32)pBuffer[2]) << 8) |
+ (((sal_uInt32)pBuffer[3]) );
+ pBuffer += 4;
+ return nRet;
+}
+
+static italic::type parseItalic( const ByteString& rItalic )
+{
+ italic::type eItalic = italic::Unknown;
+ if( rItalic.EqualsIgnoreCaseAscii( "i" ) )
+ eItalic = italic::Italic;
+ else if( rItalic.EqualsIgnoreCaseAscii( "o" ) )
+ eItalic = italic::Oblique;
+ else
+ eItalic = italic::Upright;
+ return eItalic;
+}
+
+// -------------------------------------------------------------------------
+
+static weight::type parseWeight( const ByteString& rWeight )
+{
+ weight::type eWeight = weight::Unknown;
+ if( rWeight.Search( "bold" ) != STRING_NOTFOUND )
+ {
+ if( rWeight.Search( "emi" ) != STRING_NOTFOUND ) // semi, demi
+ eWeight = weight::SemiBold;
+ else if( rWeight.Search( "ultra" ) != STRING_NOTFOUND )
+ eWeight = weight::UltraBold;
+ else
+ eWeight = weight::Bold;
+ }
+ else if( rWeight.Search( "heavy" ) != STRING_NOTFOUND )
+ eWeight = weight::Bold;
+ else if( rWeight.Search( "light" ) != STRING_NOTFOUND )
+ {
+ if( rWeight.Search( "emi" ) != STRING_NOTFOUND ) // semi, demi
+ eWeight = weight::SemiLight;
+ else if( rWeight.Search( "ultra" ) != STRING_NOTFOUND )
+ eWeight = weight::UltraLight;
+ else
+ eWeight = weight::Light;
+ }
+ else if( rWeight.Search( "black" ) != STRING_NOTFOUND )
+ eWeight = weight::Black;
+ else if( rWeight.Equals( "demi" ) )
+ eWeight = weight::SemiBold;
+ else if( rWeight.Equals( "book" ) ||
+ rWeight.Equals( "semicondensed" ) )
+ eWeight = weight::Light;
+ else if( rWeight.Equals( "medium" ) || rWeight.Equals( "roman" ) )
+ eWeight = weight::Medium;
+ else
+ eWeight = weight::Normal;
+ return eWeight;
+}
+
+// -------------------------------------------------------------------------
+
+static width::type parseWidth( const ByteString& rWidth )
+{
+ width::type eWidth = width::Unknown;
+ if( rWidth.Equals( "bold" ) ||
+ rWidth.Equals( "semiexpanded" ) )
+ eWidth = width::SemiExpanded;
+ else if( rWidth.Equals( "condensed" ) ||
+ rWidth.Equals( "narrow" ) )
+ eWidth = width::Condensed;
+ else if( rWidth.Equals( "double wide" ) ||
+ rWidth.Equals( "extraexpanded" ) ||
+ rWidth.Equals( "ultraexpanded" ) )
+ eWidth = width::UltraExpanded;
+ else if( rWidth.Equals( "expanded" ) ||
+ rWidth.Equals( "wide" ) )
+ eWidth = width::Expanded;
+ else if( rWidth.Equals( "extracondensed" ) )
+ eWidth = width::ExtraCondensed;
+ else if( rWidth.Equals( "semicondensed" ) )
+ eWidth = width::SemiCondensed;
+ else if( rWidth.Equals( "ultracondensed" ) )
+ eWidth = width::UltraCondensed;
+ else
+ eWidth = width::Normal;
+
+ return eWidth;
+}
+
+// -------------------------------------------------------------------------
+bool PrintFontManager::XLFDEntry::operator<(const PrintFontManager::XLFDEntry& rRight) const
+{
+ sal_Int32 nCmp = 0;
+ if( (nMask & MaskFamily) && (rRight.nMask & MaskFamily) )
+ {
+ nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aFamily.pData->buffer,
+ aFamily.pData->length,
+ rRight.aFamily.pData->buffer,
+ rRight.aFamily.pData->length );
+ if( nCmp != 0 )
+ return nCmp < 0;
+ }
+
+ if( (nMask & MaskFoundry) && (rRight.nMask & MaskFoundry) )
+ {
+ nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aFoundry.pData->buffer,
+ aFoundry.pData->length,
+ rRight.aFoundry.pData->buffer,
+ rRight.aFoundry.pData->length );
+ if( nCmp != 0 )
+ return nCmp < 0;
+ }
+
+ if( (nMask & MaskItalic) && (rRight.nMask & MaskItalic) )
+ {
+ if( eItalic != rRight.eItalic )
+ return (int)eItalic < (int)rRight.eItalic;
+ }
+
+ if( (nMask & MaskWeight) && (rRight.nMask & MaskWeight) )
+ {
+ if( eWeight != rRight.eWeight )
+ return (int)eWeight < (int)rRight.eWeight;
+ }
+
+ if( (nMask & MaskWidth) && (rRight.nMask & MaskWidth) )
+ {
+ if( eWidth != rRight.eWidth )
+ return (int)eWidth < (int)rRight.eWidth;
+ }
+
+ if( (nMask & MaskPitch) && (rRight.nMask & MaskPitch) )
+ {
+ if( ePitch != rRight.ePitch )
+ return (int)ePitch < (int)rRight.ePitch;
+ }
+
+ if( (nMask & MaskAddStyle) && (rRight.nMask & MaskAddStyle) )
+ {
+ nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aAddStyle.pData->buffer,
+ aAddStyle.pData->length,
+ rRight.aAddStyle.pData->buffer,
+ rRight.aAddStyle.pData->length );
+ if( nCmp != 0 )
+ return nCmp < 0;
+ }
+
+ if( (nMask & MaskEncoding) && (rRight.nMask & MaskEncoding) )
+ {
+ if( aEncoding != rRight.aEncoding )
+ return aEncoding < rRight.aEncoding;
+ }
+
+ return false;
+}
+
+bool PrintFontManager::XLFDEntry::operator==(const PrintFontManager::XLFDEntry& rRight) const
+{
+ sal_Int32 nCmp = 0;
+ if( (nMask & MaskFamily) && (rRight.nMask & MaskFamily) )
+ {
+ nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aFamily.pData->buffer,
+ aFamily.pData->length,
+ rRight.aFamily.pData->buffer,
+ rRight.aFamily.pData->length );
+ if( nCmp != 0 )
+ return false;
+ }
+
+ if( (nMask & MaskFoundry) && (rRight.nMask & MaskFoundry) )
+ {
+ nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aFoundry.pData->buffer,
+ aFoundry.pData->length,
+ rRight.aFoundry.pData->buffer,
+ rRight.aFoundry.pData->length );
+ if( nCmp != 0 )
+ return false;
+ }
+
+ if( (nMask & MaskItalic) && (rRight.nMask & MaskItalic) )
+ {
+ if( eItalic != rRight.eItalic )
+ return false;
+ }
+
+ if( (nMask & MaskWeight) && (rRight.nMask & MaskWeight) )
+ {
+ if( eWeight != rRight.eWeight )
+ return false;
+ }
+
+ if( (nMask & MaskWidth) && (rRight.nMask & MaskWidth) )
+ {
+ if( eWidth != rRight.eWidth )
+ return false;
+ }
+
+ if( (nMask & MaskPitch) && (rRight.nMask & MaskPitch) )
+ {
+ if( ePitch != rRight.ePitch )
+ return false;
+ }
+
+ if( (nMask & MaskAddStyle) && (rRight.nMask & MaskAddStyle) )
+ {
+ nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aAddStyle.pData->buffer,
+ aAddStyle.pData->length,
+ rRight.aAddStyle.pData->buffer,
+ rRight.aAddStyle.pData->length );
+ if( nCmp != 0 )
+ return false;
+ }
+
+ if( (nMask & MaskEncoding) && (rRight.nMask & MaskEncoding) )
+ {
+ if( aEncoding != rRight.aEncoding )
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * PrintFont implementations
+ */
+PrintFontManager::PrintFont::PrintFont( fonttype::type eType ) :
+ m_eType( eType ),
+ m_nFamilyName( 0 ),
+ m_nPSName( 0 ),
+ m_eItalic( italic::Unknown ),
+ m_eWidth( width::Unknown ),
+ m_eWeight( weight::Unknown ),
+ m_ePitch( pitch::Unknown ),
+ m_aEncoding( RTL_TEXTENCODING_DONTKNOW ),
+ m_bFontEncodingOnly( false ),
+ m_pMetrics( NULL ),
+ m_nAscend( 0 ),
+ m_nDescend( 0 ),
+ m_nLeading( 0 ),
+ m_nXMin( 0 ),
+ m_nYMin( 0 ),
+ m_nXMax( 0 ),
+ m_nYMax( 0 ),
+ m_bHaveVerticalSubstitutedGlyphs( false ),
+ m_bUserOverride( false )
+{
+}
+
+// -------------------------------------------------------------------------
+
+PrintFontManager::PrintFont::~PrintFont()
+{
+ if( m_pMetrics )
+ delete m_pMetrics;
+}
+
+// -------------------------------------------------------------------------
+
+PrintFontManager::Type1FontFile::~Type1FontFile()
+{
+}
+
+// -------------------------------------------------------------------------
+
+PrintFontManager::TrueTypeFontFile::TrueTypeFontFile()
+: PrintFont( fonttype::TrueType )
+, m_nDirectory( 0 )
+, m_nCollectionEntry(-1)
+, m_nTypeFlags( TYPEFLAG_INVALID )
+{}
+
+// -------------------------------------------------------------------------
+
+PrintFontManager::TrueTypeFontFile::~TrueTypeFontFile()
+{
+}
+
+// -------------------------------------------------------------------------
+
+PrintFontManager::BuiltinFont::~BuiltinFont()
+{
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::Type1FontFile::queryMetricPage( int /*nPage*/, MultiAtomProvider* pProvider )
+{
+ return readAfmMetrics( PrintFontManager::get().getAfmFile( this ), pProvider, false, false );
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::BuiltinFont::queryMetricPage( int /*nPage*/, MultiAtomProvider* pProvider )
+{
+ return readAfmMetrics( PrintFontManager::get().getAfmFile( this ), pProvider, false, false );
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::TrueTypeFontFile::queryMetricPage( int nPage, MultiAtomProvider* pProvider )
+{
+ bool bSuccess = false;
+
+ ByteString aFile( PrintFontManager::get().getFontFile( this ) );
+
+ TrueTypeFont* pTTFont = NULL;
+
+ if( OpenTTFontFile( aFile.GetBuffer(), m_nCollectionEntry < 0 ? 0 : m_nCollectionEntry, &pTTFont ) == SF_OK )
+ {
+ if( ! m_pMetrics )
+ {
+ m_pMetrics = new PrintFontMetrics;
+ memset (m_pMetrics->m_aPages, 0, sizeof(m_pMetrics->m_aPages));
+ }
+ m_pMetrics->m_aPages[ nPage/8 ] |= (1 << ( nPage & 7 ));
+ int i;
+ sal_uInt16 table[256], table_vert[256];
+
+ for( i = 0; i < 256; i++ )
+ table[ i ] = 256*nPage + i;
+
+ int nCharacters = nPage < 255 ? 256 : 254;
+ MapString( pTTFont, table, nCharacters, NULL, 0 );
+ TTSimpleGlyphMetrics* pMetrics = GetTTSimpleCharMetrics( pTTFont, nPage*256, nCharacters, 0 );
+ if( pMetrics )
+ {
+ for( i = 0; i < nCharacters; i++ )
+ {
+ if( table[i] )
+ {
+ CharacterMetric& rChar = m_pMetrics->m_aMetrics[ nPage*256 + i ];
+ rChar.width = pMetrics[ i ].adv;
+ rChar.height = m_aGlobalMetricX.height;
+ }
+ }
+
+ free( pMetrics );
+ }
+
+ for( i = 0; i < 256; i++ )
+ table_vert[ i ] = 256*nPage + i;
+ MapString( pTTFont, table_vert, nCharacters, NULL, 1 );
+ pMetrics = GetTTSimpleCharMetrics( pTTFont, nPage*256, nCharacters, 1 );
+ if( pMetrics )
+ {
+ for( i = 0; i < nCharacters; i++ )
+ {
+ if( table_vert[i] )
+ {
+ CharacterMetric& rChar = m_pMetrics->m_aMetrics[ nPage*256 + i + ( 1 << 16 ) ];
+ rChar.width = m_aGlobalMetricY.width;
+ rChar.height = pMetrics[ i ].adv;
+ if( table_vert[i] != table[i] )
+ m_pMetrics->m_bVerticalSubstitutions[ nPage*256 + i ] = 1;
+ }
+ }
+ free( pMetrics );
+ }
+
+ if( ! m_pMetrics->m_bKernPairsQueried )
+ {
+ m_pMetrics->m_bKernPairsQueried = true;
+ // this is really a hack
+ // in future MapString/KernGlyphs should be used
+ // but vcl is not in a state where that could be used
+ // so currently we get kernpairs by accessing the raw data
+ struct _TrueTypeFont* pImplTTFont = (struct _TrueTypeFont*)pTTFont;
+
+ //-----------------------------------------------------------------
+ // Kerning: KT_MICROSOFT
+ //-----------------------------------------------------------------
+ if( pImplTTFont->nkern && pImplTTFont->kerntype == KT_MICROSOFT )
+ {
+ // create a glyph -> character mapping
+ ::std::hash_map< sal_uInt16, sal_Unicode > aGlyphMap;
+ ::std::hash_map< sal_uInt16, sal_Unicode >::iterator left, right;
+ for( i = 21; i < 0xfffd; i++ )
+ {
+ sal_uInt16 nGlyph = MapChar( pTTFont, (sal_Unicode)i, 0 ); // kerning for horz only
+ if( nGlyph != 0 )
+ aGlyphMap[ nGlyph ] = (sal_Unicode)i;
+ }
+
+
+ KernPair aPair;
+ for( i = 0; i < (int)pImplTTFont->nkern; i++ )
+ {
+ const sal_uInt8* pTable = pImplTTFont->kerntables[i];
+
+ /*sal_uInt16 nVersion =*/ getUInt16BE( pTable );
+ /*sal_uInt16 nLength =*/ getUInt16BE( pTable );
+ sal_uInt16 nCoverage = getUInt16BE( pTable );
+
+ aPair.kern_x = 0;
+ aPair.kern_y = 0;
+ switch( nCoverage >> 8 )
+ {
+ case 0:
+ {
+ sal_uInt16 nPairs = getUInt16BE( pTable );
+ pTable += 6;
+ for( int n = 0; n < nPairs; n++ )
+ {
+ sal_uInt16 nLeftGlyph = getUInt16BE( pTable );
+ sal_uInt16 nRightGlyph = getUInt16BE( pTable );
+ sal_Int16 nKern = (sal_Int16)getUInt16BE( pTable );
+
+ left = aGlyphMap.find( nLeftGlyph );
+ right = aGlyphMap.find( nRightGlyph );
+ if( left != aGlyphMap.end() && right != aGlyphMap.end() )
+ {
+ aPair.first = left->second;
+ aPair.second = right->second;
+ switch( nCoverage & 1 )
+ {
+ case 1:
+ aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aXKernPairs.push_back( aPair );
+ break;
+ case 0:
+ aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aYKernPairs.push_back( aPair );
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ case 2:
+ {
+ const sal_uInt8* pSubTable = pTable;
+ /*sal_uInt16 nRowWidth =*/ getUInt16BE( pTable );
+ sal_uInt16 nOfLeft = getUInt16BE( pTable );
+ sal_uInt16 nOfRight = getUInt16BE( pTable );
+ /*sal_uInt16 nOfArray =*/ getUInt16BE( pTable );
+ const sal_uInt8* pTmp = pSubTable + nOfLeft;
+ sal_uInt16 nFirstLeft = getUInt16BE( pTmp );
+ sal_uInt16 nLastLeft = getUInt16BE( pTmp ) + nFirstLeft - 1;
+ pTmp = pSubTable + nOfRight;
+ sal_uInt16 nFirstRight = getUInt16BE( pTmp );
+ sal_uInt16 nLastRight = getUInt16BE( pTmp ) + nFirstRight -1;
+
+ // int nPairs = (int)(nLastLeft-nFirstLeft+1)*(int)(nLastRight-nFirstRight+1);
+ for( aPair.first = nFirstLeft; aPair.first < nLastLeft; aPair.first++ )
+ {
+ for( aPair.second = 0; aPair.second < nLastRight; aPair.second++ )
+ {
+ sal_Int16 nKern = (sal_Int16)getUInt16BE( pTmp );
+ switch( nCoverage & 1 )
+ {
+ case 1:
+ aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aXKernPairs.push_back( aPair );
+ break;
+ case 0:
+ aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aYKernPairs.push_back( aPair );
+ break;
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ //-----------------------------------------------------------------
+ // Kerning: KT_APPLE_NEW
+ //-----------------------------------------------------------------
+ if( pImplTTFont->nkern && pImplTTFont->kerntype == KT_APPLE_NEW )
+ {
+ // create a glyph -> character mapping
+ ::std::hash_map< sal_uInt16, sal_Unicode > aGlyphMap;
+ ::std::hash_map< sal_uInt16, sal_Unicode >::iterator left, right;
+ for( i = 21; i < 0xfffd; i++ )
+ {
+ sal_uInt16 nGlyph = MapChar( pTTFont, (sal_Unicode)i, 0 ); // kerning for horz only
+ if( nGlyph != 0 )
+ aGlyphMap[ nGlyph ] = (sal_Unicode)i;
+ }
+
+ // Loop through each of the 'kern' subtables
+ KernPair aPair;
+ for( i = 0; (unsigned int)i < pImplTTFont->nkern; i++ )
+ {
+ const sal_uInt8* pTable = pImplTTFont->kerntables[i];
+
+ /*sal_uInt32 nLength =*/ getUInt32BE( pTable );
+ sal_uInt16 nCoverage = getUInt16BE( pTable );
+ /*sal_uInt16 nTupleIndex =*/ getUInt16BE( pTable );
+
+ // Get kerning type
+ // sal_Bool bKernVertical = nCoverage & 0x8000;
+ // sal_Bool bKernCrossStream = nCoverage & 0x4000;
+ // sal_Bool bKernVariation = nCoverage & 0x2000;
+
+ // Kerning sub-table format, 0 through 3
+ sal_uInt8 nSubTableFormat = nCoverage & 0x00FF;
+
+ aPair.kern_x = 0;
+ aPair.kern_y = 0;
+ switch( nSubTableFormat )
+ {
+ case 0:
+ {
+ // Grab the # of kern pairs but skip over the:
+ // searchRange
+ // entrySelector
+ // rangeShift
+ sal_uInt16 nPairs = getUInt16BE( pTable );
+ pTable += 6;
+
+ for( int n = 0; n < nPairs; n++ )
+ {
+ sal_uInt16 nLeftGlyph = getUInt16BE( pTable );
+ sal_uInt16 nRightGlyph = getUInt16BE( pTable );
+ sal_Int16 nKern = (sal_Int16)getUInt16BE( pTable );
+
+ left = aGlyphMap.find( nLeftGlyph );
+ right = aGlyphMap.find( nRightGlyph );
+ if( left != aGlyphMap.end() && right != aGlyphMap.end() )
+ {
+ aPair.first = left->second;
+ aPair.second = right->second;
+
+ // Only support horizontal kerning for now
+ aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ aPair.kern_y = 0;
+ m_pMetrics->m_aXKernPairs.push_back( aPair );
+
+/* switch( nCoverage & 1 )
+ {
+ case 1:
+ aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aXKernPairs.push_back( aPair );
+ break;
+ case 0:
+ aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aYKernPairs.push_back( aPair );
+ break;
+ }
+*/
+ }
+ }
+ }
+ break;
+
+ case 2:
+ {
+ const sal_uInt8* pSubTable = pTable;
+ /*sal_uInt16 nRowWidth =*/ getUInt16BE( pTable );
+ sal_uInt16 nOfLeft = getUInt16BE( pTable );
+ sal_uInt16 nOfRight = getUInt16BE( pTable );
+ /*sal_uInt16 nOfArray =*/ getUInt16BE( pTable );
+ const sal_uInt8* pTmp = pSubTable + nOfLeft;
+ sal_uInt16 nFirstLeft = getUInt16BE( pTmp );
+ sal_uInt16 nLastLeft = getUInt16BE( pTmp ) + nFirstLeft - 1;
+ pTmp = pSubTable + nOfRight;
+ sal_uInt16 nFirstRight = getUInt16BE( pTmp );
+ sal_uInt16 nLastRight = getUInt16BE( pTmp ) + nFirstRight -1;
+
+ for( aPair.first = nFirstLeft; aPair.first < nLastLeft; aPair.first++ )
+ {
+ for( aPair.second = 0; aPair.second < nLastRight; aPair.second++ )
+ {
+ sal_Int16 nKern = (sal_Int16)getUInt16BE( pTmp );
+ switch( nCoverage & 1 )
+ {
+ case 1:
+ aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aXKernPairs.push_back( aPair );
+ break;
+ case 0:
+ aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aYKernPairs.push_back( aPair );
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ fprintf( stderr, "Found unsupported Apple-style kern subtable type %d.\n", nSubTableFormat );
+ break;
+ }
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "found %d/%d kern pairs for %s\n",
+ m_pMetrics->m_aXKernPairs.size(),
+ m_pMetrics->m_aYKernPairs.size(),
+ OUStringToOString( pProvider->getString( ATOM_FAMILYNAME, m_nFamilyName ), RTL_TEXTENCODING_MS_1252 ).getStr() );
+#else
+ (void) pProvider; /* avoid warnings */
+#endif
+ }
+
+ CloseTTFont( pTTFont );
+ bSuccess = true;
+ }
+ return bSuccess;
+}
+
+// -------------------------------------------------------------------------
+
+/* #i73387# There seem to be fonts with a rather unwell chosen family name
+* consider e.g. "Helvetica Narrow" which defines its family as "Helvetica"
+* It can really only be distinguished by its PSName and FullName. Both of
+* which are not user presentable in OOo. So replace it by something sensible.
+*
+* If other fonts feature this behaviour, insert them to the map.
+*/
+static bool familyNameOverride( const OUString& i_rPSname, OUString& o_rFamilyName )
+{
+ static std::hash_map< OUString, OUString, OUStringHash > aPSNameToFamily( 16 );
+ if( aPSNameToFamily.empty() ) // initialization
+ {
+ aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow" ) ) ] =
+ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
+ aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow-Bold" ) ) ] =
+ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
+ aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow-BoldOblique" ) ) ] =
+ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
+ aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow-Oblique" ) ) ] =
+ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
+ }
+ std::hash_map<OUString,OUString,OUStringHash>::const_iterator it =
+ aPSNameToFamily.find( i_rPSname );
+ bool bReplaced = (it != aPSNameToFamily.end() );
+ if( bReplaced )
+ o_rFamilyName = it->second;
+ return bReplaced;
+};
+
+bool PrintFontManager::PrintFont::readAfmMetrics( const OString& rFileName, MultiAtomProvider* pProvider, bool bFillEncodingvector, bool bOnlyGlobalAttributes )
+{
+ PrintFontManager& rManager( PrintFontManager::get() );
+
+ int i;
+ FontInfo* pInfo = NULL;
+ parseFile( rFileName.getStr(), &pInfo, P_ALL );
+ if( ! pInfo || ! pInfo->numOfChars )
+ {
+ if( pInfo )
+ freeFontInfo( pInfo );
+ return false;
+ }
+
+ m_aEncodingVector.clear();
+ // fill in global info
+
+ // PSName
+ OUString aPSName( OStringToOUString( pInfo->gfi->fontName, RTL_TEXTENCODING_ISO_8859_1 ) );
+ m_nPSName = pProvider->getAtom( ATOM_PSNAME, aPSName, sal_True );
+
+ // family name (if not already set)
+ OUString aFamily;
+ if( ! m_nFamilyName )
+ {
+ aFamily = OStringToOUString( pInfo->gfi->familyName, RTL_TEXTENCODING_ISO_8859_1 );
+ if( ! aFamily.getLength() )
+ {
+ aFamily = OStringToOUString( pInfo->gfi->fontName, RTL_TEXTENCODING_ISO_8859_1 );
+ sal_Int32 nIndex = 0;
+ aFamily = aFamily.getToken( 0, '-', nIndex );
+ }
+ familyNameOverride( aPSName, aFamily );
+ m_nFamilyName = pProvider->getAtom( ATOM_FAMILYNAME, aFamily, sal_True );
+ }
+ else
+ aFamily = pProvider->getString( ATOM_FAMILYNAME, m_nFamilyName );
+
+ // style name: if fullname begins with family name
+ // interpret the rest of fullname as style
+ if( ! m_aStyleName.getLength() && pInfo->gfi->fullName && *pInfo->gfi->fullName )
+ {
+ OUString aFullName( OStringToOUString( pInfo->gfi->fullName, RTL_TEXTENCODING_ISO_8859_1 ) );
+ if( aFullName.indexOf( aFamily ) == 0 )
+ m_aStyleName = WhitespaceToSpace( aFullName.copy( aFamily.getLength() ) );
+ }
+
+ // italic
+ if( pInfo->gfi->italicAngle > 0 )
+ m_eItalic = italic::Oblique;
+ else if( pInfo->gfi->italicAngle < 0 )
+ m_eItalic = italic::Italic;
+ else
+ m_eItalic = italic::Upright;
+
+ // weight
+ ByteString aLowerWeight( pInfo->gfi->weight );
+ aLowerWeight.ToLowerAscii();
+ m_eWeight = parseWeight( aLowerWeight );
+
+ // pitch
+ m_ePitch = pInfo->gfi->isFixedPitch ? pitch::Fixed : pitch::Variable;
+
+ // encoding - only set if unknown
+ int nAdobeEncoding = 0;
+ if( pInfo->gfi->encodingScheme )
+ {
+ if( !strcmp( pInfo->gfi->encodingScheme, "AdobeStandardEncoding" ) )
+ nAdobeEncoding = 1;
+ else if( !strcmp( pInfo->gfi->encodingScheme, "ISO10646-1" ) )
+ {
+ nAdobeEncoding = 1;
+ m_aEncoding = RTL_TEXTENCODING_UNICODE;
+ }
+ else if( !strcmp( pInfo->gfi->encodingScheme, "Symbol") )
+ nAdobeEncoding = 2;
+ else if( !strcmp( pInfo->gfi->encodingScheme, "FontSpecific") )
+ nAdobeEncoding = 3;
+
+ if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
+ m_aEncoding = nAdobeEncoding == 1 ?
+ RTL_TEXTENCODING_ADOBE_STANDARD : RTL_TEXTENCODING_SYMBOL;
+ }
+ else if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
+ m_aEncoding = RTL_TEXTENCODING_ADOBE_STANDARD;
+
+ // try to parse the font name and decide wether it might be a
+ // japanese font. Who invented this PITA ?
+ OUString aPSNameLastToken( aPSName.copy( aPSName.lastIndexOf( '-' )+1 ) );
+ if( ! aPSNameLastToken.compareToAscii( "H" ) ||
+ ! aPSNameLastToken.compareToAscii( "V" ) )
+ {
+ static const char* pEncs[] =
+ {
+ "EUC",
+ "RKSJ",
+ "SJ"
+ };
+ static const rtl_TextEncoding aEncs[] =
+ {
+ RTL_TEXTENCODING_EUC_JP,
+ RTL_TEXTENCODING_SHIFT_JIS,
+ RTL_TEXTENCODING_JIS_X_0208
+ };
+
+ for( unsigned int enc = 0; enc < sizeof( aEncs )/sizeof(aEncs[0]) && m_aEncoding == RTL_TEXTENCODING_DONTKNOW; enc++ )
+ {
+ sal_Int32 nIndex = 0, nOffset = 1;
+ do
+ {
+ OUString aToken( aPSName.getToken( nOffset, '-', nIndex ) );
+ if( nIndex == -1 )
+ break;
+ nOffset = 0;
+ if( ! aToken.compareToAscii( pEncs[enc] ) )
+ {
+ m_aEncoding = aEncs[ enc ];
+ m_bFontEncodingOnly = true;
+ }
+ } while( nIndex != -1 );
+ }
+
+ // default is jis
+ if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
+ m_aEncoding = RTL_TEXTENCODING_JIS_X_0208;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "Encoding %d for %s\n", m_aEncoding, pInfo->gfi->fontName );
+#endif
+ }
+
+ // hack for GB encoded builtin fonts posing as FontSpecific
+ if( m_eType == fonttype::Builtin && ( nAdobeEncoding == 3 || nAdobeEncoding == 0 ) )
+ {
+ int nLen = aFamily.getLength();
+ if( nLen > 2 &&
+ aFamily.getStr()[ nLen-2 ] == 'G' &&
+ aFamily.getStr()[ nLen-1 ] == 'B' &&
+ pInfo->numOfChars > 255 )
+ {
+ m_aEncoding = RTL_TEXTENCODING_GBK;
+ m_bFontEncodingOnly = true;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "found builtin font %s with GBK encoding\n", pInfo->gfi->fontName );
+#endif
+ }
+ }
+
+ // #i37313# check if Fontspecific is not rather some character encoding
+ if( nAdobeEncoding == 3 && m_aEncoding == RTL_TEXTENCODING_SYMBOL )
+ {
+ bool bYFound = false;
+ bool bQFound = false;
+ CharMetricInfo* pChar = pInfo->cmi;
+ for( int j = 0; j < pInfo->numOfChars && ! (bYFound && bQFound); j++ )
+ {
+ if( pChar[j].name )
+ {
+ if( pChar[j].name[0] == 'Y' && pChar[j].name[1] == 0 )
+ bYFound = true;
+ else if( pChar[j].name[0] == 'Q' && pChar[j].name[1] == 0 )
+ bQFound = true;
+ }
+ }
+ if( bQFound && bYFound )
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "setting FontSpecific font %s (file %s) to unicode\n",
+ pInfo->gfi->fontName,
+ rFileName.getStr()
+ );
+ #endif
+ nAdobeEncoding = 4;
+ m_aEncoding = RTL_TEXTENCODING_UNICODE;
+ bFillEncodingvector = false; // will be filled anyway, don't do the work twice
+ }
+ }
+
+ // ascend
+ m_nAscend = pInfo->gfi->fontBBox.ury;
+
+ // descend
+ // descends have opposite sign of our definition
+ m_nDescend = -pInfo->gfi->fontBBox.lly;
+
+ // fallback to ascender, descender
+ // interesting: the BBox seems to describe Ascender and Descender better
+ // as we understand it
+ if( m_nAscend == 0 )
+ m_nAscend = pInfo->gfi->ascender;
+ if( m_nDescend == 0)
+ m_nDescend = -pInfo->gfi->descender;
+
+ m_nLeading = m_nAscend + m_nDescend - 1000;
+
+ if( m_pMetrics )
+ delete m_pMetrics;
+ m_pMetrics = new PrintFontMetrics;
+ // mark all pages as queried (or clear if only global font info queiried)
+ memset( m_pMetrics->m_aPages, bOnlyGlobalAttributes ? 0 : 0xff, sizeof( m_pMetrics->m_aPages ) );
+
+ m_aGlobalMetricX.width = m_aGlobalMetricY.width =
+ pInfo->gfi->charwidth ? pInfo->gfi->charwidth : pInfo->gfi->fontBBox.urx;
+ m_aGlobalMetricX.height = m_aGlobalMetricY.height =
+ pInfo->gfi->capHeight ? pInfo->gfi->capHeight : pInfo->gfi->fontBBox.ury;
+
+ m_nXMin = pInfo->gfi->fontBBox.llx;
+ m_nYMin = pInfo->gfi->fontBBox.lly;
+ m_nXMax = pInfo->gfi->fontBBox.urx;
+ m_nYMax = pInfo->gfi->fontBBox.ury;
+
+ if( bFillEncodingvector || !bOnlyGlobalAttributes )
+ {
+ // fill in character metrics
+
+ // first transform the character codes to unicode
+ // note: this only works with single byte encodings
+ sal_Unicode* pUnicodes = (sal_Unicode*)alloca( pInfo->numOfChars * sizeof(sal_Unicode));
+ CharMetricInfo* pChar = pInfo->cmi;
+
+ for( i = 0; i < pInfo->numOfChars; i++, pChar++ )
+ {
+ if( nAdobeEncoding == 4 )
+ {
+ if( pChar->name )
+ {
+ pUnicodes[i] = 0;
+ std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
+ for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
+ {
+ if( *it != 0 )
+ {
+ m_aEncodingVector[ *it ] = pChar->code;
+ if( pChar->code == -1 )
+ m_aNonEncoded[ *it ] = pChar->name;
+ if( ! pUnicodes[i] ) // map the first
+ pUnicodes[i] = *it;
+ }
+ }
+ }
+ }
+ else if( pChar->code != -1 )
+ {
+ if( nAdobeEncoding == 3 && m_aEncoding == RTL_TEXTENCODING_SYMBOL )
+ {
+ pUnicodes[i] = pChar->code + 0xf000;
+ if( bFillEncodingvector )
+ m_aEncodingVector[ pUnicodes[i] ] = pChar->code;
+ continue;
+ }
+
+ if( m_aEncoding == RTL_TEXTENCODING_UNICODE )
+ {
+ pUnicodes[i] = (sal_Unicode)pChar->code;
+ continue;
+ }
+
+ ByteString aTranslate;
+ if( pChar->code & 0xff000000 )
+ aTranslate += (char)(pChar->code >> 24 );
+ if( pChar->code & 0xffff0000 )
+ aTranslate += (char)((pChar->code & 0x00ff0000) >> 16 );
+ if( pChar->code & 0xffffff00 )
+ aTranslate += (char)((pChar->code & 0x0000ff00) >> 8 );
+ aTranslate += (char)(pChar->code & 0xff);
+ String aUni( aTranslate, m_aEncoding );
+ pUnicodes[i] = *aUni.GetBuffer();
+ }
+ else
+ pUnicodes[i] = 0;
+ }
+
+ // now fill in the character metrics
+ // parseAFM.cxx effectively only supports direction 0 (horizontal)
+ pChar = pInfo->cmi;
+ CharacterMetric aMetric;
+ for( i = 0; i < pInfo->numOfChars; i++, pChar++ )
+ {
+ if( pChar->code == -1 && ! pChar->name )
+ continue;
+
+ if( bFillEncodingvector && pChar->name )
+ {
+ std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
+ for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
+ {
+ if( *it != 0 )
+ {
+ m_aEncodingVector[ *it ] = pChar->code;
+ if( pChar->code == -1 )
+ m_aNonEncoded[ *it ] = pChar->name;
+ }
+ }
+ }
+
+ aMetric.width = pChar->wx ? pChar->wx : pChar->charBBox.urx;
+ aMetric.height = pChar->wy ? pChar->wy : pChar->charBBox.ury - pChar->charBBox.lly;
+ if( aMetric.width == 0 && aMetric.height == 0 )
+ // guess something for e.g. space
+ aMetric.width = m_aGlobalMetricX.width/4;
+
+ if( ( nAdobeEncoding == 0 ) ||
+ ( ( nAdobeEncoding == 3 ) && ( m_aEncoding != RTL_TEXTENCODING_SYMBOL ) ) )
+ {
+ if( pChar->code != -1 )
+ {
+ m_pMetrics->m_aMetrics[ pUnicodes[i] ] = aMetric;
+ if( bFillEncodingvector )
+ m_aEncodingVector[ pUnicodes[i] ] = pChar->code;
+ }
+ else if( pChar->name )
+ {
+ std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
+ for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
+ {
+ if( *it != 0 )
+ m_pMetrics->m_aMetrics[ *it ] = aMetric;
+ }
+ }
+ }
+ else if( nAdobeEncoding == 1 || nAdobeEncoding == 2 || nAdobeEncoding == 4)
+ {
+ if( pChar->name )
+ {
+ std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
+ for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
+ {
+ if( *it != 0 )
+ m_pMetrics->m_aMetrics[ *it ] = aMetric;
+ }
+ }
+ else if( pChar->code != -1 )
+ {
+ ::std::pair< ::std::hash_multimap< sal_uInt8, sal_Unicode >::const_iterator,
+ ::std::hash_multimap< sal_uInt8, sal_Unicode >::const_iterator >
+ aCodes = rManager.getUnicodeFromAdobeCode( pChar->code );
+ while( aCodes.first != aCodes.second )
+ {
+ if( (*aCodes.first).second != 0 )
+ {
+ m_pMetrics->m_aMetrics[ (*aCodes.first).second ] = aMetric;
+ if( bFillEncodingvector )
+ m_aEncodingVector[ (*aCodes.first).second ] = pChar->code;
+ }
+ ++aCodes.first;
+ }
+ }
+ }
+ else if( nAdobeEncoding == 3 )
+ {
+ if( pChar->code != -1 )
+ {
+ sal_Unicode code = 0xf000 + pChar->code;
+ m_pMetrics->m_aMetrics[ code ] = aMetric;
+ // maybe should try to find the name in the convtabs ?
+ if( bFillEncodingvector )
+ m_aEncodingVector[ code ] = pChar->code;
+ }
+ }
+ }
+
+ m_pMetrics->m_aXKernPairs.clear();
+ m_pMetrics->m_aYKernPairs.clear();
+
+ // now fill in the kern pairs
+ // parseAFM.cxx effectively only supports direction 0 (horizontal)
+ PairKernData* pKern = pInfo->pkd;
+ KernPair aPair;
+ for( i = 0; i < pInfo->numOfPairs; i++, pKern++ )
+ {
+ // #i37703# broken kern table
+ if( ! pKern->name1 || ! pKern->name2 )
+ continue;
+
+ aPair.first = 0;
+ aPair.second = 0;
+ // currently we have to find the adobe character names
+ // in the already parsed character metrics to find
+ // the corresponding UCS2 code which is a bit dangerous
+ // since the character names are not required
+ // in the metric descriptions
+ pChar = pInfo->cmi;
+ for( int j = 0;
+ j < pInfo->numOfChars && ( aPair.first == 0 || aPair.second == 0 );
+ j++, pChar++ )
+ {
+ if( pChar->code != -1 )
+ {
+ if( ! strcmp( pKern->name1, pChar->name ? pChar->name : "" ) )
+ aPair.first = pUnicodes[ j ];
+ if( ! strcmp( pKern->name2, pChar->name ? pChar->name : "" ) )
+ aPair.second = pUnicodes[ j ];
+ }
+ }
+ if( aPair.first && aPair.second )
+ {
+ aPair.kern_x = pKern->xamt;
+ aPair.kern_y = pKern->yamt;
+ m_pMetrics->m_aXKernPairs.push_back( aPair );
+ }
+ }
+ m_pMetrics->m_bKernPairsQueried = true;
+ }
+
+ freeFontInfo( pInfo );
+ return true;
+}
+
+// -------------------------------------------------------------------------
+
+OString PrintFontManager::s_aEmptyOString;
+
+/*
+ * one instance only
+ */
+PrintFontManager& PrintFontManager::get()
+{
+ static PrintFontManager* theManager = NULL;
+ if( ! theManager )
+ {
+ theManager = new PrintFontManager();
+ theManager->initialize();
+ }
+ return *theManager;
+}
+
+// -------------------------------------------------------------------------
+
+/*
+ * the PrintFontManager
+ */
+
+PrintFontManager::PrintFontManager() :
+ m_nNextFontID( 1 ),
+ m_pAtoms( new MultiAtomProvider() ),
+ m_nNextDirAtom( 1 ),
+ m_pFontCache( NULL ),
+ m_bFontconfigSuccess( false )
+{
+ for( unsigned int i = 0; i < sizeof( aAdobeCodes )/sizeof( aAdobeCodes[0] ); i++ )
+ {
+ m_aUnicodeToAdobename.insert( ::std::hash_multimap< sal_Unicode, ::rtl::OString >::value_type( aAdobeCodes[i].aUnicode, aAdobeCodes[i].pAdobename ) );
+ m_aAdobenameToUnicode.insert( ::std::hash_multimap< ::rtl::OString, sal_Unicode, ::rtl::OStringHash >::value_type( aAdobeCodes[i].pAdobename, aAdobeCodes[i].aUnicode ) );
+ if( aAdobeCodes[i].aAdobeStandardCode )
+ {
+ m_aUnicodeToAdobecode.insert( ::std::hash_multimap< sal_Unicode, sal_uInt8 >::value_type( aAdobeCodes[i].aUnicode, aAdobeCodes[i].aAdobeStandardCode ) );
+ m_aAdobecodeToUnicode.insert( ::std::hash_multimap< sal_uInt8, sal_Unicode >::value_type( aAdobeCodes[i].aAdobeStandardCode, aAdobeCodes[i].aUnicode ) );
+ }
+#if 0
+ m_aUnicodeToAdobename[ aAdobeCodes[i].aUnicode ] = aAdobeCodes[i].pAdobename;
+ m_aAdobenameToUnicode[ aAdobeCodes[i].pAdobename ] = aAdobeCodes[i].aUnicode;
+ if( aAdobeCodes[i].aAdobeStandardCode )
+ {
+ m_aUnicodeToAdobecode[ aAdobeCodes[i].aUnicode ] = aAdobeCodes[i].aAdobeStandardCode;
+ m_aAdobecodeToUnicode[ aAdobeCodes[i].aAdobeStandardCode ] = aAdobeCodes[i].aUnicode;
+ }
+#endif
+ }
+}
+
+// -------------------------------------------------------------------------
+
+PrintFontManager::~PrintFontManager()
+{
+ deinitFontconfig();
+ for( ::std::hash_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
+ delete (*it).second;
+ delete m_pAtoms;
+ if( m_pFontCache )
+ delete m_pFontCache;
+}
+
+// -------------------------------------------------------------------------
+
+const OString& PrintFontManager::getDirectory( int nAtom ) const
+{
+ ::std::hash_map< int, OString >::const_iterator it( m_aAtomToDir.find( nAtom ) );
+ return it != m_aAtomToDir.end() ? it->second : s_aEmptyOString;
+}
+
+// -------------------------------------------------------------------------
+
+int PrintFontManager::getDirectoryAtom( const OString& rDirectory, bool bCreate )
+{
+ int nAtom = 0;
+ ::std::hash_map< OString, int, OStringHash >::const_iterator it
+ ( m_aDirToAtom.find( rDirectory ) );
+ if( it != m_aDirToAtom.end() )
+ nAtom = it->second;
+ else if( bCreate )
+ {
+ nAtom = m_nNextDirAtom++;
+ m_aDirToAtom[ rDirectory ] = nAtom;
+ m_aAtomToDir[ nAtom ] = rDirectory;
+ }
+ return nAtom;
+}
+
+// -------------------------------------------------------------------------
+
+int PrintFontManager::addFontFile( const ::rtl::OString& rFileName, int /*nFaceNum*/ )
+{
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ INetURLObject aPath( OStringToOUString( rFileName, aEncoding ), INET_PROT_FILE, INetURLObject::ENCODE_ALL );
+ OString aName( OUStringToOString( aPath.GetName(), aEncoding ) );
+ OString aDir( OUStringToOString( aPath.GetPath(), aEncoding ) );
+
+ int nDirID = getDirectoryAtom( aDir, true );
+ fontID nFontId = findFontFileID( nDirID, aName );
+ if( !nFontId )
+ {
+ ::std::list< PrintFont* > aNewFonts;
+ if( analyzeFontFile( nDirID, aName, ::std::list<OString>(), aNewFonts ) )
+ {
+ for( ::std::list< PrintFont* >::iterator it = aNewFonts.begin();
+ it != aNewFonts.end(); ++it )
+ {
+ m_aFonts[ nFontId = m_nNextFontID++ ] = *it;
+ m_aFontFileToFontID[ aName ].insert( nFontId );
+ m_pFontCache->updateFontCacheEntry( *it, true );
+ }
+ }
+ }
+ return nFontId;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::analyzeFontFile( int nDirID, const OString& rFontFile, const ::std::list<OString>& rXLFDs, ::std::list< PrintFontManager::PrintFont* >& rNewFonts ) const
+{
+ rNewFonts.clear();
+
+ OString aDir( getDirectory( nDirID ) );
+
+ OString aFullPath( aDir );
+ aFullPath += "/";
+ aFullPath += rFontFile;
+
+ // #i1872# reject unreadable files
+ if( access( aFullPath.getStr(), R_OK ) )
+ return false;
+
+ ByteString aExt( rFontFile.copy( rFontFile.lastIndexOf( '.' )+1 ) );
+ if( aExt.EqualsIgnoreCaseAscii( "pfb" ) || aExt.EqualsIgnoreCaseAscii( "pfa" ) )
+ {
+ // check for corresponding afm metric
+ // first look for an adjacent file
+ static const char* pSuffix[] = { ".afm", ".AFM" };
+
+ for( unsigned int i = 0; i < sizeof(pSuffix)/sizeof(pSuffix[0]); i++ )
+ {
+ ByteString aName( rFontFile );
+ aName.Erase( aName.Len()-4 );
+ aName.Append( pSuffix[i] );
+
+ ByteString aFilePath( aDir );
+ aFilePath.Append( '/' );
+ aFilePath.Append( aName );
+
+ ByteString aAfmFile;
+ if( access( aFilePath.GetBuffer(), R_OK ) )
+ {
+ // try in subdirectory afm instead
+ aFilePath = aDir;
+ aFilePath.Append( "/afm/" );
+ aFilePath.Append( aName );
+
+ if( ! access( aFilePath.GetBuffer(), R_OK ) )
+ {
+ aAfmFile = "afm/";
+ aAfmFile += aName;
+ }
+ }
+ else
+ aAfmFile = aName;
+
+ if( aAfmFile.Len() )
+ {
+ Type1FontFile* pFont = new Type1FontFile();
+ pFont->m_nDirectory = nDirID;
+
+ pFont->m_aFontFile = rFontFile;
+ pFont->m_aMetricFile = aAfmFile;
+
+ if( ! pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true ) )
+ {
+ delete pFont;
+ pFont = NULL;
+ }
+ if( pFont && rXLFDs.size() )
+ getFontAttributesFromXLFD( pFont, rXLFDs );
+ if( pFont )
+ rNewFonts.push_back( pFont );
+ break;
+ }
+ }
+ }
+ else if( aExt.EqualsIgnoreCaseAscii( "afm" ) )
+ {
+ ByteString aFilePath( aDir );
+ aFilePath.Append( '/' );
+ aFilePath.Append( ByteString( rFontFile ) );
+ BuiltinFont* pFont = new BuiltinFont();
+ pFont->m_nDirectory = nDirID;
+ pFont->m_aMetricFile = rFontFile;
+ if( pFont->readAfmMetrics( aFilePath, m_pAtoms, false, true ) )
+ rNewFonts.push_back( pFont );
+ else
+ delete pFont;
+ }
+ else if( aExt.EqualsIgnoreCaseAscii( "ttf" )
+ || aExt.EqualsIgnoreCaseAscii( "tte" ) // #i33947# for Gaiji support
+ || aExt.EqualsIgnoreCaseAscii( "otf" ) ) // check for TTF- and PS-OpenType too
+ {
+ TrueTypeFontFile* pFont = new TrueTypeFontFile();
+ pFont->m_nDirectory = nDirID;
+ pFont->m_aFontFile = rFontFile;
+ pFont->m_nCollectionEntry = -1;
+
+ if( rXLFDs.size() )
+ getFontAttributesFromXLFD( pFont, rXLFDs );
+ // need to read the font anyway to get aliases inside the font file
+ if( ! analyzeTrueTypeFile( pFont ) )
+ {
+ delete pFont;
+ pFont = NULL;
+ }
+ else
+ rNewFonts.push_back( pFont );
+ }
+ else if( aExt.EqualsIgnoreCaseAscii( "ttc" ) )
+ {
+ // get number of ttc entries
+ int nLength = CountTTCFonts( aFullPath.getStr() );
+ if( nLength )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%s contains %d fonts\n", aFullPath.getStr(), nLength );
+#endif
+ for( int i = 0; i < nLength; i++ )
+ {
+ TrueTypeFontFile* pFont = new TrueTypeFontFile();
+ pFont->m_nDirectory = nDirID;
+ pFont->m_aFontFile = rFontFile;
+ pFont->m_nCollectionEntry = i;
+ if( nLength == 1 )
+ getFontAttributesFromXLFD( pFont, rXLFDs );
+ if( ! analyzeTrueTypeFile( pFont ) )
+ {
+ delete pFont;
+ pFont = NULL;
+ }
+ else
+ rNewFonts.push_back( pFont );
+ }
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "CountTTCFonts( \"%s/%s\" ) failed\n", getDirectory(nDirID).getStr(), rFontFile.getStr() );
+#endif
+ }
+ return ! rNewFonts.empty();
+}
+
+// -------------------------------------------------------------------------
+
+fontID PrintFontManager::findFontBuiltinID( int nPSNameAtom ) const
+{
+ fontID nID = 0;
+ ::std::hash_map< fontID, PrintFont* >::const_iterator it;
+ for( it = m_aFonts.begin(); nID == 0 && it != m_aFonts.end(); ++it )
+ {
+ if( it->second->m_eType == fonttype::Builtin &&
+ it->second->m_nPSName == nPSNameAtom )
+ nID = it->first;
+ }
+ return nID;
+}
+
+// -------------------------------------------------------------------------
+
+fontID PrintFontManager::findFontFileID( int nDirID, const OString& rFontFile ) const
+{
+ fontID nID = 0;
+
+ ::std::hash_map< OString, ::std::set< fontID >, OStringHash >::const_iterator set_it = m_aFontFileToFontID.find( rFontFile );
+ if( set_it != m_aFontFileToFontID.end() )
+ {
+ for( ::std::set< fontID >::const_iterator font_it = set_it->second.begin(); font_it != set_it->second.end() && ! nID; ++font_it )
+ {
+ ::std::hash_map< fontID, PrintFont* >::const_iterator it = m_aFonts.find( *font_it );
+ if( it != m_aFonts.end() )
+ {
+ switch( it->second->m_eType )
+ {
+ case fonttype::Type1:
+ {
+ Type1FontFile* const pFont = static_cast< Type1FontFile* const >((*it).second);
+ if( pFont->m_nDirectory == nDirID &&
+ pFont->m_aFontFile == rFontFile )
+ nID = it->first;
+ }
+ break;
+ case fonttype::TrueType:
+ {
+ TrueTypeFontFile* const pFont = static_cast< TrueTypeFontFile* const >((*it).second);
+ if( pFont->m_nDirectory == nDirID &&
+ pFont->m_aFontFile == rFontFile )
+ nID = it->first;
+ }
+ break;
+ case fonttype::Builtin:
+ if( static_cast<const BuiltinFont*>((*it).second)->m_nDirectory == nDirID &&
+ static_cast<const BuiltinFont*>((*it).second)->m_aMetricFile == rFontFile )
+ nID = it->first;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ return nID;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::parseXLFD( const OString& rXLFD, XLFDEntry& rEntry )
+{
+ sal_Int32 nIndex = 0;
+ OString aFoundry = WhitespaceToSpace( rXLFD.getToken( 1, '-', nIndex ) );
+ if( nIndex < 0 ) return false;
+ OString aFamilyXLFD = WhitespaceToSpace( rXLFD.getToken( 0, '-', nIndex ) );
+ if( nIndex < 0 ) return false;
+ OString aWeight = rXLFD.getToken( 0, '-', nIndex ).toAsciiLowerCase();
+ if( nIndex < 0 ) return false;
+ OString aSlant = rXLFD.getToken( 0, '-', nIndex ).toAsciiLowerCase();
+ if( nIndex < 0 ) return false;
+ OString aWidth = rXLFD.getToken( 0, '-', nIndex ).toAsciiLowerCase();
+ if( nIndex < 0 ) return false;
+ OString aAddStyle = rXLFD.getToken( 0, '-', nIndex ).toAsciiLowerCase();
+ if( nIndex < 0 ) return false;
+ OString aPitch = rXLFD.getToken( 4, '-', nIndex ).toAsciiLowerCase();
+ if( nIndex < 0 ) return false;
+ OString aRegEnc = WhitespaceToSpace( rXLFD.getToken( 1, '-', nIndex ).toAsciiLowerCase() );
+ if( nIndex < 0 ) return false;
+ OString aEnc = WhitespaceToSpace( rXLFD.getToken( 0, '-', nIndex ).toAsciiLowerCase() );
+
+ // capitalize words
+ sal_Int32 nFamIndex = 0;
+ OStringBuffer aFamilyName;
+ while( nFamIndex >= 0 )
+ {
+ OString aToken = aFamilyXLFD.getToken( 0, ' ', nFamIndex );
+ sal_Char aFirst = aToken.toChar();
+ if( aFirst >= 'a' && aFirst <= 'z' )
+ aFirst = aFirst - 'a' + 'A';
+ OStringBuffer aNewToken( aToken.getLength() );
+ aNewToken.append( aToken );
+ aNewToken.setCharAt( 0, aFirst );
+ if( aFamilyName.getLength() > 0 )
+ aFamilyName.append( ' ' );
+ aFamilyName.append( aNewToken.makeStringAndClear() );
+ }
+
+ rEntry.aFoundry = aFoundry;
+ rEntry.aFamily = aFamilyName.makeStringAndClear();
+ rEntry.aAddStyle = aAddStyle;
+ // evaluate weight
+ rEntry.eWeight = parseWeight( aWeight );
+ // evaluate slant
+ rEntry.eItalic = parseItalic( aSlant );
+ // evaluate width
+ rEntry.eWidth = parseWidth( aWidth );
+
+ // evaluate pitch
+ if( aPitch.toChar() == 'c' || aPitch.toChar() == 'm' )
+ rEntry.ePitch = pitch::Fixed;
+ else
+ rEntry.ePitch = pitch::Variable;
+
+ OString aToken = aEnc.toAsciiLowerCase();
+ // get encoding
+ if( aAddStyle.indexOf( "symbol" ) != -1 )
+ rEntry.aEncoding = RTL_TEXTENCODING_SYMBOL;
+ else
+ {
+ if( aToken.equals( "symbol" ) )
+ rEntry.aEncoding = RTL_TEXTENCODING_SYMBOL;
+ else
+ {
+ OStringBuffer aCharset( aRegEnc.getLength() + aEnc.getLength() + 1 );
+ aCharset.append( aRegEnc );
+ aCharset.append( '-' );
+ aCharset.append( aEnc );
+ rEntry.aEncoding = rtl_getTextEncodingFromUnixCharset( aCharset.getStr() );
+ }
+ }
+
+ // set correct mask flags
+ rEntry.nMask = 0;
+ if( rEntry.aFoundry != "*" ) rEntry.nMask |= XLFDEntry::MaskFoundry;
+ if( rEntry.aFamily != "*" ) rEntry.nMask |= XLFDEntry::MaskFamily;
+ if( rEntry.aAddStyle != "*" ) rEntry.nMask |= XLFDEntry::MaskAddStyle;
+ if( aWeight != "*" ) rEntry.nMask |= XLFDEntry::MaskWeight;
+ if( aSlant != "*" ) rEntry.nMask |= XLFDEntry::MaskItalic;
+ if( aWidth != "*" ) rEntry.nMask |= XLFDEntry::MaskWidth;
+ if( aPitch != "*" ) rEntry.nMask |= XLFDEntry::MaskPitch;
+ if( aRegEnc != "*" && aEnc != "*" ) rEntry.nMask |= XLFDEntry::MaskEncoding;
+
+ return true;
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::parseXLFD_appendAliases( const std::list< OString >& rXLFDs, std::list< XLFDEntry >& rEntries ) const
+{
+ for( std::list< OString >::const_iterator it = rXLFDs.begin(); it != rXLFDs.end(); ++it )
+ {
+ XLFDEntry aEntry;
+ if( ! parseXLFD(*it, aEntry) )
+ continue;
+ rEntries.push_back( aEntry );
+ std::map< XLFDEntry, std::list< XLFDEntry > >::const_iterator alias_it =
+ m_aXLFD_Aliases.find( aEntry );
+ if( alias_it != m_aXLFD_Aliases.end() )
+ {
+ rEntries.insert( rEntries.end(), alias_it->second.begin(), alias_it->second.end() );
+ }
+ }
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::getFontAttributesFromXLFD( PrintFont* pFont, const std::list< OString >& rXLFDs ) const
+{
+ bool bFamilyName = false;
+
+ std::list< XLFDEntry > aXLFDs;
+
+ parseXLFD_appendAliases( rXLFDs, aXLFDs );
+
+ for( std::list< XLFDEntry >::const_iterator it = aXLFDs.begin();
+ it != aXLFDs.end(); ++it )
+ {
+ // set family name or alias
+ int nFam =
+ m_pAtoms->getAtom( ATOM_FAMILYNAME,
+ OStringToOUString( it->aFamily, it->aAddStyle.indexOf( "utf8" ) != -1 ? RTL_TEXTENCODING_UTF8 : RTL_TEXTENCODING_ISO_8859_1 ),
+ sal_True );
+ if( ! bFamilyName )
+ {
+ bFamilyName = true;
+ pFont->m_nFamilyName = nFam;
+ switch( pFont->m_eType )
+ {
+ case fonttype::Type1:
+ static_cast<Type1FontFile*>(pFont)->m_aXLFD = rXLFDs.front();
+ break;
+ case fonttype::TrueType:
+ static_cast<TrueTypeFontFile*>(pFont)->m_aXLFD = rXLFDs.front();
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ // make sure that aliases are unique
+ if( nFam != pFont->m_nFamilyName )
+ {
+ std::list< int >::const_iterator al_it;
+ for( al_it = pFont->m_aAliases.begin(); al_it != pFont->m_aAliases.end() && *al_it != nFam; ++al_it )
+ ;
+ if( al_it == pFont->m_aAliases.end() )
+ pFont->m_aAliases.push_back( nFam );
+
+ }
+ // for the rest of the attributes there can only be one value;
+ // we'll trust the first one
+ continue;
+ }
+
+ // fill in weight
+ pFont->m_eWeight = it->eWeight;
+ // fill in slant
+ pFont->m_eItalic = it->eItalic;
+ // fill in width
+ pFont->m_eWidth = it->eWidth;
+ // fill in pitch
+ pFont->m_ePitch = it->ePitch;
+ // fill in encoding
+ pFont->m_aEncoding = it->aEncoding;
+ }
+
+ // handle iso8859-1 as ms1252 to fill the "gap" starting at 0x80
+ if( pFont->m_aEncoding == RTL_TEXTENCODING_ISO_8859_1 )
+ pFont->m_aEncoding = RTL_TEXTENCODING_MS_1252;
+ if( rXLFDs.begin() != rXLFDs.end() )
+ {
+ switch( pFont->m_eType )
+ {
+ case fonttype::Type1:
+ static_cast<Type1FontFile*>(pFont)->m_aXLFD = rXLFDs.front();
+ break;
+ case fonttype::TrueType:
+ static_cast<TrueTypeFontFile*>(pFont)->m_aXLFD = rXLFDs.front();
+ break;
+ default: break;
+ }
+ }
+}
+
+// -------------------------------------------------------------------------
+
+OString PrintFontManager::getXLFD( PrintFont* pFont ) const
+{
+ if( pFont->m_eType == fonttype::Type1 )
+ {
+ if( static_cast<Type1FontFile*>(pFont)->m_aXLFD.getLength() )
+ return static_cast<Type1FontFile*>(pFont)->m_aXLFD;
+ }
+ if( pFont->m_eType == fonttype::TrueType )
+ {
+ if( static_cast<TrueTypeFontFile*>(pFont)->m_aXLFD.getLength() )
+ return static_cast<TrueTypeFontFile*>(pFont)->m_aXLFD;
+ }
+
+ OStringBuffer aXLFD( 128 );
+
+ aXLFD.append( "-misc-" );
+ ByteString aFamily( String( m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName ) ), RTL_TEXTENCODING_UTF8 );
+ aFamily.SearchAndReplaceAll( '-',' ' );
+ aFamily.SearchAndReplaceAll( '?',' ' );
+ aFamily.SearchAndReplaceAll( '*',' ' );
+ aXLFD.append( OString( aFamily ) );
+ aXLFD.append( '-' );
+ switch( pFont->m_eWeight )
+ {
+ case weight::Thin: aXLFD.append("thin");break;
+ case weight::UltraLight: aXLFD.append("ultralight");break;
+ case weight::Light: aXLFD.append("light");break;
+ case weight::SemiLight: aXLFD.append("semilight");break;
+ case weight::Normal: aXLFD.append("normal");break;
+ case weight::Medium: aXLFD.append("medium");break;
+ case weight::SemiBold: aXLFD.append("semibold");break;
+ case weight::Bold: aXLFD.append("bold");break;
+ case weight::UltraBold: aXLFD.append("ultrabold");break;
+ case weight::Black: aXLFD.append("black");break;
+ default: break;
+ }
+ aXLFD.append('-');
+ switch( pFont->m_eItalic )
+ {
+ case italic::Upright: aXLFD.append('r');break;
+ case italic::Oblique: aXLFD.append('o');break;
+ case italic::Italic: aXLFD.append('i');break;
+ default: break;
+ }
+ aXLFD.append('-');
+ switch( pFont->m_eWidth )
+ {
+ case width::UltraCondensed: aXLFD.append("ultracondensed");break;
+ case width::ExtraCondensed: aXLFD.append("extracondensed");break;
+ case width::Condensed: aXLFD.append("condensed");break;
+ case width::SemiCondensed: aXLFD.append("semicondensed");break;
+ case width::Normal: aXLFD.append("normal");break;
+ case width::SemiExpanded: aXLFD.append("semiexpanded");break;
+ case width::Expanded: aXLFD.append("expanded");break;
+ case width::ExtraExpanded: aXLFD.append("extraexpanded");break;
+ case width::UltraExpanded: aXLFD.append("ultraexpanded");break;
+ default: break;
+ }
+ aXLFD.append("-utf8-0-0-0-0-");
+ aXLFD.append( pFont->m_ePitch == pitch::Fixed ? "m" : "p" );
+ aXLFD.append("-0-");
+ const char* pEnc = rtl_getBestUnixCharsetFromTextEncoding( pFont->m_aEncoding );
+ if( ! pEnc )
+ {
+ if( pFont->m_aEncoding == RTL_TEXTENCODING_ADOBE_STANDARD )
+ pEnc = "adobe-standard";
+ else
+ pEnc = "iso8859-1";
+ }
+ aXLFD .append( pEnc );
+
+ return aXLFD.makeStringAndClear();
+}
+
+// -------------------------------------------------------------------------
+
+OUString PrintFontManager::convertTrueTypeName( void* pRecord ) const
+{
+ NameRecord* pNameRecord = (NameRecord*)pRecord;
+ OUString aValue;
+ if(
+ ( pNameRecord->platformID == 3 && ( pNameRecord->encodingID == 0 || pNameRecord->encodingID == 1 ) ) // MS, Unicode
+ ||
+ ( pNameRecord->platformID == 0 ) // Apple, Unicode
+ )
+ {
+ OUStringBuffer aName( pNameRecord->slen/2 );
+ const sal_uInt8* pNameBuffer = pNameRecord->sptr;
+ for(int n = 0; n < pNameRecord->slen/2; n++ )
+ aName.append( (sal_Unicode)getUInt16BE( pNameBuffer ) );
+ aValue = aName.makeStringAndClear();
+ }
+ else if( pNameRecord->platformID == 3 )
+ {
+ if( pNameRecord->encodingID >= 2 && pNameRecord->encodingID <= 6 )
+ {
+ /*
+ * and now for a special kind of madness:
+ * some fonts encode their byte value string as BE uint16
+ * (leading to stray zero bytes in the string)
+ * while others code two bytes as a uint16 and swap to BE
+ */
+ OStringBuffer aName;
+ const sal_uInt8* pNameBuffer = pNameRecord->sptr;
+ for(int n = 0; n < pNameRecord->slen/2; n++ )
+ {
+ sal_Unicode aCode = (sal_Unicode)getUInt16BE( pNameBuffer );
+ sal_Char aChar = aCode >> 8;
+ if( aChar )
+ aName.append( aChar );
+ aChar = aCode & 0x00ff;
+ if( aChar )
+ aName.append( aChar );
+ }
+ switch( pNameRecord->encodingID )
+ {
+ case 2:
+ aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_932 );
+ break;
+ case 3:
+ aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_936 );
+ break;
+ case 4:
+ aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_950 );
+ break;
+ case 5:
+ aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_949 );
+ break;
+ case 6:
+ aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_1361 );
+ break;
+ }
+ }
+ }
+ return aValue;
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::analyzeTrueTypeFamilyName( void* pTTFont, ::std::list< OUString >& rNames ) const
+{
+ OUString aFamily;
+
+ rNames.clear();
+ ::std::set< OUString > aSet;
+
+ NameRecord* pNameRecords = NULL;
+ int nNameRecords = GetTTNameRecords( (TrueTypeFont*)pTTFont, &pNameRecords );
+ if( nNameRecords && pNameRecords )
+ {
+ LanguageType aLang = MsLangId::getSystemLanguage();
+ int nLastMatch = -1;
+ for( int i = 0; i < nNameRecords; i++ )
+ {
+ if( pNameRecords[i].nameID != 1 || pNameRecords[i].sptr == NULL )
+ continue;
+ int nMatch = -1;
+ if( pNameRecords[i].platformID == 0 ) // Unicode
+ nMatch = 4000;
+ else if( pNameRecords[i].platformID == 3 )
+ {
+ // this bases on the LanguageType actually being a Win LCID
+ if( pNameRecords[i].languageID == aLang )
+ nMatch = 8000;
+ else if( pNameRecords[i].languageID == LANGUAGE_ENGLISH_US )
+ nMatch = 2000;
+ else if( pNameRecords[i].languageID == LANGUAGE_ENGLISH ||
+ pNameRecords[i].languageID == LANGUAGE_ENGLISH_UK )
+ nMatch = 1500;
+ else
+ nMatch = 1000;
+ }
+ OUString aName = convertTrueTypeName( pNameRecords + i );
+ aSet.insert( aName );
+ if( nMatch > nLastMatch )
+ {
+ nLastMatch = nMatch;
+ aFamily = aName;
+ }
+ }
+ DisposeNameRecords( pNameRecords, nNameRecords );
+ }
+ if( aFamily.getLength() )
+ {
+ rNames.push_front( aFamily );
+ for( ::std::set< OUString >::const_iterator it = aSet.begin(); it != aSet.end(); ++it )
+ if( *it != aFamily )
+ rNames.push_back( *it );
+ }
+ return;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::analyzeTrueTypeFile( PrintFont* pFont ) const
+{
+ bool bSuccess = false;
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ ByteString aFile = getFontFile( pFont );
+ TrueTypeFont* pTTFont = NULL;
+
+ TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
+ if( OpenTTFontFile( aFile.GetBuffer(), pTTFontFile->m_nCollectionEntry < 0 ? 0 : pTTFontFile->m_nCollectionEntry, &pTTFont ) == SF_OK )
+ {
+ TTGlobalFontInfo aInfo;
+ GetTTGlobalFontInfo( pTTFont, & aInfo );
+
+ ::std::list< OUString > aNames;
+ analyzeTrueTypeFamilyName( pTTFont, aNames );
+
+ // set family name from XLFD if possible
+ if( ! pFont->m_nFamilyName )
+ {
+ if( aNames.begin() != aNames.end() )
+ {
+ pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, aNames.front(), sal_True );
+ aNames.pop_front();
+ }
+ else
+ {
+ sal_Int32 dotIndex;
+
+ // poor font does not have a family name
+ // name it to file name minus the extension
+ dotIndex = pTTFontFile->m_aFontFile.lastIndexOf( '.' );
+ if ( dotIndex == -1 )
+ dotIndex = pTTFontFile->m_aFontFile.getLength();
+
+ pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, OStringToOUString( pTTFontFile->m_aFontFile.copy( 0, dotIndex ), aEncoding ), sal_True );
+ }
+ }
+ for( ::std::list< OUString >::iterator it = aNames.begin(); it != aNames.end(); ++it )
+ {
+ if( it->getLength() )
+ {
+ int nAlias = m_pAtoms->getAtom( ATOM_FAMILYNAME, *it, sal_True );
+ if( nAlias != pFont->m_nFamilyName )
+ {
+ std::list< int >::const_iterator al_it;
+ for( al_it = pFont->m_aAliases.begin(); al_it != pFont->m_aAliases.end() && *al_it != nAlias; ++al_it )
+ ;
+ if( al_it == pFont->m_aAliases.end() )
+ pFont->m_aAliases.push_back( nAlias );
+ }
+ }
+ }
+
+ if( aInfo.usubfamily )
+ pFont->m_aStyleName = OUString( aInfo.usubfamily );
+
+ pFont->m_nPSName = m_pAtoms->getAtom( ATOM_PSNAME, String( ByteString( aInfo.psname ), aEncoding ), sal_True );
+ switch( aInfo.weight )
+ {
+ case FW_THIN: pFont->m_eWeight = weight::Thin; break;
+ case FW_EXTRALIGHT: pFont->m_eWeight = weight::UltraLight; break;
+ case FW_LIGHT: pFont->m_eWeight = weight::Light; break;
+ case FW_MEDIUM: pFont->m_eWeight = weight::Medium; break;
+ case FW_SEMIBOLD: pFont->m_eWeight = weight::SemiBold; break;
+ case FW_BOLD: pFont->m_eWeight = weight::Bold; break;
+ case FW_EXTRABOLD: pFont->m_eWeight = weight::UltraBold; break;
+ case FW_BLACK: pFont->m_eWeight = weight::Black; break;
+
+ case FW_NORMAL:
+ default: pFont->m_eWeight = weight::Normal; break;
+ }
+
+ switch( aInfo.width )
+ {
+ case FWIDTH_ULTRA_CONDENSED: pFont->m_eWidth = width::UltraCondensed; break;
+ case FWIDTH_EXTRA_CONDENSED: pFont->m_eWidth = width::ExtraCondensed; break;
+ case FWIDTH_CONDENSED: pFont->m_eWidth = width::Condensed; break;
+ case FWIDTH_SEMI_CONDENSED: pFont->m_eWidth = width::SemiCondensed; break;
+ case FWIDTH_SEMI_EXPANDED: pFont->m_eWidth = width::SemiExpanded; break;
+ case FWIDTH_EXPANDED: pFont->m_eWidth = width::Expanded; break;
+ case FWIDTH_EXTRA_EXPANDED: pFont->m_eWidth = width::ExtraExpanded; break;
+ case FWIDTH_ULTRA_EXPANDED: pFont->m_eWidth = width::UltraExpanded; break;
+
+ case FWIDTH_NORMAL:
+ default: pFont->m_eWidth = width::Normal; break;
+ }
+
+ pFont->m_ePitch = aInfo.pitch ? pitch::Fixed : pitch::Variable;
+ pFont->m_eItalic = aInfo.italicAngle == 0 ? italic::Upright : ( aInfo.italicAngle < 0 ? italic::Italic : italic::Oblique );
+ // #104264# there are fonts that set italic angle 0 although they are
+ // italic; use macstyle bit here
+ if( aInfo.italicAngle == 0 && (aInfo.macStyle & 2) )
+ pFont->m_eItalic = italic::Italic;
+
+ pFont->m_aEncoding = aInfo.symbolEncoded ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UCS2;
+
+ pFont->m_aGlobalMetricY.width = pFont->m_aGlobalMetricX.width = aInfo.xMax - aInfo.xMin;
+ pFont->m_aGlobalMetricY.height = pFont->m_aGlobalMetricX.height = aInfo.yMax - aInfo.yMin;
+
+ if( aInfo.winAscent && aInfo.winDescent )
+ {
+ pFont->m_nAscend = aInfo.winAscent;
+ pFont->m_nDescend = aInfo.winDescent;
+ pFont->m_nLeading = pFont->m_nAscend + pFont->m_nDescend - 1000;
+ }
+ else if( aInfo.typoAscender && aInfo.typoDescender )
+ {
+ pFont->m_nLeading = aInfo.typoLineGap;
+ pFont->m_nAscend = aInfo.typoAscender;
+ pFont->m_nDescend = -aInfo.typoDescender;
+ }
+ else
+ {
+ pFont->m_nLeading = aInfo.linegap;
+ pFont->m_nAscend = aInfo.ascender;
+ pFont->m_nDescend = -aInfo.descender;
+ }
+
+ // last try: font bounding box
+ if( pFont->m_nAscend == 0 )
+ pFont->m_nAscend = aInfo.yMax;
+ if( pFont->m_nDescend == 0 )
+ pFont->m_nDescend = -aInfo.yMin;
+ if( pFont->m_nLeading == 0 )
+ pFont->m_nLeading = 15 * (pFont->m_nAscend+pFont->m_nDescend) / 100;
+
+ if( pFont->m_nAscend )
+ pFont->m_aGlobalMetricX.height = pFont->m_aGlobalMetricY.height = pFont->m_nAscend + pFont->m_nDescend;
+
+ // get bounding box
+ pFont->m_nXMin = aInfo.xMin;
+ pFont->m_nYMin = aInfo.yMin;
+ pFont->m_nXMax = aInfo.xMax;
+ pFont->m_nYMax = aInfo.yMax;
+
+ // get type flags
+ pTTFontFile->m_nTypeFlags = (unsigned int)aInfo.typeFlags;
+
+ // get vertical substitutions flag
+ pFont->m_bHaveVerticalSubstitutedGlyphs = DoesVerticalSubstitution( pTTFont, 1 );
+
+ CloseTTFont( pTTFont );
+ bSuccess = true;
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "could not OpenTTFont \"%s\"\n", aFile.GetBuffer() );
+#endif
+
+ return bSuccess;
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::initFontsAlias()
+{
+ m_aXLFD_Aliases.clear();
+ rtl_TextEncoding aEnc = osl_getThreadTextEncoding();
+ for( std::list< OString >::const_iterator dir_it = m_aFontDirectories.begin();
+ dir_it != m_aFontDirectories.end(); ++dir_it )
+ {
+ OStringBuffer aDirName(512);
+ aDirName.append( *dir_it );
+ aDirName.append( "/fonts.alias" );
+ SvFileStream aStream( OStringToOUString( aDirName.makeStringAndClear(), aEnc ), STREAM_READ );
+ if( ! aStream.IsOpen() )
+ continue;
+
+ do
+ {
+ ByteString aLine;
+ aStream.ReadLine( aLine );
+
+ // get the alias and the pattern it gets translated to
+ ByteString aAlias = GetCommandLineToken( 0, aLine );
+ ByteString aMap = GetCommandLineToken( 1, aLine );
+
+ // remove eventual quotes
+ aAlias.EraseLeadingChars( '"' );
+ aAlias.EraseTrailingChars( '"' );
+ aMap.EraseLeadingChars( '"' );
+ aMap.EraseTrailingChars( '"' );
+
+ XLFDEntry aAliasEntry, aMapEntry;
+ parseXLFD( aAlias, aAliasEntry );
+ parseXLFD( aMap, aMapEntry );
+
+ if( aAliasEntry.nMask && aMapEntry.nMask )
+ m_aXLFD_Aliases[ aMapEntry ].push_back( aAliasEntry );
+ } while( ! aStream.IsEof() );
+ }
+}
+
+// code stolen from vcl's RegisterFontSubstitutors()
+// TODO: use that method once psprint gets merged into vcl
+static bool AreFCSubstitutionsEnabled()
+{
+ // init font substitution defaults
+ int nDisableBits = 0;
+#ifdef SOLARIS
+ // TODO: check the OS version and fc-data maintenance level
+ nDisableBits = 1; // disable "font fallback" here on default
+#endif
+ // apply the environment variable if any
+ const char* pEnvStr = ::getenv( "SAL_DISABLE_FC_SUBST" );
+ if( pEnvStr )
+ {
+ //
+ if( (*pEnvStr >= '0') && (*pEnvStr <= '9') )
+ nDisableBits = (*pEnvStr - '0');
+ else
+ nDisableBits = ~0U; // no specific bits set: disable all
+ }
+
+ return ((nDisableBits & 3) == 0);
+}
+
+void PrintFontManager::initialize()
+{
+ #ifdef CALLGRIND_COMPILE
+ CALLGRIND_TOGGLE_COLLECT();
+ CALLGRIND_ZERO_STATS();
+ #endif
+
+ long aDirEntBuffer[ (sizeof(struct dirent)+_PC_NAME_MAX)+1 ];
+
+ if( ! m_pFontCache )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "creating font cache ... " );
+ clock_t aStart;
+ struct tms tms;
+ aStart = times( &tms );
+#endif
+ m_pFontCache = new FontCache();
+#if OSL_DEBUG_LEVEL > 1
+ clock_t aStop = times( &tms );
+ fprintf( stderr, "done in %lf s\n", (double)(aStop - aStart)/(double)sysconf( _SC_CLK_TCK ) );
+#endif
+ }
+
+ // initialize may be called twice in the future
+ {
+ for( ::std::hash_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
+ delete (*it).second;
+ m_nNextFontID = 1;
+ m_aFonts.clear();
+ m_aFontDirectories.clear();
+ m_aPrivateFontDirectories.clear();
+ m_aOverrideFonts.clear();
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ clock_t aStart;
+ clock_t aStep1;
+ clock_t aStep2;
+ clock_t aStep3;
+ int nBuiltinFonts = 0;
+ int nCached = 0;
+
+ struct tms tms;
+
+ aStart = times( &tms );
+#endif
+
+ // first try fontconfig
+ m_bFontconfigSuccess = initFontconfig();
+
+ // part one - look for downloadable fonts
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ const ::rtl::OUString &rSalPrivatePath = psp::getFontPath();
+
+ // search for the fonts in SAL_PRIVATE_FONTPATH first; those are
+ // the fonts installed with the office
+ if( rSalPrivatePath.getLength() )
+ {
+ OString aPath = rtl::OUStringToOString( rSalPrivatePath, aEncoding );
+ const bool bAreFCSubstitutionsEnabled = AreFCSubstitutionsEnabled();
+ sal_Int32 nIndex = 0;
+ do
+ {
+ OString aToken = aPath.getToken( 0, ';', nIndex );
+ normPath( aToken );
+ // if registering an app-specific fontdir with fontconfig fails
+ // and fontconfig-based substitutions are enabled
+ // then trying to use these app-specific fonts doesn't make sense
+ if( m_bFontconfigSuccess && !addFontconfigDir( aToken ) )
+ if( bAreFCSubstitutionsEnabled )
+ continue;
+ m_aFontDirectories.push_back( aToken );
+ m_aPrivateFontDirectories.push_back( getDirectoryAtom( aToken, true ) );
+ } while( nIndex >= 0 );
+ }
+
+ // protect against duplicate paths
+ std::hash_map< OString, int, OStringHash > visited_dirs;
+
+ // now that all global and local font dirs are known to fontconfig
+ // check that there are fonts actually managed by fontconfig
+ // also don't search directories that fontconfig already did
+ if( m_bFontconfigSuccess )
+ m_bFontconfigSuccess = (countFontconfigFonts( visited_dirs ) > 0);
+
+ // don't search through many directories fontconfig already told us about
+ if( ! m_bFontconfigSuccess )
+ ImplGetSVData()->mpDefInst->FillFontPathList( m_aFontDirectories );
+
+ // fill XLFD aliases from fonts.alias files
+ initFontsAlias();
+
+ // search for font files in each path
+ std::list< OString >::iterator dir_it;
+ for( dir_it = m_aFontDirectories.begin(); dir_it != m_aFontDirectories.end(); ++dir_it )
+ {
+ OString aPath( *dir_it );
+ // see if we were here already
+ if( visited_dirs.find( aPath ) != visited_dirs.end() )
+ continue;
+ visited_dirs[ aPath ] = 1;
+
+ // there may be ":unscaled" directories (see XFree86)
+ // it should be safe to ignore them since they should not
+ // contain any of our recognizeable fonts
+
+ // ask the font cache whether it handles this directory
+ std::list< PrintFont* > aCacheFonts;
+ if( m_pFontCache->listDirectory( aPath, aCacheFonts ) )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "adding cache directory: %s\n", aPath.getStr() );
+#endif
+ for( ::std::list< PrintFont* >::iterator it = aCacheFonts.begin(); it != aCacheFonts.end(); ++it )
+ {
+ fontID aFont = m_nNextFontID++;
+ m_aFonts[ aFont ] = *it;
+ if( (*it)->m_eType == fonttype::Type1 )
+ m_aFontFileToFontID[ static_cast<Type1FontFile*>(*it)->m_aFontFile ].insert( aFont );
+ else if( (*it)->m_eType == fonttype::TrueType )
+ m_aFontFileToFontID[ static_cast<TrueTypeFontFile*>(*it)->m_aFontFile ].insert( aFont );
+ else if( (*it)->m_eType == fonttype::Builtin )
+ m_aFontFileToFontID[ static_cast<BuiltinFont*>(*it)->m_aMetricFile ].insert( aFont );
+#if OSL_DEBUG_LEVEL > 1
+ if( (*it)->m_eType == fonttype::Builtin )
+ nBuiltinFonts++;
+ nCached++;
+#if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, "adding cached font %d: \"%s\" from %s\n", aFont,
+ OUStringToOString( getFontFamily( aFont ), RTL_TEXTENCODING_MS_1252 ).getStr(),
+ getFontFileSysPath( aFont ).getStr() );
+#endif
+#endif
+ }
+ if( ! m_pFontCache->scanAdditionalFiles( aPath ) )
+ continue;
+ }
+
+ DIR* pDIR = opendir( aPath.getStr() );
+ struct dirent* pEntry = (struct dirent*)aDirEntBuffer;
+ if( pDIR )
+ {
+ // read fonts.dir if possible
+ ::std::hash_map< OString, ::std::list<OString>, OStringHash > aFontsDir;
+ int nDirID = getDirectoryAtom( aPath, true );
+ // #i38367# no fonts.dir in our own directories anymore
+ std::list< int >::const_iterator priv_dir;
+ for( priv_dir = m_aPrivateFontDirectories.begin();
+ priv_dir != m_aPrivateFontDirectories.end() && *priv_dir != nDirID;
+ ++priv_dir )
+ ;
+
+ if( priv_dir == m_aPrivateFontDirectories.end() )
+ {
+ ByteString aGccDummy( aPath );
+ String aFontsDirPath( aGccDummy, aEncoding );
+ aFontsDirPath.AppendAscii( "/fonts.dir" );
+ SvFileStream aStream( aFontsDirPath, STREAM_READ );
+ if( aStream.IsOpen() )
+ {
+ ByteString aLine;
+ while( ! aStream.IsEof() )
+ {
+ aStream.ReadLine( aLine );
+ ByteString aFileName( GetCommandLineToken( 0, aLine ) );
+ ByteString aXLFD( aLine.Copy( aFileName.Len() ) );
+ if( aFileName.Len() && aXLFD.Len() )
+ aFontsDir[ aFileName ].push_back(aXLFD);
+ }
+ }
+ }
+
+ int nDirFonts = 0;
+ while( ! readdir_r( pDIR, (struct dirent*)aDirEntBuffer, &pEntry ) && pEntry )
+ {
+ OString aFileName( pEntry->d_name );
+ // ignore .afm files here
+ if( aFileName.getLength() > 3 &&
+ aFileName.lastIndexOf( ".afm" ) == aFileName.getLength()-4 )
+ continue;
+
+ struct stat aStat;
+ ByteString aFilePath( aPath );
+ aFilePath.Append( '/' );
+ aFilePath.Append( ByteString( aFileName ) );
+ if( ! stat( aFilePath.GetBuffer(), &aStat ) &&
+ S_ISREG( aStat.st_mode ) )
+ {
+ if( findFontFileID( nDirID, aFileName ) == 0 )
+ {
+ ::std::list<OString> aXLFDs;
+ ::std::hash_map< OString, ::std::list<OString>, OStringHash >::const_iterator it =
+ aFontsDir.find( aFileName );
+ if( it != aFontsDir.end() )
+ aXLFDs = (*it).second;
+
+ // fill in font attributes from XLFD rather
+ // than reading every file
+ ::std::list< PrintFont* > aNewFonts;
+ if( analyzeFontFile( nDirID, aFileName, aXLFDs, aNewFonts ) )
+ {
+ for( ::std::list< PrintFont* >::iterator font_it = aNewFonts.begin(); font_it != aNewFonts.end(); ++font_it )
+ {
+ fontID aFont = m_nNextFontID++;
+ m_aFonts[ aFont ] = *font_it;
+ m_aFontFileToFontID[ aFileName ].insert( aFont );
+ m_pFontCache->updateFontCacheEntry( *font_it, false );
+ nDirFonts++;
+#if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, "adding font %d: \"%s\" from %s\n", aFont,
+ OUStringToOString( getFontFamily( aFont ), RTL_TEXTENCODING_MS_1252 ).getStr(),
+ getFontFileSysPath( aFont ).getStr() );
+#endif
+ }
+ }
+ }
+ }
+ }
+ closedir( pDIR );
+ m_pFontCache->updateDirTimestamp( nDirID );
+ if( ! nDirFonts )
+ m_pFontCache->markEmptyDir( nDirID );
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ aStep1 = times( &tms );
+#endif
+
+ // part two - look for metrics for builtin printer fonts
+ std::list< OUString > aMetricDirs;
+ psp::getPrinterPathList( aMetricDirs, PRINTER_METRICDIR );
+
+ std::list< OString > aEmptyFontsDir;
+ for( std::list< OUString >::const_iterator met_dir_it = aMetricDirs.begin(); met_dir_it != aMetricDirs.end(); ++met_dir_it )
+ {
+ OString aDir = OUStringToOString( *met_dir_it, aEncoding );
+
+ // ask the font cache whether it handles this directory
+ std::list< PrintFont* > aCacheFonts;
+
+ if( m_pFontCache->listDirectory( aDir, aCacheFonts ) )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "adding cache directory: %s\n", aDir.getStr() );
+#endif
+ for( ::std::list< PrintFont* >::iterator it = aCacheFonts.begin(); it != aCacheFonts.end(); ++it )
+ {
+ fontID aFont = m_nNextFontID++;
+ m_aFonts[ aFont ] = *it;
+ if( (*it)->m_eType == fonttype::Type1 )
+ m_aFontFileToFontID[ static_cast<Type1FontFile*>(*it)->m_aFontFile ].insert( aFont );
+ else if( (*it)->m_eType == fonttype::TrueType )
+ m_aFontFileToFontID[ static_cast<TrueTypeFontFile*>(*it)->m_aFontFile ].insert( aFont );
+ else if( (*it)->m_eType == fonttype::Builtin )
+ m_aFontFileToFontID[ static_cast<BuiltinFont*>(*it)->m_aMetricFile ].insert( aFont );
+#if OSL_DEBUG_LEVEL > 1
+ if( (*it)->m_eType == fonttype::Builtin )
+ nBuiltinFonts++;
+ nCached++;
+#if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, "adding cached font %d: \"%s\" from %s\n", aFont,
+ OUStringToOString( getFontFamily( aFont ), RTL_TEXTENCODING_MS_1252 ).getStr(),
+ getFontFileSysPath( aFont ).getStr() );
+#endif
+#endif
+ }
+ continue;
+ }
+
+ DIR* pDIR = opendir( aDir.getStr() );
+ if( pDIR )
+ {
+ struct dirent* pDirEntry = (struct dirent*)aDirEntBuffer;
+ int nDirID = getDirectoryAtom( aDir, true );
+ int nDirFonts = 0;
+
+ while( ! readdir_r( pDIR, (struct dirent*)aDirEntBuffer, &pDirEntry ) && pDirEntry )
+ {
+ ByteString aFile( aDir );
+ aFile += '/';
+ aFile += pDirEntry->d_name;
+ struct stat aStat;
+ if( ! stat( aFile.GetBuffer(), &aStat )
+ && S_ISREG( aStat.st_mode )
+ )
+ {
+ OString aFileName( pDirEntry->d_name, strlen( pDirEntry->d_name ) );
+ OString aExt( aFileName.copy( aFileName.lastIndexOf( '.' )+1 ) );
+ if( aExt.equalsIgnoreAsciiCase( "afm" ) )
+ {
+ ::std::list< PrintFont* > aNewFonts;
+
+ analyzeFontFile( nDirID, aFileName, aEmptyFontsDir, aNewFonts );
+ for( ::std::list< PrintFont* >::iterator it = aNewFonts.begin(); it != aNewFonts.end(); ++it )
+ {
+ if( findFontBuiltinID( (*it)->m_nPSName ) == 0 )
+ {
+ m_aFontFileToFontID[ aFileName ].insert( m_nNextFontID );
+ m_aFonts[ m_nNextFontID++ ] = *it;
+ m_pFontCache->updateFontCacheEntry( *it, false );
+#if OSL_DEBUG_LEVEL > 2
+ nBuiltinFonts++;
+#endif
+ }
+ else
+ delete *it;
+ }
+ }
+ }
+ }
+ closedir( pDIR );
+ if( ! nDirFonts )
+ m_pFontCache->markEmptyDir( nDirID );
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ aStep2 = times( &tms );
+#endif
+
+ // part three - fill in family styles
+ ::std::hash_map< fontID, PrintFont* >::iterator font_it;
+ for (font_it = m_aFonts.begin(); font_it != m_aFonts.end(); ++font_it)
+ {
+ ::std::hash_map< int, family::type >::const_iterator it =
+ m_aFamilyTypes.find( font_it->second->m_nFamilyName );
+ if (it != m_aFamilyTypes.end())
+ continue;
+ const ::rtl::OUString& rFamily =
+ m_pAtoms->getString( ATOM_FAMILYNAME, font_it->second->m_nFamilyName);
+ family::type eType = matchFamilyName( rFamily );
+ m_aFamilyTypes[ font_it->second->m_nFamilyName ] = eType;
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ aStep3 = times( &tms );
+ fprintf( stderr, "PrintFontManager::initialize: collected %d fonts (%d builtin, %d cached)\n", m_aFonts.size(), nBuiltinFonts, nCached );
+ double fTick = (double)sysconf( _SC_CLK_TCK );
+ fprintf( stderr, "Step 1 took %lf seconds\n", (double)(aStep1 - aStart)/fTick );
+ fprintf( stderr, "Step 2 took %lf seconds\n", (double)(aStep2 - aStep1)/fTick );
+ fprintf( stderr, "Step 3 took %lf seconds\n", (double)(aStep3 - aStep2)/fTick );
+#endif
+
+ m_pFontCache->flush();
+
+ #ifdef CALLGRIND_COMPILE
+ CALLGRIND_DUMP_STATS();
+ CALLGRIND_TOGGLE_COLLECT();
+ #endif
+}
+
+// -------------------------------------------------------------------------
+inline bool
+equalPitch (psp::pitch::type from, psp::pitch::type to)
+{
+ return from == to;
+}
+
+inline bool
+equalWeight (psp::weight::type from, psp::weight::type to)
+{
+ return from > to ? (from - to) <= 3 : (to - from) <= 3;
+}
+
+inline bool
+equalItalic (psp::italic::type from, psp::italic::type to)
+{
+ if ( (from == psp::italic::Italic) || (from == psp::italic::Oblique) )
+ return (to == psp::italic::Italic) || (to == psp::italic::Oblique);
+ return to == from;
+}
+inline bool
+equalEncoding (rtl_TextEncoding from, rtl_TextEncoding to)
+{
+ if ((from == RTL_TEXTENCODING_ISO_8859_1) || (from == RTL_TEXTENCODING_MS_1252))
+ return (to == RTL_TEXTENCODING_ISO_8859_1) || (to == RTL_TEXTENCODING_MS_1252);
+ return from == to;
+}
+
+namespace {
+ struct BuiltinFontIdentifier
+ {
+ OUString aFamily;
+ italic::type eItalic;
+ weight::type eWeight;
+ pitch::type ePitch;
+ rtl_TextEncoding aEncoding;
+
+ BuiltinFontIdentifier( const OUString& rFam,
+ italic::type eIt,
+ weight::type eWg,
+ pitch::type ePt,
+ rtl_TextEncoding enc ) :
+ aFamily( rFam ),
+ eItalic( eIt ),
+ eWeight( eWg ),
+ ePitch( ePt ),
+ aEncoding( enc )
+ {}
+
+ bool operator==( const BuiltinFontIdentifier& rRight ) const
+ {
+ return equalItalic( eItalic, rRight.eItalic ) &&
+ equalWeight( eWeight, rRight.eWeight ) &&
+ equalPitch( ePitch, rRight.ePitch ) &&
+ equalEncoding( aEncoding, rRight.aEncoding ) &&
+ aFamily.equalsIgnoreAsciiCase( rRight.aFamily );
+ }
+ };
+
+ struct BuiltinFontIdentifierHash
+ {
+ size_t operator()( const BuiltinFontIdentifier& rFont ) const
+ {
+ return rFont.aFamily.hashCode() ^ rFont.eItalic ^ rFont.eWeight ^ rFont.ePitch ^ rFont.aEncoding;
+ }
+ };
+}
+
+void PrintFontManager::getFontList( ::std::list< fontID >& rFontIDs, const PPDParser* pParser, bool bUseOverrideMetrics )
+{
+ rFontIDs.clear();
+ std::hash_map< fontID, PrintFont* >::const_iterator it;
+
+ /*
+ * Note: there are two easy steps making this faster:
+ * first: insert the printer builtins first, then the not builtins,
+ * if they do not match.
+ * drawback: this would change the sequence of fonts; this could have
+ * subtle, unknown consequences in vcl font matching
+ * second: instead of comparing attributes to see whether a softfont
+ * is duplicate to a builtin one could simply compare the PSName (which is
+ * supposed to be unique), which at this point is just an int.
+ * drawback: this could change which fonts are listed; especially TrueType
+ * fonts often have a rather dubious PSName, so this could change the
+ * font list not so subtle.
+ * Until getFontList for a printer becomes a performance issue (which is
+ * currently not the case), best stay with the current algorithm.
+ */
+
+ // fill sets of printer supported fonts
+ if( pParser )
+ {
+ std::set<int> aBuiltinPSNames;
+ std::hash_set< BuiltinFontIdentifier,
+ BuiltinFontIdentifierHash
+ > aBuiltinFonts;
+
+ std::map<int, fontID > aOverridePSNames;
+ if( bUseOverrideMetrics )
+ {
+ readOverrideMetrics();
+ for( std::vector<fontID>::const_iterator over = m_aOverrideFonts.begin();
+ over != m_aOverrideFonts.end(); ++over )
+ {
+ std::hash_map<fontID,PrintFont*>::const_iterator font_it = m_aFonts.find( *over );
+ DBG_ASSERT( font_it != m_aFonts.end(), "override to nonexistant font" );
+ if( font_it != m_aFonts.end() )
+ aOverridePSNames[ font_it->second->m_nPSName ] = *over;
+ }
+ }
+
+ int nFonts = pParser->getFonts();
+ for( int i = 0; i < nFonts; i++ )
+ aBuiltinPSNames.insert( m_pAtoms->getAtom( ATOM_PSNAME, pParser->getFont( i ) ) );
+ for( it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
+ {
+ PrintFont* pFont = it->second;
+ if( it->second->m_eType == fonttype::Builtin &&
+ aBuiltinPSNames.find( pFont->m_nPSName ) != aBuiltinPSNames.end() )
+ {
+ bool bInsert = true;
+ if( bUseOverrideMetrics )
+ {
+ // in override case only use the override fonts, not their counterparts
+ std::map<int,fontID>::const_iterator over = aOverridePSNames.find( pFont->m_nPSName );
+ if( over != aOverridePSNames.end() && over->second != it->first )
+ bInsert = false;
+ }
+ else
+ {
+ // do not insert override fonts in non override case
+ if( std::find( m_aOverrideFonts.begin(), m_aOverrideFonts.end(), it->first ) != m_aOverrideFonts.end() )
+ bInsert = false;
+ }
+ if( bInsert )
+ {
+ aBuiltinFonts.insert( BuiltinFontIdentifier(
+ m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName ),
+ pFont->m_eItalic,
+ pFont->m_eWeight,
+ pFont->m_ePitch,
+ pFont->m_aEncoding
+ ) );
+ }
+ }
+ }
+ for( it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
+ {
+ PrintFont* pFont = it->second;
+ if( it->second->m_eType == fonttype::Builtin )
+ {
+ if( aBuiltinPSNames.find( pFont->m_nPSName ) != aBuiltinPSNames.end() )
+ {
+ bool bInsert = true;
+ if( bUseOverrideMetrics )
+ {
+ // in override case only use the override fonts, not their counterparts
+ std::map<int,fontID>::const_iterator over = aOverridePSNames.find( pFont->m_nPSName );
+ if( over != aOverridePSNames.end() && over->second != it->first )
+ bInsert = false;
+ }
+ else
+ {
+ // do not insert override fonts in non override case
+ if( std::find( m_aOverrideFonts.begin(), m_aOverrideFonts.end(), it->first ) != m_aOverrideFonts.end() )
+ bInsert = false;
+ }
+ if( bInsert )
+ rFontIDs.push_back( it->first );
+ }
+ }
+ else if( aBuiltinFonts.find( BuiltinFontIdentifier(
+ m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName ),
+ pFont->m_eItalic,
+ pFont->m_eWeight,
+ pFont->m_ePitch,
+ pFont->m_aEncoding
+ ) ) == aBuiltinFonts.end() )
+ {
+ rFontIDs.push_back( it->first );
+ }
+ }
+ }
+ else // no specific printer
+ {
+ for( it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
+ rFontIDs.push_back( it->first );
+ }
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::fillPrintFontInfo( PrintFont* pFont, FastPrintFontInfo& rInfo ) const
+{
+ ::std::hash_map< int, family::type >::const_iterator style_it =
+ m_aFamilyTypes.find( pFont->m_nFamilyName );
+ rInfo.m_eType = pFont->m_eType;
+ rInfo.m_aFamilyName = m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName );
+ rInfo.m_aStyleName = pFont->m_aStyleName;
+ rInfo.m_eFamilyStyle = style_it != m_aFamilyTypes.end() ? style_it->second : family::Unknown;
+ rInfo.m_eItalic = pFont->m_eItalic;
+ rInfo.m_eWidth = pFont->m_eWidth;
+ rInfo.m_eWeight = pFont->m_eWeight;
+ rInfo.m_ePitch = pFont->m_ePitch;
+ rInfo.m_aEncoding = pFont->m_aEncoding;
+
+ rInfo.m_bEmbeddable = (pFont->m_eType == fonttype::Type1);
+ rInfo.m_bSubsettable = (pFont->m_eType == fonttype::TrueType); // TODO: rename to SfntType
+
+ rInfo.m_aAliases.clear();
+ for( ::std::list< int >::iterator it = pFont->m_aAliases.begin(); it != pFont->m_aAliases.end(); ++it )
+ rInfo.m_aAliases.push_back( m_pAtoms->getString( ATOM_FAMILYNAME, *it ) );
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::fillPrintFontInfo( PrintFont* pFont, PrintFontInfo& rInfo ) const
+{
+ if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 ) ||
+ ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
+ )
+ {
+ // might be a truetype font not analyzed or type1 without metrics read
+ if( pFont->m_eType == fonttype::Type1 )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, false );
+ else if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+
+ fillPrintFontInfo( pFont, static_cast< FastPrintFontInfo& >( rInfo ) );
+
+ rInfo.m_nAscend = pFont->m_nAscend;
+ rInfo.m_nDescend = pFont->m_nDescend;
+ rInfo.m_nLeading = pFont->m_nLeading;
+ rInfo.m_nWidth = pFont->m_aGlobalMetricX.width < pFont->m_aGlobalMetricY.width ? pFont->m_aGlobalMetricY.width : pFont->m_aGlobalMetricX.width;
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::getFontListWithInfo( ::std::list< PrintFontInfo >& rFonts, const PPDParser* pParser, bool bUseOverrideMetrics )
+{
+ rFonts.clear();
+ ::std::list< fontID > aFontList;
+ getFontList( aFontList, pParser, bUseOverrideMetrics );
+
+ ::std::list< fontID >::iterator it;
+ for( it = aFontList.begin(); it != aFontList.end(); ++it )
+ {
+ PrintFontInfo aInfo;
+ aInfo.m_nID = *it;
+ fillPrintFontInfo( getFont( *it ), aInfo );
+ rFonts.push_back( aInfo );
+ }
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::getFontListWithFastInfo( ::std::list< FastPrintFontInfo >& rFonts, const PPDParser* pParser, bool bUseOverrideMetrics )
+{
+ rFonts.clear();
+ ::std::list< fontID > aFontList;
+ getFontList( aFontList, pParser, bUseOverrideMetrics );
+
+ ::std::list< fontID >::iterator it;
+ for( it = aFontList.begin(); it != aFontList.end(); ++it )
+ {
+ FastPrintFontInfo aInfo;
+ aInfo.m_nID = *it;
+ fillPrintFontInfo( getFont( *it ), aInfo );
+ rFonts.push_back( aInfo );
+ }
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::getFontInfo( fontID nFontID, PrintFontInfo& rInfo ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont )
+ {
+ rInfo.m_nID = nFontID;
+ fillPrintFontInfo( pFont, rInfo );
+ }
+ return pFont ? true : false;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::getFontFastInfo( fontID nFontID, FastPrintFontInfo& rInfo ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont )
+ {
+ rInfo.m_nID = nFontID;
+ fillPrintFontInfo( pFont, rInfo );
+ }
+ return pFont ? true : false;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::getFontBoundingBox( fontID nFontID, int& xMin, int& yMin, int& xMax, int& yMax )
+{
+ bool bSuccess = false;
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont )
+ {
+ if( pFont->m_nXMin == 0 && pFont->m_nYMin == 0 && pFont->m_nXMax == 0 && pFont->m_nYMax == 0 )
+ {
+ // might be a truetype font not analyzed or type1 without metrics read
+ if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true );
+ else if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+ bSuccess = true;
+ xMin = pFont->m_nXMin;
+ yMin = pFont->m_nYMin;
+ xMax = pFont->m_nXMax;
+ yMax = pFont->m_nYMax;
+ }
+ return bSuccess;
+}
+
+// -------------------------------------------------------------------------
+
+int PrintFontManager::getFontFaceNumber( fontID nFontID ) const
+{
+ int nRet = -1;
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont && pFont->m_eType == fonttype::TrueType )
+ nRet = static_cast< TrueTypeFontFile* >(pFont)->m_nCollectionEntry;
+ return nRet;
+}
+
+// -------------------------------------------------------------------------
+
+
+family::type PrintFontManager::matchFamilyName( const ::rtl::OUString& rFamily ) const
+{
+ typedef struct {
+ const char* mpName;
+ sal_uInt16 mnLength;
+ family::type meType;
+ } family_t;
+
+#define InitializeClass( p, a ) p, sizeof(p) - 1, a
+ const family_t pFamilyMatch[] = {
+ { InitializeClass( "arial", family::Swiss ) },
+ { InitializeClass( "arioso", family::Script ) },
+ { InitializeClass( "avant garde", family::Swiss ) },
+ { InitializeClass( "avantgarde", family::Swiss ) },
+ { InitializeClass( "bembo", family::Roman ) },
+ { InitializeClass( "bookman", family::Roman ) },
+ { InitializeClass( "conga", family::Roman ) },
+ { InitializeClass( "courier", family::Modern ) },
+ { InitializeClass( "curl", family::Script ) },
+ { InitializeClass( "fixed", family::Modern ) },
+ { InitializeClass( "gill", family::Swiss ) },
+ { InitializeClass( "helmet", family::Modern ) },
+ { InitializeClass( "helvetica", family::Swiss ) },
+ { InitializeClass( "international", family::Modern ) },
+ { InitializeClass( "lucida", family::Swiss ) },
+ { InitializeClass( "new century schoolbook", family::Roman ) },
+ { InitializeClass( "palatino", family::Roman ) },
+ { InitializeClass( "roman", family::Roman ) },
+ { InitializeClass( "sans serif", family::Swiss ) },
+ { InitializeClass( "sansserif", family::Swiss ) },
+ { InitializeClass( "serf", family::Roman ) },
+ { InitializeClass( "serif", family::Roman ) },
+ { InitializeClass( "times", family::Roman ) },
+ { InitializeClass( "utopia", family::Roman ) },
+ { InitializeClass( "zapf chancery", family::Script ) },
+ { InitializeClass( "zapfchancery", family::Script ) }
+ };
+
+ rtl::OString aFamily = rtl::OUStringToOString( rFamily, RTL_TEXTENCODING_ASCII_US );
+ sal_uInt32 nLower = 0;
+ sal_uInt32 nUpper = sizeof(pFamilyMatch) / sizeof(pFamilyMatch[0]);
+
+ while( nLower < nUpper )
+ {
+ sal_uInt32 nCurrent = (nLower + nUpper) / 2;
+ const family_t* pHaystack = pFamilyMatch + nCurrent;
+ sal_Int32 nComparison =
+ rtl_str_compareIgnoreAsciiCase_WithLength
+ (
+ aFamily.getStr(), aFamily.getLength(),
+ pHaystack->mpName, pHaystack->mnLength
+ );
+
+ if( nComparison < 0 )
+ nUpper = nCurrent;
+ else
+ if( nComparison > 0 )
+ nLower = nCurrent + 1;
+ else
+ return pHaystack->meType;
+ }
+
+ return family::Unknown;
+}
+
+// -------------------------------------------------------------------------
+
+family::type PrintFontManager::getFontFamilyType( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( !pFont )
+ return family::Unknown;
+
+ ::std::hash_map< int, family::type >::const_iterator it =
+ m_aFamilyTypes.find( pFont->m_nFamilyName );
+ return (it != m_aFamilyTypes.end()) ? it->second : family::Unknown;
+}
+
+
+// -------------------------------------------------------------------------
+
+const ::rtl::OUString& PrintFontManager::getFontFamily( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ return m_pAtoms->getString( ATOM_FAMILYNAME, pFont ? pFont->m_nFamilyName : INVALID_ATOM );
+}
+
+// -------------------------------------------------------------------------
+
+OString PrintFontManager::getAfmFile( PrintFont* pFont ) const
+{
+ OString aMetricPath;
+ if( pFont )
+ {
+ switch( pFont->m_eType )
+ {
+ case fonttype::Type1:
+ {
+ Type1FontFile* pPSFont = static_cast< Type1FontFile* >(pFont);
+ aMetricPath = getDirectory( pPSFont->m_nDirectory );
+ aMetricPath += "/";
+ aMetricPath += pPSFont->m_aMetricFile;
+ }
+ break;
+ case fonttype::Builtin:
+ {
+ BuiltinFont* pBuiltinFont = static_cast< BuiltinFont* >(pFont);
+ aMetricPath = getDirectory( pBuiltinFont->m_nDirectory );
+ aMetricPath += "/";
+ aMetricPath += pBuiltinFont->m_aMetricFile;
+ }
+ break;
+ default: break;
+ }
+ }
+ return aMetricPath;
+}
+
+// -------------------------------------------------------------------------
+
+OString PrintFontManager::getFontFile( PrintFont* pFont ) const
+{
+ OString aPath;
+
+ if( pFont && pFont->m_eType == fonttype::Type1 )
+ {
+ Type1FontFile* pPSFont = static_cast< Type1FontFile* >(pFont);
+ ::std::hash_map< int, OString >::const_iterator it = m_aAtomToDir.find( pPSFont->m_nDirectory );
+ aPath = it->second;
+ aPath += "/";
+ aPath += pPSFont->m_aFontFile;
+ }
+ else if( pFont && pFont->m_eType == fonttype::TrueType )
+ {
+ TrueTypeFontFile* pTTFont = static_cast< TrueTypeFontFile* >(pFont);
+ ::std::hash_map< int, OString >::const_iterator it = m_aAtomToDir.find( pTTFont->m_nDirectory );
+ aPath = it->second;
+ aPath += "/";
+ aPath += pTTFont->m_aFontFile;
+ }
+ return aPath;
+}
+
+// -------------------------------------------------------------------------
+
+const ::rtl::OUString& PrintFontManager::getPSName( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont && pFont->m_nPSName == 0 )
+ {
+ if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+
+ return m_pAtoms->getString( ATOM_PSNAME, pFont ? pFont->m_nPSName : INVALID_ATOM );
+}
+
+// -------------------------------------------------------------------------
+
+const CharacterMetric& PrintFontManager::getGlobalFontMetric( fontID nFontID, bool bHorizontal ) const
+{
+ static CharacterMetric aMetric;
+ PrintFont* pFont = getFont( nFontID );
+ return pFont ? ( bHorizontal ? pFont->m_aGlobalMetricX : pFont->m_aGlobalMetricY ) : aMetric;
+}
+
+// -------------------------------------------------------------------------
+
+int PrintFontManager::getFontAscend( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
+ {
+ // might be a truetype font not yet analyzed
+ if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ else if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true );
+ }
+ return pFont->m_nAscend;
+}
+
+// -------------------------------------------------------------------------
+
+int PrintFontManager::getFontDescend( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
+ {
+ // might be a truetype font not yet analyzed
+ if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ else if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true );
+ }
+ return pFont->m_nDescend;
+}
+
+// -------------------------------------------------------------------------
+
+int PrintFontManager::getFontLeading( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
+ {
+ // might be a truetype font not yet analyzed
+ if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+ return pFont->m_nLeading;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::hasVerticalSubstitutions( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
+ {
+ // might be a truetype font not yet analyzed
+ if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+ return pFont->m_bHaveVerticalSubstitutedGlyphs;
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::hasVerticalSubstitutions( fontID nFontID,
+ const sal_Unicode* pCharacters, int nCharacters, bool* pHasSubst ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
+ {
+ // might be a truetype font not yet analyzed
+ if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+
+ if( ! pFont->m_bHaveVerticalSubstitutedGlyphs )
+ memset( pHasSubst, 0, sizeof(bool)*nCharacters );
+ else
+ {
+ for( int i = 0; i < nCharacters; i++ )
+ {
+ sal_Unicode code = pCharacters[i];
+ if( ! pFont->m_pMetrics ||
+ ! ( pFont->m_pMetrics->m_aPages[ code >> 11 ] & ( 1 << ( ( code >> 8 ) & 7 ) ) ) )
+ pFont->queryMetricPage( code >> 8, m_pAtoms );
+ ::std::hash_map< sal_Unicode, bool >::const_iterator it = pFont->m_pMetrics->m_bVerticalSubstitutions.find( code );
+ pHasSubst[i] = it != pFont->m_pMetrics->m_bVerticalSubstitutions.end();
+ }
+ }
+}
+
+// -------------------------------------------------------------------------
+
+OUString PrintFontManager::getFontXLFD( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ OUString aRet;
+ if( pFont )
+ {
+ ByteString aXLFD( getXLFD( pFont ) );
+ rtl_TextEncoding aEncoding = aXLFD.GetToken( 6, '-' ).Search( "utf8" ) != STRING_NOTFOUND ? RTL_TEXTENCODING_UTF8 : RTL_TEXTENCODING_ISO_8859_1;
+ aRet = OStringToOUString( aXLFD, aEncoding );
+ }
+ return aRet;
+}
+
+// -------------------------------------------------------------------------
+
+const ::std::list< KernPair >& PrintFontManager::getKernPairs( fontID nFontID, bool bVertical ) const
+{
+ static ::std::list< KernPair > aEmpty;
+
+ PrintFont* pFont = getFont( nFontID );
+ if( ! pFont )
+ return aEmpty;
+
+ if( ! pFont->m_pMetrics || ! pFont->m_pMetrics->m_bKernPairsQueried )
+ pFont->queryMetricPage( 0, m_pAtoms );
+ if( ! pFont->m_pMetrics || ! pFont->m_pMetrics->m_bKernPairsQueried )
+ return aEmpty;
+ return bVertical ? pFont->m_pMetrics->m_aYKernPairs : pFont->m_pMetrics->m_aXKernPairs;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::isFontDownloadingAllowed( fontID nFont ) const
+{
+ static const char* pEnable = getenv( "PSPRINT_ENABLE_TTF_COPYRIGHTAWARENESS" );
+ bool bRet = true;
+
+ if( pEnable && *pEnable )
+ {
+ PrintFont* pFont = getFont( nFont );
+ if( pFont && pFont->m_eType == fonttype::TrueType )
+ {
+ TrueTypeFontFile* pTTFontFile = static_cast<TrueTypeFontFile*>(pFont);
+ if( pTTFontFile->m_nTypeFlags & TYPEFLAG_INVALID )
+ {
+ TrueTypeFont* pTTFont = NULL;
+ ByteString aFile = getFontFile( pFont );
+ if( OpenTTFontFile( aFile.GetBuffer(), pTTFontFile->m_nCollectionEntry < 0 ? 0 : pTTFontFile->m_nCollectionEntry, &pTTFont ) == SF_OK )
+ {
+ // get type flags
+ TTGlobalFontInfo aInfo;
+ GetTTGlobalFontInfo( pTTFont, & aInfo );
+ pTTFontFile->m_nTypeFlags = (unsigned int)aInfo.typeFlags;
+ CloseTTFont( pTTFont );
+ }
+ }
+
+ unsigned int nCopyrightFlags = pTTFontFile->m_nTypeFlags & TYPEFLAG_COPYRIGHT_MASK;
+
+ // font embedding is allowed if either
+ // no restriction at all (bit 1 clear)
+ // printing allowed (bit 1 set, bit 2 set )
+ bRet = ! ( nCopyrightFlags & 0x02 ) || ( nCopyrightFlags & 0x04 );
+ }
+ }
+ return bRet;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::getMetrics( fontID nFontID, const sal_Unicode* pString, int nLen, CharacterMetric* pArray, bool bVertical ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( ! pFont )
+ return false;
+
+ if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
+ || ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
+ )
+ {
+ // might be a font not yet analyzed
+ if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, false );
+ else if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+
+ for( int i = 0; i < nLen; i++ )
+ {
+ if( ! pFont->m_pMetrics ||
+ ! ( pFont->m_pMetrics->m_aPages[ pString[i] >> 11 ] & ( 1 << ( ( pString[i] >> 8 ) & 7 ) ) ) )
+ pFont->queryMetricPage( pString[i] >> 8, m_pAtoms );
+ pArray[i].width = pArray[i].height = -1;
+ if( pFont->m_pMetrics )
+ {
+ int effectiveCode = pString[i];
+ effectiveCode |= bVertical ? 1 << 16 : 0;
+ ::std::hash_map< int, CharacterMetric >::const_iterator it =
+ pFont->m_pMetrics->m_aMetrics.find( effectiveCode );
+ // if no vertical metrics are available assume rotated horizontal metrics
+ if( bVertical && (it == pFont->m_pMetrics->m_aMetrics.end()) )
+ it = pFont->m_pMetrics->m_aMetrics.find( pString[i] );
+ // the character metrics are in it->second
+ if( it != pFont->m_pMetrics->m_aMetrics.end() )
+ pArray[ i ] = it->second;
+ }
+ }
+
+ return true;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::getMetrics( fontID nFontID, sal_Unicode minCharacter, sal_Unicode maxCharacter, CharacterMetric* pArray, bool bVertical ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( ! pFont )
+ return false;
+
+ if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
+ || ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
+ )
+ {
+ // might be a font not yet analyzed
+ if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, false );
+ else if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+
+ sal_Unicode code = minCharacter;
+ do
+ {
+ if( ! pFont->m_pMetrics ||
+ ! ( pFont->m_pMetrics->m_aPages[ code >> 11 ] & ( 1 << ( ( code >> 8 ) & 7 ) ) ) )
+ pFont->queryMetricPage( code >> 8, m_pAtoms );
+ pArray[ code - minCharacter ].width = -1;
+ pArray[ code - minCharacter ].height = -1;
+ if( pFont->m_pMetrics )
+ {
+ int effectiveCode = code;
+ effectiveCode |= bVertical ? 1 << 16 : 0;
+ ::std::hash_map< int, CharacterMetric >::const_iterator it =
+ pFont->m_pMetrics->m_aMetrics.find( effectiveCode );
+ // if no vertical metrics are available assume rotated horizontal metrics
+ if( bVertical && (it == pFont->m_pMetrics->m_aMetrics.end()) )
+ it = pFont->m_pMetrics->m_aMetrics.find( code );
+ // the character metrics are in it->second
+ if( it != pFont->m_pMetrics->m_aMetrics.end() )
+ pArray[ code - minCharacter ] = it->second;
+ }
+ } while( code++ != maxCharacter );
+
+ return true;
+}
+
+// -------------------------------------------------------------------------
+
+static bool createWriteablePath( const ByteString& rPath )
+{
+ bool bSuccess = false;
+
+ if( access( rPath.GetBuffer(), W_OK ) )
+ {
+ int nPos = rPath.SearchBackward( '/' );
+ if( nPos != STRING_NOTFOUND )
+ while( nPos > 0 && rPath.GetChar( nPos ) == '/' )
+ nPos--;
+
+ if( nPos != STRING_NOTFOUND && nPos != 0 && createWriteablePath( rPath.Copy( 0, nPos+1 ) ) )
+ {
+ bSuccess = mkdir( rPath.GetBuffer(), 0777 ) ? false : true;
+ }
+ }
+ else
+ bSuccess = true;
+
+ return bSuccess;
+}
+
+
+// -------------------------------------------------------------------------
+
+int PrintFontManager::importFonts( const ::std::list< OString >& rFiles, bool bLinkOnly, ImportFontCallback* pCallback )
+{
+ int nSuccess = 0;
+
+ // find a directory with write access
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ bool bCanWrite = false;
+ int nDirID = 0;
+ INetURLObject aDir;
+ for( ::std::list< int >::const_iterator dir_it = m_aPrivateFontDirectories.begin();
+ ! bCanWrite && dir_it != m_aPrivateFontDirectories.end(); ++dir_it )
+ {
+ // check if we can create files in that directory
+ ByteString aDirPath = getDirectory( *dir_it );
+ if( createWriteablePath( aDirPath ) )
+ {
+ aDir = INetURLObject( OStringToOUString( aDirPath, aEncoding ), INET_PROT_FILE, INetURLObject::ENCODE_ALL );
+ nDirID = *dir_it;
+ bCanWrite = true;
+ }
+ }
+ if( bCanWrite )
+ {
+ for( ::std::list< OString >::const_iterator font_it = rFiles.begin();
+ font_it != rFiles.end(); ++font_it )
+ {
+ INetURLObject aFrom( OStringToOUString( *font_it, aEncoding ), INET_PROT_FILE, INetURLObject::ENCODE_ALL );
+ INetURLObject aTo( aDir );
+ aTo.Append( aFrom.GetName() );
+
+ if( pCallback )
+ pCallback->progress( aTo.PathToFileName() );
+
+ if( pCallback && pCallback->isCanceled() )
+ break;
+
+ if( ! access( ByteString( String(aTo.PathToFileName()), aEncoding ).GetBuffer(), F_OK ) )
+ {
+ if( ! ( pCallback ? pCallback->queryOverwriteFile( aTo.PathToFileName() ) : false ) )
+ continue;
+ }
+ // look for afm if necessary
+ OUString aAfmCopied;
+ FileBase::RC nError;
+ if( aFrom.getExtension().equalsIgnoreAsciiCaseAscii( "pfa" ) ||
+ aFrom.getExtension().equalsIgnoreAsciiCaseAscii( "pfb" ) )
+ {
+ INetURLObject aFromAfm( aFrom );
+ aFromAfm.setExtension( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "afm" ) ) );
+ if( access( ByteString( String(aFromAfm.PathToFileName()), aEncoding ).GetBuffer(), F_OK ) )
+ {
+ aFromAfm.setExtension( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AFM" ) ) );
+ if( access( ByteString( String(aFromAfm.PathToFileName()), aEncoding ).GetBuffer(), F_OK ) )
+ {
+ aFromAfm.removeSegment();
+ aFromAfm.Append( String( RTL_CONSTASCII_USTRINGPARAM( "afm" ) ) );
+ aFromAfm.Append( aTo.GetName() );
+ aFromAfm.setExtension( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "afm" ) ) );
+ if( access( ByteString( String(aFromAfm.PathToFileName()), aEncoding ).GetBuffer(), F_OK ) )
+ {
+ aFromAfm.setExtension( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AFM" ) ) );
+ if( access( ByteString( String(aFromAfm.PathToFileName()), aEncoding ).GetBuffer(), F_OK ) )
+ {
+ // give up
+ if( pCallback )
+ pCallback->importFontFailed( aTo.PathToFileName(), ImportFontCallback::NoAfmMetric );
+ continue;
+ }
+ }
+ }
+ }
+ INetURLObject aToAfm( aTo );
+ aToAfm.setExtension( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "afm" ) ) );
+ OUString aFromPath, aToPath;
+ if( bLinkOnly )
+ {
+ ByteString aLinkFromPath( String(aFromAfm.PathToFileName()),
+ aEncoding );
+ ByteString aLinkToPath( String(aToAfm.PathToFileName()),
+ aEncoding );
+ nError = (FileBase::RC)symlink( aLinkFromPath.GetBuffer(), aLinkToPath.GetBuffer() );
+ }
+ else
+ nError = File::copy( aFromAfm.GetMainURL(INetURLObject::DECODE_TO_IURI), aToAfm.GetMainURL(INetURLObject::DECODE_TO_IURI) );
+ if( nError )
+ {
+ if( pCallback )
+ pCallback->importFontFailed( aTo.PathToFileName(), ImportFontCallback::AfmCopyFailed );
+ continue;
+ }
+ aAfmCopied = aToPath;
+ }
+ if( bLinkOnly )
+ {
+ ByteString aFromPath( String(aFrom.PathToFileName()),
+ aEncoding );
+ ByteString aToPath( String(aTo.PathToFileName()), aEncoding );
+ nError = (FileBase::RC)symlink( aFromPath.GetBuffer(),
+ aToPath.GetBuffer() );
+ }
+ else
+ nError = File::copy( aFrom.GetMainURL(INetURLObject::DECODE_TO_IURI), aTo.GetMainURL(INetURLObject::DECODE_TO_IURI) );
+ // copy font file
+ if( nError )
+ {
+ if( aAfmCopied.getLength() )
+ File::remove( aAfmCopied );
+ if( pCallback )
+ pCallback->importFontFailed( aTo.PathToFileName(), ImportFontCallback::FontCopyFailed );
+ continue;
+ }
+
+ ::std::list< PrintFont* > aNewFonts;
+ ::std::list< PrintFont* >::iterator it;
+ if( analyzeFontFile( nDirID, OUStringToOString( aTo.GetName(), aEncoding ), ::std::list<OString>(), aNewFonts ) )
+ {
+ // remove all fonts for the same file
+ // discarding their font ids
+ ::std::hash_map< fontID, PrintFont* >::iterator current, next;
+ current = m_aFonts.begin();
+ OString aFileName( OUStringToOString( aTo.GetName(), aEncoding ) );
+ while( current != m_aFonts.end() )
+ {
+ bool bRemove = false;
+ switch( current->second->m_eType )
+ {
+ case fonttype::Type1:
+ if( static_cast<Type1FontFile*>(current->second)->m_aFontFile == aFileName )
+ bRemove = true;
+ break;
+ case fonttype::TrueType:
+ if( static_cast<TrueTypeFontFile*>(current->second)->m_aFontFile == aFileName )
+ bRemove = true;
+ break;
+ default: break;
+ }
+ if( bRemove )
+ {
+ next = current;
+ ++next;
+ m_aFontFileToFontID[ aFileName ].erase( current->first );
+ delete current->second;
+ m_aFonts.erase( current );
+ current = next;
+ }
+ else
+ ++current;
+ }
+
+ DBG_ASSERT( !findFontFileID( nDirID, aFileName ), "not all fonts removed for file" );
+
+ nSuccess++;
+ for( it = aNewFonts.begin(); it != aNewFonts.end(); ++it )
+ {
+ m_aFontFileToFontID[ aFileName ].insert( m_nNextFontID );
+ m_aFonts[ m_nNextFontID++ ] = *it;
+ m_pFontCache->updateFontCacheEntry( *it, false );
+ }
+ }
+ }
+
+ m_pFontCache->updateDirTimestamp( nDirID );
+ m_pFontCache->flush();
+ }
+ else if( pCallback )
+ pCallback->importFontsFailed( ImportFontCallback::NoWritableDirectory );
+
+ return nSuccess;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::checkImportPossible() const
+{
+ bool bSuccess = false;
+
+ // find a directory with write access
+ ByteString aDir;
+ for( std::list< int >::const_iterator dir_it = m_aPrivateFontDirectories.begin();
+ dir_it != m_aPrivateFontDirectories.end(); ++dir_it )
+ {
+ aDir = getDirectory( *dir_it );
+ if( createWriteablePath( aDir ) )
+ {
+ bSuccess = true;
+ break;
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ if( bSuccess )
+ fprintf( stderr, "found writable %s\n", aDir.GetBuffer() );
+#endif
+
+ return bSuccess;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::checkChangeFontPropertiesPossible( fontID /*nFontID*/ ) const
+{
+ // since font properties are changed in the font cache file only nowadays
+ // they can always be changed
+ return true;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::changeFontProperties( fontID nFontID, const ::rtl::OUString& rXLFD )
+{
+ ByteString aXLFD( OUStringToOString( rXLFD, RTL_TEXTENCODING_UTF8 ) );
+ ByteString aAddStyle = aXLFD.GetToken( '-', 6 );
+ if( aAddStyle.Search( "utf8" ) == STRING_NOTFOUND )
+ {
+ aAddStyle.Append( aAddStyle.Len() ? ";utf8" : "utf8" );
+ aXLFD.SetToken( 6, ';', aAddStyle );
+ }
+ PrintFont* pFont = getFont( nFontID );
+ std::list< OString > aDummyList;
+ aDummyList.push_back( aXLFD );
+ getFontAttributesFromXLFD( pFont, aDummyList );
+ pFont->m_bUserOverride = true;
+ m_pFontCache->updateFontCacheEntry( pFont, true );
+
+ return true;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::
+getImportableFontProperties(
+ const OString& rFile,
+ ::std::list< FastPrintFontInfo >& rFontProps
+ )
+{
+ rFontProps.clear();
+ int nIndex = rFile.lastIndexOf( '/' );
+ OString aDir, aFile( rFile.copy( nIndex+1 ) );
+ if( nIndex != -1 )
+ aDir = rFile.copy( 0, nIndex );
+ int nDirID = getDirectoryAtom( aDir, true );
+ ::std::list< PrintFont* > aFonts;
+ bool bRet = analyzeFontFile( nDirID, aFile, ::std::list<OString>(), aFonts );
+ while( aFonts.begin() != aFonts.end() )
+ {
+ PrintFont* pFont = aFonts.front();
+ aFonts.pop_front();
+ FastPrintFontInfo aInfo;
+ fillPrintFontInfo( pFont, aInfo );
+ rFontProps.push_back( aInfo );
+ delete pFont;
+ }
+ return bRet;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::getFileDuplicates( fontID nFont, ::std::list< fontID >& rFonts ) const
+{
+ bool bRet = false;
+
+ rFonts.clear();
+
+ PrintFont* pSearchFont = getFont( nFont );
+ if( ! pSearchFont ||
+ pSearchFont->m_eType != fonttype::TrueType ||
+ static_cast<TrueTypeFontFile*>(pSearchFont)->m_nCollectionEntry == -1
+ )
+ return false;
+
+ OString aFile( getFontFileSysPath( nFont ) );
+ if( ! aFile.getLength() )
+ return false;
+
+ for( ::std::hash_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
+ {
+ if( nFont != it->first )
+ {
+ OString aCompFile( getFontFile( it->second ) );
+ if( aCompFile == aFile )
+ {
+ rFonts.push_back( it->first );
+ bRet = true;
+ }
+ }
+ }
+ return bRet;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::removeFonts( const ::std::list< fontID >& rFonts )
+{
+ bool bRet = true;
+ ::std::list< fontID > aDuplicates;
+ for( ::std::list< fontID >::const_iterator it = rFonts.begin(); it != rFonts.end(); ++it )
+ {
+ ::std::hash_map< fontID, PrintFont* >::const_iterator haveFont = m_aFonts.find( *it );
+ if( haveFont == m_aFonts.end() )
+ continue;
+
+ PrintFont* pFont = haveFont->second;
+ bool bRemoveDuplicates = getFileDuplicates( *it, aDuplicates );
+ ByteString aFile( getFontFile( pFont ) );
+ if( aFile.Len() )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "try unlink( \"%s\" ) ... ", aFile.GetBuffer() );
+#endif
+ if( unlink( aFile.GetBuffer() ) )
+ {
+ bRet = false;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "failed\n" );
+#endif
+ continue;
+ }
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "succeeded\n" );
+#endif
+ OString aAfm( getAfmFile( pFont ) );
+ if( aAfm.getLength() )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "unlink( \"%s\" )\n", aAfm.getStr() );
+#endif
+ unlink( aAfm.getStr() );
+ }
+ m_aFonts.erase( *it );
+ delete pFont;
+ if( bRemoveDuplicates )
+ {
+ for( ::std::list< fontID >::iterator dup = aDuplicates.begin(); dup != aDuplicates.end(); ++dup )
+ {
+ m_aFontFileToFontID[ aFile ].erase( *dup );
+ PrintFont* pDup = m_aFonts[ *dup ];
+ m_aFonts.erase( *dup );
+ delete pDup;
+ }
+ }
+ }
+ }
+ return bRet;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::isPrivateFontFile( fontID nFont ) const
+{
+ bool bRet = false;
+ int nDirID = -1;
+ PrintFont* pFont = getFont( nFont );
+ if( pFont )
+ {
+ switch( pFont->m_eType )
+ {
+ case fonttype::Type1: nDirID = static_cast< Type1FontFile* >(pFont)->m_nDirectory;break;
+ case fonttype::TrueType: nDirID = static_cast< TrueTypeFontFile* >(pFont)->m_nDirectory;break;
+ default: break;
+ }
+ }
+ if( nDirID != -1 )
+ {
+ for( ::std::list< int >::const_iterator it = m_aPrivateFontDirectories.begin(); it != m_aPrivateFontDirectories.end(); ++it )
+ {
+ if( nDirID == *it )
+ {
+ bRet = true;
+ break;
+ }
+ }
+ }
+ return bRet;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::getAlternativeFamilyNames( fontID nFont, ::std::list< OUString >& rNames ) const
+{
+ rNames.clear();
+
+ PrintFont* pFont = getFont( nFont );
+ if( pFont && pFont->m_eType == fonttype::TrueType )
+ {
+ TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
+ ByteString aFile( getFontFile( pFont ) );
+ TrueTypeFont* pTTFont;
+ if( OpenTTFontFile( aFile.GetBuffer(), pTTFontFile->m_nCollectionEntry < 0 ? 0 : pTTFontFile->m_nCollectionEntry, &pTTFont ) == SF_OK )
+ {
+ NameRecord* pNameRecords = NULL;
+ int nNameRecords = GetTTNameRecords( pTTFont, &pNameRecords );
+ for( int i = 0; i < nNameRecords; i++ )
+ {
+ if( pNameRecords[i].nameID != 1 ) // family name
+ continue;
+
+ OUString aFamily( convertTrueTypeName( pNameRecords+i ) );
+ if( aFamily.getLength()
+ &&
+ m_pAtoms->getAtom( ATOM_FAMILYNAME, aFamily, sal_True ) != pFont->m_nFamilyName
+ )
+ {
+ rNames.push_back( aFamily );
+ }
+ }
+
+ if( nNameRecords )
+ DisposeNameRecords( pNameRecords, nNameRecords );
+ CloseTTFont( pTTFont );
+ }
+ }
+ return rNames.begin() != rNames.end();
+}
+
+// -------------------------------------------------------------------------
+
+// TODO: move most of this stuff into the central font-subsetting code
+bool PrintFontManager::createFontSubset(
+ FontSubsetInfo& rInfo,
+ fontID nFont,
+ const OUString& rOutFile,
+ sal_Int32* pGlyphIDs,
+ sal_uInt8* pNewEncoding,
+ sal_Int32* pWidths,
+ int nGlyphs,
+ bool bVertical
+ )
+{
+ PrintFont* pFont = getFont( nFont );
+ if( !pFont )
+ return false;
+
+ switch( pFont->m_eType )
+ {
+ case psp::fonttype::TrueType: rInfo.m_nFontType = FontSubsetInfo::SFNT_TTF; break;
+ case psp::fonttype::Type1: rInfo.m_nFontType = FontSubsetInfo::ANY_TYPE1; break;
+ default:
+ return false;
+ }
+ // TODO: remove when Type1 subsetting gets implemented
+ if( pFont->m_eType != fonttype::TrueType )
+ return false;
+
+ // reshuffle array of requested glyphs to make sure glyph0==notdef
+ sal_uInt8 pEnc[256];
+ sal_uInt16 pGID[256];
+ sal_uInt8 pOldIndex[256];
+ memset( pEnc, 0, sizeof( pEnc ) );
+ memset( pGID, 0, sizeof( pGID ) );
+ memset( pOldIndex, 0, sizeof( pOldIndex ) );
+ if( nGlyphs > 256 )
+ return false;
+ int nChar = 1;
+ for( int i = 0; i < nGlyphs; i++ )
+ {
+ if( pNewEncoding[i] == 0 )
+ {
+ pOldIndex[ 0 ] = i;
+ }
+ else
+ {
+ DBG_ASSERT( !(pGlyphIDs[i] & 0x007f0000), "overlong glyph id" );
+ DBG_ASSERT( (int)pNewEncoding[i] < nGlyphs, "encoding wrong" );
+ DBG_ASSERT( pEnc[pNewEncoding[i]] == 0 && pGID[pNewEncoding[i]] == 0, "duplicate encoded glyph" );
+ pEnc[ pNewEncoding[i] ] = pNewEncoding[i];
+ pGID[ pNewEncoding[i] ] = (sal_uInt16)pGlyphIDs[ i ];
+ pOldIndex[ pNewEncoding[i] ] = i;
+ nChar++;
+ }
+ }
+ nGlyphs = nChar; // either input value or increased by one
+
+ // prepare system name for read access for subset source file
+ // TODO: since this file is usually already mmapped there is no need to open it again
+ const ByteString aFromFile = getFontFile( pFont );
+
+ TrueTypeFont* pTTFont = NULL; // TODO: rename to SfntFont
+ TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
+ if( OpenTTFontFile( aFromFile.GetBuffer(), pTTFontFile->m_nCollectionEntry < 0 ? 0 : pTTFontFile->m_nCollectionEntry, &pTTFont ) != SF_OK )
+ return false;
+
+ // prepare system name for write access for subset file target
+ OUString aSysPath;
+ if( osl_File_E_None != osl_getSystemPathFromFileURL( rOutFile.pData, &aSysPath.pData ) )
+ return false;
+ const rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ const ByteString aToFile( OUStringToOString( aSysPath, aEncoding ) );
+
+ // do CFF subsetting if possible
+ int nCffLength = 0;
+ const sal_uInt8* pCffBytes = NULL;
+ if( GetSfntTable( pTTFont, O_CFF, &pCffBytes, &nCffLength ) )
+ {
+ rInfo.LoadFont( FontSubsetInfo::CFF_FONT, pCffBytes, nCffLength );
+#if 1 // TODO: remove 16bit->long conversion when related methods handle non-16bit glyphids
+ long aRequestedGlyphs[256];
+ for( int i = 0; i < nGlyphs; ++i )
+ aRequestedGlyphs[i] = pGID[i];
+#endif
+ // create subset file at requested path
+ FILE* pOutFile = fopen( aToFile.GetBuffer(), "wb" );
+ // create font subset
+ const char* pGlyphSetName = NULL; // TODO: better name?
+ const bool bOK = rInfo.CreateFontSubset(
+ FontSubsetInfo::TYPE1_PFB,
+ pOutFile, pGlyphSetName,
+ aRequestedGlyphs, pEnc, nGlyphs, pWidths );
+ fclose( pOutFile );
+ // cleanup before early return
+ CloseTTFont( pTTFont );
+ return bOK;
+ }
+
+ // do TTF->Type42 or Type3 subsetting
+ // fill in font info
+ psp::PrintFontInfo aFontInfo;
+ if( ! getFontInfo( nFont, aFontInfo ) )
+ return false;
+
+ rInfo.m_nAscent = aFontInfo.m_nAscend;
+ rInfo.m_nDescent = aFontInfo.m_nDescend;
+ rInfo.m_aPSName = getPSName( nFont );
+
+ int xMin, yMin, xMax, yMax;
+ getFontBoundingBox( nFont, xMin, yMin, xMax, yMax );
+ rInfo.m_aFontBBox = Rectangle( Point( xMin, yMin ), Size( xMax-xMin, yMax-yMin ) );
+ rInfo.m_nCapHeight = yMax; // Well ...
+
+ // fill in glyph advance widths
+ TTSimpleGlyphMetrics* pMetrics = GetTTSimpleGlyphMetrics( pTTFont,
+ pGID,
+ nGlyphs,
+ bVertical ? 1 : 0 );
+ if( pMetrics )
+ {
+ for( int i = 0; i < nGlyphs; i++ )
+ pWidths[pOldIndex[i]] = pMetrics[i].adv;
+ free( pMetrics );
+ }
+ else
+ {
+ CloseTTFont( pTTFont );
+ return false;
+ }
+
+ bool bSuccess = ( SF_OK == CreateTTFromTTGlyphs( pTTFont,
+ aToFile.GetBuffer(),
+ pGID,
+ pEnc,
+ nGlyphs,
+ 0,
+ NULL,
+ 0 ) );
+ CloseTTFont( pTTFont );
+
+ return bSuccess;
+}
+
+void PrintFontManager::getGlyphWidths( fontID nFont,
+ bool bVertical,
+ std::vector< sal_Int32 >& rWidths,
+ std::map< sal_Unicode, sal_uInt32 >& rUnicodeEnc )
+{
+ PrintFont* pFont = getFont( nFont );
+ if( !pFont ||
+ (pFont->m_eType != fonttype::TrueType && pFont->m_eType != fonttype::Type1) )
+ return;
+ if( pFont->m_eType == fonttype::TrueType )
+ {
+ TrueTypeFont* pTTFont = NULL;
+ TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
+ ByteString aFromFile = getFontFile( pFont );
+ if( OpenTTFontFile( aFromFile.GetBuffer(), pTTFontFile->m_nCollectionEntry < 0 ? 0 : pTTFontFile->m_nCollectionEntry, &pTTFont ) != SF_OK )
+ return;
+ int nGlyphs = GetTTGlyphCount( pTTFont );
+ if( nGlyphs > 0 )
+ {
+ rWidths.resize(nGlyphs);
+ std::vector<sal_uInt16> aGlyphIds(nGlyphs);
+ for( int i = 0; i < nGlyphs; i++ )
+ aGlyphIds[i] = sal_uInt16(i);
+ TTSimpleGlyphMetrics* pMetrics = GetTTSimpleGlyphMetrics( pTTFont,
+ &aGlyphIds[0],
+ nGlyphs,
+ bVertical ? 1 : 0 );
+ if( pMetrics )
+ {
+ for( int i = 0; i< nGlyphs; i++ )
+ rWidths[i] = pMetrics[i].adv;
+ free( pMetrics );
+ rUnicodeEnc.clear();
+ }
+
+ // fill the unicode map
+ // TODO: isn't this map already available elsewhere in the fontmanager?
+ const sal_uInt8* pCmapData = NULL;
+ int nCmapSize = 0;
+ if( GetSfntTable( pTTFont, O_cmap, &pCmapData, &nCmapSize ) )
+ {
+ CmapResult aCmapResult;
+ if( ParseCMAP( pCmapData, nCmapSize, aCmapResult ) )
+ {
+ const ImplFontCharMap aCharMap( aCmapResult );
+ for( sal_uInt32 cOld = 0;;)
+ {
+ // get next unicode covered by font
+ const sal_uInt32 c = aCharMap.GetNextChar( cOld );
+ if( c == cOld )
+ break;
+ cOld = c;
+#if 1 // TODO: remove when sal_Unicode covers all of unicode
+ if( c > (sal_Unicode)~0 )
+ break;
+#endif
+ // get the matching glyph index
+ const sal_uInt32 nGlyphId = aCharMap.GetGlyphIndex( c );
+ // update the requested map
+ rUnicodeEnc[ (sal_Unicode)c ] = nGlyphId;
+ }
+ }
+ }
+ }
+ CloseTTFont( pTTFont );
+ }
+ else if( pFont->m_eType == fonttype::Type1 )
+ {
+ if( ! pFont->m_aEncodingVector.size() )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, true, true );
+ if( pFont->m_pMetrics )
+ {
+ rUnicodeEnc.clear();
+ rWidths.clear();
+ rWidths.reserve( pFont->m_pMetrics->m_aMetrics.size() );
+ for( std::hash_map< int, CharacterMetric >::const_iterator it =
+ pFont->m_pMetrics->m_aMetrics.begin();
+ it != pFont->m_pMetrics->m_aMetrics.end(); ++it )
+ {
+ if( (it->first & 0x00010000) == 0 || bVertical )
+ {
+ rUnicodeEnc[ sal_Unicode(it->first & 0x0000ffff) ] = sal_uInt32(rWidths.size());
+ rWidths.push_back( it->second.width );
+ }
+ }
+ }
+ }
+}
+
+// -------------------------------------------------------------------------
+
+const std::map< sal_Unicode, sal_Int32 >* PrintFontManager::getEncodingMap( fontID nFont, const std::map< sal_Unicode, rtl::OString >** pNonEncoded ) const
+{
+ PrintFont* pFont = getFont( nFont );
+ if( !pFont ||
+ (pFont->m_eType != fonttype::Type1 && pFont->m_eType != fonttype::Builtin)
+ )
+ return NULL;
+
+ if( ! pFont->m_aEncodingVector.size() )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, true, true );
+
+ if( pNonEncoded )
+ *pNonEncoded = pFont->m_aNonEncoded.size() ? &pFont->m_aNonEncoded : NULL;
+
+ return pFont->m_aEncodingVector.size() ? &pFont->m_aEncodingVector : NULL;
+}
+
+// -------------------------------------------------------------------------
+
+std::list< OString > PrintFontManager::getAdobeNameFromUnicode( sal_Unicode aChar ) const
+{
+ std::pair< std::hash_multimap< sal_Unicode, rtl::OString >::const_iterator,
+ std::hash_multimap< sal_Unicode, rtl::OString >::const_iterator > range
+ = m_aUnicodeToAdobename.equal_range( aChar );
+
+ std::list< OString > aRet;
+ for( ; range.first != range.second; ++range.first )
+ aRet.push_back( range.first->second );
+
+ if( aRet.begin() == aRet.end() && aChar != 0 )
+ {
+ sal_Char aBuf[8];
+ sal_Int32 nChars = snprintf( (char*)aBuf, sizeof( aBuf ), "uni%.4hX", aChar );
+ aRet.push_back( OString( aBuf, nChars ) );
+ }
+
+ return aRet;
+}
+
+// -------------------------------------------------------------------------
+std::list< sal_Unicode > PrintFontManager::getUnicodeFromAdobeName( const rtl::OString& rName ) const
+{
+ std::pair< std::hash_multimap< rtl::OString, sal_Unicode, rtl::OStringHash >::const_iterator,
+ std::hash_multimap< rtl::OString, sal_Unicode, rtl::OStringHash >::const_iterator > range
+ = m_aAdobenameToUnicode.equal_range( rName );
+
+ std::list< sal_Unicode > aRet;
+ for( ; range.first != range.second; ++range.first )
+ aRet.push_back( range.first->second );
+
+ if( aRet.begin() == aRet.end() )
+ {
+ if( rName.getLength() == 7 && rName.indexOf( "uni" ) == 0 )
+ {
+ sal_Unicode aCode = (sal_Unicode)rName.copy( 3 ).toInt32( 16 );
+ aRet.push_back( aCode );
+ }
+ }
+
+ return aRet;
+}
+
+// -------------------------------------------------------------------------
+namespace
+{
+ OUString getString( const Any& rAny )
+ {
+ OUString aStr;
+ rAny >>= aStr;
+ return aStr;
+ }
+ bool getBool( const Any& rAny )
+ {
+ sal_Bool bBool = sal_False;
+ rAny >>= bBool;
+ return static_cast<bool>(bBool);
+ }
+ sal_Int32 getInt( const Any& rAny )
+ {
+ sal_Int32 n = 0;
+ rAny >>= n;
+ return n;
+ }
+}
+bool PrintFontManager::readOverrideMetrics()
+{
+ if( ! m_aOverrideFonts.empty() )
+ return false;
+
+ Reference< XMultiServiceFactory > xFact( comphelper::getProcessServiceFactory() );
+ if( !xFact.is() )
+ return false;
+ Reference< XMaterialHolder > xMat(
+ xFact->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.psprint.CompatMetricOverride" ) ) ),
+ UNO_QUERY );
+ if( !xMat.is() )
+ return false;
+
+ Any aAny( xMat->getMaterial() );
+ Sequence< Any > aOverrideFonts;
+ if( ! (aAny >>= aOverrideFonts ) )
+ return false;
+ sal_Int32 nFonts = aOverrideFonts.getLength();
+ for( sal_Int32 i = 0; i < nFonts; i++ )
+ {
+ Sequence< NamedValue > aMetrics;
+ if( ! (aOverrideFonts.getConstArray()[i] >>= aMetrics) )
+ continue;
+ BuiltinFont* pFont = new BuiltinFont();
+ pFont->m_nDirectory = 0;
+ pFont->m_bUserOverride = false;
+ pFont->m_pMetrics = new PrintFontMetrics;
+ memset( pFont->m_pMetrics->m_aPages, 0xff, sizeof( pFont->m_pMetrics->m_aPages ) );
+ pFont->m_pMetrics->m_bKernPairsQueried = true;
+ sal_Int32 nProps = aMetrics.getLength();
+ const NamedValue* pProps = aMetrics.getConstArray();
+ for( sal_Int32 n = 0; n < nProps; n++ )
+ {
+ if( pProps[n].Name.equalsAscii( "FamilyName" ) )
+ pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME,
+ getString(pProps[n].Value),
+ sal_True );
+ else if( pProps[n].Name.equalsAscii( "PSName" ) )
+ pFont->m_nPSName = m_pAtoms->getAtom( ATOM_PSNAME,
+ getString(pProps[n].Value),
+ sal_True );
+ else if( pProps[n].Name.equalsAscii( "StyleName" ) )
+ pFont->m_aStyleName = getString(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "Italic" ) )
+ pFont->m_eItalic = static_cast<italic::type>(getInt(pProps[n].Value));
+ else if( pProps[n].Name.equalsAscii( "Width" ) )
+ pFont->m_eWidth = static_cast<width::type>(getInt(pProps[n].Value));
+ else if( pProps[n].Name.equalsAscii( "Weight" ) )
+ pFont->m_eWeight = static_cast<weight::type>(getInt(pProps[n].Value));
+ else if( pProps[n].Name.equalsAscii( "Pitch" ) )
+ pFont->m_ePitch = static_cast<pitch::type>(getInt(pProps[n].Value));
+ else if( pProps[n].Name.equalsAscii( "Encoding" ) )
+ pFont->m_aEncoding = static_cast<rtl_TextEncoding>(getInt(pProps[n].Value));
+ else if( pProps[n].Name.equalsAscii( "FontEncodingOnly" ) )
+ pFont->m_bFontEncodingOnly = getBool(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "GlobalMetricXWidth" ) )
+ pFont->m_aGlobalMetricX.width = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "GlobalMetricXHeight" ) )
+ pFont->m_aGlobalMetricX.height = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "GlobalMetricYWidth" ) )
+ pFont->m_aGlobalMetricY.width = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "GlobalMetricYHeight" ) )
+ pFont->m_aGlobalMetricY.height = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "Ascend" ) )
+ pFont->m_nAscend = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "Descend" ) )
+ pFont->m_nDescend = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "Leading" ) )
+ pFont->m_nLeading = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "XMin" ) )
+ pFont->m_nXMin = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "YMin" ) )
+ pFont->m_nYMin = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "XMax" ) )
+ pFont->m_nXMax = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "YMax" ) )
+ pFont->m_nYMax = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "VerticalSubstitutes" ) )
+ pFont->m_bHaveVerticalSubstitutedGlyphs = getBool(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "EncodingVector" ) )
+ {
+ Sequence< NamedValue > aEncoding;
+ pProps[n].Value >>= aEncoding;
+ sal_Int32 nEnc = aEncoding.getLength();
+ const NamedValue* pEnc = aEncoding.getConstArray();
+ for( sal_Int32 m = 0; m < nEnc; m++ )
+ {
+ sal_Unicode cCode = *pEnc[m].Name.getStr();
+ sal_Int32 nGlyph = getInt(pEnc[m].Value);
+ pFont->m_aEncodingVector[ cCode ] = nGlyph;
+ }
+ }
+ else if( pProps[n].Name.equalsAscii( "NonEncoded" ) )
+ {
+ Sequence< NamedValue > aEncoding;
+ pProps[n].Value >>= aEncoding;
+ sal_Int32 nEnc = aEncoding.getLength();
+ const NamedValue* pEnc = aEncoding.getConstArray();
+ for( sal_Int32 m = 0; m < nEnc; m++ )
+ {
+ sal_Unicode cCode = *pEnc[m].Name.getStr();
+ OUString aGlyphName( getString(pEnc[m].Value) );
+ pFont->m_aNonEncoded[ cCode ] = OUStringToOString(aGlyphName,RTL_TEXTENCODING_ASCII_US);
+ }
+ }
+ else if( pProps[n].Name.equalsAscii( "CharacterMetrics" ) )
+ {
+ // fill pFont->m_pMetrics->m_aMetrics
+ // expect triples of int: int -> CharacterMetric.{ width, height }
+ Sequence< sal_Int32 > aSeq;
+ pProps[n].Value >>= aSeq;
+ sal_Int32 nInts = aSeq.getLength();
+ const sal_Int32* pInts = aSeq.getConstArray();
+ for( sal_Int32 m = 0; m < nInts; m+=3 )
+ {
+ pFont->m_pMetrics->m_aMetrics[ pInts[m] ].width = static_cast<short int>(pInts[m+1]);
+ pFont->m_pMetrics->m_aMetrics[ pInts[m] ].height = static_cast<short int>(pInts[m+2]);
+ }
+ }
+ else if( pProps[n].Name.equalsAscii( "XKernPairs" ) )
+ {
+ // fill pFont->m_pMetrics->m_aXKernPairs
+ // expection name: <unicode1><unicode2> value: ((height << 16)| width)
+ Sequence< NamedValue > aKern;
+ pProps[n].Value >>= aKern;
+ KernPair aPair;
+ const NamedValue* pVals = aKern.getConstArray();
+ int nPairs = aKern.getLength();
+ for( int m = 0; m < nPairs; m++ )
+ {
+ if( pVals[m].Name.getLength() == 2 )
+ {
+ aPair.first = pVals[m].Name.getStr()[0];
+ aPair.second = pVals[m].Name.getStr()[1];
+ sal_Int32 nKern = getInt( pVals[m].Value );
+ aPair.kern_x = static_cast<short int>(nKern & 0xffff);
+ aPair.kern_y = static_cast<short int>((sal_uInt32(nKern) >> 16) & 0xffff);
+ pFont->m_pMetrics->m_aXKernPairs.push_back( aPair );
+ }
+ }
+ }
+ }
+ // sanity check
+ if( pFont->m_nPSName &&
+ pFont->m_nFamilyName &&
+ ! pFont->m_pMetrics->m_aMetrics.empty() )
+ {
+ m_aOverrideFonts.push_back( m_nNextFontID );
+ m_aFonts[ m_nNextFontID++ ] = pFont;
+ }
+ else
+ {
+ DBG_ASSERT( 0, "override font failed" );
+ delete pFont;
+ }
+ }
+
+ return true;
+}
diff --git a/vcl/unx/source/fontmanager/helper.cxx b/vcl/unx/source/fontmanager/helper.cxx
new file mode 100644
index 000000000000..05213a52597c
--- /dev/null
+++ b/vcl/unx/source/fontmanager/helper.cxx
@@ -0,0 +1,404 @@
+/*************************************************************************
+ *
+ * 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 <sys/stat.h>
+#include <unistd.h>
+#include <limits.h>
+
+#include "vcl/helper.hxx"
+#include "vcl/ppdparser.hxx"
+#include "tools/string.hxx"
+#include "tools/urlobj.hxx"
+#include "osl/file.hxx"
+#include "osl/process.h"
+#include "rtl/bootstrap.hxx"
+
+using namespace rtl;
+
+namespace psp {
+
+OUString getOfficePath( enum whichOfficePath ePath )
+{
+ static OUString aNetPath;
+ static OUString aUserPath;
+ static OUString aConfigPath;
+ static OUString aEmpty;
+ static bool bOnce = false;
+
+ if( ! bOnce )
+ {
+ bOnce = true;
+ OUString aIni;
+ Bootstrap::get( OUString( RTL_CONSTASCII_USTRINGPARAM( "BRAND_BASE_DIR" ) ), aIni );
+ aIni += OUString( RTL_CONSTASCII_USTRINGPARAM( "/program/" SAL_CONFIGFILE( "bootstrap" ) ) );
+ Bootstrap aBootstrap( aIni );
+ aBootstrap.getFrom( OUString( RTL_CONSTASCII_USTRINGPARAM( "CustomDataUrl" ) ), aConfigPath );
+ aBootstrap.getFrom( OUString( RTL_CONSTASCII_USTRINGPARAM( "BaseInstallation" ) ), aNetPath );
+ aBootstrap.getFrom( OUString( RTL_CONSTASCII_USTRINGPARAM( "UserInstallation" ) ), aUserPath );
+ OUString aUPath = aUserPath;
+
+ if( ! aConfigPath.compareToAscii( "file://", 7 ) )
+ {
+ OUString aSysPath;
+ if( osl_getSystemPathFromFileURL( aConfigPath.pData, &aSysPath.pData ) == osl_File_E_None )
+ aConfigPath = aSysPath;
+ }
+ if( ! aNetPath.compareToAscii( "file://", 7 ) )
+ {
+ OUString aSysPath;
+ if( osl_getSystemPathFromFileURL( aNetPath.pData, &aSysPath.pData ) == osl_File_E_None )
+ aNetPath = aSysPath;
+ }
+ if( ! aUserPath.compareToAscii( "file://", 7 ) )
+ {
+ OUString aSysPath;
+ if( osl_getSystemPathFromFileURL( aUserPath.pData, &aSysPath.pData ) == osl_File_E_None )
+ aUserPath = aSysPath;
+ }
+ // ensure user path exists
+ aUPath += OUString( RTL_CONSTASCII_USTRINGPARAM( "/user/psprint" ) );
+ #if OSL_DEBUG_LEVEL > 1
+ oslFileError eErr =
+ #endif
+ osl_createDirectoryPath( aUPath.pData, NULL, NULL );
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "try to create \"%s\" = %d\n", OUStringToOString( aUPath, RTL_TEXTENCODING_UTF8 ).getStr(), eErr );
+ #endif
+ }
+
+ switch( ePath )
+ {
+ case ConfigPath: return aConfigPath;
+ case NetPath: return aNetPath;
+ case UserPath: return aUserPath;
+ }
+ return aEmpty;
+}
+
+static OString getEnvironmentPath( const char* pKey )
+{
+ OString aPath;
+
+ const char* pValue = getenv( pKey );
+ if( pValue && *pValue )
+ {
+ aPath = OString( pValue );
+ }
+ return aPath;
+}
+
+} // namespace psp
+
+void psp::getPrinterPathList( std::list< OUString >& rPathList, const char* pSubDir )
+{
+ rPathList.clear();
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+
+ OUStringBuffer aPathBuffer( 256 );
+
+ // append net path
+ aPathBuffer.append( getOfficePath( psp::NetPath ) );
+ if( aPathBuffer.getLength() )
+ {
+ aPathBuffer.appendAscii( "/share/psprint" );
+ if( pSubDir )
+ {
+ aPathBuffer.append( sal_Unicode('/') );
+ aPathBuffer.appendAscii( pSubDir );
+ }
+ rPathList.push_back( aPathBuffer.makeStringAndClear() );
+ }
+ // append user path
+ aPathBuffer.append( getOfficePath( psp::UserPath ) );
+ if( aPathBuffer.getLength() )
+ {
+ aPathBuffer.appendAscii( "/user/psprint" );
+ if( pSubDir )
+ {
+ aPathBuffer.append( sal_Unicode('/') );
+ aPathBuffer.appendAscii( pSubDir );
+ }
+ rPathList.push_back( aPathBuffer.makeStringAndClear() );
+ }
+
+ OString aPath( getEnvironmentPath("SAL_PSPRINT") );
+ sal_Int32 nIndex = 0;
+ do
+ {
+ OString aDir( aPath.getToken( 0, ':', nIndex ) );
+ if( ! aDir.getLength() )
+ continue;
+
+ if( pSubDir )
+ {
+ aDir += "/";
+ aDir += pSubDir;
+ }
+ struct stat aStat;
+ if( stat( aDir.getStr(), &aStat ) || ! S_ISDIR( aStat.st_mode ) )
+ continue;
+
+ rPathList.push_back( OStringToOUString( aDir, aEncoding ) );
+ } while( nIndex != -1 );
+
+ #ifdef SYSTEM_PPD_DIR
+ if( pSubDir && rtl_str_compare( pSubDir, PRINTER_PPDDIR ) == 0 )
+ {
+ rPathList.push_back( rtl::OStringToOUString( rtl::OString( SYSTEM_PPD_DIR ), RTL_TEXTENCODING_UTF8 ) );
+ }
+ #endif
+
+ if( rPathList.empty() )
+ {
+ // last resort: next to program file (mainly for setup)
+ OUString aExe;
+ if( osl_getExecutableFile( &aExe.pData ) == osl_Process_E_None )
+ {
+ INetURLObject aDir( aExe );
+ aDir.removeSegment();
+ aExe = aDir.GetMainURL( INetURLObject::NO_DECODE );
+ OUString aSysPath;
+ if( osl_getSystemPathFromFileURL( aExe.pData, &aSysPath.pData ) == osl_File_E_None )
+ {
+ rPathList.push_back( aSysPath );
+ }
+ }
+ }
+}
+
+OUString psp::getFontPath()
+{
+ static OUString aPath;
+
+ if( ! aPath.getLength() )
+ {
+ OUStringBuffer aPathBuffer( 512 );
+
+ OUString aConfigPath( getOfficePath( psp::ConfigPath ) );
+ OUString aNetPath( getOfficePath( psp::NetPath ) );
+ OUString aUserPath( getOfficePath( psp::UserPath ) );
+ if( aConfigPath.getLength() )
+ {
+ // #i53530# Path from CustomDataUrl will completely
+ // replace net and user paths if the path exists
+ aPathBuffer.append(aConfigPath);
+ aPathBuffer.appendAscii("/share/fonts");
+ // check existance of config path
+ struct stat aStat;
+ if( 0 != stat( OUStringToOString( aPathBuffer.makeStringAndClear(), osl_getThreadTextEncoding() ).getStr(), &aStat )
+ || ! S_ISDIR( aStat.st_mode ) )
+ aConfigPath = OUString();
+ else
+ {
+ aPathBuffer.append(aConfigPath);
+ aPathBuffer.appendAscii("/share/fonts");
+ }
+ }
+ if( aConfigPath.getLength() == 0 )
+ {
+ if( aNetPath.getLength() )
+ {
+ aPathBuffer.append( aNetPath );
+ aPathBuffer.appendAscii( "/share/fonts/truetype;");
+ aPathBuffer.append( aNetPath );
+ aPathBuffer.appendAscii( "/share/fonts/type1;" );
+ }
+ if( aUserPath.getLength() )
+ {
+ aPathBuffer.append( aUserPath );
+ aPathBuffer.appendAscii( "/user/fonts" );
+ }
+ }
+ OString aEnvPath( getEnvironmentPath( "SAL_FONTPATH_PRIVATE" ) );
+ if( aEnvPath.getLength() )
+ {
+ aPathBuffer.append( sal_Unicode(';') );
+ aPathBuffer.append( OStringToOUString( aEnvPath, osl_getThreadTextEncoding() ) );
+ }
+
+ aPath = aPathBuffer.makeStringAndClear();
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "initializing font path to \"%s\"\n", OUStringToOString( aPath, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+ }
+ return aPath;
+}
+
+bool psp::convertPfbToPfa( ::osl::File& rInFile, ::osl::File& rOutFile )
+{
+ static unsigned char hexDigits[] =
+ {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+ };
+
+ bool bSuccess = true;
+ bool bEof = false;
+ unsigned char buffer[256];
+ sal_uInt64 nRead;
+ sal_uInt64 nOrgPos = 0;
+ rInFile.getPos( nOrgPos );
+
+ while( bSuccess && ! bEof )
+ {
+ // read leading bytes
+ bEof = ! rInFile.read( buffer, 6, nRead ) && nRead == 6 ? false : true;
+ unsigned int nType = buffer[ 1 ];
+ unsigned int nBytesToRead = buffer[2] | buffer[3] << 8 | buffer[4] << 16 | buffer[5] << 24;
+ if( buffer[0] != 0x80 ) // test for pfb m_agic number
+ {
+ // this migt be a pfa font already
+ sal_uInt64 nWrite = 0;
+ if( ! rInFile.read( buffer+6, 9, nRead ) && nRead == 9 &&
+ ( ! std::strncmp( (char*)buffer, "%!FontType1-", 12 ) ||
+ ! std::strncmp( (char*)buffer, "%!PS-AdobeFont-", 15 ) ) )
+ {
+ if( rOutFile.write( buffer, 15, nWrite ) || nWrite != 15 )
+ bSuccess = false;
+ while( bSuccess &&
+ ! rInFile.read( buffer, sizeof( buffer ), nRead ) &&
+ nRead != 0 )
+ {
+ if( rOutFile.write( buffer, nRead, nWrite ) ||
+ nWrite != nRead )
+ bSuccess = false;
+ }
+ bEof = true;
+ }
+ else
+ bSuccess = false;
+ }
+ else if( nType == 1 || nType == 2 )
+ {
+ unsigned char* pBuffer = new unsigned char[ nBytesToRead+1 ];
+
+ if( ! rInFile.read( pBuffer, nBytesToRead, nRead ) && nRead == nBytesToRead )
+ {
+ if( nType == 1 )
+ {
+ // ascii data, convert dos lineends( \r\n ) and
+ // m_ac lineends( \r ) to \n
+ unsigned char * pWriteBuffer = new unsigned char[ nBytesToRead ];
+ unsigned int nBytesToWrite = 0;
+ for( unsigned int i = 0; i < nBytesToRead; i++ )
+ {
+ if( pBuffer[i] != '\r' )
+ pWriteBuffer[ nBytesToWrite++ ] = pBuffer[i];
+ else if( pBuffer[ i+1 ] == '\n' )
+ {
+ i++;
+ pWriteBuffer[ nBytesToWrite++ ] = '\n';
+ }
+ else
+ pWriteBuffer[ nBytesToWrite++ ] = '\n';
+ }
+ if( rOutFile.write( pWriteBuffer, nBytesToWrite, nRead ) || nRead != nBytesToWrite )
+ bSuccess = false;
+
+ delete [] pWriteBuffer;
+ }
+ else
+ {
+ // binary data
+ unsigned int nBuffer = 0;
+ for( unsigned int i = 0; i < nBytesToRead && bSuccess; i++ )
+ {
+ buffer[ nBuffer++ ] = hexDigits[ pBuffer[ i ] >> 4 ];
+ buffer[ nBuffer++ ] = hexDigits[ pBuffer[ i ] & 15 ];
+ if( nBuffer >= 80 )
+ {
+ buffer[ nBuffer++ ] = '\n';
+ if( rOutFile.write( buffer, nBuffer, nRead ) || nRead != nBuffer )
+ bSuccess = false;
+ nBuffer = 0;
+ }
+ }
+ if( nBuffer > 0 && bSuccess )
+ {
+ buffer[ nBuffer++ ] = '\n';
+ if( rOutFile.write( buffer, nBuffer, nRead ) || nRead != nBuffer )
+ bSuccess = false;
+ }
+ }
+ }
+ else
+ bSuccess = false;
+
+ delete [] pBuffer;
+ }
+ else if( nType == 3 )
+ bEof = true;
+ else
+ bSuccess = false;
+ }
+
+ return bSuccess;
+}
+
+void psp::normPath( OString& rPath )
+{
+ char buf[PATH_MAX];
+
+ ByteString aPath( rPath );
+
+ // double slashes and slash at end are probably
+ // removed by realpath anyway, but since this runs
+ // on many different platforms let's play it safe
+ while( aPath.SearchAndReplace( "//", "/" ) != STRING_NOTFOUND )
+ ;
+ if( aPath.Len() > 0 && aPath.GetChar( aPath.Len()-1 ) == '/' )
+ aPath.Erase( aPath.Len()-1 );
+
+ if( ( aPath.Search( "./" ) != STRING_NOTFOUND ||
+ aPath.Search( "~" ) != STRING_NOTFOUND )
+ && realpath( aPath.GetBuffer(), buf ) )
+ {
+ rPath = buf;
+ }
+ else
+ {
+ rPath = aPath;
+ }
+}
+
+void psp::splitPath( OString& rPath, OString& rDir, OString& rBase )
+{
+ normPath( rPath );
+ sal_Int32 nIndex = rPath.lastIndexOf( '/' );
+ if( nIndex > 0 )
+ rDir = rPath.copy( 0, nIndex );
+ else if( nIndex == 0 ) // root dir
+ rDir = rPath.copy( 0, 1 );
+ if( rPath.getLength() > nIndex+1 )
+ rBase = rPath.copy( nIndex+1 );
+}
+
+
diff --git a/vcl/unx/source/fontmanager/makefile.mk b/vcl/unx/source/fontmanager/makefile.mk
new file mode 100644
index 000000000000..c6a23b88f35b
--- /dev/null
+++ b/vcl/unx/source/fontmanager/makefile.mk
@@ -0,0 +1,72 @@
+#*************************************************************************
+#
+# 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=fontman
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+
+CFLAGS+= -I..$/fontsubset
+INCDEPN+= -I..$/fontsubset
+
+.IF "$(ENABLE_FONTCONFIG)" != ""
+CDEFS += -DENABLE_FONTCONFIG
+.ENDIF
+
+CFLAGS+=$(FREETYPE_CFLAGS)
+
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)"=="aqua"
+
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+
+.ELSE # "$(GUIBASE)"=="aqua"
+
+SLOFILES=\
+ $(SLO)$/fontmanager.obj \
+ $(SLO)$/fontcache.obj \
+ $(SLO)$/fontconfig.obj \
+ $(SLO)$/helper.obj \
+ $(SLO)$/parseAFM.obj
+
+.IF "$(OS)$(CPU)"=="SOLARISI"
+NOOPTFILES=$(SLO)$/fontmanager.obj
+.ENDIF
+
+.ENDIF
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
diff --git a/vcl/unx/source/fontmanager/parseAFM.cxx b/vcl/unx/source/fontmanager/parseAFM.cxx
new file mode 100644
index 000000000000..e1a33b4d1b5d
--- /dev/null
+++ b/vcl/unx/source/fontmanager/parseAFM.cxx
@@ -0,0 +1,1577 @@
+/*
+ * (C) 1988, 1989, 1990 by Adobe Systems Incorporated. All rights reserved.
+ *
+ * This file may be freely copied and redistributed as long as:
+ * 1) This entire notice continues to be included in the file,
+ * 2) If the file has been modified in any way, a notice of such
+ * modification is conspicuously indicated.
+ *
+ * PostScript, Display PostScript, and Adobe are registered trademarks of
+ * Adobe Systems Incorporated.
+ *
+ * ************************************************************************
+ * THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO CHANGE WITHOUT
+ * NOTICE, AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY ADOBE SYSTEMS
+ * INCORPORATED. ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY OR
+ * LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO WARRANTY OF ANY
+ * KIND (EXPRESS, IMPLIED OR STATUTORY) WITH RESPECT TO THIS INFORMATION,
+ * AND EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+ * ************************************************************************
+ */
+
+/*
+ * Changes made for OpenOffice.org
+ *
+ * 10/24/2000 pl - changed code to compile with c++-compilers
+ * - added namespace to avoid symbol clashes
+ * - replaced BOOL by bool
+ * - added function to free space allocated by parseFile
+ * 10/26/2000 pl - added additional keys
+ * - added ability to parse slightly broken files
+ * - added charwidth member to GlobalFontInfo
+ * 04/26/2001 pl - added OpenOffice header
+ * 10/19/2005 pl - performance increase:
+ * - fread file in one pass
+ * - replace file io by buffer access
+ * 10/20/2005 pl - performance increase:
+ * - use one table lookup in token() routine
+ * instead of many conditions
+ * - return token length in toke() routine
+ * - use hash lookup instead of binary search
+ * in recognize() routine
+ */
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+/* parseAFM.c
+ *
+ * This file is used in conjuction with the parseAFM.h header file.
+ * This file contains several procedures that are used to parse AFM
+ * files. It is intended to work with an application program that needs
+ * font metric information. The program can be used as is by making a
+ * procedure call to "parseFile" (passing in the expected parameters)
+ * and having it fill in a data structure with the data from the
+ * AFM file, or an application developer may wish to customize this
+ * code.
+ *
+ * There is also a file, parseAFMclient.c, that is a sample application
+ * showing how to call the "parseFile" procedure and how to use the data
+ * after "parseFile" has returned.
+ *
+ * Please read the comments in parseAFM.h and parseAFMclient.c.
+ *
+ * History:
+ * original: DSM Thu Oct 20 17:39:59 PDT 1988
+ * modified: DSM Mon Jul 3 14:17:50 PDT 1989
+ * - added 'storageProblem' return code
+ * - fixed bug of not allocating extra byte for string duplication
+ * - fixed typos
+ * modified: DSM Tue Apr 3 11:18:34 PDT 1990
+ * - added free(ident) at end of parseFile routine
+ * modified: DSM Tue Jun 19 10:16:29 PDT 1990
+ * - changed (width == 250) to (width = 250) in initializeArray
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <math.h>
+
+#include "parseAFM.hxx"
+#include "vcl/strhelper.hxx"
+
+#include "rtl/alloc.h"
+
+#define lineterm EOL /* line terminating character */
+#define normalEOF 1 /* return code from parsing routines used only */
+/* in this module */
+#define Space "space" /* used in string comparison to look for the width */
+/* of the space character to init the widths array */
+#define False "false" /* used in string comparison to check the value of */
+/* boolean keys (e.g. IsFixedPitch) */
+
+#define MATCH(A,B) (strncmp((A),(B), MAX_NAME) == 0)
+
+namespace psp {
+
+class FileInputStream
+{
+ char* m_pMemory;
+ unsigned int m_nPos;
+ unsigned int m_nLen;
+ public:
+ FileInputStream( const char* pFilename );
+ ~FileInputStream();
+
+ int getChar() { return (m_nPos < m_nLen) ? int(m_pMemory[m_nPos++]) : -1; }
+ void ungetChar()
+ {
+ if( m_nPos > 0 )
+ m_nPos--;
+ }
+ unsigned int tell() const { return m_nPos; }
+ void seek( unsigned int nPos )
+ // NOTE: do not check input data since only results of tell()
+ // get seek()ed in this file
+ { m_nPos = nPos; }
+};
+
+FileInputStream::FileInputStream( const char* pFilename ) :
+ m_pMemory( NULL ),
+ m_nPos( 0 ),
+ m_nLen( 0 )
+{
+ struct stat aStat;
+ if( ! stat( pFilename, &aStat ) &&
+ S_ISREG( aStat.st_mode ) &&
+ aStat.st_size > 0
+ )
+ {
+ FILE* fp = fopen( pFilename, "r" );
+ if( fp )
+ {
+ m_pMemory = (char*)rtl_allocateMemory( aStat.st_size );
+ m_nLen = (unsigned int)fread( m_pMemory, 1, aStat.st_size, fp );
+ fclose( fp );
+ }
+ }
+}
+
+FileInputStream::~FileInputStream()
+{
+ rtl_freeMemory( m_pMemory );
+}
+
+/*************************** GLOBALS ***********************/
+/* "shorts" for fast case statement
+ * The values of each of these enumerated items correspond to an entry in the
+ * table of strings defined below. Therefore, if you add a new string as
+ * new keyword into the keyStrings table, you must also add a corresponding
+ * parseKey AND it MUST be in the same position!
+ *
+ * IMPORTANT: since the sorting algorithm is a binary search, the strings of
+ * keywords must be placed in lexicographical order, below. [Therefore, the
+ * enumerated items are not necessarily in lexicographical order, depending
+ * on the name chosen. BUT, they must be placed in the same position as the
+ * corresponding key string.] The NOPE shall remain in the last position,
+ * since it does not correspond to any key string, and it is used in the
+ * "recognize" procedure to calculate how many possible keys there are.
+ */
+
+// some metrics have Ascent, Descent instead Ascender, Descender or Em
+// which is not allowed per afm spcification, but let us handle
+// this gently
+enum parseKey {
+ ASCENDER, ASCENT, CHARBBOX, CODE, COMPCHAR, CODEHEX, CAPHEIGHT, CHARWIDTH, CHARACTERSET, CHARACTERS, COMMENT,
+ DESCENDER, DESCENT, EM, ENCODINGSCHEME, ENDCHARMETRICS, ENDCOMPOSITES, ENDDIRECTION,
+ ENDFONTMETRICS, ENDKERNDATA, ENDKERNPAIRS, ENDTRACKKERN,
+ FAMILYNAME, FONTBBOX, FONTNAME, FULLNAME, ISBASEFONT, ISFIXEDPITCH,
+ ITALICANGLE, KERNPAIR, KERNPAIRXAMT, LIGATURE, MAPPINGSCHEME, METRICSSETS, CHARNAME,
+ NOTICE, COMPCHARPIECE, STARTCHARMETRICS, STARTCOMPOSITES, STARTDIRECTION,
+ STARTFONTMETRICS, STARTKERNDATA, STARTKERNPAIRS,
+ STARTTRACKKERN, STDHW, STDVW, TRACKKERN, UNDERLINEPOSITION,
+ UNDERLINETHICKNESS, VVECTOR, VERSION, XYWIDTH, X0WIDTH, XWIDTH, WEIGHT, XHEIGHT,
+ NOPE
+};
+
+/*************************** PARSING ROUTINES **************/
+
+/*************************** token *************************/
+
+/* A "AFM file Conventions" tokenizer. That means that it will
+ * return the next token delimited by white space. See also
+ * the `linetoken' routine, which does a similar thing but
+ * reads all tokens until the next end-of-line.
+ */
+
+// token white space is ' ', '\n', '\r', ',', '\t', ';'
+static const bool is_white_Array[ 256 ] =
+{ false, false, false, false, false, false, false, false, // 0-7
+ false, true, true, false, false, true, false, false, // 8-15
+ false, false, false, false, false, false, false, false, // 16-23
+ false, false, false, false, false, false, false, false, // 24-31
+ true, false, false, false, false, false, false, false, // 32-39
+ false, false, false, false, true, false, false, false, // 40-47
+ false, false, false, false, false, false, false, false, // 48-55
+ false, false, false, true, false, false, false, false, // 56-63
+
+ false, false, false, false, false, false, false, false, // 64 -
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, // 127
+
+ false, false, false, false, false, false, false, false, // 128 -
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, // 191
+
+ false, false, false, false, false, false, false, false, // 192 -
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, // 255
+};
+// token delimiters are ' ', '\n', '\r', '\t', ':', ';'
+static const bool is_delimiter_Array[ 256 ] =
+{ false, false, false, false, false, false, false, false, // 0-7
+ false, true, true, false, false, true, false, false, // 8-15
+ false, false, false, false, false, false, false, false, // 16-23
+ false, false, false, false, false, false, false, false, // 24-31
+ true, false, false, false, false, false, false, false, // 32-39
+ false, false, false, false, false, false, false, false, // 40-47
+ false, false, false, false, false, false, false, false, // 48-55
+ false, false, true, true, false, false, false, false, // 56-63
+
+ false, false, false, false, false, false, false, false, // 64 -
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, // 127
+
+ false, false, false, false, false, false, false, false, // 128 -
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, // 191
+
+ false, false, false, false, false, false, false, false, // 192 -
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, // 255
+};
+static char *token( FileInputStream* stream, int& rLen )
+{
+ static char ident[MAX_NAME]; /* storage buffer for keywords */
+
+ int ch, idx;
+
+ /* skip over white space */
+ // relies on EOF = -1
+ while( is_white_Array[ (ch = stream->getChar()) & 255 ] )
+ ;
+
+ idx = 0;
+ while( ch != -1 && ! is_delimiter_Array[ ch & 255 ] && idx < MAX_NAME-1 )
+ {
+ ident[idx++] = ch;
+ ch = stream->getChar();
+ }
+
+ if (ch == -1 && idx < 1) return ((char *)NULL);
+ if (idx >= 1 && ch != ':' && ch != -1) stream->ungetChar();
+ if (idx < 1 ) ident[idx++] = ch; /* single-character token */
+ ident[idx] = 0;
+ rLen = idx;
+
+ return(ident); /* returns pointer to the token */
+
+} /* token */
+
+
+/*************************** linetoken *************************/
+
+/* "linetoken" will get read all tokens until the EOL character from
+ * the given stream. This is used to get any arguments that can be
+ * more than one word (like Comment lines and FullName).
+ */
+
+static char *linetoken( FileInputStream* stream )
+{
+ static char ident[MAX_NAME]; /* storage buffer for keywords */
+ int ch, idx;
+
+ while ((ch = stream->getChar()) == ' ' || ch == '\t' ) ;
+
+ idx = 0;
+ while (ch != -1 && ch != lineterm && ch != '\r' && idx < MAX_NAME-1 )
+ {
+ ident[idx++] = ch;
+ ch = stream->getChar();
+ } /* while */
+
+ stream->ungetChar();
+ ident[idx] = 0;
+
+ return(ident); /* returns pointer to the token */
+
+} /* linetoken */
+
+
+/*************************** recognize *************************/
+
+/* This function tries to match a string to a known list of
+ * valid AFM entries (check the keyStrings array above).
+ * "ident" contains everything from white space through the
+ * next space, tab, or ":" character.
+ *
+ * The algorithm is a standard Knuth binary search.
+ */
+#include "afm_hash.cpp"
+
+static inline enum parseKey recognize( register char* ident, int len)
+{
+ const hash_entry* pEntry = AfmKeywordHash::in_word_set( ident, len );
+ return pEntry ? pEntry->eKey : NOPE;
+
+} /* recognize */
+
+
+/************************* parseGlobals *****************************/
+
+/* This function is called by "parseFile". It will parse the AFM file
+ * up to the "StartCharMetrics" keyword, which essentially marks the
+ * end of the Global Font Information and the beginning of the character
+ * metrics information.
+ *
+ * If the caller of "parseFile" specified that it wanted the Global
+ * Font Information (as defined by the "AFM file Specification"
+ * document), then that information will be stored in the returned
+ * data structure.
+ *
+ * Any Global Font Information entries that are not found in a
+ * given file, will have the usual default initialization value
+ * for its type (i.e. entries of type int will be 0, etc).
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parseGlobals( FileInputStream* fp, register GlobalFontInfo* gfi )
+{
+ bool cont = true, save = (gfi != NULL);
+ int error = ok;
+ register char *keyword;
+ int direction = -1;
+ int tokenlen;
+
+ while (cont)
+ {
+ keyword = token(fp, tokenlen);
+
+ if (keyword == NULL)
+ /* Have reached an early and unexpected EOF. */
+ /* Set flag and stop parsing */
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ if (!save)
+ /* get tokens until the end of the Global Font info section */
+ /* without saving any of the data */
+ switch (recognize(keyword, tokenlen))
+ {
+ case STARTCHARMETRICS:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ default:
+ break;
+ } /* switch */
+ else
+ /* otherwise parse entire global font info section, */
+ /* saving the data */
+ switch(recognize(keyword, tokenlen))
+ {
+ case STARTFONTMETRICS:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->afmVersion = strdup( keyword );
+ break;
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case FONTNAME:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->fontName = strdup( keyword );
+ break;
+ case ENCODINGSCHEME:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->encodingScheme = strdup( keyword );
+ break;
+ case FULLNAME:
+ if ((keyword = linetoken(fp)) != NULL)
+ gfi->fullName = strdup( keyword );
+ break;
+ case FAMILYNAME:
+ if ((keyword = linetoken(fp)) != NULL)
+ gfi->familyName = strdup( keyword );
+ break;
+ case WEIGHT:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->weight = strdup( keyword );
+ break;
+ case ITALICANGLE:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->italicAngle = StringToDouble( keyword );
+ break;
+ case ISFIXEDPITCH:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ {
+ if (MATCH(keyword, False))
+ gfi->isFixedPitch = 0;
+ else
+ gfi->isFixedPitch = 1;
+ }
+ break;
+ case UNDERLINEPOSITION:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->underlinePosition = atoi(keyword);
+ break;
+ case UNDERLINETHICKNESS:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->underlineThickness = atoi(keyword);
+ break;
+ case VERSION:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->version = strdup( keyword );
+ break;
+ case NOTICE:
+ if ((keyword = linetoken(fp)) != NULL)
+ gfi->notice = strdup( keyword );
+ break;
+ case FONTBBOX:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->fontBBox.llx = atoi(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->fontBBox.lly = atoi(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->fontBBox.urx = atoi(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->fontBBox.ury = atoi(keyword);
+ break;
+ case CAPHEIGHT:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->capHeight = atoi(keyword);
+ break;
+ case XHEIGHT:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->xHeight = atoi(keyword);
+ break;
+ case DESCENT:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->descender = -atoi(keyword);
+ break;
+ case DESCENDER:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->descender = atoi(keyword);
+ break;
+ case ASCENT:
+ case ASCENDER:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ gfi->ascender = atoi(keyword);
+ break;
+ case STARTCHARMETRICS:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case EM:
+ // skip one token
+ keyword = token(fp,tokenlen);
+ break;
+ case STARTDIRECTION:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ direction = atoi(keyword);
+ break; /* ignore this for now */
+ case ENDDIRECTION:
+ break; /* ignore this for now */
+ case MAPPINGSCHEME:
+ keyword = token(fp,tokenlen);
+ break; /* ignore this for now */
+ case CHARACTERS:
+ keyword = token(fp,tokenlen);
+ break; /* ignore this for now */
+ case ISBASEFONT:
+ keyword = token(fp,tokenlen);
+ break; /* ignore this for now */
+ case CHARACTERSET:
+ keyword=token(fp,tokenlen); //ignore
+ break;
+ case STDHW:
+ keyword=token(fp,tokenlen); //ignore
+ break;
+ case STDVW:
+ keyword=token(fp,tokenlen); //ignore
+ break;
+ case CHARWIDTH:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ {
+ if (direction == 0)
+ gfi->charwidth = atoi(keyword);
+ }
+ keyword = token(fp,tokenlen);
+ /* ignore y-width for now */
+ break;
+ case METRICSSETS:
+ keyword = token(fp,tokenlen);
+ break; /* ignore this for now */
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ return(error);
+
+} /* parseGlobals */
+
+
+#if 0
+/************************* initializeArray ************************/
+
+/* Unmapped character codes are (at Adobe Systems) assigned the
+ * width of the space character (if one exists) else they get the
+ * value of 250 ems. This function initializes all entries in the
+ * char widths array to have this value. Then any mapped character
+ * codes will be replaced with the width of the appropriate character
+ * when parsing the character metric section.
+
+ * This function parses the Character Metrics Section looking
+ * for a space character (by comparing character names). If found,
+ * the width of the space character will be used to initialize the
+ * values in the array of character widths.
+ *
+ * Before returning, the position of the read/write pointer of the
+ * FileInputStream is reset to be where it was upon entering this function.
+ */
+
+static int initializeArray( FileInputStream* fp, register int* cwi)
+{
+ bool cont = true, found = false;
+ unsigned int opos = fp->tell();
+ int code = 0, width = 0, i = 0, error = 0, tokenlen;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp,tokenlen);
+ if (keyword == NULL)
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ switch(recognize(keyword,tokenlen))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case CODE:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ code = atoi(keyword);
+ break;
+ case CODEHEX:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ sscanf(keyword,"<%x>", &code);
+ break;
+ case XWIDTH:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ width = atoi(keyword);
+ break;
+ case X0WIDTH:
+ (void) token(fp,tokenlen);
+ break;
+ case CHARNAME:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ if (MATCH(keyword, Space))
+ {
+ cont = false;
+ found = true;
+ }
+ break;
+ case ENDCHARMETRICS:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ if (!found)
+ width = 250;
+
+ for (i = 0; i < 256; ++i)
+ cwi[i] = width;
+
+ fp->seek(opos);
+
+ return(error);
+
+} /* initializeArray */
+#endif
+
+/************************* parseCharWidths **************************/
+
+/* This function is called by "parseFile". It will parse the AFM file
+ * up to the "EndCharMetrics" keyword. It will save the character
+ * width info (as opposed to all of the character metric information)
+ * if requested by the caller of parseFile. Otherwise, it will just
+ * parse through the section without saving any information.
+ *
+ * If data is to be saved, parseCharWidths is passed in a pointer
+ * to an array of widths that has already been initialized by the
+ * standard value for unmapped character codes. This function parses
+ * the Character Metrics section only storing the width information
+ * for the encoded characters into the array using the character code
+ * as the index into that array.
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parseCharWidths( FileInputStream* fp, register int* cwi)
+{
+ bool cont = true, save = (cwi != NULL);
+ int pos = 0, error = ok, tokenlen;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp,tokenlen);
+ /* Have reached an early and unexpected EOF. */
+ /* Set flag and stop parsing */
+ if (keyword == NULL)
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ if (!save)
+ /* get tokens until the end of the Char Metrics section without */
+ /* saving any of the data*/
+ switch (recognize(keyword,tokenlen))
+ {
+ case ENDCHARMETRICS:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ default:
+ break;
+ } /* switch */
+ else
+ /* otherwise parse entire char metrics section, saving */
+ /* only the char x-width info */
+ switch(recognize(keyword,tokenlen))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case CODE:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ pos = atoi(keyword);
+ break;
+ case XYWIDTH:
+ /* PROBLEM: Should be no Y-WIDTH when doing "quick & dirty" */
+ keyword = token(fp,tokenlen); keyword = token(fp,tokenlen); /* eat values */
+ error = parseError;
+ break;
+ case CODEHEX:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ sscanf(keyword, "<%x>", &pos);
+ break;
+ case X0WIDTH:
+ (void) token(fp,tokenlen);
+ break;
+ case XWIDTH:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ if (pos >= 0) /* ignore unmapped chars */
+ cwi[pos] = atoi(keyword);
+ break;
+ case ENDCHARMETRICS:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case CHARNAME: /* eat values (so doesn't cause parseError) */
+ keyword = token(fp,tokenlen);
+ break;
+ case CHARBBOX:
+ keyword = token(fp,tokenlen); keyword = token(fp,tokenlen);
+ keyword = token(fp,tokenlen); keyword = token(fp,tokenlen);
+ break;
+ case LIGATURE:
+ keyword = token(fp,tokenlen); keyword = token(fp,tokenlen);
+ break;
+ case VVECTOR:
+ keyword = token(fp,tokenlen);
+ keyword = token(fp,tokenlen);
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ return(error);
+
+} /* parseCharWidths */
+
+
+/*
+ * number of char metrics is almost allways inaccurate, so be gentle and try to
+ * adapt our internal storage by adjusting the allocated list
+ */
+
+static int
+reallocFontMetrics( void **pp_fontmetrics, int *p_oldcount, int n_newcount, unsigned int n_size )
+{
+ char *p_tmpmetrics = NULL;
+
+ if ((pp_fontmetrics == NULL) || (*pp_fontmetrics == NULL))
+ return storageProblem;
+
+ if (*p_oldcount == n_newcount)
+ return ok;
+
+ p_tmpmetrics = (char*)realloc(*pp_fontmetrics, n_newcount * n_size);
+ if (p_tmpmetrics == NULL)
+ return storageProblem;
+
+ if ( n_newcount > *p_oldcount )
+ {
+ char *p_inimetrics = p_tmpmetrics + n_size * *p_oldcount;
+ int n_inimetrics = n_size * (n_newcount - *p_oldcount);
+ memset( p_inimetrics, 0, n_inimetrics );
+ }
+
+ *pp_fontmetrics = p_tmpmetrics;
+ *p_oldcount = n_newcount;
+
+ return ok;
+}
+
+static unsigned int
+enlargeCount( unsigned int n_oldcount )
+{
+ unsigned int n_newcount = n_oldcount + n_oldcount / 5;
+ if (n_oldcount == n_newcount )
+ n_newcount = n_oldcount + 5;
+
+ return n_newcount;
+}
+
+/************************* parseCharMetrics ************************/
+
+/* This function is called by parseFile if the caller of parseFile
+ * requested that all character metric information be saved
+ * (as opposed to only the character width information).
+ *
+ * parseCharMetrics is passed in a pointer to an array of records
+ * to hold information on a per character basis. This function
+ * parses the Character Metrics section storing all character
+ * metric information for the ALL characters (mapped and unmapped)
+ * into the array.
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parseCharMetrics( FileInputStream* fp, register FontInfo* fi)
+{
+ bool cont = true, firstTime = true;
+ int error = ok, count = 0, tokenlen;
+ register CharMetricInfo *temp = fi->cmi;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp,tokenlen);
+ if (keyword == NULL)
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ switch(recognize(keyword,tokenlen))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case CODE:
+ if (!(count < fi->numOfChars))
+ {
+ reallocFontMetrics( (void**)&(fi->cmi),
+ &(fi->numOfChars), enlargeCount(fi->numOfChars),
+ sizeof(CharMetricInfo) );
+ temp = &(fi->cmi[ count - 1 ]);
+ }
+ if (count < fi->numOfChars)
+ {
+ if (firstTime) firstTime = false;
+ else temp++;
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ temp->code = atoi(keyword);
+ if (fi->gfi && fi->gfi->charwidth)
+ temp->wx = fi->gfi->charwidth;
+ count++;
+ }
+ else
+ {
+ error = parseError;
+ cont = false;
+ }
+ break;
+ case CODEHEX:
+ if (!(count < fi->numOfChars ))
+ {
+ reallocFontMetrics( (void**)&(fi->cmi),
+ &(fi->numOfChars), enlargeCount(fi->numOfChars),
+ sizeof(CharMetricInfo) );
+ temp = &(fi->cmi[ count - 1 ]);
+ }
+ if (count < fi->numOfChars) {
+ if (firstTime)
+ firstTime = false;
+ else
+ temp++;
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ sscanf(keyword,"<%x>", &temp->code);
+ if (fi->gfi && fi->gfi->charwidth)
+ temp->wx = fi->gfi->charwidth;
+ count++;
+ }
+ else {
+ error = parseError;
+ cont = false;
+ }
+ break;
+ case XYWIDTH:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ temp->wx = atoi(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ temp->wy = atoi(keyword);
+ break;
+ case X0WIDTH:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ temp->wx = atoi(keyword);
+ break;
+ case XWIDTH:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ temp->wx = atoi(keyword);
+ break;
+ case CHARNAME:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ temp->name = (char *)strdup(keyword);
+ break;
+ case CHARBBOX:
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ temp->charBBox.llx = atoi(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ temp->charBBox.lly = atoi(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ temp->charBBox.urx = atoi(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ temp->charBBox.ury = atoi(keyword);
+ break;
+ case LIGATURE: {
+ Ligature **tail = &(temp->ligs);
+ Ligature *node = *tail;
+
+ if (*tail != NULL)
+ {
+ while (node->next != NULL)
+ node = node->next;
+ tail = &(node->next);
+ }
+
+ *tail = (Ligature *) calloc(1, sizeof(Ligature));
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ (*tail)->succ = (char *)strdup(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ (*tail)->lig = (char *)strdup(keyword);
+ break; }
+ case ENDCHARMETRICS:
+ cont = false;;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case VVECTOR:
+ keyword = token(fp,tokenlen);
+ keyword = token(fp,tokenlen);
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ if ((error == ok) && (count != fi->numOfChars))
+ error = reallocFontMetrics( (void**)&(fi->cmi), &(fi->numOfChars),
+ count, sizeof(CharMetricInfo) );
+
+ if ((error == ok) && (count != fi->numOfChars))
+ error = parseError;
+
+ return(error);
+
+} /* parseCharMetrics */
+
+
+
+/************************* parseTrackKernData ***********************/
+
+/* This function is called by "parseFile". It will parse the AFM file
+ * up to the "EndTrackKern" or "EndKernData" keywords. It will save the
+ * track kerning data if requested by the caller of parseFile.
+ *
+ * parseTrackKernData is passed in a pointer to the FontInfo record.
+ * If data is to be saved, the FontInfo record will already contain
+ * a valid pointer to storage for the track kerning data.
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parseTrackKernData( FileInputStream* fp, register FontInfo* fi)
+{
+ bool cont = true, save = (fi->tkd != NULL);
+ int pos = 0, error = ok, tcount = 0, tokenlen;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp,tokenlen);
+
+ if (keyword == NULL)
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ if (!save)
+ /* get tokens until the end of the Track Kerning Data */
+ /* section without saving any of the data */
+ switch(recognize(keyword,tokenlen))
+ {
+ case ENDTRACKKERN:
+ case ENDKERNDATA:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ default:
+ break;
+ } /* switch */
+ else
+ /* otherwise parse entire Track Kerning Data section, */
+ /* saving the data */
+ switch(recognize(keyword,tokenlen))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case TRACKKERN:
+ if (!(tcount < fi->numOfTracks))
+ {
+ reallocFontMetrics( (void**)&(fi->tkd), &(fi->numOfTracks),
+ enlargeCount(fi->numOfTracks), sizeof(TrackKernData) );
+ }
+
+ if (tcount < fi->numOfTracks)
+ {
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->tkd[pos].degree = atoi(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->tkd[pos].minPtSize = StringToDouble(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->tkd[pos].minKernAmt = StringToDouble(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->tkd[pos].maxPtSize = StringToDouble(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->tkd[pos++].maxKernAmt = StringToDouble(keyword);
+ tcount++;
+ }
+ else
+ {
+ error = parseError;
+ cont = false;
+ }
+ break;
+ case ENDTRACKKERN:
+ case ENDKERNDATA:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ if (error == ok && tcount != fi->numOfTracks)
+ error = reallocFontMetrics( (void**)&(fi->tkd), &(fi->numOfTracks),
+ tcount, sizeof(TrackKernData) );
+
+ if (error == ok && tcount != fi->numOfTracks)
+ error = parseError;
+
+ return(error);
+
+} /* parseTrackKernData */
+
+
+/************************* parsePairKernData ************************/
+
+/* This function is called by "parseFile". It will parse the AFM file
+ * up to the "EndKernPairs" or "EndKernData" keywords. It will save
+ * the pair kerning data if requested by the caller of parseFile.
+ *
+ * parsePairKernData is passed in a pointer to the FontInfo record.
+ * If data is to be saved, the FontInfo record will already contain
+ * a valid pointer to storage for the pair kerning data.
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parsePairKernData( FileInputStream* fp, register FontInfo* fi)
+{
+ bool cont = true, save = (fi->pkd != NULL);
+ int pos = 0, error = ok, pcount = 0, tokenlen;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp,tokenlen);
+
+ if (keyword == NULL)
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ if (!save)
+ /* get tokens until the end of the Pair Kerning Data */
+ /* section without saving any of the data */
+ switch(recognize(keyword,tokenlen))
+ {
+ case ENDKERNPAIRS:
+ case ENDKERNDATA:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ default:
+ break;
+ } /* switch */
+ else
+ /* otherwise parse entire Pair Kerning Data section, */
+ /* saving the data */
+ switch(recognize(keyword,tokenlen))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case KERNPAIR:
+ if (!(pcount < fi->numOfPairs))
+ {
+ reallocFontMetrics( (void**)&(fi->pkd), &(fi->numOfPairs),
+ enlargeCount(fi->numOfPairs), sizeof(PairKernData) );
+ }
+ if (pcount < fi->numOfPairs)
+ {
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->pkd[pos].name1 = strdup( keyword );
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->pkd[pos].name2 = strdup( keyword );
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->pkd[pos].xamt = atoi(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->pkd[pos++].yamt = atoi(keyword);
+ pcount++;
+ }
+ else
+ {
+ error = parseError;
+ cont = false;
+ }
+ break;
+ case KERNPAIRXAMT:
+ if (!(pcount < fi->numOfPairs))
+ {
+ reallocFontMetrics( (void**)&(fi->pkd), &(fi->numOfPairs),
+ enlargeCount(fi->numOfPairs), sizeof(PairKernData) );
+ }
+ if (pcount < fi->numOfPairs)
+ {
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->pkd[pos].name1 = strdup( keyword );
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->pkd[pos].name2 = strdup( keyword );
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->pkd[pos++].xamt = atoi(keyword);
+ pcount++;
+ }
+ else
+ {
+ error = parseError;
+ cont = false;
+ }
+ break;
+ case ENDKERNPAIRS:
+ case ENDKERNDATA:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ if ((error == ok) && (pcount != fi->numOfPairs))
+ error = reallocFontMetrics( (void**)&(fi->pkd), &(fi->numOfPairs),
+ pcount, sizeof(PairKernData) );
+
+ if (error == ok && pcount != fi->numOfPairs)
+ error = parseError;
+
+ return(error);
+
+} /* parsePairKernData */
+
+
+/************************* parseCompCharData **************************/
+
+/* This function is called by "parseFile". It will parse the AFM file
+ * up to the "EndComposites" keyword. It will save the composite
+ * character data if requested by the caller of parseFile.
+ *
+ * parseCompCharData is passed in a pointer to the FontInfo record, and
+ * a boolean representing if the data should be saved.
+ *
+ * This function will create the appropriate amount of storage for
+ * the composite character data and store a pointer to the storage
+ * in the FontInfo record.
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parseCompCharData( FileInputStream* fp, register FontInfo* fi)
+{
+ bool cont = true, firstTime = true, save = (fi->ccd != NULL);
+ int pos = 0, j = 0, error = ok, ccount = 0, pcount = 0, tokenlen;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp,tokenlen);
+ if (keyword == NULL)
+ /* Have reached an early and unexpected EOF. */
+ /* Set flag and stop parsing */
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ if (ccount > fi->numOfComps)
+ {
+ reallocFontMetrics( (void**)&(fi->ccd), &(fi->numOfComps),
+ enlargeCount(fi->numOfComps), sizeof(CompCharData) );
+ }
+ if (ccount > fi->numOfComps)
+ {
+ error = parseError;
+ break; /* get out of loop */
+ }
+ if (!save)
+ /* get tokens until the end of the Composite Character info */
+ /* section without saving any of the data */
+ switch(recognize(keyword,tokenlen))
+ {
+ case ENDCOMPOSITES:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case COMMENT:
+ case COMPCHAR:
+ keyword = linetoken(fp);
+ break;
+ default:
+ break;
+ } /* switch */
+ else
+ /* otherwise parse entire Composite Character info section, */
+ /* saving the data */
+ switch(recognize(keyword,tokenlen))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case COMPCHAR:
+ if (!(ccount < fi->numOfComps))
+ {
+ reallocFontMetrics( (void**)&(fi->ccd), &(fi->numOfComps),
+ enlargeCount(fi->numOfComps), sizeof(CompCharData) );
+ }
+ if (ccount < fi->numOfComps)
+ {
+ keyword = token(fp,tokenlen);
+ if (pcount != fi->ccd[pos].numOfPieces)
+ error = parseError;
+ pcount = 0;
+ if (firstTime) firstTime = false;
+ else pos++;
+ fi->ccd[pos].ccName = strdup( keyword );
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->ccd[pos].numOfPieces = atoi(keyword);
+ fi->ccd[pos].pieces = (Pcc *)
+ calloc(fi->ccd[pos].numOfPieces, sizeof(Pcc));
+ j = 0;
+ ccount++;
+ }
+ else
+ {
+ error = parseError;
+ cont = false;
+ }
+ break;
+ case COMPCHARPIECE:
+ if (pcount < fi->ccd[pos].numOfPieces)
+ {
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->ccd[pos].pieces[j].pccName = strdup( keyword );
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->ccd[pos].pieces[j].deltax = atoi(keyword);
+ if ((keyword = token(fp,tokenlen)) != NULL)
+ fi->ccd[pos].pieces[j++].deltay = atoi(keyword);
+ pcount++;
+ }
+ else
+ error = parseError;
+ break;
+ case ENDCOMPOSITES:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ if (error == ok && ccount != fi->numOfComps)
+ reallocFontMetrics( (void**)&(fi->ccd), &(fi->numOfComps),
+ ccount, sizeof(CompCharData) );
+
+ if (error == ok && ccount != fi->numOfComps)
+ error = parseError;
+
+ return(error);
+
+} /* parseCompCharData */
+
+
+
+
+/*************************** 'PUBLIC' FUNCTION ********************/
+
+
+/*************************** parseFile *****************************/
+
+/* parseFile is the only 'public' procedure available. It is called
+ * from an application wishing to get information from an AFM file.
+ * The caller of this function is responsible for locating and opening
+ * an AFM file and handling all errors associated with that task.
+ *
+ * parseFile expects 3 parameters: a filename pointer, a pointer
+ * to a (FontInfo *) variable (for which storage will be allocated and
+ * the data requested filled in), and a mask specifying which
+ * data from the AFM file should be saved in the FontInfo structure.
+ *
+ * The file will be parsed and the requested data will be stored in
+ * a record of type FontInfo (refer to ParseAFM.h).
+ *
+ * parseFile returns an error code as defined in parseAFM.h.
+ *
+ * The position of the read/write pointer associated with the file
+ * pointer upon return of this function is undefined.
+ */
+
+int parseFile( const char* pFilename, FontInfo** fi, FLAGS flags)
+{
+ FileInputStream aFile( pFilename );
+
+ int code = ok; /* return code from each of the parsing routines */
+ int error = ok; /* used as the return code from this function */
+ int tokenlen;
+
+ register char *keyword; /* used to store a token */
+
+
+ (*fi) = (FontInfo *) calloc(1, sizeof(FontInfo));
+ if ((*fi) == NULL) {error = storageProblem; return(error);}
+
+ if (flags & P_G)
+ {
+ (*fi)->gfi = (GlobalFontInfo *) calloc(1, sizeof(GlobalFontInfo));
+ if ((*fi)->gfi == NULL) {error = storageProblem; return(error);}
+ }
+
+ /* The AFM file begins with Global Font Information. This section */
+ /* will be parsed whether or not information should be saved. */
+ code = parseGlobals(&aFile, (*fi)->gfi);
+
+ if (code < 0) error = code;
+
+ /* The Global Font Information is followed by the Character Metrics */
+ /* section. Which procedure is used to parse this section depends on */
+ /* how much information should be saved. If all of the metrics info */
+ /* is wanted, parseCharMetrics is called. If only the character widths */
+ /* is wanted, parseCharWidths is called. parseCharWidths will also */
+ /* be called in the case that no character data is to be saved, just */
+ /* to parse through the section. */
+
+ if ((code != normalEOF) && (code != earlyEOF))
+ {
+ if ((keyword = token(&aFile,tokenlen)) != NULL)
+ (*fi)->numOfChars = atoi(keyword);
+ if (flags & (P_M ^ P_W))
+ {
+ (*fi)->cmi = (CharMetricInfo *)
+ calloc((*fi)->numOfChars, sizeof(CharMetricInfo));
+ if ((*fi)->cmi == NULL) {error = storageProblem; return(error);}
+ code = parseCharMetrics(&aFile, *fi);
+ }
+ else
+ {
+ if (flags & P_W)
+ {
+ (*fi)->cwi = (int *) calloc(256, sizeof(int));
+ if ((*fi)->cwi == NULL)
+ {
+ error = storageProblem;
+ return(error);
+ }
+ }
+ /* parse section regardless */
+ code = parseCharWidths(&aFile, (*fi)->cwi);
+ } /* else */
+ } /* if */
+
+ if ((error != earlyEOF) && (code < 0)) error = code;
+
+ /* The remaining sections of the AFM are optional. This code will */
+ /* look at the next keyword in the file to determine what section */
+ /* is next, and then allocate the appropriate amount of storage */
+ /* for the data (if the data is to be saved) and call the */
+ /* appropriate parsing routine to parse the section. */
+
+ while ((code != normalEOF) && (code != earlyEOF))
+ {
+ keyword = token(&aFile,tokenlen);
+ if (keyword == NULL)
+ /* Have reached an early and unexpected EOF. */
+ /* Set flag and stop parsing */
+ {
+ code = earlyEOF;
+ break; /* get out of loop */
+ }
+ switch(recognize(keyword,tokenlen))
+ {
+ case STARTKERNDATA:
+ break;
+ case ENDKERNDATA:
+ break;
+ case STARTTRACKKERN:
+ keyword = token(&aFile,tokenlen);
+ if ((flags & P_T) && keyword)
+ {
+ (*fi)->numOfTracks = atoi(keyword);
+ (*fi)->tkd = (TrackKernData *)
+ calloc((*fi)->numOfTracks, sizeof(TrackKernData));
+ if ((*fi)->tkd == NULL)
+ {
+ error = storageProblem;
+ return(error);
+ }
+ } /* if */
+ code = parseTrackKernData(&aFile, *fi);
+ break;
+ case STARTKERNPAIRS:
+ keyword = token(&aFile,tokenlen);
+ if ((flags & P_P) && keyword)
+ {
+ (*fi)->numOfPairs = atoi(keyword);
+ (*fi)->pkd = (PairKernData *)
+ calloc((*fi)->numOfPairs, sizeof(PairKernData));
+ if ((*fi)->pkd == NULL)
+ {
+ error = storageProblem;
+ return(error);
+ }
+ } /* if */
+ code = parsePairKernData(&aFile, *fi);
+ break;
+ case STARTCOMPOSITES:
+ keyword = token(&aFile,tokenlen);
+ if ((flags & P_C) && keyword)
+ {
+ (*fi)->numOfComps = atoi(keyword);
+ (*fi)->ccd = (CompCharData *)
+ calloc((*fi)->numOfComps, sizeof(CompCharData));
+ if ((*fi)->ccd == NULL)
+ {
+ error = storageProblem;
+ return(error);
+ }
+ } /* if */
+ code = parseCompCharData(&aFile, *fi);
+ break;
+ case ENDFONTMETRICS:
+ code = normalEOF;
+ break;
+ case COMMENT:
+ linetoken(&aFile);
+ break;
+ case NOPE:
+ default:
+ code = parseError;
+ break;
+ } /* switch */
+
+ if ((error != earlyEOF) && (code < 0)) error = code;
+
+ } /* while */
+
+ if ((error != earlyEOF) && (code < 0)) error = code;
+
+ return(error);
+
+} /* parseFile */
+
+void
+freeFontInfo (FontInfo *fi)
+{
+ int i, j;
+
+ if (fi->gfi)
+ {
+ free (fi->gfi->afmVersion);
+ free (fi->gfi->fontName);
+ free (fi->gfi->fullName);
+ free (fi->gfi->familyName);
+ free (fi->gfi->weight);
+ free (fi->gfi->version);
+ free (fi->gfi->notice);
+ free (fi->gfi->encodingScheme);
+ free (fi->gfi);
+ }
+
+ free (fi->cwi);
+
+ if (fi->cmi)
+ {
+ for (i = 0; i < fi->numOfChars; i++)
+ {
+ Ligature *ligs;
+ free (fi->cmi[i].name);
+ ligs = fi->cmi[i].ligs;
+ while (ligs)
+ {
+ Ligature *tmp;
+ tmp = ligs;
+ ligs = ligs->next;
+ free (tmp->succ);
+ free (tmp->lig);
+ free (tmp);
+ }
+ }
+ free (fi->cmi);
+ }
+
+ free (fi->tkd);
+
+ if (fi->pkd)
+ {
+ for ( i = 0; i < fi->numOfPairs; i++)
+ {
+ free (fi->pkd[i].name1);
+ free (fi->pkd[i].name2);
+ }
+ free (fi->pkd);
+ }
+
+ if (fi->ccd)
+ {
+ for (i = 0; i < fi->numOfComps; i++)
+ {
+ free (fi->ccd[i].ccName);
+ for (j = 0; j < fi->ccd[i].numOfPieces; j++)
+ free (fi->ccd[i].pieces[j].pccName);
+
+ free (fi->ccd[i].pieces);
+ }
+ free (fi->ccd);
+ }
+
+ free (fi);
+}
+
+} // namspace
diff --git a/vcl/unx/source/fontmanager/parseAFM.hxx b/vcl/unx/source/fontmanager/parseAFM.hxx
new file mode 100644
index 000000000000..cfebde696c14
--- /dev/null
+++ b/vcl/unx/source/fontmanager/parseAFM.hxx
@@ -0,0 +1,334 @@
+/*
+ * (C) 1988, 1989 by Adobe Systems Incorporated. All rights reserved.
+ *
+ * This file may be freely copied and redistributed as long as:
+ * 1) This entire notice continues to be included in the file,
+ * 2) If the file has been modified in any way, a notice of such
+ * modification is conspicuously indicated.
+ *
+ * PostScript, Display PostScript, and Adobe are registered trademarks of
+ * Adobe Systems Incorporated.
+ *
+ * ************************************************************************
+ * THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO CHANGE WITHOUT
+ * NOTICE, AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY ADOBE SYSTEMS
+ * INCORPORATED. ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY OR
+ * LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO WARRANTY OF ANY
+ * KIND (EXPRESS, IMPLIED OR STATUTORY) WITH RESPECT TO THIS INFORMATION,
+ * AND EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+ * ************************************************************************
+ */
+
+/*
+ * Changes made for OpenOffice.org
+ *
+ * 10/24/2000 pl - changed code to compile with c++-compilers
+ * - added namespace to avoid symbol clashes
+ * - replaced BOOL by bool
+ * - added function to free space allocated by parseFile
+ * 10/26/2000 pl - added additional keys
+ * - added ability to parse slightly broken files
+ * - added charwidth member to GlobalFontInfo
+ * 04/26/2001 pl - added OpenOffice header
+ * 10/19/2005 pl - changed parseFile to accept a file name instead of a stream
+ */
+
+/* ParseAFM.h
+ *
+ * This header file is used in conjuction with the parseAFM.c file.
+ * Together these files provide the functionality to parse Adobe Font
+ * Metrics files and store the information in predefined data structures.
+ * It is intended to work with an application program that needs font metric
+ * information. The program can be used as is by making a procedure call to
+ * parse an AFM file and have the data stored, or an application developer
+ * may wish to customize the code.
+ *
+ * This header file defines the data structures used as well as the key
+ * strings that are currently recognized by this version of the AFM parser.
+ * This program is based on the document "Adobe Font Metrics Files,
+ * Specification Version 2.0".
+ *
+ * AFM files are separated into distinct sections of different data. Because
+ * of this, the parseAFM program can parse a specified file to only save
+ * certain sections of information based on the application's needs. A record
+ * containing the requested information will be returned to the application.
+ *
+ * AFM files are divided into five sections of data:
+ * 1) The Global Font Information
+ * 2) The Character Metrics Information
+ * 3) The Track Kerning Data
+ * 4) The Pair-Wise Kerning Data
+ * 5) The Composite Character Data
+ *
+ * Basically, the application can request any of these sections independent
+ * of what other sections are requested. In addition, in recognizing that
+ * many applications will want ONLY the x-width of characters and not all
+ * of the other character metrics information, there is a way to receive
+ * only the width information so as not to pay the storage cost for the
+ * unwanted data. An application should never request both the
+ * "quick and dirty" char metrics (widths only) and the Character Metrics
+ * Information since the Character Metrics Information will contain all
+ * of the character widths as well.
+ *
+ * There is a procedure in parseAFM.c, called parseFile, that can be
+ * called from any application wishing to get information from the AFM File.
+ * This procedure expects 3 parameters: a vaild file descriptor, a pointer
+ * to a (FontInfo *) variable (for which space will be allocated and then
+ * will be filled in with the data requested), and a mask specifying
+ * which data from the AFM File should be saved in the FontInfo structure.
+ *
+ * The flags that can be used to set the appropriate mask are defined below.
+ * In addition, several commonly used masks have already been defined.
+ *
+ * History:
+ * original: DSM Thu Oct 20 17:39:59 PDT 1988
+ * modified: DSM Mon Jul 3 14:17:50 PDT 1989
+ * - added 'storageProblem' return code
+ * - fixed typos
+ */
+
+#include <stdio.h>
+
+namespace psp {
+
+/* your basic constants */
+#define EOL '\n' /* end-of-line indicator */
+#define MAX_NAME 4096 /* max length for identifiers */
+#define FLAGS int
+
+
+
+/* Flags that can be AND'ed together to specify exactly what
+ * information from the AFM file should be saved.
+ */
+#define P_G 0x01 /* 0000 0001 */ /* Global Font Info */
+#define P_W 0x02 /* 0000 0010 */ /* Character Widths ONLY */
+#define P_M 0x06 /* 0000 0110 */ /* All Char Metric Info */
+#define P_P 0x08 /* 0000 1000 */ /* Pair Kerning Info */
+#define P_T 0x10 /* 0001 0000 */ /* Track Kerning Info */
+#define P_C 0x20 /* 0010 0000 */ /* Composite Char Info */
+
+
+/* Commonly used flags
+ */
+#define P_GW (P_G | P_W)
+#define P_GM (P_G | P_M)
+#define P_GMP (P_G | P_M | P_P)
+#define P_GMK (P_G | P_M | P_P | P_T)
+#define P_ALL (P_G | P_M | P_P | P_T | P_C)
+
+
+
+/* Possible return codes from the parseFile procedure.
+ *
+ * ok means there were no problems parsing the file.
+ *
+ * parseError means that there was some kind of parsing error, but the
+ * parser went on. This could include problems like the count for any given
+ * section does not add up to how many entries there actually were, or
+ * there was a key that was not recognized. The return record may contain
+ * vaild data or it may not.
+ *
+ * earlyEOF means that an End of File was encountered before expected. This
+ * may mean that the AFM file had been truncated, or improperly formed.
+ *
+ * storageProblem means that there were problems allocating storage for
+ * the data structures that would have contained the AFM data.
+ */
+
+enum afmError { ok = 0, parseError = -1, earlyEOF = -2, storageProblem = -3 };
+
+
+/************************* TYPES *********************************/
+/* Below are all of the data structure definitions. These structures
+ * try to map as closely as possible to grouping and naming of data
+ * in the AFM Files.
+ */
+
+
+/* Bounding box definition. Used for the Font BBox as well as the
+ * Character BBox.
+ */
+typedef struct
+{
+ int llx; /* lower left x-position */
+ int lly; /* lower left y-position */
+ int urx; /* upper right x-position */
+ int ury; /* upper right y-position */
+} BBox;
+
+
+/* Global Font information.
+ * The key that each field is associated with is in comments. For an
+ * explanation about each key and its value please refer to the AFM
+ * documentation (full title & version given above).
+ */
+typedef struct
+{
+ char *afmVersion; /* key: StartFontMetrics */
+ char *fontName; /* key: FontName */
+ char *fullName; /* key: FullName */
+ char *familyName; /* key: FamilyName */
+ char *weight; /* key: Weight */
+ float italicAngle; /* key: ItalicAngle */
+ bool isFixedPitch; /* key: IsFixedPitch */
+ BBox fontBBox; /* key: FontBBox */
+ int underlinePosition; /* key: UnderlinePosition */
+ int underlineThickness; /* key: UnderlineThickness */
+ char *version; /* key: Version */
+ char *notice; /* key: Notice */
+ char *encodingScheme; /* key: EncodingScheme */
+ int capHeight; /* key: CapHeight */
+ int xHeight; /* key: XHeight */
+ int ascender; /* key: Ascender */
+ int descender; /* key: Descender */
+ int charwidth; /* key: CharWidth */
+} GlobalFontInfo;
+
+
+/* Ligature definition is a linked list since any character can have
+ * any number of ligatures.
+ */
+typedef struct _t_ligature
+{
+ char *succ, *lig;
+ struct _t_ligature *next;
+} Ligature;
+
+
+/* Character Metric Information. This structure is used only if ALL
+ * character metric information is requested. If only the character
+ * widths is requested, then only an array of the character x-widths
+ * is returned.
+ *
+ * The key that each field is associated with is in comments. For an
+ * explanation about each key and its value please refer to the
+ * Character Metrics section of the AFM documentation (full title
+ * & version given above).
+ */
+typedef struct
+{
+ int code, /* key: C */
+ wx, /* key: WX */
+ w0x, /* key: W0X */
+ wy; /* together wx and wy are associated with key: W */
+ char *name; /* key: N */
+ BBox charBBox; /* key: B */
+ Ligature *ligs; /* key: L (linked list; not a fixed number of Ls */
+} CharMetricInfo;
+
+
+/* Track kerning data structure.
+ * The fields of this record are the five values associated with every
+ * TrackKern entry.
+ *
+ * For an explanation about each value please refer to the
+ * Track Kerning section of the AFM documentation (full title
+ * & version given above).
+ */
+typedef struct
+{
+ int degree;
+ float minPtSize,
+ minKernAmt,
+ maxPtSize,
+ maxKernAmt;
+} TrackKernData;
+
+
+/* Pair Kerning data structure.
+ * The fields of this record are the four values associated with every
+ * KP entry. For KPX entries, the yamt will be zero.
+ *
+ * For an explanation about each value please refer to the
+ * Pair Kerning section of the AFM documentation (full title
+ * & version given above).
+ */
+typedef struct
+{
+ char *name1;
+ char *name2;
+ int xamt,
+ yamt;
+} PairKernData;
+
+
+/* PCC is a piece of a composite character. This is a sub structure of a
+ * compCharData described below.
+ * These fields will be filled in with the values from the key PCC.
+ *
+ * For an explanation about each key and its value please refer to the
+ * Composite Character section of the AFM documentation (full title
+ * & version given above).
+ */
+typedef struct
+{
+ char *pccName;
+ int deltax,
+ deltay;
+} Pcc;
+
+
+/* Composite Character Information data structure.
+ * The fields ccName and numOfPieces are filled with the values associated
+ * with the key CC. The field pieces points to an array (size = numOfPieces)
+ * of information about each of the parts of the composite character. That
+ * array is filled in with the values from the key PCC.
+ *
+ * For an explanation about each key and its value please refer to the
+ * Composite Character section of the AFM documentation (full title
+ * & version given above).
+ */
+typedef struct
+{
+ char *ccName;
+ int numOfPieces;
+ Pcc *pieces;
+} CompCharData;
+
+
+/* FontInfo
+ * Record type containing pointers to all of the other data
+ * structures containing information about a font.
+ * A a record of this type is filled with data by the
+ * parseFile function.
+ */
+typedef struct
+{
+ GlobalFontInfo *gfi; /* ptr to a GlobalFontInfo record */
+ int *cwi; /* ptr to 256 element array of just char widths */
+ int numOfChars; /* number of entries in char metrics array */
+ CharMetricInfo *cmi; /* ptr to char metrics array */
+ int numOfTracks; /* number to entries in track kerning array */
+ TrackKernData *tkd; /* ptr to track kerning array */
+ int numOfPairs; /* number to entries in pair kerning array */
+ PairKernData *pkd; /* ptr to pair kerning array */
+ int numOfComps; /* number to entries in comp char array */
+ CompCharData *ccd; /* ptr to comp char array */
+} FontInfo;
+
+
+
+/************************* PROCEDURES ****************************/
+
+/* Call this procedure to do the grunt work of parsing an AFM file.
+ *
+ * "fp" should be a valid file pointer to an AFM file.
+ *
+ * "fi" is a pointer to a pointer to a FontInfo record sturcture
+ * (defined above). Storage for the FontInfo structure will be
+ * allocated in parseFile and the structure will be filled in
+ * with the requested data from the AFM File.
+ *
+ * "flags" is a mask with bits set representing what data should
+ * be saved. Defined above are valid flags that can be used to set
+ * the mask, as well as a few commonly used masks.
+ *
+ * The possible return codes from parseFile are defined above.
+ */
+
+int parseFile( const char* pFilename, FontInfo **fi, FLAGS flags );
+void freeFontInfo(FontInfo *fi);
+
+} // namespace
diff --git a/vcl/unx/source/gdi/cdeint.cxx b/vcl/unx/source/gdi/cdeint.cxx
new file mode 100644
index 000000000000..caa4867af874
--- /dev/null
+++ b/vcl/unx/source/gdi/cdeint.cxx
@@ -0,0 +1,241 @@
+/*************************************************************************
+ *
+ * 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 <ctype.h>
+#include <unistd.h>
+#include <salunx.h>
+#include <saldisp.hxx>
+#include <cdeint.hxx>
+#include <vcl/settings.hxx>
+
+#include <tools/stream.hxx>
+#include <tools/debug.hxx>
+
+CDEIntegrator::CDEIntegrator()
+{
+ meType = DtCDE;
+}
+
+CDEIntegrator::~CDEIntegrator()
+{
+}
+
+static int getHexDigit( const char c )
+{
+ if( c >= '0' && c <= '9' )
+ return (int)(c-'0');
+ else if( c >= 'a' && c <= 'f' )
+ return (int)(c-'a'+10);
+ else if( c >= 'A' && c <= 'F' )
+ return (int)(c-'A'+10);
+ return -1;
+}
+
+
+void CDEIntegrator::GetSystemLook( AllSettings& rSettings )
+{
+ static Color aColors[ 8 ];
+ static sal_Bool bRead = sal_False;
+ static sal_Bool bValid = sal_False;
+
+ if( ! bRead )
+ {
+ // get used palette from xrdb
+ char **ppStringList = 0;
+ int nStringCount;
+ XTextProperty aTextProperty;
+ aTextProperty.value = 0;
+ int i;
+
+ static Atom nResMgrAtom = XInternAtom( mpDisplay, "RESOURCE_MANAGER", False );
+
+ if( XGetTextProperty( mpDisplay,
+ RootWindow( mpDisplay, 0 ),
+ &aTextProperty,
+ nResMgrAtom )
+ && aTextProperty.value
+ && XTextPropertyToStringList( &aTextProperty, &ppStringList, &nStringCount )
+ )
+ {
+ // format of ColorPalette resource:
+ // *n*ColorPalette: palettefile
+
+ ByteString aLines;
+ for( i=0; i < nStringCount; i++ )
+ aLines += ppStringList[i];
+ for( i = aLines.GetTokenCount( '\n' )-1; i >= 0; i-- )
+ {
+ ByteString aLine = aLines.GetToken( i, '\n' );
+ int nIndex = aLine.Search( "ColorPalette" );
+ if( nIndex != STRING_NOTFOUND )
+ {
+ int nPos = nIndex;
+
+ nIndex+=12;
+ const char* pStr = aLine.GetBuffer() +nIndex;
+ while( *pStr && isspace( *pStr ) && *pStr != ':' )
+ {
+ pStr++;
+ nIndex++;
+ }
+ if( *pStr != ':' )
+ continue;
+ pStr++, nIndex++;
+ for( ; *pStr && isspace( *pStr ); pStr++, nIndex++ )
+ ;
+ if( ! *pStr )
+ continue;
+ int nIndex2 = nIndex;
+ for( ; *pStr && ! isspace( *pStr ); pStr++, nIndex2++ )
+ ;
+ ByteString aPaletteFile( aLine.Copy( nIndex, nIndex2 - nIndex ) );
+ // extract number before ColorPalette;
+ for( ; nPos >= 0 && aLine.GetChar( nPos ) != '*'; nPos-- )
+ ;
+ nPos--;
+ for( ; nPos >= 0 && aLine.GetChar( nPos ) != '*'; nPos-- )
+ ;
+ int nNumber = aLine.Copy( ++nPos ).ToInt32();
+
+ DBG_TRACE2( "found palette %d in resource \"%s\"", nNumber, aLine.GetBuffer() );
+
+ // found no documentation what this number actually means;
+ // might be the screen number. 0 seems to be the right one
+ // in most cases.
+ if( nNumber )
+ continue;
+
+ DBG_TRACE1( "Palette file is \"%s\".\n", aPaletteFile.GetBuffer() );
+
+ String aPath( aHomeDir );
+ aPath.AppendAscii( "/.dt/palettes/" );
+ aPath += String( aPaletteFile, gsl_getSystemTextEncoding() );
+
+ SvFileStream aStream( aPath, STREAM_READ );
+ if( ! aStream.IsOpen() )
+ {
+ aPath = String::CreateFromAscii( "/usr/dt/palettes/" );
+ aPath += String( aPaletteFile, gsl_getSystemTextEncoding() );
+ aStream.Open( aPath, STREAM_READ );
+ if( ! aStream.IsOpen() )
+ continue;
+ }
+
+ ByteString aBuffer;
+ for( nIndex = 0; nIndex < 8; nIndex++ )
+ {
+ aStream.ReadLine( aBuffer );
+ // format is "#RRRRGGGGBBBB"
+
+ DBG_TRACE1( "\t\"%s\".\n", aBuffer.GetBuffer() );
+
+ if( aBuffer.Len() )
+ {
+ const char* pArr = (const char*)aBuffer.GetBuffer()+1;
+ aColors[nIndex] = Color(
+ getHexDigit( pArr[1] )
+ | ( getHexDigit( pArr[0] ) << 4 ),
+ getHexDigit( pArr[5] )
+ | ( getHexDigit( pArr[4] ) << 4 ),
+ getHexDigit( pArr[9] )
+ | ( getHexDigit( pArr[8] ) << 4 )
+ );
+
+ DBG_TRACE1( "\t\t%lx\n", aColors[nIndex].GetColor() );
+ }
+ }
+
+ bValid = sal_True;
+ break;
+ }
+ }
+ }
+
+ if( ppStringList )
+ XFreeStringList( ppStringList );
+ if( aTextProperty.value )
+ XFree( aTextProperty.value );
+ }
+
+
+ StyleSettings aStyleSettings = rSettings.GetStyleSettings();
+ // #i48001# set a default blink rate
+ aStyleSettings.SetCursorBlinkTime( 500 );
+ if (bValid)
+ {
+ aStyleSettings.SetActiveColor( aColors[0] );
+ aStyleSettings.SetActiveColor2( aColors[0] );
+ aStyleSettings.SetActiveBorderColor( aColors[0] );
+
+ aStyleSettings.SetDeactiveColor( aColors[0] );
+ aStyleSettings.SetDeactiveColor2( aColors[0] );
+ aStyleSettings.SetDeactiveBorderColor( aColors[0] );
+
+ Color aActive =
+ aColors[ 0 ].GetBlue() < 128 ||
+ aColors[ 0 ].GetGreen() < 128 ||
+ aColors[ 0 ].GetRed() < 128
+ ? Color( COL_WHITE ) : Color( COL_BLACK );
+ Color aDeactive =
+ aColors[ 1 ].GetBlue() < 128 ||
+ aColors[ 1 ].GetGreen() < 128 ||
+ aColors[ 1 ].GetRed() < 128
+ ? Color( COL_WHITE ) : Color( COL_BLACK );
+ aStyleSettings.SetActiveTextColor( aActive );
+ aStyleSettings.SetDeactiveTextColor( aDeactive );
+
+ aStyleSettings.SetDialogTextColor( aDeactive );
+ aStyleSettings.SetMenuTextColor( aDeactive );
+ aStyleSettings.SetMenuBarTextColor( aDeactive );
+ aStyleSettings.SetButtonTextColor( aDeactive );
+ aStyleSettings.SetRadioCheckTextColor( aDeactive );
+ aStyleSettings.SetGroupTextColor( aDeactive );
+ aStyleSettings.SetLabelTextColor( aDeactive );
+ aStyleSettings.SetInfoTextColor( aDeactive );
+
+ aStyleSettings.Set3DColors( aColors[1] );
+ aStyleSettings.SetFaceColor( aColors[1] );
+ aStyleSettings.SetDialogColor( aColors[1] );
+ aStyleSettings.SetMenuColor( aColors[1] );
+ aStyleSettings.SetMenuBarColor( aColors[1] );
+ if ( aStyleSettings.GetFaceColor() == COL_LIGHTGRAY )
+ aStyleSettings.SetCheckedColor( Color( 0xCC, 0xCC, 0xCC ) );
+ else
+ {
+ // calculate Checked color
+ Color aColor2 = aStyleSettings.GetLightColor();
+ BYTE nRed = (BYTE)(((USHORT)aColors[1].GetRed() + (USHORT)aColor2.GetRed())/2);
+ BYTE nGreen = (BYTE)(((USHORT)aColors[1].GetGreen() + (USHORT)aColor2.GetGreen())/2);
+ BYTE nBlue = (BYTE)(((USHORT)aColors[1].GetBlue() + (USHORT)aColor2.GetBlue())/2);
+ aStyleSettings.SetCheckedColor( Color( nRed, nGreen, nBlue ) );
+ }
+ }
+ rSettings.SetStyleSettings( aStyleSettings );
+}
diff --git a/vcl/unx/source/gdi/dtint.cxx b/vcl/unx/source/gdi/dtint.cxx
new file mode 100644
index 000000000000..5f0dbd50ea17
--- /dev/null
+++ b/vcl/unx/source/gdi/dtint.cxx
@@ -0,0 +1,139 @@
+/*************************************************************************
+ *
+ * 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 <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dlfcn.h>
+
+#include <salunx.h>
+#include <X11/Xatom.h>
+
+#ifdef USE_CDE
+#include <cdeint.hxx>
+#endif
+#include <dtint.hxx>
+#include <saldisp.hxx>
+#include <saldata.hxx>
+#include <wmadaptor.hxx>
+
+#include <vcl/svapp.hxx>
+#include <dtsetenum.hxx>
+
+#include <osl/file.h>
+#include <osl/process.h>
+#include <osl/security.h>
+
+#include <set>
+#include <stdio.h>
+
+// NETBSD has no RTLD_GLOBAL
+#ifndef RTLD_GLOBAL
+#define DLOPEN_MODE (RTLD_LAZY)
+#else
+#define DLOPEN_MODE (RTLD_GLOBAL | RTLD_LAZY)
+#endif
+
+
+using namespace rtl;
+using namespace vcl_sal;
+
+String DtIntegrator::aHomeDir;
+
+DtIntegrator::DtIntegrator() :
+ meType( DtGeneric ),
+ mnSystemLookCommandProcess( -1 )
+{
+ mpSalDisplay = GetX11SalData()->GetDisplay();
+ mpDisplay = mpSalDisplay->GetDisplay();
+ OUString aDir;
+ oslSecurity aCur = osl_getCurrentSecurity();
+ if( aCur )
+ {
+ osl_getHomeDir( aCur, &aDir.pData );
+ osl_freeSecurityHandle( aCur );
+ OUString aSysDir;
+ osl_getSystemPathFromFileURL( aDir.pData, &aSysDir.pData );
+ aHomeDir = aSysDir;
+ }
+}
+
+DtIntegrator::~DtIntegrator()
+{
+}
+
+DtIntegrator* DtIntegrator::CreateDtIntegrator()
+{
+ /*
+ * #i22061# override desktop detection
+ * if environment variable OOO_FORCE_DESKTOP is set
+ * to one of "cde" "kde" "gnome" then autodetection
+ * is overridden.
+ */
+ static const char* pOverride = getenv( "OOO_FORCE_DESKTOP" );
+ if( pOverride && *pOverride )
+ {
+ OString aOver( pOverride );
+
+#if USE_CDE
+ if( aOver.equalsIgnoreAsciiCase( "cde" ) )
+ return new CDEIntegrator();
+#endif
+ if( aOver.equalsIgnoreAsciiCase( "none" ) )
+ return new DtIntegrator();
+ }
+
+#ifdef USE_CDE
+ void* pLibrary = NULL;
+
+ // check dt type
+ // CDE
+ SalDisplay* pSalDisplay = GetX11SalData()->GetDisplay();
+ Display* pDisplay = pSalDisplay->GetDisplay();
+ Atom nDtAtom = XInternAtom( pDisplay, "_DT_WM_READY", True );
+ if( nDtAtom && ( pLibrary = dlopen( "/usr/dt/lib/libDtSvc.so", DLOPEN_MODE ) ) )
+ {
+ dlclose( pLibrary );
+ return new CDEIntegrator();
+ }
+#endif
+
+ // default: generic implementation
+ return new DtIntegrator();
+}
+
+void DtIntegrator::GetSystemLook( AllSettings& rSettings )
+{
+ // #i48001# set a default blink rate
+ StyleSettings aStyleSettings = rSettings.GetStyleSettings();
+ aStyleSettings.SetCursorBlinkTime( 500 );
+ rSettings.SetStyleSettings( aStyleSettings );
+}
diff --git a/vcl/unx/source/gdi/dtsetenum.hxx b/vcl/unx/source/gdi/dtsetenum.hxx
new file mode 100644
index 000000000000..5406ac870a43
--- /dev/null
+++ b/vcl/unx/source/gdi/dtsetenum.hxx
@@ -0,0 +1,146 @@
+/*************************************************************************
+ *
+ * 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_DTSETENUM_HXX
+#define _VCL_DTSETENUM_HXX
+
+enum DtSetEnum
+{
+ /* settings for mouse */
+ MouseOptions = 1,
+ DoubleClickTime,
+ DoubleClickWidth,
+ DoubleClickHeight,
+ StartDragWidth,
+ StartDragHeight,
+ DragMoveCode,
+ DragCopyCode,
+ DragLinkCode,
+ ContextMenuCode,
+ ContextMenuClicks,
+ ContextMenuDown,
+ ScrollRepeat,
+ ButtonStartRepeat,
+ ButtonRepeat,
+ ActionDelay,
+ MenuDelay,
+ Follow,
+ MiddleButtonAction,
+ /* settings for keyboard */
+ KeyboardOptions=64,
+ /* style settings */
+ StyleOptions = 128,
+ BorderSize,
+ TitleHeight,
+ FloatTitleHeight,
+ TearOffTitleHeight,
+ MenuBarHeight,
+ ScrollBarSize,
+ SpinSize,
+ SplitSize,
+ IconHorzSpace,
+ IconVertSpace,
+ CursorSize,
+ CursorBlinkTime,
+ ScreenZoom,
+ ScreenFontZoom,
+ LogoDisplayTime,
+ DragFullOptions,
+ AnimationOptions,
+ SelectionOptions,
+ DisplayOptions,
+ AntialiasingMinPixelHeight,
+ /* style colors */
+ AllTextColors, /* convenience, sets all control text colors */
+ AllBackColors, /* convenience, sets all control background colors */
+ ThreeDColor,
+ FaceColor,
+ CheckedColor,
+ LightColor,
+ LightBorderColor,
+ ShadowColor,
+ DarkShadowColor,
+ ButtonTextColor,
+ RadioCheckTextColor,
+ GroupTextColor,
+ LabelTextColor,
+ InfoTextColor,
+ WindowColor,
+ WindowTextColor,
+ DialogColor,
+ DialogTextColor,
+ WorkspaceColor,
+ FieldColor,
+ FieldTextColor,
+ ActiveColor,
+ ActiveColor2,
+ ActiveTextColor,
+ ActiveBorderColor,
+ DeactiveColor,
+ DeactiveColor2,
+ DeactiveTextColor,
+ DeactiveBorderColor,
+ HighlightColor,
+ HighlightTextColor,
+ DisableColor,
+ HelpColor,
+ HelpTextColor,
+ MenuColor,
+ MenuBarColor,
+ MenuTextColor,
+ MenuHighlightColor,
+ MenuHighlightTextColor,
+ LinkColor,
+ VisitedLinkColor,
+ HighlightLinkColor,
+ HighContrastMode,
+ /* style fonts */
+ UIFont, /* convenience, sets all fonts but TitleFont and FloatTitleFont */
+ AppFont,
+ HelpFont,
+ TitleFont,
+ FloatTitleFont,
+ MenuFont,
+ ToolFont,
+ GroupFont,
+ LabelFont,
+ InfoFont,
+ RadioCheckFont,
+ PushButtonFont,
+ FieldFont,
+ IconFont,
+ /* style numeric styles */
+ RadioButtonStyle,
+ CheckBoxStyle,
+ PushButtonStyle,
+ TabControlStyle,
+ /* toolbar style */
+ ToolbarIconSize
+
+};
+
+#endif // _VCL_DTSETENUM_HXX
diff --git a/vcl/unx/source/gdi/gcach_xpeer.cxx b/vcl/unx/source/gdi/gcach_xpeer.cxx
new file mode 100644
index 000000000000..a69a2426b519
--- /dev/null
+++ b/vcl/unx/source/gdi/gcach_xpeer.cxx
@@ -0,0 +1,682 @@
+/*************************************************************************
+ *
+ * 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/ustring.hxx>
+#include <osl/module.h>
+#include <osl/thread.h>
+
+#include <gcach_xpeer.hxx>
+#include <xrender_peer.hxx>
+#include <saldisp.hxx>
+#include <saldata.hxx>
+#include <salgdi.h>
+
+// ===========================================================================
+
+// all glyph specific data needed by the XGlyphPeer is quite trivial
+// with one exception: if multiple screens are involved and non-antialiased
+// glyph rendering is active, then we need screen specific pixmaps
+struct MultiScreenGlyph
+{
+ const RawBitmap* mpRawBitmap;
+ Glyph maXRGlyphId;
+ Pixmap maPixmaps[1]; // [mnMaxScreens]
+};
+
+// ===========================================================================
+
+X11GlyphPeer::X11GlyphPeer()
+: mpDisplay( GetX11SalData()->GetDisplay()->GetDisplay() )
+, mnMaxScreens(0)
+, mnDefaultScreen(0)
+, mnExtByteCount(0)
+, mnForcedAA(0)
+, mnUsingXRender(0)
+{
+ maRawBitmap.mnAllocated = 0;
+ maRawBitmap.mpBits = NULL;
+ if( !mpDisplay )
+ return;
+
+ SalDisplay& rSalDisplay = *GetX11SalData()->GetDisplay();
+ mpDisplay = rSalDisplay.GetDisplay();
+ mnMaxScreens = rSalDisplay.GetScreenCount();
+ if( mnMaxScreens > MAX_GCACH_SCREENS )
+ mnMaxScreens = MAX_GCACH_SCREENS;
+ // if specific glyph data has to be kept for many screens
+ // then prepare the allocation of MultiScreenGlyph objects
+ if( mnMaxScreens > 1 )
+ mnExtByteCount = sizeof(MultiScreenGlyph) + sizeof(Pixmap) * (mnMaxScreens - 1);
+ mnDefaultScreen = rSalDisplay.GetDefaultScreenNumber();
+
+ InitAntialiasing();
+}
+
+// ---------------------------------------------------------------------------
+
+X11GlyphPeer::~X11GlyphPeer()
+{
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ Display* const pX11Disp = pSalDisp->GetDisplay();
+ XRenderPeer& rRenderPeer = XRenderPeer::GetInstance();
+ for( int i = 0; i < mnMaxScreens; i++ )
+ {
+ SalDisplay::RenderEntryMap& rMap = pSalDisp->GetRenderEntries( i );
+ for( SalDisplay::RenderEntryMap::iterator it = rMap.begin(); it != rMap.end(); ++it )
+ {
+ if( it->second.m_aPixmap )
+ ::XFreePixmap( pX11Disp, it->second.m_aPixmap );
+ if( it->second.m_aPicture )
+ rRenderPeer.FreePicture( it->second.m_aPicture );
+ }
+ rMap.clear();
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+void X11GlyphPeer::InitAntialiasing()
+{
+ int nEnvAntiAlias = 0;
+ const char* pEnvAntiAlias = getenv( "SAL_ANTIALIAS_DISABLE" );
+ if( pEnvAntiAlias )
+ {
+ nEnvAntiAlias = atoi( pEnvAntiAlias );
+ if( nEnvAntiAlias == 0 )
+ return;
+ }
+
+ mnUsingXRender = 0;
+ mnForcedAA = 0;
+
+ // enable XRENDER accelerated aliasing on screens that support it
+ // unless it explicitly disabled by an environment variable
+ if( (nEnvAntiAlias & 2) == 0 )
+ mnUsingXRender = XRenderPeer::GetInstance().InitRenderText();
+
+ // else enable client side antialiasing for these screens
+ // unless it is explicitly disabled by an environment variable
+ if( (nEnvAntiAlias & 1) != 0 )
+ return;
+
+ // enable client side antialiasing for screen visuals that are suitable
+ // mnForcedAA is a bitmask of screens enabled for client side antialiasing
+ mnForcedAA = (~(~0U << mnMaxScreens)) ^ mnUsingXRender;
+ SalDisplay& rSalDisplay = *GetX11SalData()->GetDisplay();
+ for( int nScreen = 0; nScreen < mnMaxScreens; ++nScreen)
+ {
+ Visual* pVisual = rSalDisplay.GetVisual( nScreen ).GetVisual();
+ XVisualInfo aXVisualInfo;
+ aXVisualInfo.visualid = pVisual->visualid;
+ int nVisuals = 0;
+ XVisualInfo* pXVisualInfo = XGetVisualInfo( mpDisplay, VisualIDMask, &aXVisualInfo, &nVisuals );
+ for( int i = nVisuals; --i >= 0; )
+ {
+ if( ((pXVisualInfo[i].c_class==PseudoColor) || (pXVisualInfo[i].depth<24))
+ && ((pXVisualInfo[i].c_class>GrayScale) || (pXVisualInfo[i].depth!=8) ) )
+ mnForcedAA &= ~(1U << nScreen);
+ }
+ if( pXVisualInfo != NULL )
+ XFree( pXVisualInfo );
+ }
+}
+
+// ===========================================================================
+
+enum { INFO_EMPTY=0, INFO_PIXMAP, INFO_XRENDER, INFO_RAWBMP, INFO_MULTISCREEN };
+static const Glyph NO_GLYPHID = 0;
+static RawBitmap* const NO_RAWBMP = NULL;
+static const Pixmap NO_PIXMAP = ~0;
+
+// ---------------------------------------------------------------------------
+
+MultiScreenGlyph* X11GlyphPeer::PrepareForMultiscreen( ExtGlyphData& rEGD ) const
+{
+ // prepare to store screen specific pixmaps
+ MultiScreenGlyph* pMSGlyph = (MultiScreenGlyph*)new char[ mnExtByteCount ];
+
+ // init the glyph formats
+ pMSGlyph->mpRawBitmap = NO_RAWBMP;
+ pMSGlyph->maXRGlyphId = NO_GLYPHID;
+ for( int i = 0; i < mnMaxScreens; ++i )
+ pMSGlyph->maPixmaps[i] = NO_PIXMAP;
+ // reuse already available glyph formats
+ if( rEGD.meInfo == INFO_XRENDER )
+ pMSGlyph->maXRGlyphId = reinterpret_cast<Glyph>(rEGD.mpData);
+ else if( rEGD.meInfo == INFO_RAWBMP )
+ pMSGlyph->mpRawBitmap = reinterpret_cast<RawBitmap*>(rEGD.mpData);
+ else if( rEGD.meInfo == INFO_PIXMAP )
+ {
+ Pixmap aPixmap = reinterpret_cast<Pixmap>(rEGD.mpData);
+ if( aPixmap != None )
+ // pixmap for the default screen is available
+ pMSGlyph->maPixmaps[ mnDefaultScreen ] = aPixmap;
+ else // empty pixmap for all screens is available
+ for( int i = 0; i < mnMaxScreens; ++i )
+ pMSGlyph->maPixmaps[ i ] = None;
+ }
+ // enable use of multiscreen glyph
+ rEGD.mpData = (void*)pMSGlyph;
+ rEGD.meInfo = INFO_MULTISCREEN;
+
+ return pMSGlyph;
+ }
+
+// ---------------------------------------------------------------------------
+
+Glyph X11GlyphPeer::GetRenderGlyph( const GlyphData& rGD ) const
+{
+ Glyph aGlyphId = NO_GLYPHID;
+ const ExtGlyphData& rEGD = rGD.ExtDataRef();
+ if( rEGD.meInfo == INFO_XRENDER )
+ aGlyphId = reinterpret_cast<Glyph>(rEGD.mpData);
+ else if( rEGD.meInfo == INFO_MULTISCREEN )
+ aGlyphId = reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData)->maXRGlyphId;
+ return aGlyphId;
+}
+
+// ---------------------------------------------------------------------------
+
+void X11GlyphPeer::SetRenderGlyph( GlyphData& rGD, Glyph aGlyphId ) const
+{
+ ExtGlyphData& rEGD = rGD.ExtDataRef();
+ switch( rEGD.meInfo )
+ {
+ case INFO_EMPTY:
+ rEGD.meInfo = INFO_XRENDER;
+ // fall through
+ case INFO_XRENDER:
+ rEGD.mpData = reinterpret_cast<void*>(aGlyphId);
+ break;
+ case INFO_PIXMAP:
+ case INFO_RAWBMP:
+ PrepareForMultiscreen( rEGD );
+ // fall through
+ case INFO_MULTISCREEN:
+ reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData)->maXRGlyphId = aGlyphId;
+ break;
+ default:
+ break; // cannot happen...
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+const RawBitmap* X11GlyphPeer::GetRawBitmap( const GlyphData& rGD ) const
+{
+ const RawBitmap* pRawBitmap = NO_RAWBMP;
+ const ExtGlyphData& rEGD = rGD.ExtDataRef();
+ if( rEGD.meInfo == INFO_RAWBMP )
+ pRawBitmap = reinterpret_cast<RawBitmap*>(rEGD.mpData);
+ else if( rEGD.meInfo == INFO_MULTISCREEN )
+ pRawBitmap = reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData)->mpRawBitmap;
+ return pRawBitmap;
+}
+
+// ---------------------------------------------------------------------------
+
+void X11GlyphPeer::SetRawBitmap( GlyphData& rGD, const RawBitmap* pRawBitmap ) const
+{
+ ExtGlyphData& rEGD = rGD.ExtDataRef();
+ switch( rEGD.meInfo )
+ {
+ case INFO_EMPTY:
+ rEGD.meInfo = INFO_RAWBMP;
+ // fall through
+ case INFO_RAWBMP:
+ rEGD.mpData = (void*)pRawBitmap;
+ break;
+ case INFO_PIXMAP:
+ case INFO_XRENDER:
+ PrepareForMultiscreen( rEGD );
+ // fall through
+ case INFO_MULTISCREEN:
+ reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData)->mpRawBitmap = pRawBitmap;
+ break;
+ default:
+ // cannot happen...
+ break;
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+Pixmap X11GlyphPeer::GetPixmap( const GlyphData& rGD, int nScreen ) const
+{
+ Pixmap aPixmap = NO_PIXMAP;
+ const ExtGlyphData& rEGD = rGD.ExtDataRef();
+ if( (rEGD.meInfo == INFO_PIXMAP) && (nScreen == mnDefaultScreen) )
+ aPixmap = (Pixmap)rEGD.mpData;
+ else if( rEGD.meInfo == INFO_MULTISCREEN )
+ aPixmap = (Pixmap)(reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData)->maPixmaps[nScreen]);
+ return aPixmap;
+}
+
+// ---------------------------------------------------------------------------
+
+void X11GlyphPeer::SetPixmap( GlyphData& rGD, Pixmap aPixmap, int nScreen ) const
+{
+ if( aPixmap == NO_PIXMAP )
+ aPixmap = None;
+
+ ExtGlyphData& rEGD = rGD.ExtDataRef();
+ if( (rEGD.meInfo == INFO_EMPTY) && (nScreen == mnDefaultScreen) )
+ {
+ rEGD.meInfo = INFO_PIXMAP;
+ rEGD.mpData = (void*)aPixmap;
+ }
+ else
+ {
+ MultiScreenGlyph* pMSGlyph;
+ if( rEGD.meInfo == INFO_MULTISCREEN )
+ pMSGlyph = reinterpret_cast<MultiScreenGlyph*>(rEGD.mpData);
+ else
+ pMSGlyph = PrepareForMultiscreen( rEGD );
+
+ pMSGlyph->maPixmaps[ nScreen ] = aPixmap;
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+void X11GlyphPeer::RemovingFont( ServerFont& rServerFont )
+{
+ void* pFontExt = rServerFont.GetExtPointer();
+ switch( rServerFont.GetExtInfo() )
+ {
+ case INFO_PIXMAP:
+ case INFO_RAWBMP:
+ // nothing to do
+ break;
+ case INFO_MULTISCREEN:
+ // cannot happen...
+ break;
+
+ case INFO_XRENDER:
+ XRenderPeer::GetInstance().FreeGlyphSet( (GlyphSet)pFontExt );
+ break;
+ }
+
+ rServerFont.SetExtended( INFO_EMPTY, NULL );
+}
+
+// ---------------------------------------------------------------------------
+
+// notification to clean up GlyphPeer resources for this glyph
+void X11GlyphPeer::RemovingGlyph( ServerFont& /*rServerFont*/, GlyphData& rGlyphData, int /*nGlyphIndex*/ )
+{
+ // nothing to do if the GlyphPeer hasn't allocated resources for the glyph
+ if( rGlyphData.ExtDataRef().meInfo == INFO_EMPTY )
+ return;
+
+ const GlyphMetric& rGM = rGlyphData.GetMetric();
+ const int nWidth = rGM.GetSize().Width();
+ const int nHeight = rGM.GetSize().Height();
+
+ void* pGlyphExt = rGlyphData.ExtDataRef().mpData;
+ switch( rGlyphData.ExtDataRef().meInfo )
+ {
+ case INFO_PIXMAP:
+ {
+ Pixmap aPixmap = (Pixmap)pGlyphExt;
+ if( aPixmap != None )
+ {
+ XFreePixmap( mpDisplay, aPixmap );
+ mnBytesUsed -= nHeight * ((nWidth + 7) >> 3);
+ }
+ }
+ break;
+
+ case INFO_MULTISCREEN:
+ {
+ MultiScreenGlyph* pMSGlyph = reinterpret_cast<MultiScreenGlyph*>(pGlyphExt);
+ for( int i = 0; i < mnMaxScreens; ++i)
+ {
+ if( pMSGlyph->maPixmaps[i] == NO_PIXMAP )
+ continue;
+ if( pMSGlyph->maPixmaps[i] == None )
+ continue;
+ XFreePixmap( mpDisplay, pMSGlyph->maPixmaps[i] );
+ mnBytesUsed -= nHeight * ((nWidth + 7) >> 3);
+ }
+ delete pMSGlyph->mpRawBitmap;
+ // Glyph nGlyphId = (Glyph)rGlyphData.GetExtPointer();
+ // XRenderPeer::GetInstance().FreeGlyph( aGlyphSet, &nGlyphId );
+ delete[] pMSGlyph; // it was allocated with new char[]
+ }
+ break;
+
+ case INFO_RAWBMP:
+ {
+ RawBitmap* pRawBitmap = (RawBitmap*)pGlyphExt;
+ if( pRawBitmap != NULL )
+ {
+ mnBytesUsed -= pRawBitmap->mnScanlineSize * pRawBitmap->mnHeight;
+ mnBytesUsed -= sizeof(RawBitmap);
+ delete pRawBitmap;
+ }
+ }
+ break;
+
+ case INFO_XRENDER:
+ {
+ // Glyph nGlyphId = (Glyph)rGlyphData.GetExtPointer();
+ // XRenderPeer::GetInstance().FreeGlyph( aGlyphSet, &nGlyphId );
+ mnBytesUsed -= nHeight * ((nWidth + 3) & ~3);
+ }
+ break;
+ }
+
+ if( mnBytesUsed < 0 ) // TODO: eliminate nBytesUsed calc mismatch
+ mnBytesUsed = 0;
+
+ rGlyphData.ExtDataRef() = ExtGlyphData();
+}
+
+// ---------------------------------------------------------------------------
+
+bool X11GlyphPeer::ForcedAntialiasing( const ServerFont& rServerFont, int nScreen ) const
+{
+ bool bForceOk = rServerFont.GetAntialiasAdvice();
+ // maximum size for antialiasing is 250 pixels
+ bForceOk &= (rServerFont.GetFontSelData().mnHeight < 250);
+ return (bForceOk && ((mnForcedAA >> nScreen) & 1));
+}
+
+// ---------------------------------------------------------------------------
+
+GlyphSet X11GlyphPeer::GetGlyphSet( ServerFont& rServerFont, int nScreen )
+{
+ if( (nScreen >= 0) && ((mnUsingXRender >> nScreen) & 1) == 0 )
+ return 0;
+
+ GlyphSet aGlyphSet;
+
+ switch( rServerFont.GetExtInfo() )
+ {
+ case INFO_XRENDER:
+ aGlyphSet = (GlyphSet)rServerFont.GetExtPointer();
+ break;
+
+ case INFO_EMPTY:
+ {
+ // antialiasing for reasonable font heights only
+ // => prevents crashes caused by X11 requests >= 256k
+ // => prefer readablity of hinted glyphs at small sizes
+ // => prefer "grey clouds" to "black clouds" at very small sizes
+ int nHeight = rServerFont.GetFontSelData().mnHeight;
+ if( nHeight<250 && rServerFont.GetAntialiasAdvice() )
+ {
+ aGlyphSet = XRenderPeer::GetInstance().CreateGlyphSet();
+ rServerFont.SetExtended( INFO_XRENDER, (void*)aGlyphSet );
+ }
+ else
+ aGlyphSet = 0;
+ }
+ break;
+
+ default:
+ aGlyphSet = 0;
+ break;
+ }
+
+ return aGlyphSet;
+}
+
+// ---------------------------------------------------------------------------
+
+Pixmap X11GlyphPeer::GetPixmap( ServerFont& rServerFont, int nGlyphIndex, int nReqScreen )
+{
+ if( rServerFont.IsGlyphInvisible( nGlyphIndex ) )
+ return None;
+
+ GlyphData& rGlyphData = rServerFont.GetGlyphData( nGlyphIndex );
+ Pixmap aPixmap = GetPixmap( rGlyphData, nReqScreen );
+ if( aPixmap == NO_PIXMAP )
+ {
+ aPixmap = None;
+ if( rServerFont.GetGlyphBitmap1( nGlyphIndex, maRawBitmap ) )
+ {
+ // #94666# circumvent bug in some X11 systems, e.g. XF410.LynxEM.v163
+ ULONG nPixmapWidth = 8 * maRawBitmap.mnScanlineSize - 1;
+ nPixmapWidth = Max( nPixmapWidth, maRawBitmap.mnWidth );
+
+ rGlyphData.SetSize( Size( nPixmapWidth, maRawBitmap.mnHeight ) );
+ rGlyphData.SetOffset( +maRawBitmap.mnXOffset, +maRawBitmap.mnYOffset );
+
+ const ULONG nBytes = maRawBitmap.mnHeight * maRawBitmap.mnScanlineSize;
+ if( nBytes > 0 )
+ {
+ // conversion table LSB<->MSB (for XCreatePixmapFromData)
+ static const unsigned char lsb2msb[256] =
+ {
+ 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
+ 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
+ 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
+ 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
+ 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
+ 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
+ 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
+ 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
+ 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
+ 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
+ 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
+ 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
+ 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
+ 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
+ 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
+ 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
+ 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
+ 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
+ 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
+ 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
+ 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
+ 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
+ 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
+ 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
+ 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
+ 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
+ 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
+ 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
+ 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
+ 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
+ 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
+ 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
+ };
+
+ unsigned char* pTemp = maRawBitmap.mpBits;
+ for( int i = nBytes; --i >= 0; ++pTemp )
+ *pTemp = lsb2msb[ *pTemp ];
+
+ // often a glyph pixmap is only needed on the default screen
+ // => optimize for this common case
+ int nMinScreen = 0;
+ int nEndScreen = mnMaxScreens;
+ if( nReqScreen == mnDefaultScreen ) {
+ nMinScreen = mnDefaultScreen;
+ nEndScreen = mnDefaultScreen + 1;
+ }
+ // prepare glyph pixmaps for the different screens
+ for( int i = nMinScreen; i < nEndScreen; ++i )
+ {
+ // don't bother if the pixmap is already there
+ if( GetPixmap( rGlyphData, i ) != NO_PIXMAP )
+ continue;
+ // create the glyph pixmap
+ Pixmap aScreenPixmap = XCreatePixmapFromBitmapData( mpDisplay,
+ RootWindow( mpDisplay, i ), (char*)maRawBitmap.mpBits,
+ nPixmapWidth, maRawBitmap.mnHeight, 1, 0, 1 );
+ // and cache it as glyph specific data
+ SetPixmap( rGlyphData, aScreenPixmap, i );
+ mnBytesUsed += nBytes;
+ if( i == nReqScreen )
+ aPixmap = aScreenPixmap;
+ }
+ }
+ }
+ else
+ {
+ // fall back to .notdef glyph
+ if( nGlyphIndex != 0 ) // recurse only once
+ aPixmap = GetPixmap( rServerFont, 0, nReqScreen );
+
+ if( aPixmap == NO_PIXMAP )
+ aPixmap = None;
+ }
+ }
+
+ return aPixmap;
+}
+
+// ---------------------------------------------------------------------------
+
+const RawBitmap* X11GlyphPeer::GetRawBitmap( ServerFont& rServerFont,
+ int nGlyphIndex )
+{
+ if( rServerFont.IsGlyphInvisible( nGlyphIndex ) )
+ return NO_RAWBMP;
+
+ GlyphData& rGlyphData = rServerFont.GetGlyphData( nGlyphIndex );
+
+ const RawBitmap* pRawBitmap = GetRawBitmap( rGlyphData );
+ if( pRawBitmap == NO_RAWBMP )
+ {
+ RawBitmap* pNewBitmap = new RawBitmap;
+ if( rServerFont.GetGlyphBitmap8( nGlyphIndex, *pNewBitmap ) )
+ {
+ pRawBitmap = pNewBitmap;
+ mnBytesUsed += pNewBitmap->mnScanlineSize * pNewBitmap->mnHeight;
+ mnBytesUsed += sizeof(pNewBitmap);
+ }
+ else
+ {
+ delete pNewBitmap;
+ // fall back to .notdef glyph
+ if( nGlyphIndex != 0 ) // recurse only once
+ pRawBitmap = GetRawBitmap( rServerFont, 0 );
+ }
+
+ SetRawBitmap( rGlyphData, pRawBitmap );
+ }
+
+ return pRawBitmap;
+}
+
+// ---------------------------------------------------------------------------
+
+Glyph X11GlyphPeer::GetGlyphId( ServerFont& rServerFont, int nGlyphIndex )
+{
+ if( rServerFont.IsGlyphInvisible( nGlyphIndex ) )
+ return NO_GLYPHID;
+
+ GlyphData& rGlyphData = rServerFont.GetGlyphData( nGlyphIndex );
+
+ Glyph aGlyphId = GetRenderGlyph( rGlyphData );
+ if( aGlyphId == NO_GLYPHID )
+ {
+ // prepare GlyphInfo and Bitmap
+ if( rServerFont.GetGlyphBitmap8( nGlyphIndex, maRawBitmap ) )
+ {
+ XGlyphInfo aGlyphInfo;
+ aGlyphInfo.width = maRawBitmap.mnWidth;
+ aGlyphInfo.height = maRawBitmap.mnHeight;
+ aGlyphInfo.x = -maRawBitmap.mnXOffset;
+ aGlyphInfo.y = -maRawBitmap.mnYOffset;
+
+ rGlyphData.SetSize( Size( maRawBitmap.mnWidth, maRawBitmap.mnHeight ) );
+ rGlyphData.SetOffset( +maRawBitmap.mnXOffset, +maRawBitmap.mnYOffset );
+
+ const GlyphMetric& rGM = rGlyphData.GetMetric();
+ aGlyphInfo.xOff = +rGM.GetDelta().X();
+ aGlyphInfo.yOff = +rGM.GetDelta().Y();
+
+ // upload glyph bitmap to server
+ GlyphSet aGlyphSet = GetGlyphSet( rServerFont, -1 );
+
+ aGlyphId = nGlyphIndex & 0x00FFFFFF;
+ const ULONG nBytes = maRawBitmap.mnScanlineSize * maRawBitmap.mnHeight;
+ XRenderPeer::GetInstance().AddGlyph( aGlyphSet, aGlyphId,
+ aGlyphInfo, (char*)maRawBitmap.mpBits, nBytes );
+ mnBytesUsed += nBytes;
+ }
+ else
+ {
+ // fall back to .notdef glyph
+ if( nGlyphIndex != 0 ) // recurse only once
+ aGlyphId = GetGlyphId( rServerFont, 0 );
+ }
+
+ SetRenderGlyph( rGlyphData, aGlyphId );
+ }
+
+ return aGlyphId;
+}
+
+// ===========================================================================
+
+X11GlyphCache::X11GlyphCache( X11GlyphPeer& rPeer )
+: GlyphCache( rPeer )
+{
+}
+
+// ---------------------------------------------------------------------------
+
+static X11GlyphPeer* pX11GlyphPeer = NULL;
+static X11GlyphCache* pX11GlyphCache = NULL;
+
+X11GlyphCache& X11GlyphCache::GetInstance()
+{
+ if( !pX11GlyphCache )
+ {
+ pX11GlyphPeer = new X11GlyphPeer();
+ pX11GlyphCache = new X11GlyphCache( *pX11GlyphPeer );
+ }
+ return *pX11GlyphCache;
+}
+
+// ---------------------------------------------------------------------------
+
+void X11GlyphCache::KillInstance()
+{
+ delete pX11GlyphCache;
+ delete pX11GlyphPeer;
+ pX11GlyphCache = NULL;
+ pX11GlyphPeer = NULL;
+}
+
+// ===========================================================================
+
+void X11SalGraphics::releaseGlyphPeer()
+{
+ X11GlyphCache::KillInstance();
+}
+
+// ===========================================================================
+
diff --git a/vcl/unx/source/gdi/gcach_xpeer.hxx b/vcl/unx/source/gdi/gcach_xpeer.hxx
new file mode 100644
index 000000000000..13277fa975de
--- /dev/null
+++ b/vcl/unx/source/gdi/gcach_xpeer.hxx
@@ -0,0 +1,94 @@
+/*************************************************************************
+ *
+ * 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_GCACH_XPEER_HXX
+#define _SV_GCACH_XPEER_HXX
+
+#include <vcl/glyphcache.hxx>
+
+#include <tools/prex.h>
+#include <X11/extensions/Xrender.h>
+#include <tools/postx.h>
+#include <vcl/dllapi.h>
+
+
+class SalDisplay;
+struct MultiScreenGlyph;
+
+class X11GlyphPeer
+: public GlyphCachePeer
+{
+public:
+ X11GlyphPeer();
+ virtual ~X11GlyphPeer();
+
+ Pixmap GetPixmap( ServerFont&, int nGlyphIndex, int nScreen );
+ const RawBitmap* GetRawBitmap( ServerFont&, int nGlyphIndex );
+ bool ForcedAntialiasing( const ServerFont&, int nScreen ) const;
+
+ GlyphSet GetGlyphSet( ServerFont&, int nScreen );
+ Glyph GetGlyphId( ServerFont&, int nGlyphIndex );
+
+protected:
+ void InitAntialiasing();
+
+ virtual void RemovingFont( ServerFont& );
+ virtual void RemovingGlyph( ServerFont&, GlyphData&, int nGlyphIndex );
+
+ MultiScreenGlyph* PrepareForMultiscreen( ExtGlyphData& ) const;
+ void SetRenderGlyph( GlyphData&, Glyph ) const;
+ void SetRawBitmap( GlyphData&, const RawBitmap* ) const;
+ void SetPixmap( GlyphData&, Pixmap, int nScreen ) const;
+ Glyph GetRenderGlyph( const GlyphData& ) const;
+ const RawBitmap* GetRawBitmap( const GlyphData& ) const;
+ Pixmap GetPixmap( const GlyphData&, int nScreen ) const;
+
+private:
+ Display* mpDisplay;
+
+ // thirty-two screens should be enough for everyone...
+ static const int MAX_GCACH_SCREENS = 32;
+ int mnMaxScreens;
+ int mnDefaultScreen;
+ int mnExtByteCount;
+ RawBitmap maRawBitmap;
+ sal_uInt32 mnForcedAA;
+ sal_uInt32 mnUsingXRender;
+};
+
+class X11GlyphCache : public GlyphCache
+{
+public:
+ X11GlyphPeer& GetPeer() { return reinterpret_cast<X11GlyphPeer&>( mrPeer ); }
+static X11GlyphCache& GetInstance();
+static void KillInstance();
+
+private:
+ X11GlyphCache( X11GlyphPeer& );
+};
+
+#endif // _SV_GCACH_XPEER_HXX
diff --git a/vcl/unx/source/gdi/makefile.mk b/vcl/unx/source/gdi/makefile.mk
new file mode 100644
index 000000000000..536aadcac015
--- /dev/null
+++ b/vcl/unx/source/gdi/makefile.mk
@@ -0,0 +1,111 @@
+#*************************************************************************
+#
+# 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=salgdi
+
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)"!="unx"
+
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+
+.ELSE # "$(GUIBASE)"!="unx"
+
+SLOFILES= \
+ $(SLO)$/salgdi2.obj \
+ $(SLO)$/salbmp.obj \
+ $(SLO)$/salgdi.obj \
+ $(SLO)$/salvd.obj \
+ $(SLO)$/dtint.obj \
+ $(SLO)$/salcvt.obj \
+ $(SLO)$/xfont.obj \
+ $(SLO)$/xlfd_attr.obj \
+ $(SLO)$/xlfd_extd.obj \
+ $(SLO)$/xlfd_smpl.obj \
+ $(SLO)$/salgdi3.obj \
+ $(SLO)$/gcach_xpeer.obj \
+ $(SLO)$/xrender_peer.obj \
+ $(SLO)$/pspgraphics.obj
+
+EXCEPTIONSFILES=\
+ $(SLO)$/xlfd_extd.obj \
+ $(SLO)$/salgdi.obj \
+ $(SLO)$/salbmp.obj \
+ $(SLO)$/salgdi3.obj \
+ $(SLO)$/salcvt.obj
+
+.IF "$(USE_XPRINT)" == "TRUE"
+CFLAGS+=-D_USE_PRINT_EXTENSION_=1
+SLOFILES+=$(SLO)$/xprintext.obj
+.ELSE
+SLOFILES+=$(SLO)$/salprnpsp.obj
+EXCEPTIONSFILES+=$(SLO)$/salprnpsp.obj
+.ENDIF
+
+.IF "$(OS)"=="SOLARIS"
+SLOFILES+=$(SLO)$/cdeint.obj
+ENVCFLAGS+=-DUSE_CDE
+.ENDIF
+
+.IF "$(XRENDER_LINK)" == "YES"
+CFLAGS+=-DXRENDER_LINK
+.ENDIF
+
+.IF "$(ENABLE_GRAPHITE)" == "TRUE"
+CFLAGS+=-DENABLE_GRAPHITE
+.ENDIF
+
+.ENDIF # "$(GUIBASE)"!="unx"
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
+.INCLUDE : $(PRJ)$/util$/target.pmk
+
+ALLTAR : $(MACOSXRC)
+
+XSALSETLIBNAME=$(DLLPRE)spa$(DLLPOSTFIX)$(DLLPOST)
+
+$(INCCOM)$/rtsname.hxx:
+ @rm -f $(INCCOM)$/rtsname.hxx ; \
+ echo "#define _XSALSET_LIBNAME "\"$(XSALSETLIBNAME)\" > $(INCCOM)$/rtsname.hxx
+
+$(SLO)$/salpimpl.obj : $(INCCOM)$/rtsname.hxx
+$(SLO)$/salprnpsp.obj : $(INCCOM)$/rtsname.hxx
+
diff --git a/vcl/unx/source/gdi/pspgraphics.cxx b/vcl/unx/source/gdi/pspgraphics.cxx
new file mode 100644
index 000000000000..d3eb103b9dd6
--- /dev/null
+++ b/vcl/unx/source/gdi/pspgraphics.cxx
@@ -0,0 +1,1500 @@
+/*************************************************************************
+ *
+ * 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 "pspgraphics.h"
+#include "vcl/jobdata.hxx"
+#include "vcl/printergfx.hxx"
+#include "vcl/printerinfomanager.hxx"
+#include "vcl/bmpacc.hxx"
+#include "vcl/salbmp.hxx"
+#include "vcl/glyphcache.hxx"
+#include "vcl/impfont.hxx"
+#include "vcl/outfont.hxx"
+#include "vcl/fontsubset.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/salprn.hxx"
+#include "vcl/sysdata.hxx"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#ifdef ENABLE_GRAPHITE
+#include <vcl/graphite_layout.hxx>
+#include <vcl/graphite_serverfont.hxx>
+#endif
+
+using namespace psp;
+using namespace rtl;
+
+// ----- Implementation of PrinterBmp by means of SalBitmap/BitmapBuffer ---------------
+
+class SalPrinterBmp : public psp::PrinterBmp
+{
+ private:
+ BitmapBuffer* mpBmpBuffer;
+
+ FncGetPixel mpFncGetPixel;
+ Scanline mpScanAccess;
+ sal_PtrDiff mnScanOffset;
+
+ sal_uInt32 ColorOf (BitmapColor& rColor) const;
+ sal_uInt8 GrayOf (BitmapColor& rColor) const;
+
+ SalPrinterBmp ();
+
+ public:
+
+ SalPrinterBmp (BitmapBuffer* pBitmap);
+ virtual ~SalPrinterBmp ();
+ virtual sal_uInt32 GetPaletteColor (sal_uInt32 nIdx) const;
+ virtual sal_uInt32 GetPaletteEntryCount () const;
+ virtual sal_uInt32 GetPixelRGB (sal_uInt32 nRow, sal_uInt32 nColumn) const;
+ virtual sal_uInt8 GetPixelGray (sal_uInt32 nRow, sal_uInt32 nColumn) const;
+ virtual sal_uInt8 GetPixelIdx (sal_uInt32 nRow, sal_uInt32 nColumn) const;
+ virtual sal_uInt32 GetWidth () const;
+ virtual sal_uInt32 GetHeight() const;
+ virtual sal_uInt32 GetDepth () const;
+};
+
+SalPrinterBmp::SalPrinterBmp (BitmapBuffer* pBuffer) :
+ mpBmpBuffer (pBuffer)
+{
+ DBG_ASSERT (mpBmpBuffer, "SalPrinterBmp::SalPrinterBmp () can't acquire Bitmap");
+
+ // calibrate scanline buffer
+ if( BMP_SCANLINE_ADJUSTMENT( mpBmpBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN )
+ {
+ mpScanAccess = mpBmpBuffer->mpBits;
+ mnScanOffset = mpBmpBuffer->mnScanlineSize;
+ }
+ else
+ {
+ mpScanAccess = mpBmpBuffer->mpBits
+ + (mpBmpBuffer->mnHeight - 1) * mpBmpBuffer->mnScanlineSize;
+ mnScanOffset = - mpBmpBuffer->mnScanlineSize;
+ }
+
+ // request read access to the pixels
+ switch( BMP_SCANLINE_FORMAT( mpBmpBuffer->mnFormat ) )
+ {
+ case BMP_FORMAT_1BIT_MSB_PAL:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_1BIT_MSB_PAL; break;
+ case BMP_FORMAT_1BIT_LSB_PAL:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_1BIT_LSB_PAL; break;
+ case BMP_FORMAT_4BIT_MSN_PAL:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_4BIT_MSN_PAL; break;
+ case BMP_FORMAT_4BIT_LSN_PAL:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_4BIT_LSN_PAL; break;
+ case BMP_FORMAT_8BIT_PAL:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_8BIT_PAL; break;
+ case BMP_FORMAT_8BIT_TC_MASK:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_8BIT_TC_MASK; break;
+ case BMP_FORMAT_16BIT_TC_MSB_MASK:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_16BIT_TC_MSB_MASK; break;
+ case BMP_FORMAT_16BIT_TC_LSB_MASK:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_16BIT_TC_LSB_MASK; break;
+ case BMP_FORMAT_24BIT_TC_BGR:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_24BIT_TC_BGR; break;
+ case BMP_FORMAT_24BIT_TC_RGB:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_24BIT_TC_RGB; break;
+ case BMP_FORMAT_24BIT_TC_MASK:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_24BIT_TC_MASK; break;
+ case BMP_FORMAT_32BIT_TC_ABGR:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_32BIT_TC_ABGR; break;
+ case BMP_FORMAT_32BIT_TC_ARGB:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_32BIT_TC_ARGB; break;
+ case BMP_FORMAT_32BIT_TC_BGRA:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_32BIT_TC_BGRA; break;
+ case BMP_FORMAT_32BIT_TC_RGBA:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_32BIT_TC_RGBA; break;
+ case BMP_FORMAT_32BIT_TC_MASK:
+ mpFncGetPixel = BitmapReadAccess::GetPixelFor_32BIT_TC_MASK; break;
+
+ default:
+ DBG_ERROR("Error: SalPrinterBmp::SalPrinterBmp() unknown bitmap format");
+ break;
+ }
+}
+
+SalPrinterBmp::~SalPrinterBmp ()
+{
+}
+
+sal_uInt32
+SalPrinterBmp::GetWidth () const
+{
+ return mpBmpBuffer->mnWidth;
+}
+
+sal_uInt32
+SalPrinterBmp::GetHeight () const
+{
+ return mpBmpBuffer->mnHeight;
+}
+
+sal_uInt32
+SalPrinterBmp::GetDepth () const
+{
+ sal_uInt32 nDepth;
+
+ switch (mpBmpBuffer->mnBitCount)
+ {
+ case 1:
+ nDepth = 1;
+ break;
+
+ case 4:
+ case 8:
+ nDepth = 8;
+ break;
+
+ case 16:
+ case 24:
+ case 32:
+ nDepth = 24;
+ break;
+
+ default:
+ nDepth = 1;
+ DBG_ERROR ("Error: unsupported bitmap depth in SalPrinterBmp::GetDepth()");
+ break;
+ }
+
+ return nDepth;
+}
+
+sal_uInt32
+SalPrinterBmp::ColorOf (BitmapColor& rColor) const
+{
+ if (rColor.IsIndex())
+ return ColorOf (mpBmpBuffer->maPalette[rColor.GetIndex()]);
+ else
+ return ((rColor.GetBlue()) & 0x000000ff)
+ | ((rColor.GetGreen() << 8) & 0x0000ff00)
+ | ((rColor.GetRed() << 16) & 0x00ff0000);
+}
+
+sal_uInt8
+SalPrinterBmp::GrayOf (BitmapColor& rColor) const
+{
+ if (rColor.IsIndex())
+ return GrayOf (mpBmpBuffer->maPalette[rColor.GetIndex()]);
+ else
+ return ( rColor.GetBlue() * 28UL
+ + rColor.GetGreen() * 151UL
+ + rColor.GetRed() * 77UL ) >> 8;
+}
+
+sal_uInt32
+SalPrinterBmp::GetPaletteEntryCount () const
+{
+ return mpBmpBuffer->maPalette.GetEntryCount ();
+}
+
+sal_uInt32
+SalPrinterBmp::GetPaletteColor (sal_uInt32 nIdx) const
+{
+ return ColorOf (mpBmpBuffer->maPalette[nIdx]);
+}
+
+sal_uInt32
+SalPrinterBmp::GetPixelRGB (sal_uInt32 nRow, sal_uInt32 nColumn) const
+{
+ Scanline pScan = mpScanAccess + nRow * mnScanOffset;
+ BitmapColor aColor = mpFncGetPixel (pScan, nColumn, mpBmpBuffer->maColorMask);
+
+ return ColorOf (aColor);
+}
+
+sal_uInt8
+SalPrinterBmp::GetPixelGray (sal_uInt32 nRow, sal_uInt32 nColumn) const
+{
+ Scanline pScan = mpScanAccess + nRow * mnScanOffset;
+ BitmapColor aColor = mpFncGetPixel (pScan, nColumn, mpBmpBuffer->maColorMask);
+
+ return GrayOf (aColor);
+}
+
+sal_uInt8
+SalPrinterBmp::GetPixelIdx (sal_uInt32 nRow, sal_uInt32 nColumn) const
+{
+ Scanline pScan = mpScanAccess + nRow * mnScanOffset;
+ BitmapColor aColor = mpFncGetPixel (pScan, nColumn, mpBmpBuffer->maColorMask);
+
+ if (aColor.IsIndex())
+ return aColor.GetIndex();
+ else
+ return 0;
+}
+
+/*******************************************************
+ * PspGraphics *
+ *******************************************************/
+
+PspGraphics::~PspGraphics()
+{
+ ReleaseFonts();
+}
+
+void PspGraphics::GetResolution( sal_Int32 &rDPIX, sal_Int32 &rDPIY )
+{
+ if (m_pJobData != NULL)
+ {
+ int x = m_pJobData->m_aContext.getRenderResolution();
+
+ rDPIX = x;
+ rDPIY = x;
+ }
+}
+
+USHORT PspGraphics::GetBitCount()
+{
+ return m_pPrinterGfx->GetBitCount();
+}
+
+long PspGraphics::GetGraphicsWidth() const
+{
+ return 0;
+}
+
+void PspGraphics::ResetClipRegion()
+{
+ m_pPrinterGfx->ResetClipRegion ();
+}
+
+void PspGraphics::BeginSetClipRegion( ULONG n )
+{
+ m_pPrinterGfx->BeginSetClipRegion(n);
+}
+
+BOOL PspGraphics::unionClipRegion( long nX, long nY, long nDX, long nDY )
+{
+ return (BOOL)m_pPrinterGfx->UnionClipRegion (nX, nY, nDX, nDY);
+}
+
+bool PspGraphics::unionClipRegion( const ::basegfx::B2DPolyPolygon& )
+{
+ // TODO: implement and advertise OutDevSupport_B2DClip support
+ return false;
+}
+
+void PspGraphics::EndSetClipRegion()
+{
+ m_pPrinterGfx->EndSetClipRegion ();
+}
+
+void PspGraphics::SetLineColor()
+{
+ m_pPrinterGfx->SetLineColor ();
+}
+
+void PspGraphics::SetLineColor( SalColor nSalColor )
+{
+ psp::PrinterColor aColor (SALCOLOR_RED (nSalColor),
+ SALCOLOR_GREEN (nSalColor),
+ SALCOLOR_BLUE (nSalColor));
+ m_pPrinterGfx->SetLineColor (aColor);
+}
+
+void PspGraphics::SetFillColor()
+{
+ m_pPrinterGfx->SetFillColor ();
+}
+
+void PspGraphics::SetFillColor( SalColor nSalColor )
+{
+ psp::PrinterColor aColor (SALCOLOR_RED (nSalColor),
+ SALCOLOR_GREEN (nSalColor),
+ SALCOLOR_BLUE (nSalColor));
+ m_pPrinterGfx->SetFillColor (aColor);
+}
+
+void PspGraphics::SetROPLineColor( SalROPColor )
+{
+ DBG_ASSERT( 0, "Error: PrinterGfx::SetROPLineColor() not implemented" );
+}
+
+void PspGraphics::SetROPFillColor( SalROPColor )
+{
+ DBG_ASSERT( 0, "Error: PrinterGfx::SetROPFillColor() not implemented" );
+}
+
+void PspGraphics::SetXORMode( bool bSet, bool )
+{
+ (void)bSet;
+ DBG_ASSERT( !bSet, "Error: PrinterGfx::SetXORMode() not implemented" );
+}
+
+void PspGraphics::drawPixel( long nX, long nY )
+{
+ m_pPrinterGfx->DrawPixel (Point(nX, nY));
+}
+
+void PspGraphics::drawPixel( long nX, long nY, SalColor nSalColor )
+{
+ psp::PrinterColor aColor (SALCOLOR_RED (nSalColor),
+ SALCOLOR_GREEN (nSalColor),
+ SALCOLOR_BLUE (nSalColor));
+ m_pPrinterGfx->DrawPixel (Point(nX, nY), aColor);
+}
+
+void PspGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 )
+{
+ m_pPrinterGfx->DrawLine (Point(nX1, nY1), Point(nX2, nY2));
+}
+
+void PspGraphics::drawRect( long nX, long nY, long nDX, long nDY )
+{
+ m_pPrinterGfx->DrawRect (Rectangle(Point(nX, nY), Size(nDX, nDY)));
+}
+
+void PspGraphics::drawPolyLine( ULONG nPoints, const SalPoint *pPtAry )
+{
+ m_pPrinterGfx->DrawPolyLine (nPoints, (Point*)pPtAry);
+}
+
+void PspGraphics::drawPolygon( ULONG nPoints, const SalPoint* pPtAry )
+{
+ // Point must be equal to SalPoint! see vcl/inc/salgtype.hxx
+ m_pPrinterGfx->DrawPolygon (nPoints, (Point*)pPtAry);
+}
+
+void PspGraphics::drawPolyPolygon( sal_uInt32 nPoly,
+ const sal_uInt32 *pPoints,
+ PCONSTSALPOINT *pPtAry )
+{
+ m_pPrinterGfx->DrawPolyPolygon (nPoly, pPoints, (const Point**)pPtAry);
+}
+
+bool PspGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double /*fTransparency*/ )
+{
+ // TODO: implement and advertise OutDevSupport_B2DDraw support
+ return false;
+}
+
+bool PspGraphics::drawPolyLine( const basegfx::B2DPolygon&, double /*fTranspareny*/, const basegfx::B2DVector& /*rLineWidths*/, basegfx::B2DLineJoin /*eJoin*/)
+{
+ // TODO: a PS printer can draw B2DPolyLines almost directly
+ return false;
+}
+
+sal_Bool PspGraphics::drawPolyLineBezier( ULONG nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry )
+{
+ m_pPrinterGfx->DrawPolyLineBezier (nPoints, (Point*)pPtAry, pFlgAry);
+ return sal_True;
+}
+
+sal_Bool PspGraphics::drawPolygonBezier( ULONG nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry )
+{
+ m_pPrinterGfx->DrawPolygonBezier (nPoints, (Point*)pPtAry, pFlgAry);
+ return sal_True;
+}
+
+sal_Bool PspGraphics::drawPolyPolygonBezier( sal_uInt32 nPoly,
+ const sal_uInt32* pPoints,
+ const SalPoint* const* pPtAry,
+ const BYTE* const* pFlgAry )
+{
+ // Point must be equal to SalPoint! see vcl/inc/salgtype.hxx
+ m_pPrinterGfx->DrawPolyPolygonBezier (nPoly, pPoints, (Point**)pPtAry, (BYTE**)pFlgAry);
+ return sal_True;
+}
+
+void PspGraphics::invert( ULONG,
+ const SalPoint*,
+ SalInvert )
+{
+ DBG_ASSERT( 0, "Error: PrinterGfx::Invert() not implemented" );
+}
+BOOL PspGraphics::drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, ULONG nSize )
+{
+ return m_pPrinterGfx->DrawEPS( Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) ), pPtr, nSize );
+}
+
+void PspGraphics::copyBits( const SalTwoRect*,
+ SalGraphics* )
+{
+ DBG_ERROR( "Error: PrinterGfx::CopyBits() not implemented" );
+}
+
+void PspGraphics::copyArea ( long,long,long,long,long,long,USHORT )
+{
+ DBG_ERROR( "Error: PrinterGfx::CopyArea() not implemented" );
+}
+
+void PspGraphics::drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap )
+{
+ Rectangle aSrc (Point(pPosAry->mnSrcX, pPosAry->mnSrcY),
+ Size(pPosAry->mnSrcWidth, pPosAry->mnSrcHeight));
+ Rectangle aDst (Point(pPosAry->mnDestX, pPosAry->mnDestY),
+ Size(pPosAry->mnDestWidth, pPosAry->mnDestHeight));
+
+ BitmapBuffer* pBuffer= const_cast<SalBitmap&>(rSalBitmap).AcquireBuffer(sal_True);
+
+ SalPrinterBmp aBmp (pBuffer);
+ m_pPrinterGfx->DrawBitmap (aDst, aSrc, aBmp);
+
+ const_cast<SalBitmap&>(rSalBitmap).ReleaseBuffer (pBuffer, sal_True);
+}
+
+void PspGraphics::drawBitmap( const SalTwoRect*,
+ const SalBitmap&,
+ const SalBitmap& )
+{
+ DBG_ERROR("Error: no PrinterGfx::DrawBitmap() for transparent bitmap");
+}
+
+void PspGraphics::drawBitmap( const SalTwoRect*,
+ const SalBitmap&,
+ SalColor )
+{
+ DBG_ERROR("Error: no PrinterGfx::DrawBitmap() for transparent color");
+}
+
+void PspGraphics::drawMask( const SalTwoRect*,
+ const SalBitmap &,
+ SalColor )
+{
+ DBG_ERROR("Error: PrinterGfx::DrawMask() not implemented");
+}
+
+SalBitmap* PspGraphics::getBitmap( long, long, long, long )
+{
+ DBG_WARNING ("Warning: PrinterGfx::GetBitmap() not implemented");
+ return NULL;
+}
+
+SalColor PspGraphics::getPixel( long, long )
+{
+ DBG_ERROR ("Warning: PrinterGfx::GetPixel() not implemented");
+ return 0;
+}
+
+void PspGraphics::invert(long,long,long,long,SalInvert)
+{
+ DBG_ERROR ("Warning: PrinterGfx::Invert() not implemented");
+}
+
+//==========================================================================
+
+class ImplPspFontData : public ImplFontData
+{
+private:
+ enum { PSPFD_MAGIC = 0xb5bf01f0 };
+ sal_IntPtr mnFontId;
+
+public:
+ ImplPspFontData( const psp::FastPrintFontInfo& );
+ virtual sal_IntPtr GetFontId() const { return mnFontId; }
+ virtual ImplFontData* Clone() const { return new ImplPspFontData( *this ); }
+ virtual ImplFontEntry* CreateFontInstance( ImplFontSelectData& ) const;
+ static bool CheckFontData( const ImplFontData& r ) { return r.CheckMagic( PSPFD_MAGIC ); }
+};
+
+//--------------------------------------------------------------------------
+
+ImplPspFontData::ImplPspFontData( const psp::FastPrintFontInfo& rInfo )
+: ImplFontData( PspGraphics::Info2DevFontAttributes(rInfo), PSPFD_MAGIC ),
+ mnFontId( rInfo.m_nID )
+{}
+
+//--------------------------------------------------------------------------
+
+ImplFontEntry* ImplPspFontData::CreateFontInstance( ImplFontSelectData& rFSD ) const
+{
+ ImplServerFontEntry* pEntry = new ImplServerFontEntry( rFSD );
+ return pEntry;
+}
+
+//==========================================================================
+
+class PspFontLayout : public GenericSalLayout
+{
+public:
+ PspFontLayout( ::psp::PrinterGfx& );
+ virtual bool LayoutText( ImplLayoutArgs& );
+ virtual void InitFont() const;
+ virtual void DrawText( SalGraphics& ) const;
+private:
+ ::psp::PrinterGfx& mrPrinterGfx;
+ sal_IntPtr mnFontID;
+ int mnFontHeight;
+ int mnFontWidth;
+ bool mbVertical;
+ bool mbArtItalic;
+ bool mbArtBold;
+};
+
+//--------------------------------------------------------------------------
+
+PspFontLayout::PspFontLayout( ::psp::PrinterGfx& rGfx )
+: mrPrinterGfx( rGfx )
+{
+ mnFontID = mrPrinterGfx.GetFontID();
+ mnFontHeight = mrPrinterGfx.GetFontHeight();
+ mnFontWidth = mrPrinterGfx.GetFontWidth();
+ mbVertical = mrPrinterGfx.GetFontVertical();
+ mbArtItalic = mrPrinterGfx.GetArtificialItalic();
+ mbArtBold = mrPrinterGfx.GetArtificialBold();
+}
+
+//--------------------------------------------------------------------------
+
+bool PspFontLayout::LayoutText( ImplLayoutArgs& rArgs )
+{
+ mbVertical = ((rArgs.mnFlags & SAL_LAYOUT_VERTICAL) != 0);
+
+ long nUnitsPerPixel = 1;
+ int nOldGlyphId = -1;
+ long nGlyphWidth = 0;
+ int nCharPos = -1;
+ Point aNewPos( 0, 0 );
+ GlyphItem aPrevItem;
+ rtl_TextEncoding aFontEnc = mrPrinterGfx.GetFontMgr().getFontEncoding( mnFontID );
+ for(;;)
+ {
+ bool bRightToLeft;
+ if( !rArgs.GetNextPos( &nCharPos, &bRightToLeft ) )
+ break;
+
+ sal_Unicode cChar = rArgs.mpStr[ nCharPos ];
+ if( bRightToLeft )
+ cChar = GetMirroredChar( cChar );
+ // symbol font aliasing: 0x0020-0x00ff -> 0xf020 -> 0xf0ff
+ if( aFontEnc == RTL_TEXTENCODING_SYMBOL )
+ if( cChar < 256 )
+ cChar += 0xf000;
+ int nGlyphIndex = cChar; // printer glyphs = unicode
+
+ // update fallback_runs if needed
+ psp::CharacterMetric aMetric;
+ mrPrinterGfx.GetFontMgr().getMetrics( mnFontID, cChar, cChar, &aMetric, mbVertical );
+ if( aMetric.width == -1 && aMetric.height == -1 )
+ rArgs.NeedFallback( nCharPos, bRightToLeft );
+
+ // apply pair kerning to prev glyph if requested
+ if( SAL_LAYOUT_KERNING_PAIRS & rArgs.mnFlags )
+ {
+ if( nOldGlyphId > 0 )
+ {
+ const std::list< KernPair >& rKernPairs = mrPrinterGfx.getKernPairs(mbVertical);
+ for( std::list< KernPair >::const_iterator it = rKernPairs.begin();
+ it != rKernPairs.end(); ++it )
+ {
+ if( it->first == nOldGlyphId && it->second == nGlyphIndex )
+ {
+ int nTextScale = mrPrinterGfx.GetFontWidth();
+ if( ! nTextScale )
+ nTextScale = mrPrinterGfx.GetFontHeight();
+ int nKern = (mbVertical ? it->kern_y : it->kern_x) * nTextScale;
+ nGlyphWidth += nKern;
+ aPrevItem.mnNewWidth = nGlyphWidth;
+ break;
+ }
+ }
+ }
+ }
+
+ // finish previous glyph
+ if( nOldGlyphId >= 0 )
+ AppendGlyph( aPrevItem );
+ nOldGlyphId = nGlyphIndex;
+ aNewPos.X() += nGlyphWidth;
+
+ // prepare GlyphItem for appending it in next round
+ nUnitsPerPixel = mrPrinterGfx.GetCharWidth( cChar, cChar, &nGlyphWidth );
+ int nGlyphFlags = bRightToLeft ? GlyphItem::IS_RTL_GLYPH : 0;
+ nGlyphIndex |= GF_ISCHAR;
+ aPrevItem = GlyphItem( nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nGlyphWidth );
+ }
+
+ // append last glyph item if any
+ if( nOldGlyphId >= 0 )
+ AppendGlyph( aPrevItem );
+
+ SetOrientation( mrPrinterGfx.GetFontAngle() );
+ SetUnitsPerPixel( nUnitsPerPixel );
+ return (nOldGlyphId >= 0);
+}
+
+class PspServerFontLayout : public ServerFontLayout
+{
+public:
+ PspServerFontLayout( psp::PrinterGfx&, ServerFont& rFont, const ImplLayoutArgs& rArgs );
+
+ virtual void InitFont() const;
+ const sal_Unicode* getTextPtr() const { return maText.getStr() - mnMinCharPos; }
+ int getMinCharPos() const { return mnMinCharPos; }
+ int getMaxCharPos() const { return mnMinCharPos+maText.getLength()-1; }
+private:
+ ::psp::PrinterGfx& mrPrinterGfx;
+ sal_IntPtr mnFontID;
+ int mnFontHeight;
+ int mnFontWidth;
+ bool mbVertical;
+ bool mbArtItalic;
+ bool mbArtBold;
+ rtl::OUString maText;
+ int mnMinCharPos;
+};
+
+PspServerFontLayout::PspServerFontLayout( ::psp::PrinterGfx& rGfx, ServerFont& rFont, const ImplLayoutArgs& rArgs )
+ : ServerFontLayout( rFont ),
+ mrPrinterGfx( rGfx )
+{
+ mnFontID = mrPrinterGfx.GetFontID();
+ mnFontHeight = mrPrinterGfx.GetFontHeight();
+ mnFontWidth = mrPrinterGfx.GetFontWidth();
+ mbVertical = mrPrinterGfx.GetFontVertical();
+ mbArtItalic = mrPrinterGfx.GetArtificialItalic();
+ mbArtBold = mrPrinterGfx.GetArtificialBold();
+ maText = OUString( rArgs.mpStr + rArgs.mnMinCharPos, rArgs.mnEndCharPos - rArgs.mnMinCharPos+1 );
+ mnMinCharPos = rArgs.mnMinCharPos;
+}
+
+void PspServerFontLayout::InitFont() const
+{
+ mrPrinterGfx.SetFont( mnFontID, mnFontHeight, mnFontWidth,
+ mnOrientation, mbVertical, mbArtItalic, mbArtBold );
+}
+
+//--------------------------------------------------------------------------
+
+static void DrawPrinterLayout( const SalLayout& rLayout, ::psp::PrinterGfx& rGfx, bool bIsPspServerFontLayout )
+{
+ const int nMaxGlyphs = 200;
+ sal_GlyphId aGlyphAry[ nMaxGlyphs ];
+ sal_Int32 aWidthAry[ nMaxGlyphs ];
+ sal_Int32 aIdxAry [ nMaxGlyphs ];
+ sal_Unicode aUnicodes[ nMaxGlyphs ];
+ int aCharPosAry [ nMaxGlyphs ];
+
+ Point aPos;
+ long nUnitsPerPixel = rLayout.GetUnitsPerPixel();
+ const sal_Unicode* pText = NULL;
+ int nMinCharPos = 0;
+ int nMaxCharPos = 0;
+ if (bIsPspServerFontLayout)
+ {
+ const PspServerFontLayout * pPspLayout = dynamic_cast<const PspServerFontLayout*>(&rLayout);
+#ifdef ENABLE_GRAPHITE
+ const GraphiteServerFontLayout * pGrLayout = dynamic_cast<const GraphiteServerFontLayout*>(&rLayout);
+#endif
+ if (pPspLayout)
+ {
+ pText = pPspLayout->getTextPtr();
+ nMinCharPos = pPspLayout->getMinCharPos();
+ nMaxCharPos = pPspLayout->getMaxCharPos();
+ }
+#ifdef ENABLE_GRAPHITE
+ else if (pGrLayout)
+ {
+ pText = pGrLayout->getTextPtr();
+ nMinCharPos = pGrLayout->getMinCharPos();
+ nMaxCharPos = pGrLayout->getMaxCharPos();
+ }
+#endif
+ }
+ for( int nStart = 0;; )
+ {
+ int nGlyphCount = rLayout.GetNextGlyphs( nMaxGlyphs, aGlyphAry, aPos, nStart, aWidthAry, bIsPspServerFontLayout ? aCharPosAry : NULL );
+ if( !nGlyphCount )
+ break;
+
+ sal_Int32 nXOffset = 0;
+ for( int i = 0; i < nGlyphCount; ++i )
+ {
+ nXOffset += aWidthAry[ i ];
+ aIdxAry[ i ] = nXOffset / nUnitsPerPixel;
+ sal_Int32 nGlyphIdx = aGlyphAry[i] & (GF_IDXMASK | GF_ROTMASK);
+ if( bIsPspServerFontLayout )
+ aUnicodes[i] = (aCharPosAry[i] >= nMinCharPos && aCharPosAry[i] <= nMaxCharPos) ? pText[ aCharPosAry[i] ] : 0;
+ else
+ aUnicodes[i] = (aGlyphAry[i] & GF_ISCHAR) ? nGlyphIdx : 0;
+ aGlyphAry[i] = nGlyphIdx;
+ }
+
+ rGfx.DrawGlyphs( aPos, (sal_uInt32 *)aGlyphAry, aUnicodes, nGlyphCount, aIdxAry );
+ }
+}
+
+//--------------------------------------------------------------------------
+
+void PspFontLayout::InitFont() const
+{
+ mrPrinterGfx.SetFont( mnFontID, mnFontHeight, mnFontWidth,
+ mnOrientation, mbVertical, mbArtItalic, mbArtBold );
+}
+
+//--------------------------------------------------------------------------
+
+void PspFontLayout::DrawText( SalGraphics& ) const
+{
+ DrawPrinterLayout( *this, mrPrinterGfx, false );
+}
+
+void PspGraphics::DrawServerFontLayout( const ServerFontLayout& rLayout )
+{
+ // print complex text
+ DrawPrinterLayout( rLayout, *m_pPrinterGfx, true );
+}
+
+ImplFontCharMap* PspGraphics::GetImplFontCharMap() const
+{
+ // TODO: get ImplFontCharMap directly from fonts
+ if( !m_pServerFont[0] )
+ return NULL;
+
+ CmapResult aCmapResult;
+ if( !m_pServerFont[0]->GetFontCodeRanges( aCmapResult ) )
+ return NULL;
+ return new ImplFontCharMap( aCmapResult );
+}
+
+USHORT PspGraphics::SetFont( ImplFontSelectData *pEntry, int nFallbackLevel )
+{
+ // release all fonts that are to be overridden
+ for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
+ {
+ if( m_pServerFont[i] != NULL )
+ {
+ // old server side font is no longer referenced
+ GlyphCache::GetInstance().UncacheFont( *m_pServerFont[i] );
+ m_pServerFont[i] = NULL;
+ }
+ }
+
+ // return early if there is no new font
+ if( !pEntry )
+ return 0;
+
+ sal_IntPtr nID = pEntry->mpFontData ? pEntry->mpFontData->GetFontId() : 0;
+
+ // determine which font attributes need to be emulated
+ bool bArtItalic = false;
+ bool bArtBold = false;
+ if( pEntry->meItalic == ITALIC_OBLIQUE || pEntry->meItalic == ITALIC_NORMAL )
+ {
+ psp::italic::type eItalic = m_pPrinterGfx->GetFontMgr().getFontItalic( nID );
+ if( eItalic != psp::italic::Italic && eItalic != psp::italic::Oblique )
+ bArtItalic = true;
+ }
+ int nWeight = (int)pEntry->meWeight;
+ int nRealWeight = (int)m_pPrinterGfx->GetFontMgr().getFontWeight( nID );
+ if( nRealWeight <= (int)psp::weight::Medium && nWeight > (int)WEIGHT_MEDIUM )
+ {
+ bArtBold = true;
+ }
+
+ // also set the serverside font for layouting
+ m_bFontVertical = pEntry->mbVertical;
+ if( pEntry->mpFontData )
+ {
+ // requesting a font provided by builtin rasterizer
+ ServerFont* pServerFont = GlyphCache::GetInstance().CacheFont( *pEntry );
+ if( pServerFont != NULL )
+ {
+ if( pServerFont->TestFont() )
+ m_pServerFont[ nFallbackLevel ] = pServerFont;
+ else
+ GlyphCache::GetInstance().UncacheFont( *pServerFont );
+ }
+ }
+
+ // set the printer font
+ return m_pPrinterGfx->SetFont( nID,
+ pEntry->mnHeight,
+ pEntry->mnWidth,
+ pEntry->mnOrientation,
+ pEntry->mbVertical,
+ bArtItalic,
+ bArtBold
+ );
+}
+
+void PspGraphics::SetTextColor( SalColor nSalColor )
+{
+ psp::PrinterColor aColor (SALCOLOR_RED (nSalColor),
+ SALCOLOR_GREEN (nSalColor),
+ SALCOLOR_BLUE (nSalColor));
+ m_pPrinterGfx->SetTextColor (aColor);
+}
+
+bool PspGraphics::AddTempDevFont( ImplDevFontList*, const String&,const String& )
+{
+ return false;
+}
+
+void RegisterFontSubstitutors( ImplDevFontList* );
+
+void PspGraphics::GetDevFontList( ImplDevFontList *pList )
+{
+ ::std::list< psp::fontID > aList;
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ rMgr.getFontList( aList, m_pJobData->m_pParser, m_pInfoPrinter->m_bCompatMetrics );
+
+ ::std::list< psp::fontID >::iterator it;
+ psp::FastPrintFontInfo aInfo;
+ for (it = aList.begin(); it != aList.end(); ++it)
+ if (rMgr.getFontFastInfo (*it, aInfo))
+ AnnounceFonts( pList, aInfo );
+
+ // register platform specific font substitutions if available
+ if( rMgr.hasFontconfig() )
+ RegisterFontSubstitutors( pList );
+}
+
+void PspGraphics::GetDevFontSubstList( OutputDevice* pOutDev )
+{
+ const psp::PrinterInfo& rInfo = psp::PrinterInfoManager::get().getPrinterInfo( m_pJobData->m_aPrinterName );
+ if( rInfo.m_bPerformFontSubstitution )
+ {
+ for( std::hash_map< rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator it = rInfo.m_aFontSubstitutes.begin(); it != rInfo.m_aFontSubstitutes.end(); ++it )
+ pOutDev->ImplAddDevFontSubstitute( it->first, it->second, FONT_SUBSTITUTE_ALWAYS );
+ }
+}
+
+void PspGraphics::GetFontMetric( ImplFontMetricData *pMetric )
+{
+ const psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ psp::PrintFontInfo aInfo;
+
+ if (rMgr.getFontInfo (m_pPrinterGfx->GetFontID(), aInfo))
+ {
+ ImplDevFontAttributes aDFA = Info2DevFontAttributes( aInfo );
+ static_cast<ImplFontAttributes&>(*pMetric) = aDFA;
+ pMetric->mbDevice = aDFA.mbDevice;
+ pMetric->mbScalableFont = true;
+
+ pMetric->mnOrientation = m_pPrinterGfx->GetFontAngle();
+ pMetric->mnSlant = 0;
+
+ sal_Int32 nTextHeight = m_pPrinterGfx->GetFontHeight();
+ sal_Int32 nTextWidth = m_pPrinterGfx->GetFontWidth();
+ if( ! nTextWidth )
+ nTextWidth = nTextHeight;
+
+ pMetric->mnWidth = nTextWidth;
+ pMetric->mnAscent = ( aInfo.m_nAscend * nTextHeight + 500 ) / 1000;
+ pMetric->mnDescent = ( aInfo.m_nDescend * nTextHeight + 500 ) / 1000;
+ pMetric->mnIntLeading = ( aInfo.m_nLeading * nTextHeight + 500 ) / 1000;
+ pMetric->mnExtLeading = 0;
+ }
+}
+
+ULONG PspGraphics::GetKernPairs( ULONG nPairs, ImplKernPairData *pKernPairs )
+{
+ const ::std::list< ::psp::KernPair >& rPairs( m_pPrinterGfx->getKernPairs() );
+ ULONG nHavePairs = rPairs.size();
+ if( pKernPairs && nPairs )
+ {
+ ::std::list< ::psp::KernPair >::const_iterator it;
+ unsigned int i;
+ int nTextScale = m_pPrinterGfx->GetFontWidth();
+ if( ! nTextScale )
+ nTextScale = m_pPrinterGfx->GetFontHeight();
+ for( i = 0, it = rPairs.begin(); i < nPairs && i < nHavePairs; i++, ++it )
+ {
+ pKernPairs[i].mnChar1 = it->first;
+ pKernPairs[i].mnChar2 = it->second;
+ pKernPairs[i].mnKern = it->kern_x * nTextScale / 1000;
+ }
+
+ }
+ return nHavePairs;
+}
+
+BOOL PspGraphics::GetGlyphBoundRect( long nGlyphIndex, Rectangle& rRect )
+{
+ int nLevel = nGlyphIndex >> GF_FONTSHIFT;
+ if( nLevel >= MAX_FALLBACK )
+ return FALSE;
+
+ ServerFont* pSF = m_pServerFont[ nLevel ];
+ if( !pSF )
+ return FALSE;
+
+ nGlyphIndex &= ~GF_FONTMASK;
+ const GlyphMetric& rGM = pSF->GetGlyphMetric( nGlyphIndex );
+ rRect = Rectangle( rGM.GetOffset(), rGM.GetSize() );
+ return TRUE;
+}
+
+BOOL PspGraphics::GetGlyphOutline( long nGlyphIndex,
+ ::basegfx::B2DPolyPolygon& rB2DPolyPoly )
+{
+ int nLevel = nGlyphIndex >> GF_FONTSHIFT;
+ if( nLevel >= MAX_FALLBACK )
+ return FALSE;
+
+ ServerFont* pSF = m_pServerFont[ nLevel ];
+ if( !pSF )
+ return FALSE;
+
+ nGlyphIndex &= ~GF_FONTMASK;
+ if( pSF->GetGlyphOutline( nGlyphIndex, rB2DPolyPoly ) )
+ return TRUE;
+
+ return FALSE;
+}
+
+SalLayout* PspGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLevel )
+{
+ // workaround for printers not handling glyph indexing for non-TT fonts
+ int nFontId = m_pPrinterGfx->GetFontID();
+ if( psp::fonttype::TrueType != psp::PrintFontManager::get().getFontType( nFontId ) )
+ rArgs.mnFlags |= SAL_LAYOUT_DISABLE_GLYPH_PROCESSING;
+ else if( nFallbackLevel > 0 )
+ rArgs.mnFlags &= ~SAL_LAYOUT_DISABLE_GLYPH_PROCESSING;
+
+ GenericSalLayout* pLayout = NULL;
+
+ if( m_pServerFont[ nFallbackLevel ]
+ && !(rArgs.mnFlags & SAL_LAYOUT_DISABLE_GLYPH_PROCESSING) )
+ {
+#ifdef ENABLE_GRAPHITE
+ // Is this a Graphite font?
+ if (GraphiteFontAdaptor::IsGraphiteEnabledFont(*m_pServerFont[nFallbackLevel]))
+ {
+ sal_Int32 xdpi, ydpi;
+ GetResolution(xdpi, ydpi);
+ GraphiteFontAdaptor * pGrfont = new GraphiteFontAdaptor( *m_pServerFont[nFallbackLevel], xdpi, ydpi);
+ if (!pGrfont) return NULL;
+ pLayout = new GraphiteServerFontLayout(pGrfont);
+ }
+ else
+#endif
+ pLayout = new PspServerFontLayout( *m_pPrinterGfx, *m_pServerFont[nFallbackLevel], rArgs );
+ }
+ else
+ pLayout = new PspFontLayout( *m_pPrinterGfx );
+
+ return pLayout;
+}
+
+//--------------------------------------------------------------------------
+
+BOOL PspGraphics::CreateFontSubset(
+ const rtl::OUString& rToFile,
+ const ImplFontData* pFont,
+ sal_Int32* pGlyphIDs,
+ sal_uInt8* pEncoding,
+ sal_Int32* pWidths,
+ int nGlyphCount,
+ FontSubsetInfo& rInfo
+ )
+{
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ bool bSuccess = rMgr.createFontSubset( rInfo,
+ aFont,
+ rToFile,
+ pGlyphIDs,
+ pEncoding,
+ pWidths,
+ nGlyphCount );
+ return bSuccess;
+}
+
+//--------------------------------------------------------------------------
+
+const void* PspGraphics::GetEmbedFontData( const ImplFontData* pFont, const sal_Ucs* pUnicodes, sal_Int32* pWidths, FontSubsetInfo& rInfo, long* pDataLen )
+{
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+ return PspGraphics::DoGetEmbedFontData( aFont, pUnicodes, pWidths, rInfo, pDataLen );
+}
+
+//--------------------------------------------------------------------------
+
+void PspGraphics::FreeEmbedFontData( const void* pData, long nLen )
+{
+ PspGraphics::DoFreeEmbedFontData( pData, nLen );
+}
+
+//--------------------------------------------------------------------------
+
+const Ucs2SIntMap* PspGraphics::GetFontEncodingVector( const ImplFontData* pFont, const Ucs2OStrMap** pNonEncoded )
+{
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+ return PspGraphics::DoGetFontEncodingVector( aFont, pNonEncoded );
+}
+
+//--------------------------------------------------------------------------
+
+void PspGraphics::GetGlyphWidths( const ImplFontData* pFont,
+ bool bVertical,
+ Int32Vector& rWidths,
+ Ucs2UIntMap& rUnicodeEnc )
+{
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+ PspGraphics::DoGetGlyphWidths( aFont, bVertical, rWidths, rUnicodeEnc );
+}
+
+
+// static helpers of PspGraphics
+
+const void* PspGraphics::DoGetEmbedFontData( fontID aFont, const sal_Ucs* pUnicodes, sal_Int32* pWidths, FontSubsetInfo& rInfo, long* pDataLen )
+{
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+
+ psp::PrintFontInfo aFontInfo;
+ if( ! rMgr.getFontInfo( aFont, aFontInfo ) )
+ return NULL;
+
+ // fill in font info
+ rInfo.m_nAscent = aFontInfo.m_nAscend;
+ rInfo.m_nDescent = aFontInfo.m_nDescend;
+ rInfo.m_aPSName = rMgr.getPSName( aFont );
+
+ int xMin, yMin, xMax, yMax;
+ rMgr.getFontBoundingBox( aFont, xMin, yMin, xMax, yMax );
+
+ psp::CharacterMetric aMetrics[256];
+ sal_Ucs aUnicodes[256];
+ if( aFontInfo.m_aEncoding == RTL_TEXTENCODING_SYMBOL && aFontInfo.m_eType == psp::fonttype::Type1 )
+ {
+ for( int i = 0; i < 256; i++ )
+ aUnicodes[i] = pUnicodes[i] < 0x0100 ? pUnicodes[i] + 0xf000 : pUnicodes[i];
+ pUnicodes = aUnicodes;
+ }
+ if( ! rMgr.getMetrics( aFont, pUnicodes, 256, aMetrics ) )
+ return NULL;
+
+ OString aSysPath = rMgr.getFontFileSysPath( aFont );
+ struct stat aStat;
+ if( stat( aSysPath.getStr(), &aStat ) )
+ return NULL;
+ int fd = open( aSysPath.getStr(), O_RDONLY );
+ if( fd < 0 )
+ return NULL;
+ void* pFile = mmap( NULL, aStat.st_size, PROT_READ, MAP_SHARED, fd, 0 );
+ close( fd );
+ if( pFile == MAP_FAILED )
+ return NULL;
+
+ *pDataLen = aStat.st_size;
+
+ rInfo.m_aFontBBox = Rectangle( Point( xMin, yMin ), Size( xMax-xMin, yMax-yMin ) );
+ rInfo.m_nCapHeight = yMax; // Well ...
+
+ for( int i = 0; i < 256; i++ )
+ pWidths[i] = (aMetrics[i].width > 0 ? aMetrics[i].width : 0);
+
+ switch( aFontInfo.m_eType )
+ {
+ case psp::fonttype::TrueType:
+ rInfo.m_nFontType = FontSubsetInfo::SFNT_TTF;
+ break;
+ case psp::fonttype::Type1: {
+ const bool bPFA = ((*(unsigned char*)pFile) < 0x80);
+ rInfo.m_nFontType = bPFA ? FontSubsetInfo::TYPE1_PFA : FontSubsetInfo::TYPE1_PFB;
+ }
+ break;
+ default:
+ return NULL;
+ }
+
+ return pFile;
+}
+
+void PspGraphics::DoFreeEmbedFontData( const void* pData, long nLen )
+{
+ if( pData )
+ munmap( (char*)pData, nLen );
+}
+
+const Ucs2SIntMap* PspGraphics::DoGetFontEncodingVector( fontID aFont, const Ucs2OStrMap** pNonEncoded )
+{
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+
+ psp::PrintFontInfo aFontInfo;
+ if( ! rMgr.getFontInfo( aFont, aFontInfo ) )
+ {
+ if( pNonEncoded )
+ *pNonEncoded = NULL;
+ return NULL;
+ }
+
+ return rMgr.getEncodingMap( aFont, pNonEncoded );
+}
+
+void PspGraphics::DoGetGlyphWidths( psp::fontID aFont,
+ bool bVertical,
+ Int32Vector& rWidths,
+ Ucs2UIntMap& rUnicodeEnc )
+{
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ rMgr.getGlyphWidths( aFont, bVertical, rWidths, rUnicodeEnc );
+}
+// ----------------------------------------------------------------------------
+
+FontWidth PspGraphics::ToFontWidth (psp::width::type eWidth)
+{
+ switch (eWidth)
+ {
+ case psp::width::UltraCondensed: return WIDTH_ULTRA_CONDENSED;
+ case psp::width::ExtraCondensed: return WIDTH_EXTRA_CONDENSED;
+ case psp::width::Condensed: return WIDTH_CONDENSED;
+ case psp::width::SemiCondensed: return WIDTH_SEMI_CONDENSED;
+ case psp::width::Normal: return WIDTH_NORMAL;
+ case psp::width::SemiExpanded: return WIDTH_SEMI_EXPANDED;
+ case psp::width::Expanded: return WIDTH_EXPANDED;
+ case psp::width::ExtraExpanded: return WIDTH_EXTRA_EXPANDED;
+ case psp::width::UltraExpanded: return WIDTH_ULTRA_EXPANDED;
+ case psp::width::Unknown: return WIDTH_DONTKNOW;
+ default:
+ DBG_ERROR( "unknown width mapping" );
+ break;
+ }
+ return WIDTH_DONTKNOW;
+}
+
+FontWeight PspGraphics::ToFontWeight (psp::weight::type eWeight)
+{
+ switch (eWeight)
+ {
+ case psp::weight::Thin: return WEIGHT_THIN;
+ case psp::weight::UltraLight: return WEIGHT_ULTRALIGHT;
+ case psp::weight::Light: return WEIGHT_LIGHT;
+ case psp::weight::SemiLight: return WEIGHT_SEMILIGHT;
+ case psp::weight::Normal: return WEIGHT_NORMAL;
+ case psp::weight::Medium: return WEIGHT_MEDIUM;
+ case psp::weight::SemiBold: return WEIGHT_SEMIBOLD;
+ case psp::weight::Bold: return WEIGHT_BOLD;
+ case psp::weight::UltraBold: return WEIGHT_ULTRABOLD;
+ case psp::weight::Black: return WEIGHT_BLACK;
+ case psp::weight::Unknown: return WEIGHT_DONTKNOW;
+ default:
+ DBG_ERROR( "unknown weight mapping" );
+ break;
+ }
+ return WEIGHT_DONTKNOW;
+}
+
+FontPitch PspGraphics::ToFontPitch (psp::pitch::type ePitch)
+{
+ switch (ePitch)
+ {
+ case psp::pitch::Fixed: return PITCH_FIXED;
+ case psp::pitch::Variable: return PITCH_VARIABLE;
+ case psp::pitch::Unknown: return PITCH_DONTKNOW;
+ default:
+ DBG_ERROR( "unknown pitch mapping" );
+ break;
+ }
+ return PITCH_DONTKNOW;
+}
+
+FontItalic PspGraphics::ToFontItalic (psp::italic::type eItalic)
+{
+ switch (eItalic)
+ {
+ case psp::italic::Upright: return ITALIC_NONE;
+ case psp::italic::Oblique: return ITALIC_OBLIQUE;
+ case psp::italic::Italic: return ITALIC_NORMAL;
+ case psp::italic::Unknown: return ITALIC_DONTKNOW;
+ default:
+ DBG_ERROR( "unknown italic mapping" );
+ break;
+ }
+ return ITALIC_DONTKNOW;
+}
+
+FontFamily PspGraphics::ToFontFamily (psp::family::type eFamily)
+{
+ switch (eFamily)
+ {
+ case psp::family::Decorative: return FAMILY_DECORATIVE;
+ case psp::family::Modern: return FAMILY_MODERN;
+ case psp::family::Roman: return FAMILY_ROMAN;
+ case psp::family::Script: return FAMILY_SCRIPT;
+ case psp::family::Swiss: return FAMILY_SWISS;
+ case psp::family::System: return FAMILY_SYSTEM;
+ case psp::family::Unknown: return FAMILY_DONTKNOW;
+ default:
+ DBG_ERROR( "unknown family mapping" );
+ break;
+ }
+ return FAMILY_DONTKNOW;
+}
+
+ImplDevFontAttributes PspGraphics::Info2DevFontAttributes( const psp::FastPrintFontInfo& rInfo )
+{
+ ImplDevFontAttributes aDFA;
+ aDFA.maName = rInfo.m_aFamilyName;
+ aDFA.maStyleName = rInfo.m_aStyleName;
+ aDFA.meFamily = ToFontFamily (rInfo.m_eFamilyStyle);
+ aDFA.meWeight = ToFontWeight (rInfo.m_eWeight);
+ aDFA.meItalic = ToFontItalic (rInfo.m_eItalic);
+ aDFA.meWidthType = ToFontWidth (rInfo.m_eWidth);
+ aDFA.mePitch = ToFontPitch (rInfo.m_ePitch);
+ aDFA.mbSymbolFlag = (rInfo.m_aEncoding == RTL_TEXTENCODING_SYMBOL);
+ aDFA.mbSubsettable = rInfo.m_bSubsettable;
+ aDFA.mbEmbeddable = rInfo.m_bEmbeddable;
+
+ switch( rInfo.m_eType )
+ {
+ case psp::fonttype::Builtin:
+ aDFA.mnQuality = 1024;
+ aDFA.mbDevice = true;
+ break;
+ case psp::fonttype::TrueType:
+ aDFA.mnQuality = 512;
+ aDFA.mbDevice = false;
+ break;
+ case psp::fonttype::Type1:
+ aDFA.mnQuality = 0;
+ aDFA.mbDevice = false;
+ break;
+ default:
+ aDFA.mnQuality = 0;
+ aDFA.mbDevice = false;
+ break;
+ }
+
+ aDFA.mbOrientation = true;
+
+ // add font family name aliases
+ ::std::list< OUString >::const_iterator it = rInfo.m_aAliases.begin();
+ bool bHasMapNames = false;
+ for(; it != rInfo.m_aAliases.end(); ++it )
+ {
+ if( bHasMapNames )
+ aDFA.maMapNames.Append( ';' );
+ aDFA.maMapNames.Append( (*it).getStr() );
+ bHasMapNames = true;
+ }
+
+#if OSL_DEBUG_LEVEL > 2
+ if( bHasMapNames )
+ {
+ ByteString aOrigName( aDFA.maName, osl_getThreadTextEncoding() );
+ ByteString aAliasNames( aDFA.maMapNames, osl_getThreadTextEncoding() );
+ fprintf( stderr, "using alias names \"%s\" for font family \"%s\"\n",
+ aAliasNames.GetBuffer(), aOrigName.GetBuffer() );
+ }
+#endif
+
+ return aDFA;
+}
+
+// -----------------------------------------------------------------------
+
+void PspGraphics::AnnounceFonts( ImplDevFontList* pFontList, const psp::FastPrintFontInfo& aInfo )
+{
+ int nQuality = 0;
+
+ if( aInfo.m_eType == psp::fonttype::TrueType )
+ {
+ // asian type 1 fonts are not known
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ ByteString aFileName( rMgr.getFontFileSysPath( aInfo.m_nID ) );
+ int nPos = aFileName.SearchBackward( '_' );
+ if( nPos == STRING_NOTFOUND || aFileName.GetChar( nPos+1 ) == '.' )
+ nQuality += 5;
+ else
+ {
+ static const char* pLangBoost = NULL;
+ static bool bOnce = true;
+ if( bOnce )
+ {
+ bOnce = false;
+ const 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 )
+ if( aFileName.Copy( nPos+1, 3 ).EqualsIgnoreCaseAscii( pLangBoost ) )
+ nQuality += 10;
+ }
+ }
+
+ ImplPspFontData* pFD = new ImplPspFontData( aInfo );
+ pFD->mnQuality += nQuality;
+ pFontList->Add( pFD );
+}
+
+bool PspGraphics::filterText( const String& rOrig, String& rNewText, xub_StrLen nIndex, xub_StrLen& rLen, xub_StrLen& rCutStart, xub_StrLen& rCutStop )
+{
+ if( ! m_pPhoneNr )
+ return false;
+
+ rCutStop = rCutStart = STRING_NOTFOUND;
+
+#define FAX_PHONE_TOKEN "@@#"
+#define FAX_PHONE_TOKEN_LENGTH 3
+#define FAX_END_TOKEN "@@"
+#define FAX_END_TOKEN_LENGTH 2
+
+ bool bRet = false;
+ bool bStarted = false;
+ bool bStopped = false;
+ USHORT nPos;
+ USHORT nStart = 0;
+ USHORT nStop = rLen;
+ String aPhone = rOrig.Copy( nIndex, rLen );
+
+ if( ! m_bPhoneCollectionActive )
+ {
+ if( ( nPos = aPhone.SearchAscii( FAX_PHONE_TOKEN ) ) != STRING_NOTFOUND )
+ {
+ nStart = nPos;
+ m_bPhoneCollectionActive = true;
+ m_aPhoneCollection.Erase();
+ bRet = true;
+ bStarted = true;
+ }
+ }
+ if( m_bPhoneCollectionActive )
+ {
+ bRet = true;
+ nPos = bStarted ? nStart + FAX_PHONE_TOKEN_LENGTH : 0;
+ if( ( nPos = aPhone.SearchAscii( FAX_END_TOKEN, nPos ) ) != STRING_NOTFOUND )
+ {
+ m_bPhoneCollectionActive = false;
+ nStop = nPos + FAX_END_TOKEN_LENGTH;
+ bStopped = true;
+ }
+ int nTokenStart = nStart + (bStarted ? FAX_PHONE_TOKEN_LENGTH : 0);
+ int nTokenStop = nStop - (bStopped ? FAX_END_TOKEN_LENGTH : 0);
+ m_aPhoneCollection += aPhone.Copy( nTokenStart, nTokenStop - nTokenStart );
+ if( ! m_bPhoneCollectionActive )
+ {
+ m_pPhoneNr->AppendAscii( "<Fax#>" );
+ m_pPhoneNr->Append( m_aPhoneCollection );
+ m_pPhoneNr->AppendAscii( "</Fax#>" );
+ m_aPhoneCollection.Erase();
+ }
+ }
+ if( m_aPhoneCollection.Len() > 1024 )
+ {
+ m_bPhoneCollectionActive = false;
+ m_aPhoneCollection.Erase();
+ bRet = false;
+ }
+
+ if( bRet && m_bSwallowFaxNo )
+ {
+ rLen -= nStop - nStart;
+ rCutStart = nStart+nIndex;
+ rCutStop = nStop+nIndex;
+ if( rCutStart )
+ rNewText = rOrig.Copy( 0, rCutStart );
+ rNewText += rOrig.Copy( rCutStop );
+ }
+
+ return bRet && m_bSwallowFaxNo;
+}
+
+bool PspGraphics::drawAlphaBitmap( const SalTwoRect&,
+ const SalBitmap&,
+ const SalBitmap& )
+{
+ return false;
+}
+
+bool PspGraphics::drawAlphaRect( long, long, long, long, sal_uInt8 )
+{
+ return false;
+}
+
+SystemGraphicsData PspGraphics::GetGraphicsData() const
+{
+ SystemGraphicsData aRes;
+ aRes.nSize = sizeof(aRes);
+ aRes.hDrawable = 0;
+ aRes.pRenderFormat = 0;
+ return aRes;
+}
+
+SystemFontData PspGraphics::GetSysFontData( int nFallbacklevel ) const
+{
+ SystemFontData aSysFontData;
+
+ if (nFallbacklevel >= MAX_FALLBACK) nFallbacklevel = MAX_FALLBACK - 1;
+ if (nFallbacklevel < 0 ) nFallbacklevel = 0;
+
+ aSysFontData.nSize = sizeof( SystemFontData );
+ aSysFontData.nFontId = 0;
+ aSysFontData.nFontFlags = 0;
+ aSysFontData.bFakeBold = false;
+ aSysFontData.bFakeItalic = false;
+ aSysFontData.bAntialias = true;
+ return aSysFontData;
+}
+
+bool PspGraphics::supportsOperation( OutDevSupportType ) const
+{
+ return false;
+}
diff --git a/vcl/unx/source/gdi/salbmp.cxx b/vcl/unx/source/gdi/salbmp.cxx
new file mode 100644
index 000000000000..cc7934b0a798
--- /dev/null
+++ b/vcl/unx/source/gdi/salbmp.cxx
@@ -0,0 +1,1093 @@
+/*************************************************************************
+ *
+ * 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 <stdio.h>
+#include <errno.h>
+#ifdef FREEBSD
+#include <sys/types.h>
+#endif
+#include <tools/prex.h>
+#include "Xproto.h"
+#include <tools/postx.h>
+#include <salunx.h>
+#include <osl/endian.h>
+#include <rtl/memory.h>
+#include <vcl/salbtype.hxx>
+#include <saldata.hxx>
+#include <saldisp.hxx>
+#include <salgdi.h>
+#include <salbmp.h>
+#include <salinst.h>
+#include <vcl/bitmap.hxx>
+
+// -----------
+// - Defines -
+// -----------
+
+#define SAL_DRAWPIXMAP_MAX_EXT 4096
+
+// -------------
+// - SalBitmap -
+// -------------
+
+SalBitmap* X11SalInstance::CreateSalBitmap()
+{
+ return new X11SalBitmap();
+}
+
+ImplSalBitmapCache* X11SalBitmap::mpCache = NULL;
+ULONG X11SalBitmap::mnCacheInstCount = 0;
+
+// -----------------------------------------------------------------------------
+
+X11SalBitmap::X11SalBitmap() :
+ mpDIB( NULL ),
+ mpDDB( NULL )
+{
+}
+
+// -----------------------------------------------------------------------------
+
+X11SalBitmap::~X11SalBitmap()
+{
+ Destroy();
+}
+
+// -----------------------------------------------------------------------------
+
+void X11SalBitmap::ImplCreateCache()
+{
+ if( !mnCacheInstCount++ )
+ mpCache = new ImplSalBitmapCache;
+}
+
+// -----------------------------------------------------------------------------
+
+void X11SalBitmap::ImplDestroyCache()
+{
+ DBG_ASSERT( mnCacheInstCount, "X11SalBitmap::ImplDestroyCache(): underflow" );
+
+ if( mnCacheInstCount && !--mnCacheInstCount )
+ delete mpCache, mpCache = NULL;
+}
+
+// -----------------------------------------------------------------------------
+
+void X11SalBitmap::ImplRemovedFromCache()
+{
+ if( mpDDB )
+ delete mpDDB, mpDDB = NULL;
+}
+
+// -----------------------------------------------------------------------------
+
+BitmapBuffer* X11SalBitmap::ImplCreateDIB( const Size& rSize, USHORT nBitCount, const BitmapPalette& rPal )
+{
+ DBG_ASSERT( nBitCount == 1 || nBitCount == 4 || nBitCount == 8 || nBitCount == 16 || nBitCount == 24, "Unsupported BitCount!" );
+
+ BitmapBuffer* pDIB = NULL;
+
+ if( rSize.Width() && rSize.Height() )
+ {
+ try
+ {
+ pDIB = new BitmapBuffer;
+ }
+ catch( std::bad_alloc& )
+ {
+ pDIB = NULL;
+ }
+
+ if( pDIB )
+ {
+ const USHORT nColors = ( nBitCount <= 8 ) ? ( 1 << nBitCount ) : 0;
+
+ pDIB->mnFormat = BMP_FORMAT_BOTTOM_UP;
+
+ switch( nBitCount )
+ {
+ case( 1 ): pDIB->mnFormat |= BMP_FORMAT_1BIT_MSB_PAL; break;
+ case( 4 ): pDIB->mnFormat |= BMP_FORMAT_4BIT_MSN_PAL; break;
+ case( 8 ): pDIB->mnFormat |= BMP_FORMAT_8BIT_PAL; break;
+#ifdef OSL_BIGENDIAN
+ case(16 ):
+ pDIB->mnFormat|= BMP_FORMAT_16BIT_TC_MSB_MASK;
+ pDIB->maColorMask = ColorMask( 0xf800, 0x07e0, 0x001f );
+ break;
+#else
+ case(16 ):
+ pDIB->mnFormat|= BMP_FORMAT_16BIT_TC_LSB_MASK;
+ pDIB->maColorMask = ColorMask( 0xf800, 0x07e0, 0x001f );
+ break;
+#endif
+ default:
+ nBitCount = 24;
+ //fall through
+ case 24:
+ pDIB->mnFormat |= BMP_FORMAT_24BIT_TC_BGR;
+ break;
+ }
+
+ pDIB->mnWidth = rSize.Width();
+ pDIB->mnHeight = rSize.Height();
+ pDIB->mnScanlineSize = AlignedWidth4Bytes( pDIB->mnWidth * nBitCount );
+ pDIB->mnBitCount = nBitCount;
+
+ if( nColors )
+ {
+ pDIB->maPalette = rPal;
+ pDIB->maPalette.SetEntryCount( nColors );
+ }
+
+ try
+ {
+ pDIB->mpBits = new BYTE[ pDIB->mnScanlineSize * pDIB->mnHeight ];
+ }
+ catch(std::bad_alloc&)
+ {
+ delete pDIB;
+ pDIB = NULL;
+ }
+ }
+ }
+ else
+ pDIB = NULL;
+
+ return pDIB;
+}
+
+// -----------------------------------------------------------------------------
+
+BitmapBuffer* X11SalBitmap::ImplCreateDIB( Drawable aDrawable,
+ int nScreen,
+ long nDrawableDepth,
+ long nX, long nY,
+ long nWidth, long nHeight )
+{
+ BitmapBuffer* pDIB = NULL;
+
+ if( aDrawable && nWidth && nHeight && nDrawableDepth )
+ {
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ SalXLib* pXLib = pSalDisp->GetXLib();
+ Display* pXDisp = pSalDisp->GetDisplay();
+
+ // do not die on XError here
+ // alternatively one could check the coordinates for being offscreen
+ // but this call can actually work on servers with backing store
+ // defaults even if the rectangle is offscreen
+ // so better catch the XError
+ pXLib->PushXErrorLevel( true );
+ XImage* pImage = XGetImage( pXDisp, aDrawable, nX, nY, nWidth, nHeight, AllPlanes, ZPixmap );
+ bool bWasError = pXLib->HasXErrorOccured() && pXLib->GetLastXErrorRequestCode() == X_GetImage;
+ pXLib->PopXErrorLevel();
+
+ if( ! bWasError && pImage && pImage->data )
+ {
+ const SalTwoRect aTwoRect = { 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight };
+ BitmapBuffer aSrcBuf;
+ ULONG nDstFormat = BMP_FORMAT_BOTTOM_UP;
+ const BitmapPalette* pDstPal = NULL;
+
+ aSrcBuf.mnFormat = BMP_FORMAT_TOP_DOWN;
+ aSrcBuf.mnWidth = nWidth;
+ aSrcBuf.mnHeight = nHeight;
+ aSrcBuf.mnBitCount = pImage->bits_per_pixel;
+ aSrcBuf.mnScanlineSize = pImage->bytes_per_line;
+ aSrcBuf.mpBits = (BYTE*) pImage->data;
+
+ pImage->red_mask = pSalDisp->GetVisual( nScreen ).red_mask;
+ pImage->green_mask = pSalDisp->GetVisual( nScreen ).green_mask;
+ pImage->blue_mask = pSalDisp->GetVisual( nScreen ).blue_mask;
+
+ switch( aSrcBuf.mnBitCount )
+ {
+ case( 1 ):
+ {
+ aSrcBuf.mnFormat |= ( LSBFirst == pImage->bitmap_bit_order ? BMP_FORMAT_1BIT_LSB_PAL : BMP_FORMAT_1BIT_MSB_PAL );
+ nDstFormat |= BMP_FORMAT_1BIT_MSB_PAL;
+ }
+ break;
+
+ case( 4 ):
+ {
+ aSrcBuf.mnFormat |= ( LSBFirst == pImage->bitmap_bit_order ? BMP_FORMAT_4BIT_LSN_PAL : BMP_FORMAT_4BIT_MSN_PAL );
+ nDstFormat |= BMP_FORMAT_4BIT_MSN_PAL;
+ }
+ break;
+
+ case( 8 ):
+ {
+ aSrcBuf.mnFormat |= BMP_FORMAT_8BIT_PAL;
+ nDstFormat |= BMP_FORMAT_8BIT_PAL;
+ }
+ break;
+
+ case( 16 ):
+ {
+ nDstFormat |= BMP_FORMAT_24BIT_TC_BGR;
+ aSrcBuf.maColorMask = ColorMask( pImage->red_mask, pImage->green_mask, pImage->blue_mask );
+
+ if( LSBFirst == pImage->byte_order )
+ {
+ aSrcBuf.mnFormat |= BMP_FORMAT_16BIT_TC_LSB_MASK;
+ }
+ else
+ {
+ aSrcBuf.mnFormat |= BMP_FORMAT_16BIT_TC_MSB_MASK;
+ // aSrcBuf.maColorMask = ColorMask( pImage->red_mask ), SWAPSHORT( pImage->green_mask ), SWAPSHORT( pImage->blue_mask ) );
+ }
+ }
+ break;
+
+ case( 24 ):
+ {
+ if( ( LSBFirst == pImage->byte_order ) && ( pImage->red_mask == 0xFF ) )
+ aSrcBuf.mnFormat |= BMP_FORMAT_24BIT_TC_RGB;
+ else
+ aSrcBuf.mnFormat |= BMP_FORMAT_24BIT_TC_BGR;
+
+ nDstFormat |= BMP_FORMAT_24BIT_TC_BGR;
+ }
+ break;
+
+ case( 32 ):
+ {
+ if( LSBFirst == pImage->byte_order )
+ aSrcBuf.mnFormat |= ( pSalDisp->GetVisual(nScreen).red_mask == 0xFF ? BMP_FORMAT_32BIT_TC_RGBA : BMP_FORMAT_32BIT_TC_BGRA );
+ else
+ aSrcBuf.mnFormat |= ( pSalDisp->GetVisual(nScreen).red_mask == 0xFF ? BMP_FORMAT_32BIT_TC_ABGR : BMP_FORMAT_32BIT_TC_ARGB );
+
+ nDstFormat |= BMP_FORMAT_24BIT_TC_BGR;
+ }
+ break;
+ }
+
+ BitmapPalette& rPal = aSrcBuf.maPalette;
+
+ if( aSrcBuf.mnBitCount == 1 )
+ {
+ rPal.SetEntryCount( 2 );
+ pDstPal = &rPal;
+
+ rPal[ 0 ] = Color( COL_BLACK );
+ rPal[ 1 ] = Color( COL_WHITE );
+ }
+ else if( aSrcBuf.mnBitCount <= 8 )
+ {
+ const SalColormap& rColMap = pSalDisp->GetColormap( nScreen );
+ const USHORT nCols = Min( (ULONG)rColMap.GetUsed(), (ULONG)(1 << nDrawableDepth) );
+
+ rPal.SetEntryCount( nCols );
+ pDstPal = &rPal;
+
+ for( USHORT i = 0; i < nCols; i++ )
+ {
+ const SalColor nColor( rColMap.GetColor( i ) );
+ BitmapColor& rBmpCol = rPal[ i ];
+
+ rBmpCol.SetRed( SALCOLOR_RED( nColor ) );
+ rBmpCol.SetGreen( SALCOLOR_GREEN( nColor ) );
+ rBmpCol.SetBlue( SALCOLOR_BLUE( nColor ) );
+ }
+ }
+
+ nDstFormat = aSrcBuf.mnFormat;
+ pDIB = StretchAndConvert( aSrcBuf, aTwoRect, nDstFormat,
+ const_cast<BitmapPalette*>(pDstPal), &aSrcBuf.maColorMask );
+ XDestroyImage( pImage );
+ }
+ }
+
+ return pDIB;
+}
+
+// -----------------------------------------------------------------------------
+
+XImage* X11SalBitmap::ImplCreateXImage( SalDisplay *pSalDisp, int nScreen, long nDepth, const SalTwoRect& rTwoRect ) const
+{
+ XImage* pImage = NULL;
+
+ if( !mpDIB && mpDDB )
+ {
+ const_cast<X11SalBitmap*>(this)->mpDIB =
+ ImplCreateDIB( mpDDB->ImplGetPixmap(),
+ mpDDB->ImplGetScreen(),
+ mpDDB->ImplGetDepth(),
+ 0, 0,
+ mpDDB->ImplGetWidth(),
+ mpDDB->ImplGetHeight() );
+ }
+
+ if( mpDIB && mpDIB->mnWidth && mpDIB->mnHeight )
+ {
+ Display* pXDisp = pSalDisp->GetDisplay();
+ long nWidth = rTwoRect.mnDestWidth;
+ long nHeight = rTwoRect.mnDestHeight;
+
+ if( 1 == GetBitCount() )
+ nDepth = 1;
+
+ pImage = XCreateImage( pXDisp, pSalDisp->GetVisual( nScreen ).GetVisual(),
+ nDepth, ( 1 == nDepth ) ? XYBitmap :ZPixmap, 0, NULL,
+ nWidth, nHeight, 32, 0 );
+
+ if( pImage )
+ {
+ BitmapBuffer* pDstBuf;
+ ULONG nDstFormat = BMP_FORMAT_TOP_DOWN;
+ BitmapPalette* pPal = NULL;
+ ColorMask* pMask = NULL;
+
+ switch( pImage->bits_per_pixel )
+ {
+ case( 1 ):
+ nDstFormat |= ( LSBFirst == pImage->bitmap_bit_order ? BMP_FORMAT_1BIT_LSB_PAL : BMP_FORMAT_1BIT_MSB_PAL );
+ break;
+
+ case( 4 ):
+ nDstFormat |= ( LSBFirst == pImage->bitmap_bit_order ? BMP_FORMAT_4BIT_LSN_PAL : BMP_FORMAT_4BIT_MSN_PAL );
+ break;
+
+ case( 8 ):
+ nDstFormat |= BMP_FORMAT_8BIT_PAL;
+ break;
+
+ case( 16 ):
+ {
+ #ifdef OSL_BIGENDIAN
+
+ if( MSBFirst == pImage->byte_order )
+ nDstFormat |= BMP_FORMAT_16BIT_TC_MSB_MASK;
+ else
+ nDstFormat |= BMP_FORMAT_16BIT_TC_LSB_MASK;
+
+ #else /* OSL_LITENDIAN */
+
+ nDstFormat |= BMP_FORMAT_16BIT_TC_LSB_MASK;
+ if( MSBFirst == pImage->byte_order )
+ pImage->byte_order = LSBFirst;
+
+ #endif
+
+ pMask = new ColorMask( pImage->red_mask, pImage->green_mask, pImage->blue_mask );
+ }
+ break;
+
+ case( 24 ):
+ {
+ if( ( LSBFirst == pImage->byte_order ) && ( pImage->red_mask == 0xFF ) )
+ nDstFormat |= BMP_FORMAT_24BIT_TC_RGB;
+ else
+ nDstFormat |= BMP_FORMAT_24BIT_TC_BGR;
+ }
+ break;
+
+ case( 32 ):
+ {
+ if( LSBFirst == pImage->byte_order )
+ nDstFormat |= ( pImage->red_mask == 0xFF ? BMP_FORMAT_32BIT_TC_RGBA : BMP_FORMAT_32BIT_TC_BGRA );
+ else
+ nDstFormat |= ( pImage->red_mask == 0xFF ? BMP_FORMAT_32BIT_TC_ABGR : BMP_FORMAT_32BIT_TC_ARGB );
+ }
+ break;
+ }
+
+ if( pImage->depth == 1 )
+ {
+ pPal = new BitmapPalette( 2 );
+ (*pPal)[ 0 ] = Color( COL_BLACK );
+ (*pPal)[ 1 ] = Color( COL_WHITE );
+ }
+ else if( pImage->depth <= 8 )
+ {
+ const SalColormap& rColMap = pSalDisp->GetColormap( nScreen );
+ const USHORT nCols = Min( (ULONG)rColMap.GetUsed(), (ULONG)(1 << pImage->depth) );
+
+ pPal = new BitmapPalette( nCols );
+
+ for( USHORT i = 0; i < nCols; i++ )
+ {
+ const SalColor nColor( rColMap.GetColor( i ) );
+ BitmapColor& rBmpCol = (*pPal)[ i ];
+
+ rBmpCol.SetRed( SALCOLOR_RED( nColor ) );
+ rBmpCol.SetGreen( SALCOLOR_GREEN( nColor ) );
+ rBmpCol.SetBlue( SALCOLOR_BLUE( nColor ) );
+ }
+ }
+
+ pDstBuf = StretchAndConvert( *mpDIB, rTwoRect, nDstFormat, pPal, pMask );
+ delete pPal;
+ delete pMask;
+
+ if( pDstBuf && pDstBuf->mpBits )
+ {
+ // set data in buffer as data member in pImage
+ pImage->data = (char*) pDstBuf->mpBits;
+
+ // destroy buffer; don't destroy allocated data in buffer
+ delete pDstBuf;
+ }
+ else
+ {
+ XDestroyImage( pImage );
+ pImage = NULL;
+ }
+ }
+ }
+
+ return pImage;
+}
+
+// -----------------------------------------------------------------------------
+bool X11SalBitmap::ImplCreateFromDrawable( Drawable aDrawable,
+ int nScreen, long nDrawableDepth,
+ long nX, long nY, long nWidth, long nHeight )
+{
+ Destroy();
+
+ if( aDrawable && nWidth && nHeight && nDrawableDepth )
+ mpDDB = new ImplSalDDB( aDrawable, nScreen, nDrawableDepth, nX, nY, nWidth, nHeight );
+
+ return( mpDDB != NULL );
+}
+// -----------------------------------------------------------------------------
+
+bool
+X11SalBitmap::SnapShot (Display* pDisplay, XLIB_Window hWindow)
+{
+ if (hWindow != None)
+ {
+ XWindowAttributes aAttribute;
+ XGetWindowAttributes (pDisplay, hWindow, &aAttribute);
+ if (aAttribute.map_state == IsViewable)
+ {
+ // get coordinates relative to root window
+ XLIB_Window hPetitFleur;
+ int nRootX, nRootY;
+
+ if (XTranslateCoordinates (pDisplay, hWindow, aAttribute.root,
+ 0, 0, &nRootX, &nRootY, &hPetitFleur))
+ {
+ XWindowAttributes aRootAttribute;
+ XGetWindowAttributes (pDisplay, aAttribute.root, &aRootAttribute);
+
+ int width = aAttribute.width;
+ int height = aAttribute.height;
+ int x = nRootX;
+ int y = nRootY;
+
+ // horizontal range check
+ if (x < 0)
+ {
+ width = width + x;
+ x = 0;
+ }
+ else
+ if (x > aRootAttribute.width)
+ {
+ width = 0;
+ x = aRootAttribute.width;
+ }
+ else
+ if (x + width > aRootAttribute.width)
+ {
+ width = aRootAttribute.width - x;
+ }
+
+ // vertical range check
+ if (y < 0)
+ {
+ height = height + y;
+ y = 0;
+ }
+ else
+ if (y > aRootAttribute.height)
+ {
+ height = 0;
+ y = aRootAttribute.height;
+ }
+ else
+ if (y + height > aRootAttribute.height)
+ {
+ height = aRootAttribute.height - y;
+ }
+
+ if ((width > 0) && (height > 0))
+ {
+ XImage* pImage = XGetImage( pDisplay, aAttribute.root,
+ x, y, width, height, AllPlanes, ZPixmap );
+ bool bSnapShot = ImplCreateFromXImage( pDisplay,
+ aAttribute.root,
+ XScreenNumberOfScreen( aAttribute.screen ),
+ pImage );
+ XDestroyImage (pImage);
+
+ return bSnapShot;
+ }
+ }
+ }
+ }
+
+ return False;
+}
+
+bool
+X11SalBitmap::ImplCreateFromXImage (Display* pDisplay, XLIB_Window hWindow, int nScreen, XImage* pImage)
+{
+ Destroy();
+
+ if (pImage != NULL && pImage->width != 0 && pImage->height != 0 && pImage->depth != 0)
+ {
+ mpDDB = new ImplSalDDB (pDisplay, hWindow, nScreen, pImage);
+ return True;
+ }
+ return False;
+}
+
+ImplSalDDB* X11SalBitmap::ImplGetDDB( Drawable aDrawable,
+ int nScreen,
+ long nDrawableDepth,
+ const SalTwoRect& rTwoRect ) const
+{
+ if( !mpDDB || !mpDDB->ImplMatches( nScreen, nDrawableDepth, rTwoRect ) )
+ {
+ if( mpDDB )
+ {
+ // do we already have a DIB? if not, create aDIB from current DDB first
+ if( !mpDIB )
+ {
+ const_cast<X11SalBitmap*>(this)->mpDIB = ImplCreateDIB( mpDDB->ImplGetPixmap(),
+ mpDDB->ImplGetScreen(),
+ mpDDB->ImplGetDepth(),
+ 0, 0,
+ mpDDB->ImplGetWidth(),
+ mpDDB->ImplGetHeight() );
+ }
+
+ delete mpDDB, const_cast<X11SalBitmap*>(this)->mpDDB = NULL;
+ }
+
+ if( mpCache )
+ mpCache->ImplRemove( const_cast<X11SalBitmap*>(this) );
+
+ SalTwoRect aTwoRect( rTwoRect );
+ if( aTwoRect.mnSrcX < 0 )
+ {
+ aTwoRect.mnSrcWidth += aTwoRect.mnSrcX;
+ aTwoRect.mnSrcX = 0;
+ }
+ if( aTwoRect.mnSrcY < 0 )
+ {
+ aTwoRect.mnSrcHeight += aTwoRect.mnSrcY;
+ aTwoRect.mnSrcY = 0;
+ }
+
+ // create new DDB from DIB
+ const Size aSize( GetSize() );
+ if( aTwoRect.mnSrcWidth == aTwoRect.mnDestWidth &&
+ aTwoRect.mnSrcHeight == aTwoRect.mnDestHeight )
+ {
+ aTwoRect.mnSrcX = aTwoRect.mnSrcY = aTwoRect.mnDestX = aTwoRect.mnDestY = 0;
+ aTwoRect.mnSrcWidth = aTwoRect.mnDestWidth = aSize.Width();
+ aTwoRect.mnSrcHeight = aTwoRect.mnDestHeight = aSize.Height();
+ }
+ else if( aTwoRect.mnSrcWidth+aTwoRect.mnSrcX > aSize.Width() ||
+ aTwoRect.mnSrcHeight+aTwoRect.mnSrcY > aSize.Height() )
+ {
+ // #i47823# this should not happen at all, but does nonetheless
+ // because BitmapEx allows for mask bitmaps of different size
+ // than image bitmap (broken)
+ if( aTwoRect.mnSrcX >= aSize.Width() ||
+ aTwoRect.mnSrcY >= aSize.Height() )
+ return NULL; // this would be a really mad case
+
+ if( aTwoRect.mnSrcWidth+aTwoRect.mnSrcX > aSize.Width() )
+ {
+ aTwoRect.mnSrcWidth = aSize.Width()-aTwoRect.mnSrcX;
+ if( aTwoRect.mnSrcWidth < 1 )
+ {
+ aTwoRect.mnSrcX = 0;
+ aTwoRect.mnSrcWidth = aSize.Width();
+ }
+ }
+ if( aTwoRect.mnSrcHeight+aTwoRect.mnSrcY > aSize.Height() )
+ {
+ aTwoRect.mnSrcHeight = aSize.Height() - aTwoRect.mnSrcY;
+ if( aTwoRect.mnSrcHeight < 1 )
+ {
+ aTwoRect.mnSrcY = 0;
+ aTwoRect.mnSrcHeight = aSize.Height();
+ }
+ }
+ }
+
+ XImage* pImage = ImplCreateXImage( GetX11SalData()->GetDisplay(), nScreen,
+ nDrawableDepth, aTwoRect );
+
+ if( pImage )
+ {
+ const_cast<X11SalBitmap*>(this)->mpDDB = new ImplSalDDB( pImage, aDrawable, nScreen, aTwoRect );
+ delete[] pImage->data, pImage->data = NULL;
+ XDestroyImage( pImage );
+
+ if( mpCache )
+ mpCache->ImplAdd( const_cast<X11SalBitmap*>(this), mpDDB->ImplGetMemSize() );
+ }
+ }
+
+ return mpDDB;
+}
+
+// -----------------------------------------------------------------------------
+
+void X11SalBitmap::ImplDraw( Drawable aDrawable,
+ int nScreen,
+ long nDrawableDepth,
+ const SalTwoRect& rTwoRect,
+ const GC& rGC ) const
+{
+ ImplGetDDB( aDrawable, nScreen, nDrawableDepth, rTwoRect );
+ if( mpDDB )
+ mpDDB->ImplDraw( aDrawable, nDrawableDepth, rTwoRect, rGC );
+}
+
+// -----------------------------------------------------------------------------
+
+bool X11SalBitmap::Create( const Size& rSize, USHORT nBitCount, const BitmapPalette& rPal )
+{
+ Destroy();
+ mpDIB = ImplCreateDIB( rSize, nBitCount, rPal );
+
+ return( mpDIB != NULL );
+}
+
+// -----------------------------------------------------------------------------
+
+bool X11SalBitmap::Create( const SalBitmap& rSSalBmp )
+{
+ Destroy();
+
+ const X11SalBitmap& rSalBmp = static_cast<const X11SalBitmap&>( rSSalBmp );
+
+ if( rSalBmp.mpDIB )
+ {
+ // TODO: reference counting...
+ mpDIB = new BitmapBuffer( *rSalBmp.mpDIB );
+ // TODO: get rid of this when BitmapBuffer gets copy constructor
+ try
+ {
+ mpDIB->mpBits = new BYTE[ mpDIB->mnScanlineSize * mpDIB->mnHeight ];
+ }
+ catch( std::bad_alloc& )
+ {
+ delete mpDIB;
+ mpDIB = NULL;
+ }
+
+ if( mpDIB )
+ memcpy( mpDIB->mpBits, rSalBmp.mpDIB->mpBits, mpDIB->mnScanlineSize * mpDIB->mnHeight );
+ }
+ else if( rSalBmp.mpDDB )
+ ImplCreateFromDrawable( rSalBmp.mpDDB->ImplGetPixmap(),
+ rSalBmp.mpDDB->ImplGetScreen(),
+ rSalBmp.mpDDB->ImplGetDepth(),
+ 0, 0, rSalBmp.mpDDB->ImplGetWidth(), rSalBmp.mpDDB->ImplGetHeight() );
+
+ return( ( !rSalBmp.mpDIB && !rSalBmp.mpDDB ) ||
+ ( rSalBmp.mpDIB && ( mpDIB != NULL ) ) ||
+ ( rSalBmp.mpDDB && ( mpDDB != NULL ) ) );
+}
+
+// -----------------------------------------------------------------------------
+
+bool X11SalBitmap::Create( const SalBitmap&, SalGraphics* )
+{
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------------
+
+bool X11SalBitmap::Create( const SalBitmap&, USHORT )
+{
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------------
+
+void X11SalBitmap::Destroy()
+{
+ if( mpDIB )
+ {
+ delete[] mpDIB->mpBits;
+ delete mpDIB, mpDIB = NULL;
+ }
+
+ if( mpDDB )
+ delete mpDDB, mpDDB = NULL;
+
+ if( mpCache )
+ mpCache->ImplRemove( this );
+}
+
+// -----------------------------------------------------------------------------
+
+Size X11SalBitmap::GetSize() const
+{
+ Size aSize;
+
+ if( mpDIB )
+ aSize.Width() = mpDIB->mnWidth, aSize.Height() = mpDIB->mnHeight;
+ else if( mpDDB )
+ aSize.Width() = mpDDB->ImplGetWidth(), aSize.Height() = mpDDB->ImplGetHeight();
+
+ return aSize;
+}
+
+// -----------------------------------------------------------------------------
+
+USHORT X11SalBitmap::GetBitCount() const
+{
+ USHORT nBitCount;
+
+ if( mpDIB )
+ nBitCount = mpDIB->mnBitCount;
+ else if( mpDDB )
+ nBitCount = mpDDB->ImplGetDepth();
+ else
+ nBitCount = 0;
+
+ return nBitCount;
+}
+
+// -----------------------------------------------------------------------------
+
+BitmapBuffer* X11SalBitmap::AcquireBuffer( bool )
+{
+ if( !mpDIB && mpDDB )
+ {
+ mpDIB = ImplCreateDIB( mpDDB->ImplGetPixmap(),
+ mpDDB->ImplGetScreen(),
+ mpDDB->ImplGetDepth(),
+ 0, 0, mpDDB->ImplGetWidth(), mpDDB->ImplGetHeight() );
+ }
+
+ return mpDIB;
+}
+
+// -----------------------------------------------------------------------------
+
+void X11SalBitmap::ReleaseBuffer( BitmapBuffer*, bool bReadOnly )
+{
+ if( !bReadOnly )
+ {
+ if( mpDDB )
+ delete mpDDB, mpDDB = NULL;
+
+ if( mpCache )
+ mpCache->ImplRemove( this );
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+bool X11SalBitmap::GetSystemData( BitmapSystemData& rData )
+{
+ if( mpDDB )
+ {
+ // Rename/retype pDummy to your likings (though X11 Pixmap is
+ // prolly not a good idea, since it's accessed from
+ // non-platform aware code in vcl/bitmap.hxx)
+ rData.aPixmap = (void*)mpDDB->ImplGetPixmap();
+ rData.mnWidth = mpDDB->ImplGetWidth ();
+ rData.mnHeight = mpDDB->ImplGetHeight ();
+ return true;
+ }
+
+ return false;
+}
+
+// --------------
+// - ImplSalDDB -
+// --------------
+
+ImplSalDDB::ImplSalDDB( XImage* pImage, Drawable aDrawable, int nScreen, const SalTwoRect& rTwoRect ) :
+ maPixmap ( 0 ),
+ maTwoRect ( rTwoRect ),
+ mnDepth ( pImage->depth ),
+ mnScreen ( nScreen )
+{
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ Display* pXDisp = pSalDisp->GetDisplay();
+
+ if( (maPixmap = XCreatePixmap( pXDisp, aDrawable, ImplGetWidth(), ImplGetHeight(), ImplGetDepth() )) )
+ {
+ XGCValues aValues;
+ GC aGC;
+ int nValues = GCFunction;
+
+ aValues.function = GXcopy;
+
+ if( 1 == mnDepth )
+ {
+ nValues |= ( GCForeground | GCBackground );
+ aValues.foreground = 1, aValues.background = 0;
+ }
+
+ aGC = XCreateGC( pXDisp, maPixmap, nValues, &aValues );
+ XPutImage( pXDisp, maPixmap, aGC, pImage, 0, 0, 0, 0, maTwoRect.mnDestWidth, maTwoRect.mnDestHeight );
+ XFreeGC( pXDisp, aGC );
+ }
+}
+
+// -----------------------------------------------------------------------------------------
+// create from XImage
+
+ImplSalDDB::ImplSalDDB (Display* pDisplay, XLIB_Window hWindow, int nScreen, XImage* pImage) :
+ mnScreen( nScreen )
+{
+ maPixmap = XCreatePixmap (pDisplay, hWindow, pImage->width, pImage->height, pImage->depth);
+ if (maPixmap != 0)
+ {
+ XGCValues aValues;
+ GC aGC;
+ int nValues = GCFunction;
+
+ aValues.function = GXcopy;
+
+ if (pImage->depth == 1)
+ {
+ nValues |= ( GCForeground | GCBackground );
+ aValues.foreground = 1;
+ aValues.background = 0;
+ }
+
+ aGC = XCreateGC (pDisplay, maPixmap, nValues, &aValues);
+ XPutImage (pDisplay, maPixmap, aGC, pImage, 0, 0, 0, 0, pImage->width, pImage->height);
+ XFreeGC (pDisplay, aGC);
+
+ maTwoRect.mnSrcX = 0;
+ maTwoRect.mnSrcY = 0;
+ maTwoRect.mnDestX = 0;
+ maTwoRect.mnDestY = 0;
+ maTwoRect.mnSrcWidth = pImage->width;
+ maTwoRect.mnDestWidth = pImage->width;
+ maTwoRect.mnSrcHeight = pImage->height;
+ maTwoRect.mnDestHeight = pImage->height;
+
+ mnDepth = pImage->depth;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+ImplSalDDB::ImplSalDDB( Drawable aDrawable, int nScreen, long nDrawableDepth, long nX, long nY, long nWidth, long nHeight ) :
+ mnDepth( nDrawableDepth ),
+ mnScreen( nScreen )
+{
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ Display* pXDisp = pSalDisp->GetDisplay();
+
+ if( (maPixmap = XCreatePixmap( pXDisp, aDrawable, nWidth, nHeight, nDrawableDepth )) )
+ {
+ XGCValues aValues;
+ GC aGC;
+ int nValues = GCFunction;
+
+ aValues.function = GXcopy;
+
+ if( 1 == mnDepth )
+ {
+ nValues |= ( GCForeground | GCBackground );
+ aValues.foreground = 1, aValues.background = 0;
+ }
+
+ aGC = XCreateGC( pXDisp, maPixmap, nValues, &aValues );
+ ImplDraw( aDrawable, nDrawableDepth, maPixmap, mnDepth,
+ nX, nY, nWidth, nHeight, 0, 0, aGC );
+ XFreeGC( pXDisp, aGC );
+
+ maTwoRect.mnSrcX = maTwoRect.mnSrcY = maTwoRect.mnDestX = maTwoRect.mnDestY = 0;
+ maTwoRect.mnSrcWidth = maTwoRect.mnDestWidth = nWidth;
+ maTwoRect.mnSrcHeight = maTwoRect.mnDestHeight = nHeight;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+ImplSalDDB::~ImplSalDDB()
+{
+ if( maPixmap && ImplGetSVData() )
+ XFreePixmap( GetX11SalData()->GetDisplay()->GetDisplay(), maPixmap );
+}
+
+// -----------------------------------------------------------------------------
+
+bool ImplSalDDB::ImplMatches( int nScreen, long nDepth, const SalTwoRect& rTwoRect ) const
+{
+ bool bRet = FALSE;
+
+ if( ( maPixmap != 0 ) && ( ( mnDepth == nDepth ) || ( 1 == mnDepth ) ) && nScreen == mnScreen)
+ {
+ if( rTwoRect.mnSrcX == maTwoRect.mnSrcX && rTwoRect.mnSrcY == maTwoRect.mnSrcY &&
+ rTwoRect.mnSrcWidth == maTwoRect.mnSrcWidth && rTwoRect.mnSrcHeight == maTwoRect.mnSrcHeight &&
+ rTwoRect.mnDestWidth == maTwoRect.mnDestWidth && rTwoRect.mnDestHeight == maTwoRect.mnDestHeight )
+ {
+ // absolutely indentically
+ bRet = TRUE;
+ }
+ else if( rTwoRect.mnSrcWidth == rTwoRect.mnDestWidth && rTwoRect.mnSrcHeight == rTwoRect.mnDestHeight &&
+ maTwoRect.mnSrcWidth == maTwoRect.mnDestWidth && maTwoRect.mnSrcHeight == maTwoRect.mnDestHeight &&
+ rTwoRect.mnSrcX >= maTwoRect.mnSrcX && rTwoRect.mnSrcY >= maTwoRect.mnSrcY &&
+ ( rTwoRect.mnSrcX + rTwoRect.mnSrcWidth ) <= ( maTwoRect.mnSrcX + maTwoRect.mnSrcWidth ) &&
+ ( rTwoRect.mnSrcY + rTwoRect.mnSrcHeight ) <= ( maTwoRect.mnSrcY + maTwoRect.mnSrcHeight ) )
+ {
+ bRet = TRUE;
+ }
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------------
+
+void ImplSalDDB::ImplDraw( Drawable aDrawable, long nDrawableDepth, const SalTwoRect& rTwoRect, const GC& rGC ) const
+{
+ ImplDraw( maPixmap, mnDepth, aDrawable, nDrawableDepth,
+ rTwoRect.mnSrcX - maTwoRect.mnSrcX, rTwoRect.mnSrcY - maTwoRect.mnSrcY,
+ rTwoRect.mnDestWidth, rTwoRect.mnDestHeight,
+ rTwoRect.mnDestX, rTwoRect.mnDestY, rGC );
+}
+
+// -----------------------------------------------------------------------------
+
+void ImplSalDDB::ImplDraw( Drawable aSrcDrawable, long nSrcDrawableDepth,
+ Drawable aDstDrawable, long,
+ long nSrcX, long nSrcY,
+ long nDestWidth, long nDestHeight,
+ long nDestX, long nDestY, const GC& rGC )
+{
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ Display* pXDisp = pSalDisp->GetDisplay();
+
+ if( 1 == nSrcDrawableDepth )
+ {
+ XCopyPlane( pXDisp, aSrcDrawable, aDstDrawable, rGC,
+ nSrcX, nSrcY, nDestWidth, nDestHeight, nDestX, nDestY, 1 );
+ }
+ else
+ {
+ XCopyArea( pXDisp, aSrcDrawable, aDstDrawable, rGC,
+ nSrcX, nSrcY, nDestWidth, nDestHeight, nDestX, nDestY );
+ }
+}
+
+// ----------------------
+// - ImplSalBitmapCache -
+// ----------------------
+
+struct ImplBmpObj
+{
+ X11SalBitmap* mpBmp;
+ ULONG mnMemSize;
+ ULONG mnFlags;
+
+ ImplBmpObj( X11SalBitmap* pBmp, ULONG nMemSize, ULONG nFlags ) :
+ mpBmp( pBmp ), mnMemSize( nMemSize ), mnFlags( nFlags ) {}
+};
+
+// -----------------------------------------------------------------------------
+
+ImplSalBitmapCache::ImplSalBitmapCache() :
+ mnTotalSize( 0UL )
+{
+}
+
+// -----------------------------------------------------------------------------
+
+ImplSalBitmapCache::~ImplSalBitmapCache()
+{
+ ImplClear();
+}
+
+// -----------------------------------------------------------------------------
+
+void ImplSalBitmapCache::ImplAdd( X11SalBitmap* pBmp, ULONG nMemSize, ULONG nFlags )
+{
+ ImplBmpObj* pObj;
+ bool bFound = FALSE;
+
+ for( pObj = (ImplBmpObj*) maBmpList.Last(); pObj && !bFound; pObj = (ImplBmpObj*) maBmpList.Prev() )
+ if( pObj->mpBmp == pBmp )
+ bFound = TRUE;
+
+ mnTotalSize += nMemSize;
+
+ if( bFound )
+ {
+ mnTotalSize -= pObj->mnMemSize;
+ pObj->mnMemSize = nMemSize, pObj->mnFlags = nFlags;
+ }
+ else
+ maBmpList.Insert( new ImplBmpObj( pBmp, nMemSize, nFlags ), LIST_APPEND );
+}
+
+// -----------------------------------------------------------------------------
+
+void ImplSalBitmapCache::ImplRemove( X11SalBitmap* pBmp )
+{
+ for( ImplBmpObj* pObj = (ImplBmpObj*) maBmpList.Last(); pObj; pObj = (ImplBmpObj*) maBmpList.Prev() )
+ {
+ if( pObj->mpBmp == pBmp )
+ {
+ maBmpList.Remove( pObj );
+ pObj->mpBmp->ImplRemovedFromCache();
+ mnTotalSize -= pObj->mnMemSize;
+ delete pObj;
+ break;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void ImplSalBitmapCache::ImplClear()
+{
+ for( ImplBmpObj* pObj = (ImplBmpObj*) maBmpList.First(); pObj; pObj = (ImplBmpObj*) maBmpList.Next() )
+ {
+ pObj->mpBmp->ImplRemovedFromCache();
+ delete pObj;
+ }
+
+ maBmpList.Clear();
+ mnTotalSize = 0;
+}
diff --git a/vcl/unx/source/gdi/salcvt.cxx b/vcl/unx/source/gdi/salcvt.cxx
new file mode 100644
index 000000000000..c699cdb12335
--- /dev/null
+++ b/vcl/unx/source/gdi/salcvt.cxx
@@ -0,0 +1,341 @@
+/*************************************************************************
+ *
+ * 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 "salcvt.hxx"
+
+
+SalConverterCache::SalConverterCache()
+{
+}
+
+SalConverterCache*
+SalConverterCache::GetInstance ()
+{
+ static SalConverterCache* pCvt = NULL;
+ if (pCvt == NULL)
+ pCvt = new SalConverterCache;
+
+ return pCvt;
+}
+
+SalConverterCache::~SalConverterCache()
+{
+}
+
+// ---> FIXME
+#include <stdio.h>
+// <---
+
+rtl_UnicodeToTextConverter
+SalConverterCache::GetU2TConverter( rtl_TextEncoding nEncoding )
+{
+ if( rtl_isOctetTextEncoding( nEncoding ) )
+ {
+ ConverterT& rConverter( m_aConverters[ nEncoding ] );
+ if ( rConverter.mpU2T == NULL )
+ {
+ rConverter.mpU2T =
+ rtl_createUnicodeToTextConverter( nEncoding );
+// ---> FIXME
+if ( rConverter.mpU2T == NULL )
+ fprintf( stderr, "failed to create Unicode -> %i converter\n", nEncoding);
+// <---
+ }
+ return rConverter.mpU2T;
+ }
+ return NULL;
+}
+
+rtl_TextToUnicodeConverter
+SalConverterCache::GetT2UConverter( rtl_TextEncoding nEncoding )
+{
+ if( rtl_isOctetTextEncoding( nEncoding ) )
+ {
+ ConverterT& rConverter( m_aConverters[ nEncoding ] );
+ if ( rConverter.mpT2U == NULL )
+ {
+ rConverter.mpT2U =
+ rtl_createTextToUnicodeConverter( nEncoding );
+// ---> FIXME
+if ( rConverter.mpT2U == NULL )
+ fprintf( stderr, "failed to create %i -> Unicode converter\n", nEncoding );
+// <---
+ }
+ return rConverter.mpT2U;
+ }
+ return NULL;
+}
+
+Bool
+SalConverterCache::IsSingleByteEncoding( rtl_TextEncoding nEncoding )
+{
+ if( rtl_isOctetTextEncoding( nEncoding ) )
+ {
+ ConverterT& rConverter( m_aConverters[ nEncoding ] );
+ if ( ! rConverter.mbValid )
+ {
+ rConverter.mbValid = True;
+
+ rtl_TextEncodingInfo aTextEncInfo;
+ aTextEncInfo.StructSize = sizeof( aTextEncInfo );
+ rtl_getTextEncodingInfo( nEncoding, &aTextEncInfo );
+
+ if ( aTextEncInfo.MinimumCharSize == aTextEncInfo.MaximumCharSize
+ && aTextEncInfo.MinimumCharSize == 1)
+ rConverter.mbSingleByteEncoding = True;
+ else
+ rConverter.mbSingleByteEncoding = False;
+ }
+
+ return rConverter.mbSingleByteEncoding;
+ }
+ return False;
+}
+
+// check whether the character set nEncoding contains the unicode
+// code point nChar. This list has been compiled from the according
+// ttmap files in /usr/openwin/lib/X11/fonts/TrueType/ttmap/
+Bool
+SalConverterCache::EncodingHasChar( rtl_TextEncoding nEncoding,
+ sal_Unicode nChar )
+{
+ Bool bMatch = False;
+
+ switch ( nEncoding )
+ {
+ case RTL_TEXTENCODING_DONTKNOW:
+ bMatch = False;
+ break;
+
+ case RTL_TEXTENCODING_MS_1252:
+ case RTL_TEXTENCODING_ISO_8859_1:
+ case RTL_TEXTENCODING_ISO_8859_15:
+ // handle iso8859-15 and iso8859-1 the same (and both with euro)
+ // handle them also like ms1252
+ // this is due to the fact that so many X fonts say they are iso8859-1
+ // but have the other glyphs anyway because they are really ms1252
+ bMatch = ( /*nChar >= 0x0000 &&*/ nChar <= 0x00ff )
+ || ( nChar == 0x20ac )
+ || ( nChar == 0x201a )
+ || ( nChar == 0x0192 )
+ || ( nChar == 0x201e )
+ || ( nChar == 0x2026 )
+ || ( nChar == 0x2020 )
+ || ( nChar == 0x2021 )
+ || ( nChar == 0x02c6 )
+ || ( nChar == 0x2030 )
+ || ( nChar == 0x0160 )
+ || ( nChar == 0x2039 )
+ || ( nChar == 0x0152 )
+ || ( nChar == 0x017d )
+ || ( nChar == 0x2018 )
+ || ( nChar == 0x2019 )
+ || ( nChar == 0x201c )
+ || ( nChar == 0x201d )
+ || ( nChar == 0x2022 )
+ || ( nChar == 0x2013 )
+ || ( nChar == 0x2014 )
+ || ( nChar == 0x02dc )
+ || ( nChar == 0x2122 )
+ || ( nChar == 0x0161 )
+ || ( nChar == 0x203a )
+ || ( nChar == 0x0153 )
+ || ( nChar == 0x017e )
+ || ( nChar == 0x0178 )
+ ;
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_2:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x00a0 && nChar <= 0x017e )
+ || ( nChar >= 0x02c7 && nChar <= 0x02dd );
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_4:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x00a0 && nChar <= 0x017e )
+ || ( nChar >= 0x02c7 && nChar <= 0x02db );
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_5:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x00a0 && nChar <= 0x00ad )
+ || ( nChar >= 0x0401 && nChar <= 0x045f )
+ || ( nChar == 0x2116 );
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_6:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x0600 && nChar <= 0x06ff )
+ || ( nChar >= 0xfb50 && nChar <= 0xfffe );
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_7:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x00a0 && nChar <= 0x00bd )
+ || ( nChar == 0x02bd )
+ || ( nChar >= 0x0384 && nChar <= 0x03ce )
+ || ( nChar >= 0x2014 && nChar <= 0x2019 );
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_8:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x00a0 && nChar <= 0x00f7 )
+ || ( nChar >= 0x05d0 && nChar <= 0x05ea )
+ || ( nChar == 0x2017 );
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_9:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x00a0 && nChar <= 0x015f );
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_13:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x00a0 && nChar <= 0x017e )
+ || ( nChar >= 0x2019 && nChar <= 0x201e );
+ break;
+
+ /* real case for RTL_TEXTENCODING_ISO_8859_15
+ case RTL_TEXTENCODING_ISO_8859_15:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x00a0 && nChar <= 0x00ff )
+ || ( nChar >= 0x0152 && nChar <= 0x017e )
+ || ( nChar == 0x20ac );
+ break;
+ */
+
+ case RTL_TEXTENCODING_JIS_X_0201:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0xff61 && nChar <= 0xff9f );
+ break;
+
+ case RTL_TEXTENCODING_MS_1251:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x00a0 && nChar <= 0x00bb )
+ || ( nChar >= 0x0401 && nChar <= 0x045f )
+ || ( nChar >= 0x0490 && nChar <= 0x0491 )
+ || ( nChar >= 0x2013 && nChar <= 0x203a )
+ || ( nChar >= 0x2116 && nChar <= 0x2122 );
+ break;
+
+ case RTL_TEXTENCODING_KOI8_R:
+ bMatch = ( nChar >= 0x0020 && nChar <= 0x007e )
+ || ( nChar >= 0x00a0 && nChar <= 0x00b7 )
+ || ( nChar == 0x00f7 )
+ || ( nChar >= 0x0401 && nChar <= 0x0451 )
+ || ( nChar >= 0x2219 && nChar <= 0x221a )
+ || ( nChar >= 0x2248 && nChar <= 0x2265 )
+ || ( nChar >= 0x2320 && nChar <= 0x2321 )
+ || ( nChar >= 0x2500 && nChar <= 0x25a0 );
+ break;
+
+ case RTL_TEXTENCODING_UNICODE:
+ bMatch = True;
+ break;
+
+ case RTL_TEXTENCODING_EUC_KR:
+ case RTL_TEXTENCODING_BIG5:
+ case RTL_TEXTENCODING_GBK:
+ case RTL_TEXTENCODING_GB_2312:
+ case RTL_TEXTENCODING_MS_1361:
+ case RTL_TEXTENCODING_JIS_X_0208:
+
+ // XXX Big5 and Korean EUC contain Ascii chars, but Solaris
+ // *-big5-1 and *-ksc5601.1992-3 fonts dont, in general CJK fonts
+ // are monospaced, so dont trust them for latin chars
+ if (nChar <= 0xFF)
+ {
+ bMatch = False;
+ break;
+ }
+
+ default:
+ // XXX really convert the unicode char into the encoding
+ // and check for conversion errors, this is expensive !
+ rtl_UnicodeToTextConverter aConverter;
+ rtl_UnicodeToTextContext aContext;
+
+ aConverter = GetU2TConverter(nEncoding);
+ aContext = rtl_createUnicodeToTextContext( aConverter );
+
+ // ---> FIXME
+ if ( aConverter == NULL )
+ return False;
+ // <---
+
+ sal_Char pConversionBuffer[ 32 ];
+ sal_uInt32 nConversionInfo;
+ sal_Size nConvertedChars;
+ sal_Size nSize;
+
+ nSize = rtl_convertUnicodeToText( aConverter, aContext,
+ &nChar, 1, pConversionBuffer, sizeof(pConversionBuffer),
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
+ | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR,
+ &nConversionInfo, &nConvertedChars );
+
+ rtl_destroyUnicodeToTextContext( aConverter, aContext );
+
+ bMatch = (nConvertedChars == 1)
+ && (nSize == 1 || nSize == 2) // XXX Fix me this is a hack
+ && ((nConversionInfo & RTL_UNICODETOTEXT_INFO_ERROR) == 0);
+ break;
+ }
+
+ return bMatch;
+}
+
+// wrapper for rtl_convertUnicodeToText that handles the usual cases for
+// textconversion in drawtext and gettextwidth routines
+sal_Size
+SalConverterCache::ConvertStringUTF16( const sal_Unicode *pText, int nTextLen,
+ sal_Char *pBuffer, sal_Size nBufferSize, rtl_TextEncoding nEncoding )
+{
+ rtl_UnicodeToTextConverter aConverter = GetU2TConverter(nEncoding);
+
+ const sal_uInt32 nCvtFlags =
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACE
+ | RTL_UNICODETOTEXT_FLAGS_UNDEFINED_QUESTIONMARK
+ | RTL_UNICODETOTEXT_FLAGS_INVALID_QUESTIONMARK ;
+ sal_uInt32 nCvtInfo;
+ sal_Size nCvtChars;
+
+ rtl_UnicodeToTextContext aContext =
+ rtl_createUnicodeToTextContext( aConverter );
+
+ sal_Size nSize = rtl_convertUnicodeToText( aConverter, aContext,
+ pText, nTextLen, pBuffer, nBufferSize,
+ nCvtFlags, &nCvtInfo, &nCvtChars );
+
+ rtl_destroyUnicodeToTextContext( aConverter, aContext );
+
+ return nSize;
+}
+
diff --git a/vcl/unx/source/gdi/salcvt.hxx b/vcl/unx/source/gdi/salcvt.hxx
new file mode 100644
index 000000000000..c142c76fe5d0
--- /dev/null
+++ b/vcl/unx/source/gdi/salcvt.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.
+ *
+ ************************************************************************/
+#ifndef SAL_CONVERTER_CACHE_HXX_
+#define SAL_CONVERTER_CACHE_HXX_
+
+#include <salunx.h>
+#include <rtl/tencinfo.h>
+#include <rtl/textcvt.h>
+
+#include <map>
+
+extern "C" const char*
+pGetEncodingName( rtl_TextEncoding nEncoding );
+
+//
+// Cache TextToUnicode and UnicodeToText converter and conversion info which is
+// used in DrawXYZ routines and in the Event loop
+//
+
+class SalConverterCache {
+
+ public:
+ SalConverterCache();
+ ~SalConverterCache();
+ Bool EncodingHasChar(
+ rtl_TextEncoding nEncoding, sal_Unicode nChar );
+ rtl_UnicodeToTextConverter
+ GetU2TConverter( rtl_TextEncoding nEncoding );
+ rtl_TextToUnicodeConverter
+ GetT2UConverter( rtl_TextEncoding nEncoding );
+ Bool IsSingleByteEncoding( rtl_TextEncoding nEncoding );
+ sal_Size ConvertStringUTF16( const sal_Unicode *pText, int nTextLen,
+ sal_Char *pBuffer, sal_Size nBufferSize,
+ rtl_TextEncoding nEncoding);
+
+ static SalConverterCache*
+ GetInstance ();
+
+ private:
+
+ struct ConverterT {
+ rtl_UnicodeToTextConverter mpU2T;
+ rtl_TextToUnicodeConverter mpT2U;
+ Bool mbSingleByteEncoding;
+ Bool mbValid;
+ ConverterT() :
+ mpU2T( NULL ),
+ mpT2U( NULL ),
+ mbSingleByteEncoding( False ),
+ mbValid( False )
+ {
+ }
+ ~ConverterT()
+ {
+ if( mpU2T )
+ rtl_destroyUnicodeToTextConverter( mpU2T );
+ if( mpT2U )
+ rtl_destroyTextToUnicodeConverter( mpT2U );
+ }
+ };
+
+ std::map< rtl_TextEncoding, ConverterT > m_aConverters;
+};
+
+
+
+#endif /* SAL_CONVERTER_CACHE_HXX_ */
+
diff --git a/vcl/unx/source/gdi/salgdi.cxx b/vcl/unx/source/gdi/salgdi.cxx
new file mode 100644
index 000000000000..ae21c3aa9f7b
--- /dev/null
+++ b/vcl/unx/source/gdi/salgdi.cxx
@@ -0,0 +1,1285 @@
+/*************************************************************************
+ *
+ * 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 "Xproto.h"
+
+#include "salunx.h"
+#include "saldata.hxx"
+#include "saldisp.hxx"
+#include "salgdi.h"
+#include "salframe.h"
+#include "salvd.h"
+#include "xrender_peer.hxx"
+
+#include "vcl/printergfx.hxx"
+#include "vcl/jobdata.hxx"
+
+#include "tools/debug.hxx"
+
+#include "basegfx/polygon/b2dpolygon.hxx"
+#include "basegfx/polygon/b2dpolypolygon.hxx"
+#include "basegfx/polygon/b2dpolypolygontools.hxx"
+#include "basegfx/polygon/b2dpolygontools.hxx"
+#include "basegfx/polygon/b2dpolygonclipper.hxx"
+#include "basegfx/polygon/b2dlinegeometry.hxx"
+#include "basegfx/matrix/b2dhommatrix.hxx"
+#include "basegfx/matrix/b2dhommatrixtools.hxx"
+#include "basegfx/polygon/b2dpolypolygoncutter.hxx"
+#include "basegfx/polygon/b2dtrapezoid.hxx"
+
+#include <vector>
+#include <queue>
+#include <set>
+
+// -=-= SalPolyLine =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#define STATIC_POINTS 64
+
+class SalPolyLine
+{
+ XPoint Points_[STATIC_POINTS];
+ XPoint *pFirst_;
+public:
+ inline SalPolyLine( ULONG nPoints );
+ inline SalPolyLine( ULONG nPoints, const SalPoint *p );
+ inline ~SalPolyLine();
+ inline XPoint &operator [] ( ULONG n ) const
+ { return pFirst_[n]; }
+};
+
+inline SalPolyLine::SalPolyLine( ULONG nPoints )
+ : pFirst_( nPoints+1 > STATIC_POINTS ? new XPoint[nPoints+1] : Points_ )
+{}
+
+inline SalPolyLine::SalPolyLine( ULONG nPoints, const SalPoint *p )
+ : pFirst_( nPoints+1 > STATIC_POINTS ? new XPoint[nPoints+1] : Points_ )
+{
+ for( ULONG i = 0; i < nPoints; i++ )
+ {
+ pFirst_[i].x = (short)p[i].mnX;
+ pFirst_[i].y = (short)p[i].mnY;
+ }
+ pFirst_[nPoints] = pFirst_[0]; // close polyline
+}
+
+inline SalPolyLine::~SalPolyLine()
+{ if( pFirst_ != Points_ ) delete [] pFirst_; }
+
+#undef STATIC_POINTS
+// -=-= X11SalGraphics =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+X11SalGraphics::X11SalGraphics()
+{
+ m_pFrame = NULL;
+ m_pVDev = NULL;
+ m_pDeleteColormap = NULL;
+ hDrawable_ = None;
+ m_aRenderPicture = 0;
+ m_pRenderFormat = NULL;
+
+ pClipRegion_ = NULL;
+ pPaintRegion_ = NULL;
+
+ pPenGC_ = NULL;
+ nPenPixel_ = 0;
+ nPenColor_ = MAKE_SALCOLOR( 0x00, 0x00, 0x00 ); // Black
+
+ pFontGC_ = NULL;
+ for( int i = 0; i < MAX_FALLBACK; ++i )
+ {
+ mXFont[i] = NULL;
+ mpServerFont[i] = NULL;
+ }
+
+ nTextPixel_ = 0;
+ nTextColor_ = MAKE_SALCOLOR( 0x00, 0x00, 0x00 ); // Black
+
+#ifdef ENABLE_GRAPHITE
+ // check if graphite fonts have been disabled
+ static const char* pDisableGraphiteStr = getenv( "SAL_DISABLE_GRAPHITE" );
+ bDisableGraphite_ = pDisableGraphiteStr ? (pDisableGraphiteStr[0]!='0') : FALSE;
+#endif
+
+ pBrushGC_ = NULL;
+ nBrushPixel_ = 0;
+ nBrushColor_ = MAKE_SALCOLOR( 0xFF, 0xFF, 0xFF ); // White
+ hBrush_ = None;
+
+ pMonoGC_ = NULL;
+ pCopyGC_ = NULL;
+ pMaskGC_ = NULL;
+ pInvertGC_ = NULL;
+ pInvert50GC_ = NULL;
+ pStippleGC_ = NULL;
+ pTrackingGC_ = NULL;
+
+ bWindow_ = FALSE;
+ bPrinter_ = FALSE;
+ bVirDev_ = FALSE;
+ bPenGC_ = FALSE;
+ bFontGC_ = FALSE;
+ bBrushGC_ = FALSE;
+ bMonoGC_ = FALSE;
+ bCopyGC_ = FALSE;
+ bInvertGC_ = FALSE;
+ bInvert50GC_ = FALSE;
+ bStippleGC_ = FALSE;
+ bTrackingGC_ = FALSE;
+ bXORMode_ = FALSE;
+ bDitherBrush_ = FALSE;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+X11SalGraphics::~X11SalGraphics()
+{
+ ReleaseFonts();
+ freeResources();
+}
+
+// -=-= SalGraphics / X11SalGraphics =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalGraphics::freeResources()
+{
+ Display *pDisplay = GetXDisplay();
+
+ DBG_ASSERT( !pPaintRegion_, "pPaintRegion_" );
+ if( pClipRegion_ ) XDestroyRegion( pClipRegion_ ), pClipRegion_ = None;
+
+ if( hBrush_ ) XFreePixmap( pDisplay, hBrush_ ), hBrush_ = None;
+ if( pPenGC_ ) XFreeGC( pDisplay, pPenGC_ ), pPenGC_ = None;
+ if( pFontGC_ ) XFreeGC( pDisplay, pFontGC_ ), pFontGC_ = None;
+ if( pBrushGC_ ) XFreeGC( pDisplay, pBrushGC_ ), pBrushGC_ = None;
+ if( pMonoGC_ ) XFreeGC( pDisplay, pMonoGC_ ), pMonoGC_ = None;
+ if( pCopyGC_ ) XFreeGC( pDisplay, pCopyGC_ ), pCopyGC_ = None;
+ if( pMaskGC_ ) XFreeGC( pDisplay, pMaskGC_ ), pMaskGC_ = None;
+ if( pInvertGC_ ) XFreeGC( pDisplay, pInvertGC_ ), pInvertGC_ = None;
+ if( pInvert50GC_ ) XFreeGC( pDisplay, pInvert50GC_ ), pInvert50GC_ = None;
+ if( pStippleGC_ ) XFreeGC( pDisplay, pStippleGC_ ), pStippleGC_ = None;
+ if( pTrackingGC_ ) XFreeGC( pDisplay, pTrackingGC_ ), pTrackingGC_ = None;
+ if( m_pDeleteColormap )
+ delete m_pDeleteColormap, m_pColormap = m_pDeleteColormap = NULL;
+
+ if( m_aRenderPicture )
+ XRenderPeer::GetInstance().FreePicture( m_aRenderPicture ), m_aRenderPicture = 0;
+
+ bPenGC_ = bFontGC_ = bBrushGC_ = bMonoGC_ = bCopyGC_ = bInvertGC_ = bInvert50GC_ = bStippleGC_ = bTrackingGC_ = false;
+}
+
+void X11SalGraphics::SetDrawable( Drawable aDrawable, int nScreen )
+{
+ // shortcut if nothing changed
+ if( hDrawable_ == aDrawable )
+ return;
+
+ // free screen specific resources if needed
+ if( nScreen != m_nScreen )
+ {
+ freeResources();
+ m_pColormap = &GetX11SalData()->GetDisplay()->GetColormap( nScreen );
+ m_nScreen = nScreen;
+ }
+
+ hDrawable_ = aDrawable;
+ SetXRenderFormat( NULL );
+ if( m_aRenderPicture )
+ {
+ XRenderPeer::GetInstance().FreePicture( m_aRenderPicture );
+ m_aRenderPicture = 0;
+ }
+
+ if( hDrawable_ )
+ {
+ nPenPixel_ = GetPixel( nPenColor_ );
+ nTextPixel_ = GetPixel( nTextColor_ );
+ nBrushPixel_ = GetPixel( nBrushColor_ );
+ }
+}
+
+void X11SalGraphics::Init( SalFrame *pFrame, Drawable aTarget, int nScreen )
+{
+#if 0 // TODO: use SetDrawable() instead
+ m_pColormap = &GetX11SalData()->GetDisplay()->GetColormap(nScreen);
+ hDrawable_ = aTarget;
+ m_nScreen = nScreen;
+ SetXRenderFormat( NULL );
+ if( m_aRenderPicture )
+ XRenderPeer::GetInstance().FreePicture( m_aRenderPicture ), m_aRenderPicture = 0;
+
+ nPenPixel_ = GetPixel( nPenColor_ );
+ nTextPixel_ = GetPixel( nTextColor_ );
+ nBrushPixel_ = GetPixel( nBrushColor_ );
+#else
+ m_pColormap = &GetX11SalData()->GetDisplay()->GetColormap(nScreen);
+ m_nScreen = nScreen;
+ SetDrawable( aTarget, nScreen );
+#endif
+
+ bWindow_ = TRUE;
+ m_pFrame = pFrame;
+ m_pVDev = NULL;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::DeInit()
+{
+ SetDrawable( None, m_nScreen );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::SetClipRegion( GC pGC, XLIB_Region pXReg ) const
+{
+ Display *pDisplay = GetXDisplay();
+
+ int n = 0;
+ XLIB_Region Regions[3];
+
+ if( pClipRegion_ /* && !XEmptyRegion( pClipRegion_ ) */ )
+ Regions[n++] = pClipRegion_;
+// if( pPaintRegion_ /* && !XEmptyRegion( pPaintRegion_ ) */ )
+// Regions[n++] = pPaintRegion_;
+
+ if( pXReg && !XEmptyRegion( pXReg ) )
+ Regions[n++] = pXReg;
+
+ if( 0 == n )
+ XSetClipMask( pDisplay, pGC, None );
+ else if( 1 == n )
+ XSetRegion( pDisplay, pGC, Regions[0] );
+ else
+ {
+ XLIB_Region pTmpRegion = XCreateRegion();
+ XIntersectRegion( Regions[0], Regions[1], pTmpRegion );
+// if( 3 == n )
+// XIntersectRegion( Regions[2], pTmpRegion, pTmpRegion );
+ XSetRegion( pDisplay, pGC, pTmpRegion );
+ XDestroyRegion( pTmpRegion );
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+GC X11SalGraphics::SelectPen()
+{
+ Display *pDisplay = GetXDisplay();
+
+ if( !pPenGC_ )
+ {
+ XGCValues values;
+ values.subwindow_mode = ClipByChildren;
+ values.fill_rule = EvenOddRule; // Pict import/ Gradient
+ values.graphics_exposures = False;
+
+ pPenGC_ = XCreateGC( pDisplay, hDrawable_,
+ GCSubwindowMode | GCFillRule | GCGraphicsExposures,
+ &values );
+ }
+
+ if( !bPenGC_ )
+ {
+ if( nPenColor_ != SALCOLOR_NONE )
+ XSetForeground( pDisplay, pPenGC_, nPenPixel_ );
+ XSetFunction ( pDisplay, pPenGC_, bXORMode_ ? GXxor : GXcopy );
+ SetClipRegion( pPenGC_ );
+ bPenGC_ = TRUE;
+ }
+
+ return pPenGC_;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+GC X11SalGraphics::SelectBrush()
+{
+ Display *pDisplay = GetXDisplay();
+
+ DBG_ASSERT( nBrushColor_ != SALCOLOR_NONE, "Brush Transparent" );
+
+ if( !pBrushGC_ )
+ {
+ XGCValues values;
+ // values.subwindow_mode = IncludeInferiors;
+ values.subwindow_mode = ClipByChildren;
+ values.fill_rule = EvenOddRule; // Pict import/ Gradient
+ values.graphics_exposures = False;
+
+ pBrushGC_ = XCreateGC( pDisplay, hDrawable_,
+ GCSubwindowMode | GCFillRule | GCGraphicsExposures,
+ &values );
+ }
+
+ if( !bBrushGC_ )
+ {
+ if( !bDitherBrush_ )
+ {
+ XSetFillStyle ( pDisplay, pBrushGC_, FillSolid );
+ XSetForeground( pDisplay, pBrushGC_, nBrushPixel_ );
+ #if defined(_USE_PRINT_EXTENSION_)
+ XSetBackground( pDisplay, pBrushGC_,
+ WhitePixel(pDisplay, DefaultScreen(pDisplay)) );
+ #else
+ if( bPrinter_ )
+ XSetTile( pDisplay, pBrushGC_, None );
+ #endif
+ }
+ else
+ {
+ // Bug in Sun Solaris 2.5.1, XFillPolygon doesn't allways reflect
+ // changes of the tile. PROPERTY_BUG_Tile doesn't fix this !
+ if (GetDisplay()->GetProperties() & PROPERTY_BUG_FillPolygon_Tile)
+ XSetFillStyle ( pDisplay, pBrushGC_, FillSolid );
+
+ XSetFillStyle ( pDisplay, pBrushGC_, FillTiled );
+ XSetTile ( pDisplay, pBrushGC_, hBrush_ );
+ }
+ XSetFunction ( pDisplay, pBrushGC_, bXORMode_ ? GXxor : GXcopy );
+ SetClipRegion( pBrushGC_ );
+
+ bBrushGC_ = TRUE;
+ }
+
+ return pBrushGC_;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+GC X11SalGraphics::GetTrackingGC()
+{
+ const char dash_list[2] = {2, 2};
+
+ if( !pTrackingGC_ )
+ {
+ XGCValues values;
+
+ values.graphics_exposures = False;
+ values.foreground = m_pColormap->GetBlackPixel()
+ ^ m_pColormap->GetWhitePixel();
+ values.function = GXxor;
+ values.line_width = 1;
+ values.line_style = LineOnOffDash;
+
+ pTrackingGC_ = XCreateGC( GetXDisplay(), GetDrawable(),
+ GCGraphicsExposures | GCForeground | GCFunction
+ | GCLineWidth | GCLineStyle,
+ &values );
+ XSetDashes( GetXDisplay(), pTrackingGC_, 0, dash_list, 2 );
+ }
+
+ if( !bTrackingGC_ )
+ {
+ SetClipRegion( pTrackingGC_ );
+ bTrackingGC_ = TRUE;
+ }
+
+ return pTrackingGC_;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::DrawLines( ULONG nPoints,
+ const SalPolyLine &rPoints,
+ GC pGC,
+ bool bClose
+ )
+{
+ // errechne wie viele Linien XWindow auf einmal zeichnen kann
+ ULONG nMaxLines = (GetDisplay()->GetMaxRequestSize() - sizeof(xPolyPointReq))
+ / sizeof(xPoint);
+ if( nMaxLines > nPoints ) nMaxLines = nPoints;
+
+ // gebe alle Linien aus, die XWindows zeichnen kann.
+ ULONG n;
+ for( n = 0; nPoints - n > nMaxLines; n += nMaxLines - 1 )
+ XDrawLines( GetXDisplay(),
+ GetDrawable(),
+ pGC,
+ &rPoints[n],
+ nMaxLines,
+ CoordModeOrigin );
+
+ if( n < nPoints )
+ XDrawLines( GetXDisplay(),
+ GetDrawable(),
+ pGC,
+ &rPoints[n],
+ nPoints - n,
+ CoordModeOrigin );
+ if( bClose )
+ {
+ if( rPoints[nPoints-1].x != rPoints[0].x || rPoints[nPoints-1].y != rPoints[0].y )
+ drawLine( rPoints[nPoints-1].x, rPoints[nPoints-1].y, rPoints[0].x, rPoints[0].y );
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// Dithern: Calculate a dither-pixmap and make a brush of it
+#define P_DELTA 51
+#define DMAP( v, m ) ((v % P_DELTA) > m ? (v / P_DELTA) + 1 : (v / P_DELTA))
+
+BOOL X11SalGraphics::GetDitherPixmap( SalColor nSalColor )
+{
+ static const short nOrdDither8Bit[ 8 ][ 8 ] =
+ {
+ { 0, 38, 9, 48, 2, 40, 12, 50},
+ {25, 12, 35, 22, 28, 15, 37, 24},
+ { 6, 44, 3, 41, 8, 47, 5, 44},
+ {32, 19, 28, 16, 34, 21, 31, 18},
+ { 1, 40, 11, 49, 0, 39, 10, 48},
+ {27, 14, 36, 24, 26, 13, 36, 23},
+ { 8, 46, 4, 43, 7, 45, 4, 42},
+ {33, 20, 30, 17, 32, 20, 29, 16}
+ };
+
+ // test for correct depth (8bit)
+ if( GetColormap().GetVisual().GetDepth() != 8 )
+ return FALSE;
+
+ char pBits[64];
+ char *pBitsPtr = pBits;
+
+ // Set the pallette-entries for the dithering tile
+ UINT8 nSalColorRed = SALCOLOR_RED ( nSalColor );
+ UINT8 nSalColorGreen = SALCOLOR_GREEN ( nSalColor );
+ UINT8 nSalColorBlue = SALCOLOR_BLUE ( nSalColor );
+
+ for( int nY = 0; nY < 8; nY++ )
+ {
+ for( int nX = 0; nX < 8; nX++ )
+ {
+ short nMagic = nOrdDither8Bit[nY][nX];
+ UINT8 nR = P_DELTA * DMAP( nSalColorRed, nMagic );
+ UINT8 nG = P_DELTA * DMAP( nSalColorGreen, nMagic );
+ UINT8 nB = P_DELTA * DMAP( nSalColorBlue, nMagic );
+
+ *pBitsPtr++ = GetColormap().GetPixel( MAKE_SALCOLOR( nR, nG, nB ) );
+ }
+ }
+
+ // create the tile as ximage and an according pixmap -> caching
+ XImage *pImage = XCreateImage( GetXDisplay(),
+ GetColormap().GetXVisual(),
+ 8,
+ ZPixmap,
+ 0, // offset
+ pBits, // data
+ 8, 8, // width & height
+ 8, // bitmap_pad
+ 0 ); // (default) bytes_per_line
+
+ if ( GetDisplay()->GetProperties() & PROPERTY_BUG_Tile )
+ {
+ if (hBrush_)
+ XFreePixmap (GetXDisplay(), hBrush_);
+ hBrush_ = XCreatePixmap( GetXDisplay(), GetDrawable(), 8, 8, 8 );
+ }
+ else
+ if( !hBrush_ )
+ hBrush_ = XCreatePixmap( GetXDisplay(), GetDrawable(), 8, 8, 8 );
+
+ // put the ximage to the pixmap
+ XPutImage( GetXDisplay(),
+ hBrush_,
+ GetDisplay()->GetCopyGC( m_nScreen ),
+ pImage,
+ 0, 0, // Source
+ 0, 0, // Destination
+ 8, 8 ); // width & height
+
+ // destroy image-frame but not palette-data
+ pImage->data = NULL;
+ XDestroyImage( pImage );
+
+ return TRUE;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::GetResolution( sal_Int32 &rDPIX, sal_Int32 &rDPIY ) // const
+{
+ const SalDisplay *pDisplay = GetDisplay();
+
+ rDPIX = pDisplay->GetResolution().A();
+ rDPIY = pDisplay->GetResolution().B();
+ if( !pDisplay->GetExactResolution() && rDPIY < 96 )
+ {
+ rDPIX = Divide( rDPIX * 96, rDPIY );
+ rDPIY = 96;
+ }
+ else if ( rDPIY > 200 )
+ {
+ rDPIX = Divide( rDPIX * 200, rDPIY );
+ rDPIY = 200;
+ }
+
+ // #i12705# equalize x- and y-resolution if they are close enough
+ if( rDPIX != rDPIY )
+ {
+ // different x- and y- resolutions are usually artifacts of
+ // a wrongly calculated screen size.
+ //if( (13*rDPIX >= 10*rDPIY) && (13*rDPIY >= 10*rDPIX) ) //+-30%
+ {
+#ifdef DEBUG
+ printf("Forcing Resolution from %" SAL_PRIdINT32 "x%" SAL_PRIdINT32 " to %" SAL_PRIdINT32 "x%" SAL_PRIdINT32 "\n",
+ rDPIX,rDPIY,rDPIY,rDPIY);
+#endif
+ rDPIX = rDPIY; // y-resolution is more trustworthy
+ }
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+USHORT X11SalGraphics::GetBitCount() // const
+{
+ return GetVisual().GetDepth();
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+long X11SalGraphics::GetGraphicsWidth() const
+{
+ if( m_pFrame )
+ return m_pFrame->maGeometry.nWidth;
+ else if( m_pVDev )
+ return m_pVDev->GetWidth();
+ else
+ return 0;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+long X11SalGraphics::GetGraphicsHeight() const
+{
+ if( m_pFrame )
+ return m_pFrame->maGeometry.nHeight;
+ else if( m_pVDev )
+ return m_pVDev->GetHeight();
+ else
+ return 0;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::ResetClipRegion()
+{
+ if( pClipRegion_ )
+ {
+ bPenGC_ = FALSE;
+ bFontGC_ = FALSE;
+ bBrushGC_ = FALSE;
+ bMonoGC_ = FALSE;
+ bCopyGC_ = FALSE;
+ bInvertGC_ = FALSE;
+ bInvert50GC_ = FALSE;
+ bStippleGC_ = FALSE;
+ bTrackingGC_ = FALSE;
+
+ XDestroyRegion( pClipRegion_ );
+ pClipRegion_ = NULL;
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::BeginSetClipRegion( ULONG )
+{
+ if( pClipRegion_ )
+ XDestroyRegion( pClipRegion_ );
+ pClipRegion_ = XCreateRegion();
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+BOOL X11SalGraphics::unionClipRegion( long nX, long nY, long nDX, long nDY )
+{
+ if (!nDX || !nDY)
+ return TRUE;
+
+ XRectangle aRect;
+ aRect.x = (short)nX;
+ aRect.y = (short)nY;
+ aRect.width = (unsigned short)nDX;
+ aRect.height = (unsigned short)nDY;
+
+ XUnionRectWithRegion( &aRect, pClipRegion_, pClipRegion_ );
+
+ return TRUE;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+bool X11SalGraphics::unionClipRegion( const ::basegfx::B2DPolyPolygon& )
+{
+ // TODO: implement and advertise OutDevSupport_B2DClip support
+ return false;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::EndSetClipRegion()
+{
+ bPenGC_ = FALSE;
+ bFontGC_ = FALSE;
+ bBrushGC_ = FALSE;
+ bMonoGC_ = FALSE;
+ bCopyGC_ = FALSE;
+ bInvertGC_ = FALSE;
+ bInvert50GC_ = FALSE;
+ bStippleGC_ = FALSE;
+ bTrackingGC_ = FALSE;
+
+ if( XEmptyRegion( pClipRegion_ ) )
+ {
+ XDestroyRegion( pClipRegion_ );
+ pClipRegion_= NULL;
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::SetLineColor()
+{
+ if( nPenColor_ != SALCOLOR_NONE )
+ {
+ nPenColor_ = SALCOLOR_NONE;
+ bPenGC_ = FALSE;
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::SetLineColor( SalColor nSalColor )
+{
+ if( nPenColor_ != nSalColor )
+ {
+ nPenColor_ = nSalColor;
+ nPenPixel_ = GetPixel( nSalColor );
+ bPenGC_ = FALSE;
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::SetFillColor()
+{
+ if( nBrushColor_ != SALCOLOR_NONE )
+ {
+ bDitherBrush_ = FALSE;
+ nBrushColor_ = SALCOLOR_NONE;
+ bBrushGC_ = FALSE;
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::SetFillColor( SalColor nSalColor )
+{
+ if( nBrushColor_ != nSalColor )
+ {
+ bDitherBrush_ = FALSE;
+ nBrushColor_ = nSalColor;
+ nBrushPixel_ = GetPixel( nSalColor );
+ if( TrueColor != GetColormap().GetVisual().GetClass()
+ && GetColormap().GetColor( nBrushPixel_ ) != nBrushColor_
+ && nSalColor != MAKE_SALCOLOR( 0x00, 0x00, 0x00 ) // black
+ && nSalColor != MAKE_SALCOLOR( 0x00, 0x00, 0x80 ) // blue
+ && nSalColor != MAKE_SALCOLOR( 0x00, 0x80, 0x00 ) // green
+ && nSalColor != MAKE_SALCOLOR( 0x00, 0x80, 0x80 ) // cyan
+ && nSalColor != MAKE_SALCOLOR( 0x80, 0x00, 0x00 ) // red
+ && nSalColor != MAKE_SALCOLOR( 0x80, 0x00, 0x80 ) // magenta
+ && nSalColor != MAKE_SALCOLOR( 0x80, 0x80, 0x00 ) // brown
+ && nSalColor != MAKE_SALCOLOR( 0x80, 0x80, 0x80 ) // gray
+ && nSalColor != MAKE_SALCOLOR( 0xC0, 0xC0, 0xC0 ) // light gray
+ && nSalColor != MAKE_SALCOLOR( 0x00, 0x00, 0xFF ) // light blue
+ && nSalColor != MAKE_SALCOLOR( 0x00, 0xFF, 0x00 ) // light green
+ && nSalColor != MAKE_SALCOLOR( 0x00, 0xFF, 0xFF ) // light cyan
+ && nSalColor != MAKE_SALCOLOR( 0xFF, 0x00, 0x00 ) // light red
+ && nSalColor != MAKE_SALCOLOR( 0xFF, 0x00, 0xFF ) // light magenta
+ && nSalColor != MAKE_SALCOLOR( 0xFF, 0xFF, 0x00 ) // light brown
+ && nSalColor != MAKE_SALCOLOR( 0xFF, 0xFF, 0xFF ) )
+ bDitherBrush_ = GetDitherPixmap(nSalColor);
+ bBrushGC_ = FALSE;
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::SetROPLineColor( SalROPColor nROPColor )
+{
+ switch( nROPColor )
+ {
+ case SAL_ROP_0 : // 0
+ nPenPixel_ = (Pixel)0;
+ break;
+ case SAL_ROP_1 : // 1
+ nPenPixel_ = (Pixel)(1 << GetVisual().GetDepth()) - 1;
+ break;
+ case SAL_ROP_INVERT : // 2
+ nPenPixel_ = (Pixel)(1 << GetVisual().GetDepth()) - 1;
+ break;
+ }
+ nPenColor_ = GetColormap().GetColor( nPenPixel_ );
+ bPenGC_ = FALSE;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::SetROPFillColor( SalROPColor nROPColor )
+{
+ switch( nROPColor )
+ {
+ case SAL_ROP_0 : // 0
+ nBrushPixel_ = (Pixel)0;
+ break;
+ case SAL_ROP_1 : // 1
+ nBrushPixel_ = (Pixel)(1 << GetVisual().GetDepth()) - 1;
+ break;
+ case SAL_ROP_INVERT : // 2
+ nBrushPixel_ = (Pixel)(1 << GetVisual().GetDepth()) - 1;
+ break;
+ }
+ bDitherBrush_ = FALSE;
+ nBrushColor_ = GetColormap().GetColor( nBrushPixel_ );
+ bBrushGC_ = FALSE;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::SetXORMode( bool bSet, bool )
+{
+ if( !bXORMode_ == bSet )
+ {
+ bXORMode_ = bSet;
+ bPenGC_ = FALSE;
+ bBrushGC_ = FALSE;
+ bMonoGC_ = FALSE;
+ bCopyGC_ = FALSE;
+ bInvertGC_ = FALSE;
+ bInvert50GC_ = FALSE;
+ bStippleGC_ = FALSE;
+ bTrackingGC_ = FALSE;
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::drawPixel( long nX, long nY )
+{
+ if( nPenColor_ != SALCOLOR_NONE )
+ XDrawPoint( GetXDisplay(), GetDrawable(), SelectPen(), nX, nY );
+}
+
+void X11SalGraphics::drawPixel( long nX, long nY, SalColor nSalColor )
+{
+ if( nSalColor != SALCOLOR_NONE )
+ {
+ Display *pDisplay = GetXDisplay();
+
+ if( (nPenColor_ == SALCOLOR_NONE) && !bPenGC_ )
+ {
+ SetLineColor( nSalColor );
+ XDrawPoint( pDisplay, GetDrawable(), SelectPen(), nX, nY );
+ nPenColor_ = SALCOLOR_NONE;
+ bPenGC_ = False;
+ }
+ else
+ {
+ GC pGC = SelectPen();
+
+ if( nSalColor != nPenColor_ )
+ XSetForeground( pDisplay, pGC, GetPixel( nSalColor ) );
+
+ XDrawPoint( pDisplay, GetDrawable(), pGC, nX, nY );
+
+ if( nSalColor != nPenColor_ )
+ XSetForeground( pDisplay, pGC, nPenPixel_ );
+ }
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 )
+{
+ if( nPenColor_ != SALCOLOR_NONE )
+ {
+ if ( GetDisplay()->GetProperties() & PROPERTY_BUG_DrawLine )
+ {
+ GC aGC = SelectPen();
+ XDrawPoint (GetXDisplay(), GetDrawable(), aGC, (int)nX1, (int)nY1);
+ XDrawPoint (GetXDisplay(), GetDrawable(), aGC, (int)nX2, (int)nY2);
+ XDrawLine (GetXDisplay(), GetDrawable(), aGC, nX1, nY1, nX2, nY2 );
+ }
+ else
+ XDrawLine( GetXDisplay(), GetDrawable(),SelectPen(),
+ nX1, nY1, nX2, nY2 );
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::drawRect( long nX, long nY, long nDX, long nDY )
+{
+ if( nBrushColor_ != SALCOLOR_NONE )
+ {
+ XFillRectangle( GetXDisplay(),
+ GetDrawable(),
+ SelectBrush(),
+ nX, nY, nDX, nDY );
+ }
+ // Beschreibung DrawRect verkehrt, deshalb -1
+ if( nPenColor_ != SALCOLOR_NONE )
+ XDrawRectangle( GetXDisplay(),
+ GetDrawable(),
+ SelectPen(),
+ nX, nY, nDX-1, nDY-1 );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::drawPolyLine( ULONG nPoints, const SalPoint *pPtAry )
+{
+ drawPolyLine( nPoints, pPtAry, false );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::drawPolyLine( ULONG nPoints, const SalPoint *pPtAry, bool bClose )
+{
+ if( nPenColor_ != 0xFFFFFFFF )
+ {
+ SalPolyLine Points( nPoints, pPtAry );
+
+ DrawLines( nPoints, Points, SelectPen(), bClose );
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::drawPolygon( ULONG nPoints, const SalPoint* pPtAry )
+{
+ if( nPoints == 0 )
+ return;
+
+ if( nPoints < 3 )
+ {
+ if( !bXORMode_ )
+ {
+ if( 1 == nPoints )
+ drawPixel( pPtAry[0].mnX, pPtAry[0].mnY );
+ else
+ drawLine( pPtAry[0].mnX, pPtAry[0].mnY,
+ pPtAry[1].mnX, pPtAry[1].mnY );
+ }
+ return;
+ }
+
+ SalPolyLine Points( nPoints, pPtAry );
+
+ nPoints++;
+
+ /* WORKAROUND: some Xservers (Xorg, VIA chipset in this case)
+ * do not draw the visible part of a polygon
+ * if it overlaps to the left of screen 0,y.
+ * This happens to be the case in the gradient drawn in the
+ * menubar background. workaround for the special case of
+ * of a rectangle overlapping to the left.
+ */
+ if( nPoints == 5 &&
+ Points[ 0 ].x == Points[ 1 ].x &&
+ Points[ 1 ].y == Points[ 2 ].y &&
+ Points[ 2 ].x == Points[ 3 ].x &&
+ Points[ 0 ].x == Points[ 4 ].x && Points[ 0 ].y == Points[ 4 ].y
+ )
+ {
+ bool bLeft = false;
+ bool bRight = false;
+ for(unsigned int i = 0; i < nPoints; i++ )
+ {
+ if( Points[i].x < 0 )
+ bLeft = true;
+ else
+ bRight= true;
+ }
+ if( bLeft && ! bRight )
+ return;
+ if( bLeft && bRight )
+ {
+ for( unsigned int i = 0; i < nPoints; i++ )
+ if( Points[i].x < 0 )
+ Points[i].x = 0;
+ }
+ }
+
+ if( nBrushColor_ != SALCOLOR_NONE )
+ XFillPolygon( GetXDisplay(),
+ GetDrawable(),
+ SelectBrush(),
+ &Points[0], nPoints,
+ Complex, CoordModeOrigin );
+
+ if( nPenColor_ != 0xFFFFFFFF )
+ DrawLines( nPoints, Points, SelectPen(), true );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::drawPolyPolygon( sal_uInt32 nPoly,
+ const sal_uInt32 *pPoints,
+ PCONSTSALPOINT *pPtAry )
+{
+ if( nBrushColor_ != SALCOLOR_NONE )
+ {
+ ULONG i, n;
+ XLIB_Region pXRegA = NULL;
+
+ for( i = 0; i < nPoly; i++ ) {
+ n = pPoints[i];
+ SalPolyLine Points( n, pPtAry[i] );
+ if( n > 2 )
+ {
+ XLIB_Region pXRegB = XPolygonRegion( &Points[0], n+1, WindingRule );
+ if( !pXRegA )
+ pXRegA = pXRegB;
+ else
+ {
+ XXorRegion( pXRegA, pXRegB, pXRegA );
+ XDestroyRegion( pXRegB );
+ }
+ }
+ }
+
+ if( pXRegA )
+ {
+ XRectangle aXRect;
+ XClipBox( pXRegA, &aXRect );
+
+ GC pGC = SelectBrush();
+ SetClipRegion( pGC, pXRegA ); // ??? doppelt
+ XDestroyRegion( pXRegA );
+ bBrushGC_ = FALSE;
+
+ XFillRectangle( GetXDisplay(),
+ GetDrawable(),
+ pGC,
+ aXRect.x, aXRect.y, aXRect.width, aXRect.height );
+ }
+ }
+
+ if( nPenColor_ != SALCOLOR_NONE )
+ for( ULONG i = 0; i < nPoly; i++ )
+ drawPolyLine( pPoints[i], pPtAry[i], true );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+sal_Bool X11SalGraphics::drawPolyLineBezier( ULONG, const SalPoint*, const BYTE* )
+{
+ return sal_False;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+sal_Bool X11SalGraphics::drawPolygonBezier( ULONG, const SalPoint*, const BYTE* )
+{
+ return sal_False;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+sal_Bool X11SalGraphics::drawPolyPolygonBezier( sal_uInt32, const sal_uInt32*,
+ const SalPoint* const*, const BYTE* const* )
+{
+ return sal_False;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalGraphics::invert( ULONG nPoints,
+ const SalPoint* pPtAry,
+ SalInvert nFlags )
+{
+ SalPolyLine Points ( nPoints, pPtAry );
+
+ GC pGC;
+ if( SAL_INVERT_50 & nFlags )
+ pGC = GetInvert50GC();
+ else
+ if ( SAL_INVERT_TRACKFRAME & nFlags )
+ pGC = GetTrackingGC();
+ else
+ pGC = GetInvertGC();
+
+ if( SAL_INVERT_TRACKFRAME & nFlags )
+ DrawLines ( nPoints, Points, pGC, true );
+ else
+ XFillPolygon( GetXDisplay(),
+ GetDrawable(),
+ pGC,
+ &Points[0], nPoints,
+ Complex, CoordModeOrigin );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+BOOL X11SalGraphics::drawEPS( long,long,long,long,void*,ULONG )
+{
+ return FALSE;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+XID X11SalGraphics::GetXRenderPicture()
+{
+ XRenderPeer& rRenderPeer = XRenderPeer::GetInstance();
+
+ if( !m_aRenderPicture )
+ {
+ // check xrender support for matching visual
+ // find a XRenderPictFormat compatible with the Drawable
+ XRenderPictFormat* pVisualFormat = static_cast<XRenderPictFormat*>(GetXRenderFormat());
+ if( !pVisualFormat )
+ {
+ Visual* pVisual = GetDisplay()->GetVisual( m_nScreen ).GetVisual();
+ pVisualFormat = rRenderPeer.FindVisualFormat( pVisual );
+ if( !pVisualFormat )
+ return 0;
+ // cache the XRenderPictFormat
+ SetXRenderFormat( static_cast<void*>(pVisualFormat) );
+ }
+
+ // get the matching xrender target for drawable
+ m_aRenderPicture = rRenderPeer.CreatePicture( hDrawable_, pVisualFormat, 0, NULL );
+ }
+
+#if 0
+ // setup clipping so the callers don't have to do it themselves
+ // TODO: avoid clipping if already set correctly
+ if( pClipRegion_ && !XEmptyRegion( pClipRegion_ ) )
+ rRenderPeer.SetPictureClipRegion( aDstPic, pClipRegion_ );
+ else
+#endif
+ {
+ // reset clip region
+ // TODO: avoid clip reset if already done
+ XRenderPictureAttributes aAttr;
+ aAttr.clip_mask = None;
+ rRenderPeer.ChangePicture( m_aRenderPicture, CPClipMask, &aAttr );
+ }
+
+ return m_aRenderPicture;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+SystemGraphicsData X11SalGraphics::GetGraphicsData() const
+{
+ SystemGraphicsData aRes;
+
+ aRes.nSize = sizeof(aRes);
+ aRes.pDisplay = GetXDisplay();
+ aRes.hDrawable = hDrawable_;
+ aRes.pVisual = GetDisplay()->GetVisual( m_nScreen ).GetVisual();
+ aRes.nScreen = m_nScreen;
+ aRes.nDepth = GetDisplay()->GetVisual( m_nScreen ).GetDepth();
+ aRes.aColormap = GetDisplay()->GetColormap( m_nScreen ).GetXColormap();
+ aRes.pRenderFormat = m_pRenderFormat;
+ return aRes;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+// draw a poly-polygon
+bool X11SalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rOrigPolyPoly, double fTransparency )
+{
+ // nothing to do for empty polypolygons
+ const int nOrigPolyCount = rOrigPolyPoly.count();
+ if( nOrigPolyCount <= 0 )
+ return TRUE;
+
+ // nothing to do if everything is transparent
+ if( (nBrushColor_ == SALCOLOR_NONE)
+ && (nPenColor_ == SALCOLOR_NONE) )
+ return TRUE;
+
+ // cannot handle pencolor!=brushcolor yet
+ if( (nPenColor_ != SALCOLOR_NONE)
+ && (nPenColor_ != nBrushColor_) )
+ return FALSE;
+
+ // TODO: remove the env-variable when no longer needed
+ static const char* pRenderEnv = getenv( "SAL_DISABLE_RENDER_POLY" );
+ if( pRenderEnv )
+ return FALSE;
+
+ // snap to raster if requested
+ basegfx::B2DPolyPolygon aPolyPoly = rOrigPolyPoly;
+ const bool bSnapToRaster = !getAntiAliasB2DDraw();
+ if( bSnapToRaster )
+ aPolyPoly = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges( aPolyPoly );
+
+ // don't bother with polygons outside of visible area
+ const basegfx::B2DRange aViewRange( 0, 0, GetGraphicsWidth(), GetGraphicsHeight() );
+ aPolyPoly = basegfx::tools::clipPolyPolygonOnRange( aPolyPoly, aViewRange, true, false );
+ if( !aPolyPoly.count() )
+ return true;
+
+ // tesselate the polypolygon into trapezoids
+ basegfx::B2DTrapezoidVector aB2DTrapVector;
+ basegfx::tools::trapezoidSubdivide( aB2DTrapVector, aPolyPoly );
+ const int nTrapCount = aB2DTrapVector.size();
+ const bool bDrawn = drawFilledTrapezoids( &aB2DTrapVector[0], nTrapCount, fTransparency );
+ return bDrawn;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+bool X11SalGraphics::drawFilledTrapezoids( const ::basegfx::B2DTrapezoid* pB2DTraps, int nTrapCount, double fTransparency )
+{
+ if( nTrapCount <= 0 )
+ return true;
+
+ Picture aDstPic = GetXRenderPicture();
+ // check xrender support for this drawable
+ if( !aDstPic )
+ return false;
+
+ // convert the B2DTrapezoids into XRender-Trapezoids
+ typedef std::vector<XTrapezoid> TrapezoidVector;
+ TrapezoidVector aTrapVector( nTrapCount );
+ const basegfx::B2DTrapezoid* pB2DTrap = pB2DTraps;
+ for( int i = 0; i < nTrapCount; ++pB2DTrap, ++i )
+ {
+ XTrapezoid& rTrap = aTrapVector[ i ] ;
+
+ // set y-coordinates
+ const double fY1 = pB2DTrap->getTopY();
+ rTrap.left.p1.y = rTrap.right.p1.y = rTrap.top = XDoubleToFixed( fY1 );
+ const double fY2 = pB2DTrap->getBottomY();
+ rTrap.left.p2.y = rTrap.right.p2.y = rTrap.bottom = XDoubleToFixed( fY2 );
+
+ // set x-coordinates
+ const double fXL1 = pB2DTrap->getTopXLeft();
+ rTrap.left.p1.x = XDoubleToFixed( fXL1 );
+ const double fXR1 = pB2DTrap->getTopXRight();
+ rTrap.right.p1.x = XDoubleToFixed( fXR1 );
+ const double fXL2 = pB2DTrap->getBottomXLeft();
+ rTrap.left.p2.x = XDoubleToFixed( fXL2 );
+ const double fXR2 = pB2DTrap->getBottomXRight();
+ rTrap.right.p2.x = XDoubleToFixed( fXR2 );
+ }
+
+ // get xrender Picture for polygon foreground
+ // TODO: cache it like the target picture which uses GetXRenderPicture()
+ XRenderPeer& rRenderPeer = XRenderPeer::GetInstance();
+ SalDisplay::RenderEntry& rEntry = GetDisplay()->GetRenderEntries( m_nScreen )[ 32 ];
+ if( !rEntry.m_aPicture )
+ {
+ Display* pXDisplay = GetXDisplay();
+
+ rEntry.m_aPixmap = ::XCreatePixmap( pXDisplay, hDrawable_, 1, 1, 32 );
+ XRenderPictureAttributes aAttr;
+ aAttr.repeat = true;
+
+ XRenderPictFormat* pXRPF = rRenderPeer.FindStandardFormat( PictStandardARGB32 );
+ rEntry.m_aPicture = rRenderPeer.CreatePicture( rEntry.m_aPixmap, pXRPF, CPRepeat, &aAttr );
+ }
+
+ // set polygon foreground color and opacity
+ XRenderColor aRenderColor = GetXRenderColor( nBrushColor_ , fTransparency );
+ rRenderPeer.FillRectangle( PictOpSrc, rEntry.m_aPicture, &aRenderColor, 0, 0, 1, 1 );
+
+ // set clipping
+ // TODO: move into GetXRenderPicture?
+ if( pClipRegion_ && !XEmptyRegion( pClipRegion_ ) )
+ rRenderPeer.SetPictureClipRegion( aDstPic, pClipRegion_ );
+
+ // render the trapezoids
+ const XRenderPictFormat* pMaskFormat = rRenderPeer.GetStandardFormatA8();
+ rRenderPeer.CompositeTrapezoids( PictOpOver,
+ rEntry.m_aPicture, aDstPic, pMaskFormat, 0, 0, &aTrapVector[0], aTrapVector.size() );
+
+ return true;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+bool X11SalGraphics::drawPolyLine(const ::basegfx::B2DPolygon& rPolygon, double fTransparency, const ::basegfx::B2DVector& rLineWidth, basegfx::B2DLineJoin eLineJoin)
+{
+ const bool bIsHairline = (rLineWidth.getX() == rLineWidth.getY()) && (rLineWidth.getX() <= 1.2);
+
+ // #i101491#
+ if( !bIsHairline && (rPolygon.count() > 1000) )
+ {
+ // the used basegfx::tools::createAreaGeometry is simply too
+ // expensive with very big polygons; fallback to caller (who
+ // should use ImplLineConverter normally)
+ // AW: ImplLineConverter had to be removed since it does not even
+ // know LineJoins, so the fallback will now prepare the line geometry
+ // the same way.
+ return false;
+ }
+
+ // temporarily adjust brush color to pen color
+ // since the line is drawn as an area-polygon
+ const SalColor aKeepBrushColor = nBrushColor_;
+ nBrushColor_ = nPenColor_;
+
+ // #i11575#desc5#b adjust B2D tesselation result to raster positions
+ basegfx::B2DPolygon aPolygon = rPolygon;
+ const double fHalfWidth = 0.5 * rLineWidth.getX();
+ aPolygon.transform( basegfx::tools::createTranslateB2DHomMatrix(+fHalfWidth,+fHalfWidth) );
+
+ // shortcut for hairline drawing to improve performance
+ if( bIsHairline )
+ {
+ // hairlines can benefit from a simplified tesselation
+ // e.g. for hairlines the linejoin style can be ignored
+ basegfx::B2DTrapezoidVector aB2DTrapVector;
+ basegfx::tools::createLineTrapezoidFromB2DPolygon( aB2DTrapVector, aPolygon, rLineWidth.getX() );
+
+ // draw tesselation result
+ const int nTrapCount = aB2DTrapVector.size();
+ const bool bDrawOk = drawFilledTrapezoids( &aB2DTrapVector[0], nTrapCount, fTransparency );
+
+ // restore the original brush GC
+ nBrushColor_ = aKeepBrushColor;
+ return bDrawOk;
+ }
+
+ // get the area polygon for the line polygon
+ if( (rLineWidth.getX() != rLineWidth.getY())
+ && !basegfx::fTools::equalZero( rLineWidth.getY() ) )
+ {
+ // prepare for createAreaGeometry() with anisotropic linewidth
+ aPolygon.transform( basegfx::tools::createScaleB2DHomMatrix(1.0, rLineWidth.getX() / rLineWidth.getY()));
+ }
+
+ // create the area-polygon for the line
+ const basegfx::B2DPolyPolygon aAreaPolyPoly( basegfx::tools::createAreaGeometry(aPolygon, fHalfWidth, eLineJoin) );
+
+ if( (rLineWidth.getX() != rLineWidth.getY())
+ && !basegfx::fTools::equalZero( rLineWidth.getX() ) )
+ {
+ // postprocess createAreaGeometry() for anisotropic linewidth
+ aPolygon.transform(basegfx::tools::createScaleB2DHomMatrix(1.0, rLineWidth.getY() / rLineWidth.getX()));
+ }
+
+ // draw each area polypolygon component individually
+ // to emulate the polypolygon winding rule "non-zero"
+ bool bDrawOk = true;
+ const int nPolyCount = aAreaPolyPoly.count();
+ for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx )
+ {
+ const ::basegfx::B2DPolyPolygon aOnePoly( aAreaPolyPoly.getB2DPolygon( nPolyIdx ) );
+ bDrawOk = drawPolyPolygon( aOnePoly, fTransparency );
+ if( !bDrawOk )
+ break;
+ }
+
+ // restore the original brush GC
+ nBrushColor_ = aKeepBrushColor;
+ return bDrawOk;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
diff --git a/vcl/unx/source/gdi/salgdi2.cxx b/vcl/unx/source/gdi/salgdi2.cxx
new file mode 100644
index 000000000000..1cb2abbedf43
--- /dev/null
+++ b/vcl/unx/source/gdi/salgdi2.cxx
@@ -0,0 +1,1149 @@
+/*************************************************************************
+ *
+ * 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 <poll.h>
+
+#include "salunx.h"
+#include "saldata.hxx"
+#include "saldisp.hxx"
+#include "salbmp.h"
+#include "salgdi.h"
+#include "salframe.h"
+#include "salvd.h"
+#include "xrender_peer.hxx"
+
+#include "vcl/salbtype.hxx"
+#include "vcl/printergfx.hxx"
+#include "vcl/bmpacc.hxx"
+
+#undef SALGDI2_TESTTRANS
+
+// -=-= debugging =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#if 0
+
+static void sal_PrintImage( char *s, XImage*p )
+{
+ fprintf( stderr, "%s %d %d %d\n", s, p->depth, p->width, p->height );
+ int nW = Min( 64, p->width*p->bits_per_pixel >> 3 );
+ for( int i = 0; i < Min( 16, p->height ); i++ )
+ {
+ for( int j = 0; j < nW; j++ )
+ fprintf( stderr, "%02X", (UINT8)p->data[i*p->bytes_per_line+j] );
+ fprintf( stderr, "\n" );
+ }
+}
+
+#endif // DBG_UTIL
+
+// -----------------------------------------------------------------------------
+
+#if (OSL_DEBUG_LEVEL > 1) && defined SALGDI2_TESTTRANS
+#define DBG_TESTTRANS( _def_drawable ) \
+{ \
+ XCopyArea( pXDisp, _def_drawable, aDrawable, GetCopyGC(), \
+ 0, 0, \
+ pPosAry->mnDestWidth, pPosAry->mnDestHeight, \
+ 0, 0 ); \
+}
+#else // (OSL_DEBUG_LEVEL > 1) && defined SALGDI2_TESTTRANS
+#define DBG_TESTTRANS( _def_drawable )
+#endif // (OSL_DEBUG_LEVEL > 1) && defined SALGDI2_TESTTRANS
+
+// -=-= X11SalGraphics =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::CopyScreenArea( Display* pDisplay,
+ Drawable aSrc, int nScreenSrc, int nSrcDepth,
+ Drawable aDest, int nScreenDest, int nDestDepth,
+ GC aDestGC,
+ int src_x, int src_y,
+ unsigned int w, unsigned int h,
+ int dest_x, int dest_y )
+{
+ if( nSrcDepth == nDestDepth )
+ {
+ if( nScreenSrc == nScreenDest )
+ XCopyArea( pDisplay, aSrc, aDest, aDestGC,
+ src_x, src_y, w, h, dest_x, dest_y );
+ else
+ {
+ SalXLib* pLib = GetX11SalData()->GetDisplay()->GetXLib();
+ pLib->PushXErrorLevel( true );
+ XImage* pImage = XGetImage( pDisplay, aSrc, src_x, src_y, w, h,
+ AllPlanes, ZPixmap );
+ if( pImage )
+ {
+ if( pImage->data )
+ {
+ XPutImage( pDisplay, aDest, aDestGC, pImage,
+ 0, 0, dest_x, dest_y, w, h );
+ }
+ XDestroyImage( pImage );
+ }
+ pLib->PopXErrorLevel();
+ }
+ }
+ else
+ {
+ X11SalBitmap aBM;
+ aBM.ImplCreateFromDrawable( aSrc, nScreenSrc, nSrcDepth, src_x, src_y, w, h );
+ SalTwoRect aTwoRect;
+ aTwoRect.mnSrcX = aTwoRect.mnSrcY = 0;
+ aTwoRect.mnSrcWidth = aTwoRect.mnDestWidth = w;
+ aTwoRect.mnSrcHeight = aTwoRect.mnDestHeight = h;
+ aTwoRect.mnDestX = dest_x;
+ aTwoRect.mnDestY = dest_y;
+ aBM.ImplDraw( aDest, nScreenDest, nDestDepth, aTwoRect,aDestGC );
+ }
+}
+
+GC X11SalGraphics::CreateGC( Drawable hDrawable, unsigned long nMask )
+{
+ XGCValues values;
+
+ values.graphics_exposures = False;
+ values.foreground = m_pColormap->GetBlackPixel()
+ ^ m_pColormap->GetWhitePixel();
+ values.function = GXxor;
+ values.line_width = 1;
+ values.fill_style = FillStippled;
+ values.stipple = GetDisplay()->GetInvert50( m_nScreen );
+ values.subwindow_mode = ClipByChildren;
+
+ return XCreateGC( GetXDisplay(), hDrawable, nMask | GCSubwindowMode, &values );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+inline GC X11SalGraphics::GetMonoGC( Pixmap hPixmap )
+{
+ if( !pMonoGC_ )
+ pMonoGC_ = CreateGC( hPixmap );
+
+ if( !bMonoGC_ )
+ {
+ SetClipRegion( pMonoGC_ );
+ bMonoGC_ = TRUE;
+ }
+
+ return pMonoGC_;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+inline GC X11SalGraphics::GetCopyGC()
+{
+ if( bXORMode_ ) return GetInvertGC();
+
+ if( !pCopyGC_ )
+ pCopyGC_ = CreateGC( GetDrawable() );
+
+ if( !bCopyGC_ )
+ {
+ SetClipRegion( pCopyGC_ );
+ bCopyGC_ = TRUE;
+ }
+ return pCopyGC_;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+GC X11SalGraphics::GetInvertGC()
+{
+ if( !pInvertGC_ )
+ pInvertGC_ = CreateGC( GetDrawable(),
+ GCGraphicsExposures
+ | GCForeground
+ | GCFunction
+ | GCLineWidth );
+
+ if( !bInvertGC_ )
+ {
+ SetClipRegion( pInvertGC_ );
+ bInvertGC_ = TRUE;
+ }
+ return pInvertGC_;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+GC X11SalGraphics::GetInvert50GC()
+{
+ if( !pInvert50GC_ )
+ {
+ XGCValues values;
+
+ values.graphics_exposures = False;
+ values.foreground = m_pColormap->GetWhitePixel();
+ values.background = m_pColormap->GetBlackPixel();
+ values.function = GXinvert;
+ values.line_width = 1;
+ values.line_style = LineSolid;
+ unsigned long nValueMask =
+ GCGraphicsExposures
+ | GCForeground
+ | GCBackground
+ | GCFunction
+ | GCLineWidth
+ | GCLineStyle
+ | GCFillStyle
+ | GCStipple;
+
+ char* pEnv = getenv( "SAL_DO_NOT_USE_INVERT50" );
+ if( pEnv && ! strcasecmp( pEnv, "true" ) )
+ {
+ values.fill_style = FillSolid;
+ nValueMask &= ~ GCStipple;
+ }
+ else
+ {
+ values.fill_style = FillStippled;
+ values.stipple = GetDisplay()->GetInvert50( m_nScreen );
+ }
+
+ pInvert50GC_ = XCreateGC( GetXDisplay(), GetDrawable(),
+ nValueMask,
+ &values );
+ }
+
+ if( !bInvert50GC_ )
+ {
+ SetClipRegion( pInvert50GC_ );
+ bInvert50GC_ = TRUE;
+ }
+ return pInvert50GC_;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+inline GC X11SalGraphics::GetStippleGC()
+{
+ if( !pStippleGC_ )
+ pStippleGC_ = CreateGC( GetDrawable(),
+ GCGraphicsExposures
+ | GCFillStyle
+ | GCLineWidth );
+
+ if( !bStippleGC_ )
+ {
+ XSetFunction( GetXDisplay(), pStippleGC_, bXORMode_ ? GXxor : GXcopy );
+ SetClipRegion( pStippleGC_ );
+ bStippleGC_ = TRUE;
+ }
+
+ return pStippleGC_;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+int X11SalGraphics::Clip( XLIB_Region pRegion,
+ int &nX,
+ int &nY,
+ unsigned int &nDX,
+ unsigned int &nDY,
+ int &nSrcX,
+ int &nSrcY ) const
+{
+ XRectangle aRect;
+ XClipBox( pRegion, &aRect );
+
+ if( int(nX + nDX) <= int(aRect.x) || nX >= int(aRect.x + aRect.width) )
+ return RectangleOut;
+ if( int(nY + nDY) <= int(aRect.y) || nY >= int(aRect.y + aRect.height) )
+ return RectangleOut;
+
+ if( nX < aRect.x )
+ {
+ nSrcX += aRect.x - nX;
+ nDX -= aRect.x - nX;
+ nX = aRect.x;
+ }
+ else if( int(nX + nDX) > int(aRect.x + aRect.width) )
+ nDX = aRect.x + aRect.width - nX;
+
+ if( nY < aRect.y )
+ {
+ nSrcY += aRect.y - nY;
+ nDY -= aRect.y - nY;
+ nY = aRect.y;
+ }
+ else if( int(nY + nDY) > int(aRect.y + aRect.height) )
+ nDY = aRect.y + aRect.height - nY;
+
+ return RectangleIn;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+int X11SalGraphics::Clip( int &nX,
+ int &nY,
+ unsigned int &nDX,
+ unsigned int &nDY,
+ int &nSrcX,
+ int &nSrcY ) const
+
+{
+ if( pPaintRegion_
+ && RectangleOut == Clip( pPaintRegion_, nX, nY, nDX, nDY, nSrcX, nSrcY ) )
+ return RectangleOut;
+
+ if( pClipRegion_
+ && RectangleOut == Clip( pClipRegion_, nX, nY, nDX, nDY, nSrcX, nSrcY ) )
+ return RectangleOut;
+
+ int nPaint;
+ if( pPaintRegion_ )
+ {
+ nPaint = XRectInRegion( pPaintRegion_, nX, nY, nDX, nDY );
+ if( RectangleOut == nPaint )
+ return RectangleOut;
+ }
+ else
+ nPaint = RectangleIn;
+
+ int nClip;
+ if( pClipRegion_ )
+ {
+ nClip = XRectInRegion( pClipRegion_, nX, nY, nDX, nDY );
+ if( RectangleOut == nClip )
+ return RectangleOut;
+ }
+ else
+ nClip = RectangleIn;
+
+ return RectangleIn == nClip && RectangleIn == nPaint
+ ? RectangleIn
+ : RectanglePart;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+GC X11SalGraphics::SetMask( int &nX,
+ int &nY,
+ unsigned int &nDX,
+ unsigned int &nDY,
+ int &nSrcX,
+ int &nSrcY,
+ Pixmap hClipMask )
+{
+ int n = Clip( nX, nY, nDX, nDY, nSrcX, nSrcY );
+ if( RectangleOut == n )
+ return NULL;
+
+ Display *pDisplay = GetXDisplay();
+
+ if( !pMaskGC_ )
+ pMaskGC_ = CreateGC( GetDrawable() );
+
+ if( RectangleIn == n )
+ {
+ XSetClipMask( pDisplay, pMaskGC_, hClipMask );
+ XSetClipOrigin( pDisplay, pMaskGC_, nX - nSrcX, nY - nSrcY );
+ return pMaskGC_;
+ }
+
+ // - - - - create alternate clip pixmap for region clipping - - - -
+ Pixmap hPixmap = XCreatePixmap( pDisplay, hClipMask, nDX, nDY, 1 );
+
+ if( !hPixmap )
+ {
+#if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
+ fprintf( stderr, "X11SalGraphics::SetMask !hPixmap\n" );
+#endif
+ return NULL;
+ }
+
+ // - - - - reset pixmap; all 0 - - - - - - - - - - - - - - - - - - -
+ XFillRectangle( pDisplay,
+ hPixmap,
+ GetDisplay()->GetMonoGC( m_nScreen ),
+ 0, 0,
+ nDX, nDY );
+
+ // - - - - copy pixmap only within region - - - - - - - - - - - - -
+ GC pMonoGC = GetMonoGC( hPixmap );
+ XSetClipOrigin( pDisplay, pMonoGC, -nX, -nY );
+ XCopyArea( pDisplay,
+ hClipMask, // Source
+ hPixmap, // Destination
+ pMonoGC,
+ nSrcX, nSrcY, // Source
+ nDX, nDY, // Width & Height
+ 0, 0 ); // Destination
+
+ XSetClipMask( pDisplay, pMaskGC_, hPixmap );
+ XSetClipOrigin( pDisplay, pMaskGC_, nX, nY );
+
+ XFreePixmap( pDisplay, hPixmap );
+ return pMaskGC_;
+}
+
+// -=-= SalGraphics =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+extern "C"
+{
+ static Bool GraphicsExposePredicate( Display*, XEvent* pEvent, XPointer pFrameWindow )
+ {
+ Bool bRet = False;
+ if( (pEvent->type == GraphicsExpose || pEvent->type == NoExpose) &&
+ pEvent->xnoexpose.drawable == (Drawable)pFrameWindow )
+ {
+ bRet = True;
+ }
+ return bRet;
+ }
+}
+
+
+void X11SalGraphics::YieldGraphicsExpose()
+{
+ // get frame if necessary
+ SalFrame* pFrame = m_pFrame;
+ Display* pDisplay = GetXDisplay();
+ XLIB_Window aWindow = GetDrawable();
+ if( ! pFrame )
+ {
+ const std::list< SalFrame* >& rFrames = GetX11SalData()->GetDisplay()->getFrames();
+ for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end() && ! pFrame; ++it )
+ {
+ const SystemEnvData* pEnvData = (*it)->GetSystemData();
+ if( Drawable(pEnvData->aWindow) == aWindow )
+ pFrame = *it;
+ }
+ if( ! pFrame )
+ return;
+ }
+
+ XEvent aEvent;
+ while( XCheckTypedWindowEvent( pDisplay, aWindow, Expose, &aEvent ) )
+ {
+ SalPaintEvent aPEvt( aEvent.xexpose.x, aEvent.xexpose.y, aEvent.xexpose.width+1, aEvent.xexpose.height+1 );
+ pFrame->CallCallback( SALEVENT_PAINT, &aPEvt );
+ }
+
+ do
+ {
+ if( ! GetDisplay()->XIfEventWithTimeout( &aEvent, (XPointer)aWindow, GraphicsExposePredicate ) )
+ // this should not happen at all; still sometimes it happens
+ break;
+
+ if( aEvent.type == NoExpose )
+ break;
+
+ if( pFrame )
+ {
+ SalPaintEvent aPEvt( aEvent.xgraphicsexpose.x, aEvent.xgraphicsexpose.y, aEvent.xgraphicsexpose.width+1, aEvent.xgraphicsexpose.height+1 );
+ pFrame->CallCallback( SALEVENT_PAINT, &aPEvt );
+ }
+ } while( aEvent.xgraphicsexpose.count != 0 );
+}
+
+void X11SalGraphics::copyBits( const SalTwoRect *pPosAry,
+ SalGraphics *pSSrcGraphics )
+{
+ X11SalGraphics* pSrcGraphics = pSSrcGraphics
+ ? static_cast<X11SalGraphics*>(pSSrcGraphics)
+ : this;
+
+ if( pPosAry->mnSrcWidth <= 0
+ || pPosAry->mnSrcHeight <= 0
+ || pPosAry->mnDestWidth <= 0
+ || pPosAry->mnDestHeight <= 0 )
+ {
+ return;
+ }
+
+ int n;
+ if( pSrcGraphics == this )
+ {
+ n = 2;
+ }
+ else if( pSrcGraphics->bWindow_ )
+ {
+ // window or compatible virtual device
+ if( pSrcGraphics->GetDisplay() == GetDisplay() &&
+ pSrcGraphics->m_nScreen == m_nScreen &&
+ pSrcGraphics->GetVisual().GetDepth() == GetVisual().GetDepth()
+ )
+ n = 2; // same Display
+ else
+ n = 1; // printer or other display
+ }
+ else if( pSrcGraphics->bVirDev_ )
+ {
+ // printer compatible virtual device
+ if( bPrinter_ )
+ n = 2; // printer or compatible virtual device == same display
+ else
+ n = 1; // window or compatible virtual device
+ }
+ else
+ n = 0;
+
+ if( n == 2
+ && pPosAry->mnSrcWidth == pPosAry->mnDestWidth
+ && pPosAry->mnSrcHeight == pPosAry->mnDestHeight
+ )
+ {
+ // #i60699# Need to generate graphics exposures (to repaint
+ // obscured areas beneath overlapping windows), src and dest
+ // are the same window.
+ const bool bNeedGraphicsExposures( pSrcGraphics == this &&
+ !bVirDev_ &&
+ pSrcGraphics->bWindow_ );
+
+ GC pCopyGC;
+
+ if( bXORMode_
+ && !pSrcGraphics->bVirDev_
+ && (GetDisplay()->GetProperties() & PROPERTY_BUG_XCopyArea_GXxor) )
+ {
+ Pixmap hPixmap = XCreatePixmap( GetXDisplay(),
+ pSrcGraphics->GetDrawable(), // source
+ pPosAry->mnSrcWidth, pPosAry->mnSrcHeight,
+ pSrcGraphics->GetBitCount() );
+
+ pCopyGC = GetDisplay()->GetCopyGC( m_nScreen );
+
+ if( bNeedGraphicsExposures )
+ XSetGraphicsExposures( GetXDisplay(),
+ pCopyGC,
+ True );
+
+ XCopyArea( GetXDisplay(),
+ pSrcGraphics->GetDrawable(), // source
+ hPixmap, // destination
+ pCopyGC, // no clipping
+ pPosAry->mnSrcX, pPosAry->mnSrcY,
+ pPosAry->mnSrcWidth, pPosAry->mnSrcHeight,
+ 0, 0 ); // destination
+ XCopyArea( GetXDisplay(),
+ hPixmap, // source
+ GetDrawable(), // destination
+ GetInvertGC(), // destination clipping
+ 0, 0, // source
+ pPosAry->mnSrcWidth, pPosAry->mnSrcHeight,
+ pPosAry->mnDestX, pPosAry->mnDestY );
+ XFreePixmap( GetXDisplay(), hPixmap );
+ }
+ else
+ {
+ pCopyGC = GetCopyGC();
+
+ if( bNeedGraphicsExposures )
+ XSetGraphicsExposures( GetXDisplay(),
+ pCopyGC,
+ True );
+
+ XCopyArea( GetXDisplay(),
+ pSrcGraphics->GetDrawable(), // source
+ GetDrawable(), // destination
+ pCopyGC, // destination clipping
+ pPosAry->mnSrcX, pPosAry->mnSrcY,
+ pPosAry->mnSrcWidth, pPosAry->mnSrcHeight,
+ pPosAry->mnDestX, pPosAry->mnDestY );
+ }
+
+ if( bNeedGraphicsExposures )
+ {
+ YieldGraphicsExpose();
+
+ if( pCopyGC )
+ XSetGraphicsExposures( GetXDisplay(),
+ pCopyGC,
+ False );
+ }
+ }
+ else if( n )
+ {
+ // #i60699# No chance to handle graphics exposures - we copy
+ // to a temp bitmap first, into which no repaints are
+ // technically possible.
+ SalBitmap *pDDB = pSrcGraphics->getBitmap( pPosAry->mnSrcX,
+ pPosAry->mnSrcY,
+ pPosAry->mnSrcWidth,
+ pPosAry->mnSrcHeight );
+
+ if( !pDDB )
+ {
+ stderr0( "SalGraphics::CopyBits !pSrcGraphics->GetBitmap()\n" );
+ return;
+ }
+
+ SalTwoRect aPosAry( *pPosAry );
+
+ aPosAry.mnSrcX = 0, aPosAry.mnSrcY = 0;
+ drawBitmap( &aPosAry, *pDDB );
+
+ delete pDDB;
+ }
+ else {
+ stderr0( "X11SalGraphics::CopyBits from Printer not yet implemented\n" );
+ }
+}
+
+// --------------------------------------------------------------------------
+
+void X11SalGraphics::copyArea ( long nDestX, long nDestY,
+ long nSrcX, long nSrcY,
+ long nSrcWidth, long nSrcHeight,
+ USHORT )
+{
+ SalTwoRect aPosAry;
+
+ aPosAry.mnDestX = nDestX;
+ aPosAry.mnDestY = nDestY;
+ aPosAry.mnDestWidth = nSrcWidth;
+ aPosAry.mnDestHeight = nSrcHeight;
+
+ aPosAry.mnSrcX = nSrcX;
+ aPosAry.mnSrcY = nSrcY;
+ aPosAry.mnSrcWidth = nSrcWidth;
+ aPosAry.mnSrcHeight = nSrcHeight;
+
+ copyBits ( &aPosAry, 0 );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap )
+{
+ const SalDisplay* pSalDisp = GetDisplay();
+ Display* pXDisp = pSalDisp->GetDisplay();
+ const Drawable aDrawable( GetDrawable() );
+ const SalColormap& rColMap = pSalDisp->GetColormap( m_nScreen );
+ const long nDepth = GetDisplay()->GetVisual( m_nScreen ).GetDepth();
+ GC aGC( GetCopyGC() );
+ XGCValues aOldVal, aNewVal;
+ int nValues = GCForeground | GCBackground;
+
+ if( rSalBitmap.GetBitCount() == 1 )
+ {
+ // set foreground/background values for 1Bit bitmaps
+ XGetGCValues( pXDisp, aGC, nValues, &aOldVal );
+ aNewVal.foreground = rColMap.GetWhitePixel(), aNewVal.background = rColMap.GetBlackPixel();
+ XChangeGC( pXDisp, aGC, nValues, &aNewVal );
+ }
+
+ static_cast<const X11SalBitmap&>(rSalBitmap).ImplDraw( aDrawable, m_nScreen, nDepth, *pPosAry, aGC );
+
+ if( rSalBitmap.GetBitCount() == 1 )
+ XChangeGC( pXDisp, aGC, nValues, &aOldVal );
+ XFlush( pXDisp );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalGraphics::drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSrcBitmap,
+ const SalBitmap& rMaskBitmap )
+{
+ DBG_ASSERT( !bPrinter_, "Drawing of transparent bitmaps on printer devices is strictly forbidden" );
+
+ // decide if alpha masking or transparency masking is needed
+ BitmapBuffer* pAlphaBuffer = const_cast<SalBitmap&>(rMaskBitmap).AcquireBuffer( TRUE );
+ if( pAlphaBuffer != NULL )
+ {
+ int nMaskFormat = pAlphaBuffer->mnFormat;
+ const_cast<SalBitmap&>(rMaskBitmap).ReleaseBuffer( pAlphaBuffer, TRUE );
+ if( nMaskFormat == BMP_FORMAT_8BIT_PAL )
+ drawAlphaBitmap( *pPosAry, rSrcBitmap, rMaskBitmap );
+ }
+
+ drawMaskedBitmap( pPosAry, rSrcBitmap, rMaskBitmap );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalGraphics::drawMaskedBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ const SalBitmap& rTransBitmap )
+{
+ const SalDisplay* pSalDisp = GetDisplay();
+ Display* pXDisp = pSalDisp->GetDisplay();
+ Drawable aDrawable( GetDrawable() );
+
+ // figure work mode depth. If this is a VDev Drawable, use its
+ // bitdepth to create pixmaps for, otherwise, XCopyArea will
+ // refuse to work.
+ const USHORT nDepth( m_pVDev ?
+ m_pVDev->GetDepth() :
+ pSalDisp->GetVisual( m_nScreen ).GetDepth() );
+ Pixmap aFG( XCreatePixmap( pXDisp, aDrawable, pPosAry->mnDestWidth,
+ pPosAry->mnDestHeight, nDepth ) );
+ Pixmap aBG( XCreatePixmap( pXDisp, aDrawable, pPosAry->mnDestWidth,
+ pPosAry->mnDestHeight, nDepth ) );
+
+ if( aFG && aBG )
+ {
+ GC aTmpGC;
+ XGCValues aValues;
+ const SalColormap& rColMap = pSalDisp->GetColormap( m_nScreen );
+ const int nBlack = rColMap.GetBlackPixel(), nWhite = rColMap.GetWhitePixel();
+ const int nValues = GCFunction | GCForeground | GCBackground;
+ SalTwoRect aTmpRect( *pPosAry ); aTmpRect.mnDestX = aTmpRect.mnDestY = 0;
+
+ // draw paint bitmap in pixmap #1
+ aValues.function = GXcopy, aValues.foreground = nWhite, aValues.background = nBlack;
+ aTmpGC = XCreateGC( pXDisp, aFG, nValues, &aValues );
+ static_cast<const X11SalBitmap&>(rSalBitmap).ImplDraw( aFG, m_nScreen, nDepth, aTmpRect, aTmpGC );
+ DBG_TESTTRANS( aFG );
+
+ // draw background in pixmap #2
+ XCopyArea( pXDisp, aDrawable, aBG, aTmpGC,
+ pPosAry->mnDestX, pPosAry->mnDestY,
+ pPosAry->mnDestWidth, pPosAry->mnDestHeight,
+ 0, 0 );
+
+ DBG_TESTTRANS( aBG );
+
+ // mask out paint bitmap in pixmap #1 (transparent areas 0)
+ aValues.function = GXand, aValues.foreground = 0x00000000, aValues.background = 0xffffffff;
+ XChangeGC( pXDisp, aTmpGC, nValues, &aValues );
+ static_cast<const X11SalBitmap&>(rTransBitmap).ImplDraw( aFG, m_nScreen, 1, aTmpRect, aTmpGC );
+
+ DBG_TESTTRANS( aFG );
+
+ // #105055# For XOR mode, keep background behind bitmap intact
+ if( !bXORMode_ )
+ {
+ // mask out background in pixmap #2 (nontransparent areas 0)
+ aValues.function = GXand, aValues.foreground = 0xffffffff, aValues.background = 0x00000000;
+ XChangeGC( pXDisp, aTmpGC, nValues, &aValues );
+ static_cast<const X11SalBitmap&>(rTransBitmap).ImplDraw( aBG, m_nScreen, 1, aTmpRect, aTmpGC );
+
+ DBG_TESTTRANS( aBG );
+ }
+
+ // merge pixmap #1 and pixmap #2 in pixmap #2
+ aValues.function = GXxor, aValues.foreground = 0xffffffff, aValues.background = 0x00000000;
+ XChangeGC( pXDisp, aTmpGC, nValues, &aValues );
+ XCopyArea( pXDisp, aFG, aBG, aTmpGC,
+ 0, 0,
+ pPosAry->mnDestWidth, pPosAry->mnDestHeight,
+ 0, 0 );
+ DBG_TESTTRANS( aBG );
+
+ // #105055# Disable XOR temporarily
+ BOOL bOldXORMode( bXORMode_ );
+ bXORMode_ = FALSE;
+
+ // copy pixmap #2 (result) to background
+ XCopyArea( pXDisp, aBG, aDrawable, GetCopyGC(),
+ 0, 0,
+ pPosAry->mnDestWidth, pPosAry->mnDestHeight,
+ pPosAry->mnDestX, pPosAry->mnDestY );
+
+ DBG_TESTTRANS( aBG );
+
+ bXORMode_ = bOldXORMode;
+
+ XFreeGC( pXDisp, aTmpGC );
+ XFlush( pXDisp );
+ }
+ else
+ drawBitmap( pPosAry, rSalBitmap );
+
+ if( aFG )
+ XFreePixmap( pXDisp, aFG );
+
+ if( aBG )
+ XFreePixmap( pXDisp, aBG );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+bool X11SalGraphics::drawAlphaBitmap( const SalTwoRect& rTR,
+ const SalBitmap& rSrcBitmap, const SalBitmap& rAlphaBmp )
+{
+ // non 8-bit alpha not implemented yet
+ if( rAlphaBmp.GetBitCount() != 8 )
+ return false;
+
+ // horizontal mirroring not implemented yet
+ if( rTR.mnDestWidth < 0 )
+ return false;
+
+ // stretched conversion is not implemented yet
+ if( rTR.mnDestWidth != rTR.mnSrcWidth )
+ return false;
+ if( rTR.mnDestHeight!= rTR.mnSrcHeight )
+ return false;
+
+ XRenderPeer& rPeer = XRenderPeer::GetInstance();
+ if( rPeer.GetVersion() < 0x02 )
+ return false;
+
+ // create destination picture
+ Picture aDstPic = GetXRenderPicture();
+ if( !aDstPic )
+ return false;
+
+ const SalDisplay* pSalDisp = GetDisplay();
+ const SalVisual& rSalVis = pSalDisp->GetVisual( m_nScreen );
+ Display* pXDisplay = pSalDisp->GetDisplay();
+
+ // create source Picture
+ int nDepth = m_pVDev ? m_pVDev->GetDepth() : rSalVis.GetDepth();
+ const X11SalBitmap& rSrcX11Bmp = static_cast<const X11SalBitmap&>( rSrcBitmap );
+ ImplSalDDB* pSrcDDB = rSrcX11Bmp.ImplGetDDB( hDrawable_, m_nScreen, nDepth, rTR );
+ if( !pSrcDDB )
+ return false;
+
+ //#i75249# workaround for ImplGetDDB() giving us back a different depth than
+ // we requested. E.g. mask pixmaps are always compatible with the drawable
+ // TODO: find an appropriate picture format for these cases
+ // then remove the workaround below and the one for #i75531#
+ if( nDepth != pSrcDDB->ImplGetDepth() )
+ return false;
+
+ Pixmap aSrcPM = pSrcDDB->ImplGetPixmap();
+ if( !aSrcPM )
+ return false;
+
+ // create source picture
+ // TODO: use scoped picture
+ Visual* pSrcXVisual = rSalVis.GetVisual();
+ XRenderPictFormat* pSrcVisFmt = rPeer.FindVisualFormat( pSrcXVisual );
+ if( !pSrcVisFmt )
+ return false;
+ Picture aSrcPic = rPeer.CreatePicture( aSrcPM, pSrcVisFmt, 0, NULL );
+ if( !aSrcPic )
+ return false;
+
+ // create alpha Picture
+
+ // TODO: use SalX11Bitmap functionality and caching for the Alpha Pixmap
+ // problem is that they don't provide an 8bit Pixmap on a non-8bit display
+ BitmapBuffer* pAlphaBuffer = const_cast<SalBitmap&>(rAlphaBmp).AcquireBuffer( TRUE );
+
+ // an XImage needs its data top_down
+ // TODO: avoid wrongly oriented images in upper layers!
+ const int nImageSize = pAlphaBuffer->mnHeight * pAlphaBuffer->mnScanlineSize;
+ const char* pSrcBits = (char*)pAlphaBuffer->mpBits;
+ char* pAlphaBits = new char[ nImageSize ];
+ if( BMP_SCANLINE_ADJUSTMENT( pAlphaBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN )
+ memcpy( pAlphaBits, pSrcBits, nImageSize );
+ else
+ {
+ char* pDstBits = pAlphaBits + nImageSize;
+ const int nLineSize = pAlphaBuffer->mnScanlineSize;
+ for(; (pDstBits -= nLineSize) >= pAlphaBits; pSrcBits += nLineSize )
+ memcpy( pDstBits, pSrcBits, nLineSize );
+ }
+
+ // the alpha values need to be inverted for XRender
+ // TODO: make upper layers use standard alpha
+ long* pLDst = (long*)pAlphaBits;
+ for( int i = nImageSize/sizeof(long); --i >= 0; ++pLDst )
+ *pLDst = ~*pLDst;
+
+ char* pCDst = (char*)pLDst;
+ for( int i = nImageSize & (sizeof(long)-1); --i >= 0; ++pCDst )
+ *pCDst = ~*pCDst;
+
+ const XRenderPictFormat* pAlphaFormat = rPeer.GetStandardFormatA8();
+ XImage* pAlphaImg = XCreateImage( pXDisplay, pSrcXVisual, 8, ZPixmap, 0,
+ pAlphaBits, pAlphaBuffer->mnWidth, pAlphaBuffer->mnHeight,
+ pAlphaFormat->depth, pAlphaBuffer->mnScanlineSize );
+
+ Pixmap aAlphaPM = XCreatePixmap( pXDisplay, hDrawable_,
+ rTR.mnDestWidth, rTR.mnDestHeight, 8 );
+
+ XGCValues aAlphaGCV;
+ aAlphaGCV.function = GXcopy;
+ GC aAlphaGC = XCreateGC( pXDisplay, aAlphaPM, GCFunction, &aAlphaGCV );
+ XPutImage( pXDisplay, aAlphaPM, aAlphaGC, pAlphaImg,
+ rTR.mnSrcX, rTR.mnSrcY, 0, 0, rTR.mnDestWidth, rTR.mnDestHeight );
+ XFreeGC( pXDisplay, aAlphaGC );
+ XFree( pAlphaImg );
+ if( pAlphaBits != (char*)pAlphaBuffer->mpBits )
+ delete[] pAlphaBits;
+
+ const_cast<SalBitmap&>(rAlphaBmp).ReleaseBuffer( pAlphaBuffer, TRUE );
+
+ XRenderPictureAttributes aAttr;
+ aAttr.repeat = true;
+ Picture aAlphaPic = rPeer.CreatePicture( aAlphaPM, pAlphaFormat, CPRepeat, &aAttr );
+ if( !aAlphaPic )
+ return false;
+
+ // set clipping
+ if( pClipRegion_ && !XEmptyRegion( pClipRegion_ ) )
+ rPeer.SetPictureClipRegion( aDstPic, pClipRegion_ );
+
+ // paint source * mask over destination picture
+ rPeer.CompositePicture( PictOpOver, aSrcPic, aAlphaPic, aDstPic,
+ rTR.mnSrcX, rTR.mnSrcY, 0, 0,
+ rTR.mnDestX, rTR.mnDestY, rTR.mnDestWidth, rTR.mnDestHeight );
+
+ // TODO: used ScopedPic
+ rPeer.FreePicture( aAlphaPic );
+ XFreePixmap(pXDisplay, aAlphaPM);
+ rPeer.FreePicture( aSrcPic );
+ return true;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+bool X11SalGraphics::drawAlphaRect( long nX, long nY, long nWidth,
+ long nHeight, sal_uInt8 nTransparency )
+{
+ if( ! m_pFrame && ! m_pVDev )
+ return false;
+
+ if( bPenGC_ || !bBrushGC_ || bXORMode_ )
+ return false; // can only perform solid fills without XOR.
+
+ if( m_pVDev && m_pVDev->GetDepth() < 8 )
+ return false;
+
+ XRenderPeer& rPeer = XRenderPeer::GetInstance();
+ if( rPeer.GetVersion() < 0x02 ) // TODO: replace with better test
+ return false;
+
+ Picture aDstPic = GetXRenderPicture();
+ if( !aDstPic )
+ return false;
+
+ const double fTransparency = (100 - nTransparency) * (1.0/100);
+ const XRenderColor aRenderColor = GetXRenderColor( nBrushColor_ , fTransparency);
+
+ rPeer.FillRectangle( PictOpOver,
+ aDstPic,
+ &aRenderColor,
+ nX, nY,
+ nWidth, nHeight );
+
+ return true;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::drawBitmap( const SalTwoRect*,
+ const SalBitmap&,
+ SalColor )
+{
+ DBG_ERROR( "::DrawBitmap with transparent color not supported" );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::drawMask( const SalTwoRect* pPosAry,
+ const SalBitmap &rSalBitmap,
+ SalColor nMaskColor )
+{
+ const SalDisplay* pSalDisp = GetDisplay();
+ Display* pXDisp = pSalDisp->GetDisplay();
+ Drawable aDrawable( GetDrawable() );
+ Pixmap aStipple( XCreatePixmap( pXDisp, aDrawable,
+ pPosAry->mnDestWidth,
+ pPosAry->mnDestHeight, 1 ) );
+
+ if( aStipple )
+ {
+ SalTwoRect aTwoRect( *pPosAry ); aTwoRect.mnDestX = aTwoRect.mnDestY = 0;
+ GC aTmpGC;
+ XGCValues aValues;
+
+ // create a stipple bitmap first (set bits are changed to unset bits and vice versa)
+ aValues.function = GXcopyInverted;
+ aValues.foreground = 1, aValues.background = 0;
+ aTmpGC = XCreateGC( pXDisp, aStipple, GCFunction | GCForeground | GCBackground, &aValues );
+ static_cast<const X11SalBitmap&>(rSalBitmap).ImplDraw( aStipple, m_nScreen, 1, aTwoRect, aTmpGC );
+
+ XFreeGC( pXDisp, aTmpGC );
+
+ // Set stipple and draw rectangle
+ GC aStippleGC( GetStippleGC() );
+ int nX = pPosAry->mnDestX, nY = pPosAry->mnDestY;
+
+ XSetStipple( pXDisp, aStippleGC, aStipple );
+ XSetTSOrigin( pXDisp, aStippleGC, nX, nY );
+ XSetForeground( pXDisp, aStippleGC, GetPixel( nMaskColor ) );
+ XFillRectangle( pXDisp, aDrawable, aStippleGC,
+ nX, nY,
+ pPosAry->mnDestWidth, pPosAry->mnDestHeight );
+ XFreePixmap( pXDisp, aStipple );
+ XFlush( pXDisp );
+ }
+ else
+ drawBitmap( pPosAry, rSalBitmap );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+SalBitmap *X11SalGraphics::getBitmap( long nX, long nY, long nDX, long nDY )
+{
+ if( bPrinter_ && !bVirDev_ )
+ return NULL;
+
+ bool bFakeWindowBG = false;
+
+ // normalize
+ if( nDX < 0 )
+ {
+ nX += nDX;
+ nDX = -nDX;
+ }
+ if ( nDY < 0 )
+ {
+ nY += nDY;
+ nDY = -nDY;
+ }
+
+ if( bWindow_ && !bVirDev_ )
+ {
+ XWindowAttributes aAttrib;
+
+ XGetWindowAttributes( GetXDisplay(), GetDrawable(), &aAttrib );
+ if( aAttrib.map_state != IsViewable )
+ bFakeWindowBG = true;
+ else
+ {
+ long nOrgDX = nDX, nOrgDY = nDY;
+
+ // clip to window size
+ if ( nX < 0 )
+ {
+ nDX += nX;
+ nX = 0;
+ }
+ if ( nY < 0 )
+ {
+ nDY += nY;
+ nY = 0;
+ }
+ if( nX + nDX > aAttrib.width )
+ nDX = aAttrib.width - nX;
+ if( nY + nDY > aAttrib.height )
+ nDY = aAttrib.height - nY;
+
+ // inside ?
+ if( nDX <= 0 || nDY <= 0 )
+ {
+ bFakeWindowBG = true;
+ nDX = nOrgDX;
+ nDY = nOrgDY;
+ }
+ }
+ }
+
+ X11SalBitmap* pSalBitmap = new X11SalBitmap;
+ USHORT nBitCount = GetBitCount();
+
+ if( &GetDisplay()->GetColormap( m_nScreen ) != &GetColormap() )
+ nBitCount = 1;
+
+ if( ! bFakeWindowBG )
+ pSalBitmap->ImplCreateFromDrawable( GetDrawable(), m_nScreen, nBitCount, nX, nY, nDX, nDY );
+ else
+ pSalBitmap->Create( Size( nDX, nDY ), (nBitCount > 8) ? 24 : nBitCount, BitmapPalette( nBitCount > 8 ? nBitCount : 0 ) );
+
+ return pSalBitmap;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+SalColor X11SalGraphics::getPixel( long nX, long nY )
+{
+ if( bWindow_ && !bVirDev_ )
+ {
+ XWindowAttributes aAttrib;
+
+ XGetWindowAttributes( GetXDisplay(), GetDrawable(), &aAttrib );
+ if( aAttrib.map_state != IsViewable )
+ {
+ stderr0( "X11SalGraphics::GetPixel drawable not viewable\n" );
+ return 0;
+ }
+ }
+
+ XImage *pXImage = XGetImage( GetXDisplay(),
+ GetDrawable(),
+ nX, nY,
+ 1, 1,
+ AllPlanes,
+ ZPixmap );
+ if( !pXImage )
+ {
+ stderr0( "X11SalGraphics::GetPixel !XGetImage()\n" );
+ return 0;
+ }
+
+ XColor aXColor;
+
+ aXColor.pixel = XGetPixel( pXImage, 0, 0 );
+ XDestroyImage( pXImage );
+
+ return GetColormap().GetColor( aXColor.pixel );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::invert( long nX,
+ long nY,
+ long nDX,
+ long nDY,
+ SalInvert nFlags )
+{
+ GC pGC;
+ if( SAL_INVERT_50 & nFlags )
+ {
+ pGC = GetInvert50GC();
+ XFillRectangle( GetXDisplay(), GetDrawable(), pGC, nX, nY, nDX, nDY );
+ }
+ else
+ {
+ if ( SAL_INVERT_TRACKFRAME & nFlags )
+ {
+ pGC = GetTrackingGC();
+ XDrawRectangle( GetXDisplay(), GetDrawable(), pGC, nX, nY, nDX, nDY );
+ }
+ else
+ {
+ pGC = GetInvertGC();
+ XFillRectangle( GetXDisplay(), GetDrawable(), pGC, nX, nY, nDX, nDY );
+ }
+ }
+}
+
+bool X11SalGraphics::supportsOperation( OutDevSupportType eType ) const
+{
+ bool bRet = false;
+ switch( eType )
+ {
+ case OutDevSupport_TransparentRect:
+ case OutDevSupport_B2DDraw:
+ {
+ XRenderPeer& rPeer = XRenderPeer::GetInstance();
+ if( rPeer.GetVersion() >= 0x02 )
+ {
+ const SalDisplay* pSalDisp = GetDisplay();
+ const SalVisual& rSalVis = pSalDisp->GetVisual( m_nScreen );
+
+ Visual* pDstXVisual = rSalVis.GetVisual();
+ XRenderPictFormat* pDstVisFmt = rPeer.FindVisualFormat( pDstXVisual );
+ if( pDstVisFmt )
+ bRet = true;
+ }
+ }
+ break;
+ default: break;
+ }
+ return bRet;
+}
+
diff --git a/vcl/unx/source/gdi/salgdi3.cxx b/vcl/unx/source/gdi/salgdi3.cxx
new file mode 100644
index 000000000000..6024b66f6010
--- /dev/null
+++ b/vcl/unx/source/gdi/salgdi3.cxx
@@ -0,0 +1,2264 @@
+/*************************************************************************
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "gcach_xpeer.hxx"
+#include "xrender_peer.hxx"
+#include "salunx.h"
+#include "saldata.hxx"
+#include "saldisp.hxx"
+#include "salgdi.h"
+#include "pspgraphics.h"
+#include "salvd.h"
+#include "xfont.hxx"
+#include <vcl/sysdata.hxx>
+#include "xlfd_attr.hxx"
+#include "xlfd_smpl.hxx"
+#include "xlfd_extd.hxx"
+#include "salcvt.hxx"
+
+#include "vcl/printergfx.hxx"
+#include "vcl/fontmanager.hxx"
+#include "vcl/jobdata.hxx"
+#include "vcl/printerinfomanager.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/impfont.hxx"
+#include "vcl/salframe.hxx"
+#include "vcl/outdev.h"
+
+#include "sal/alloca.h"
+#include "sal/types.h"
+
+#include "rtl/tencinfo.h"
+
+#include "osl/file.hxx"
+
+#include "tools/string.hxx"
+#include "tools/debug.hxx"
+#include "tools/stream.hxx"
+
+#include "basegfx/polygon/b2dpolypolygon.hxx"
+
+#include "i18npool/mslangid.hxx"
+
+#include <hash_set>
+
+#ifdef ENABLE_GRAPHITE
+#include <vcl/graphite_layout.hxx>
+#include <vcl/graphite_serverfont.hxx>
+#endif
+
+struct cairo_surface_t;
+struct cairo_t;
+struct cairo_font_face_t;
+typedef void* FT_Face;
+struct cairo_matrix_t {
+ double xx; double yx;
+ double xy; double yy;
+ double x0; double y0;
+};
+struct cairo_glyph_t
+{
+ unsigned long index;
+ double x;
+ double y;
+};
+struct BOX
+{
+ short x1, x2, y1, y2;
+};
+struct _XRegion
+{
+ long size;
+ long numRects;
+ BOX *rects;
+ BOX extents;
+};
+using namespace rtl;
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+// ----------------------------------------------------------------------------
+//
+// manage X11 fonts and self rastered fonts
+//
+// ----------------------------------------------------------------------------
+
+#ifndef _USE_PRINT_EXTENSION_
+
+class FontLookup
+{
+ public:
+
+ struct hash;
+ struct equal;
+ typedef ::std::hash_set< FontLookup,
+ FontLookup::hash,
+ FontLookup::equal > fl_hashset;
+
+ private:
+
+ rtl::OString maName;
+ FontWeight mnWeight;
+ FontItalic mnItalic;
+ sal_Bool mbDisplay;
+
+ public:
+
+ FontLookup ( ::std::list< psp::fontID >::iterator& it,
+ const psp::PrintFontManager& rMgr );
+ FontLookup (const Xlfd& rFont);
+ FontLookup (const FontLookup &rRef) :
+ maName (rRef.maName),
+ mnWeight (rRef.mnWeight),
+ mnItalic (rRef.mnItalic),
+ mbDisplay(rRef.mbDisplay)
+ {}
+ ~FontLookup ()
+ {}
+
+ static void BuildSet (fl_hashset& rSet);
+ static bool InSet (const fl_hashset& rSet, const Xlfd& rXfld);
+ bool InSet (const fl_hashset& rSet) const;
+
+ bool operator== (const FontLookup &rRef) const
+ {
+ return (abs(mnWeight - rRef.mnWeight) < 2)
+ && (mnItalic == rRef.mnItalic)
+ && (maName == rRef.maName)
+ && (mbDisplay== rRef.mbDisplay);
+ }
+ FontLookup& operator= (const FontLookup &rRef)
+ {
+ mnWeight = rRef.mnWeight;
+ mnItalic = rRef.mnItalic;
+ maName = rRef.maName;
+ mbDisplay= rRef.mbDisplay;
+
+ return *this;
+ }
+ size_t Hash() const
+ {
+ return maName.hashCode ();
+ }
+
+ struct equal
+ {
+ bool operator()(const FontLookup &r1, const FontLookup &r2) const
+ {
+ return r1 == r2;
+ }
+ };
+ struct hash
+ {
+ size_t operator()(const FontLookup &rArg) const
+ {
+ return rArg.Hash();
+ }
+ };
+};
+
+FontLookup::FontLookup ( ::std::list< psp::fontID >::iterator& it,
+ const psp::PrintFontManager& rMgr )
+{
+ psp::FastPrintFontInfo aInfo;
+ if (rMgr.getFontFastInfo (*it, aInfo))
+ {
+ mnItalic = PspGraphics::ToFontItalic (aInfo.m_eItalic);
+ mnWeight = PspGraphics::ToFontWeight (aInfo.m_eWeight);
+ mbDisplay= aInfo.m_eType == psp::fonttype::Builtin
+ || aInfo.m_eType == psp::fonttype::Unknown ? False : True;
+ maName = rtl::OUStringToOString
+ ( aInfo.m_aFamilyName,
+ RTL_TEXTENCODING_ISO_8859_1).toAsciiLowerCase();
+
+ sal_Int32 n_length = maName.getLength();
+ const sal_Char* p_from = maName.getStr();
+ sal_Char* p_to = (sal_Char*)alloca (n_length + 1);
+
+ sal_Int32 i, j;
+ for (i = 0, j = 0; i < n_length; i++)
+ {
+ if ( p_from[i] != ' ' )
+ p_to[j++] = p_from[i];
+ }
+ maName = rtl::OString (p_to, j);
+ if (mnItalic == ITALIC_OBLIQUE)
+ mnItalic = ITALIC_NORMAL;
+ }
+ else
+ {
+ mnItalic = ITALIC_DONTKNOW;
+ mnWeight = WEIGHT_DONTKNOW;
+ mbDisplay= False;
+ }
+}
+
+FontLookup::FontLookup (const Xlfd& rFont)
+{
+ AttributeProvider* pFactory = rFont.mpFactory;
+ Attribute* pAttr;
+
+ pAttr = pFactory->RetrieveSlant (rFont.mnSlant);
+ mnItalic = (FontItalic)pAttr->GetValue();
+ pAttr = pFactory->RetrieveWeight (rFont.mnWeight);
+ mnWeight = (FontWeight)pAttr->GetValue();
+ pAttr = pFactory->RetrieveFamily (rFont.mnFamily);
+ maName = pAttr->GetKey();
+
+ if (mnItalic == ITALIC_OBLIQUE)
+ mnItalic = ITALIC_NORMAL;
+
+ mbDisplay = True;
+}
+
+void
+FontLookup::BuildSet (FontLookup::fl_hashset &rSet)
+{
+ ::std::list< psp::fontID > aIdList;
+
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ rMgr.getFontList( aIdList, NULL, false );
+
+ ::std::list< psp::fontID >::iterator it;
+ for (it = aIdList.begin(); it != aIdList.end(); ++it)
+ {
+ FontLookup aItem (it, rMgr);
+ rSet.insert (aItem);
+ }
+}
+
+bool
+FontLookup::InSet (const FontLookup::fl_hashset& rSet) const
+{
+ fl_hashset::const_iterator it = rSet.find(*this);
+ return it == rSet.end() ? false : true;
+}
+
+bool
+FontLookup::InSet (const FontLookup::fl_hashset& rSet, const Xlfd& rXlfd)
+{
+ FontLookup aNeedle (rXlfd);
+ return aNeedle.InSet (rSet);
+}
+
+#endif
+
+// ----------------------------------------------------------------------------
+//
+// SalDisplay
+//
+// ----------------------------------------------------------------------------
+
+XlfdStorage*
+SalDisplay::GetXlfdList() const
+{
+ if ( mpFontList != NULL )
+ {
+ return mpFontList;
+ }
+ else
+ {
+ const_cast<SalDisplay*>(this)->mpFactory = new AttributeProvider;
+ const_cast<SalDisplay*>(this)->mpFontList = new XlfdStorage;
+ const_cast<SalDisplay*>(this)->mpFallbackFactory = new VirtualXlfd;
+
+ int i, nFontCount;
+ const int nMaxCount = 64 * 1024 - 1;
+ Display *pDisplay = GetDisplay();
+ char **ppFontList = XListFonts(pDisplay, "-*", nMaxCount, &nFontCount);
+
+ //
+ // create a list of simple Xlfd font information
+ //
+
+ Xlfd *pXlfdList = (Xlfd*)malloc( nFontCount * sizeof(Xlfd) );
+ int nXlfdCount = 0;
+
+ for ( i = 0; i < nFontCount; i++ )
+ {
+ if ( pXlfdList[ nXlfdCount ].FromString(ppFontList[i], mpFactory) )
+ ++nXlfdCount;
+ }
+
+ XFreeFontNames( ppFontList );
+
+ mpFactory->AddClassification();
+ // add some pretty print description
+ mpFactory->AddAnnotation();
+ // misc feature checking
+ mpFactory->TagFeature();
+
+ // sort according to font style
+ qsort( pXlfdList, nXlfdCount, sizeof(Xlfd), XlfdCompare );
+
+#ifndef _USE_PRINT_EXTENSION_
+ // create a list of fonts already managed by the fontmanager
+ FontLookup::fl_hashset aSet;
+ FontLookup::BuildSet (aSet);
+#endif
+
+ //
+ // create a font list with merged encoding information
+ //
+
+ BitmapXlfdStorage aBitmapList;
+ ScalableXlfd *pScalableFont = NULL;
+
+ int nFrom = 0;
+ for ( i = 0; i < nXlfdCount; i++ )
+ {
+ // exclude openlook glyph and cursor
+ Attribute *pAttr = mpFactory->RetrieveFamily(pXlfdList[i].mnFamily);
+ if ( pAttr->HasFeature( XLFD_FEATURE_OL_GLYPH
+ | XLFD_FEATURE_OL_CURSOR) )
+ continue;
+ // exclude fonts with unknown encoding
+ if ( pXlfdList[i].GetEncoding() == RTL_TEXTENCODING_DONTKNOW )
+ continue;
+ // exclude "interface system" and "interface user"
+ if (pAttr->HasFeature( XLFD_FEATURE_APPLICATION_FONT ) )
+ continue;
+ // exclude fonts already managed by fontmanager, anyway keep
+ // gui fonts: they are candidates for GetInterfaceFont ()
+ if (pXlfdList[i].Fonttype() == eTypeScalable)
+ ((VirtualXlfd*)mpFallbackFactory)->FilterInterfaceFont (pXlfdList + i);
+#ifndef _USE_PRINT_EXTENSION_
+ if (FontLookup::InSet (aSet, pXlfdList[i]))
+ continue;
+#endif
+ Bool bSameOutline = pXlfdList[i].SameFontoutline(pXlfdList + nFrom);
+ XlfdFonttype eType = pXlfdList[i].Fonttype();
+
+ // flush the old merged font list if the name doesn't match any more
+ if ( !bSameOutline )
+ {
+ mpFontList->Add( pScalableFont );
+ mpFontList->Add( &aBitmapList );
+ pScalableFont = NULL;
+ aBitmapList.Reset();
+ }
+
+ // merge the font or generate a new one
+ switch( eType )
+ {
+ case eTypeScalable:
+ if ( pScalableFont == NULL )
+ pScalableFont = new ScalableXlfd;
+ pScalableFont->AddEncoding(pXlfdList + i);
+ break;
+
+ case eTypeBitmap:
+ aBitmapList.AddBitmapFont( pXlfdList + i );
+ break;
+
+ case eTypeScalableBitmap:
+ // ignore scaled X11 bitmap fonts because they look too ugly
+ default:
+ break;
+ }
+
+ nFrom = i;
+ }
+
+ // flush the merged list into the global list
+ mpFontList->Add( pScalableFont );
+ mpFontList->Add( &aBitmapList );
+ if (mpFallbackFactory->NumEncodings() > 0)
+ mpFontList->Add( mpFallbackFactory );
+ // cleanup the list of simple font information
+ if ( pXlfdList != NULL )
+ free( pXlfdList );
+
+ return mpFontList;
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+ExtendedFontStruct*
+SalDisplay::GetFont( const ExtendedXlfd *pRequestedFont,
+ const Size& rPixelSize, sal_Bool bVertical ) const
+{
+ // TODO: either get rid of X11 fonts or get rid of the non-hashmapped cache
+ if( !m_pFontCache )
+ {
+ m_pFontCache = new SalFontCache( 64, 64, 16 ); // ???
+ }
+ else
+ {
+ ExtendedFontStruct *pItem;
+ for ( pItem = m_pFontCache->First();
+ pItem != NULL;
+ pItem = m_pFontCache->Next() )
+ {
+ if ( pItem->Match(pRequestedFont, rPixelSize, bVertical) )
+ {
+ if( m_pFontCache->GetCurPos() )
+ {
+ m_pFontCache->Remove( pItem );
+ m_pFontCache->Insert( pItem, 0UL );
+ }
+ return pItem;
+ }
+ }
+ }
+
+ // before we expand the cache, we look for very old and unused items
+ if( m_pFontCache->Count() >= 64 )
+ {
+ ExtendedFontStruct *pItem;
+ for ( pItem = m_pFontCache->Last();
+ pItem != NULL;
+ pItem = m_pFontCache->Prev() )
+ {
+ if( 1 == pItem->GetRefCount() )
+ {
+ m_pFontCache->Remove( pItem );
+ pItem->ReleaseRef();
+ if( m_pFontCache->Count() < 64 )
+ break;
+ }
+ }
+ }
+
+ ExtendedFontStruct *pItem = new ExtendedFontStruct( GetDisplay(),
+ rPixelSize, bVertical,
+ const_cast<ExtendedXlfd*>(pRequestedFont) );
+ m_pFontCache->Insert( pItem, 0UL );
+ pItem->AddRef();
+
+ return pItem;
+}
+
+// ---------------------------------------------------------------------------
+
+void
+SalDisplay::DestroyFontCache()
+{
+ if( m_pFontCache )
+ {
+ ExtendedFontStruct *pItem = m_pFontCache->First();
+ while( pItem )
+ {
+ delete pItem;
+ pItem = m_pFontCache->Next();
+ }
+ delete m_pFontCache;
+ }
+ if( mpFontList )
+ {
+ mpFontList->Dispose();
+ delete mpFontList;
+ }
+ if ( mpFactory )
+ {
+ delete mpFactory;
+ }
+
+ m_pFontCache = (SalFontCache*)NULL;
+ mpFontList = (XlfdStorage*)NULL;
+ mpFactory = (AttributeProvider*)NULL;
+}
+
+// ===========================================================================
+
+// PspKernInfo allows on-demand-querying of psprint provided kerning info (#i29881#)
+class PspKernInfo : public ExtraKernInfo
+{
+public:
+ PspKernInfo( int nFontId ) : ExtraKernInfo(nFontId) {}
+protected:
+ virtual void Initialize() const;
+};
+
+//--------------------------------------------------------------------------
+
+void PspKernInfo::Initialize() const
+{
+ mbInitialized = true;
+
+ // get the kerning pairs from psprint
+ const psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ typedef std::list< psp::KernPair > PspKernPairs;
+ const PspKernPairs& rKernPairs = rMgr.getKernPairs( mnFontId );
+ if( rKernPairs.empty() )
+ return;
+
+ // feed psprint's kerning list into a lookup-friendly container
+ maUnicodeKernPairs.resize( rKernPairs.size() );
+ PspKernPairs::const_iterator it = rKernPairs.begin();
+ for(; it != rKernPairs.end(); ++it )
+ {
+ ImplKernPairData aKernPair = { it->first, it->second, it->kern_x };
+ maUnicodeKernPairs.insert( aKernPair );
+ }
+}
+
+// ----------------------------------------------------------------------------
+//
+// X11SalGraphics
+//
+// ----------------------------------------------------------------------------
+
+GC
+X11SalGraphics::SelectFont()
+{
+ Display *pDisplay = GetXDisplay();
+
+ if( !pFontGC_ )
+ {
+ XGCValues values;
+ values.subwindow_mode = ClipByChildren;
+ values.fill_rule = EvenOddRule; // Pict import/ Gradient
+ values.graphics_exposures = False;
+ values.foreground = nTextPixel_;
+#ifdef _USE_PRINT_EXTENSION_
+ values.background = xColormap_->GetWhitePixel();
+ pFontGC_ = XCreateGC( pDisplay, hDrawable_,
+ GCSubwindowMode | GCFillRule
+ | GCGraphicsExposures | GCBackground | GCForeground,
+ &values );
+#else
+ pFontGC_ = XCreateGC( pDisplay, hDrawable_,
+ GCSubwindowMode | GCFillRule
+ | GCGraphicsExposures | GCForeground,
+ &values );
+#endif
+ }
+ if( !bFontGC_ )
+ {
+ XSetForeground( pDisplay, pFontGC_, nTextPixel_ );
+ SetClipRegion( pFontGC_ );
+ bFontGC_ = TRUE;
+ }
+
+ return pFontGC_;
+}
+
+//--------------------------------------------------------------------------
+
+bool X11SalGraphics::setFont( const ImplFontSelectData *pEntry, int nFallbackLevel )
+{
+#ifdef HDU_DEBUG
+ ByteString aReqName( "NULL" );
+ if( pEntry )
+ aReqName = ByteString( pEntry->maName, RTL_TEXTENCODING_UTF8 );
+ ByteString aUseName( "NULL" );
+ if( pEntry && pEntry->mpFontData )
+ aUseName = ByteString( pEntry->mpFontData->GetFamilyName(), RTL_TEXTENCODING_UTF8 );
+ fprintf( stderr, "SetFont(lvl=%d,\"%s\", %d*%d, naa=%d,b=%d,i=%d) => \"%s\"\n",
+ nFallbackLevel, aReqName.GetBuffer(),
+ !pEntry?-1:pEntry->mnWidth, !pEntry?-1:pEntry->mnHeight,
+ !pEntry?-1:pEntry->mbNonAntialiased,
+ !pEntry?-1:pEntry->meWeight, !pEntry?-1:pEntry->meItalic,
+ aUseName.GetBuffer() );
+#endif
+
+ // release all no longer needed font resources
+ for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
+ {
+ mXFont[i] = NULL; // ->ReleaseRef()
+
+ if( mpServerFont[i] != NULL )
+ {
+ // old server side font is no longer referenced
+ GlyphCache::GetInstance().UncacheFont( *mpServerFont[i] );
+ mpServerFont[i] = NULL;
+ }
+ }
+
+ // return early if there is no new font
+ if( !pEntry )
+ return false;
+
+ bFontVertical_ = pEntry->mbVertical;
+
+ // return early if this is not a valid font for this graphics
+ if( !pEntry->mpFontData )
+ return false;
+
+ // handle the request for a native X11-font
+ if( ImplX11FontData::CheckFontData( *pEntry->mpFontData ) )
+ {
+ const ImplX11FontData* pRequestedFont = static_cast<const ImplX11FontData*>( pEntry->mpFontData );
+ const ExtendedXlfd& rX11Font = pRequestedFont->GetExtendedXlfd();
+
+ Size aReqSize( pEntry->mnWidth, pEntry->mnHeight );
+ mXFont[ nFallbackLevel ] = GetDisplay()->GetFont( &rX11Font, aReqSize, bFontVertical_ );
+ bFontGC_ = FALSE;
+ return true;
+ }
+
+ // handle the request for a non-native X11-font => use the GlyphCache
+ ServerFont* pServerFont = GlyphCache::GetInstance().CacheFont( *pEntry );
+ if( pServerFont != NULL )
+ {
+ // ignore fonts with e.g. corrupted font files
+ if( !pServerFont->TestFont() )
+ {
+ GlyphCache::GetInstance().UncacheFont( *pServerFont );
+ return false;
+ }
+
+ // register to use the font
+ mpServerFont[ nFallbackLevel ] = pServerFont;
+
+ // apply font specific-hint settings if needed
+ // TODO: also disable it for reference devices
+ if( !bPrinter_ )
+ {
+ ImplServerFontEntry* pSFE = static_cast<ImplServerFontEntry*>( pEntry->mpFontEntry );
+ pSFE->HandleFontOptions();
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+void ImplServerFontEntry::HandleFontOptions( void )
+{
+ bool GetFCFontOptions( const ImplFontAttributes&, int nSize, ImplFontOptions& );
+
+ if( !mpServerFont )
+ return;
+ if( !mbGotFontOptions )
+ {
+ // get and cache the font options
+ mbGotFontOptions = true;
+ mbValidFontOptions = GetFCFontOptions( *maFontSelData.mpFontData,
+ maFontSelData.mnHeight, maFontOptions );
+ }
+ // apply the font options
+ if( mbValidFontOptions )
+ mpServerFont->SetFontOptions( maFontOptions );
+}
+
+//--------------------------------------------------------------------------
+
+inline sal_Unicode SwapBytes( const sal_Unicode nIn )
+{
+ return ((nIn >> 8) & 0x00ff) | ((nIn & 0x00ff) << 8);
+}
+
+// draw string in a specific multibyte encoding
+static void
+ConvertTextItem16( XTextItem16* pTextItem, rtl_TextEncoding nEncoding )
+{
+ if ( (pTextItem == NULL) || (pTextItem->nchars <= 0) )
+ return;
+
+ SalConverterCache* pCvt = SalConverterCache::GetInstance();
+ // convert the string into the font encoding
+ sal_Size nSize;
+ sal_Size nBufferSize = pTextItem->nchars * 2;
+ sal_Char *pBuffer = (sal_Char*)alloca( nBufferSize );
+
+ nSize = pCvt->ConvertStringUTF16( (sal_Unicode*)pTextItem->chars, pTextItem->nchars,
+ pBuffer, nBufferSize, nEncoding);
+
+ sal_Char *pTextChars = (sal_Char*)pTextItem->chars;
+ unsigned int n = 0, m = 0;
+
+ if ( nEncoding == RTL_TEXTENCODING_GB_2312
+ || nEncoding == RTL_TEXTENCODING_GBT_12345
+ || nEncoding == RTL_TEXTENCODING_GBK
+ || nEncoding == RTL_TEXTENCODING_BIG5 )
+ {
+ // GB and Big5 needs special treatment since chars can be single or
+ // double byte: encoding is
+ // [ 0x00 - 0x7f ] | [ 0x81 - 0xfe ] [ 0x40 - 0x7e 0x80 - 0xfe ]
+ while ( n < nSize )
+ {
+ if ( (unsigned char)pBuffer[ n ] < 0x80 )
+ {
+ pTextChars[ m++ ] = 0x0;
+ pTextChars[ m++ ] = pBuffer[ n++ ];
+ }
+ else
+ {
+ pTextChars[ m++ ] = pBuffer[ n++ ];
+ pTextChars[ m++ ] = pBuffer[ n++ ];
+ }
+ }
+ pTextItem->nchars = m / 2;
+ }
+ else
+ if ( pCvt->IsSingleByteEncoding(nEncoding) )
+ {
+ // Single Byte encoding has to be padded
+ while ( n < nSize )
+ {
+ pTextChars[ m++ ] = 0x0;
+ pTextChars[ m++ ] = pBuffer[ n++ ];
+ }
+ pTextItem->nchars = nSize;
+ }
+ else
+ {
+ while ( n < nSize )
+ {
+ pTextChars[ m++ ] = pBuffer[ n++ ];
+ }
+ pTextItem->nchars = nSize / 2;
+ }
+
+ // XXX FIXME
+ if ( (nEncoding == RTL_TEXTENCODING_GB_2312)
+ || (nEncoding == RTL_TEXTENCODING_EUC_KR) )
+ {
+ for (unsigned int n_char = 0; n_char < m; n_char++ )
+ pTextChars[ n_char ] &= 0x7F;
+ }
+}
+
+//--------------------------------------------------------------------------
+namespace {
+
+class CairoWrapper
+{
+private:
+ oslModule mpCairoLib;
+
+ cairo_surface_t* (*mp_xlib_surface_create_with_xrender_format)(Display *, Drawable , Screen *, XRenderPictFormat *, int , int );
+ void (*mp_surface_destroy)(cairo_surface_t *);
+ cairo_t* (*mp_create)(cairo_surface_t *);
+ void (*mp_destroy)(cairo_t*);
+ void (*mp_clip)(cairo_t*);
+ void (*mp_rectangle)(cairo_t*, double, double, double, double);
+ cairo_font_face_t * (*mp_ft_font_face_create_for_ft_face)(FT_Face, int);
+ void (*mp_set_font_face)(cairo_t *, cairo_font_face_t *);
+ void (*mp_font_face_destroy)(cairo_font_face_t *);
+ void (*mp_matrix_init_identity)(cairo_matrix_t *);
+ void (*mp_matrix_scale)(cairo_matrix_t *, double, double);
+ void (*mp_matrix_rotate)(cairo_matrix_t *, double);
+ void (*mp_set_font_matrix)(cairo_t *, const cairo_matrix_t *);
+ void (*mp_show_glyphs)(cairo_t *, const cairo_glyph_t *, int );
+ void (*mp_set_source_rgb)(cairo_t *, double , double , double );
+ void (*mp_set_font_options)(cairo_t *, const void *);
+ void (*mp_ft_font_options_substitute)(const void*, void*);
+
+ bool canEmbolden() const { return false; }
+
+ CairoWrapper();
+public:
+ static CairoWrapper& get();
+ bool isValid() const { return (mpCairoLib != NULL); }
+ bool isCairoRenderable(const ServerFont& rFont);
+
+ cairo_surface_t* xlib_surface_create_with_xrender_format(Display *pDisplay, Drawable drawable, Screen *pScreen, XRenderPictFormat *pFormat, int width, int height)
+ { return (*mp_xlib_surface_create_with_xrender_format)(pDisplay, drawable, pScreen, pFormat, width, height); }
+ void surface_destroy(cairo_surface_t *surface) { (*mp_surface_destroy)(surface); }
+ cairo_t* create(cairo_surface_t *surface) { return (*mp_create)(surface); }
+ void destroy(cairo_t *cr) { (*mp_destroy)(cr); }
+ void clip(cairo_t *cr) { (*mp_clip)(cr); }
+ void rectangle(cairo_t *cr, double x, double y, double width, double height)
+ { (*mp_rectangle)(cr, x, y, width, height); }
+ cairo_font_face_t* ft_font_face_create_for_ft_face(FT_Face face, int load_flags)
+ { return (*mp_ft_font_face_create_for_ft_face)(face, load_flags); }
+ void set_font_face(cairo_t *cr, cairo_font_face_t *font_face)
+ { (*mp_set_font_face)(cr, font_face); }
+ void font_face_destroy(cairo_font_face_t *font_face)
+ { (*mp_font_face_destroy)(font_face); }
+ void matrix_init_identity(cairo_matrix_t *matrix)
+ { (*mp_matrix_init_identity)(matrix); }
+ void matrix_scale(cairo_matrix_t *matrix, double sx, double sy)
+ { (*mp_matrix_scale)(matrix, sx, sy); }
+ void matrix_rotate(cairo_matrix_t *matrix, double radians)
+ { (*mp_matrix_rotate)(matrix, radians); }
+ void set_font_matrix(cairo_t *cr, const cairo_matrix_t *matrix)
+ { (*mp_set_font_matrix)(cr, matrix); }
+ void show_glyphs(cairo_t *cr, const cairo_glyph_t *glyphs, int no_glyphs)
+ { (*mp_show_glyphs)(cr, glyphs, no_glyphs); }
+ void set_source_rgb(cairo_t *cr, double red, double green, double blue)
+ { (*mp_set_source_rgb)(cr, red, green, blue); }
+ void set_font_options(cairo_t *cr, const void *options)
+ { (*mp_set_font_options)(cr, options); }
+ void ft_font_options_substitute(const void *options, void *pattern)
+ { (*mp_ft_font_options_substitute)(options, pattern); }
+};
+
+static CairoWrapper* pCairoInstance = NULL;
+
+CairoWrapper& CairoWrapper::get()
+{
+ if( ! pCairoInstance )
+ pCairoInstance = new CairoWrapper();
+ return *pCairoInstance;
+}
+
+CairoWrapper::CairoWrapper()
+: mpCairoLib( NULL )
+{
+ static const char* pDisableCairoText = getenv( "SAL_DISABLE_CAIROTEXT" );
+ if( pDisableCairoText && (pDisableCairoText[0] != '0') )
+ return;
+
+ int nDummy;
+ if( !XQueryExtension( GetX11SalData()->GetDisplay()->GetDisplay(), "RENDER", &nDummy, &nDummy, &nDummy ) )
+ return;
+
+#ifdef MACOSX
+ OUString aLibName( RTL_CONSTASCII_USTRINGPARAM( "libcairo.2.dylib" ));
+#else
+ OUString aLibName( RTL_CONSTASCII_USTRINGPARAM( "libcairo.so.2" ));
+#endif
+ mpCairoLib = osl_loadModule( aLibName.pData, SAL_LOADMODULE_DEFAULT );
+ if( !mpCairoLib )
+ return;
+
+#ifdef DEBUG
+ // check cairo version
+ int (*p_version)();
+ p_version = (int(*)()) osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_version" );
+ const int nVersion = p_version ? (*p_version)() : 0;
+ fprintf( stderr, "CAIRO version=%d\n", nVersion );
+#endif
+
+ mp_xlib_surface_create_with_xrender_format = (cairo_surface_t* (*)(Display *, Drawable , Screen *, XRenderPictFormat *, int , int ))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_xlib_surface_create_with_xrender_format" );
+ mp_surface_destroy = (void(*)(cairo_surface_t*))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_surface_destroy" );
+ mp_create = (cairo_t*(*)(cairo_surface_t*))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_create" );
+ mp_destroy = (void(*)(cairo_t*))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_destroy" );
+ mp_clip = (void(*)(cairo_t*))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_clip" );
+ mp_rectangle = (void(*)(cairo_t*, double, double, double, double))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_rectangle" );
+ mp_ft_font_face_create_for_ft_face = (cairo_font_face_t * (*)(FT_Face, int))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_ft_font_face_create_for_ft_face" );
+ mp_set_font_face = (void (*)(cairo_t *, cairo_font_face_t *))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_set_font_face" );
+ mp_font_face_destroy = (void (*)(cairo_font_face_t *))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_font_face_destroy" );
+ mp_matrix_init_identity = (void (*)(cairo_matrix_t *))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_matrix_init_identity" );
+ mp_matrix_scale = (void (*)(cairo_matrix_t *, double, double))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_matrix_scale" );
+ mp_matrix_rotate = (void (*)(cairo_matrix_t *, double))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_matrix_rotate" );
+ mp_set_font_matrix = (void (*)(cairo_t *, const cairo_matrix_t *))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_set_font_matrix" );
+ mp_show_glyphs = (void (*)(cairo_t *, const cairo_glyph_t *, int ))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_show_glyphs" );
+ mp_set_source_rgb = (void (*)(cairo_t *, double , double , double ))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_set_source_rgb" );
+ mp_set_font_options = (void (*)(cairo_t *, const void *options ))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_set_font_options" );
+ mp_ft_font_options_substitute = (void (*)(const void *, void *))
+ osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_ft_font_options_substitute" );
+
+ if( !(
+ mp_xlib_surface_create_with_xrender_format &&
+ mp_surface_destroy &&
+ mp_create &&
+ mp_destroy &&
+ mp_clip &&
+ mp_rectangle &&
+ mp_ft_font_face_create_for_ft_face &&
+ mp_set_font_face &&
+ mp_font_face_destroy &&
+ mp_matrix_init_identity &&
+ mp_matrix_scale &&
+ mp_matrix_rotate &&
+ mp_set_font_matrix &&
+ mp_show_glyphs &&
+ mp_set_source_rgb &&
+ mp_set_font_options &&
+ mp_ft_font_options_substitute
+ ) )
+ {
+ osl_unloadModule( mpCairoLib );
+ mpCairoLib = NULL;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "not all needed symbols were found\n" );
+#endif
+ }
+}
+
+bool CairoWrapper::isCairoRenderable(const ServerFont& rFont)
+{
+ return rFont.GetFtFace() && isValid() && rFont.GetAntialiasAdvice() &&
+ (rFont.NeedsArtificialBold() ? canEmbolden() : true);
+}
+
+} //namespace
+
+CairoFontsCache::LRUFonts CairoFontsCache::maLRUFonts;
+int CairoFontsCache::mnRefCount = 0;
+
+CairoFontsCache::CairoFontsCache()
+{
+ ++mnRefCount;
+}
+
+CairoFontsCache::~CairoFontsCache()
+{
+ --mnRefCount;
+ if (!mnRefCount && !maLRUFonts.empty())
+ {
+ CairoWrapper &rCairo = CairoWrapper::get();
+ LRUFonts::iterator aEnd = maLRUFonts.end();
+ for (LRUFonts::iterator aI = maLRUFonts.begin(); aI != aEnd; ++aI)
+ rCairo.font_face_destroy((cairo_font_face_t*)aI->first);
+ }
+}
+
+void CairoFontsCache::CacheFont(void *pFont, void* pId)
+{
+ maLRUFonts.push_front( std::pair<void*, void *>(pFont, pId) );
+ if (maLRUFonts.size() > 8)
+ {
+ CairoWrapper &rCairo = CairoWrapper::get();
+ rCairo.font_face_destroy((cairo_font_face_t*)maLRUFonts.back().first);
+ maLRUFonts.pop_back();
+ }
+}
+
+void* CairoFontsCache::FindCachedFont(void *pId)
+{
+ LRUFonts::iterator aEnd = maLRUFonts.end();
+ for (LRUFonts::iterator aI = maLRUFonts.begin(); aI != aEnd; ++aI)
+ if (aI->second == pId)
+ return aI->first;
+ return NULL;
+}
+
+void X11SalGraphics::DrawCairoAAFontString( const ServerFontLayout& rLayout )
+{
+ std::vector<cairo_glyph_t> cairo_glyphs;
+ cairo_glyphs.reserve( 256 );
+
+ Point aPos;
+ sal_GlyphId aGlyphId;
+ for( int nStart = 0; rLayout.GetNextGlyphs( 1, &aGlyphId, aPos, nStart ); )
+ {
+ cairo_glyph_t aGlyph;
+ aGlyph.index = aGlyphId & GF_IDXMASK;
+ aGlyph.x = aPos.X();
+ aGlyph.y = aPos.Y();
+ cairo_glyphs.push_back(aGlyph);
+ }
+
+ if (cairo_glyphs.empty())
+ return;
+
+ // find a XRenderPictFormat compatible with the Drawable
+ XRenderPictFormat* pVisualFormat = static_cast<XRenderPictFormat*>(GetXRenderFormat());
+ if( !pVisualFormat )
+ {
+ Visual* pVisual = GetDisplay()->GetVisual( m_nScreen ).GetVisual();
+ pVisualFormat = XRenderPeer::GetInstance().FindVisualFormat( pVisual );
+ // cache the XRenderPictFormat
+ SetXRenderFormat( static_cast<void*>(pVisualFormat) );
+ }
+
+ DBG_ASSERT( pVisualFormat!=NULL, "no matching XRenderPictFormat for text" );
+ if( !pVisualFormat )
+ return;
+
+ CairoWrapper &rCairo = CairoWrapper::get();
+
+ Display* pDisplay = GetXDisplay();
+
+ cairo_surface_t *surface = rCairo.xlib_surface_create_with_xrender_format (pDisplay,
+ hDrawable_, ScreenOfDisplay(pDisplay, m_nScreen), pVisualFormat, SAL_MAX_INT16, SAL_MAX_INT16);
+
+ /*
+ * It might be ideal to cache surface and cairo context between calls and
+ * only destroy it when the drawable changes, but to do that we need to at
+ * least change the SalFrame etc impls to dtor the SalGraphics *before* the
+ * destruction of the windows they reference
+ */
+ cairo_t *cr = rCairo.create(surface);
+ rCairo.surface_destroy(surface);
+
+ if (const void *pOptions = Application::GetSettings().GetStyleSettings().GetCairoFontOptions())
+ rCairo.set_font_options( cr, pOptions);
+
+ if( pClipRegion_ && !XEmptyRegion( pClipRegion_ ) )
+ {
+ for (long i = 0; i < pClipRegion_->numRects; ++i)
+ {
+ rCairo.rectangle(cr,
+ pClipRegion_->rects[i].x1,
+ pClipRegion_->rects[i].y1,
+ pClipRegion_->rects[i].x2 - pClipRegion_->rects[i].x1,
+ pClipRegion_->rects[i].y2 - pClipRegion_->rects[i].y1);
+ }
+ rCairo.clip(cr);
+ }
+
+ rCairo.set_source_rgb(cr,
+ SALCOLOR_RED(nTextColor_)/255.0,
+ SALCOLOR_GREEN(nTextColor_)/255.0,
+ SALCOLOR_BLUE(nTextColor_)/255.0);
+
+ ServerFont& rFont = rLayout.GetServerFont();
+
+ cairo_font_face_t* font_face = NULL;
+
+ void *pId = rFont.GetFtFace();
+ font_face = (cairo_font_face_t*)m_aCairoFontsCache.FindCachedFont(pId);
+ if (!font_face)
+ {
+ font_face = rCairo.ft_font_face_create_for_ft_face(pId, rFont.GetLoadFlags());
+ m_aCairoFontsCache.CacheFont(font_face, pId);
+ }
+
+ rCairo.set_font_face(cr, font_face);
+
+ cairo_matrix_t m;
+ const ImplFontSelectData& rFSD = rFont.GetFontSelData();
+ int nWidth = rFSD.mnWidth ? rFSD.mnWidth : rFSD.mnHeight;
+
+ rCairo.matrix_init_identity(&m);
+
+ if (rLayout.GetOrientation())
+ rCairo.matrix_rotate(&m, (3600 - rLayout.GetOrientation()) * M_PI / 1800.0);
+
+ rCairo.matrix_scale(&m, nWidth, rFSD.mnHeight);
+ if (rFont.NeedsArtificialItalic())
+ m.xy = -m.xx * 0x6000L / 0x10000L;
+
+ rCairo.set_font_matrix(cr, &m);
+ rCairo.show_glyphs(cr, &cairo_glyphs[0], cairo_glyphs.size());
+ rCairo.destroy(cr);
+}
+
+//--------------------------------------------------------------------------
+
+void X11SalGraphics::DrawServerAAFontString( const ServerFontLayout& rLayout )
+{
+ // get xrender target for this drawable
+ Picture aDstPic = GetXRenderPicture();
+ if( !aDstPic )
+ return;
+
+ // get a XRenderPicture for the font foreground
+ // TODO: move into own method
+ XRenderPeer& rRenderPeer = XRenderPeer::GetInstance();
+ XRenderPictFormat* pVisualFormat = (XRenderPictFormat*)GetXRenderFormat();
+ DBG_ASSERT( pVisualFormat, "we already have a render picture, but XRenderPictFormat==NULL???");
+ const int nVisualDepth = pVisualFormat->depth;
+ SalDisplay::RenderEntry& rEntry = GetDisplay()->GetRenderEntries( m_nScreen )[ nVisualDepth ];
+ if( !rEntry.m_aPicture )
+ {
+ // create and cache XRenderPicture for the font foreground
+ Display* pDisplay = GetXDisplay();
+#ifdef DEBUG
+ int iDummy;
+ unsigned uDummy;
+ XLIB_Window wDummy;
+ unsigned int nDrawDepth;
+ ::XGetGeometry( pDisplay, hDrawable_, &wDummy, &iDummy, &iDummy,
+ &uDummy, &uDummy, &uDummy, &nDrawDepth );
+ DBG_ASSERT( static_cast<unsigned>(nVisualDepth) == nDrawDepth, "depth messed up for XRender" );
+#endif
+
+ rEntry.m_aPixmap = ::XCreatePixmap( pDisplay, hDrawable_, 1, 1, nVisualDepth );
+
+ XRenderPictureAttributes aAttr;
+ aAttr.repeat = true;
+ rEntry.m_aPicture = rRenderPeer.CreatePicture ( rEntry.m_aPixmap, pVisualFormat, CPRepeat, &aAttr );
+ }
+
+ // set font foreground color and opacity
+ XRenderColor aRenderColor = GetXRenderColor( nTextColor_ );
+ rRenderPeer.FillRectangle( PictOpSrc, rEntry.m_aPicture, &aRenderColor, 0, 0, 1, 1 );
+
+ // set clipping
+ // TODO: move into GetXRenderPicture()?
+ if( pClipRegion_ && !XEmptyRegion( pClipRegion_ ) )
+ rRenderPeer.SetPictureClipRegion( aDstPic, pClipRegion_ );
+
+ ServerFont& rFont = rLayout.GetServerFont();
+ X11GlyphPeer& rGlyphPeer = X11GlyphCache::GetInstance().GetPeer();
+ GlyphSet aGlyphSet = rGlyphPeer.GetGlyphSet( rFont, m_nScreen );
+
+ Point aPos;
+ static const int MAXGLYPHS = 160;
+ sal_GlyphId aGlyphAry[ MAXGLYPHS ];
+ int nMaxGlyphs = rLayout.GetOrientation() ? 1 : MAXGLYPHS;
+ for( int nStart = 0;;)
+ {
+ int nGlyphs = rLayout.GetNextGlyphs( nMaxGlyphs, aGlyphAry, aPos, nStart );
+ if( !nGlyphs )
+ break;
+
+ // #i51924# avoid 32->16bit coordinate truncation problem in X11
+ // TODO: reevaluate once displays with >30000 pixels are available
+ if( aPos.X() >= 30000 || aPos.Y() >= 30000 )
+ continue;
+
+ unsigned int aRenderAry[ MAXGLYPHS ];
+ for( int i = 0; i < nGlyphs; ++i )
+ aRenderAry[ i ] = rGlyphPeer.GetGlyphId( rFont, aGlyphAry[i] );
+ rRenderPeer.CompositeString32( rEntry.m_aPicture, aDstPic,
+ aGlyphSet, aPos.X(), aPos.Y(), aRenderAry, nGlyphs );
+ }
+}
+
+//--------------------------------------------------------------------------
+
+bool X11SalGraphics::DrawServerAAForcedString( const ServerFontLayout& rLayout )
+{
+ ServerFont& rFont = rLayout.GetServerFont();
+
+ // prepare glyphs and get extent of operation
+ X11GlyphPeer& rGlyphPeer = X11GlyphCache::GetInstance().GetPeer();
+ int nXmin = 0;
+ int nXmax = 0;
+ int nYmin = 0;
+ int nYmax = 0;
+ int nStart = 0;
+ Point aPos;
+ sal_GlyphId nGlyph;
+ for( bool bFirst=true; rLayout.GetNextGlyphs( 1, &nGlyph, aPos, nStart ); )
+ {
+ const RawBitmap* const pRawBitmap = rGlyphPeer.GetRawBitmap( rFont, nGlyph );
+ if( !pRawBitmap )
+ continue;
+
+ const int nX1 = aPos.X() + pRawBitmap->mnXOffset;
+ const int nY1 = aPos.Y() + pRawBitmap->mnYOffset;
+ const int nX2 = nX1 + pRawBitmap->mnWidth;
+ const int nY2 = nY1 + pRawBitmap->mnHeight;
+
+ if( bFirst )
+ {
+ bFirst = false;
+ nXmin = nX1;
+ nXmax = nX2;
+ nYmin = nY1;
+ nYmax = nY2;
+ }
+ else
+ {
+ if( nXmin > nX1 ) nXmin = nX1;
+ if( nXmax < nX2 ) nXmax = nX2;
+ if( nYmin > nY1 ) nYmin = nY1;
+ if( nYmax < nY2 ) nYmax = nY2;
+ }
+ }
+
+ // get XImage
+ GetDisplay()->GetXLib()->PushXErrorLevel( true );
+ Display* pDisplay = GetXDisplay();
+
+ XRectangle aXRect;
+ long nWidth = 1, nHeight = 1;
+ if( m_pFrame )
+ nWidth = m_pFrame->maGeometry.nWidth, nHeight = m_pFrame->maGeometry.nHeight;
+ else if( m_pVDev )
+ nWidth = m_pVDev->GetWidth(), nHeight = m_pVDev->GetHeight();
+
+ if( pClipRegion_ && !XEmptyRegion( pClipRegion_ ) )
+ {
+ // get bounding box
+ XClipBox( pClipRegion_, &aXRect );
+ // clip with window
+ if( aXRect.x < 0 ) aXRect.x = 0;
+
+ if( aXRect.y < 0 ) aXRect.y = 0;
+ if( aXRect.width+aXRect.x > nWidth ) aXRect.width = nWidth-aXRect.x;
+ if( aXRect.height+aXRect.y > nHeight ) aXRect.height = nHeight-aXRect.y;
+ }
+ else
+ {
+ aXRect.x = 0;
+ aXRect.y = 0;
+ aXRect.width = nWidth;
+ aXRect.height = nHeight;
+ }
+ if( m_pFrame )
+ {
+ // clip with screen
+ int nScreenX = m_pFrame->maGeometry.nX+aXRect.x;
+ int nScreenY = m_pFrame->maGeometry.nY+aXRect.y;
+ const Size& rScreenSize = GetDisplay()->getDataForScreen( m_nScreen ).m_aSize;
+ int nScreenW = rScreenSize.Width();
+ int nScreenH = rScreenSize.Height();
+ if( nScreenX < 0 )
+ aXRect.x -= nScreenX, aXRect.width += nScreenX;
+ if( nScreenX+aXRect.width > nScreenW )
+ aXRect.width = nScreenW-nScreenX;
+ if( nScreenY < 0 )
+ aXRect.y -= nScreenY, aXRect.height += nScreenY;
+ if( nScreenY+aXRect.height > nScreenH )
+ aXRect.height = nScreenH-nScreenY;
+ }
+
+
+ if( nXmin < aXRect.x ) nXmin = aXRect.x;
+ if( nYmin < aXRect.y ) nYmin = aXRect.y;
+ if( nXmax >= aXRect.x+aXRect.width ) nXmax = aXRect.x + aXRect.width - 1;
+ if( nYmax >= aXRect.y+aXRect.height ) nYmax = aXRect.y + aXRect.height - 1;
+
+ if( nXmin > nXmax )
+ return false;
+ if( nYmin > nYmax )
+ return false;
+
+ XImage* pImg = XGetImage( pDisplay, hDrawable_,
+ nXmin, nYmin,
+ (nXmax-nXmin+1), (nYmax-nYmin+1),
+ ~0, ZPixmap );
+ if( pImg == NULL )
+ {
+ if( m_pFrame )
+ {
+ // the reason we did not get an image could be that the frame
+ // geometry changed in the meantime; lets get the current geometry
+ // and clip against the current window size as well as the screen
+ // with the current frame position
+ const Size& rScreenSize = GetDisplay()->getDataForScreen(m_nScreen).m_aSize;
+ int nScreenW = rScreenSize.Width();
+ int nScreenH = rScreenSize.Height();
+ XLIB_Window aRoot = None;
+ int x = 0, y = 0;
+ unsigned int w = 0, h = 0, bw = 0, d;
+ XGetGeometry( pDisplay, hDrawable_, &aRoot, &x, &y, &w, &h, &bw, &d );
+ XTranslateCoordinates( pDisplay, hDrawable_, aRoot, 0, 0, &x, &y, &aRoot );
+ if( nXmin + x < 0 ) // clip on left screen edge
+ nXmin += x-nXmin;
+ if( nYmin + y < 0 ) // clip on top screen edge
+ nYmin += y-nYmin;
+ if( nXmax >= int(w) ) // clip on right window egde
+ nXmax = w-1;
+ if( nYmax >= int(h) ) // clip on bottom window edge
+ nYmax = h-1;
+ if( nXmax + x >= nScreenW ) // clip on right screen edge
+ nXmax -= (nXmax + x - nScreenW)+1;
+ if( nYmax + y >= nScreenH ) // clip on bottom screen edge
+ nYmax -= (nYmax + y - nScreenH)+1;
+ if( nXmax >= nXmin && nYmax >= nYmin )
+ {
+ // try again to get the image
+ pImg = XGetImage( pDisplay, hDrawable_,
+ nXmin, nYmin,
+ (nXmax-nXmin+1), (nYmax-nYmin+1),
+ ~0, ZPixmap );
+ }
+ }
+ if( pImg == NULL )
+ {
+ GetDisplay()->GetXLib()->PopXErrorLevel();
+ return false;
+ }
+ }
+
+ // prepare context
+ GC nGC = SelectFont();
+ XGCValues aGCVal;
+ XGetGCValues( pDisplay, nGC, GCForeground, &aGCVal );
+
+ unsigned long nOrigColor = XGetPixel( pImg, 0, 0 );
+ XPutPixel( pImg, 0, 0, aGCVal.foreground );
+ unsigned char aColor[4];
+ aColor[0] = pImg->data[0];
+ aColor[1] = pImg->data[1];
+ aColor[2] = pImg->data[2];
+ aColor[3] = pImg->data[3];
+ XPutPixel( pImg, 0, 0, nOrigColor );
+
+ // work on XImage
+ const int bpp = pImg->bits_per_pixel >> 3;
+ for( nStart = 0; rLayout.GetNextGlyphs( 1, &nGlyph, aPos, nStart ); )
+ {
+ const RawBitmap* const pRawBitmap = rGlyphPeer.GetRawBitmap( rFont, nGlyph );
+ if( !pRawBitmap )
+ continue;
+
+ const int nX1 = aPos.X() + pRawBitmap->mnXOffset;
+ const int nY1 = aPos.Y() + pRawBitmap->mnYOffset;
+
+ if( (nX1 <= nXmax) && (int(nX1 + pRawBitmap->mnWidth) > nXmin)
+ && (nY1 <= nYmax) && (int(nY1 + pRawBitmap->mnHeight) > nYmin) )
+ {
+ const unsigned char* p10 = pRawBitmap->mpBits;
+ unsigned char* p20 = (unsigned char*)pImg->data; // dest left limit
+ p20 += (nY1 - nYmin) * pImg->bytes_per_line;
+ unsigned char* p21 = p20 + (nX1 - nXmin + pImg->xoffset) * bpp;
+ int y = pRawBitmap->mnHeight;
+ if( y > nYmax - nY1 )
+ y = nYmax - nY1 + 1;
+ while( --y >= 0 )
+ {
+ if( p20 >= (unsigned char*)pImg->data )
+ {
+ unsigned char* const p22 = p20 + pImg->width * bpp; // dest right limit
+ unsigned char* pDst = p21;
+ const unsigned char* pSrc = p10;
+ for( int x = pRawBitmap->mnWidth; (--x >= 0) && (p22 > pDst); ++pSrc )
+ {
+ if( (*pSrc == 0) || (p20 > pDst) ) // keep background
+ pDst += bpp;
+ else if( *pSrc == 0xFF ) // paint foreground
+ {
+ const unsigned char* pColor = aColor;
+ for( int z = bpp; --z >= 0; ++pColor, ++pDst )
+ *pDst = *pColor;
+ }
+ else // blend fg into bg
+ {
+ const unsigned char* pColor = aColor;
+ for( int z = bpp; --z >= 0; ++pColor, ++pDst )
+ // theoretically it should be *257) >> 16
+ // but the error is <0.4% worst case and we are in
+ // the innermost loop of very perf-sensitive code
+
+ *pDst += (*pSrc * ((int)*pColor - *pDst)) >> 8;
+ }
+ }
+ }
+ p10 += pRawBitmap->mnScanlineSize;
+ p20 += pImg->bytes_per_line;
+ p21 += pImg->bytes_per_line;
+ }
+ }
+ }
+
+ // put XImage
+ XPutImage( pDisplay, hDrawable_, nGC, pImg,
+ 0, 0, nXmin, nYmin, (nXmax - nXmin + 1), (nYmax - nYmin + 1) );
+ XDestroyImage( pImg );
+
+ GetDisplay()->GetXLib()->PopXErrorLevel();
+ return true;
+}
+
+//--------------------------------------------------------------------------
+
+void X11SalGraphics::DrawServerSimpleFontString( const ServerFontLayout& rSalLayout )
+{
+ ServerFont& rFont = rSalLayout.GetServerFont();
+ X11GlyphPeer& rGlyphPeer = X11GlyphCache::GetInstance().GetPeer();
+
+ Display* pDisplay = GetXDisplay();
+ GC nGC = SelectFont();
+
+ XGCValues aGCVal;
+ aGCVal.fill_style = FillStippled;
+ aGCVal.line_width = 0;
+ GC tmpGC = XCreateGC( pDisplay, hDrawable_, GCFillStyle|GCLineWidth, &aGCVal );
+ XCopyGC( pDisplay, nGC, (1<<GCLastBit)-(1+GCFillStyle+GCLineWidth), tmpGC );
+
+ Point aPos;
+ sal_GlyphId nGlyph;
+ for( int nStart = 0; rSalLayout.GetNextGlyphs( 1, &nGlyph, aPos, nStart ); )
+ {
+ // #i51924# avoid 32->16bit coordinate truncation problem in X11
+ // TODO: reevaluate once displays with >30000 pixels are available
+ if( aPos.X() >= 30000 || aPos.Y() >= 30000 )
+ continue;
+
+ Pixmap aStipple = rGlyphPeer.GetPixmap( rFont, nGlyph, m_nScreen );
+ const GlyphMetric& rGM = rFont.GetGlyphMetric( nGlyph );
+
+ if( aStipple != None )
+ {
+ const int nDestX = aPos.X() + rGM.GetOffset().X();
+ const int nDestY = aPos.Y() + rGM.GetOffset().Y();
+
+ aGCVal.stipple = aStipple;
+ aGCVal.ts_x_origin = nDestX;
+ aGCVal.ts_y_origin = nDestY;
+ XChangeGC( pDisplay, tmpGC, GCStipple|GCTileStipXOrigin|GCTileStipYOrigin, &aGCVal );
+
+ const int nWidth = rGM.GetSize().Width();
+ const int nHeight = rGM.GetSize().Height();
+ XFillRectangle( pDisplay, hDrawable_, tmpGC, nDestX, nDestY, nWidth, nHeight );
+ }
+ }
+
+ XFreeGC( pDisplay, tmpGC );
+}
+
+//--------------------------------------------------------------------------
+
+void X11SalGraphics::DrawServerFontLayout( const ServerFontLayout& rLayout )
+{
+ // draw complex text
+ ServerFont& rFont = rLayout.GetServerFont();
+ const bool bVertical = rFont.GetFontSelData().mbVertical;
+
+ if( !bVertical && CairoWrapper::get().isCairoRenderable(rFont) )
+ DrawCairoAAFontString( rLayout );
+ else
+ {
+ X11GlyphPeer& rGlyphPeer = X11GlyphCache::GetInstance().GetPeer();
+ if( rGlyphPeer.GetGlyphSet( rFont, m_nScreen ) )
+ DrawServerAAFontString( rLayout );
+ else if( !rGlyphPeer.ForcedAntialiasing( rFont, m_nScreen ) )
+ DrawServerSimpleFontString( rLayout );
+ else
+ DrawServerAAForcedString( rLayout );
+ }
+}
+
+//--------------------------------------------------------------------------
+
+void X11SalGraphics::DrawStringUCS2MB( ExtendedFontStruct& rFont,
+ const Point& rPoint, const sal_Unicode* pStr, int nLength )
+{
+ Display* pDisplay = GetXDisplay();
+ GC nGC = SelectFont();
+
+ if( rFont.GetAsciiEncoding() == RTL_TEXTENCODING_UNICODE )
+ {
+ // plain Unicode, can handle all chars and can be handled straight forward
+ XFontStruct* pFontStruct = rFont.GetFontStruct( RTL_TEXTENCODING_UNICODE );
+ if( !pFontStruct )
+ return;
+
+ XSetFont( pDisplay, nGC, pFontStruct->fid );
+
+ #ifdef OSL_LITENDIAN
+ sal_Unicode *pBuffer = (sal_Unicode*)alloca( nLength * sizeof(sal_Unicode) );
+ for ( int i = 0; i < nLength; i++ )
+ pBuffer[ i ] = SwapBytes(pStr[ i ]) ;
+ #else
+ sal_Unicode *pBuffer = const_cast<sal_Unicode*>(pStr);
+ #endif
+
+ XDrawString16( pDisplay, hDrawable_, nGC, rPoint.X(), rPoint.Y(), (XChar2b*)pBuffer, nLength );
+ }
+ else
+ {
+ XTextItem16 *pTextItem = (XTextItem16*)alloca( nLength * sizeof(XTextItem16) );
+ XChar2b *pMBChar = (XChar2b*)pStr;
+ int nItem = 0;
+
+ DBG_ASSERT( nLength<=1, "#i49902# DrawStringUCS2MB with nLength>1 => problems with XOrg6.8.[0123]");
+
+ for( int nChar = 0; nChar < nLength; ++nChar )
+ {
+ rtl_TextEncoding nEnc;
+ XFontStruct* pFontStruct = rFont.GetFontStruct( pStr[nChar], &nEnc );
+ if( !pFontStruct )
+ continue;
+
+ pTextItem[ nItem ].chars = pMBChar + nChar;
+ pTextItem[ nItem ].delta = 0;
+ pTextItem[ nItem ].font = pFontStruct->fid;
+ pTextItem[ nItem ].nchars = 1;
+
+ ConvertTextItem16( &pTextItem[ nItem ], nEnc );
+ ++nItem;
+ }
+
+ XDrawText16( pDisplay, hDrawable_, nGC, rPoint.X(), rPoint.Y(), pTextItem, nItem );
+ }
+}
+
+//--------------------------------------------------------------------------
+
+ImplFontCharMap* X11SalGraphics::GetImplFontCharMap() const
+{
+ // TODO: get ImplFontCharMap directly from fonts
+ if( !mpServerFont[0] )
+#if 0 // RIP XLFD fonts
+ if( mXFont[0] )
+ // TODO?: nPairCount = mXFont[0]->GetFontCodeRanges( NULL );
+#endif
+ return NULL;
+
+ CmapResult aCmapResult;
+ if( !mpServerFont[0]->GetFontCodeRanges( aCmapResult ) )
+ return NULL;
+ return new ImplFontCharMap( aCmapResult );
+}
+
+// ----------------------------------------------------------------------------
+//
+// SalGraphics
+//
+// ----------------------------------------------------------------------------
+
+USHORT X11SalGraphics::SetFont( ImplFontSelectData *pEntry, int nFallbackLevel )
+{
+ USHORT nRetVal = 0;
+ if( !setFont( pEntry, nFallbackLevel ) )
+ nRetVal |= SAL_SETFONT_BADFONT;
+ if( bPrinter_ || (mpServerFont[ nFallbackLevel ] != NULL) )
+ nRetVal |= SAL_SETFONT_USEDRAWTEXTARRAY;
+ return nRetVal;
+}
+
+// ----------------------------------------------------------------------------
+
+void
+X11SalGraphics::SetTextColor( SalColor nSalColor )
+{
+ if( nTextColor_ != nSalColor )
+ {
+ nTextColor_ = nSalColor;
+ nTextPixel_ = GetPixel( nSalColor );
+ bFontGC_ = FALSE;
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+bool X11SalGraphics::AddTempDevFont( ImplDevFontList* pFontList,
+ const String& rFileURL, const String& rFontName )
+{
+ // inform PSP font manager
+ rtl::OUString aUSystemPath;
+ OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFileURL, aUSystemPath ) );
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ OString aOFileName( OUStringToOString( aUSystemPath, aEncoding ) );
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ int nFontId = rMgr.addFontFile( aOFileName, 0 );
+ if( !nFontId )
+ return false;
+
+ // prepare font data
+ psp::FastPrintFontInfo aInfo;
+ rMgr.getFontFastInfo( nFontId, aInfo );
+ aInfo.m_aFamilyName = rFontName;
+
+ // inform glyph cache of new font
+ ImplDevFontAttributes aDFA = PspGraphics::Info2DevFontAttributes( aInfo );
+ aDFA.mnQuality += 5800;
+
+ int nFaceNum = rMgr.getFontFaceNumber( aInfo.m_nID );
+ if( nFaceNum < 0 )
+ nFaceNum = 0;
+
+ GlyphCache& rGC = X11GlyphCache::GetInstance();
+ const rtl::OString& rFileName = rMgr.getFontFileSysPath( aInfo.m_nID );
+ rGC.AddFontFile( rFileName, nFaceNum, aInfo.m_nID, aDFA );
+
+ // announce new font to device's font list
+ rGC.AnnounceFonts( pFontList );
+ return true;
+}
+
+// ----------------------------------------------------------------------------
+
+void RegisterFontSubstitutors( ImplDevFontList* );
+
+void X11SalGraphics::GetDevFontList( ImplDevFontList *pList )
+{
+ // allow disabling of native X11 fonts
+ static const char* pEnableX11FontStr = getenv( "SAL_ENABLE_NATIVE_XFONTS" );
+ if( pEnableX11FontStr && (pEnableX11FontStr[0] != '0') )
+ {
+ // announce X11 fonts
+ XlfdStorage* pX11FontList = GetDisplay()->GetXlfdList();
+ pX11FontList->AnnounceFonts( pList );
+ }
+
+ // prepare the GlyphCache using psprint's font infos
+ X11GlyphCache& rGC = X11GlyphCache::GetInstance();
+
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ ::std::list< psp::fontID > aList;
+ ::std::list< psp::fontID >::iterator it;
+ psp::FastPrintFontInfo aInfo;
+ rMgr.getFontList( aList );
+ for( it = aList.begin(); it != aList.end(); ++it )
+ {
+ if( !rMgr.getFontFastInfo( *it, aInfo ) )
+ continue;
+
+ // the GlyphCache must not bother with builtin fonts because
+ // it cannot access or use them anyway
+ if( aInfo.m_eType == psp::fonttype::Builtin )
+ continue;
+
+ // normalize face number to the GlyphCache
+ int nFaceNum = rMgr.getFontFaceNumber( aInfo.m_nID );
+ if( nFaceNum < 0 )
+ nFaceNum = 0;
+
+ // for fonts where extra kerning info can be provided on demand
+ // an ExtraKernInfo object is supplied
+ const ExtraKernInfo* pExtraKernInfo = NULL;
+ if( aInfo.m_eType == psp::fonttype::Type1 )
+ pExtraKernInfo = new PspKernInfo( *it );
+
+ // inform GlyphCache about this font provided by the PsPrint subsystem
+ ImplDevFontAttributes aDFA = PspGraphics::Info2DevFontAttributes( aInfo );
+ aDFA.mnQuality += 4096;
+ const rtl::OString& rFileName = rMgr.getFontFileSysPath( aInfo.m_nID );
+ rGC.AddFontFile( rFileName, nFaceNum, aInfo.m_nID, aDFA, pExtraKernInfo );
+ }
+
+ // announce glyphcache fonts
+ rGC.AnnounceFonts( pList );
+
+ // register platform specific font substitutions if available
+ if( rMgr.hasFontconfig() )
+ RegisterFontSubstitutors( pList );
+
+ ImplGetSVData()->maGDIData.mbNativeFontConfig = rMgr.hasFontconfig();
+}
+
+// ----------------------------------------------------------------------------
+
+void X11SalGraphics::GetDevFontSubstList( OutputDevice* )
+{
+ // no device specific font substitutions on X11 needed
+}
+
+// ----------------------------------------------------------------------------
+
+void cairosubcallback( void* pPattern )
+{
+ CairoWrapper& rCairo = CairoWrapper::get();
+ if( !rCairo.isValid() )
+ return;
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ const void* pFontOptions = rStyleSettings.GetCairoFontOptions();
+ if( !pFontOptions )
+ return;
+ rCairo.ft_font_options_substitute( pFontOptions, pPattern );
+}
+
+bool GetFCFontOptions( const ImplFontAttributes& rFontAttributes, int nSize,
+ ImplFontOptions& rFontOptions)
+{
+ // TODO: get rid of these insane enum-conversions
+ // e.g. by using the classic vclenum values inside VCL
+
+ psp::FastPrintFontInfo aInfo;
+ // set family name
+ aInfo.m_aFamilyName = rFontAttributes.GetFamilyName();
+ // set italic
+ switch( rFontAttributes.GetSlant() )
+ {
+ case ITALIC_NONE:
+ aInfo.m_eItalic = psp::italic::Upright;
+ break;
+ case ITALIC_NORMAL:
+ aInfo.m_eItalic = psp::italic::Italic;
+ break;
+ case ITALIC_OBLIQUE:
+ aInfo.m_eItalic = psp::italic::Oblique;
+ break;
+ default:
+ aInfo.m_eItalic = psp::italic::Unknown;
+ break;
+ }
+ // set weight
+ switch( rFontAttributes.GetWeight() )
+ {
+ case WEIGHT_THIN:
+ aInfo.m_eWeight = psp::weight::Thin;
+ break;
+ case WEIGHT_ULTRALIGHT:
+ aInfo.m_eWeight = psp::weight::UltraLight;
+ break;
+ case WEIGHT_LIGHT:
+ aInfo.m_eWeight = psp::weight::Light;
+ break;
+ case WEIGHT_SEMILIGHT:
+ aInfo.m_eWeight = psp::weight::SemiLight;
+ break;
+ case WEIGHT_NORMAL:
+ aInfo.m_eWeight = psp::weight::Normal;
+ break;
+ case WEIGHT_MEDIUM:
+ aInfo.m_eWeight = psp::weight::Medium;
+ break;
+ case WEIGHT_SEMIBOLD:
+ aInfo.m_eWeight = psp::weight::SemiBold;
+ break;
+ case WEIGHT_BOLD:
+ aInfo.m_eWeight = psp::weight::Bold;
+ break;
+ case WEIGHT_ULTRABOLD:
+ aInfo.m_eWeight = psp::weight::UltraBold;
+ break;
+ case WEIGHT_BLACK:
+ aInfo.m_eWeight = psp::weight::Black;
+ break;
+ default:
+ aInfo.m_eWeight = psp::weight::Unknown;
+ break;
+ }
+ // set width
+ switch( rFontAttributes.GetWidthType() )
+ {
+ case WIDTH_ULTRA_CONDENSED:
+ aInfo.m_eWidth = psp::width::UltraCondensed;
+ break;
+ case WIDTH_EXTRA_CONDENSED:
+ aInfo.m_eWidth = psp::width::ExtraCondensed;
+ break;
+ case WIDTH_CONDENSED:
+ aInfo.m_eWidth = psp::width::Condensed;
+ break;
+ case WIDTH_SEMI_CONDENSED:
+ aInfo.m_eWidth = psp::width::SemiCondensed;
+ break;
+ case WIDTH_NORMAL:
+ aInfo.m_eWidth = psp::width::Normal;
+ break;
+ case WIDTH_SEMI_EXPANDED:
+ aInfo.m_eWidth = psp::width::SemiExpanded;
+ break;
+ case WIDTH_EXPANDED:
+ aInfo.m_eWidth = psp::width::Expanded;
+ break;
+ case WIDTH_EXTRA_EXPANDED:
+ aInfo.m_eWidth = psp::width::ExtraExpanded;
+ break;
+ case WIDTH_ULTRA_EXPANDED:
+ aInfo.m_eWidth = psp::width::UltraExpanded;
+ break;
+ default:
+ aInfo.m_eWidth = psp::width::Unknown;
+ break;
+ }
+
+ const psp::PrintFontManager& rPFM = psp::PrintFontManager::get();
+ bool bOK = rPFM.getFontOptions( aInfo, nSize, cairosubcallback, rFontOptions);
+ return bOK;
+}
+
+// ----------------------------------------------------------------------------
+
+void
+X11SalGraphics::GetFontMetric( ImplFontMetricData *pMetric )
+{
+ if( mpServerFont[0] != NULL )
+ {
+ long rDummyFactor;
+ mpServerFont[0]->FetchFontMetric( *pMetric, rDummyFactor );
+ }
+ else if( mXFont[0] != NULL )
+ {
+ mXFont[0]->ToImplFontMetricData( pMetric );
+ if ( bFontVertical_ )
+ pMetric->mnOrientation = 0;
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+ULONG
+X11SalGraphics::GetKernPairs( ULONG nPairs, ImplKernPairData *pKernPairs )
+{
+ if( ! bPrinter_ )
+ {
+ if( mpServerFont[0] != NULL )
+ {
+ ImplKernPairData* pTmpKernPairs;
+ ULONG nGotPairs = mpServerFont[0]->GetKernPairs( &pTmpKernPairs );
+ for( unsigned int i = 0; i < nPairs && i < nGotPairs; ++i )
+ pKernPairs[ i ] = pTmpKernPairs[ i ];
+ delete[] pTmpKernPairs;
+ return nGotPairs;
+ }
+ }
+ return 0;
+}
+
+// ---------------------------------------------------------------------------
+
+BOOL X11SalGraphics::GetGlyphBoundRect( long nGlyphIndex, Rectangle& rRect )
+{
+ int nLevel = nGlyphIndex >> GF_FONTSHIFT;
+ if( nLevel >= MAX_FALLBACK )
+ return FALSE;
+
+ ServerFont* pSF = mpServerFont[ nLevel ];
+ if( !pSF )
+ return FALSE;
+
+ nGlyphIndex &= ~GF_FONTMASK;
+ const GlyphMetric& rGM = pSF->GetGlyphMetric( nGlyphIndex );
+ rRect = Rectangle( rGM.GetOffset(), rGM.GetSize() );
+ return TRUE;
+}
+
+// ---------------------------------------------------------------------------
+
+BOOL X11SalGraphics::GetGlyphOutline( long nGlyphIndex,
+ ::basegfx::B2DPolyPolygon& rPolyPoly )
+{
+ int nLevel = nGlyphIndex >> GF_FONTSHIFT;
+ if( nLevel >= MAX_FALLBACK )
+ return FALSE;
+
+ ServerFont* pSF = mpServerFont[ nLevel ];
+ if( !pSF )
+ return FALSE;
+
+ nGlyphIndex &= ~GF_FONTMASK;
+ if( pSF->GetGlyphOutline( nGlyphIndex, rPolyPoly ) )
+ return TRUE;
+
+ return FALSE;
+}
+
+//--------------------------------------------------------------------------
+
+SalLayout* X11SalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLevel )
+{
+ SalLayout* pLayout = NULL;
+
+ if( mpServerFont[ nFallbackLevel ]
+ && !(rArgs.mnFlags & SAL_LAYOUT_DISABLE_GLYPH_PROCESSING) )
+ {
+#ifdef ENABLE_GRAPHITE
+ // Is this a Graphite font?
+ if (!bDisableGraphite_ &&
+ GraphiteFontAdaptor::IsGraphiteEnabledFont(*mpServerFont[nFallbackLevel]))
+ {
+ sal_Int32 xdpi, ydpi;
+
+ xdpi = GetDisplay()->GetResolution().A();
+ ydpi = GetDisplay()->GetResolution().B();
+
+ GraphiteFontAdaptor * pGrfont = new GraphiteFontAdaptor( *mpServerFont[nFallbackLevel], xdpi, ydpi);
+ if (!pGrfont) return NULL;
+ pLayout = new GraphiteServerFontLayout(pGrfont);
+ }
+ else
+#endif
+ pLayout = new ServerFontLayout( *mpServerFont[ nFallbackLevel ] );
+ }
+ else if( mXFont[ nFallbackLevel ] )
+ pLayout = new X11FontLayout( *mXFont[ nFallbackLevel ] );
+ else
+ pLayout = NULL;
+
+ return pLayout;
+}
+
+//--------------------------------------------------------------------------
+
+SystemFontData X11SalGraphics::GetSysFontData( int nFallbacklevel ) const
+{
+ SystemFontData aSysFontData;
+ aSysFontData.nSize = sizeof( SystemFontData );
+ aSysFontData.nFontId = 0;
+
+ if (nFallbacklevel >= MAX_FALLBACK) nFallbacklevel = MAX_FALLBACK - 1;
+ if (nFallbacklevel < 0 ) nFallbacklevel = 0;
+
+ if (mpServerFont[nFallbacklevel] != NULL)
+ {
+ ServerFont* rFont = mpServerFont[nFallbacklevel];
+ aSysFontData.nFontId = rFont->GetFtFace();
+ aSysFontData.nFontFlags = rFont->GetLoadFlags();
+ aSysFontData.bFakeBold = rFont->NeedsArtificialBold();
+ aSysFontData.bFakeItalic = rFont->NeedsArtificialItalic();
+ aSysFontData.bAntialias = rFont->GetAntialiasAdvice();
+ aSysFontData.bVerticalCharacterType = rFont->GetFontSelData().mbVertical;
+ }
+
+ return aSysFontData;
+}
+
+//--------------------------------------------------------------------------
+
+BOOL X11SalGraphics::CreateFontSubset(
+ const rtl::OUString& rToFile,
+ const ImplFontData* pFont,
+ sal_Int32* pGlyphIDs,
+ sal_uInt8* pEncoding,
+ sal_Int32* pWidths,
+ int nGlyphCount,
+ FontSubsetInfo& rInfo
+ )
+{
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+
+ psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ bool bSuccess = rMgr.createFontSubset( rInfo,
+ aFont,
+ rToFile,
+ pGlyphIDs,
+ pEncoding,
+ pWidths,
+ nGlyphCount );
+ return bSuccess;
+}
+
+//--------------------------------------------------------------------------
+
+const void* X11SalGraphics::GetEmbedFontData( const ImplFontData* pFont, const sal_Ucs* pUnicodes, sal_Int32* pWidths, FontSubsetInfo& rInfo, long* pDataLen )
+{
+#ifndef _USE_PRINT_EXTENSION_
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+ return PspGraphics::DoGetEmbedFontData( aFont, pUnicodes, pWidths, rInfo, pDataLen );
+#else
+ return NULL;
+#endif
+}
+
+//--------------------------------------------------------------------------
+
+void X11SalGraphics::FreeEmbedFontData( const void* pData, long nLen )
+{
+#ifndef _USE_PRINT_EXTENSION_
+ PspGraphics::DoFreeEmbedFontData( pData, nLen );
+#endif
+}
+
+//--------------------------------------------------------------------------
+
+const Ucs2SIntMap* X11SalGraphics::GetFontEncodingVector( const ImplFontData* pFont, const Ucs2OStrMap** pNonEncoded )
+{
+#ifndef _USE_PRINT_EXTENSION_
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+ return PspGraphics::DoGetFontEncodingVector( aFont, pNonEncoded );
+#else
+ return NULL;
+#endif
+}
+
+//--------------------------------------------------------------------------
+
+void X11SalGraphics::GetGlyphWidths( const ImplFontData* pFont,
+ bool bVertical,
+ Int32Vector& rWidths,
+ Ucs2UIntMap& rUnicodeEnc )
+{
+ // in this context the pFont->GetFontId() is a valid PSP
+ // font since they are the only ones left after the PDF
+ // export has filtered its list of subsettable fonts (for
+ // which this method was created). The correct way would
+ // be to have the GlyphCache search for the ImplFontData pFont
+ psp::fontID aFont = pFont->GetFontId();
+ PspGraphics::DoGetGlyphWidths( aFont, bVertical, rWidths, rUnicodeEnc );
+}
+
+// ===========================================================================
+// platform specific font substitution hooks
+
+class FcPreMatchSubstititution
+: public ImplPreMatchFontSubstitution
+{
+public:
+ bool FindFontSubstitute( ImplFontSelectData& ) const;
+};
+
+class FcGlyphFallbackSubstititution
+: public ImplGlyphFallbackFontSubstitution
+{
+ // TODO: add a cache
+public:
+ bool FindFontSubstitute( ImplFontSelectData&, OUString& rMissingCodes ) const;
+};
+
+void RegisterFontSubstitutors( ImplDevFontList* pList )
+{
+ // init font substitution defaults
+ int nDisableBits = 0;
+#ifdef SOLARIS
+ nDisableBits = 1; // disable "font fallback" here on default
+#endif
+ // apply the environment variable if any
+ const char* pEnvStr = ::getenv( "SAL_DISABLE_FC_SUBST" );
+ if( pEnvStr )
+ {
+ if( (*pEnvStr >= '0') && (*pEnvStr <= '9') )
+ nDisableBits = (*pEnvStr - '0');
+ else
+ nDisableBits = ~0U; // no specific bits set: disable all
+ }
+
+ // register font fallback substitutions (unless disabled by bit0)
+ if( (nDisableBits & 1) == 0 )
+ {
+ static FcPreMatchSubstititution aSubstPreMatch;
+ pList->SetPreMatchHook( &aSubstPreMatch );
+ }
+
+ // register glyph fallback substitutions (unless disabled by bit1)
+ if( (nDisableBits & 2) == 0 )
+ {
+ static FcGlyphFallbackSubstititution aSubstFallback;
+ pList->SetFallbackHook( &aSubstFallback );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static ImplFontSelectData GetFcSubstitute(const ImplFontSelectData &rFontSelData, OUString& rMissingCodes )
+{
+ ImplFontSelectData aRet(rFontSelData);
+
+ const rtl::OString aLangAttrib = MsLangId::convertLanguageToIsoByteString( rFontSelData.meLanguage );
+
+ psp::italic::type eItalic = psp::italic::Unknown;
+ if( rFontSelData.GetSlant() != ITALIC_DONTKNOW )
+ {
+ switch( rFontSelData.GetSlant() )
+ {
+ case ITALIC_NONE: eItalic = psp::italic::Upright; break;
+ case ITALIC_NORMAL: eItalic = psp::italic::Italic; break;
+ case ITALIC_OBLIQUE: eItalic = psp::italic::Oblique; break;
+ default:
+ break;
+ }
+ }
+
+ psp::weight::type eWeight = psp::weight::Unknown;
+ if( rFontSelData.GetWeight() != WEIGHT_DONTKNOW )
+ {
+ switch( rFontSelData.GetWeight() )
+ {
+ case WEIGHT_THIN: eWeight = psp::weight::Thin; break;
+ case WEIGHT_ULTRALIGHT: eWeight = psp::weight::UltraLight; break;
+ case WEIGHT_LIGHT: eWeight = psp::weight::Light; break;
+ case WEIGHT_SEMILIGHT: eWeight = psp::weight::SemiLight; break;
+ case WEIGHT_NORMAL: eWeight = psp::weight::Normal; break;
+ case WEIGHT_MEDIUM: eWeight = psp::weight::Medium; break;
+ case WEIGHT_SEMIBOLD: eWeight = psp::weight::SemiBold; break;
+ case WEIGHT_BOLD: eWeight = psp::weight::Bold; break;
+ case WEIGHT_ULTRABOLD: eWeight = psp::weight::UltraBold; break;
+ case WEIGHT_BLACK: eWeight = psp::weight::Black; break;
+ default:
+ break;
+ }
+ }
+
+ psp::width::type eWidth = psp::width::Unknown;
+ if( rFontSelData.GetWidthType() != WIDTH_DONTKNOW )
+ {
+ switch( rFontSelData.GetWidthType() )
+ {
+ case WIDTH_ULTRA_CONDENSED: eWidth = psp::width::UltraCondensed; break;
+ case WIDTH_EXTRA_CONDENSED: eWidth = psp::width::ExtraCondensed; break;
+ case WIDTH_CONDENSED: eWidth = psp::width::Condensed; break;
+ case WIDTH_SEMI_CONDENSED: eWidth = psp::width::SemiCondensed; break;
+ case WIDTH_NORMAL: eWidth = psp::width::Normal; break;
+ case WIDTH_SEMI_EXPANDED: eWidth = psp::width::SemiExpanded; break;
+ case WIDTH_EXPANDED: eWidth = psp::width::Expanded; break;
+ case WIDTH_EXTRA_EXPANDED: eWidth = psp::width::ExtraExpanded; break;
+ case WIDTH_ULTRA_EXPANDED: eWidth = psp::width::UltraExpanded; break;
+ default:
+ break;
+ }
+ }
+
+ psp::pitch::type ePitch = psp::pitch::Unknown;
+ if( rFontSelData.GetPitch() != PITCH_DONTKNOW )
+ {
+ switch( rFontSelData.GetPitch() )
+ {
+ case PITCH_FIXED: ePitch=psp::pitch::Fixed; break;
+ case PITCH_VARIABLE: ePitch=psp::pitch::Variable; break;
+ default:
+ break;
+ }
+ }
+
+ const psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+ aRet.maSearchName = rMgr.Substitute( rFontSelData.maTargetName, rMissingCodes, aLangAttrib, eItalic, eWeight, eWidth, ePitch);
+
+ switch (eItalic)
+ {
+ case psp::italic::Upright: aRet.meItalic = ITALIC_NONE; break;
+ case psp::italic::Italic: aRet.meItalic = ITALIC_NORMAL; break;
+ case psp::italic::Oblique: aRet.meItalic = ITALIC_OBLIQUE; break;
+ default:
+ break;
+ }
+
+ switch (eWeight)
+ {
+ case psp::weight::Thin: aRet.meWeight = WEIGHT_THIN; break;
+ case psp::weight::UltraLight: aRet.meWeight = WEIGHT_ULTRALIGHT; break;
+ case psp::weight::Light: aRet.meWeight = WEIGHT_LIGHT; break;
+ case psp::weight::SemiLight: aRet.meWeight = WEIGHT_SEMILIGHT; break;
+ case psp::weight::Normal: aRet.meWeight = WEIGHT_NORMAL; break;
+ case psp::weight::Medium: aRet.meWeight = WEIGHT_MEDIUM; break;
+ case psp::weight::SemiBold: aRet.meWeight = WEIGHT_SEMIBOLD; break;
+ case psp::weight::Bold: aRet.meWeight = WEIGHT_BOLD; break;
+ case psp::weight::UltraBold: aRet.meWeight = WEIGHT_ULTRABOLD; break;
+ case psp::weight::Black: aRet.meWeight = WEIGHT_BLACK; break;
+ default:
+ break;
+ }
+
+ switch (eWidth)
+ {
+ case psp::width::UltraCondensed: aRet.meWidthType = WIDTH_ULTRA_CONDENSED; break;
+ case psp::width::ExtraCondensed: aRet.meWidthType = WIDTH_EXTRA_CONDENSED; break;
+ case psp::width::Condensed: aRet.meWidthType = WIDTH_CONDENSED; break;
+ case psp::width::SemiCondensed: aRet.meWidthType = WIDTH_SEMI_CONDENSED; break;
+ case psp::width::Normal: aRet.meWidthType = WIDTH_NORMAL; break;
+ case psp::width::SemiExpanded: aRet.meWidthType = WIDTH_SEMI_EXPANDED; break;
+ case psp::width::Expanded: aRet.meWidthType = WIDTH_EXPANDED; break;
+ case psp::width::ExtraExpanded: aRet.meWidthType = WIDTH_EXTRA_EXPANDED; break;
+ case psp::width::UltraExpanded: aRet.meWidthType = WIDTH_ULTRA_EXPANDED; break;
+ default:
+ break;
+ }
+
+ switch (ePitch)
+ {
+ case psp::pitch::Fixed: aRet.mePitch = PITCH_FIXED; break;
+ case psp::pitch::Variable: aRet.mePitch = PITCH_VARIABLE; break;
+ default:
+ break;
+ }
+
+ return aRet;
+}
+
+namespace
+{
+ bool uselessmatch(const ImplFontSelectData &rOrig, const ImplFontSelectData &rNew)
+ {
+ return
+ (
+ rOrig.maTargetName == rNew.maSearchName &&
+ rOrig.meWeight == rNew.meWeight &&
+ rOrig.meItalic == rNew.meItalic &&
+ rOrig.mePitch == rNew.mePitch &&
+ rOrig.meWidthType == rNew.meWidthType
+ );
+ }
+}
+
+//--------------------------------------------------------------------------
+
+bool FcPreMatchSubstititution::FindFontSubstitute( ImplFontSelectData &rFontSelData ) const
+{
+ // We dont' actually want to talk to Fontconfig at all for symbol fonts
+ if( rFontSelData.IsSymbolFont() )
+ return false;
+ // StarSymbol is a unicode font, but it still deserves the symbol flag
+ if( 0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "starsymbol", 10)
+ || 0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "opensymbol", 10) )
+ return false;
+
+ rtl::OUString aDummy;
+ const ImplFontSelectData aOut = GetFcSubstitute( rFontSelData, aDummy );
+ // TODO: cache the font substitution suggestion
+ // FC doing it would be preferable because it knows the invariables
+ // e.g. FC knows the FC rule that all Arial gets replaced by LiberationSans
+ // whereas we would have to check for every size or attribute
+ if( !aOut.maSearchName.Len() )
+ return false;
+
+ const bool bHaveSubstitute = !uselessmatch( rFontSelData, aOut );
+
+#ifdef DEBUG
+ const ByteString aOrigName( rFontSelData.maTargetName, RTL_TEXTENCODING_UTF8 );
+ const ByteString aSubstName( aOut.maSearchName, RTL_TEXTENCODING_UTF8 );
+ printf( "FcPreMatchSubstititution \"%s\" bipw=%d%d%d%d -> ",
+ aOrigName.GetBuffer(), rFontSelData.meWeight, rFontSelData.meItalic,
+ rFontSelData.mePitch, rFontSelData.meWidthType );
+ if( !bHaveSubstitute )
+ printf( "no substitute available\n" );
+ else
+ printf( "\"%s\" bipw=%d%d%d%d\n", aSubstName.GetBuffer(),
+ aOut.meWeight, aOut.meItalic, aOut.mePitch, aOut.meWidthType );
+#endif
+
+ if( bHaveSubstitute )
+ rFontSelData = aOut;
+
+ return bHaveSubstitute;
+}
+
+// -----------------------------------------------------------------------
+
+bool FcGlyphFallbackSubstititution::FindFontSubstitute( ImplFontSelectData& rFontSelData,
+ rtl::OUString& rMissingCodes ) const
+{
+ // We dont' actually want to talk to Fontconfig at all for symbol fonts
+ if( rFontSelData.IsSymbolFont() )
+ return false;
+ // StarSymbol is a unicode font, but it still deserves the symbol flag
+ if( 0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "starsymbol", 10)
+ || 0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "opensymbol", 10) )
+ return false;
+
+ const ImplFontSelectData aOut = GetFcSubstitute( rFontSelData, rMissingCodes );
+ // TODO: cache the unicode + srcfont specific result
+ // FC doing it would be preferable because it knows the invariables
+ // e.g. FC knows the FC rule that all Arial gets replaced by LiberationSans
+ // whereas we would have to check for every size or attribute
+ if( !aOut.maSearchName.Len() )
+ return false;
+
+ const bool bHaveSubstitute = !uselessmatch( rFontSelData, aOut );
+
+#ifdef DEBUG
+ const ByteString aOrigName( rFontSelData.maTargetName, RTL_TEXTENCODING_UTF8 );
+ const ByteString aSubstName( aOut.maSearchName, RTL_TEXTENCODING_UTF8 );
+ printf( "FcGFSubstititution \"%s\" bipw=%d%d%d%d ->",
+ aOrigName.GetBuffer(), rFontSelData.meWeight, rFontSelData.meItalic,
+ rFontSelData.mePitch, rFontSelData.meWidthType );
+ if( !bHaveSubstitute )
+ printf( "no substitute available\n" );
+ else
+ printf( "\"%s\" bipw=%d%d%d%d\n", aSubstName.GetBuffer(),
+ aOut.meWeight, aOut.meItalic, aOut.mePitch, aOut.meWidthType );
+#endif
+
+ if( bHaveSubstitute )
+ rFontSelData = aOut;
+
+ return bHaveSubstitute;
+}
+
+// ===========================================================================
+
diff --git a/vcl/unx/source/gdi/salprnpsp.cxx b/vcl/unx/source/gdi/salprnpsp.cxx
new file mode 100644
index 000000000000..90c6a196143e
--- /dev/null
+++ b/vcl/unx/source/gdi/salprnpsp.cxx
@@ -0,0 +1,1167 @@
+/*************************************************************************
+ *
+ * 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"
+
+/**
+ this file implements the sal printer interface ( SalPrinter, SalInfoPrinter
+ and some printer relevant methods of SalInstance and SalGraphicsData )
+
+ as aunderlying library the printer features of psprint are used.
+
+ The query methods of a SalInfoPrinter are implemented by querying psprint
+
+ The job methods of a SalPrinter are implemented by calling psprint
+ printer job functions.
+ */
+
+#include <salunx.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+
+#include "saldisp.hxx"
+#include "salinst.h"
+#include "salprn.h"
+#include "salframe.h"
+#include "pspgraphics.h"
+#include "saldata.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/jobset.h"
+#include "vcl/print.h"
+#include "vcl/salptype.hxx"
+#include "vcl/printerinfomanager.hxx"
+
+#include "rtl/ustring.hxx"
+
+#include "osl/module.h"
+
+using namespace psp;
+using namespace rtl;
+
+/*
+ * static helpers
+ */
+
+#include "rtsname.hxx"
+
+static oslModule driverLib = NULL;
+extern "C"
+{
+typedef int(*setupFunction)(PrinterInfo&);
+static setupFunction pSetupFunction = NULL;
+typedef int(*faxFunction)(String&);
+static faxFunction pFaxNrFunction = NULL;
+}
+
+static String getPdfDir( const PrinterInfo& rInfo )
+{
+ String aDir;
+ sal_Int32 nIndex = 0;
+ while( nIndex != -1 )
+ {
+ OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
+ if( ! aToken.compareToAscii( "pdf=", 4 ) )
+ {
+ sal_Int32 nPos = 0;
+ aDir = aToken.getToken( 1, '=', nPos );
+ if( ! aDir.Len() )
+ aDir = String( ByteString( getenv( "HOME" ) ), osl_getThreadTextEncoding() );
+ break;
+ }
+ }
+ return aDir;
+}
+
+static void getPaLib()
+{
+ if( ! driverLib )
+ {
+ OUString aLibName( RTL_CONSTASCII_USTRINGPARAM( _XSALSET_LIBNAME ) );
+ driverLib = osl_loadModuleRelative( (oslGenericFunction)getPaLib, aLibName.pData, SAL_LOADMODULE_DEFAULT );
+ if ( !driverLib )
+ {
+ return;
+ }
+
+ pSetupFunction = (setupFunction)osl_getAsciiFunctionSymbol( driverLib, "Sal_SetupPrinterDriver" );
+ if ( !pSetupFunction )
+ fprintf( stderr, "could not resolve Sal_SetupPrinterDriver\n" );
+
+ pFaxNrFunction = (faxFunction)osl_getAsciiFunctionSymbol( driverLib, "Sal_queryFaxNumber" );
+ if ( !pFaxNrFunction )
+ fprintf( stderr, "could not resolve Sal_queryFaxNumber\n" );
+ }
+}
+
+inline int PtTo10Mu( int nPoints ) { return (int)((((double)nPoints)*35.27777778)+0.5); }
+
+inline int TenMuToPt( int nUnits ) { return (int)((((double)nUnits)/35.27777778)+0.5); }
+
+static void copyJobDataToJobSetup( ImplJobSetup* pJobSetup, JobData& rData )
+{
+ pJobSetup->meOrientation = (Orientation)(rData.m_eOrientation == orientation::Landscape ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT);
+
+ // copy page size
+ String aPaper;
+ int width, height;
+
+ rData.m_aContext.getPageSize( aPaper, width, height );
+ pJobSetup->mePaperFormat = PaperInfo::fromPSName(OUStringToOString( aPaper, RTL_TEXTENCODING_ISO_8859_1 ));
+
+ pJobSetup->mnPaperWidth = 0;
+ pJobSetup->mnPaperHeight = 0;
+ if( pJobSetup->mePaperFormat == PAPER_USER )
+ {
+ // transform to 100dth mm
+ width = PtTo10Mu( width );
+ height = PtTo10Mu( height );
+
+ if( rData.m_eOrientation == psp::orientation::Portrait )
+ {
+ pJobSetup->mnPaperWidth = width;
+ pJobSetup->mnPaperHeight= height;
+ }
+ else
+ {
+ pJobSetup->mnPaperWidth = height;
+ pJobSetup->mnPaperHeight= width;
+ }
+ }
+
+ // copy input slot
+ const PPDKey* pKey = NULL;
+ const PPDValue* pValue = NULL;
+
+ pJobSetup->mnPaperBin = 0;
+ if( rData.m_pParser )
+ pKey = rData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) );
+ if( pKey )
+ pValue = rData.m_aContext.getValue( pKey );
+ if( pKey && pValue )
+ {
+ for( pJobSetup->mnPaperBin = 0;
+ pValue != pKey->getValue( pJobSetup->mnPaperBin ) &&
+ pJobSetup->mnPaperBin < pKey->countValues();
+ pJobSetup->mnPaperBin++ )
+ ;
+ if( pJobSetup->mnPaperBin >= pKey->countValues() )
+ pJobSetup->mnPaperBin = 0;
+ }
+
+ // copy duplex
+ pKey = NULL;
+ pValue = NULL;
+
+ pJobSetup->meDuplexMode = DUPLEX_UNKNOWN;
+ if( rData.m_pParser )
+ pKey = rData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) );
+ if( pKey )
+ pValue = rData.m_aContext.getValue( pKey );
+ if( pKey && pValue )
+ {
+ if( pValue->m_aOption.EqualsIgnoreCaseAscii( "None" ) ||
+ pValue->m_aOption.EqualsIgnoreCaseAscii( "Simplex", 0, 7 )
+ )
+ {
+ pJobSetup->meDuplexMode = DUPLEX_OFF;
+ }
+ else if( pValue->m_aOption.EqualsIgnoreCaseAscii( "DuplexNoTumble" ) )
+ {
+ pJobSetup->meDuplexMode = DUPLEX_LONGEDGE;
+ }
+ else if( pValue->m_aOption.EqualsIgnoreCaseAscii( "DuplexTumble" ) )
+ {
+ pJobSetup->meDuplexMode = DUPLEX_SHORTEDGE;
+ }
+ }
+
+ // copy the whole context
+ if( pJobSetup->mpDriverData )
+ rtl_freeMemory( pJobSetup->mpDriverData );
+
+ int nBytes;
+ void* pBuffer = NULL;
+ if( rData.getStreamBuffer( pBuffer, nBytes ) )
+ {
+ pJobSetup->mnDriverDataLen = nBytes;
+ pJobSetup->mpDriverData = (BYTE*)pBuffer;
+ }
+ else
+ {
+ pJobSetup->mnDriverDataLen = 0;
+ pJobSetup->mpDriverData = NULL;
+ }
+}
+
+static bool passFileToCommandLine( const String& rFilename, const String& rCommandLine, bool bRemoveFile = true )
+{
+ bool bSuccess = false;
+
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ ByteString aCmdLine( rCommandLine, aEncoding );
+ ByteString aFilename( rFilename, aEncoding );
+
+ bool bPipe = aCmdLine.Search( "(TMP)" ) != STRING_NOTFOUND ? false : true;
+
+ // setup command line for exec
+ if( ! bPipe )
+ while( aCmdLine.SearchAndReplace( "(TMP)", aFilename ) != STRING_NOTFOUND )
+ ;
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%s commandline: \"%s\"\n",
+ bPipe ? "piping to" : "executing",
+ aCmdLine.GetBuffer() );
+ struct stat aStat;
+ if( stat( aFilename.GetBuffer(), &aStat ) )
+ fprintf( stderr, "stat( %s ) failed\n", aFilename.GetBuffer() );
+ fprintf( stderr, "Tmp file %s has modes: 0%03lo\n", aFilename.GetBuffer(), (long)aStat.st_mode );
+#endif
+ const char* argv[4];
+ if( ! ( argv[ 0 ] = getenv( "SHELL" ) ) )
+ argv[ 0 ] = "/bin/sh";
+ argv[ 1 ] = "-c";
+ argv[ 2 ] = aCmdLine.GetBuffer();
+ argv[ 3 ] = 0;
+
+ bool bHavePipes = false;
+ int pid, fd[2];
+
+ if( bPipe )
+ bHavePipes = pipe( fd ) ? false : true;
+ if( ( pid = fork() ) > 0 )
+ {
+ if( bPipe && bHavePipes )
+ {
+ close( fd[0] );
+ char aBuffer[ 2048 ];
+ FILE* fp = fopen( aFilename.GetBuffer(), "r" );
+ while( fp && ! feof( fp ) )
+ {
+ int nBytes = fread( aBuffer, 1, sizeof( aBuffer ), fp );
+ if( nBytes )
+ write( fd[ 1 ], aBuffer, nBytes );
+ }
+ fclose( fp );
+ close( fd[ 1 ] );
+ }
+ int status = 0;
+ waitpid( pid, &status, 0 );
+ if( ! status )
+ bSuccess = true;
+ }
+ else if( ! pid )
+ {
+ if( bPipe && bHavePipes )
+ {
+ close( fd[1] );
+ if( fd[0] != STDIN_FILENO ) // not probable, but who knows :)
+ dup2( fd[0], STDIN_FILENO );
+ }
+ execv( argv[0], const_cast<char**>(argv) );
+ fprintf( stderr, "failed to execute \"%s\"\n", aCmdLine.GetBuffer() );
+ _exit( 1 );
+ }
+ else
+ fprintf( stderr, "failed to fork\n" );
+
+ // clean up the mess
+ if( bRemoveFile )
+ unlink( aFilename.GetBuffer() );
+
+ return bSuccess;
+}
+
+static bool sendAFax( const String& rFaxNumber, const String& rFileName, const String& rCommand )
+{
+ std::list< OUString > aFaxNumbers;
+
+ if( ! rFaxNumber.Len() )
+ {
+ getPaLib();
+ if( pFaxNrFunction )
+ {
+ String aNewNr;
+ if( pFaxNrFunction( aNewNr ) )
+ aFaxNumbers.push_back( OUString( aNewNr ) );
+ }
+ }
+ else
+ {
+ sal_Int32 nIndex = 0;
+ OUString aFaxes( rFaxNumber );
+ OUString aBeginToken( RTL_CONSTASCII_USTRINGPARAM("<Fax#>") );
+ OUString aEndToken( RTL_CONSTASCII_USTRINGPARAM("</Fax#>") );
+ while( nIndex != -1 )
+ {
+ nIndex = aFaxes.indexOf( aBeginToken, nIndex );
+ if( nIndex != -1 )
+ {
+ sal_Int32 nBegin = nIndex + aBeginToken.getLength();
+ nIndex = aFaxes.indexOf( aEndToken, nIndex );
+ if( nIndex != -1 )
+ {
+ aFaxNumbers.push_back( aFaxes.copy( nBegin, nIndex-nBegin ) );
+ nIndex += aEndToken.getLength();
+ }
+ }
+ }
+ }
+
+ bool bSuccess = true;
+ if( aFaxNumbers.begin() != aFaxNumbers.end() )
+ {
+ while( aFaxNumbers.begin() != aFaxNumbers.end() && bSuccess )
+ {
+ String aCmdLine( rCommand );
+ String aFaxNumber( aFaxNumbers.front() );
+ aFaxNumbers.pop_front();
+ while( aCmdLine.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "(PHONE)" ) ), aFaxNumber ) != STRING_NOTFOUND )
+ ;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "sending fax to \"%s\"\n", OUStringToOString( aFaxNumber, osl_getThreadTextEncoding() ).getStr() );
+#endif
+ bSuccess = passFileToCommandLine( rFileName, aCmdLine, false );
+ }
+ }
+ else
+ bSuccess = false;
+
+ // clean up temp file
+ unlink( ByteString( rFileName, osl_getThreadTextEncoding() ).GetBuffer() );
+
+ return bSuccess;
+}
+
+static bool createPdf( const String& rToFile, const String& rFromFile, const String& rCommandLine )
+{
+ String aCommandLine( rCommandLine );
+ while( aCommandLine.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "(OUTFILE)" ) ), rToFile ) != STRING_NOTFOUND )
+ ;
+ return passFileToCommandLine( rFromFile, aCommandLine );
+}
+
+/*
+ * SalInstance
+ */
+
+// -----------------------------------------------------------------------
+
+SalInfoPrinter* X11SalInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
+ ImplJobSetup* pJobSetup )
+{
+ mbPrinterInit = true;
+ // create and initialize SalInfoPrinter
+ PspSalInfoPrinter* pPrinter = new PspSalInfoPrinter;
+
+ if( pJobSetup )
+ {
+ PrinterInfoManager& rManager( PrinterInfoManager::get() );
+ PrinterInfo aInfo( rManager.getPrinterInfo( pQueueInfo->maPrinterName ) );
+ pPrinter->m_aJobData = aInfo;
+ pPrinter->m_aPrinterGfx.Init( pPrinter->m_aJobData );
+
+ if( pJobSetup->mpDriverData )
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aInfo );
+
+ pJobSetup->mnSystem = JOBSETUP_SYSTEM_UNIX;
+ pJobSetup->maPrinterName = pQueueInfo->maPrinterName;
+ pJobSetup->maDriver = aInfo.m_aDriverName;
+ copyJobDataToJobSetup( pJobSetup, aInfo );
+
+ // set/clear backwards compatibility flag
+ bool bStrictSO52Compatibility = false;
+ std::hash_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it =
+ pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StrictSO52Compatibility" ) ) );
+
+ if( compat_it != pJobSetup->maValueMap.end() )
+ {
+ if( compat_it->second.equalsIgnoreAsciiCaseAscii( "true" ) )
+ bStrictSO52Compatibility = true;
+ }
+ pPrinter->m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility );
+ }
+
+
+ return pPrinter;
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter )
+{
+ delete pPrinter;
+}
+
+// -----------------------------------------------------------------------
+
+SalPrinter* X11SalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter )
+{
+ mbPrinterInit = true;
+ // create and initialize SalPrinter
+ PspSalPrinter* pPrinter = new PspSalPrinter( pInfoPrinter );
+ pPrinter->m_aJobData = static_cast<PspSalInfoPrinter*>(pInfoPrinter)->m_aJobData;
+
+ return pPrinter;
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalInstance::DestroyPrinter( SalPrinter* pPrinter )
+{
+ delete pPrinter;
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList )
+{
+ mbPrinterInit = true;
+ PrinterInfoManager& rManager( PrinterInfoManager::get() );
+ static const char* pNoSyncDetection = getenv( "SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION" );
+ if( ! pNoSyncDetection || ! *pNoSyncDetection )
+ {
+ // #i62663# synchronize possible asynchronouse printer detection now
+ rManager.checkPrintersChanged( true );
+ }
+ ::std::list< OUString > aPrinters;
+ rManager.listPrinters( aPrinters );
+
+ for( ::std::list< OUString >::iterator it = aPrinters.begin(); it != aPrinters.end(); ++it )
+ {
+ const PrinterInfo& rInfo( rManager.getPrinterInfo( *it ) );
+ // Neuen Eintrag anlegen
+ SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo;
+ pInfo->maPrinterName = *it;
+ pInfo->maDriver = rInfo.m_aDriverName;
+ pInfo->maLocation = rInfo.m_aLocation;
+ pInfo->maComment = rInfo.m_aComment;
+ pInfo->mpSysData = NULL;
+
+ sal_Int32 nIndex = 0;
+ while( nIndex != -1 )
+ {
+ String aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
+ if( aToken.CompareToAscii( "pdf=", 4 ) == COMPARE_EQUAL )
+ {
+ pInfo->maLocation = getPdfDir( rInfo );
+ break;
+ }
+ }
+
+ pList->Add( pInfo );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo )
+{
+ delete pInfo;
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalInstance::GetPrinterQueueState( SalPrinterQueueInfo* )
+{
+ mbPrinterInit = true;
+}
+
+// -----------------------------------------------------------------------
+
+String X11SalInstance::GetDefaultPrinter()
+{
+ mbPrinterInit = true;
+ PrinterInfoManager& rManager( PrinterInfoManager::get() );
+ return rManager.getDefaultPrinter();
+}
+
+// =======================================================================
+
+PspSalInfoPrinter::PspSalInfoPrinter()
+{
+ m_pGraphics = NULL;
+ m_bPapersInit = false;
+}
+
+// -----------------------------------------------------------------------
+
+PspSalInfoPrinter::~PspSalInfoPrinter()
+{
+ if( m_pGraphics )
+ {
+ delete m_pGraphics;
+ m_pGraphics = NULL;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void PspSalInfoPrinter::InitPaperFormats( const ImplJobSetup* )
+{
+ m_aPaperFormats.clear();
+ m_bPapersInit = true;
+
+ if( m_aJobData.m_pParser )
+ {
+ const PPDKey* pKey = m_aJobData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
+ if( pKey )
+ {
+ int nValues = pKey->countValues();
+ for( int i = 0; i < nValues; i++ )
+ {
+ const PPDValue* pValue = pKey->getValue( i );
+ int nWidth = 0, nHeight = 0;
+ m_aJobData.m_pParser->getPaperDimension( pValue->m_aOption, nWidth, nHeight );
+ PaperInfo aInfo(PtTo10Mu( nWidth ), PtTo10Mu( nHeight ));
+ m_aPaperFormats.push_back( aInfo );
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+int PspSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* )
+{
+ return 900;
+}
+
+// -----------------------------------------------------------------------
+
+SalGraphics* PspSalInfoPrinter::GetGraphics()
+{
+ // return a valid pointer only once
+ // the reasoning behind this is that we could have different
+ // SalGraphics that can run in multiple threads
+ // (future plans)
+ SalGraphics* pRet = NULL;
+ if( ! m_pGraphics )
+ {
+ m_pGraphics = new PspGraphics( &m_aJobData, &m_aPrinterGfx, NULL, false, this );
+ m_pGraphics->SetLayout( 0 );
+ pRet = m_pGraphics;
+ }
+ return pRet;
+}
+
+// -----------------------------------------------------------------------
+
+void PspSalInfoPrinter::ReleaseGraphics( SalGraphics* pGraphics )
+{
+ if( pGraphics == m_pGraphics )
+ {
+ delete pGraphics;
+ m_pGraphics = NULL;
+ }
+ return;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL PspSalInfoPrinter::Setup( SalFrame* pFrame, ImplJobSetup* pJobSetup )
+{
+ if( ! pFrame || ! pJobSetup )
+ return FALSE;
+
+ getPaLib();
+
+ if( ! pSetupFunction )
+ return FALSE;
+
+ PrinterInfoManager& rManager = PrinterInfoManager::get();
+
+ PrinterInfo aInfo( rManager.getPrinterInfo( pJobSetup->maPrinterName ) );
+ if ( pJobSetup->mpDriverData )
+ {
+ SetData( ~0, pJobSetup );
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aInfo );
+ }
+
+ if( pSetupFunction( aInfo ) )
+ {
+ rtl_freeMemory( pJobSetup->mpDriverData );
+ pJobSetup->mpDriverData = NULL;
+
+ int nBytes;
+ void* pBuffer = NULL;
+ aInfo.getStreamBuffer( pBuffer, nBytes );
+ pJobSetup->mnDriverDataLen = nBytes;
+ pJobSetup->mpDriverData = (BYTE*)pBuffer;
+
+ // copy everything to job setup
+ copyJobDataToJobSetup( pJobSetup, aInfo );
+ return TRUE;
+ }
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+// This function gets the driver data and puts it into pJobSetup
+// If pJobSetup->mpDriverData is NOT NULL, then the independend
+// data should be merged into the driver data
+// If pJobSetup->mpDriverData IS NULL, then the driver defaults
+// should be merged into the independent data
+BOOL PspSalInfoPrinter::SetPrinterData( ImplJobSetup* pJobSetup )
+{
+ // set/clear backwards compatibility flag
+ bool bStrictSO52Compatibility = false;
+ std::hash_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it =
+ pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StrictSO52Compatibility" ) ) );
+
+ if( compat_it != pJobSetup->maValueMap.end() )
+ {
+ if( compat_it->second.equalsIgnoreAsciiCaseAscii( "true" ) )
+ bStrictSO52Compatibility = true;
+ }
+ m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility );
+
+ if( pJobSetup->mpDriverData )
+ return SetData( ~0, pJobSetup );
+
+ copyJobDataToJobSetup( pJobSetup, m_aJobData );
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+// This function merges the independ driver data
+// and sets the new independ data in pJobSetup
+// Only the data must be changed, where the bit
+// in nGetDataFlags is set
+BOOL PspSalInfoPrinter::SetData(
+ ULONG nSetDataFlags,
+ ImplJobSetup* pJobSetup )
+{
+ JobData aData;
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
+
+ if( aData.m_pParser )
+ {
+ const PPDKey* pKey;
+ const PPDValue* pValue;
+
+ // merge papersize if necessary
+ if( nSetDataFlags & SAL_JOBSET_PAPERSIZE )
+ {
+ int nWidth, nHeight;
+ if( pJobSetup->meOrientation == ORIENTATION_PORTRAIT )
+ {
+ nWidth = pJobSetup->mnPaperWidth;
+ nHeight = pJobSetup->mnPaperHeight;
+ }
+ else
+ {
+ nWidth = pJobSetup->mnPaperHeight;
+ nHeight = pJobSetup->mnPaperWidth;
+ }
+ String aPaper;
+
+ if( pJobSetup->mePaperFormat == PAPER_USER )
+ aPaper = aData.m_pParser->matchPaper(
+ TenMuToPt( pJobSetup->mnPaperWidth ),
+ TenMuToPt( pJobSetup->mnPaperHeight ) );
+ else
+ aPaper = rtl::OStringToOUString(PaperInfo::toPSName(pJobSetup->mePaperFormat), RTL_TEXTENCODING_ISO_8859_1);
+
+ pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
+ pValue = pKey ? pKey->getValueCaseInsensitive( aPaper ) : NULL;
+
+ // some PPD files do not specify the standard paper names (e.g. C5 instead of EnvC5)
+ // try to find the correct paper anyway using the size
+ if( pKey && ! pValue && pJobSetup->mePaperFormat != PAPER_USER )
+ {
+ PaperInfo aInfo( pJobSetup->mePaperFormat );
+ aPaper = aData.m_pParser->matchPaper(
+ TenMuToPt( aInfo.getWidth() ),
+ TenMuToPt( aInfo.getHeight() ) );
+ pValue = pKey->getValueCaseInsensitive( aPaper );
+ }
+
+ if( ! ( pKey && pValue && aData.m_aContext.setValue( pKey, pValue, false ) == pValue ) )
+ return FALSE;
+ }
+
+ // merge paperbin if necessary
+ if( nSetDataFlags & SAL_JOBSET_PAPERBIN )
+ {
+ pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) );
+ if( pKey )
+ {
+ int nPaperBin = pJobSetup->mnPaperBin;
+ if( nPaperBin >= pKey->countValues() )
+ pValue = pKey->getDefaultValue();
+ else
+ pValue = pKey->getValue( pJobSetup->mnPaperBin );
+
+ // may fail due to constraints;
+ // real paper bin is copied back to jobsetup in that case
+ aData.m_aContext.setValue( pKey, pValue );
+ }
+ // if printer has no InputSlot key simply ignore this setting
+ // (e.g. SGENPRT has no InputSlot)
+ }
+
+ // merge orientation if necessary
+ if( nSetDataFlags & SAL_JOBSET_ORIENTATION )
+ aData.m_eOrientation = pJobSetup->meOrientation == ORIENTATION_LANDSCAPE ? orientation::Landscape : orientation::Portrait;
+
+ // merge duplex if necessary
+ if( nSetDataFlags & SAL_JOBSET_DUPLEXMODE )
+ {
+ pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) );
+ if( pKey )
+ {
+ pValue = NULL;
+ switch( pJobSetup->meDuplexMode )
+ {
+ case DUPLEX_OFF:
+ pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "None" ) ) );
+ if( pValue == NULL )
+ pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "SimplexNoTumble" ) ) );
+ break;
+ case DUPLEX_SHORTEDGE:
+ pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "DuplexTumble" ) ) );
+ break;
+ case DUPLEX_LONGEDGE:
+ pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "DuplexNoTumble" ) ) );
+ break;
+ case DUPLEX_UNKNOWN:
+ default:
+ pValue = 0;
+ break;
+ }
+ if( ! pValue )
+ pValue = pKey->getDefaultValue();
+ aData.m_aContext.setValue( pKey, pValue );
+ }
+ }
+
+ m_aJobData = aData;
+ copyJobDataToJobSetup( pJobSetup, aData );
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void PspSalInfoPrinter::GetPageInfo(
+ const ImplJobSetup* pJobSetup,
+ long& rOutWidth, long& rOutHeight,
+ long& rPageOffX, long& rPageOffY,
+ long& rPageWidth, long& rPageHeight )
+{
+ if( ! pJobSetup )
+ return;
+
+ JobData aData;
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
+
+ // get the selected page size
+ if( aData.m_pParser )
+ {
+
+ String aPaper;
+ int width, height;
+ int left = 0, top = 0, right = 0, bottom = 0;
+ int nDPI = aData.m_aContext.getRenderResolution();
+
+
+ if( aData.m_eOrientation == psp::orientation::Portrait )
+ {
+ aData.m_aContext.getPageSize( aPaper, width, height );
+ aData.m_pParser->getMargins( aPaper, left, right, top, bottom );
+ }
+ else
+ {
+ aData.m_aContext.getPageSize( aPaper, height, width );
+ aData.m_pParser->getMargins( aPaper, top, bottom, right, left );
+ }
+
+ rPageWidth = width * nDPI / 72;
+ rPageHeight = height * nDPI / 72;
+ rPageOffX = left * nDPI / 72;
+ rPageOffY = top * nDPI / 72;
+ rOutWidth = ( width - left - right ) * nDPI / 72;
+ rOutHeight = ( height - top - bottom ) * nDPI / 72;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ULONG PspSalInfoPrinter::GetPaperBinCount( const ImplJobSetup* pJobSetup )
+{
+ if( ! pJobSetup )
+ return 0;
+
+ JobData aData;
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
+
+ const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ): NULL;
+ return pKey ? pKey->countValues() : 0;
+}
+
+// -----------------------------------------------------------------------
+
+String PspSalInfoPrinter::GetPaperBinName( const ImplJobSetup* pJobSetup, ULONG nPaperBin )
+{
+ JobData aData;
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
+
+ String aRet;
+ if( aData.m_pParser )
+ {
+ const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ): NULL;
+ if( ! pKey || nPaperBin >= (ULONG)pKey->countValues() )
+ aRet = aData.m_pParser->getDefaultInputSlot();
+ else
+ {
+ const PPDValue* pValue = pKey->getValue( nPaperBin );
+ if( pValue )
+ aRet = aData.m_pParser->translateOption( pKey->getKey(), pValue->m_aOption );
+ }
+ }
+
+ return aRet;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG PspSalInfoPrinter::GetCapabilities( const ImplJobSetup* pJobSetup, USHORT nType )
+{
+ switch( nType )
+ {
+ case PRINTER_CAPABILITIES_SUPPORTDIALOG:
+ return 1;
+ case PRINTER_CAPABILITIES_COPIES:
+ return 0xffff;
+ case PRINTER_CAPABILITIES_COLLATECOPIES:
+ {
+ // see if the PPD contains a value to set Collate to True
+ JobData aData;
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
+
+ const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ) ) : NULL;
+ const PPDValue* pVal = pKey ? pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "True" ) ) ) : NULL;
+
+ // PPDs don't mention the number of possible collated copies.
+ // so let's guess as many as we want ?
+ return pVal ? 0xffff : 0;
+ }
+ case PRINTER_CAPABILITIES_SETORIENTATION:
+ return 1;
+ case PRINTER_CAPABILITIES_SETDUPLEX:
+ return 1;
+ case PRINTER_CAPABILITIES_SETPAPERBIN:
+ return 1;
+ case PRINTER_CAPABILITIES_SETPAPERSIZE:
+ return 1;
+ case PRINTER_CAPABILITIES_SETPAPER:
+ return 0;
+ case PRINTER_CAPABILITIES_FAX:
+ return PrinterInfoManager::get().checkFeatureToken( pJobSetup->maPrinterName, "fax" ) ? 1 : 0;
+ case PRINTER_CAPABILITIES_PDF:
+ return PrinterInfoManager::get().checkFeatureToken( pJobSetup->maPrinterName, "pdf" ) ? 1 : 0;
+ case PRINTER_CAPABILITIES_EXTERNALDIALOG:
+ return PrinterInfoManager::get().checkFeatureToken( pJobSetup->maPrinterName, "external_dialog" ) ? 1 : 0;
+ default: break;
+ };
+ return 0;
+}
+
+// =======================================================================
+
+/*
+ * SalPrinter
+ */
+
+ PspSalPrinter::PspSalPrinter( SalInfoPrinter* pInfoPrinter )
+ : m_bFax( false ),
+ m_bPdf( false ),
+ m_bSwallowFaxNo( false ),
+ m_pGraphics( NULL ),
+ m_nCopies( 1 ),
+ m_bCollate( false ),
+ m_pInfoPrinter( pInfoPrinter )
+{
+}
+
+// -----------------------------------------------------------------------
+
+PspSalPrinter::~PspSalPrinter()
+{
+}
+
+// -----------------------------------------------------------------------
+
+static String getTmpName()
+{
+ rtl::OUString aTmp, aSys;
+ osl_createTempFile( NULL, NULL, &aTmp.pData );
+ osl_getSystemPathFromFileURL( aTmp.pData, &aSys.pData );
+
+ return aSys;
+}
+
+BOOL PspSalPrinter::StartJob(
+ const XubString* pFileName,
+ const XubString& rJobName,
+ const XubString& rAppName,
+ ULONG nCopies,
+ bool bCollate,
+ bool bDirect,
+ ImplJobSetup* pJobSetup )
+{
+ vcl_sal::PrinterUpdate::jobStarted();
+
+ m_bFax = false;
+ m_bPdf = false;
+ m_aFileName = pFileName ? *pFileName : String();
+ m_aTmpFile = String();
+ m_nCopies = nCopies;
+ m_bCollate = bCollate;
+
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData );
+ if( m_nCopies > 1 )
+ {
+ // in case user did not do anything (m_nCopies=1)
+ // take the default from jobsetup
+ m_aJobData.m_nCopies = m_nCopies;
+ m_aJobData.setCollate( bCollate );
+ }
+
+ // check wether this printer is configured as fax
+ int nMode = 0;
+ const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) );
+ sal_Int32 nIndex = 0;
+ while( nIndex != -1 )
+ {
+ OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
+ if( ! aToken.compareToAscii( "fax", 3 ) )
+ {
+ m_bFax = true;
+ m_aTmpFile = getTmpName();
+ nMode = S_IRUSR | S_IWUSR;
+
+ ::std::hash_map< ::rtl::OUString, ::rtl::OUString, ::rtl::OUStringHash >::const_iterator it;
+ it = pJobSetup->maValueMap.find( ::rtl::OUString::createFromAscii( "FAX#" ) );
+ if( it != pJobSetup->maValueMap.end() )
+ m_aFaxNr = it->second;
+
+ sal_Int32 nPos = 0;
+ m_bSwallowFaxNo = ! aToken.getToken( 1, '=', nPos ).compareToAscii( "swallow", 7 ) ? true : false;
+
+ break;
+ }
+ if( ! aToken.compareToAscii( "pdf=", 4 ) )
+ {
+ m_bPdf = true;
+ m_aTmpFile = getTmpName();
+ nMode = S_IRUSR | S_IWUSR;
+
+ if( ! m_aFileName.Len() )
+ {
+ m_aFileName = getPdfDir( rInfo );
+ m_aFileName.Append( '/' );
+ m_aFileName.Append( rJobName );
+ m_aFileName.AppendAscii( ".pdf" );
+ }
+ break;
+ }
+ }
+ m_aPrinterGfx.Init( m_aJobData );
+
+ // set/clear backwards compatibility flag
+ bool bStrictSO52Compatibility = false;
+ std::hash_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it =
+ pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StrictSO52Compatibility" ) ) );
+
+ if( compat_it != pJobSetup->maValueMap.end() )
+ {
+ if( compat_it->second.equalsIgnoreAsciiCaseAscii( "true" ) )
+ bStrictSO52Compatibility = true;
+ }
+ m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility );
+
+ return m_aPrintJob.StartJob( m_aTmpFile.Len() ? m_aTmpFile : m_aFileName, nMode, rJobName, rAppName, m_aJobData, &m_aPrinterGfx, bDirect ) ? TRUE : FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL PspSalPrinter::EndJob()
+{
+ BOOL bSuccess = m_aPrintJob.EndJob();
+
+ if( bSuccess )
+ {
+ // check for fax
+ if( m_bFax )
+ {
+
+ const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) );
+ // sendAFax removes the file after use
+ bSuccess = sendAFax( m_aFaxNr, m_aTmpFile, rInfo.m_aCommand );
+ }
+ else if( m_bPdf )
+ {
+ const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) );
+ bSuccess = createPdf( m_aFileName, m_aTmpFile, rInfo.m_aCommand );
+ }
+ }
+ vcl_sal::PrinterUpdate::jobEnded();
+ return bSuccess;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL PspSalPrinter::AbortJob()
+{
+ BOOL bAbort = m_aPrintJob.AbortJob() ? TRUE : FALSE;
+ vcl_sal::PrinterUpdate::jobEnded();
+ return bAbort;
+}
+
+// -----------------------------------------------------------------------
+
+SalGraphics* PspSalPrinter::StartPage( ImplJobSetup* pJobSetup, BOOL )
+{
+ JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData );
+ m_pGraphics = new PspGraphics( &m_aJobData, &m_aPrinterGfx, m_bFax ? &m_aFaxNr : NULL, m_bSwallowFaxNo, m_pInfoPrinter );
+ m_pGraphics->SetLayout( 0 );
+ if( m_nCopies > 1 )
+ {
+ // in case user did not do anything (m_nCopies=1)
+ // take the default from jobsetup
+ m_aJobData.m_nCopies = m_nCopies;
+ m_aJobData.setCollate( m_nCopies > 1 && m_bCollate );
+ }
+
+ m_aPrintJob.StartPage( m_aJobData );
+ m_aPrinterGfx.Init( m_aPrintJob );
+
+ return m_pGraphics;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL PspSalPrinter::EndPage()
+{
+ sal_Bool bResult = m_aPrintJob.EndPage();
+ m_aPrinterGfx.Clear();
+ return bResult ? TRUE : FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG PspSalPrinter::GetErrorCode()
+{
+ return 0;
+}
+
+/*
+ * vcl::PrinterUpdate
+ */
+
+Timer* vcl_sal::PrinterUpdate::pPrinterUpdateTimer = NULL;
+int vcl_sal::PrinterUpdate::nActiveJobs = 0;
+
+void vcl_sal::PrinterUpdate::doUpdate()
+{
+ ::psp::PrinterInfoManager& rManager( ::psp::PrinterInfoManager::get() );
+ if( rManager.checkPrintersChanged( false ) )
+ {
+ SalDisplay* pDisp = GetX11SalData()->GetDisplay();
+ const std::list< SalFrame* >& rList = pDisp->getFrames();
+ for( std::list< SalFrame* >::const_iterator it = rList.begin();
+ it != rList.end(); ++it )
+ pDisp->SendInternalEvent( *it, NULL, SALEVENT_PRINTERCHANGED );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+IMPL_STATIC_LINK_NOINSTANCE( vcl_sal::PrinterUpdate, UpdateTimerHdl, void*, EMPTYARG )
+{
+ if( nActiveJobs < 1 )
+ {
+ doUpdate();
+ delete pPrinterUpdateTimer;
+ pPrinterUpdateTimer = NULL;
+ }
+ else
+ pPrinterUpdateTimer->Start();
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void vcl_sal::PrinterUpdate::update()
+{
+ if( Application::GetSettings().GetMiscSettings().GetDisablePrinting() )
+ return;
+
+ if( ! static_cast< X11SalInstance* >(GetSalData()->m_pInstance)->isPrinterInit() )
+ {
+ // #i45389# start background printer detection
+ psp::PrinterInfoManager::get();
+ return;
+ }
+
+ if( nActiveJobs < 1 )
+ doUpdate();
+ else if( ! pPrinterUpdateTimer )
+ {
+ pPrinterUpdateTimer = new Timer();
+ pPrinterUpdateTimer->SetTimeout( 500 );
+ pPrinterUpdateTimer->SetTimeoutHdl( STATIC_LINK( NULL, vcl_sal::PrinterUpdate, UpdateTimerHdl ) );
+ pPrinterUpdateTimer->Start();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void vcl_sal::PrinterUpdate::jobEnded()
+{
+ nActiveJobs--;
+ if( nActiveJobs < 1 )
+ {
+ if( pPrinterUpdateTimer )
+ {
+ pPrinterUpdateTimer->Stop();
+ delete pPrinterUpdateTimer;
+ pPrinterUpdateTimer = NULL;
+ doUpdate();
+ }
+ }
+}
diff --git a/vcl/unx/source/gdi/salvd.cxx b/vcl/unx/source/gdi/salvd.cxx
new file mode 100644
index 000000000000..f242fffae715
--- /dev/null
+++ b/vcl/unx/source/gdi/salvd.cxx
@@ -0,0 +1,272 @@
+/*************************************************************************
+ *
+ * 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/prex.h>
+#include <X11/extensions/Xrender.h>
+#include <tools/postx.h>
+
+#include <salunx.h>
+#include <saldata.hxx>
+#include <saldisp.hxx>
+#include <vcl/salinst.hxx>
+#include <salgdi.h>
+#include <salvd.h>
+#include <vcl/sysdata.hxx>
+
+// -=-= SalInstance =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+SalVirtualDevice* X11SalInstance::CreateVirtualDevice( SalGraphics* pGraphics,
+ long nDX, long nDY,
+ USHORT nBitCount, const SystemGraphicsData *pData )
+{
+ X11SalVirtualDevice *pVDev = new X11SalVirtualDevice();
+ if( !nBitCount && pGraphics )
+ nBitCount = pGraphics->GetBitCount();
+
+ if( pData && pData->hDrawable != None )
+ {
+ XLIB_Window aRoot;
+ int x, y;
+ unsigned int w = 0, h = 0, bw, d;
+ Display* pDisp = GetX11SalData()->GetDisplay()->GetDisplay();
+ XGetGeometry( pDisp, pData->hDrawable,
+ &aRoot, &x, &y, &w, &h, &bw, &d );
+ int nScreen = 0;
+ while( nScreen < ScreenCount( pDisp ) )
+ {
+ if( RootWindow( pDisp, nScreen ) == aRoot )
+ break;
+ nScreen++;
+ }
+ nDX = (long)w;
+ nDY = (long)h;
+ if( !pVDev->Init( GetX11SalData()->GetDisplay(), nDX, nDY, nBitCount, nScreen, pData->hDrawable, pData->pRenderFormat ) )
+ {
+ delete pVDev;
+ return NULL;
+ }
+ }
+ else if( !pVDev->Init( GetX11SalData()->GetDisplay(), nDX, nDY, nBitCount,
+ pGraphics ? static_cast<X11SalGraphics*>(pGraphics)->GetScreenNumber() :
+ GetX11SalData()->GetDisplay()->GetDefaultScreenNumber() ) )
+ {
+ delete pVDev;
+ return NULL;
+ }
+
+ pVDev->InitGraphics( pVDev );
+ return pVDev;
+}
+
+void X11SalInstance::DestroyVirtualDevice( SalVirtualDevice* pDevice )
+{
+ delete pDevice;
+}
+
+// -=-= SalGraphicsData =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalGraphics::Init( X11SalVirtualDevice *pDevice, SalColormap* pColormap, bool bDeleteColormap )
+{
+ SalColormap *pOrigDeleteColormap = m_pDeleteColormap;
+
+ SalDisplay *pDisplay = pDevice->GetDisplay();
+ m_nScreen = pDevice->GetScreenNumber();
+
+ int nVisualDepth = pDisplay->GetColormap( m_nScreen ).GetVisual().GetDepth();
+ int nDeviceDepth = pDevice->GetDepth();
+
+ if( pColormap )
+ {
+ m_pColormap = pColormap;
+ if( bDeleteColormap )
+ m_pDeleteColormap = pColormap;
+ }
+ else
+ if( nDeviceDepth == nVisualDepth )
+ m_pColormap = &pDisplay->GetColormap( m_nScreen );
+ else
+ if( nDeviceDepth == 1 )
+ m_pColormap = m_pDeleteColormap = new SalColormap();
+
+ if (m_pDeleteColormap != pOrigDeleteColormap)
+ delete pOrigDeleteColormap;
+
+ const Drawable aVdevDrawable = pDevice->GetDrawable();
+ SetDrawable( aVdevDrawable, m_nScreen );
+
+ m_pVDev = pDevice;
+ m_pFrame = NULL;
+
+ bWindow_ = pDisplay->IsDisplay();
+ bVirDev_ = TRUE;
+}
+
+// -=-= SalVirDevData / SalVirtualDevice -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+BOOL X11SalVirtualDevice::Init( SalDisplay *pDisplay,
+ long nDX, long nDY,
+ USHORT nBitCount,
+ int nScreen,
+ Pixmap hDrawable,
+ void* pRenderFormatVoid )
+{
+ SalColormap* pColormap = NULL;
+ bool bDeleteColormap = false;
+
+ pDisplay_ = pDisplay;
+ pGraphics_ = new X11SalGraphics();
+ m_nScreen = nScreen;
+ if( pRenderFormatVoid ) {
+ XRenderPictFormat *pRenderFormat = ( XRenderPictFormat* )pRenderFormatVoid;
+ pGraphics_->SetXRenderFormat( pRenderFormat );
+ if( pRenderFormat->colormap )
+ pColormap = new SalColormap( pDisplay, pRenderFormat->colormap, m_nScreen );
+ else
+ pColormap = new SalColormap( nBitCount );
+ bDeleteColormap = true;
+ }
+ else if( nBitCount != pDisplay->GetVisual( m_nScreen ).GetDepth() )
+ {
+ pColormap = new SalColormap( nBitCount );
+ bDeleteColormap = true;
+ }
+ pGraphics_->SetLayout( 0 ); // by default no! mirroring for VirtualDevices, can be enabled with EnableRTL()
+ nDX_ = nDX;
+ nDY_ = nDY;
+ nDepth_ = nBitCount;
+
+ if( hDrawable == None )
+ hDrawable_ = XCreatePixmap( GetXDisplay(),
+ pDisplay_->GetDrawable( m_nScreen ),
+ nDX_, nDY_,
+ GetDepth() );
+ else
+ {
+ hDrawable_ = hDrawable;
+ bExternPixmap_ = TRUE;
+ }
+
+ pGraphics_->Init( this, pColormap, bDeleteColormap );
+
+ return hDrawable_ != None ? TRUE : FALSE;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+X11SalVirtualDevice::X11SalVirtualDevice()
+{
+ pDisplay_ = (SalDisplay*)ILLEGAL_POINTER;
+ pGraphics_ = NULL;
+ hDrawable_ = None;
+ nDX_ = 0;
+ nDY_ = 0;
+ nDepth_ = 0;
+ bGraphics_ = FALSE;
+ bExternPixmap_ = FALSE;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+X11SalVirtualDevice::~X11SalVirtualDevice()
+{
+ if( pGraphics_ )
+ delete pGraphics_;
+ pGraphics_ = NULL;
+
+ if( GetDrawable() && !bExternPixmap_ )
+ XFreePixmap( GetXDisplay(), GetDrawable() );
+}
+
+SalGraphics* X11SalVirtualDevice::GetGraphics()
+{
+ if( bGraphics_ )
+ return NULL;
+
+ if( pGraphics_ )
+ bGraphics_ = TRUE;
+
+ return pGraphics_;
+}
+
+void X11SalVirtualDevice::ReleaseGraphics( SalGraphics* )
+{ bGraphics_ = FALSE; }
+
+BOOL X11SalVirtualDevice::SetSize( long nDX, long nDY )
+{
+ if( bExternPixmap_ )
+ return FALSE;
+
+ // #144688#
+ // the X protocol request CreatePixmap puts an upper bound
+ // of 16 bit to the size. Beyond that there may be implementation
+ // limits of the Xserver; which we should catch by a failed XCreatePixmap
+ // call. However extra large values should be caught here since we'd run into
+ // 16 bit truncation here without noticing.
+ if( nDX < 0 || nDX > 65535 ||
+ nDY < 0 || nDY > 65535 )
+ return FALSE;
+
+ if( !nDX ) nDX = 1;
+ if( !nDY ) nDY = 1;
+
+ Pixmap h = XCreatePixmap( GetXDisplay(),
+ pDisplay_->GetDrawable( m_nScreen ),
+ nDX, nDY, nDepth_ );
+
+ if( !h )
+ {
+ if( !GetDrawable() )
+ {
+ hDrawable_ = XCreatePixmap( GetXDisplay(),
+ pDisplay_->GetDrawable( m_nScreen ),
+ 1, 1, nDepth_ );
+ nDX_ = 1;
+ nDY_ = 1;
+ }
+ return FALSE;
+ }
+
+ if( GetDrawable() )
+ XFreePixmap( GetXDisplay(), GetDrawable() );
+ hDrawable_ = h;
+
+ nDX_ = nDX;
+ nDY_ = nDY;
+
+ if( pGraphics_ )
+ InitGraphics( this );
+
+ return TRUE;
+}
+
+void X11SalVirtualDevice::GetSize( long& rWidth, long& rHeight )
+{
+ rWidth = GetWidth();
+ rHeight = GetHeight();
+}
+
diff --git a/vcl/unx/source/gdi/xfont.cxx b/vcl/unx/source/gdi/xfont.cxx
new file mode 100644
index 000000000000..f6d19909cd4a
--- /dev/null
+++ b/vcl/unx/source/gdi/xfont.cxx
@@ -0,0 +1,780 @@
+/*************************************************************************
+ *
+ * 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 <salunx.h>
+#include "xfont.hxx"
+#include "xlfd_extd.hxx"
+#include "salcvt.hxx"
+#include <tools/string.hxx>
+#include <vcl/outfont.hxx>
+#include <saldisp.hxx>
+#include <salgdi.h>
+
+// for GetMirroredChar
+#include <vcl/svapp.hxx>
+
+#if OSL_DEBUG_LEVEL > 1
+#include <cstdio>
+#endif
+
+#include <algorithm>
+
+#define VCLASS_ROTATE 0
+#define VCLASS_ROTATE_REVERSE 1
+#define VCLASS_TRANSFORM1 2
+#define VCLASS_TRANSFORM2 3
+#define VCLASS_CJK 4
+#define VCLASS_DONTKNOW 5
+#define VCLASS_FONT_NUM 2 // Other than rotate and rotate_reverse,
+ // don't have spacial font
+
+// Select the max size of a font, which is token for real
+// This routine is (and should be) called only once, the result should be
+// stored in some static variable
+
+static int GetMaxFontHeight()
+{
+ static int nMaxFontHeight = 0;
+ if( nMaxFontHeight <= 0 )
+ {
+ const char *pFontHeight = getenv ("SAL_MAXFONTHEIGHT");
+ if( pFontHeight )
+ nMaxFontHeight = atoi( pFontHeight );
+ static const int DEFAULT_MAXFONTHEIGHT = 250;
+ if (nMaxFontHeight <= 20)
+ nMaxFontHeight = DEFAULT_MAXFONTHEIGHT;
+ }
+
+ return nMaxFontHeight;
+}
+
+
+ExtendedFontStruct::ExtendedFontStruct( Display* pDisplay, const Size& rPixelSize,
+ sal_Bool bVertical, ExtendedXlfd* pXlfd ) :
+ mpDisplay( pDisplay ),
+ maPixelSize( rPixelSize ),
+ mfXScale(1.0), mfYScale(1.0),
+ mbVertical( bVertical ),
+ mnCachedEncoding( RTL_TEXTENCODING_DONTKNOW ),
+ mpXlfd( pXlfd ),
+ mpRangeCodes(NULL),
+ mnRangeCount(-1)
+{
+ if( !maPixelSize.Width() )
+ maPixelSize.Width() = maPixelSize.Height();
+ mnAsciiEncoding = GetAsciiEncoding (NULL);
+ mnDefaultWidth = GetDefaultWidth();
+
+ mpXFontStruct = (XFontStruct**)calloc( mpXlfd->NumEncodings(),
+ sizeof(XFontStruct*) );
+}
+
+ExtendedFontStruct::~ExtendedFontStruct()
+{
+ delete[] mpRangeCodes;
+
+ for ( int nIdx = 0; nIdx < mpXlfd->NumEncodings(); nIdx++ )
+ if ( mpXFontStruct[nIdx] != NULL )
+ XFreeFont( mpDisplay, mpXFontStruct[nIdx] );
+
+ free(mpXFontStruct);
+}
+
+rtl_TextEncoding
+ExtendedFontStruct::GetAsciiEncoding( int *pAsciiRange ) const
+{
+ return mpXlfd->GetAsciiEncoding( pAsciiRange );
+}
+
+FontPitch
+ExtendedFontStruct::GetSpacing( rtl_TextEncoding nEncoding )
+{
+ return mpXlfd->GetPitch( nEncoding );
+}
+
+static XFontStruct*
+LoadXFont (Display* pDisplay, const char* pFontName)
+{
+ XFontStruct* pFont = XLoadQueryFont (pDisplay, pFontName);
+ if ((pFont != NULL) && (pFont->fid == 0))
+ pFont->fid = XLoadFont(pDisplay, pFontName);
+
+#ifdef HDU_DEBUG
+ fprintf( stderr, "XLoadFont \"%s\" => %d\n", pFontName, (pFont!= NULL) );
+#endif
+ return pFont;
+}
+
+int
+ExtendedFontStruct::LoadEncoding( rtl_TextEncoding nEncoding )
+{
+ int nIdx = mpXlfd->GetEncodingIdx( nEncoding );
+ if ( (nIdx < 0) || (mpXFontStruct[ nIdx ] != NULL) )
+ return nIdx;
+
+ // limit font height that gets requested from the XServer
+ // see BugId #44528# FontWork (-> #45038#) and as well Bug #47127#
+ int nReqPixelHeight = maPixelSize.Height();
+ if( nReqPixelHeight > GetMaxFontHeight() )
+ nReqPixelHeight = GetMaxFontHeight();
+ else if( nReqPixelHeight < 2 )
+ nReqPixelHeight = 2;
+
+ // get the X11 font from a matching XLFD
+ ByteString aFontName;
+ mpXlfd->ToString( aFontName, nReqPixelHeight, nEncoding );
+ mpXFontStruct[ nIdx ] = LoadXFont( mpDisplay, aFontName.GetBuffer() );
+ if (mpXFontStruct[nIdx] == NULL)
+ mpXFontStruct[nIdx] = LoadXFont( mpDisplay, "fixed" );
+
+ // calculate correction factors to improve matching
+ // the selected font size to the used bitmap font
+ int nRealPixelSize = mpXlfd->GetPixelSize();
+ if( !nRealPixelSize ) // check for scalable mpXlfd
+ nRealPixelSize = nReqPixelHeight;
+ if( nRealPixelSize && (nRealPixelSize != maPixelSize.Width()) )
+ mfXScale = (float)maPixelSize.Width() / nRealPixelSize;
+ if( nRealPixelSize && (nRealPixelSize != maPixelSize.Height()) )
+ mfYScale = (float)maPixelSize.Height() / nRealPixelSize;
+
+ return nIdx;
+}
+
+XFontStruct*
+ExtendedFontStruct::GetFontStruct( rtl_TextEncoding nEncoding )
+{
+ int nIdx = LoadEncoding( nEncoding );
+ return nIdx < 0 ? NULL : mpXFontStruct[nIdx] ;
+}
+
+bool
+ExtendedFontStruct::GetFontBoundingBox( XCharStruct *pCharStruct,
+ int *pAscent, int *pDescent )
+{
+ pCharStruct->lbearing = 0;
+ pCharStruct->rbearing = 0;
+ pCharStruct->width = 0;
+ pCharStruct->ascent = 0;
+ pCharStruct->descent = 0;
+
+ *pAscent = 0;
+ *pDescent = 0;
+
+ int nIdx;
+
+ // check if there is at least one encoding already loaded
+ bool bEmpty = true;
+ for ( nIdx = 0; nIdx < mpXlfd->NumEncodings(); nIdx++ )
+ bEmpty &= (mpXFontStruct[nIdx] == NULL);
+ if ( bEmpty )
+ LoadEncoding( mpXlfd->GetAsciiEncoding() );
+
+ // get the max bounding box from all font structs
+ for ( nIdx = 0; nIdx < mpXlfd->NumEncodings(); nIdx++ )
+ if ( mpXFontStruct[ nIdx ] != NULL )
+ {
+ *pAscent = std::max( mpXFontStruct[nIdx]->ascent, *pAscent );
+ *pDescent = std::max( mpXFontStruct[nIdx]->descent, *pDescent );
+
+ XCharStruct* pMaxBounds = &(mpXFontStruct[nIdx]->max_bounds);
+
+ pCharStruct->lbearing = std::max( pMaxBounds->lbearing,
+ pCharStruct->lbearing );
+ pCharStruct->rbearing = std::max( pMaxBounds->rbearing,
+ pCharStruct->rbearing );
+ pCharStruct->width = std::max( pMaxBounds->width,
+ pCharStruct->width );
+ pCharStruct->ascent = std::max( pMaxBounds->ascent,
+ pCharStruct->ascent );
+ pCharStruct->descent = std::max( pMaxBounds->descent,
+ pCharStruct->descent );
+ }
+
+ // apply correction factors to better match selected size to available size
+ if( mfYScale != 1.0 )
+ {
+ *pAscent = int(*pAscent * mfYScale);
+ *pDescent = int(*pDescent * mfYScale);
+ pCharStruct->ascent = (short int)(pCharStruct->ascent * mfYScale);
+ pCharStruct->descent = (short int)(pCharStruct->descent * mfYScale);
+ }
+ if( mfXScale != 1.0 )
+ {
+ pCharStruct->lbearing = (short int)(pCharStruct->lbearing * mfXScale);
+ pCharStruct->rbearing = (short int)(pCharStruct->rbearing * mfXScale);
+ pCharStruct->width = (short int)(pCharStruct->width * mfXScale);
+ }
+
+ return (pCharStruct->width > 0);
+}
+
+bool
+ExtendedFontStruct::ToImplFontMetricData(ImplFontMetricData *pFontMetric)
+{
+ pFontMetric->mnOrientation = 0;
+ pFontMetric->mnSlant = 0;
+ pFontMetric->mbDevice = true;
+ pFontMetric->mbScalableFont = mpXlfd->IsScalable();
+ pFontMetric->mbKernableFont = false;
+ pFontMetric->mbSymbolFlag= mpXlfd->IsSymbolFont();
+ pFontMetric->meFamily = mpXlfd->GetFamilyType();
+ pFontMetric->meWeight = mpXlfd->GetWeight();
+ pFontMetric->mePitch = mpXlfd->GetPitch();
+ pFontMetric->meItalic = mpXlfd->GetSlant();
+
+ int nAscent, nDescent;
+ XCharStruct aBoundingBox;
+ if ( GetFontBoundingBox(&aBoundingBox, &nAscent, &nDescent) )
+ {
+ pFontMetric->mnWidth = aBoundingBox.width;
+ pFontMetric->mnAscent = aBoundingBox.ascent;
+ pFontMetric->mnDescent = aBoundingBox.descent;
+ pFontMetric->mnIntLeading = std::max(0, aBoundingBox.ascent - nAscent
+ + aBoundingBox.descent - nDescent );
+ pFontMetric->mnExtLeading = 0; // TODO!!!
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool
+ExtendedFontStruct::Match( const ExtendedXlfd *pXlfd,
+ const Size& rPixelSize, sal_Bool bVertical ) const
+{
+ if( mpXlfd != pXlfd )
+ return false;
+
+ if( bVertical != mbVertical )
+ return FALSE;
+
+ if( rPixelSize.Height() != maPixelSize.Height() )
+ return FALSE;
+
+ long nReqWidth = rPixelSize.Width();
+ if( !nReqWidth )
+ nReqWidth = rPixelSize.Height();
+ if( nReqWidth != maPixelSize.Width() )
+ return FALSE;
+
+ return true;
+}
+
+// Get an appropriate x-font that contains a glyph for the given unicode
+// code point.
+// This routine is designed to be called for each character in a text.
+// It first checks the given encoding to optimize for the fact that two
+// adjacent characters in a text most probably have the same encoding
+// In the first call initialize pEncodingInOut to dontknow, this causes
+// EncodingHasChar() to fail and thus bootstraps the encoding, otherwise
+// make sure that the initial value of pFontInOut matches the encoding and
+// that the encoding is valid for the font.
+XFontStruct*
+ExtendedFontStruct::GetFontStruct( sal_Unicode nChar, rtl_TextEncoding *pEncoding )
+{
+ SalConverterCache *pCvt = SalConverterCache::GetInstance();
+
+ if ( pCvt->EncodingHasChar(mnAsciiEncoding, nChar) )
+ {
+ *pEncoding = mnAsciiEncoding;
+ return GetFontStruct (mnAsciiEncoding);
+ }
+ else
+ if ( pCvt->EncodingHasChar(mnCachedEncoding, nChar) )
+ {
+ *pEncoding = mnCachedEncoding;
+ return GetFontStruct (mnCachedEncoding);
+ }
+ else
+ {
+ for ( int nIdx = 0; nIdx < mpXlfd->NumEncodings(); nIdx++ )
+ {
+ rtl_TextEncoding nEnc = mpXlfd->GetEncoding(nIdx);
+ if ( (nEnc != mnCachedEncoding) && (nEnc != mnAsciiEncoding)
+ && pCvt->EncodingHasChar(nEnc, nChar))
+ {
+ mnCachedEncoding = nEnc;
+ *pEncoding = mnCachedEncoding;
+ return GetFontStruct (mnCachedEncoding);
+ }
+ }
+ }
+
+ *pEncoding = RTL_TEXTENCODING_DONTKNOW;
+ return NULL;
+}
+
+// ---------------------------------------------------------------------------
+// utility functions to handle xfontstruct information, this is all to
+// calculate charwidth information
+// ---------------------------------------------------------------------------
+
+static bool
+CharExists( const XCharStruct* pChar )
+{
+ if ( pChar == NULL )
+ return false;
+
+ return pChar->width
+ || pChar->ascent || pChar->descent
+ || pChar->lbearing || pChar->rbearing;
+}
+
+// this relies on non-null per_char information in the fontstruct
+static XCharStruct*
+GetCharinfo( const XFontStruct *pXFontStruct, sal_MultiByte nChar )
+{
+ unsigned int nRow = nChar >> 8;
+ unsigned int nCol = nChar & 0xFF;
+
+ unsigned int nMinRow = pXFontStruct->min_byte1;
+ unsigned int nMaxRow = pXFontStruct->max_byte1;
+ unsigned int nMinCol = pXFontStruct->min_char_or_byte2;
+ unsigned int nMaxCol = pXFontStruct->max_char_or_byte2;
+
+ if ( nRow >= nMinRow && nRow <= nMaxRow
+ && nCol >= nMinCol && nCol <= nMaxCol )
+ {
+ return &pXFontStruct->per_char[
+ (nRow-nMinRow) * (nMaxCol-nMinCol+1) + (nCol-nMinCol) ];
+ }
+
+ return NULL;
+}
+
+static sal_Size
+QueryCharWidth16( Display* pDisplay, XLIB_Font nFontID, sal_MultiByte nChar,
+ sal_Size nDefaultWidth )
+{
+ int nDirection, nFontAscent, nFontDescent;
+ XCharStruct aBoundingBox;
+
+ XQueryTextExtents16( pDisplay, nFontID, (XChar2b*)&nChar, 1,
+ &nDirection, &nFontAscent, &nFontDescent, &aBoundingBox );
+
+ return CharExists( &aBoundingBox ) ? aBoundingBox.width : nDefaultWidth;
+}
+
+#if 0
+// currently not used
+static sal_Size
+QueryCharWidth8( XFontStruct* pXFontStruct, sal_Char nChar,
+ sal_Size nDefaultWidth )
+{
+ int nDirection, nFontAscent, nFontDescent;
+ XCharStruct aBoundingBox;
+
+ XTextExtents( pXFontStruct, &nChar, 1,
+ &nDirection, &nFontAscent, &nFontDescent, &aBoundingBox );
+
+ return CharExists( &aBoundingBox ) ? aBoundingBox.width : nDefaultWidth;
+}
+#endif
+
+sal_Size
+ExtendedFontStruct::GetDefaultWidth()
+{
+ return (maPixelSize.Width() + 1) / 2;
+}
+
+// Handle single byte fonts which do not require conversion, this exploits
+// the fact that unicode equals latin1 or ansi1252 in the range [0..0xff] and
+// is compatible with iso8859-X at least in the range to 0x7f
+sal_Size
+ExtendedFontStruct::GetCharWidth8( sal_Unicode nFrom, sal_Unicode nTo,
+ sal_Int32* pWidthArray, rtl_TextEncoding nEncoding )
+{
+ if ( !(nFrom <= nTo) )
+ return 0;
+
+ XFontStruct* pXFontStruct = GetFontStruct( nEncoding );
+ if ( pXFontStruct == NULL )
+ return 0;
+
+ // query the font metrics
+ if ( (pXFontStruct->max_bounds.width == pXFontStruct->min_bounds.width)
+ || (pXFontStruct->per_char == NULL) )
+ {
+ // fixed width font
+ for ( int nIdx = nFrom; nIdx <= nTo; nIdx++, pWidthArray++ )
+ *pWidthArray = pXFontStruct->max_bounds.width;
+ }
+ else
+ {
+ // variable width font
+ int nMinChar = pXFontStruct->min_char_or_byte2;
+ int nMaxChar = pXFontStruct->max_char_or_byte2;
+
+ int nIdx = nFrom;
+
+ for ( ; nIdx < std::min((int)nTo, nMinChar); nIdx++, pWidthArray++ )
+ *pWidthArray = mnDefaultWidth;
+ for ( ; nIdx <= std::min((int)nTo, nMaxChar); nIdx++, pWidthArray++ )
+ {
+ XCharStruct* pChar = &(pXFontStruct->per_char[nIdx - nMinChar]);
+ *pWidthArray = CharExists(pChar) ? pChar->width : mnDefaultWidth;
+ }
+ for ( ; nIdx <= nTo; nIdx++, pWidthArray++ )
+ *pWidthArray = mnDefaultWidth;
+ }
+
+ // return amount of handled chars
+ return nTo - nFrom + 1;
+}
+
+// Handle utf16 encoded fonts, which do not require conversion
+sal_Size
+ExtendedFontStruct::GetCharWidthUTF16( sal_Unicode nFrom, sal_Unicode nTo,
+ sal_Int32* pWidthArray )
+{
+ if ( !(nFrom <= nTo) )
+ return 0;
+
+ XFontStruct* pXFontStruct = GetFontStruct( RTL_TEXTENCODING_UNICODE );
+ FontPitch nSpacing = mpXlfd->GetPitch( RTL_TEXTENCODING_UNICODE );
+
+ if ( pXFontStruct == NULL )
+ return 0;
+
+ // query the font metrics
+ if ( nSpacing == PITCH_VARIABLE
+ && pXFontStruct->per_char == NULL)
+ {
+ // get per_char information from the server
+ for ( sal_Int32 nIdx = nFrom; nIdx <= nTo; nIdx++, pWidthArray++ )
+ *pWidthArray = QueryCharWidth16( mpDisplay, pXFontStruct->fid,
+ nIdx, mnDefaultWidth );
+ }
+ else
+ if ( (pXFontStruct->max_bounds.width == pXFontStruct->min_bounds.width)
+ || (pXFontStruct->per_char == NULL) )
+ {
+ // really a fixed width font
+ for ( sal_Int32 nIdx = nFrom; nIdx <= nTo; nIdx++, pWidthArray++ )
+ *pWidthArray = pXFontStruct->max_bounds.width;
+ }
+ else
+ {
+ // get per_char information from the xfontstruct
+ for ( sal_Int32 nIdx = nFrom; nIdx <= nTo; nIdx++, pWidthArray++ )
+ {
+ XCharStruct* pChar = GetCharinfo( pXFontStruct, nIdx );
+ *pWidthArray = CharExists(pChar) ? pChar->width : mnDefaultWidth;
+ }
+ }
+
+ // return amount of handled chars
+ return nTo - nFrom + 1;
+}
+
+// handle non unicode fonts that are converted into encoding matching the
+// font in fontstruct, 8 and 16 bit fonts are handled the same way
+sal_Size
+ExtendedFontStruct::GetCharWidth16( sal_Unicode nFrom, sal_Unicode nTo,
+ sal_Int32* pWidthArray, ExtendedFontStruct *pFallback )
+{
+ if ( nFrom > nTo )
+ return 0;
+
+ sal_Char pBuffer[64];
+
+ SalConverterCache *pCvt = SalConverterCache::GetInstance();
+ for ( sal_Int32 nIdx = nFrom ; nIdx <= nTo ; nIdx++, pWidthArray++ )
+ {
+ FontPitch nSpacing;
+ sal_Size nSize;
+ sal_Unicode nUniIdx = (sal_Unicode)nIdx;
+
+ // get a matching fontstruct
+ rtl_TextEncoding nEnc;
+ XFontStruct *pFont;
+
+ if ( (pFont = GetFontStruct(nUniIdx, &nEnc)) != NULL )
+ {
+ nSpacing = GetSpacing( nEnc );
+ }
+ else
+ if ( (pFallback != NULL)
+ && ((pFont = pFallback->GetFontStruct(nUniIdx, &nEnc)) != NULL) )
+ {
+ nSpacing = pFallback->GetSpacing( nEnc );
+ }
+ else
+ if ( (pFallback != NULL)
+ && ((pFont = pFallback->GetFontStruct(nUniIdx = '?', &nEnc)) != NULL) )
+ {
+ nSpacing = pFallback->GetSpacing( nEnc );
+ }
+ else
+ {
+ // TODO What should the default value be?
+ nSpacing = PITCH_FIXED;
+ }
+
+ if ( pFont )
+ {
+ nSize = pCvt->ConvertStringUTF16(&nUniIdx, 1, pBuffer, sizeof(pBuffer), nEnc);
+ // XXX FIXME
+ if ((nEnc == RTL_TEXTENCODING_GB_2312) || (nEnc == RTL_TEXTENCODING_EUC_KR))
+ {
+ for (unsigned int n_char = 0; n_char < nSize; n_char++ )
+ pBuffer[ n_char ] &= 0x7F;
+ }
+ }
+
+ // query font metrics
+ if ( pFont && (nSize == 1 || nSize == 2) )
+ {
+ sal_MultiByte nChar = (nSize == 1) ? (unsigned char)pBuffer[0] :
+ ((sal_MultiByte)pBuffer[0] << 8) + (sal_MultiByte)pBuffer[1];
+
+ if ( nSpacing == PITCH_VARIABLE
+ && pFont->per_char == NULL)
+ {
+ // get per_char information from the x-server
+ *pWidthArray = QueryCharWidth16( mpDisplay, pFont->fid,
+ nChar, mnDefaultWidth );
+ }
+ else
+ if ( (pFont->max_bounds.width == pFont->min_bounds.width)
+ || (pFont->per_char == NULL) )
+ {
+ // fixed width font
+ *pWidthArray = pFont->max_bounds.width;
+ }
+ else
+ {
+ // get per_char information from the xfontstruct
+ XCharStruct* pChar = GetCharinfo( pFont, nChar );
+ *pWidthArray = CharExists(pChar) ? pChar->width : mnDefaultWidth;
+ }
+ }
+ else
+ {
+ // conversion error
+ *pWidthArray = mnDefaultWidth;
+ }
+ }
+
+ // return amount of handled chars
+ return nTo - nFrom + 1;
+}
+
+sal_Size
+ExtendedFontStruct::GetCharWidth( sal_Unicode cChar, sal_Int32 *pPhysicalWidth,
+ sal_Int32 *pLogicalWidth )
+{
+ sal_Size nConverted = 0;
+
+ // dispatch querying of metrics to most promising encoding candidate
+ int nAsciiRange;
+ rtl_TextEncoding nEncoding = mpXlfd->GetAsciiEncoding(&nAsciiRange);
+ if ( nEncoding == RTL_TEXTENCODING_UNICODE )
+ {
+ // if we have a unicode encoded system font than we get the charwidth
+ // straight forward
+ nConverted = GetCharWidthUTF16( cChar, cChar, pPhysicalWidth );
+ }
+ else
+ {
+ if ( cChar < nAsciiRange )
+ {
+ // optimize the most frequent case, requesting only the latin1
+ // chars which are mappable to a single encoding
+ nConverted = GetCharWidth8( cChar, cChar, pPhysicalWidth, nEncoding );
+ }
+
+ // if further requests are pending, then the according unicode
+ // codepoint has to be dispatched to one of the system fonts and
+ // converted to this fonts encoding
+ nConverted += GetCharWidth16( cChar + nConverted, cChar,
+ pPhysicalWidth + nConverted, NULL );
+ }
+
+ // convert physical width to logical width, apply correction factor if needed
+ *pLogicalWidth = *pPhysicalWidth;
+ if( mfXScale != 1.0 )
+ *pLogicalWidth = sal_Int32(*pLogicalWidth * mfXScale);
+
+ return nConverted;
+}
+
+bool ExtendedFontStruct::HasUnicodeChar( sal_Unicode cChar ) const
+{
+ // #i18818# return false if there are no known encodings
+ if( !mnRangeCount )
+ return false;
+
+ // init unicode range cache if needed
+ if( mnRangeCount < 0 )
+ {
+ mnRangeCount = mpXlfd->GetFontCodeRanges( NULL );
+ if( !mnRangeCount )
+ return false;
+ mpRangeCodes = new sal_uInt32[ 2*mnRangeCount ];
+ mpXlfd->GetFontCodeRanges( mpRangeCodes );
+ // TODO: make sure everything is sorted
+ }
+
+ // binary search in unicode ranges
+ 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;
+ }
+ if( (nMid == 0) && (cChar < mpRangeCodes[0]) )
+ return false;
+ return (nMid & 1) ? false: true;
+}
+
+int ExtendedFontStruct::GetFontCodeRanges( sal_uInt32* pCodePairs ) const
+{
+ // make sure unicode range cache is initialized
+ HasUnicodeChar(0);
+
+ // transfer range pairs if requested
+ if( pCodePairs )
+ {
+ for( int i = 0; i < 2*mnRangeCount; ++i )
+ pCodePairs[i] = mpRangeCodes[i];
+ }
+
+ return mnRangeCount;
+}
+
+// =======================================================================
+
+X11FontLayout::X11FontLayout( ExtendedFontStruct& rFont )
+: mrFont( rFont )
+{}
+
+// -----------------------------------------------------------------------
+
+bool X11FontLayout::LayoutText( ImplLayoutArgs& rArgs )
+{
+ Point aNewPos( 0, 0 );
+ bool bRightToLeft;
+ int nCharPos;
+
+ for( nCharPos = -1; rArgs.GetNextPos( &nCharPos, &bRightToLeft ); )
+ {
+ sal_UCS4 cChar = rArgs.mpStr[ nCharPos ];
+ if( bRightToLeft )
+ cChar = GetMirroredChar( cChar );
+ int nGlyphIndex = cChar | GF_ISCHAR;
+
+ // check if the font supports the char
+ if( !mrFont.HasUnicodeChar( cChar ) )
+ {
+ // try to replace the failing char using the same font
+ const char* pApproxUTF8 = GetAutofallback( cChar );
+ cChar = 0;
+ if( pApproxUTF8 )
+ {
+ String aApproxStr( pApproxUTF8, RTL_TEXTENCODING_UTF8 );
+ if( aApproxStr.Len() == 1 )
+ {
+ // TODO: support Autofallback for len>1
+ sal_Unicode cApprox = aApproxStr.GetChar( 0 );
+ if( mrFont.HasUnicodeChar( cApprox ) )
+ nGlyphIndex = (cChar = cApprox) | GF_ISCHAR;
+ }
+ }
+ // request fallback glyph if necessary
+ if( !cChar )
+ {
+ rArgs.NeedFallback( nCharPos, bRightToLeft );
+ if( rArgs.mnFlags & SAL_LAYOUT_FOR_FALLBACK )
+ nGlyphIndex = 0; // drop NotDef fallback glyphs
+ }
+ }
+
+ sal_Int32 nPhysGlyphWidth, nLogGlyphWidth;
+ mrFont.GetCharWidth( cChar, &nPhysGlyphWidth, &nLogGlyphWidth );
+ int nGlyphFlags = (nPhysGlyphWidth > 0) ? 0 : GlyphItem::IS_IN_CLUSTER;
+ if( bRightToLeft )
+ nGlyphFlags |= GlyphItem::IS_RTL_GLYPH;
+ GlyphItem aGI( nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nPhysGlyphWidth );
+ aGI.mnNewWidth = nLogGlyphWidth;
+ AppendGlyph( aGI );
+
+ aNewPos.X() += nLogGlyphWidth;
+ }
+
+ return (nCharPos >= 0);
+}
+
+// -----------------------------------------------------------------------
+
+void X11FontLayout::AdjustLayout( ImplLayoutArgs& rArgs )
+{
+ GenericSalLayout::AdjustLayout( rArgs );
+ SetOrientation( 0 ); // X11 fonts are to be rotated in upper layers
+}
+
+// -----------------------------------------------------------------------
+
+void X11FontLayout::DrawText( SalGraphics& rSalGraphics ) const
+{
+ static const int MAXGLYPHS = 160;
+ int nMaxGlyphs = GetOrientation() ? 1 : MAXGLYPHS;
+
+ // workaround for #i49902# similar to #b6228733 with XDrawText items
+ // => output each item separately for non-unicode font encodings!
+ // this is done here instead of in DrawStringUCS2MB() because
+ // it needs the item positions and they are easily available here
+ if( mrFont.GetAsciiEncoding() != RTL_TEXTENCODING_UNICODE )
+ nMaxGlyphs = 1;
+
+ Point aPos;
+ sal_GlyphId aGlyphAry[ MAXGLYPHS ];
+ sal_Unicode pStr[ MAXGLYPHS ];
+ for( int nStart=0;;)
+ {
+ int nGlyphCount = GetNextGlyphs( nMaxGlyphs, aGlyphAry, aPos, nStart );
+ if( !nGlyphCount )
+ break;
+
+ for( int i = 0; i < nGlyphCount; ++i )
+ pStr[ i ] = aGlyphAry[ i ] & GF_IDXMASK;
+
+ static_cast<X11SalGraphics&>(rSalGraphics).DrawStringUCS2MB( mrFont, aPos, pStr, nGlyphCount );
+ }
+}
+
+// =======================================================================
diff --git a/vcl/unx/source/gdi/xlfd_attr.cxx b/vcl/unx/source/gdi/xlfd_attr.cxx
new file mode 100644
index 000000000000..ca49a8548afb
--- /dev/null
+++ b/vcl/unx/source/gdi/xlfd_attr.cxx
@@ -0,0 +1,686 @@
+/*************************************************************************
+ *
+ * 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 <string.h>
+#include <sal/alloca.h>
+#include "xlfd_attr.hxx"
+#include <rtl/tencinfo.h>
+#include <vcl/vclenum.hxx>
+
+// ---------------------------------------------------------------------------
+//
+//
+// Attribute is a container for simple name value pairs
+// eg. ( "times", FAMILY_ROMAN ) or ( "demi bold", WEIGHT_SEMIBOLD )
+// enriched with an annotation which is a pretty-printed version of the
+// string, i.e. "itc avant garde" would get an annotation of "Itc Avant Garde"
+//
+//
+// ---------------------------------------------------------------------------
+
+// release the stored string
+void
+Attribute::Release()
+{
+ if ( mpAnnotation != NULL )
+ delete mpAnnotation;
+ if ( mpKeyName != NULL )
+ delete mpKeyName;
+ if ( mpName != NULL )
+ free( (void*)mpName );
+}
+
+// get a private copy of the given argument
+void
+Attribute::SetName( const char *p, int nLen )
+{
+ mpName = (char*)malloc( nLen + 1 );
+ mnLength = nLen;
+ memcpy( (void*)mpName, p, mnLength );
+ ((char*)mpName)[ mnLength ] = '\0';
+}
+
+// Compare whether two strings a equal for the first nLen bytes
+// i.e. arial == arialnarrow
+int
+Attribute::Compare( const char *p, int nLen )
+{
+ return strncmp( mpName, p, nLen );
+}
+
+// Get a all lowercase name with all blanks removed
+const rtl::OString&
+Attribute::GetKey ()
+{
+ static rtl::OString aEmptyStr;
+
+ if (mpKeyName != NULL)
+ return *mpKeyName;
+ if (mnLength == 0)
+ return aEmptyStr;
+
+ sal_Char* pBuffer = (sal_Char*)alloca (mnLength);
+
+ sal_Int32 i, j;
+ for (i = 0, j = 0; i < mnLength; i++)
+ {
+ if ( mpName[i] != ' ' )
+ pBuffer[j++] = mpName[i];
+ }
+ mpKeyName = new rtl::OString(pBuffer, j);
+
+ return *mpKeyName;
+}
+
+void
+Attribute::InitKey ()
+{
+ mpKeyName = NULL;
+}
+
+// Compare two strings, they have to be equal for nLen bytes, after nLen
+// bytes both strings have to be terminated either by '\0' or by '-'
+// this is for comparing a string being a substring in a Xlfd with a
+// zeroterminated string
+Bool
+Attribute::ExactMatch( const char *p, int nLen )
+{
+ Bool bMatch;
+ if ( nLen > 0 )
+ bMatch = Compare( p, nLen ) == 0;
+ else
+ bMatch = True;
+ if ( bMatch )
+ {
+ char c1 = p[ nLen ];
+ char c2 = mpName[ nLen ];
+ bMatch = (c1 == '-' || c1 == '\0') && (c2 == '-' || c2 == '\0');
+ }
+
+ return bMatch;
+}
+
+void
+Attribute::TagFeature( unsigned short nFeature )
+{
+ if ( (nFeature & XLFD_FEATURE_NARROW)
+ && (strstr(mpName, "narrow") != NULL) )
+ {
+ mnFeature |= XLFD_FEATURE_NARROW;
+ }
+
+ if ( (nFeature & XLFD_FEATURE_OL_CURSOR)
+ && (strcmp(mpName, "open look cursor") == 0) )
+ {
+ mnFeature |= XLFD_FEATURE_OL_CURSOR;
+ }
+
+ if ( (nFeature & XLFD_FEATURE_OL_GLYPH)
+ && (strcmp(mpName, "open look glyph") == 0) )
+ {
+ mnFeature |= XLFD_FEATURE_OL_GLYPH;
+ }
+
+ if ( (nFeature & XLFD_FEATURE_APPLICATION_FONT)
+ && ( (strcmp(mpName, "interface user") == 0)
+ || (strcmp(mpName, "interface system") == 0)))
+ {
+ mnFeature |= XLFD_FEATURE_APPLICATION_FONT;
+ }
+
+ if (nFeature & XLFD_FEATURE_INTERFACE_FONT)
+ {
+ // european
+ if (strcmp(mpName, "arial") == 0)
+ mnFeature |= (XLFD_FEATURE_INTERFACE_FONT | XLFD_FEATURE_HQ | XLFD_FEATURE_MQ);
+ else
+ if (strcmp(mpName, "helvetica") == 0)
+ mnFeature |= (XLFD_FEATURE_INTERFACE_FONT | XLFD_FEATURE_HQ);
+ else
+ if ( (strcmp(mpName, "lucidux sans") == 0)
+ || (strcmp(mpName, "luxi sans") == 0))
+ mnFeature |= (XLFD_FEATURE_INTERFACE_FONT | XLFD_FEATURE_MQ | XLFD_FEATURE_LQ);
+ else
+ if (strcmp(mpName, "charter") == 0)
+ mnFeature |= (XLFD_FEATURE_INTERFACE_FONT | XLFD_FEATURE_MQ);
+ else
+ // japanese
+ if ( (strcmp(mpName, "hg mincho l") == 0) /* Solaris: jisx0208 jisx0201 */
+ || (strcmp(mpName, "heiseimin") == 0) /* Solaris: jisx0212 */
+ || (strcmp(mpName, "minchol") == 0) /* TurboLinux */
+ || (strcmp(mpName, "mincho") == 0)) /* Redhat 6.2 JP */
+ {
+ mnFeature |= XLFD_FEATURE_INTERFACE_FONT;
+ }
+ else
+ // chinese
+ if ( (strcmp(mpName, "kai") == 0) /* Solaris */
+ || (strcmp(mpName, "ar pl mingti2l big5") == 0)) /* TurboLinux */
+ {
+ mnFeature |= XLFD_FEATURE_INTERFACE_FONT;
+ }
+ else
+ // korean
+ if ( (strcmp(mpName, "myeongjo") == 0)) /* Solaris */
+ {
+ mnFeature |= XLFD_FEATURE_INTERFACE_FONT;
+ }
+ }
+
+ if ( nFeature & XLFD_FEATURE_REDUNDANTSTYLE )
+ {
+ switch ( mpName[0] )
+ {
+ case '\0':
+ mnFeature |= XLFD_FEATURE_REDUNDANTSTYLE;
+ break;
+
+ case 'b':
+ if ( (strcmp(mpName, "bold") == 0)
+ || (strcmp(mpName, "bold italic") == 0)
+ || (strcmp(mpName, "bold sans") == 0) )
+ mnFeature |= XLFD_FEATURE_REDUNDANTSTYLE;
+ break;
+
+ case 'd':
+ if ( (strcmp(mpName, "demi") == 0)
+ || (strcmp(mpName, "demi italic") == 0) )
+ mnFeature |= XLFD_FEATURE_REDUNDANTSTYLE;
+ break;
+
+ case 'i':
+ if ( strcmp(mpName, "italic") == 0 )
+ mnFeature |= XLFD_FEATURE_REDUNDANTSTYLE;
+ break;
+
+ case 's':
+ if ( (strcmp(mpName, "sans") == 0)
+ || (strcmp(mpName, "serif") == 0) )
+ mnFeature |= XLFD_FEATURE_REDUNDANTSTYLE;
+ break;
+ }
+ }
+}
+
+// given Attribute classifications, strings have to be in alphabetical
+// order, since they are treated by binary search algorithm
+
+#define InitializeAttributeWith( p, a ) p, sizeof(p) - 1, a, 0, NULL, NULL
+#define MembersOf( p ) (sizeof(p) / sizeof(p[0]) )
+
+const Attribute pFamilyAttribute[] = {
+ { InitializeAttributeWith( "arial", FAMILY_SWISS ) },
+ { InitializeAttributeWith( "arioso", FAMILY_SCRIPT ) },
+ { InitializeAttributeWith( "avant garde", FAMILY_SWISS ) },
+ { InitializeAttributeWith( "avantgarde", FAMILY_SWISS ) },
+ { InitializeAttributeWith( "bembo", FAMILY_ROMAN ) },
+ { InitializeAttributeWith( "bookman", FAMILY_ROMAN ) },
+ { InitializeAttributeWith( "conga", FAMILY_ROMAN ) },
+ { InitializeAttributeWith( "courier", FAMILY_MODERN ) },
+ { InitializeAttributeWith( "curl", FAMILY_SCRIPT ) },
+ { InitializeAttributeWith( "fixed", FAMILY_MODERN ) },
+ { InitializeAttributeWith( "gill", FAMILY_SWISS ) },
+ { InitializeAttributeWith( "helmet", FAMILY_MODERN ) },
+ { InitializeAttributeWith( "helvetica", FAMILY_SWISS ) },
+ { InitializeAttributeWith( "international", FAMILY_MODERN ) },
+ { InitializeAttributeWith( "lucida", FAMILY_SWISS ) },
+ { InitializeAttributeWith( "new century schoolbook", FAMILY_ROMAN ) },
+ { InitializeAttributeWith( "palatino", FAMILY_ROMAN ) },
+ { InitializeAttributeWith( "roman", FAMILY_ROMAN ) },
+ { InitializeAttributeWith( "sans serif", FAMILY_SWISS ) },
+ { InitializeAttributeWith( "sansserif", FAMILY_SWISS ) },
+ { InitializeAttributeWith( "serf", FAMILY_ROMAN ) },
+ { InitializeAttributeWith( "serif", FAMILY_ROMAN ) },
+ { InitializeAttributeWith( "times", FAMILY_ROMAN ) },
+ { InitializeAttributeWith( "utopia", FAMILY_ROMAN ) },
+ { InitializeAttributeWith( "zapf chancery", FAMILY_SCRIPT ) },
+ { InitializeAttributeWith( "zapfchancery", FAMILY_SCRIPT ) }
+};
+
+const Attribute pWeightAttribute[] = {
+ { InitializeAttributeWith( "black", WEIGHT_BLACK ) },
+ { InitializeAttributeWith( "bold", WEIGHT_BOLD ) },
+ { InitializeAttributeWith( "book", WEIGHT_LIGHT ) },
+ { InitializeAttributeWith( "demi", WEIGHT_SEMIBOLD ) },
+ { InitializeAttributeWith( "demi bold", WEIGHT_SEMIBOLD ) },
+ { InitializeAttributeWith( "demibold", WEIGHT_SEMIBOLD ) },
+ { InitializeAttributeWith( "light", WEIGHT_LIGHT ) },
+ { InitializeAttributeWith( "medium", WEIGHT_MEDIUM ) },
+ { InitializeAttributeWith( "normal", WEIGHT_NORMAL ) },
+ { InitializeAttributeWith( "regular", WEIGHT_NORMAL ) },
+ { InitializeAttributeWith( "roman", WEIGHT_NORMAL ) },
+ { InitializeAttributeWith( "semicondensed", WEIGHT_LIGHT ) },
+ { InitializeAttributeWith( "ultrabold", WEIGHT_ULTRABOLD ) }
+};
+
+const Attribute pSlantAttribute[] = {
+ { InitializeAttributeWith( "i", ITALIC_NORMAL ) },
+ { InitializeAttributeWith( "o", ITALIC_OBLIQUE ) },
+ { InitializeAttributeWith( "r", ITALIC_NONE ) }
+};
+
+const Attribute pSetwidthAttribute[] = {
+ { InitializeAttributeWith( "bold", WIDTH_SEMI_EXPANDED ) },
+ { InitializeAttributeWith( "condensed", WIDTH_CONDENSED ) },
+ { InitializeAttributeWith( "double wide", WIDTH_ULTRA_EXPANDED ) },
+ { InitializeAttributeWith( "expanded", WIDTH_EXPANDED ) },
+ { InitializeAttributeWith( "extracondensed", WIDTH_EXTRA_CONDENSED ) },
+ { InitializeAttributeWith( "extraexpanded", WIDTH_EXTRA_EXPANDED ) },
+ { InitializeAttributeWith( "medium", WIDTH_NORMAL ) },
+ { InitializeAttributeWith( "narrow", WIDTH_CONDENSED ) },
+ { InitializeAttributeWith( "normal", WIDTH_NORMAL ) },
+ { InitializeAttributeWith( "semicondensed", WIDTH_SEMI_CONDENSED ) },
+ { InitializeAttributeWith( "semiexpanded", WIDTH_SEMI_EXPANDED ) },
+ { InitializeAttributeWith( "ultracondensed", WIDTH_ULTRA_CONDENSED ) },
+ { InitializeAttributeWith( "ultraexpanded", WIDTH_ULTRA_EXPANDED ) },
+ { InitializeAttributeWith( "wide", WIDTH_EXPANDED ) }
+};
+
+const Attribute pEnhancedCharsetAttribute[] = {
+ { InitializeAttributeWith( "iso8859-1", RTL_TEXTENCODING_MS_1252 ) },
+ { InitializeAttributeWith( "iso8859_1", RTL_TEXTENCODING_MS_1252 ) }
+};
+
+// -------------------------------------------------------------------------
+//
+// String handling utility functions
+//
+// -------------------------------------------------------------------------
+
+
+void
+AppendAttribute( Attribute *pAttribute, ByteString &rString )
+{
+ if ( pAttribute == NULL )
+ return ;
+
+ int nLength = pAttribute->GetLength();
+ char *pBuffer = (char*)alloca( nLength + 1);
+
+ pBuffer[ 0 ] = '-';
+ memcpy( pBuffer + 1, pAttribute->GetName(), nLength );
+ rString.Append( pBuffer, nLength + 1);
+}
+
+//
+// Prettify the font name: make each leading character of a fontname
+// uppercase. For example
+// times new roman -> Times New Roman
+//
+
+static void
+ToUpper( char *pCharacter )
+{
+ // replace [a,z] with [A,Z]
+ if ( (*pCharacter >= 97) && (*pCharacter <= 122) )
+ *pCharacter -= 32;
+}
+
+static String*
+Capitalize( const char *pStr, int nLength )
+{
+ char *pCopy = (char*)alloca( nLength + 1 );
+ char *pPtr = pCopy;
+ memcpy( pPtr, pStr, nLength + 1 );
+
+ // loop over string data and uppercase first char and all chars
+ // following a space (other white space would be unexpected here)
+ char nPreviousChar = ' ';
+ while ( *pPtr )
+ {
+ if ( nPreviousChar == ' ' )
+ ToUpper( pPtr );
+ nPreviousChar = *pPtr++;
+ }
+
+ return new String( pCopy, RTL_TEXTENCODING_ISO_8859_1 );
+}
+
+String*
+AnnotateString( const Attribute& rAttribute )
+{
+ return Capitalize(rAttribute.GetName(), rAttribute.GetLength());
+}
+
+String*
+AnnotateSlant( const Attribute& rAttribute )
+{
+ const char* pStr = rAttribute.GetName();
+ int nLen = rAttribute.GetLength();
+
+ static const struct {
+ const char *pFrom; const char *pTo;
+ } pTranslation[] = {
+ { "r", "Roman" },
+ { "o", "Oblique" },
+ { "i", "Italic" },
+ { "ri", "Reverse Italic" },
+ { "ro", "Reverse Oblique" },
+ { "ot", "Other" }
+ };
+
+ for ( unsigned int i = 0; i < MembersOf(pTranslation); i++ )
+ if ( strcmp(pStr, pTranslation[i].pFrom) == 0 )
+ {
+ return new String( pTranslation[i].pTo,
+ RTL_TEXTENCODING_ISO_8859_1 );
+ }
+
+ return Capitalize(pStr, nLen);
+}
+
+String*
+AnnotateNone( const Attribute& )
+{
+ return new String();
+}
+
+// ---------------------------------------------------------------------------
+//
+//
+// manage global lists of Attributes
+// since XListFonts does never list more than 64K fonts this storage does
+// handle array size and indices with unsigned short values for low
+// memory consumption
+//
+//
+// ---------------------------------------------------------------------------
+
+AttributeStorage::AttributeStorage( unsigned short nDefaultValue ) :
+ mpList( NULL ),
+ mnSize( 0 ),
+ mnCount( 0 ),
+ mnLastmatch( 0 ),
+ mnDefaultValue( nDefaultValue )
+{
+}
+
+AttributeStorage::~AttributeStorage()
+{
+ if ( mpList != NULL )
+ {
+ for ( int i = 0; i < mnCount; i++ )
+ mpList[i].Release();
+ free( mpList );
+ }
+}
+
+#if OSL_DEBUG_LEVEL > 1
+void
+AttributeStorage::Dump()
+{
+ fprintf(stderr, "AttributeStorage: size=%i, used=%i\n", mnSize, mnCount);
+ for ( int i = 0; i < mnCount; i++ )
+ {
+ ByteString aAnnotation = ByteString(
+ mpList[i].GetAnnotation(),
+ RTL_TEXTENCODING_ISO_8859_1 );
+ fprintf(stderr, "\t%4i: <%s><len=%i><val=%i><%s>\n", i, mpList[i].GetName(),
+ mpList[i].GetLength(), mpList[i].GetValue(),
+ aAnnotation.GetBuffer() );
+ }
+ fprintf(stderr, "\n");
+}
+#endif
+
+Attribute*
+AttributeStorage::Retrieve( unsigned short nIndex ) const
+{
+ return nIndex < mnCount ? &mpList[ nIndex ] : (Attribute*)NULL ;
+}
+
+// pClassification contains a list of name-value pairs. If names in
+// the AttributeStorage match those in the pClassification then
+// the according value is copied. Matching means match for the length
+// of the string in pClassification (i.e. arial matches arialnarrow)
+// the strings in pClassification must be in alphabetical order, all
+// strings Lowercase
+void
+AttributeStorage::AddClassification( Attribute *pClassification,
+ unsigned short nNum )
+{
+ for ( int i = 0; i < mnCount; i++ )
+ {
+ unsigned int nLower = 0;
+ unsigned int nUpper = nNum;
+ unsigned int nCurrent;
+ int nComparison = 1;
+ Attribute *pHaystack = 0, *pNeedle;
+
+ pNeedle = &mpList[ i ];
+
+ // binary search
+ while ( nLower < nUpper )
+ {
+ nCurrent = (nLower + nUpper) / 2;
+ pHaystack = &pClassification[ nCurrent ];
+ nComparison = pNeedle->Compare( pHaystack->GetName(),
+ pHaystack->GetLength() );
+ if (nComparison < 0)
+ nUpper = nCurrent;
+ else
+ if (nComparison > 0)
+ nLower = nCurrent + 1;
+ else
+ break;
+ }
+
+ // if there's a match store the according classification in the
+ // Attribute storage, otherwise do nothing since defaults are
+ // already provided in AttributeStorage::Insert()
+ if ( nComparison == 0 )
+ pNeedle->SetValue( pHaystack->GetValue() );
+ }
+}
+
+void
+AttributeStorage::AddClassification( AttributeClassifierT Classify )
+{
+ for ( int i = 0; i < mnCount; i++ )
+ {
+ Attribute& rCurrent = mpList[i] ;
+ int nValue = Classify( rCurrent.GetName() );
+ rCurrent.SetValue( nValue );
+ }
+}
+
+void
+AttributeStorage::AddAnnotation( AttributeAnnotatorT Annotate )
+{
+ for ( int i = 0; i < mnCount; i++ )
+ {
+ String* pAnnotation = Annotate( mpList[i] );
+ mpList[i].SetAnnotation( pAnnotation );
+ }
+}
+
+void
+AttributeStorage::TagFeature( unsigned short nFeature )
+{
+ for ( int i = 0; i < mnCount; i++ )
+ mpList[i].TagFeature( nFeature );
+}
+
+// Enlarge the list of Attributes
+void
+AttributeStorage::Enlarge()
+{
+ if ( mnSize == 0 )
+ {
+ mnSize = 8;
+ mpList = (Attribute*) malloc( mnSize * sizeof(Attribute) );
+ }
+ else
+ {
+ mnSize = mnSize < 32768 ? (mnSize * 2) : 65535;
+ mpList = (Attribute*) realloc( mpList, mnSize * sizeof(Attribute) );
+ }
+}
+
+// nLength is the length as it would be reported by strlen(3)
+// for an null-terminated string. if a string is part of a Xlfd
+// the field separator '-' is taken as '\0'
+// the AttributeStorage itself is NOT sorted to make sure that the
+// leased keys are still valid
+unsigned short
+AttributeStorage::Insert( const char *pString, int nLength )
+{
+ // check whether the last match is still equal to the current
+ // string since XListFonts lists fonts in sets of similar fontnames
+ if ( mnLastmatch < mnCount )
+ {
+ if ( mpList[mnLastmatch].ExactMatch(pString, nLength) )
+ return mnLastmatch;
+ }
+
+ // otherwise search in list
+ for ( int i = 0; i < mnCount; i++ )
+ {
+ if ( mpList[i].ExactMatch(pString, nLength) )
+ return mnLastmatch = i;
+ }
+
+ // if still not found we have to Insert the new string
+ if ( mnSize == mnCount )
+ Enlarge();
+ mpList[mnCount].SetName( pString, nLength );
+ mpList[mnCount].SetValue( mnDefaultValue );
+ mpList[mnCount].SetAnnotation( NULL );
+ mpList[mnCount].SetFeature( XLFD_FEATURE_NONE );
+ mpList[mnCount].InitKey( );
+ mnLastmatch = mnCount;
+ mnCount = mnCount < 65535 ? mnCount + 1 : mnCount;
+
+ return mnLastmatch;
+}
+
+
+// ---------------------------------------------------------------------------
+//
+//
+// Attribute provider is a frame for a set of AttributeStorages.
+//
+//
+// ---------------------------------------------------------------------------
+
+AttributeProvider::AttributeProvider ()
+{
+ mpField[eXLFDFoundry ] = new AttributeStorage(0);
+ mpField[eXLFDFamilyName ] = new AttributeStorage(FAMILY_DONTKNOW);
+ mpField[eXLFDWeightName ] = new AttributeStorage(WEIGHT_NORMAL);
+ mpField[eXLFDSlant ] = new AttributeStorage(ITALIC_NONE);
+ mpField[eXLFDSetwidthName] = new AttributeStorage(WIDTH_NORMAL);
+ mpField[eXLFDAddstyleName] = new AttributeStorage(RTL_TEXTENCODING_DONTKNOW);
+ mpField[eXLFDCharset ] = new AttributeStorage(RTL_TEXTENCODING_DONTKNOW);
+}
+
+AttributeProvider::~AttributeProvider()
+{
+ for ( int i = 0; i < eXLFDMaxEntry; i++ )
+ delete mpField[ i ];
+}
+
+#if OSL_DEBUG_LEVEL > 1
+void
+AttributeProvider::Dump()
+{
+ for ( int i = 0; i < eXLFDMaxEntry; i++ )
+ mpField[ i ]->Dump();
+}
+#endif
+
+extern "C" rtl_TextEncoding
+GetTextEncodingFromAddStylename( const sal_Char *pAddStylename )
+{
+ int nBufferLength = strlen( pAddStylename ) + 1;
+ sal_Char *pBuffer = (sal_Char*)alloca( nBufferLength );
+ for ( int i = 0; i < nBufferLength; i++ )
+ pBuffer[i] = pAddStylename[i] == '_' ? '-' : pAddStylename[i] ;
+
+ return rtl_getTextEncodingFromUnixCharset( pBuffer );
+}
+
+
+// classification information is needed before sorting because of course the
+// classification is the sort criteria
+void
+AttributeProvider::AddClassification()
+{
+ /* mpField[ eXLFDFoundry ] doesn't need classification */
+ mpField[ eXLFDFamilyName ]->AddClassification(
+ (Attribute*)pFamilyAttribute,
+ MembersOf(pFamilyAttribute) );
+ mpField[ eXLFDWeightName ]->AddClassification(
+ (Attribute*)pWeightAttribute,
+ MembersOf(pWeightAttribute) );
+ mpField[ eXLFDSlant ]->AddClassification(
+ (Attribute*)pSlantAttribute,
+ MembersOf(pSlantAttribute) );
+ mpField[ eXLFDSetwidthName ]->AddClassification(
+ (Attribute*)pSetwidthAttribute,
+ MembersOf(pSetwidthAttribute) );
+ mpField[ eXLFDAddstyleName ]->AddClassification(
+ GetTextEncodingFromAddStylename );
+ mpField[ eXLFDCharset ]->AddClassification(
+ rtl_getTextEncodingFromUnixCharset );
+}
+
+// add some pretty print description
+void
+AttributeProvider::AddAnnotation()
+{
+ mpField[ eXLFDFoundry ]->AddAnnotation( AnnotateNone );
+ mpField[ eXLFDFamilyName ]->AddAnnotation( AnnotateString );
+ mpField[ eXLFDWeightName ]->AddAnnotation( AnnotateString );
+ mpField[ eXLFDSlant ]->AddAnnotation( AnnotateSlant );
+ mpField[ eXLFDSetwidthName ]->AddAnnotation( AnnotateString );
+ mpField[ eXLFDAddstyleName ]->AddAnnotation( AnnotateNone );
+ mpField[ eXLFDCharset ]->AddAnnotation( AnnotateNone );
+}
+
+// this is the misc or any section: dirty hacks for dirty xlfd usage
+void
+AttributeProvider::TagFeature()
+{
+ mpField[ eXLFDFamilyName ]->TagFeature(
+ XLFD_FEATURE_OL_GLYPH
+ | XLFD_FEATURE_OL_CURSOR
+ | XLFD_FEATURE_NARROW
+ | XLFD_FEATURE_INTERFACE_FONT
+ | XLFD_FEATURE_APPLICATION_FONT);
+
+ mpField[ eXLFDSetwidthName ]->TagFeature(
+ XLFD_FEATURE_NARROW );
+
+ mpField[ eXLFDAddstyleName ]->TagFeature(
+ XLFD_FEATURE_REDUNDANTSTYLE );
+}
+
diff --git a/vcl/unx/source/gdi/xlfd_attr.hxx b/vcl/unx/source/gdi/xlfd_attr.hxx
new file mode 100644
index 000000000000..b721310da506
--- /dev/null
+++ b/vcl/unx/source/gdi/xlfd_attr.hxx
@@ -0,0 +1,228 @@
+/*************************************************************************
+ *
+ * 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 XLFD_ATTRIBUTE_HXX
+#define XLFD_ATTRIBUTE_HXX
+
+#include <salunx.h>
+#include <tools/string.hxx>
+
+
+struct Attribute {
+
+ const char* mpName;
+ unsigned short mnLength;
+ unsigned short mnValue;
+ unsigned short mnFeature;
+ String* mpAnnotation;
+ rtl::OString* mpKeyName;
+
+ const char* GetName() const
+ { return mpName; }
+ unsigned short GetValue() const
+ { return mnValue; }
+ unsigned short GetLength() const
+ { return mnLength; }
+ Bool HasFeature( unsigned short nFeature ) const
+ { return ((mnFeature & nFeature) != 0); }
+ const String &GetAnnotation() const
+ { return *mpAnnotation; }
+ const rtl::OString&
+ GetKey();
+ void InitKey();
+
+ void SetName( const char *p, int nLen );
+ void SetValue( unsigned short nIn )
+ { mnValue = nIn; }
+ void SetAnnotation( String *pString )
+ { mpAnnotation = pString; }
+ void SetFeature( unsigned short nFeature )
+ { mnFeature = nFeature; }
+ void TagFeature( unsigned short nFeature );
+
+ int Compare( const char *p, int nLen );
+ Bool ExactMatch( const char *p, int nLen );
+ void Release();
+};
+
+
+void
+AppendAttribute( Attribute *pAttribute, ByteString &rString );
+
+
+typedef String*(*AttributeAnnotatorT)(const Attribute &rAttribute);
+extern "C" {
+typedef rtl_TextEncoding(*AttributeClassifierT)(const char* pStr);
+}
+
+#define XLFD_FEATURE_NONE 0x0000
+#define XLFD_FEATURE_NARROW 0x0001
+#define XLFD_FEATURE_OL_GLYPH 0x0002
+#define XLFD_FEATURE_OL_CURSOR 0x0004
+#define XLFD_FEATURE_REDUNDANTSTYLE 0x0008
+#define XLFD_FEATURE_APPLICATION_FONT 0x0010
+
+#define XLFD_FEATURE_INTERFACE_FONT 0x0020
+#define XLFD_FEATURE_LQ 0x0040
+#define XLFD_FEATURE_MQ 0x0080
+#define XLFD_FEATURE_HQ 0x0100
+
+// ---------------------------------------------------------------------------
+//
+//
+// manage global lists of Attributes
+// since XListFonts does never list more than 64K fonts this storage does
+// handle array size and indices with unsigned short values for low
+// memory consumption
+//
+//
+// ---------------------------------------------------------------------------
+
+class AttributeStorage {
+
+ private:
+
+ Attribute* mpList;
+ unsigned short mnSize;
+ unsigned short mnCount;
+ unsigned short mnLastmatch;
+ unsigned short mnDefaultValue;
+
+ void Enlarge();
+ AttributeStorage();
+
+ public:
+
+ AttributeStorage( unsigned short nDefaultValue );
+ ~AttributeStorage();
+ unsigned short Insert( const char *pString, int nLength );
+ Attribute* Retrieve( unsigned short nIndex ) const ;
+ void AddClassification( Attribute *pClassification,
+ unsigned short nNum );
+ void AddClassification( AttributeClassifierT Classify );
+ void TagFeature( unsigned short nFeature );
+ void AddAnnotation( AttributeAnnotatorT Annotate );
+ #if OSL_DEBUG_LEVEL > 1
+ void Dump();
+ #endif
+};
+
+
+// ---------------------------------------------------------------------------
+//
+//
+// Attribute provider is a frame for a set of AttributeStorages. For XLFD
+// interpretation and efficient storage, AttributeStorages for foundry,
+// family_name, weight_name, slant, setwidth_name, add_style_name and combined
+// charset_registry and charset_encoding are used. pixel_size, point_size,
+// resolution_x and resolution_y are stored as numbers. please note that this
+// does not allow storage of matrix-enhanced fonts. spacing is stored as
+// a char, since only the 'm', 'c' and 'p' types are defined.
+//
+//
+// ---------------------------------------------------------------------------
+
+enum eXLFDAttributeT {
+ eXLFDFoundry = 0,
+ eXLFDFamilyName,
+ eXLFDWeightName,
+ eXLFDSlant,
+ eXLFDSetwidthName,
+ eXLFDAddstyleName,
+ eXLFDCharset,
+ eXLFDMaxEntry
+};
+
+class AttributeProvider {
+
+ private:
+
+ AttributeStorage* mpField[ eXLFDMaxEntry ];
+
+ AttributeStorage* GetField( eXLFDAttributeT eXLFDField )
+ { return mpField[ eXLFDField]; }
+ public:
+
+ AttributeProvider ();
+ ~AttributeProvider ();
+
+ void AddClassification();
+ void AddAnnotation();
+ void TagFeature();
+ #if OSL_DEBUG_LEVEL > 1
+ void Dump();
+ #endif
+
+ // these are just shortcuts or proxies for the most common used
+ // AttributeStorage functionality
+ AttributeStorage* GetFoundry()
+ { return GetField(eXLFDFoundry); }
+ AttributeStorage* GetFamily()
+ { return GetField(eXLFDFamilyName); }
+ AttributeStorage* GetWeight()
+ { return GetField(eXLFDWeightName); }
+ AttributeStorage* GetSlant()
+ { return GetField(eXLFDSlant); }
+ AttributeStorage* GetSetwidth()
+ { return GetField(eXLFDSetwidthName); }
+ AttributeStorage* GetAddstyle()
+ { return GetField(eXLFDAddstyleName); }
+ AttributeStorage* GetCharset()
+ { return GetField(eXLFDCharset); }
+
+ Attribute* RetrieveFoundry( unsigned short nIndex )
+ { return GetFoundry()->Retrieve(nIndex); }
+ Attribute* RetrieveFamily( unsigned short nIndex )
+ { return GetFamily()->Retrieve(nIndex); }
+ Attribute* RetrieveWeight( unsigned short nIndex )
+ { return GetWeight()->Retrieve(nIndex); }
+ Attribute* RetrieveSlant( unsigned short nIndex )
+ { return GetSlant()->Retrieve(nIndex); }
+ Attribute* RetrieveSetwidth( unsigned short nIndex )
+ { return GetSetwidth()->Retrieve(nIndex); }
+ Attribute* RetrieveAddstyle( unsigned short nIndex )
+ { return GetAddstyle()->Retrieve(nIndex); }
+ Attribute* RetrieveCharset( unsigned short nIndex )
+ { return GetCharset()->Retrieve(nIndex); }
+
+ unsigned short InsertFoundry( const char *pString, int nLength )
+ { return GetFoundry()->Insert(pString, nLength); }
+ unsigned short InsertFamily( const char *pString, int nLength )
+ { return GetFamily()->Insert(pString, nLength); }
+ unsigned short InsertWeight( const char *pString, int nLength )
+ { return GetWeight()->Insert(pString, nLength); }
+ unsigned short InsertSlant( const char *pString, int nLength )
+ { return GetSlant()->Insert(pString, nLength); }
+ unsigned short InsertSetwidth( const char *pString, int nLength )
+ { return GetSetwidth()->Insert(pString, nLength);}
+ unsigned short InsertAddstyle( const char *pString, int nLength )
+ { return GetAddstyle()->Insert(pString, nLength);}
+ unsigned short InsertCharset( const char *pString, int nLength )
+ { return GetCharset()->Insert(pString, nLength); }
+};
+
+#endif /* XLFD_ATTRIBUTE_HXX */
+
diff --git a/vcl/unx/source/gdi/xlfd_extd.cxx b/vcl/unx/source/gdi/xlfd_extd.cxx
new file mode 100644
index 000000000000..73731eddf115
--- /dev/null
+++ b/vcl/unx/source/gdi/xlfd_extd.cxx
@@ -0,0 +1,1001 @@
+/*************************************************************************
+ *
+ * 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 <string.h>
+#include "xlfd_attr.hxx"
+#include "xlfd_smpl.hxx"
+#include "xlfd_extd.hxx"
+#include <vcl/outfont.hxx>
+#include <rtl/alloc.h>
+
+#ifndef _RTL_TENCINFO_H_
+#include <rtl/tencinfo.h>
+#endif
+
+#include <set>
+
+// --------------------------------------------------------------------------
+
+ImplX11FontData::ImplX11FontData( const ExtendedXlfd& rXlfd, int nHeight )
+: ImplFontData( rXlfd, X11IFD_MAGIC ),
+ mrXlfd( rXlfd )
+{
+ mnHeight = nHeight;
+ mnWidth = 0;
+}
+
+ImplFontEntry* ImplX11FontData::CreateFontInstance( ImplFontSelectData& rFSD ) const
+{
+ ImplFontEntry* pEntry = new ImplFontEntry( rFSD );
+ return pEntry;
+}
+
+sal_IntPtr ImplX11FontData::GetFontId() const
+{
+ return reinterpret_cast<sal_IntPtr>(&mrXlfd);
+}
+
+// --------------------------------------------------------------------------
+//
+// classes for Xlfd handling that contain more than a single encoding.
+// Members that may vary through different encodings are stored in
+// a mpEncodingInfo member. There are three different classes:
+// true scalable fonts (truetype and type1) scalable bitmap fonts
+// (the ugly ones) and bitmap fonts. The ExtendedXlfd stores all the members
+// that are specific to a font outline
+// ( e.g. adobe-times-roman-medium-r-normal- X -p- X )
+// and specifies the interface.
+//
+// --------------------------------------------------------------------------
+
+ExtendedXlfd::EncodingInfo&
+ExtendedXlfd::EncodingInfo::operator= ( const Xlfd *pXlfd )
+{
+ mcSpacing = pXlfd->mcSpacing;
+ mnResolutionX = pXlfd->mnResolutionX;
+ mnResolutionY = pXlfd->mnResolutionY;
+ mnAddstyle = pXlfd->mnAddstyle;
+ mnCharset = pXlfd->mnCharset;
+ mnEncoding = pXlfd->GetEncoding();
+
+ return *this;
+}
+
+// ------ base class --------------------------------------------------------
+
+ExtendedXlfd::ExtendedXlfd( bool bScalable )
+: mbScalable( bScalable ),
+ mnEncodings( 0 ),
+ mnEncCapacity( 0 ),
+ mpEncodingInfo( NULL )
+{
+ mbOrientation = false;
+ mbDevice = false;
+ mbSubsettable = false;
+ mbEmbeddable = false;
+
+ mnQuality = -1;
+}
+
+ExtendedXlfd::~ExtendedXlfd()
+{
+ if ( mnEncodings != 0 )
+ rtl_freeMemory( mpEncodingInfo );
+}
+
+inline void*
+Realloc( void *pPtr, sal_Size nSize )
+{
+ return rtl_reallocateMemory( pPtr, nSize );
+}
+
+int
+ExtendedXlfd::GetEncodingIdx( rtl_TextEncoding nEncoding ) const
+{
+ for ( int i = 0; i < mnEncodings; i++ )
+ if ( nEncoding == mpEncodingInfo[i].mnEncoding )
+ return i;
+ return -1;
+}
+
+bool
+ExtendedXlfd::HasEncoding( rtl_TextEncoding nEncoding ) const
+{
+ return !(GetEncodingIdx( nEncoding ) < 0) ;
+}
+
+rtl_TextEncoding
+ExtendedXlfd::GetEncoding( int i ) const
+{
+ if ( i < mnEncodings && i >= 0 )
+ return mpEncodingInfo[i].mnEncoding;
+
+ return RTL_TEXTENCODING_DONTKNOW;
+}
+
+rtl_TextEncoding
+ExtendedXlfd::GetEncoding() const
+{
+ return mnEncodings == 1 ? mpEncodingInfo[0].mnEncoding : RTL_TEXTENCODING_DONTKNOW;
+}
+
+// query the most unicode / Ascii compatible font: either one of the fonts
+// is utf16 encoded or there's a single byte font which is unicode
+// compatible for the first 256 chars (latin1) or for at least 128
+// chars (most latin-X encodings, cyrillic encodings)
+rtl_TextEncoding
+ExtendedXlfd::GetAsciiEncoding( int *pAsciiRange ) const
+{
+ rtl_TextEncoding nBestEncoding = RTL_TEXTENCODING_DONTKNOW;
+ int nLargestRange = 0x0000;
+
+ for ( int i = 0; i < mnEncodings && nLargestRange < 0xffff; i++ )
+ {
+ rtl_TextEncoding nCurEncoding = mpEncodingInfo[i].mnEncoding;
+ switch ( nCurEncoding )
+ {
+ case RTL_TEXTENCODING_UNICODE:
+ nLargestRange = 0xffff;
+ nBestEncoding = nCurEncoding;
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_1:
+ case RTL_TEXTENCODING_MS_1252:
+ nLargestRange = 0x00ff;
+ nBestEncoding = nCurEncoding;
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_2:
+ case RTL_TEXTENCODING_ISO_8859_4:
+ case RTL_TEXTENCODING_ISO_8859_5:
+ case RTL_TEXTENCODING_ISO_8859_6:
+ case RTL_TEXTENCODING_ISO_8859_7:
+ case RTL_TEXTENCODING_ISO_8859_8:
+ case RTL_TEXTENCODING_ISO_8859_9:
+ case RTL_TEXTENCODING_ISO_8859_13:
+ case RTL_TEXTENCODING_ISO_8859_15:
+ case RTL_TEXTENCODING_MS_1251:
+ case RTL_TEXTENCODING_KOI8_R:
+ case RTL_TEXTENCODING_JIS_X_0201:
+ if ( nLargestRange < 0x0080 )
+ {
+ nLargestRange = 0x0080;
+ nBestEncoding = nCurEncoding;
+ }
+ break;
+
+ default:
+ if ( nLargestRange == 0x0000 )
+ {
+ nBestEncoding = nCurEncoding;
+ }
+ break;
+ }
+ }
+
+ if ( pAsciiRange != NULL )
+ *pAsciiRange = nLargestRange;
+
+ return nBestEncoding;
+}
+
+bool
+ExtendedXlfd::AddEncoding( const Xlfd *pXlfd )
+{
+ rtl_TextEncoding nEncoding = pXlfd->GetEncoding();
+ if ( HasEncoding(nEncoding) )
+ return false;
+
+ if ( mnEncodings == 0 )
+ {
+ // bootstrap
+ mnFoundry = pXlfd->mnFoundry;
+ mnFamily = pXlfd->mnFamily;
+ mnWeight = pXlfd->mnWeight;
+ mnSlant = pXlfd->mnSlant;
+ mnSetwidth = pXlfd->mnSetwidth;
+ mpFactory = pXlfd->mpFactory;
+
+ Attribute *pFamilyAttr = mpFactory->RetrieveFamily( mnFamily );
+ Attribute *pWeightAttr = mpFactory->RetrieveWeight( mnWeight );
+ Attribute *pWidthAttr = mpFactory->RetrieveSetwidth( mnSetwidth );
+ Attribute *pSlantAttr = mpFactory->RetrieveSlant( mnSlant );
+
+ meFamily = GetFamilyType();
+ meWeight = GetWeight();
+ meItalic = GetSlant();
+ meWidthType = GetWidthType();
+ mbSymbolFlag= (GetEncoding() == RTL_TEXTENCODING_SYMBOL);
+ mePitch = GetPitch();
+
+ maName = pFamilyAttr->GetAnnotation();
+
+ // the helvetica narrow hack
+ if ( ! pFamilyAttr->HasFeature(XLFD_FEATURE_NARROW)
+ && pWidthAttr->HasFeature(XLFD_FEATURE_NARROW) )
+ {
+ static const String aNarrow( RTL_CONSTASCII_USTRINGPARAM(" Narrow") );
+ maName += aNarrow;
+ }
+
+ // stylename = weight + slant + width
+ // XXX Fix me: there may be a space missing between them
+ if ( meWeight != WEIGHT_NORMAL )
+ maStyleName += pWeightAttr->GetAnnotation();
+ if ( meItalic != ITALIC_NONE )
+ maStyleName += pSlantAttr->GetAnnotation();
+ if ( (meWidthType != WIDTH_NORMAL)
+ && (! pWidthAttr->HasFeature(XLFD_FEATURE_NARROW)) )
+ maStyleName += pWidthAttr->GetAnnotation();
+ }
+
+ if( mnEncodings <= mnEncCapacity )
+ {
+ mnEncCapacity += mnEncodings + 4;
+ mpEncodingInfo = (EncodingInfo*)Realloc( mpEncodingInfo, mnEncCapacity * sizeof(EncodingInfo) );
+ }
+
+ mpEncodingInfo[ mnEncodings ] = pXlfd;
+ mnEncodings += 1;
+ return true;
+}
+
+void
+ExtendedXlfd::ToString( ByteString &rString,
+ unsigned short /*nPixelSize*/, rtl_TextEncoding /*nEncoding*/ ) const
+{
+ AppendAttribute( mpFactory->RetrieveFoundry(mnFoundry), rString );
+ AppendAttribute( mpFactory->RetrieveFamily(mnFamily), rString );
+ AppendAttribute( mpFactory->RetrieveWeight(mnWeight), rString );
+ AppendAttribute( mpFactory->RetrieveSlant(mnSlant), rString );
+ AppendAttribute( mpFactory->RetrieveSetwidth(mnSetwidth), rString );
+}
+
+void
+ExtendedXlfd::ToString( ByteString &rString,
+ unsigned short /*nPixelSize*/, char* /*pMatricsString*/, rtl_TextEncoding /*nEncoding*/ ) const
+{
+ AppendAttribute( mpFactory->RetrieveFoundry(mnFoundry), rString );
+ AppendAttribute( mpFactory->RetrieveFamily(mnFamily), rString );
+ AppendAttribute( mpFactory->RetrieveWeight(mnWeight), rString );
+ AppendAttribute( mpFactory->RetrieveSlant(mnSlant), rString );
+ AppendAttribute( mpFactory->RetrieveSetwidth(mnSetwidth), rString );
+}
+
+static FontPitch GetPitchFromX11Pitch( const char cSpacing )
+{
+ switch ( cSpacing )
+ {
+ case 'c': // fall through
+ case 'm': return PITCH_FIXED;
+ case 'p': return PITCH_VARIABLE;
+ default: return PITCH_DONTKNOW;
+ }
+}
+
+// you must not call any of the ExtendedXlfd::GetXXX() functions if the
+// ExtendedXlfd is really empty (i.e. mnEncodings is zero)
+
+FontPitch ExtendedXlfd::GetPitch() const
+{
+ if( mnEncodings > 1 )
+ return PITCH_VARIABLE;
+ if( mnEncodings == 1 )
+ return GetPitchFromX11Pitch( mpEncodingInfo[0].mcSpacing );
+ return PITCH_DONTKNOW;
+}
+
+FontPitch ExtendedXlfd::GetPitch( rtl_TextEncoding nEncoding ) const
+{
+ for ( int nIdx = 0; nIdx < mnEncodings; nIdx++ )
+ if ( mpEncodingInfo[nIdx].mnEncoding == nEncoding )
+ return GetPitchFromX11Pitch( mpEncodingInfo[nIdx].mcSpacing );
+ return PITCH_DONTKNOW;
+}
+
+FontFamily ExtendedXlfd::GetFamilyType() const
+{
+ Attribute *pFamilyAttr= mpFactory->RetrieveFamily(mnFamily);
+ return (FontFamily)pFamilyAttr->GetValue();
+}
+
+FontWeight ExtendedXlfd::GetWeight() const
+{
+ Attribute *pWeightAttr = mpFactory->RetrieveWeight(mnWeight);
+ return (FontWeight)pWeightAttr->GetValue();
+}
+
+FontItalic ExtendedXlfd::GetSlant() const
+{
+ Attribute *pSlantAttr = mpFactory->RetrieveSlant(mnSlant);
+ return (FontItalic)pSlantAttr->GetValue();
+}
+
+FontWidth ExtendedXlfd::GetWidthType() const
+{
+ Attribute *pWidthAttr = mpFactory->RetrieveSetwidth(mnSetwidth);
+ return (FontWidth)pWidthAttr->GetValue();
+}
+
+class CodeRange
+{
+public:
+ CodeRange( int nMin, int nEnd ) : mnMin( nMin ), mnEnd( nEnd ) {}
+
+ sal_uInt32 GetMin() const { return mnMin; }
+ sal_uInt32 GetEnd() const { return mnEnd; }
+
+ bool operator<( const CodeRange& r ) const
+ { return (mnMin<r.mnMin) || ((mnMin==r.mnMin) && (mnEnd<r.mnEnd)); }
+
+private:
+ sal_uInt32 mnMin, mnEnd;
+};
+
+
+int ExtendedXlfd::GetFontCodeRanges( sal_uInt32* pCodePairs ) const
+{
+ bool bHasUnicode = false;
+ bool bHasUnknownEncoding = false;
+
+ // approximate unicode ranges from encodings
+ typedef std::set<CodeRange> RangeSet;
+ RangeSet aRangeSet;
+
+ for( unsigned short i = 0; i < mnEncodings; ++i )
+ {
+ // TODO: move encoding -> unicode range mapping to RTL
+ // NOTE: for now only some are VERY roughly approximated
+ const rtl_TextEncoding eEncoding = mpEncodingInfo[i].mnEncoding;
+ switch( mpEncodingInfo[i].mnEncoding )
+ {
+ case RTL_TEXTENCODING_SYMBOL: // postscript symbol encoding
+ aRangeSet.insert( CodeRange( 0x0020, 0x0100 ) ); // symbol aliasing
+ aRangeSet.insert( CodeRange( 0xF020, 0xF100 ) );
+ break;
+
+ case RTL_TEXTENCODING_ISO_8859_15:
+ aRangeSet.insert( CodeRange( 0x20AC, 0x20AD ) ); // Euro currency symbol
+ // fall through
+ case RTL_TEXTENCODING_APPLE_ROMAN:
+ case RTL_TEXTENCODING_ISO_8859_1:
+ case RTL_TEXTENCODING_MS_1252:
+ case RTL_TEXTENCODING_IBM_437:
+ case RTL_TEXTENCODING_IBM_852:
+ aRangeSet.insert( CodeRange( 0x0020, 0x0080 ) );
+ aRangeSet.insert( CodeRange( 0x00A0, 0x0100 ) );
+ break;
+
+ // Traditional, Simplified, Japanese
+ case RTL_TEXTENCODING_APPLE_CHINSIMP:
+ case RTL_TEXTENCODING_APPLE_CHINTRAD:
+ case RTL_TEXTENCODING_APPLE_JAPANESE:
+ case RTL_TEXTENCODING_SHIFT_JIS:
+ case RTL_TEXTENCODING_GB_2312:
+ case RTL_TEXTENCODING_GBT_12345:
+ case RTL_TEXTENCODING_GBK:
+ case RTL_TEXTENCODING_BIG5:
+ case RTL_TEXTENCODING_EUC_JP:
+ case RTL_TEXTENCODING_EUC_CN:
+ case RTL_TEXTENCODING_EUC_TW:
+ case RTL_TEXTENCODING_ISO_2022_JP:
+ case RTL_TEXTENCODING_ISO_2022_CN:
+ case RTL_TEXTENCODING_GB_18030:
+ case RTL_TEXTENCODING_BIG5_HKSCS:
+ case RTL_TEXTENCODING_JIS_X_0201:
+ case RTL_TEXTENCODING_JIS_X_0208:
+ case RTL_TEXTENCODING_JIS_X_0212:
+ case RTL_TEXTENCODING_MS_932:
+ case RTL_TEXTENCODING_MS_936:
+ case RTL_TEXTENCODING_MS_950:
+ aRangeSet.insert( CodeRange( 0x3000, 0xA000 ) );
+ aRangeSet.insert( CodeRange( 0xF900, 0xFB00 ) );
+ break;
+
+ // Korean
+ case RTL_TEXTENCODING_APPLE_KOREAN:
+ case RTL_TEXTENCODING_MS_949:
+ case RTL_TEXTENCODING_MS_1361:
+ case RTL_TEXTENCODING_EUC_KR:
+ case RTL_TEXTENCODING_ISO_2022_KR:
+ aRangeSet.insert( CodeRange( 0x1100, 0x1200 ) );
+ aRangeSet.insert( CodeRange( 0x3130, 0x3190 ) );
+ aRangeSet.insert( CodeRange( 0xAC00, 0xD7A4 ) );
+ break;
+
+ // unknown encoding
+ case RTL_TEXTENCODING_DONTKNOW:
+ bHasUnknownEncoding = true;
+ break;
+
+ // Unicode
+ case RTL_TEXTENCODING_UNICODE:
+ case RTL_TEXTENCODING_UTF7:
+ case RTL_TEXTENCODING_UTF8:
+ bHasUnicode = true;
+ break;
+
+ // misc 8bit encodings
+ default:
+ if( !rtl_isOctetTextEncoding( eEncoding ) )
+ bHasUnknownEncoding = true;
+ else
+ {
+ // use the unicode converter to get the coverage of an 8bit encoding
+ rtl_TextToUnicodeConverter aConverter = rtl_createTextToUnicodeConverter( eEncoding );
+ rtl_UnicodeToTextContext aCvtContext = rtl_createTextToUnicodeContext( aConverter );
+ if( !aConverter || !aCvtContext )
+ bHasUnknownEncoding = true;
+ else
+ {
+ sal_Char cCharsInp[ 0x100 ];
+ for( int j = 0x20; j < 0x080; ++j )
+ cCharsInp[ j-0x20 ] = j;
+ for( int j = 0xA0; j < 0x100; ++j )
+ cCharsInp[ j-0x40 ] = j;
+
+ sal_Unicode cCharsOut[ 0x100 ];
+ sal_uInt32 nCvtInfo;
+ sal_Size nSrcCvtBytes;
+ int nOutLen = rtl_convertTextToUnicode(
+ aConverter, aCvtContext,
+ cCharsInp, 0xC0,
+ cCharsOut, sizeof(cCharsOut)/sizeof(*cCharsOut),
+ RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE
+ | RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_IGNORE,
+ &nCvtInfo, &nSrcCvtBytes );
+
+ for( int j = 0; j < nOutLen; ++j )
+ aRangeSet.insert( CodeRange( cCharsOut[j], cCharsOut[j]+1 ) );
+
+ rtl_destroyTextToUnicodeConverter( aCvtContext );
+ rtl_destroyTextToUnicodeConverter( aConverter );
+ }
+ }
+ break;
+ }
+ }
+
+ // unicode encoded fonts usually do not cover the entire unicode range
+ // => only use them to determine coverage when no other encodings are available
+ if( aRangeSet.empty() && (bHasUnicode || bHasUnknownEncoding) )
+ {
+ if( pCodePairs )
+ {
+ pCodePairs[0] = 0x0020;
+ pCodePairs[1] = 0xD800;
+ pCodePairs[2] = 0xE000;
+ pCodePairs[3] = 0xFFFE;
+ }
+ return 2;
+ }
+
+ if( aRangeSet.empty() )
+ return 0;
+
+ // sort and merge the code pairs
+ sal_uInt32* pDst = pCodePairs;
+ RangeSet::const_iterator it = aRangeSet.begin();
+ for( sal_uInt32 nEnd = 0; it != aRangeSet.end(); ++it )
+ {
+ // check overlap with to previous range
+ const CodeRange& rSrc = *it;
+ if( nEnd < rSrc.GetMin() )
+ {
+ nEnd = rSrc.GetEnd();
+ if( pCodePairs )
+ {
+ pDst[0] = rSrc.GetMin();
+ pDst[1] = rSrc.GetEnd();
+ }
+ pDst += 2;
+ }
+ else
+ {
+ // merge overlapping ranges
+ if( nEnd < rSrc.GetEnd() )
+ {
+ nEnd = rSrc.GetEnd();
+ if( pCodePairs )
+ pDst[-1] = nEnd;
+ }
+ }
+ }
+
+ int nRangeCount = (pDst - pCodePairs) / 2;
+ return nRangeCount;
+}
+
+// ------ class to handle scalable bitmap fonts ------------------------------
+
+ScalableBitmapXlfd::ScalableBitmapXlfd()
+: ExtendedXlfd( true )
+{}
+
+ScalableBitmapXlfd::~ScalableBitmapXlfd()
+{}
+
+void
+ScalableBitmapXlfd::ToString( ByteString &rString,
+ unsigned short nPixelSize, rtl_TextEncoding nEncoding ) const
+{
+ int nIdx = GetEncodingIdx( nEncoding );
+ if ( nIdx < 0 )
+ return;
+
+ ExtendedXlfd::ToString( rString, nPixelSize, nEncoding );
+ EncodingInfo& rInfo = mpEncodingInfo[ nIdx ];
+
+ AppendAttribute( mpFactory->RetrieveAddstyle(rInfo.mnAddstyle), rString );
+
+ rString += '-';
+ rString += ByteString::CreateFromInt32( nPixelSize );
+ rString += "-0-";
+ rString += ByteString::CreateFromInt32( rInfo.mnResolutionX );
+ rString += '-';
+ rString += ByteString::CreateFromInt32( rInfo.mnResolutionY );
+ rString += '-';
+ rString += static_cast< char >(rInfo.mcSpacing);
+ rString += "-0";
+
+ AppendAttribute( mpFactory->RetrieveCharset(rInfo.mnCharset), rString );
+}
+
+void
+ScalableBitmapXlfd::ToString( ByteString &rString,
+ unsigned short nPixelSize, char *pMatricsString, rtl_TextEncoding nEncoding ) const
+{
+ int nIdx = GetEncodingIdx( nEncoding );
+ if ( nIdx < 0 )
+ return;
+
+ ExtendedXlfd::ToString( rString, nPixelSize, nEncoding );
+ EncodingInfo& rInfo = mpEncodingInfo[ nIdx ];
+
+ AppendAttribute( mpFactory->RetrieveAddstyle(rInfo.mnAddstyle), rString );
+
+ rString += "-*-";
+ char pTmp[256];
+ snprintf( pTmp, sizeof(pTmp), pMatricsString, nPixelSize, nPixelSize );
+ rString += pTmp;
+ rString += "-*-*-";
+ rString += static_cast< char >(rInfo.mcSpacing);
+ rString += "-*";
+
+ AppendAttribute( mpFactory->RetrieveCharset(rInfo.mnCharset), rString );
+}
+
+ImplFontData* ScalableBitmapXlfd::GetImplFontData() const
+{
+ ImplX11FontData* pFontData = new ImplX11FontData( *this, 0 );
+ pFontData->mnQuality= 0;
+ return pFontData;
+}
+
+// ------ class to handle true bitmap fonts ----------------------------------
+
+void
+BitmapXlfd::ToString( ByteString &rString,
+ unsigned short nPixelSize, char *pMatricsString, rtl_TextEncoding nEncoding ) const
+{
+ int nIdx = GetEncodingIdx( nEncoding );
+ if ( nIdx < 0 )
+ return;
+
+ ExtendedXlfd::ToString( rString, nPixelSize, nEncoding );
+ EncodingInfo& rInfo = mpEncodingInfo[ nIdx ];
+
+ AppendAttribute( mpFactory->RetrieveAddstyle(rInfo.mnAddstyle), rString );
+
+ rString += "-*-";
+ char pTmp[256];
+ snprintf( pTmp, sizeof(pTmp), pMatricsString, nPixelSize, nPixelSize );
+ rString += pTmp;
+ rString += "-*-*-";
+ rString += static_cast< char >(rInfo.mcSpacing);
+ rString += "-*";
+
+ AppendAttribute( mpFactory->RetrieveCharset(rInfo.mnCharset), rString );
+}
+
+BitmapXlfd::BitmapXlfd( )
+: ExtendedXlfd( false )
+{}
+
+BitmapXlfd::~BitmapXlfd( )
+{}
+
+bool
+BitmapXlfd::AddEncoding( const Xlfd *pXlfd )
+{
+ if ( mnEncodings == 0 )
+ {
+ mnPixelSize = pXlfd->mnPixelSize;
+ mnPointSize = pXlfd->mnPointSize;
+ mnAverageWidth = pXlfd->mnAverageWidth;
+ }
+
+ return ExtendedXlfd::AddEncoding( pXlfd );
+}
+
+void
+BitmapXlfd::ToString( ByteString &rString,
+ unsigned short nPixelSize, rtl_TextEncoding nEncoding ) const
+{
+ int nIdx = GetEncodingIdx( nEncoding );
+ if ( nIdx < 0 )
+ return;
+
+ ExtendedXlfd::ToString( rString, nPixelSize, nEncoding );
+ EncodingInfo& rInfo = mpEncodingInfo[ nIdx ];
+ AppendAttribute( mpFactory->RetrieveAddstyle(rInfo.mnAddstyle), rString );
+ rString += '-';
+ rString += ByteString::CreateFromInt32( mnPixelSize );
+ rString += "-*-*-*-";
+ rString += static_cast< char >(rInfo.mcSpacing);
+ rString += "-*";
+
+ AppendAttribute( mpFactory->RetrieveCharset(rInfo.mnCharset), rString );
+}
+
+ImplFontData* BitmapXlfd::GetImplFontData() const
+{
+ ImplX11FontData* pFontData = new ImplX11FontData( *this, mnPixelSize );
+ pFontData->mnQuality= 100;
+ return pFontData;
+}
+
+// ------ class to handle true scalable fonts --------------------------------
+
+ScalableXlfd::ScalableXlfd()
+: ExtendedXlfd( true )
+{}
+
+ScalableXlfd::~ScalableXlfd()
+{}
+
+void
+ScalableXlfd::ToString( ByteString &rString,
+ unsigned short nPixelSize, rtl_TextEncoding nEncoding ) const
+{
+ int nIdx = GetEncodingIdx( nEncoding );
+ if ( nIdx < 0 )
+ return;
+
+ ExtendedXlfd::ToString( rString, nPixelSize, nEncoding);
+
+ EncodingInfo& rInfo = mpEncodingInfo[ nIdx ];
+ AppendAttribute( mpFactory->RetrieveAddstyle(rInfo.mnAddstyle), rString );
+
+ rString += '-';
+ rString += ByteString::CreateFromInt32( nPixelSize );
+ rString += "-0-0-0-";
+ rString += static_cast< char >(rInfo.mcSpacing);
+ rString += "-0";
+
+ AppendAttribute( mpFactory->RetrieveCharset(rInfo.mnCharset), rString );
+}
+
+void
+ScalableXlfd::ToString( ByteString &rString,
+ unsigned short nPixelSize, char* pMatricsString, rtl_TextEncoding nEncoding ) const
+{
+ int nIdx = GetEncodingIdx( nEncoding );
+ if ( nIdx < 0 )
+ return;
+
+ ExtendedXlfd::ToString( rString, nPixelSize, nEncoding);
+
+ EncodingInfo& rInfo = mpEncodingInfo[ nIdx ];
+ AppendAttribute( mpFactory->RetrieveAddstyle(rInfo.mnAddstyle), rString );
+
+ rString += "-*-";
+ char pTmp[256];
+ snprintf( pTmp, sizeof(pTmp), pMatricsString, nPixelSize, nPixelSize );
+ rString += pTmp;
+ rString += "-*-*-";
+ rString += static_cast< char >(rInfo.mcSpacing);
+ rString += "-*";
+
+ AppendAttribute( mpFactory->RetrieveCharset(rInfo.mnCharset), rString );
+}
+
+ImplFontData* ScalableXlfd::GetImplFontData() const
+{
+ ImplX11FontData* pFontData = new ImplX11FontData( *this, 0 );
+ pFontData->mnQuality= 200;
+ return pFontData;
+}
+
+/* ------- virtual fonts for user interface ------------------------------- */
+
+VirtualXlfd::ExtEncodingInfo&
+VirtualXlfd::ExtEncodingInfo::operator= ( const Xlfd *pXlfd )
+{
+ mnFoundry = pXlfd->mnFoundry;
+ mnFamily = pXlfd->mnFamily;
+ mnWeight = pXlfd->mnWeight;
+ mnSlant = pXlfd->mnSlant;
+ mnSetwidth = pXlfd->mnSetwidth;
+
+ return *this;
+}
+
+VirtualXlfd::VirtualXlfd()
+: ExtendedXlfd( true ),
+ mnExtCapacity(0),
+ mpExtEncodingInfo(NULL)
+{
+ mnFoundry = 0;
+ mnFamily = 0;
+ mnWeight = 0;
+ mnSlant = 0;
+ mnSetwidth = 0;
+}
+
+VirtualXlfd::~VirtualXlfd()
+{
+ if ( mpExtEncodingInfo != NULL )
+ rtl_freeMemory( mpExtEncodingInfo );
+}
+
+int
+VirtualXlfd::GetFontQuality (unsigned short nFamily)
+{
+ Attribute *pFamily = mpFactory->RetrieveFamily(nFamily);
+ int nQuality = 0;
+
+ if (pFamily->HasFeature(XLFD_FEATURE_HQ))
+ nQuality += 16;
+ if (pFamily->HasFeature(XLFD_FEATURE_MQ))
+ nQuality += 8;
+ if (pFamily->HasFeature(XLFD_FEATURE_LQ))
+ nQuality += 4;
+ return nQuality;
+}
+
+bool
+VirtualXlfd::AddEncoding( const Xlfd *pXlfd )
+{
+ // add new font
+ bool bRC = ExtendedXlfd::AddEncoding( pXlfd );
+
+ int nIdx;
+ if( bRC )
+ {
+ // new encoding => append the new pXlfd
+ nIdx = mnEncodings - 1;
+ if( nIdx >= mnExtCapacity )
+ {
+ mnExtCapacity = mnEncCapacity;
+ mpExtEncodingInfo = (ExtEncodingInfo*)Realloc( mpExtEncodingInfo,
+ mnExtCapacity * sizeof(ExtEncodingInfo) );
+ }
+ }
+ else
+ {
+ // existing encoding => check if the new pXlfd is better
+ rtl_TextEncoding nEncoding = pXlfd->GetEncoding();
+ nIdx = GetEncodingIdx( nEncoding );
+
+ int nOldQuality = GetFontQuality( mpExtEncodingInfo[nIdx].mnFamily );
+ int nNewQuality = GetFontQuality( pXlfd->mnFamily );
+ if( nOldQuality >= nNewQuality )
+ return false;
+ }
+
+ mpExtEncodingInfo[ nIdx ] = pXlfd;
+ return true;
+}
+
+void
+VirtualXlfd::FilterInterfaceFont (const Xlfd *pXlfd)
+{
+ Attribute *pAttr;
+ AttributeProvider *pFactory = pXlfd->mpFactory;
+
+ if (! pXlfd->Fonttype() == TYPE_SCALABLE)
+ return;
+ pAttr = pFactory->RetrieveFamily(pXlfd->mnFamily);
+ if (! pAttr->HasFeature(XLFD_FEATURE_INTERFACE_FONT))
+ return;
+ pAttr = pFactory->RetrieveSlant(pXlfd->mnSlant);
+ if (! (FontItalic)pAttr->GetValue() == ITALIC_NONE)
+ return;
+ pAttr = pFactory->RetrieveSetwidth(pXlfd->mnSetwidth);
+ if (pAttr->HasFeature(XLFD_FEATURE_NARROW))
+ return;
+ pAttr = pFactory->RetrieveWeight(pXlfd->mnWeight);
+ FontWeight eWeight = (FontWeight)pAttr->GetValue();
+ if ((eWeight != WEIGHT_NORMAL) && (eWeight != WEIGHT_MEDIUM))
+ return;
+
+ AddEncoding (pXlfd);
+}
+
+void
+VirtualXlfd::ToString( ByteString &rString, unsigned short nPixelSize,
+ rtl_TextEncoding nEncoding ) const
+{
+ int nIdx = GetEncodingIdx( nEncoding );
+ if ( nIdx < 0 )
+ return;
+
+ ExtEncodingInfo &rExtInfo = mpExtEncodingInfo[ nIdx ];
+
+ AppendAttribute( mpFactory->RetrieveFoundry(rExtInfo.mnFoundry), rString );
+ AppendAttribute( mpFactory->RetrieveFamily(rExtInfo.mnFamily), rString );
+ AppendAttribute( mpFactory->RetrieveWeight(rExtInfo.mnWeight), rString );
+ AppendAttribute( mpFactory->RetrieveSlant(rExtInfo.mnSlant), rString );
+ AppendAttribute( mpFactory->RetrieveSetwidth(rExtInfo.mnSetwidth), rString );
+
+ EncodingInfo& rInfo = mpEncodingInfo[ nIdx ];
+ AppendAttribute( mpFactory->RetrieveAddstyle(rInfo.mnAddstyle), rString );
+
+ rString += '-';
+ rString += ByteString::CreateFromInt32( nPixelSize );
+ rString += "-0-0-0-";
+ rString += static_cast< char >(rInfo.mcSpacing);
+ rString += "-0";
+
+ AppendAttribute( mpFactory->RetrieveCharset(rInfo.mnCharset), rString );
+}
+
+void
+VirtualXlfd::ToString( ByteString &rString, unsigned short nPixelSize,
+ char* pMatricsString, rtl_TextEncoding nEncoding ) const
+{
+ int nIdx = GetEncodingIdx( nEncoding );
+ if ( nIdx < 0 )
+ return;
+
+ ExtEncodingInfo &rExtInfo = mpExtEncodingInfo[ nIdx ];
+
+ AppendAttribute( mpFactory->RetrieveFoundry(rExtInfo.mnFoundry), rString );
+ AppendAttribute( mpFactory->RetrieveFamily(rExtInfo.mnFamily), rString );
+ AppendAttribute( mpFactory->RetrieveWeight(rExtInfo.mnWeight), rString );
+ AppendAttribute( mpFactory->RetrieveSlant(rExtInfo.mnSlant), rString );
+ AppendAttribute( mpFactory->RetrieveSetwidth(rExtInfo.mnSetwidth), rString );
+
+ EncodingInfo& rInfo = mpEncodingInfo[ nIdx ];
+ AppendAttribute( mpFactory->RetrieveAddstyle(rInfo.mnAddstyle), rString );
+
+ rString += "-*-";
+ char pTmp[256];
+ snprintf( pTmp, sizeof(pTmp), pMatricsString, nPixelSize, nPixelSize );
+ rString += pTmp;
+ rString += "-*-*-";
+ rString += static_cast< char >(rInfo.mcSpacing);
+ rString += "-*";
+
+ AppendAttribute( mpFactory->RetrieveCharset(rInfo.mnCharset), rString );
+}
+
+ImplFontData* VirtualXlfd::GetImplFontData() const
+{
+ ImplX11FontData* pFontData = new ImplX11FontData( *this, 0 );
+
+ // family name
+ static const String aFontName( RTL_CONSTASCII_USTRINGPARAM("Interface User") );
+ pFontData->maName = aFontName;
+ // pFontData->maStyleName = aStyleName;
+ pFontData->meFamily = FAMILY_SWISS;
+ pFontData->meWeight = WEIGHT_NORMAL;
+ pFontData->meItalic = ITALIC_NONE;
+ pFontData->meWidthType = WIDTH_NORMAL;
+ pFontData->mePitch = PITCH_VARIABLE;
+
+ pFontData->mbSymbolFlag = false;
+ pFontData->mbOrientation= false;
+ pFontData->mbDevice = true;
+ pFontData->mnQuality = 100;
+
+ return pFontData;
+}
+
+// ------ font list -------------------------------------------------------
+
+XlfdStorage::XlfdStorage()
+{
+ maXlfdList.reserve( 256 );
+}
+
+void
+XlfdStorage::Dispose()
+{
+ XlfdList::const_iterator it = maXlfdList.begin();
+ for(; it != maXlfdList.end(); ++it )
+ delete *it;
+ maXlfdList.clear();
+}
+
+void
+XlfdStorage::Reset()
+{
+ maXlfdList.clear();
+}
+
+void
+XlfdStorage::Add( const ExtendedXlfd* pXlfd )
+{
+ if ( pXlfd != NULL )
+ maXlfdList.push_back( pXlfd );
+}
+
+void
+XlfdStorage::Add( const XlfdStorage* pXlfd )
+{
+ if ( !pXlfd || pXlfd->maXlfdList.empty() )
+ return;
+
+ maXlfdList.reserve( maXlfdList.size() + pXlfd->maXlfdList.size() );
+ XlfdList::const_iterator it = pXlfd->maXlfdList.begin();
+ for(; it != pXlfd->maXlfdList.end(); ++it )
+ maXlfdList.push_back( *it );
+}
+
+void XlfdStorage::AnnounceFonts( ImplDevFontList* pList ) const
+{
+ XlfdList::const_iterator it = maXlfdList.begin();
+ for(; it != maXlfdList.end(); ++it )
+ {
+ const ExtendedXlfd* pXlfd = *it;
+ ImplFontData* pFontData = pXlfd->GetImplFontData();
+ pList->Add( pFontData );
+ }
+}
+
+// ------ bitmap font list --------------------------------------------------
+
+void
+BitmapXlfdStorage::AddBitmapFont( const Xlfd *pXlfd )
+{
+ if ( pXlfd == NULL )
+ return;
+
+ int nPixelSize = pXlfd->mnPixelSize;
+ XlfdList::const_iterator it = maXlfdList.begin();
+ for(; it != maXlfdList.end(); ++it )
+ {
+ BitmapXlfd* pBitmapXlfd = (BitmapXlfd*)*it;
+ if( nPixelSize == pBitmapXlfd->GetPixelSize() )
+ {
+ // we need to add an encoding to an existing bitmap font
+ pBitmapXlfd->AddEncoding( pXlfd );
+ return;
+ }
+ }
+
+ // we have a new bitmap font
+ BitmapXlfd* pBitmapXlfd = new BitmapXlfd;
+ pBitmapXlfd->AddEncoding( pXlfd );
+ Add( pBitmapXlfd );
+}
diff --git a/vcl/unx/source/gdi/xlfd_extd.hxx b/vcl/unx/source/gdi/xlfd_extd.hxx
new file mode 100644
index 000000000000..523f87fac477
--- /dev/null
+++ b/vcl/unx/source/gdi/xlfd_extd.hxx
@@ -0,0 +1,272 @@
+/*************************************************************************
+ *
+ * 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 XLFD_EXTENDED_HXX
+#define XLFD_EXTENDED_HXX
+
+#include <salunx.h>
+#ifndef _VCL_VCLENUM_HXX
+#include <vcl/enum.hxx>
+#endif
+#ifndef _VCL_OUTFONT_HXX
+#include <vcl/outfont.hxx>
+#endif
+
+#include <vector>
+
+class Xlfd;
+class AttributeProvider;
+class ImplDevFontList;
+class ByteString;
+
+// --------------------------------------------------------------------------
+//
+// classes for Xlfd handling that contain more than a single encoding.
+// Members that may vary through different encodings are stored in
+// a mpEncodingInfo member. There are three different classes:
+// true scalable fonts (truetype and type1) scalable bitmap fonts
+// (the ugly ones) and bitmap fonts. The ExtendedXlfd stores all the members
+// that are specific to a font outline
+// ( e.g. adobe-times-roman-medium-r-normal- * -p- * )
+// and specifies the interface.
+//
+// --------------------------------------------------------------------------
+
+// base class
+
+class ExtendedXlfd : public ImplDevFontAttributes
+{
+ public:
+ ExtendedXlfd( bool bScalable );
+ virtual ~ExtendedXlfd();
+ virtual bool AddEncoding( const Xlfd* );
+ bool HasEncoding( rtl_TextEncoding ) const;
+ int GetEncodingIdx( rtl_TextEncoding nEncoding ) const;
+ unsigned short NumEncodings() const
+ { return mnEncodings; }
+ virtual int GetPixelSize() const
+ { return 0; }
+ virtual void ToString( ByteString &rString,
+ unsigned short nPixelSize,
+ rtl_TextEncoding nEncoding ) const ;
+ virtual void ToString( ByteString &rString,
+ unsigned short nPixelSize,
+ char* pMatricsString,
+ rtl_TextEncoding nEncoding ) const;
+
+ virtual ImplFontData* GetImplFontData() const = 0;
+ bool IsScalable() const { return mbScalable; }
+ virtual FontFamily GetFamilyType() const;
+ virtual FontWeight GetWeight() const;
+ virtual FontItalic GetSlant() const;
+ virtual FontWidth GetWidthType() const;
+ virtual FontPitch GetPitch() const;
+ virtual FontPitch GetPitch( rtl_TextEncoding ) const;
+ rtl_TextEncoding GetAsciiEncoding( int *pAsciiRange = NULL ) const;
+ rtl_TextEncoding GetEncoding() const;
+ rtl_TextEncoding GetEncoding( int i ) const;
+
+ int GetFontCodeRanges( sal_uInt32* pCodePairs ) const;
+
+ protected:
+ AttributeProvider* mpFactory;
+
+ public:
+ unsigned short mnFoundry;
+ unsigned short mnFamily;
+ unsigned short mnWeight;
+ unsigned short mnSlant;
+ unsigned short mnSetwidth;
+ bool mbScalable;
+
+ protected:
+ unsigned short mnEncodings;
+ unsigned short mnEncCapacity;
+ struct EncodingInfo {
+ unsigned char mcSpacing;
+ unsigned short mnResolutionX;
+ unsigned short mnResolutionY;
+ unsigned short mnAddstyle;
+ unsigned short mnCharset;
+ rtl_TextEncoding mnEncoding;
+
+ EncodingInfo& operator= ( const Xlfd *pXlfd );
+ } *mpEncodingInfo;
+};
+
+// class to handle scalable bitmap fonts
+
+class ScalableBitmapXlfd : public ExtendedXlfd {
+
+ public:
+ ScalableBitmapXlfd();
+ virtual ~ScalableBitmapXlfd();
+ virtual void ToString( ByteString &rString,
+ unsigned short nPixelSize,
+ rtl_TextEncoding nEncoding ) const;
+ virtual void ToString( ByteString &rString,
+ unsigned short nPixelSize,
+ char* pMatricsString,
+ rtl_TextEncoding nEncoding ) const;
+
+ virtual ImplFontData* GetImplFontData() const ;
+};
+
+// class to handle true bitmap fonts
+
+class ScalableXlfd;
+
+class BitmapXlfd : public ExtendedXlfd {
+
+ public:
+ BitmapXlfd();
+ ~BitmapXlfd();
+ bool AddEncoding( const Xlfd* );
+ virtual int GetPixelSize() const
+ { return mnPixelSize; }
+ virtual void ToString( ByteString &rString,
+ unsigned short nPixelSize,
+ rtl_TextEncoding nEncoding ) const;
+ virtual void ToString( ByteString &rString,
+ unsigned short nPixelSize,
+ char* pMatricsString,
+ rtl_TextEncoding nEncoding ) const;
+ virtual ImplFontData* GetImplFontData() const ;
+ protected:
+
+ unsigned short mnPixelSize;
+ unsigned short mnPointSize;
+ unsigned short mnAverageWidth;
+};
+
+// class to handle true scalable fonts
+
+class ScalableXlfd : public ExtendedXlfd {
+
+ friend class BitmapXlfd;
+
+ public:
+ ScalableXlfd();
+ virtual ~ScalableXlfd();
+ virtual void ToString( ByteString &rString,
+ unsigned short nPixelSize,
+ rtl_TextEncoding nEncoding ) const;
+
+ virtual void ToString( ByteString &rString,
+ unsigned short nPixelSize,
+ char* pMatricsString,
+ rtl_TextEncoding nEncoding ) const;
+ virtual ImplFontData* GetImplFontData() const ;
+};
+
+// class to maintain a list of fonts ( bitmap and scalable )
+
+class XlfdStorage {
+
+ public:
+ XlfdStorage();
+
+ void Dispose();
+ void Reset();
+
+ void Add( const ExtendedXlfd *pXlfd );
+ void Add( const XlfdStorage *pXlfd );
+ void AnnounceFonts( ImplDevFontList* ) const;
+
+ protected:
+
+ typedef ::std::vector<const ExtendedXlfd*> XlfdList;
+ XlfdList maXlfdList;
+};
+
+// list of fonts specific for bitmap fonts
+
+class BitmapXlfdStorage : public XlfdStorage {
+
+ public:
+
+ void AddBitmapFont( const Xlfd *pXlfd );
+};
+
+
+/* Virtual font for User Interface */
+
+class VirtualXlfd : public ExtendedXlfd
+{
+ private:
+
+ int GetFontQuality (unsigned short nFamily);
+
+ public:
+ VirtualXlfd();
+ virtual ~VirtualXlfd();
+ virtual bool AddEncoding( const Xlfd* );
+ void FilterInterfaceFont (const Xlfd *pXlfd);
+ virtual void ToString( ByteString &rString,
+ unsigned short nPixelSize,
+ rtl_TextEncoding nEncoding ) const ;
+ virtual void ToString( ByteString &rString,
+ unsigned short nPixelSize,
+ char* pMatricsString,
+ rtl_TextEncoding nEncoding ) const;
+
+ virtual ImplFontData* GetImplFontData() const ;
+ protected:
+
+ unsigned short mnExtCapacity;
+ struct ExtEncodingInfo {
+ unsigned short mnFoundry;
+ unsigned short mnFamily;
+ unsigned short mnWeight;
+ unsigned short mnSlant;
+ unsigned short mnSetwidth;
+
+ ExtEncodingInfo& operator= ( const Xlfd *pXlfd );
+ } *mpExtEncodingInfo;
+
+ friend class ExtEncodingInfo;
+};
+
+
+// class to describe a X11 physically available font face
+
+class ImplX11FontData : public ImplFontData
+{
+private:
+ enum { X11IFD_MAGIC = 0x111FDA1C };
+ const ExtendedXlfd& mrXlfd;
+
+public:
+ ImplX11FontData( const ExtendedXlfd&, int nHeight );
+ const ExtendedXlfd& GetExtendedXlfd() const { return mrXlfd; }
+ virtual ImplFontData* Clone() const { return new ImplX11FontData( *this ); }
+ virtual ImplFontEntry* CreateFontInstance( ImplFontSelectData& ) const;
+ virtual sal_IntPtr GetFontId() const;
+
+ static bool CheckFontData( const ImplFontData& r ) { return r.CheckMagic( X11IFD_MAGIC ); }
+};
+
+#endif /* XLFD_EXTENDED_HXX */
diff --git a/vcl/unx/source/gdi/xlfd_smpl.cxx b/vcl/unx/source/gdi/xlfd_smpl.cxx
new file mode 100644
index 000000000000..6cf18d98de1e
--- /dev/null
+++ b/vcl/unx/source/gdi/xlfd_smpl.cxx
@@ -0,0 +1,268 @@
+/*************************************************************************
+ *
+ * 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 <string.h>
+#include "xlfd_attr.hxx"
+#include "xlfd_smpl.hxx"
+
+// --------------------------------------------------------------------------
+//
+//
+// broken down structure equivalent to a Xlfd string
+//
+//
+// --------------------------------------------------------------------------
+
+Xlfd::Xlfd()
+{
+}
+
+// XlfdCompare abi has to be qsort(3) compatible, the sorting result must
+// guarantee that fonts with SameFontoutline() are successive
+// XlfdCompare relies on vFrom->mpFactory eq vTo->mpFactory. Since comparing
+// Xlfd's is done by comparing attributes there is no way around this.
+extern "C" int
+XlfdCompare( const void *vFrom, const void *vTo )
+{
+ const Xlfd *pFrom = (Xlfd*)vFrom;
+ const Xlfd *pTo = (Xlfd*)vTo;
+
+ // Compare outline description
+ if ( pFrom->mnFoundry != pTo->mnFoundry )
+ return (int)pFrom->mnFoundry - (int)pTo->mnFoundry;
+ if ( pFrom->mnFamily != pTo->mnFamily )
+ return (int)pFrom->mnFamily - (int)pTo->mnFamily;
+ if ( pFrom->mnWeight != pTo->mnWeight )
+ return (int)pFrom->mnWeight - (int)pTo->mnWeight;
+ if ( pFrom->mnSlant != pTo->mnSlant )
+ return (int)pFrom->mnSlant - (int)pTo->mnSlant;
+ if ( pFrom->mnSetwidth != pTo->mnSetwidth )
+ return (int)pFrom->mnSetwidth - (int)pTo->mnSetwidth;
+
+ // Addstyle name is futile tricky. it may contain encoding information
+ // (like "ansi_1251") which Compares equal, or it may contain style
+ // information (like "serif") which Compares unequal, anyway if the font
+ // is "interface user" or "interface system" then compare equal anyway to
+ // build fontsets as large as possible
+ if ( pFrom->mnAddstyle == pTo->mnAddstyle )
+ return 0;
+
+ AttributeProvider *pFactory = pFrom->mpFactory;
+ Attribute *pFamily = pFactory->RetrieveFamily( pFrom->mnFamily );
+ if ( pFamily->HasFeature(XLFD_FEATURE_APPLICATION_FONT) )
+ return 0;
+
+ Attribute *pFromAddStyle = pFactory->RetrieveAddstyle( pFrom->mnAddstyle );
+ Attribute *pToAddStyle = pFactory->RetrieveAddstyle( pTo->mnAddstyle );
+
+ // if both addstyles denote encodings or if one denotes an
+ // encoding and the other denotes a style which really
+ // duplicates weight and slant information
+
+ int nFromCompare = (pFromAddStyle->GetValue() != RTL_TEXTENCODING_DONTKNOW)
+ || (pFromAddStyle->HasFeature(XLFD_FEATURE_REDUNDANTSTYLE)) ?
+ -1 : pFrom->mnAddstyle;
+ int nToCompare = (pToAddStyle->GetValue() != RTL_TEXTENCODING_DONTKNOW)
+ || (pToAddStyle->HasFeature(XLFD_FEATURE_REDUNDANTSTYLE)) ?
+ -1 : pTo->mnAddstyle;
+
+ return nFromCompare - nToCompare;
+}
+
+// check whether two fonts are identical as appearance is concerned
+// this does not Compare the actual scaling of two fonts
+Bool
+Xlfd::SameFontoutline( const Xlfd* pComparedTo ) const
+{
+ void* pThis = (void*)this;
+ return XlfdCompare( (void*)pThis, (void*)pComparedTo ) == 0 ;
+}
+
+unsigned short
+Xlfd::GetEncoding() const
+{
+ Attribute *pAddstyle = mpFactory->RetrieveAddstyle( mnAddstyle );
+ if ( pAddstyle->GetValue() != RTL_TEXTENCODING_DONTKNOW )
+ return pAddstyle->GetValue();
+
+ Attribute *pEncoding = mpFactory->RetrieveCharset( mnCharset );
+ return pEncoding->GetValue();
+}
+
+XlfdFonttype
+Xlfd::Fonttype() const
+{
+ if ( (mnAverageWidth == 0) && (mnPixelSize == 0) && (mnPointSize == 0) )
+ {
+ return (mnResolutionX == 0)
+ && (mnResolutionY == 0) ? eTypeScalable : eTypeScalableBitmap;
+ }
+
+ return eTypeBitmap;
+}
+
+void
+Advance( const char** pFrom, const char** pTo )
+{
+ const char *pTmp = *pTo;
+
+ for( ; (*pTmp != '\0') && (*pTmp++ != '-'); )
+ {}
+ *pFrom = *pTo;
+ *pTo = pTmp;
+}
+
+Bool
+Xlfd::IsConformant (const char* pXlfd) const
+{
+ // X FontNameRegistry prefix "-"
+ if (*pXlfd++ != '-')
+ return False;
+
+ // All Xlfd FontName fields are defined
+ int nNumFields = 1;
+ while (*pXlfd != '\0')
+ {
+ if (*pXlfd++ == '-')
+ nNumFields++;
+ }
+ // enough entries ?
+ if (nNumFields != 14)
+ return False;
+ // and the last one is not empty as well ?
+ if (*(pXlfd - 1) == '-')
+ return False;
+
+ return True;
+}
+
+// this is the real workhorse function. Since this is called for every font
+// in the fontpath it has to be as fast a possible
+Bool
+Xlfd::FromString( const char* pXlfdstring, AttributeProvider *pFactory )
+{
+ if (!IsConformant(pXlfdstring))
+ return False;
+
+ const char* pFrom = pXlfdstring + 1;
+ const char* pTo = pFrom;
+ mpFactory = pFactory;
+
+ Advance( &pFrom, &pTo ); //-foundry-*
+ mnFoundry = mpFactory->InsertFoundry( pFrom, pTo - pFrom - 1 );
+
+ Advance( &pFrom, &pTo ); // -*-family-*
+ mnFamily = mpFactory->InsertFamily( pFrom, pTo - pFrom - 1 );
+
+ Advance( &pFrom, &pTo ); // -*-*-weight-*
+ mnWeight = mpFactory->InsertWeight( pFrom, pTo - pFrom - 1 );
+
+ Advance( &pFrom, &pTo ); //-*-*-*-slant-*
+ mnSlant = mpFactory->InsertSlant( pFrom, pTo - pFrom - 1 );
+
+ Advance( &pFrom, &pTo ); //-*-*-*-*-setwidth-*
+ mnSetwidth = mpFactory->InsertSetwidth( pFrom, pTo - pFrom - 1 );
+
+ Advance( &pFrom, &pTo ); //-*-*-*-*-*-Addstyle-*
+ mnAddstyle = mpFactory->InsertAddstyle( pFrom, pTo - pFrom - 1 );
+
+ Advance( &pFrom, &pTo ); //-*-*-*-*-*-*-height-*
+ mnPixelSize = atoi( pFrom );
+
+ Advance( &pFrom, &pTo ); //-*-*-*-*-*-*-*-pt height-*
+ mnPointSize = atoi( pFrom );
+
+ Advance( &pFrom, &pTo ); //-*-*-*-*-*-*-*-*-x resolution-*
+ mnResolutionX = atoi( pFrom );
+
+ Advance( &pFrom, &pTo ); //-*-*-*-*-*-*-*-*-*-y resolution-*
+ mnResolutionY = atoi( pFrom );
+
+ Advance( &pFrom, &pTo ); //-*-*-*-*-*-*-*-*-*-*-spacing-*
+ mcSpacing = pFrom == pTo ? '\0' : *pFrom;
+
+ Advance( &pFrom, &pTo ); //-*-*-*-*-*-*-*-*-*-*-*-average-*
+ mnAverageWidth = atoi( pFrom );
+
+ Advance( &pFrom, &pTo ); //-*-*-*-*-*-*-*-*-*-*-*-*-registry-encoding
+ const char* pTmp = pFrom;
+ Advance( &pTmp, &pTo );
+ mnCharset = mpFactory->InsertCharset( pFrom, pTo - pFrom );
+
+ // sanity check whether we have really found a valid XLFD, if not
+ // throw away the whole font, since we have no idea what parts of
+ // the XLFD contains the error.
+ if ( !(pTo > pFrom) )
+ return False;
+
+ // a non-empty family name is essential, since otherwise the font
+ // would match the "default font" #52299#
+ Attribute* pFamily = mpFactory->RetrieveFamily( mnFamily );
+ const char* pFamilyName = pFamily->GetName();
+ if ( pFamilyName[0] == '\0' )
+ return False;
+
+ // well done
+ return True;
+}
+
+#if OSL_DEBUG_LEVEL > 1
+// pure debug for now: this is only to inspect/pretty print a Xlfd struct
+const char*
+Xlfd::ToString( ByteString &rString ) const
+{
+ AppendAttribute( mpFactory->RetrieveFoundry(mnFoundry), rString );
+ AppendAttribute( mpFactory->RetrieveFamily(mnFamily), rString );
+ AppendAttribute( mpFactory->RetrieveWeight(mnWeight), rString );
+ AppendAttribute( mpFactory->RetrieveSlant(mnSlant), rString );
+ AppendAttribute( mpFactory->RetrieveSetwidth(mnSetwidth), rString );
+ AppendAttribute( mpFactory->RetrieveAddstyle(mnAddstyle), rString );
+
+ rString.Append("-"); rString.Append( ByteString::CreateFromInt32( mnPixelSize ) );
+ rString.Append("-"); rString.Append( ByteString::CreateFromInt32( mnPointSize ) );
+ rString.Append("-"); rString.Append( ByteString::CreateFromInt32( mnResolutionX ) );
+ rString.Append("-"); rString.Append( ByteString::CreateFromInt32( mnResolutionY ) );
+ rString.Append("-"); rString.Append( (char)mcSpacing );
+ rString.Append("-"); rString.Append( ByteString::CreateFromInt32( mnAverageWidth ) );
+
+ AppendAttribute( mpFactory->RetrieveCharset(mnCharset), rString );
+
+ return rString.GetBuffer() ;
+}
+
+void
+Xlfd::Dump() const
+{
+ ByteString aString;
+ fprintf(stderr, "Xlfd: %s\n", ToString(aString) );
+}
+#endif
+
diff --git a/vcl/unx/source/gdi/xlfd_smpl.hxx b/vcl/unx/source/gdi/xlfd_smpl.hxx
new file mode 100644
index 000000000000..f62ac381e6b9
--- /dev/null
+++ b/vcl/unx/source/gdi/xlfd_smpl.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.
+ *
+ ************************************************************************/
+#ifndef XLFD_SIMPLE_HXX
+#define XLFD_SIMPLE_HXX
+
+#include <salunx.h>
+#include <vcl/vclenum.hxx>
+#include <tools/string.hxx>
+
+class AttributeProvider;
+
+// --------------------------------------------------------------------------
+//
+//
+// broken down structure equivalent to a Xlfd string
+//
+//
+// --------------------------------------------------------------------------
+
+enum XlfdFonttype {
+ eTypeUnknown = TYPE_DONTKNOW,
+ eTypeBitmap = TYPE_RASTER,
+ eTypeScalableBitmap = TYPE_VECTOR,
+ eTypeScalable = TYPE_SCALABLE
+};
+
+class Xlfd {
+
+ public:
+
+ unsigned short mnFoundry;
+ unsigned short mnFamily;
+ unsigned short mnWeight;
+ unsigned short mnSlant;
+ unsigned short mnSetwidth;
+ unsigned short mnAddstyle;
+ unsigned short mnPixelSize;
+ unsigned short mnPointSize;
+ unsigned short mnResolutionX;
+ unsigned short mnResolutionY;
+ unsigned char mcSpacing;
+ unsigned short mnAverageWidth;
+ unsigned short mnCharset;
+
+ // all foundry, family, weight ... information referres
+ // to this factory
+ AttributeProvider *mpFactory;
+
+ Bool IsConformant( const char* pXlfdstring ) const;
+
+ public:
+ Xlfd();
+ Bool FromString( const char* pXlfdstring,
+ AttributeProvider *pFactory );
+ Bool SameFontoutline( const Xlfd *pComparedTo ) const ;
+ XlfdFonttype Fonttype() const ;
+ unsigned short GetEncoding() const ;
+ #if OSL_DEBUG_LEVEL > 1
+ const char* ToString( ByteString &rString ) const ;
+ void Dump() const;
+ #endif
+};
+
+extern "C" int
+XlfdCompare( const void *vFrom, const void *vTo );
+
+#endif /* XLFD_SIMPLE_HXX */
+
diff --git a/vcl/unx/source/gdi/xrender_peer.cxx b/vcl/unx/source/gdi/xrender_peer.cxx
new file mode 100644
index 000000000000..8d24e4098df4
--- /dev/null
+++ b/vcl/unx/source/gdi/xrender_peer.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 <stdio.h>
+#include <rtl/ustring.hxx>
+#include <osl/module.h>
+//#include <osl/thread.h>
+using namespace rtl;
+
+#include <xrender_peer.hxx>
+
+#include <salunx.h>
+#include <saldata.hxx>
+#include <saldisp.hxx>
+
+// ---------------------------------------------------------------------------
+
+XRenderPeer::XRenderPeer()
+: mpDisplay( GetX11SalData()->GetDisplay()->GetDisplay() ),
+ mpStandardFormatA8( NULL ),
+ mnRenderVersion( 0 ),
+ mpRenderLib( NULL )
+#ifndef XRENDER_LINK
+, mpXRenderCompositeTrapezoids( NULL )
+, mpXRenderAddTraps( NULL )
+#endif // XRENDER_LINK
+{
+ InitRenderLib();
+}
+
+// ---------------------------------------------------------------------------
+
+XRenderPeer::~XRenderPeer()
+{
+ osl_unloadModule( mpRenderLib );
+}
+
+// ---------------------------------------------------------------------------
+
+XRenderPeer& XRenderPeer::GetInstance()
+{
+ static XRenderPeer aPeer;
+ return aPeer;
+}
+
+// ---------------------------------------------------------------------------
+
+void XRenderPeer::InitRenderLib()
+{
+ int nDummy;
+ if( !XQueryExtension( mpDisplay, "RENDER", &nDummy, &nDummy, &nDummy ) )
+ return;
+
+#ifndef XRENDER_LINK
+ // we don't know if we are running on a system with xrender library
+ // we don't want to install system libraries ourselves
+ // => load them dynamically when they are there
+ const OUString aLibName( RTL_CONSTASCII_USTRINGPARAM( "libXrender.so.1" ));
+ mpRenderLib = osl_loadModule( aLibName.pData, SAL_LOADMODULE_DEFAULT );
+ if( !mpRenderLib ) {
+#ifdef DEBUG
+ fprintf( stderr, "Display can do XRender, but no %s installed.\n"
+ "Please install for improved display performance\n", OUStringToOString( aLibName.getStr(),
+ osl_getThreadTextEncoding() ).getStr() );
+#endif
+ return;
+ }
+
+ oslGenericFunction pFunc;
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderQueryExtension" );
+ if( !pFunc ) return;
+ mpXRenderQueryExtension = (Bool(*)(Display*,int*,int*))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderQueryVersion" );
+ if( !pFunc ) return;
+ mpXRenderQueryVersion = (void(*)(Display*,int*,int*))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderFindVisualFormat" );
+ if( !pFunc ) return;
+ mpXRenderFindVisualFormat = (XRenderPictFormat*(*)(Display*,Visual*))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderFindStandardFormat" );
+ if( !pFunc ) return;
+ mpXRenderFindStandardFormat = (XRenderPictFormat*(*)(Display*,int))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderFindFormat" );
+ if( !pFunc ) return;
+ mpXRenderFindFormat = (XRenderPictFormat*(*)(Display*,unsigned long,
+ const XRenderPictFormat*,int))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderCreateGlyphSet" );
+ if( !pFunc ) return;
+ mpXRenderCreateGlyphSet = (GlyphSet(*)(Display*,const XRenderPictFormat*))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderFreeGlyphSet" );
+ if( !pFunc ) return;
+ mpXRenderFreeGlyphSet = (void(*)(Display*,GlyphSet))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderAddGlyphs" );
+ if( !pFunc ) return;
+ mpXRenderAddGlyphs = (void(*)(Display*,GlyphSet,Glyph*,const XGlyphInfo*,
+ int,const char*,int))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderFreeGlyphs" );
+ if( !pFunc ) return;
+ mpXRenderFreeGlyphs = (void(*)(Display*,GlyphSet,Glyph*,int))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderCompositeString32" );
+ if( !pFunc ) return;
+ mpXRenderCompositeString32 = (void(*)(Display*,int,Picture,Picture,
+ const XRenderPictFormat*,GlyphSet,int,int,int,int,const unsigned*,int))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderCreatePicture" );
+ if( !pFunc ) return;
+ mpXRenderCreatePicture = (Picture(*)(Display*,Drawable,const XRenderPictFormat*,
+ unsigned long,const XRenderPictureAttributes*))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderChangePicture" );
+ if( !pFunc ) return;
+ mpXRenderChangePicture = (void(*)(Display*,Picture,unsigned long,const XRenderPictureAttributes*))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderSetPictureClipRegion" );
+ if( !pFunc ) return;
+ mpXRenderSetPictureClipRegion = (void(*)(Display*,Picture,XLIB_Region))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderFreePicture" );
+ if( !pFunc ) return;
+ mpXRenderFreePicture = (void(*)(Display*,Picture))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderComposite" );
+ if( !pFunc ) return;
+ mpXRenderComposite = (void(*)(Display*,int,Picture,Picture,Picture,
+ int,int,int,int,int,int,unsigned,unsigned))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderFillRectangle" );
+ if( !pFunc ) return;
+ mpXRenderFillRectangle = (void(*)(Display*,int,Picture,const XRenderColor*,
+ int,int,unsigned int,unsigned int))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderCompositeTrapezoids" );
+#if 0 // not having trapezoid support is supported
+ if( !pFunc ) return;
+#endif
+ mpXRenderCompositeTrapezoids = (void(*)(Display*,int,Picture,Picture,
+ const XRenderPictFormat*,int,int,const XTrapezoid*,int))pFunc;
+
+ pFunc = osl_getAsciiFunctionSymbol( mpRenderLib, "XRenderAddTraps" );
+#if 0 // not having trapezoid support is supported
+ if( !pFunc ) return;
+#endif
+ mpXRenderAddTraps = (void(*)(Display*,Picture,int,int,const _XTrap*,int))pFunc;
+
+#endif // XRENDER_LINK
+
+ // needed to initialize libXrender internals, we already know its there
+#ifdef XRENDER_LINK
+ XRenderQueryExtension( mpDisplay, &nDummy, &nDummy );
+#else
+ (*mpXRenderQueryExtension)( mpDisplay, &nDummy, &nDummy );
+#endif
+
+ int nMajor, nMinor;
+#ifdef XRENDER_LINK
+ XRenderQueryVersion( mpDisplay, &nMajor, &nMinor );
+#else
+ (*mpXRenderQueryVersion)( mpDisplay, &nMajor, &nMinor );
+#endif
+ mnRenderVersion = 16*nMajor + nMinor;
+
+ // the 8bit alpha mask format must be there
+ XRenderPictFormat aPictFormat={0,0,8,{0,0,0,0,0,0,0,0xFF},0};
+ mpStandardFormatA8 = FindPictureFormat( PictFormatAlphaMask|PictFormatDepth, aPictFormat );
+}
+
+// ---------------------------------------------------------------------------
+
+// return mask of screens capable of XRENDER text
+sal_uInt32 XRenderPeer::InitRenderText()
+{
+ if( mnRenderVersion < 0x01 )
+ return 0;
+
+ // #93033# disable XRENDER for old RENDER versions if XINERAMA is present
+ int nDummy;
+ if( XQueryExtension( mpDisplay, "XINERAMA", &nDummy, &nDummy, &nDummy ) )
+ if( mnRenderVersion < 0x02 )
+ return 0;
+
+ if( !mpStandardFormatA8 )
+ return 0;
+
+ // and the visual must be supported too on at least one screen
+ sal_uInt32 nRetMask = 0;
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ const int nScreenCount = pSalDisp->GetScreenCount();
+ XRenderPictFormat* pVisualFormat = NULL;
+ int nMaxDepth = 0;
+ for( int nScreen = 0; nScreen < nScreenCount; ++nScreen )
+ {
+ Visual* pXVisual = pSalDisp->GetVisual( nScreen ).GetVisual();
+ pVisualFormat = FindVisualFormat( pXVisual );
+ if( pVisualFormat != NULL )
+ {
+ int nVDepth = pSalDisp->GetVisual( nScreen ).GetDepth();
+ if( nVDepth > nMaxDepth )
+ nMaxDepth = nVDepth;
+ nRetMask |= 1U << nScreen;
+ }
+ }
+
+ // #97763# disable XRENDER on <15bit displays for XFree<=4.2.0
+ if( mnRenderVersion <= 0x02 )
+ if( nMaxDepth < 15 )
+ nRetMask = 0;
+
+ return nRetMask;
+}
+
+// ---------------------------------------------------------------------------
diff --git a/vcl/unx/source/gdi/xrender_peer.hxx b/vcl/unx/source/gdi/xrender_peer.hxx
new file mode 100644
index 000000000000..89dccfcef40b
--- /dev/null
+++ b/vcl/unx/source/gdi/xrender_peer.hxx
@@ -0,0 +1,387 @@
+/*************************************************************************
+ *
+ * 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_XRENDER_PEER_HXX
+#define _SV_XRENDER_PEER_HXX
+
+#include <tools/prex.h>
+struct _XTrap; // on some older systems this is not declared within Xrender.h
+#include <X11/extensions/Xrender.h>
+#include <tools/postx.h>
+
+#include <vcl/salgtype.hxx>
+#include <osl/module.h>
+
+class XRenderPeer
+{
+public:
+ static XRenderPeer& GetInstance();
+ int GetVersion() const;
+
+ sal_uInt32 InitRenderText();
+
+protected:
+ XRenderPeer();
+ ~XRenderPeer();
+ void InitRenderLib();
+
+ Display* mpDisplay;
+ XRenderPictFormat* mpStandardFormatA8;
+ int mnRenderVersion;
+ oslModule mpRenderLib;
+
+public:
+ XRenderPictFormat* GetStandardFormatA8() const;
+ XRenderPictFormat* FindStandardFormat(int nFormat) const;
+
+ // the methods below are thin wrappers for the XRENDER API
+ XRenderPictFormat* FindVisualFormat( Visual* ) const;
+ XRenderPictFormat* FindPictureFormat( unsigned long nMask,
+ const XRenderPictFormat& ) const;
+ Picture CreatePicture( Drawable, const XRenderPictFormat*,
+ unsigned long nDrawable, const XRenderPictureAttributes* ) const;
+ void ChangePicture( Picture, unsigned long nValueMask,
+ const XRenderPictureAttributes* ) const;
+ void SetPictureClipRegion( Picture, XLIB_Region ) const;
+ void CompositePicture( int nOp, Picture aSrc, Picture aMask, Picture aDst,
+ int nXSrc, int nYSrc, int nXMask, int nYMask,
+ int nXDst, int nYDst, unsigned nWidth, unsigned nHeight ) const;
+ void FreePicture( Picture ) const;
+
+ GlyphSet CreateGlyphSet() const;
+ void FreeGlyphSet( GlyphSet ) const;
+ void AddGlyph( GlyphSet, Glyph nGlyphId, const XGlyphInfo&,
+ const char* pBuffer, int nBufSize ) const;
+ void FreeGlyph( GlyphSet, Glyph nGlyphId ) const;
+ void CompositeString32( Picture aSrc, Picture aDst, GlyphSet,
+ int nDstX, int nDstY, const unsigned* pText, int nTextLen ) const;
+ void FillRectangle( int nOp, Picture aDst, const XRenderColor*,
+ int nX, int nY, unsigned nW, unsigned nH ) const;
+ void CompositeTrapezoids( int nOp, Picture aSrc, Picture aDst,
+ const XRenderPictFormat*, int nXSrc, int nYSrc,
+ const XTrapezoid*, int nCount ) const;
+ bool AddTraps( Picture aDst, int nXOfs, int nYOfs,
+ const _XTrap*, int nCount ) const;
+
+ bool AreTrapezoidsSupported() const
+#ifdef XRENDER_LINK
+ { return true; }
+#else
+ { return mpXRenderCompositeTrapezoids!=NULL; }
+
+private:
+ XRenderPictFormat* (*mpXRenderFindFormat)(Display*,unsigned long,
+ const XRenderPictFormat*,int);
+ XRenderPictFormat* (*mpXRenderFindVisualFormat)(Display*,Visual*);
+ XRenderPictFormat* (*mpXRenderFindStandardFormat)(Display*,int);
+ Bool (*mpXRenderQueryExtension)(Display*,int*,int*);
+ void (*mpXRenderQueryVersion)(Display*,int*,int*);
+
+ Picture (*mpXRenderCreatePicture)(Display*,Drawable, const XRenderPictFormat*,
+ unsigned long,const XRenderPictureAttributes*);
+ void (*mpXRenderChangePicture)(Display*,Picture,
+ unsigned long,const XRenderPictureAttributes*);
+ void (*mpXRenderSetPictureClipRegion)(Display*,Picture,XLIB_Region);
+ void (*mpXRenderFreePicture)(Display*,Picture);
+ void (*mpXRenderComposite)(Display*,int,Picture,Picture,Picture,
+ int,int,int,int,int,int,unsigned,unsigned);
+
+ GlyphSet (*mpXRenderCreateGlyphSet)(Display*, const XRenderPictFormat*);
+ void (*mpXRenderFreeGlyphSet)(Display*,GlyphSet);
+ void (*mpXRenderAddGlyphs)(Display*,GlyphSet,Glyph*,
+ const XGlyphInfo*,int,const char*,int);
+ void (*mpXRenderFreeGlyphs)(Display*,GlyphSet,Glyph*,int);
+ void (*mpXRenderCompositeString32)(Display*,int,Picture,Picture,
+ const XRenderPictFormat*,GlyphSet,int,int,int,int,const unsigned*,int);
+ void (*mpXRenderFillRectangle)(Display*,int,Picture,
+ const XRenderColor*,int,int,unsigned int,unsigned int);
+ void (*mpXRenderCompositeTrapezoids)(Display*,int,Picture,Picture,
+ const XRenderPictFormat*,int,int,const XTrapezoid*,int);
+ void (*mpXRenderAddTraps)(Display*,Picture,int,int,const _XTrap*,int);
+#endif // XRENDER_LINK
+};
+
+//=====================================================================
+
+class ScopedPic
+{
+public:
+ ScopedPic( XRenderPeer& rPeer, Picture& rPic );
+ ~ScopedPic();
+ Picture& Get();
+
+private:
+ XRenderPeer& mrRenderPeer;
+ Picture maPicture;
+
+private: // prevent copy and assignmet
+ ScopedPic( const ScopedPic& );
+ void operator=( const ScopedPic& );
+};
+
+//=====================================================================
+
+inline int XRenderPeer::GetVersion() const
+{
+ return mnRenderVersion;
+}
+
+inline XRenderPictFormat* XRenderPeer::GetStandardFormatA8() const
+{
+ return mpStandardFormatA8;
+}
+
+inline XRenderPictFormat* XRenderPeer::FindStandardFormat(int nFormat) const
+{
+#ifdef XRENDER_LINK
+ return XRenderFindStandardFormat(mpDisplay, nFormat);
+#else
+ return (*mpXRenderFindStandardFormat)(mpDisplay, nFormat);
+#endif
+}
+
+inline XRenderPictFormat* XRenderPeer::FindVisualFormat( Visual* pVisual ) const
+{
+#ifdef XRENDER_LINK
+ return XRenderFindVisualFormat ( mpDisplay, pVisual );
+#else
+ return (*mpXRenderFindVisualFormat)( mpDisplay, pVisual );
+#endif
+}
+
+inline XRenderPictFormat* XRenderPeer::FindPictureFormat( unsigned long nFormatMask,
+ const XRenderPictFormat& rFormatAttr ) const
+{
+#ifdef XRENDER_LINK
+ return XRenderFindFormat( mpDisplay, nFormatMask, &rFormatAttr, 0 );
+#else
+ return (*mpXRenderFindFormat)( mpDisplay, nFormatMask, &rFormatAttr, 0 );
+#endif
+}
+
+inline Picture XRenderPeer::CreatePicture( Drawable aDrawable,
+ const XRenderPictFormat* pVisFormat, unsigned long nValueMask,
+ const XRenderPictureAttributes* pRenderAttr ) const
+{
+#ifdef XRENDER_LINK
+ return XRenderCreatePicture( mpDisplay, aDrawable, pVisFormat,
+ nValueMask, pRenderAttr );
+#else
+ return (*mpXRenderCreatePicture)( mpDisplay, aDrawable, pVisFormat,
+ nValueMask, pRenderAttr );
+#endif
+}
+
+inline void XRenderPeer::ChangePicture( Picture aPicture,
+ unsigned long nValueMask, const XRenderPictureAttributes* pRenderAttr ) const
+{
+#ifdef XRENDER_LINK
+ XRenderChangePicture( mpDisplay, aPicture, nValueMask, pRenderAttr );
+#else
+ (*mpXRenderChangePicture)( mpDisplay, aPicture, nValueMask, pRenderAttr );
+#endif
+}
+
+inline void XRenderPeer::SetPictureClipRegion( Picture aPicture,
+ XLIB_Region aXlibRegion ) const
+{
+#ifdef XRENDER_LINK
+ XRenderSetPictureClipRegion( mpDisplay, aPicture, aXlibRegion );
+#else
+ (*mpXRenderSetPictureClipRegion)( mpDisplay, aPicture, aXlibRegion );
+#endif
+}
+
+inline void XRenderPeer::CompositePicture( int nXRenderOp,
+ Picture aSrcPic, Picture aMaskPic, Picture aDstPic,
+ int nSrcX, int nSrcY, int nMaskX, int nMaskY, int nDstX, int nDstY,
+ unsigned nWidth, unsigned nHeight ) const
+{
+#ifdef XRENDER_LINK
+ XRenderComposite( mpDisplay, nXRenderOp, aSrcPic, aMaskPic, aDstPic,
+ nSrcX, nSrcY, nMaskX, nMaskY, nDstX, nDstY, nWidth, nHeight );
+#else
+ (*mpXRenderComposite)( mpDisplay, nXRenderOp, aSrcPic, aMaskPic, aDstPic,
+ nSrcX, nSrcY, nMaskX, nMaskY, nDstX, nDstY, nWidth, nHeight );
+#endif
+}
+
+inline void XRenderPeer::FreePicture( Picture aPicture ) const
+{
+#ifdef XRENDER_LINK
+ XRenderFreePicture( mpDisplay, aPicture );
+#else
+ (*mpXRenderFreePicture)( mpDisplay, aPicture );
+#endif
+}
+
+inline GlyphSet XRenderPeer::CreateGlyphSet() const
+{
+#ifdef XRENDER_LINK
+ return XRenderCreateGlyphSet( mpDisplay, mpStandardFormatA8 );
+#else
+ return (*mpXRenderCreateGlyphSet)( mpDisplay, mpStandardFormatA8 );
+#endif
+}
+
+inline void XRenderPeer::FreeGlyphSet( GlyphSet aGS ) const
+{
+#ifdef XRENDER_LINK
+ XRenderFreeGlyphSet( mpDisplay, aGS );
+#else
+ (*mpXRenderFreeGlyphSet)( mpDisplay, aGS );
+#endif
+}
+
+inline void XRenderPeer::AddGlyph( GlyphSet aGS, Glyph nGlyphId,
+ const XGlyphInfo& rGI, const char* pBuffer, int nBufSize ) const
+{
+#ifdef XRENDER_LINK
+ XRenderAddGlyphs( mpDisplay, aGS, &nGlyphId, &rGI, 1,
+ const_cast<char*>(pBuffer), nBufSize );
+#else
+ (*mpXRenderAddGlyphs)( mpDisplay, aGS, &nGlyphId, &rGI, 1,
+ const_cast<char*>(pBuffer), nBufSize );
+#endif
+}
+
+inline void XRenderPeer::FreeGlyph( GlyphSet aGS, Glyph nGlyphId ) const
+{
+ (void)aGS; (void)nGlyphId;
+
+ // XRenderFreeGlyphs not implemented yet for version<=0.2
+ // #108209# disabled because of crash potential,
+ // the glyph leak is not too bad because they will
+ // be cleaned up when the glyphset is released
+#if 0 // TODO: reenable when it works without problems
+ if( mnRenderVersion >= 0x05 )
+ {
+#ifdef XRENDER_LINK
+ XRenderFreeGlyphs( mpDisplay, aGS, &nGlyphId, 1 );
+#else
+ (*mpXRenderFreeGlyphs)( mpDisplay, aGS, &nGlyphId, 1 );
+#endif
+ }
+#endif
+}
+
+inline void XRenderPeer::CompositeString32( Picture aSrc, Picture aDst,
+ GlyphSet aGlyphSet, int nDstX, int nDstY,
+ const unsigned* pText, int nTextLen ) const
+{
+#ifdef XRENDER_LINK
+ XRenderCompositeString32( mpDisplay, PictOpOver, aSrc, aDst, NULL,
+ aGlyphSet, 0, 0, nDstX, nDstY, pText, nTextLen );
+#else
+ (*mpXRenderCompositeString32)( mpDisplay, PictOpOver, aSrc, aDst, NULL,
+ aGlyphSet, 0, 0, nDstX, nDstY, pText, nTextLen );
+#endif
+}
+
+inline void XRenderPeer::FillRectangle( int a, Picture b, const XRenderColor* c,
+ int d, int e, unsigned int f, unsigned int g) const
+{
+#ifdef XRENDER_LINK
+ XRenderFillRectangle( mpDisplay, a, b, c, d, e, f, g );
+#else
+ (*mpXRenderFillRectangle)( mpDisplay, a, b, c, d, e, f, g );
+#endif
+}
+
+
+inline void XRenderPeer::CompositeTrapezoids( int nOp,
+ Picture aSrc, Picture aDst, const XRenderPictFormat* pXRPF,
+ int nXSrc, int nYSrc, const XTrapezoid* pXT, int nCount ) const
+{
+#ifdef XRENDER_LINK
+ XRenderCompositeTrapezoids( mpDisplay, nOp, aSrc, aDst, pXRPF,
+ nXSrc, nYSrc, pXT, nCount );
+#else
+ (*mpXRenderCompositeTrapezoids)( mpDisplay, nOp, aSrc, aDst, pXRPF,
+ nXSrc, nYSrc, pXT, nCount );
+#endif
+}
+
+inline bool XRenderPeer::AddTraps( Picture aDst, int nXOfs, int nYOfs,
+ const _XTrap* pTraps, int nCount ) const
+{
+#ifdef XRENDER_LINK
+ XRenderAddTraps( mpDisplay, aDst, nXOfs, nYOfs, pTraps, nCount );
+#else
+ if( !mpXRenderAddTraps )
+ return false;
+ (*mpXRenderAddTraps)( mpDisplay, aDst, nXOfs, nYOfs, pTraps, nCount );
+#endif
+ return true;
+}
+
+//=====================================================================
+
+inline ScopedPic::ScopedPic( XRenderPeer& rPeer, Picture& rPic )
+: mrRenderPeer( rPeer)
+, maPicture( rPic )
+{}
+
+inline ScopedPic::~ScopedPic()
+{
+ if( maPicture )
+ mrRenderPeer.FreePicture( maPicture );
+}
+
+inline Picture& ScopedPic::Get()
+{
+ return maPicture;
+}
+
+//=====================================================================
+
+inline XRenderColor GetXRenderColor( const SalColor& rSalColor, double fTransparency = 0.0 )
+{
+ XRenderColor aRetVal;
+ // convert the SalColor
+ aRetVal.red = SALCOLOR_RED( rSalColor ); aRetVal.red |= (aRetVal.red << 8);
+ aRetVal.green = SALCOLOR_GREEN( rSalColor ); aRetVal.green |= (aRetVal.green << 8);
+ aRetVal.blue = SALCOLOR_BLUE( rSalColor ); aRetVal.blue |= (aRetVal.blue << 8);
+
+ // handle transparency
+ aRetVal.alpha = 0xFFFF; // default to opaque
+ if( fTransparency != 0 )
+ {
+ const double fAlpha = 1.0 - fTransparency;
+ aRetVal.alpha = static_cast<sal_uInt16>(fAlpha * 0xFFFF + 0.5);
+ // xrender wants pre-multiplied colors
+ aRetVal.red = static_cast<sal_uInt16>(fAlpha * aRetVal.red + 0.5);
+ aRetVal.green = static_cast<sal_uInt16>(fAlpha * aRetVal.green + 0.5);
+ aRetVal.blue = static_cast<sal_uInt16>(fAlpha * aRetVal.blue + 0.5);
+ }
+
+ return aRetVal;
+}
+
+//=====================================================================
+
+#endif // _SV_XRENDER_PEER_HXX
diff --git a/vcl/unx/source/inc/airbrush_curs.h b/vcl/unx/source/inc/airbrush_curs.h
new file mode 100644
index 000000000000..293c9757e77b
--- /dev/null
+++ b/vcl/unx/source/inc/airbrush_curs.h
@@ -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.
+ *
+ ************************************************************************/
+#define airbrush_curs_width 32
+#define airbrush_curs_height 32
+#define airbrush_curs_x_hot 5
+#define airbrush_curs_y_hot 22
+static char airbrush_curs_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x78,0x00,0x00,0x00,
+ 0x7c,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x1f,0x00,0x00,0x98,0x0f,0x00,0x00,
+ 0xcc,0x07,0x00,0x00,0xb4,0x03,0x00,0x00,0x10,0x01,0x00,0x00,0x88,0x00,0x00,
+ 0x00,0x44,0x00,0x00,0x00,0x62,0x60,0x00,0x00,0x91,0x10,0x00,0x80,0x88,0x10,
+ 0x00,0x40,0x04,0x09,0x00,0x40,0x02,0x06,0x00,0xa0,0x01,0x00,0x00,0x60,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/airbrush_mask.h b/vcl/unx/source/inc/airbrush_mask.h
new file mode 100644
index 000000000000..811ea2819669
--- /dev/null
+++ b/vcl/unx/source/inc/airbrush_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define airbrush_mask_width 32
+#define airbrush_mask_height 32
+#define airbrush_mask_x_hot 5
+#define airbrush_mask_y_hot 22
+static char airbrush_mask_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x78,0x00,0x00,0x00,
+ 0x7c,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x1f,0x00,0x00,0x98,0x0f,0x00,0x00,
+ 0xcc,0x07,0x00,0x00,0xf4,0x03,0x00,0x00,0xf0,0x01,0x00,0x00,0xf8,0x00,0x00,
+ 0x00,0x7c,0x00,0x00,0x00,0x7e,0x60,0x00,0x00,0x9f,0x10,0x00,0x80,0x8f,0x10,
+ 0x00,0xc0,0x07,0x09,0x00,0xc0,0x03,0x06,0x00,0xe0,0x01,0x00,0x00,0x60,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/ase_curs.h b/vcl/unx/source/inc/ase_curs.h
new file mode 100644
index 000000000000..52b67f56d2ae
--- /dev/null
+++ b/vcl/unx/source/inc/ase_curs.h
@@ -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.
+ *
+ ************************************************************************/
+#define ase_curs_width 32
+#define ase_curs_height 32
+#define ase_curs_x_hot 19
+#define ase_curs_y_hot 16
+static char ase_curs_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x1c,0x0e,
+ 0x00,0x00,0x3e,0x1e,0x00,0x00,0x3e,0x7e,0x00,0x00,0x3e,0x1e,0x00,0x00,0x1c,
+ 0x0e,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/ase_mask.h b/vcl/unx/source/inc/ase_mask.h
new file mode 100644
index 000000000000..5dbd5c134dbf
--- /dev/null
+++ b/vcl/unx/source/inc/ase_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define ase_mask_width 32
+#define ase_mask_height 32
+#define ase_mask_x_hot 19
+#define ase_mask_y_hot 16
+static char ase_mask_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x9c,0x0f,0x00,0x00,0x3e,0x1f,
+ 0x00,0x00,0x7f,0x7f,0x00,0x00,0x7f,0xff,0x00,0x00,0x7f,0x7f,0x00,0x00,0x3e,
+ 0x1f,0x00,0x00,0x9c,0x0f,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/asn_curs.h b/vcl/unx/source/inc/asn_curs.h
new file mode 100644
index 000000000000..3b5f4364b5e2
--- /dev/null
+++ b/vcl/unx/source/inc/asn_curs.h
@@ -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.
+ *
+ ************************************************************************/
+#define asn_curs_width 32
+#define asn_curs_height 32
+#define asn_curs_x_hot 16
+#define asn_curs_y_hot 12
+static char asn_curs_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x80,0x03,
+ 0x00,0x00,0xc0,0x07,0x00,0x00,0xc0,0x07,0x00,0x00,0xe0,0x0f,0x00,0x00,0x20,
+ 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x03,0x00,0x00,
+ 0xc0,0x07,0x00,0x00,0xc0,0x07,0x00,0x00,0xc0,0x07,0x00,0x00,0x80,0x03,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/asn_mask.h b/vcl/unx/source/inc/asn_mask.h
new file mode 100644
index 000000000000..902fe80df8a1
--- /dev/null
+++ b/vcl/unx/source/inc/asn_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define asn_mask_width 32
+#define asn_mask_height 32
+#define asn_mask_x_hot 16
+#define asn_mask_y_hot 12
+static char asn_mask_bits[] = {
+ 0x00,0x00,0x01,0x00,0x00,0x80,0x03,0x00,0x00,0x80,0x03,0x00,0x00,0xc0,0x07,
+ 0x00,0x00,0xe0,0x0f,0x00,0x00,0xe0,0x0f,0x00,0x00,0xf0,0x1f,0x00,0x00,0xf0,
+ 0x1f,0x00,0x00,0x20,0x08,0x00,0x00,0x80,0x03,0x00,0x00,0xc0,0x07,0x00,0x00,
+ 0xe0,0x0f,0x00,0x00,0xe0,0x0f,0x00,0x00,0xe0,0x0f,0x00,0x00,0xc0,0x07,0x00,
+ 0x00,0x80,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/asne_curs.h b/vcl/unx/source/inc/asne_curs.h
new file mode 100644
index 000000000000..0939b1d07e4b
--- /dev/null
+++ b/vcl/unx/source/inc/asne_curs.h
@@ -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.
+ *
+ ************************************************************************/
+#define asne_curs_width 32
+#define asne_curs_height 32
+#define asne_curs_x_hot 21
+#define asne_curs_y_hot 10
+static char asne_curs_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x00,0x00,0x80,
+ 0x3f,0x00,0x00,0xc0,0x3f,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x1c,0x00,0x00,
+ 0x00,0x1c,0x00,0x00,0x70,0x18,0x00,0x00,0xf8,0x08,0x00,0x00,0xf8,0x00,0x00,
+ 0x00,0xf8,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/asne_mask.h b/vcl/unx/source/inc/asne_mask.h
new file mode 100644
index 000000000000..9ab55c293218
--- /dev/null
+++ b/vcl/unx/source/inc/asne_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define asne_mask_width 32
+#define asne_mask_height 32
+#define asne_mask_x_hot 21
+#define asne_mask_y_hot 10
+static char asne_mask_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0x00,0x00,0x80,0x7f,0x00,0x00,0xc0,
+ 0x7f,0x00,0x00,0xe0,0x7f,0x00,0x00,0xc0,0x7f,0x00,0x00,0x00,0x3f,0x00,0x00,
+ 0x70,0x3e,0x00,0x00,0xf8,0x3c,0x00,0x00,0xfc,0x1d,0x00,0x00,0xfc,0x09,0x00,
+ 0x00,0xfc,0x01,0x00,0x00,0xf8,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/asns_curs.h b/vcl/unx/source/inc/asns_curs.h
new file mode 100644
index 000000000000..fef8fe2f4ab5
--- /dev/null
+++ b/vcl/unx/source/inc/asns_curs.h
@@ -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.
+ *
+ ************************************************************************/
+#define asns_curs_width 32
+#define asns_curs_height 32
+#define asns_curs_x_hot 15
+#define asns_curs_y_hot 15
+static char asns_curs_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0xc0,0x01,0x00,0x00,0xe0,
+ 0x03,0x00,0x00,0xe0,0x03,0x00,0x00,0xf0,0x07,0x00,0x00,0x10,0x04,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01,0x00,0x00,0xe0,0x03,0x00,
+ 0x00,0xe0,0x03,0x00,0x00,0xe0,0x03,0x00,0x00,0xc0,0x01,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x04,0x00,0x00,0xf0,0x07,0x00,0x00,0xe0,
+ 0x03,0x00,0x00,0xe0,0x03,0x00,0x00,0xc0,0x01,0x00,0x00,0x80,0x00,0x00,0x00,
+ 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/asns_mask.h b/vcl/unx/source/inc/asns_mask.h
new file mode 100644
index 000000000000..f90cb95ee721
--- /dev/null
+++ b/vcl/unx/source/inc/asns_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define asns_mask_width 32
+#define asns_mask_height 32
+#define asns_mask_x_hot 15
+#define asns_mask_y_hot 15
+static char asns_mask_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,
+ 0x00,0x00,0xc0,0x01,0x00,0x00,0xc0,0x01,0x00,0x00,0xe0,0x03,0x00,0x00,0xf0,
+ 0x07,0x00,0x00,0xf0,0x07,0x00,0x00,0xf8,0x0f,0x00,0x00,0xf8,0x0f,0x00,0x00,
+ 0x10,0x04,0x00,0x00,0xc0,0x01,0x00,0x00,0xe0,0x03,0x00,0x00,0xf0,0x07,0x00,
+ 0x00,0xf0,0x07,0x00,0x00,0xf0,0x07,0x00,0x00,0xe0,0x03,0x00,0x00,0xc0,0x01,
+ 0x00,0x00,0x10,0x04,0x00,0x00,0xf8,0x0f,0x00,0x00,0xf8,0x0f,0x00,0x00,0xf0,
+ 0x07,0x00,0x00,0xf0,0x07,0x00,0x00,0xe0,0x03,0x00,0x00,0xc0,0x01,0x00,0x00,
+ 0xc0,0x01,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/asnswe_curs.h b/vcl/unx/source/inc/asnswe_curs.h
new file mode 100644
index 000000000000..fd6ddaca65cb
--- /dev/null
+++ b/vcl/unx/source/inc/asnswe_curs.h
@@ -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.
+ *
+ ************************************************************************/
+#define asnswe_curs_width 32
+#define asnswe_curs_height 32
+#define asnswe_curs_x_hot 15
+#define asnswe_curs_y_hot 15
+static char asnswe_curs_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0xc0,0x01,0x00,0x00,0xe0,
+ 0x03,0x00,0x00,0xe0,0x03,0x00,0x00,0xf0,0x07,0x00,0x00,0x10,0x04,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x06,0x30,0x00,0x80,0xc3,0xe1,0x00,0xc0,0xe3,0xe3,0x01,
+ 0xf0,0xe3,0xe3,0x07,0xc0,0xe3,0xe3,0x01,0x80,0xc3,0xe1,0x00,0x00,0x06,0x30,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x04,0x00,0x00,0xf0,0x07,0x00,0x00,0xe0,
+ 0x03,0x00,0x00,0xe0,0x03,0x00,0x00,0xc0,0x01,0x00,0x00,0x80,0x00,0x00,0x00,
+ 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/asnswe_mask.h b/vcl/unx/source/inc/asnswe_mask.h
new file mode 100644
index 000000000000..e48da90e3de5
--- /dev/null
+++ b/vcl/unx/source/inc/asnswe_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define asnswe_mask_width 32
+#define asnswe_mask_height 32
+#define asnswe_mask_x_hot 15
+#define asnswe_mask_y_hot 15
+static char asnswe_mask_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,
+ 0x00,0x00,0xc0,0x01,0x00,0x00,0xc0,0x01,0x00,0x00,0xe0,0x03,0x00,0x00,0xf0,
+ 0x07,0x00,0x00,0xf0,0x07,0x00,0x00,0xf8,0x0f,0x00,0x00,0xf8,0x0f,0x00,0x00,
+ 0x16,0x34,0x00,0x80,0xcf,0xf9,0x00,0xc0,0xe7,0xf3,0x01,0xf0,0xf7,0xf7,0x07,
+ 0xf8,0xf7,0xf7,0x0f,0xf0,0xf7,0xf7,0x07,0xc0,0xe7,0xf3,0x01,0x80,0xcf,0xf9,
+ 0x00,0x00,0x16,0x34,0x00,0x00,0xf8,0x0f,0x00,0x00,0xf8,0x0f,0x00,0x00,0xf0,
+ 0x07,0x00,0x00,0xf0,0x07,0x00,0x00,0xe0,0x03,0x00,0x00,0xc0,0x01,0x00,0x00,
+ 0xc0,0x01,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/asnw_curs.h b/vcl/unx/source/inc/asnw_curs.h
new file mode 100644
index 000000000000..cb3a35d793c7
--- /dev/null
+++ b/vcl/unx/source/inc/asnw_curs.h
@@ -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.
+ *
+ ************************************************************************/
+#define asnw_curs_width 32
+#define asnw_curs_height 32
+#define asnw_curs_x_hot 10
+#define asnw_curs_y_hot 10
+static char asnw_curs_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0xfc,0x01,0x00,
+ 0x00,0xfc,0x03,0x00,0x00,0xfc,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x38,0x00,
+ 0x00,0x00,0x18,0x0e,0x00,0x00,0x10,0x1f,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,
+ 0x1f,0x00,0x00,0x00,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/asnw_mask.h b/vcl/unx/source/inc/asnw_mask.h
new file mode 100644
index 000000000000..e583957c4bae
--- /dev/null
+++ b/vcl/unx/source/inc/asnw_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define asnw_mask_width 32
+#define asnw_mask_height 32
+#define asnw_mask_x_hot 10
+#define asnw_mask_y_hot 10
+static char asnw_mask_bits[] = {
+ 0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0xfe,0x01,0x00,0x00,0xfe,0x03,0x00,
+ 0x00,0xfe,0x07,0x00,0x00,0xfe,0x03,0x00,0x00,0xfc,0x00,0x00,0x00,0x7c,0x0e,
+ 0x00,0x00,0x3c,0x1f,0x00,0x00,0xb8,0x3f,0x00,0x00,0x90,0x3f,0x00,0x00,0x80,
+ 0x3f,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/ass_curs.h b/vcl/unx/source/inc/ass_curs.h
new file mode 100644
index 000000000000..ea942cefe942
--- /dev/null
+++ b/vcl/unx/source/inc/ass_curs.h
@@ -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.
+ *
+ ************************************************************************/
+#define ass_curs_width 32
+#define ass_curs_height 32
+#define ass_curs_x_hot 15
+#define ass_curs_y_hot 19
+static char ass_curs_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01,0x00,0x00,0xe0,0x03,
+ 0x00,0x00,0xe0,0x03,0x00,0x00,0xe0,0x03,0x00,0x00,0xc0,0x01,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x04,0x00,0x00,0xf0,0x07,0x00,0x00,
+ 0xe0,0x03,0x00,0x00,0xe0,0x03,0x00,0x00,0xc0,0x01,0x00,0x00,0x80,0x00,0x00,
+ 0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/ass_mask.h b/vcl/unx/source/inc/ass_mask.h
new file mode 100644
index 000000000000..b35298183cb1
--- /dev/null
+++ b/vcl/unx/source/inc/ass_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define ass_mask_width 32
+#define ass_mask_height 32
+#define ass_mask_x_hot 15
+#define ass_mask_y_hot 19
+static char ass_mask_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0xc0,0x01,0x00,0x00,0xe0,0x03,0x00,0x00,0xf0,0x07,
+ 0x00,0x00,0xf0,0x07,0x00,0x00,0xf0,0x07,0x00,0x00,0xe0,0x03,0x00,0x00,0xc0,
+ 0x01,0x00,0x00,0x10,0x04,0x00,0x00,0xf8,0x0f,0x00,0x00,0xf8,0x0f,0x00,0x00,
+ 0xf0,0x07,0x00,0x00,0xf0,0x07,0x00,0x00,0xe0,0x03,0x00,0x00,0xc0,0x01,0x00,
+ 0x00,0xc0,0x01,0x00,0x00,0x80,0x00,0x00};
diff --git a/vcl/unx/source/inc/asse_curs.h b/vcl/unx/source/inc/asse_curs.h
new file mode 100644
index 000000000000..4b30e81882ff
--- /dev/null
+++ b/vcl/unx/source/inc/asse_curs.h
@@ -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.
+ *
+ ************************************************************************/
+#define asse_curs_width 32
+#define asse_curs_height 32
+#define asse_curs_x_hot 21
+#define asse_curs_y_hot 21
+static char asse_curs_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x70,0x00,0x00,0x00,0xf8,0x00,0x00,0x00,0xf8,0x00,0x00,0x00,
+ 0xf8,0x08,0x00,0x00,0x70,0x18,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x1c,0x00,
+ 0x00,0x00,0x3f,0x00,0x00,0xc0,0x3f,0x00,0x00,0x80,0x3f,0x00,0x00,0x00,0x3c,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/asse_mask.h b/vcl/unx/source/inc/asse_mask.h
new file mode 100644
index 000000000000..ad74b0cf724a
--- /dev/null
+++ b/vcl/unx/source/inc/asse_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define asse_mask_width 32
+#define asse_mask_height 32
+#define asse_mask_x_hot 21
+#define asse_mask_y_hot 21
+static char asse_mask_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,
+ 0x00,0x00,0x00,0xf8,0x00,0x00,0x00,0xfc,0x01,0x00,0x00,0xfc,0x09,0x00,0x00,
+ 0xfc,0x1d,0x00,0x00,0xf8,0x3c,0x00,0x00,0x70,0x3e,0x00,0x00,0x00,0x3f,0x00,
+ 0x00,0xc0,0x7f,0x00,0x00,0xe0,0x7f,0x00,0x00,0xc0,0x7f,0x00,0x00,0x80,0x7f,
+ 0x00,0x00,0x00,0x7c,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/assw_curs.h b/vcl/unx/source/inc/assw_curs.h
new file mode 100644
index 000000000000..d26c36e79ed4
--- /dev/null
+++ b/vcl/unx/source/inc/assw_curs.h
@@ -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.
+ *
+ ************************************************************************/
+#define assw_curs_width 32
+#define assw_curs_height 32
+#define assw_curs_x_hot 21
+#define assw_curs_y_hot 21
+static char assw_curs_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x0e,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x1f,0x00,0x00,0x10,0x1f,
+ 0x00,0x00,0x18,0x0e,0x00,0x00,0x38,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0xfc,
+ 0x00,0x00,0x00,0xfc,0x03,0x00,0x00,0xfc,0x01,0x00,0x00,0x3c,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/assw_mask.h b/vcl/unx/source/inc/assw_mask.h
new file mode 100644
index 000000000000..ea47a3ee27e9
--- /dev/null
+++ b/vcl/unx/source/inc/assw_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define assw_mask_width 32
+#define assw_mask_height 32
+#define assw_mask_x_hot 21
+#define assw_mask_y_hot 21
+static char assw_mask_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x0e,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x1f,0x00,0x00,0x10,0x1f,
+ 0x00,0x00,0x18,0x0e,0x00,0x00,0x38,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0xfc,
+ 0x00,0x00,0x00,0xfc,0x03,0x00,0x00,0xfc,0x01,0x00,0x00,0x3c,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/asw_curs.h b/vcl/unx/source/inc/asw_curs.h
new file mode 100644
index 000000000000..7b9b2199955a
--- /dev/null
+++ b/vcl/unx/source/inc/asw_curs.h
@@ -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.
+ *
+ ************************************************************************/
+#define asw_curs_width 32
+#define asw_curs_height 32
+#define asw_curs_x_hot 12
+#define asw_curs_y_hot 15
+static char asw_curs_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x70,0x38,0x00,0x00,0x78,0x7c,0x00,0x00,
+ 0x7e,0x7c,0x00,0x00,0x78,0x7c,0x00,0x00,0x70,0x38,0x00,0x00,0xc0,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/asw_mask.h b/vcl/unx/source/inc/asw_mask.h
new file mode 100644
index 000000000000..df934399fe91
--- /dev/null
+++ b/vcl/unx/source/inc/asw_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define asw_mask_width 32
+#define asw_mask_height 32
+#define asw_mask_x_hot 12
+#define asw_mask_y_hot 15
+static char asw_mask_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,
+ 0x00,0x00,0x00,0xf0,0x39,0x00,0x00,0xf8,0x7c,0x00,0x00,0xfe,0xfe,0x00,0x00,
+ 0xff,0xfe,0x00,0x00,0xfe,0xfe,0x00,0x00,0xf8,0x7c,0x00,0x00,0xf0,0x39,0x00,
+ 0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/aswe_curs.h b/vcl/unx/source/inc/aswe_curs.h
new file mode 100644
index 000000000000..f06d2140559e
--- /dev/null
+++ b/vcl/unx/source/inc/aswe_curs.h
@@ -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.
+ *
+ ************************************************************************/
+#define aswe_curs_width 32
+#define aswe_curs_height 32
+#define aswe_curs_x_hot 15
+#define aswe_curs_y_hot 15
+static char aswe_curs_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x06,0x30,0x00,0x80,0xc3,0xe1,0x00,0xc0,0xe3,0xe3,0x01,
+ 0xf0,0xe3,0xe3,0x07,0xc0,0xe3,0xe3,0x01,0x80,0xc3,0xe1,0x00,0x00,0x06,0x30,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/aswe_mask.h b/vcl/unx/source/inc/aswe_mask.h
new file mode 100644
index 000000000000..c04dbf5deafb
--- /dev/null
+++ b/vcl/unx/source/inc/aswe_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define aswe_mask_width 32
+#define aswe_mask_height 32
+#define aswe_mask_x_hot 15
+#define aswe_mask_y_hot 15
+static char aswe_mask_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x06,0x30,0x00,0x80,0xcf,0xf9,0x00,0xc0,0xe7,0xf3,0x01,0xf0,0xf7,0xf7,0x07,
+ 0xf8,0xf7,0xf7,0x0f,0xf0,0xf7,0xf7,0x07,0xc0,0xe7,0xf3,0x01,0x80,0xcf,0xf9,
+ 0x00,0x00,0x06,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/chain_curs.h b/vcl/unx/source/inc/chain_curs.h
new file mode 100644
index 000000000000..95b4fbe66c2e
--- /dev/null
+++ b/vcl/unx/source/inc/chain_curs.h
@@ -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.
+ *
+ ************************************************************************/
+#define chain_curs_width 32
+#define chain_curs_height 32
+#define chain_curs_x_hot 0
+#define chain_curs_y_hot 2
+static char chain_curs_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,
+ 0x00,0x05,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x21,0x00,
+ 0x00,0x00,0x41,0x00,0x00,0x00,0x81,0x00,0x00,0x00,0x01,0x01,0x00,0x00,0x01,
+ 0x02,0x00,0x00,0x01,0x04,0x00,0x00,0x81,0x0f,0x00,0x00,0x91,0x00,0x00,0x00,
+ 0x99,0x00,0x00,0x00,0x25,0x01,0x00,0x00,0x23,0x01,0x00,0x00,0x41,0x3e,0xbf,
+ 0x0f,0x40,0x82,0x40,0x10,0x80,0x5c,0xae,0x23,0x80,0x24,0x91,0x24,0x00,0x23,
+ 0x91,0x28,0x80,0x24,0x91,0x28,0x80,0x24,0x91,0x24,0x80,0x98,0x4f,0x23,0x00,
+ 0x41,0x20,0x10,0x00,0x3e,0xde,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/chain_mask.h b/vcl/unx/source/inc/chain_mask.h
new file mode 100644
index 000000000000..91d89bbed3c6
--- /dev/null
+++ b/vcl/unx/source/inc/chain_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define chain_mask_width 32
+#define chain_mask_height 32
+static char chain_mask_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,
+ 0x00,0x07,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x3f,0x00,
+ 0x00,0x00,0x7f,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x01,0x00,0x00,0xff,
+ 0x03,0x00,0x00,0xff,0x07,0x00,0x00,0xff,0x0f,0x00,0x00,0xff,0x00,0x00,0x00,
+ 0xff,0x00,0x00,0x00,0xe7,0x01,0x00,0x00,0xe3,0x01,0x00,0x00,0xc1,0x3f,0xbf,
+ 0x0f,0xc0,0xbf,0xff,0x1f,0x80,0xdf,0xff,0x3f,0x80,0xe7,0xf1,0x3c,0x00,0xe3,
+ 0xf1,0x38,0x80,0xe7,0xf1,0x38,0x80,0xe7,0xf1,0x3c,0x80,0xff,0xff,0x3f,0x00,
+ 0x7f,0xff,0x1f,0x00,0x3e,0xde,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/chainnot_curs.h b/vcl/unx/source/inc/chainnot_curs.h
new file mode 100644
index 000000000000..841e2efdec63
--- /dev/null
+++ b/vcl/unx/source/inc/chainnot_curs.h
@@ -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.
+ *
+ ************************************************************************/
+#define chainnot_curs_width 32
+#define chainnot_curs_height 32
+#define chainnot_curs_x_hot 2
+#define chainnot_curs_y_hot 2
+static char chainnot_curs_bits[] = {
+ 0x00,0x00,0x00,0x00,0x80,0x1f,0x00,0x00,0xe0,0x7f,0x00,0x00,0xf0,0xf0,0x00,
+ 0x00,0x38,0xc0,0x01,0x00,0x7c,0x80,0x03,0x00,0xec,0x00,0x03,0x00,0xce,0x01,
+ 0x07,0x00,0x86,0x03,0x06,0x00,0x06,0x07,0x06,0x00,0x06,0x0e,0x06,0x00,0x06,
+ 0x1c,0x06,0x00,0x0e,0x38,0x07,0x00,0x0c,0x70,0x03,0x00,0x1c,0xe0,0x03,0x00,
+ 0x38,0xc0,0x01,0x00,0xf0,0xe0,0x00,0x00,0xe0,0x7f,0x00,0x00,0x80,0x9f,0xfc,
+ 0x3e,0x00,0x00,0x02,0x41,0x00,0x72,0xb9,0x8e,0x00,0x92,0x44,0x92,0x00,0x8c,
+ 0x44,0xa2,0x00,0x92,0x44,0xa2,0x00,0x92,0x44,0x92,0x00,0x62,0x3e,0x8d,0x00,
+ 0x04,0x81,0x40,0x00,0xf8,0x78,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/chainnot_mask.h b/vcl/unx/source/inc/chainnot_mask.h
new file mode 100644
index 000000000000..9fbed6408c54
--- /dev/null
+++ b/vcl/unx/source/inc/chainnot_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define chainnot_mask_width 32
+#define chainnot_mask_height 32
+static char chainnot_mask_bits[] = {
+ 0x80,0x1f,0x00,0x00,0xe0,0x7f,0x00,0x00,0xf0,0xff,0x00,0x00,0xf8,0xff,0x01,
+ 0x00,0xfc,0xf0,0x03,0x00,0xfe,0xc0,0x07,0x00,0xfe,0x81,0x07,0x00,0xff,0x83,
+ 0x0f,0x00,0xcf,0x07,0x0f,0x00,0x8f,0x0f,0x0f,0x00,0x0f,0x1f,0x0f,0x00,0x0f,
+ 0x3e,0x0f,0x00,0x1f,0xfc,0x0f,0x00,0x1e,0xf8,0x07,0x00,0x3e,0xf0,0x07,0x00,
+ 0xfc,0xe0,0x03,0x00,0xf8,0xff,0x01,0x00,0xf0,0xff,0x00,0x00,0xe0,0xff,0xfc,
+ 0x3e,0x80,0xff,0xfe,0x7f,0x00,0x7e,0xff,0xff,0x00,0x9e,0xc7,0xf3,0x00,0x8c,
+ 0xc7,0xe3,0x00,0x9e,0xc7,0xe3,0x00,0x9e,0xc7,0xf3,0x00,0xfe,0xff,0xff,0x00,
+ 0xfc,0xfd,0x7f,0x00,0xf8,0x78,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/chart_curs.h b/vcl/unx/source/inc/chart_curs.h
new file mode 100644
index 000000000000..9346fbd8f2c0
--- /dev/null
+++ b/vcl/unx/source/inc/chart_curs.h
@@ -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.
+ *
+ ************************************************************************/
+#define chart_curs_width 32
+#define chart_curs_height 32
+#define chart_curs_x_hot 15
+#define chart_curs_y_hot 16
+static char chart_curs_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,
+ 0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0xbf,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,
+ 0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,
+ 0x10,0x00,0x00,0x80,0x00,0x06,0x00,0x00,0x10,0x06,0x00,0x00,0x00,0x06,0x00,
+ 0x00,0x10,0x36,0x00,0x00,0xc0,0x36,0x00,0x00,0xd0,0x36,0x00,0x00,0xc0,0x36,
+ 0x00,0x00,0xf0,0x7f,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/chart_mask.h b/vcl/unx/source/inc/chart_mask.h
new file mode 100644
index 000000000000..d4804fb6c85b
--- /dev/null
+++ b/vcl/unx/source/inc/chart_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define chart_mask_width 32
+#define chart_mask_height 32
+#define chart_mask_x_hot 15
+#define chart_mask_y_hot 16
+static char chart_mask_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0xc0,0x01,0x00,0x00,0xc0,0x01,0x00,0x00,0xc0,0x01,0x00,0x00,
+ 0xc0,0x01,0x00,0x00,0xc0,0x01,0x00,0x00,0xc0,0x01,0x00,0x00,0xc0,0x01,0x00,
+ 0x80,0xff,0xff,0x00,0x80,0xff,0xff,0x00,0x80,0xff,0xff,0x00,0x00,0xc0,0x01,
+ 0x00,0x00,0xc0,0x01,0x00,0x00,0xc0,0x01,0x00,0x00,0xc0,0x39,0x00,0x00,0xc0,
+ 0x39,0x0f,0x00,0xc0,0x39,0x0f,0x00,0xc0,0x39,0x0f,0x00,0x00,0x38,0x7f,0x00,
+ 0x00,0xf8,0x7f,0x00,0x00,0xf8,0x7f,0x00,0x00,0xf8,0x7f,0x00,0x00,0xf8,0xff,
+ 0x00,0x00,0xf8,0xff,0x00,0x00,0xf8,0xff};
diff --git a/vcl/unx/source/inc/copydata_curs.h b/vcl/unx/source/inc/copydata_curs.h
new file mode 100644
index 000000000000..e3d0e3e76530
--- /dev/null
+++ b/vcl/unx/source/inc/copydata_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 copydata_curs_width 32
+#define copydata_curs_height 32
+#define copydata_curs_x_hot 1
+#define copydata_curs_y_hot 1
+static char copydata_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00,
+ 0xfe, 0x03, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00,
+ 0x66, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x10, 0x53, 0x00, 0x00,
+ 0x28, 0xa3, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x10, 0xf0, 0x1f, 0x00, 0x08, 0xf0, 0x1f, 0x00, 0x10, 0xf0, 0x1e, 0x00,
+ 0xa8, 0xf2, 0x1e, 0x00, 0x50, 0x35, 0x18, 0x00, 0x00, 0xf0, 0x1e, 0x00,
+ 0x00, 0xf0, 0x1e, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf0, 0x1f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/copydata_mask.h b/vcl/unx/source/inc/copydata_mask.h
new file mode 100644
index 000000000000..f25b0863d807
--- /dev/null
+++ b/vcl/unx/source/inc/copydata_mask.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 copydata_mask_width 32
+#define copydata_mask_height 32
+#define copydata_mask_x_hot 1
+#define copydata_mask_y_hot 1
+static char copydata_mask_bits[] = {
+ 0x07, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
+ 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00,
+ 0xff, 0x07, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0xe7, 0x03, 0x00, 0x00,
+ 0xe0, 0x03, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00,
+ 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0x3c, 0xf8, 0x3f, 0x00,
+ 0x3c, 0xf8, 0x3f, 0x00, 0x3c, 0xf8, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00,
+ 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0x3f, 0x00,
+ 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x3f, 0x00,
+ 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/copydlnk_curs.h b/vcl/unx/source/inc/copydlnk_curs.h
new file mode 100644
index 000000000000..8e22a5bee37b
--- /dev/null
+++ b/vcl/unx/source/inc/copydlnk_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 copydlnk_curs_width 32
+#define copydlnk_curs_height 32
+#define copydlnk_curs_x_hot 1
+#define copydlnk_curs_y_hot 1
+static char copydlnk_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00,
+ 0xfe, 0x03, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00,
+ 0x66, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x10, 0x53, 0x00, 0x00,
+ 0x28, 0xa3, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0xf0, 0x01, 0x00, 0x00,
+ 0x30, 0xf1, 0x1f, 0x00, 0x10, 0xf1, 0x1f, 0x00, 0xd0, 0xf1, 0x1e, 0x00,
+ 0xf0, 0xf1, 0x1e, 0x00, 0x00, 0x34, 0x18, 0x00, 0x00, 0xf0, 0x1e, 0x00,
+ 0x00, 0xf0, 0x1e, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf0, 0x1f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/copydlnk_mask.h b/vcl/unx/source/inc/copydlnk_mask.h
new file mode 100644
index 000000000000..02ee5db5fbc1
--- /dev/null
+++ b/vcl/unx/source/inc/copydlnk_mask.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 copydlnk_mask_width 32
+#define copydlnk_mask_height 32
+#define copydlnk_mask_x_hot 1
+#define copydlnk_mask_y_hot 1
+static char copydlnk_mask_bits[] = {
+ 0x07, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
+ 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00,
+ 0xff, 0x07, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0xe7, 0x03, 0x00, 0x00,
+ 0xe0, 0x03, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00,
+ 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x3f, 0x00,
+ 0xf8, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0x3f, 0x00,
+ 0xf8, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0x3f, 0x00, 0x00, 0xfe, 0x3f, 0x00,
+ 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x3f, 0x00,
+ 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/copyfile_curs.h b/vcl/unx/source/inc/copyfile_curs.h
new file mode 100644
index 000000000000..c74a1da26b66
--- /dev/null
+++ b/vcl/unx/source/inc/copyfile_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 copyfile_curs_width 32
+#define copyfile_curs_height 32
+#define copyfile_curs_x_hot 9
+#define copyfile_curs_y_hot 9
+static char copyfile_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x02, 0x00, 0x00,
+ 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00,
+ 0xfe, 0x07, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0xfe, 0x04, 0x00, 0x00,
+ 0xfe, 0x02, 0x00, 0x00, 0xfe, 0x06, 0x00, 0x00, 0xfe, 0x0e, 0x00, 0x00,
+ 0xfe, 0x1e, 0x00, 0x00, 0xfe, 0x3e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
+ 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x03, 0x00,
+ 0x00, 0x7e, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00,
+ 0x00, 0xc2, 0xe0, 0x3f, 0x00, 0xc0, 0xe0, 0x3f, 0x00, 0x80, 0xe1, 0x3d,
+ 0x00, 0x80, 0xe1, 0x3d, 0x00, 0x00, 0x63, 0x30, 0x00, 0x00, 0xe3, 0x3d,
+ 0x00, 0x00, 0xe0, 0x3d, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x00, 0xe0, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/copyfile_mask.h b/vcl/unx/source/inc/copyfile_mask.h
new file mode 100644
index 000000000000..c13089abaea5
--- /dev/null
+++ b/vcl/unx/source/inc/copyfile_mask.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 copyfile_mask_width 32
+#define copyfile_mask_height 32
+#define copyfile_mask_x_hot 9
+#define copyfile_mask_y_hot 9
+static char copyfile_mask_bits[] = {
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00,
+ 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00,
+ 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00,
+ 0xff, 0x0f, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00,
+ 0xff, 0x7f, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00,
+ 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x07, 0x00,
+ 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xf1, 0x7f,
+ 0x00, 0xff, 0xf1, 0x7f, 0x00, 0xe7, 0xf3, 0x7f, 0x00, 0xe0, 0xf3, 0x7f,
+ 0x00, 0xc0, 0xf7, 0x7f, 0x00, 0xc0, 0xf7, 0x7f, 0x00, 0x80, 0xf7, 0x7f,
+ 0x00, 0x80, 0xf7, 0x7f, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0xf0, 0x7f,
+ 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/copyfiles_curs.h b/vcl/unx/source/inc/copyfiles_curs.h
new file mode 100644
index 000000000000..e6a9b7a668af
--- /dev/null
+++ b/vcl/unx/source/inc/copyfiles_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 copyfiles_curs_width 32
+#define copyfiles_curs_height 32
+#define copyfiles_curs_x_hot 8
+#define copyfiles_curs_y_hot 9
+static char copyfiles_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xe0, 0x2f, 0x00, 0x00,
+ 0xe8, 0x0f, 0x00, 0x00, 0xe8, 0x7f, 0x00, 0x00, 0xea, 0x7f, 0x00, 0x00,
+ 0xea, 0x7f, 0x00, 0x00, 0xea, 0x7f, 0x00, 0x00, 0x6a, 0x7e, 0x00, 0x00,
+ 0x6a, 0x7d, 0x00, 0x00, 0x6a, 0x7b, 0x00, 0x00, 0x6a, 0x77, 0x00, 0x00,
+ 0x6a, 0x6f, 0x00, 0x00, 0x6a, 0x5f, 0x00, 0x00, 0x0a, 0x3f, 0x00, 0x00,
+ 0x7a, 0x7f, 0x00, 0x00, 0x02, 0xff, 0x00, 0x00, 0x7e, 0xff, 0x01, 0x00,
+ 0x00, 0x3f, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00,
+ 0x00, 0x61, 0xe0, 0x3f, 0x00, 0x60, 0xe0, 0x3f, 0x00, 0xc0, 0xe0, 0x3d,
+ 0x00, 0xc0, 0xe0, 0x3d, 0x00, 0x80, 0x61, 0x30, 0x00, 0x80, 0xe1, 0x3d,
+ 0x00, 0x00, 0xe0, 0x3d, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x00, 0xe0, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/copyfiles_mask.h b/vcl/unx/source/inc/copyfiles_mask.h
new file mode 100644
index 000000000000..f904b7848f64
--- /dev/null
+++ b/vcl/unx/source/inc/copyfiles_mask.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 copyfiles_mask_width 32
+#define copyfiles_mask_height 32
+#define copyfiles_mask_x_hot 8
+#define copyfiles_mask_y_hot 9
+static char copyfiles_mask_bits[] = {
+ 0xf0, 0x1f, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00,
+ 0xfc, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00,
+ 0xff, 0xff, 0x03, 0x00, 0x80, 0x7f, 0x00, 0x00, 0x80, 0xff, 0xf0, 0x7f,
+ 0x80, 0xff, 0xf0, 0x7f, 0x80, 0xf3, 0xf1, 0x7f, 0x00, 0xf0, 0xf1, 0x7f,
+ 0x00, 0xe0, 0xf3, 0x7f, 0x00, 0xe0, 0xf3, 0x7f, 0x00, 0xc0, 0xf3, 0x7f,
+ 0x00, 0xc0, 0xf3, 0x7f, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0xf0, 0x7f,
+ 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/copyflnk_curs.h b/vcl/unx/source/inc/copyflnk_curs.h
new file mode 100644
index 000000000000..b76368923f31
--- /dev/null
+++ b/vcl/unx/source/inc/copyflnk_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 copyflnk_curs_width 32
+#define copyflnk_curs_height 32
+#define copyflnk_curs_x_hot 9
+#define copyflnk_curs_y_hot 9
+static char copyflnk_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x02, 0x00, 0x00,
+ 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00,
+ 0xfe, 0x07, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00,
+ 0xbe, 0x02, 0x00, 0x00, 0xa6, 0x06, 0x00, 0x00, 0xa2, 0x0e, 0x00, 0x00,
+ 0xba, 0x1e, 0x00, 0x00, 0xbe, 0x3e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
+ 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x03, 0x00,
+ 0x00, 0x7e, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00,
+ 0x00, 0xc2, 0xe0, 0x3f, 0x00, 0xc0, 0xe0, 0x3f, 0x00, 0x80, 0xe1, 0x3d,
+ 0x00, 0x80, 0xe1, 0x3d, 0x00, 0x00, 0x63, 0x30, 0x00, 0x00, 0xe3, 0x3d,
+ 0x00, 0x00, 0xe0, 0x3d, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x00, 0xe0, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/copyflnk_mask.h b/vcl/unx/source/inc/copyflnk_mask.h
new file mode 100644
index 000000000000..b8fac92fdd75
--- /dev/null
+++ b/vcl/unx/source/inc/copyflnk_mask.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 copyflnk_mask_width 32
+#define copyflnk_mask_height 32
+#define copyflnk_mask_x_hot 9
+#define copyflnk_mask_y_hot 9
+static char copyflnk_mask_bits[] = {
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00,
+ 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00,
+ 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00,
+ 0xff, 0x0f, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00,
+ 0xff, 0x7f, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00,
+ 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x07, 0x00,
+ 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xf1, 0x7f,
+ 0x00, 0xff, 0xf1, 0x7f, 0x00, 0xe7, 0xf3, 0x7f, 0x00, 0xe0, 0xf3, 0x7f,
+ 0x00, 0xc0, 0xf7, 0x7f, 0x00, 0xc0, 0xf7, 0x7f, 0x00, 0x80, 0xf7, 0x7f,
+ 0x00, 0x80, 0xf7, 0x7f, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0xf0, 0x7f,
+ 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/crook_curs.h b/vcl/unx/source/inc/crook_curs.h
new file mode 100644
index 000000000000..6e4d5f613959
--- /dev/null
+++ b/vcl/unx/source/inc/crook_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 crook_curs_width 32
+#define crook_curs_height 32
+#define crook_curs_x_hot 15
+#define crook_curs_y_hot 14
+static char crook_curs_bits[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x7c, 0x3e, 0xff, 0x7f, 0xbb, 0xdd, 0xfe,
+ 0x7f, 0xbb, 0xdd, 0xfe, 0xf3, 0xb6, 0x6d, 0xcf, 0xed, 0xb6, 0x6d, 0xb7,
+ 0xdd, 0x75, 0xae, 0xbb, 0xbb, 0x0b, 0xd0, 0xdd, 0xb7, 0xf1, 0x8f, 0xed,
+ 0x4f, 0x0e, 0x70, 0xf2, 0xbf, 0xf1, 0x8f, 0xfd, 0x5f, 0xfe, 0x7f, 0xfa,
+ 0xaf, 0xff, 0xff, 0xf5, 0xd7, 0xff, 0xff, 0xeb, 0xef, 0xff, 0xff, 0xf7,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
diff --git a/vcl/unx/source/inc/crook_mask.h b/vcl/unx/source/inc/crook_mask.h
new file mode 100644
index 000000000000..7493f3a501dc
--- /dev/null
+++ b/vcl/unx/source/inc/crook_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define crook_mask_width 32
+#define crook_mask_height 32
+static char crook_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x83, 0xc1, 0x00, 0x80, 0xc7, 0xe3, 0x01, 0xc0, 0xef, 0xf7, 0x03,
+ 0xcc, 0xef, 0xf7, 0x33, 0x9e, 0xff, 0xff, 0x79, 0xbf, 0xff, 0xff, 0xfd,
+ 0x77, 0xff, 0xff, 0xee, 0xee, 0xf6, 0x6f, 0x77, 0xfc, 0xff, 0xff, 0x3f,
+ 0xb8, 0xff, 0xff, 0x1d, 0xf0, 0xff, 0xff, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f,
+ 0xf8, 0x01, 0x80, 0x1f, 0x7c, 0x00, 0x00, 0x3e, 0x38, 0x00, 0x00, 0x1c,
+ 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/crop_curs.h b/vcl/unx/source/inc/crop_curs.h
new file mode 100644
index 000000000000..a546ce6c1ba8
--- /dev/null
+++ b/vcl/unx/source/inc/crop_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 crop_curs_width 32
+#define crop_curs_height 32
+#define crop_curs_x_hot 9
+#define crop_curs_y_hot 9
+static char crop_curs_bits[] = {
+ 0xff, 0x0f, 0xff, 0xff, 0xff, 0x6f, 0xff, 0xff, 0xff, 0x6f, 0xff, 0xff,
+ 0x07, 0x60, 0xf8, 0xff, 0xf7, 0x6f, 0xfb, 0xff, 0xf7, 0x6f, 0xfb, 0xff,
+ 0x37, 0x60, 0xf8, 0xff, 0xb7, 0x6f, 0xff, 0xff, 0xb7, 0x6f, 0xff, 0xff,
+ 0xb7, 0x6f, 0xff, 0xff, 0xb7, 0x6f, 0xff, 0xff, 0xb7, 0x6f, 0xff, 0xff,
+ 0x30, 0x60, 0xff, 0xff, 0xb6, 0x7f, 0xff, 0xff, 0xb6, 0x7f, 0xff, 0xff,
+ 0x30, 0x00, 0xff, 0xff, 0xb7, 0xff, 0xff, 0xff, 0xb7, 0xff, 0xff, 0xff,
+ 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
diff --git a/vcl/unx/source/inc/crop_mask.h b/vcl/unx/source/inc/crop_mask.h
new file mode 100644
index 000000000000..5a10726cf36c
--- /dev/null
+++ b/vcl/unx/source/inc/crop_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define crop_mask_width 32
+#define crop_mask_height 32
+static char crop_mask_bits[] = {
+ 0x00, 0xf8, 0x01, 0x00, 0x00, 0xf8, 0x01, 0x00, 0xfc, 0xff, 0x0f, 0x00,
+ 0xfc, 0xff, 0x0f, 0x00, 0xfc, 0xff, 0x0f, 0x00, 0xfc, 0xff, 0x0f, 0x00,
+ 0xfc, 0xff, 0x0f, 0x00, 0xfc, 0xff, 0x0f, 0x00, 0xfc, 0xf8, 0x01, 0x00,
+ 0xfc, 0xf8, 0x01, 0x00, 0xfc, 0xf8, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00,
+ 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00,
+ 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfc, 0x00, 0x00, 0x00,
+ 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/detective_curs.h b/vcl/unx/source/inc/detective_curs.h
new file mode 100644
index 000000000000..9d8a0d6a1c47
--- /dev/null
+++ b/vcl/unx/source/inc/detective_curs.h
@@ -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.
+ *
+ ************************************************************************/
+#define detective_curs_width 32
+#define detective_curs_height 32
+#define detective_curs_x_hot 12
+#define detective_curs_y_hot 13
+static char detective_curs_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x38,0x00,
+ 0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7c,
+ 0x00,0x00,0x00,0x83,0x01,0x00,0x80,0x00,0x02,0x00,0x80,0x10,0x02,0x00,0x40,
+ 0x38,0x04,0x00,0x40,0x7c,0x04,0x00,0x40,0xfe,0x04,0x00,0x40,0x38,0x04,0x00,
+ 0x40,0x38,0x04,0x00,0x80,0x38,0x02,0x00,0x80,0x00,0x02,0x00,0x00,0x83,0x07,
+ 0x00,0x00,0x7c,0x0e,0x00,0x00,0x00,0x1c,0x00,0x00,0x10,0x38,0x00,0x00,0x38,
+ 0x70,0x00,0x00,0x10,0x60,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/detective_mask.h b/vcl/unx/source/inc/detective_mask.h
new file mode 100644
index 000000000000..14402a37b641
--- /dev/null
+++ b/vcl/unx/source/inc/detective_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define detective_mask_width 32
+#define detective_mask_height 32
+#define detective_mask_x_hot 12
+#define detective_mask_y_hot 13
+static char detective_mask_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x38,0x00,
+ 0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7c,
+ 0x00,0x00,0x00,0xff,0x01,0x00,0x80,0xff,0x03,0x00,0x80,0xff,0x03,0x00,0xc0,
+ 0xff,0x07,0x00,0xc0,0xff,0x07,0x00,0xc0,0xff,0x07,0x00,0xc0,0xff,0x07,0x00,
+ 0xc0,0xff,0x07,0x00,0x80,0xff,0x03,0x00,0x80,0xff,0x03,0x00,0x00,0xff,0x07,
+ 0x00,0x00,0x7c,0x0e,0x00,0x00,0x00,0x1c,0x00,0x00,0x10,0x38,0x00,0x00,0x38,
+ 0x70,0x00,0x00,0x10,0x60,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/drawarc_curs.h b/vcl/unx/source/inc/drawarc_curs.h
new file mode 100644
index 000000000000..daea116e186e
--- /dev/null
+++ b/vcl/unx/source/inc/drawarc_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 drawarc_curs_width 32
+#define drawarc_curs_height 32
+#define drawarc_curs_x_hot 7
+#define drawarc_curs_y_hot 7
+static char drawarc_curs_bits[] = {
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbf, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x42, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/drawarc_mask.h b/vcl/unx/source/inc/drawarc_mask.h
new file mode 100644
index 000000000000..c9e2b6dd8737
--- /dev/null
+++ b/vcl/unx/source/inc/drawarc_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define drawarc_mask_width 32
+#define drawarc_mask_height 32
+static char drawarc_mask_bits[] = {
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0x3f, 0x7e, 0x00, 0x00, 0xbf, 0x7e, 0x00, 0x00, 0x3f, 0x7e, 0x00, 0x00,
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x80, 0xe7, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00,
+ 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/drawbezier_curs.h b/vcl/unx/source/inc/drawbezier_curs.h
new file mode 100644
index 000000000000..ea677d4734aa
--- /dev/null
+++ b/vcl/unx/source/inc/drawbezier_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 drawbezier_curs_width 32
+#define drawbezier_curs_height 32
+#define drawbezier_curs_x_hot 7
+#define drawbezier_curs_y_hot 7
+static char drawbezier_curs_bits[] = {
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbf, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x07, 0x00, 0x00, 0x88, 0x00,
+ 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00,
+ 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x0e, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/drawbezier_mask.h b/vcl/unx/source/inc/drawbezier_mask.h
new file mode 100644
index 000000000000..17c1075d07a7
--- /dev/null
+++ b/vcl/unx/source/inc/drawbezier_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define drawbezier_mask_width 32
+#define drawbezier_mask_height 32
+static char drawbezier_mask_bits[] = {
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0x3f, 0x7e, 0x00, 0x00, 0xbf, 0x7e, 0x00, 0x00, 0x3f, 0x7e, 0x00, 0x00,
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x0f, 0x00, 0x00, 0x8e, 0x0f, 0x00, 0x00, 0xdc, 0x0f,
+ 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0xe0, 0x00,
+ 0x00, 0x00, 0xf0, 0x01, 0x00, 0x00, 0xbf, 0x03, 0x00, 0x00, 0x1f, 0x07,
+ 0x00, 0x00, 0x0f, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/drawcaption_curs.h b/vcl/unx/source/inc/drawcaption_curs.h
new file mode 100644
index 000000000000..3fe104f3673e
--- /dev/null
+++ b/vcl/unx/source/inc/drawcaption_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 drawcaption_curs_width 32
+#define drawcaption_curs_height 32
+#define drawcaption_curs_x_hot 8
+#define drawcaption_curs_y_hot 8
+static char drawcaption_curs_bits[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff,
+ 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff,
+ 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x81, 0x02, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff,
+ 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xbe, 0xff, 0xff,
+ 0xff, 0x7e, 0x1f, 0xe0, 0xff, 0xff, 0xde, 0xef, 0xff, 0xff, 0xc1, 0xef,
+ 0xff, 0xff, 0xdf, 0xef, 0xff, 0xff, 0x1f, 0xe0, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
diff --git a/vcl/unx/source/inc/drawcaption_mask.h b/vcl/unx/source/inc/drawcaption_mask.h
new file mode 100644
index 000000000000..70b39e37b65e
--- /dev/null
+++ b/vcl/unx/source/inc/drawcaption_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define drawcaption_mask_width 32
+#define drawcaption_mask_height 32
+static char drawcaption_mask_bits[] = {
+ 0x80, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00,
+ 0x80, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00,
+ 0x80, 0x03, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00,
+ 0xff, 0xff, 0x01, 0x00, 0x80, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00,
+ 0x80, 0x03, 0x00, 0x00, 0x80, 0x43, 0x00, 0x00, 0x80, 0xe3, 0xf0, 0x3f,
+ 0x80, 0xc3, 0xf1, 0x3f, 0x80, 0x83, 0xff, 0x3f, 0x00, 0x00, 0x7f, 0x38,
+ 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00, 0xf0, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/drawcirclecut_curs.h b/vcl/unx/source/inc/drawcirclecut_curs.h
new file mode 100644
index 000000000000..dc632873dd3b
--- /dev/null
+++ b/vcl/unx/source/inc/drawcirclecut_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 drawcirclecut_curs_width 32
+#define drawcirclecut_curs_height 32
+#define drawcirclecut_curs_x_hot 7
+#define drawcirclecut_curs_y_hot 7
+static char drawcirclecut_curs_bits[] = {
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbf, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x41, 0x00,
+ 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/drawcirclecut_mask.h b/vcl/unx/source/inc/drawcirclecut_mask.h
new file mode 100644
index 000000000000..1f96be33b86a
--- /dev/null
+++ b/vcl/unx/source/inc/drawcirclecut_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define drawcirclecut_mask_width 32
+#define drawcirclecut_mask_height 32
+static char drawcirclecut_mask_bits[] = {
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0x3f, 0x7e, 0x00, 0x00, 0xbf, 0x7e, 0x00, 0x00, 0x3f, 0x7e, 0x00, 0x00,
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x1f, 0x00,
+ 0x00, 0x80, 0x3b, 0x00, 0x00, 0x80, 0x73, 0x00, 0x00, 0x80, 0xe3, 0x00,
+ 0x00, 0x80, 0xc3, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x7e, 0x00,
+ 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/drawconnect_curs.h b/vcl/unx/source/inc/drawconnect_curs.h
new file mode 100644
index 000000000000..994f34b96e0e
--- /dev/null
+++ b/vcl/unx/source/inc/drawconnect_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 drawconnect_curs_width 32
+#define drawconnect_curs_height 32
+#define drawconnect_curs_x_hot 7
+#define drawconnect_curs_y_hot 7
+static char drawconnect_curs_bits[] = {
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbf, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x80, 0x5f, 0x00, 0x00, 0x80, 0x70,
+ 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0xfd, 0x00,
+ 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/drawconnect_mask.h b/vcl/unx/source/inc/drawconnect_mask.h
new file mode 100644
index 000000000000..187cf31cfd1a
--- /dev/null
+++ b/vcl/unx/source/inc/drawconnect_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define drawconnect_mask_width 32
+#define drawconnect_mask_height 32
+static char drawconnect_mask_bits[] = {
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0x3f, 0x7e, 0x00, 0x00, 0xbf, 0x7e, 0x00, 0x00, 0x3f, 0x7e, 0x00, 0x00,
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
+ 0x00, 0x00, 0xc0, 0xff, 0x00, 0x00, 0xc0, 0xdf, 0x00, 0x00, 0xc0, 0xff,
+ 0x00, 0x80, 0xcf, 0xf9, 0x00, 0x80, 0xff, 0x01, 0x00, 0x80, 0xfd, 0x01,
+ 0x00, 0x80, 0xff, 0x01, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/drawcrook_curs.h b/vcl/unx/source/inc/drawcrook_curs.h
new file mode 100644
index 000000000000..4fdba0e8442a
--- /dev/null
+++ b/vcl/unx/source/inc/drawcrook_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 drawcrook_curs_width 32
+#define drawcrook_curs_height 32
+#define drawcrook_curs_x_hot 15
+#define drawcrook_curs_y_hot 14
+static char drawcrook_curs_bits[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x7c, 0x3e, 0xff, 0x7f, 0xbb, 0xdd, 0xfe,
+ 0x7f, 0xbb, 0xdd, 0xfe, 0xf3, 0xb6, 0x6d, 0xcf, 0xed, 0xb6, 0x6d, 0xb7,
+ 0xdd, 0x75, 0xae, 0xbb, 0xbb, 0x0b, 0xd0, 0xdd, 0xb7, 0xf1, 0x8f, 0xed,
+ 0x4f, 0x0e, 0x70, 0xf2, 0xbf, 0xf1, 0x8f, 0xfd, 0x5f, 0xfe, 0x7f, 0xfa,
+ 0xaf, 0xff, 0xff, 0xf5, 0xd7, 0xff, 0xff, 0xeb, 0xef, 0xff, 0xff, 0xf7,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
diff --git a/vcl/unx/source/inc/drawcrook_mask.h b/vcl/unx/source/inc/drawcrook_mask.h
new file mode 100644
index 000000000000..657fcff2b4fd
--- /dev/null
+++ b/vcl/unx/source/inc/drawcrook_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define drawcrook_mask_width 32
+#define drawcrook_mask_height 32
+static char drawcrook_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x83, 0xc1, 0x00, 0x80, 0xc7, 0xe3, 0x01, 0xc0, 0xef, 0xf7, 0x03,
+ 0xcc, 0xef, 0xf7, 0x33, 0x9e, 0xff, 0xff, 0x79, 0xbf, 0xff, 0xff, 0xfd,
+ 0x77, 0xff, 0xff, 0xee, 0xee, 0xf6, 0x6f, 0x77, 0xfc, 0xff, 0xff, 0x3f,
+ 0xb8, 0xff, 0xff, 0x1d, 0xf0, 0xff, 0xff, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f,
+ 0xf8, 0x01, 0x80, 0x1f, 0x7c, 0x00, 0x00, 0x3e, 0x38, 0x00, 0x00, 0x1c,
+ 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/drawcrop_curs.h b/vcl/unx/source/inc/drawcrop_curs.h
new file mode 100644
index 000000000000..7f574e1ab351
--- /dev/null
+++ b/vcl/unx/source/inc/drawcrop_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 drawcrop_curs_width 32
+#define drawcrop_curs_height 32
+#define drawcrop_curs_x_hot 9
+#define drawcrop_curs_y_hot 9
+static char drawcrop_curs_bits[] = {
+ 0xff, 0x0f, 0xff, 0xff, 0xff, 0x6f, 0xff, 0xff, 0xff, 0x6f, 0xff, 0xff,
+ 0x07, 0x60, 0xf8, 0xff, 0xf7, 0x6f, 0xfb, 0xff, 0xf7, 0x6f, 0xfb, 0xff,
+ 0x37, 0x60, 0xf8, 0xff, 0xb7, 0x6f, 0xff, 0xff, 0xb7, 0x6f, 0xff, 0xff,
+ 0xb7, 0x6f, 0xff, 0xff, 0xb7, 0x6f, 0xff, 0xff, 0xb7, 0x6f, 0xff, 0xff,
+ 0x30, 0x60, 0xff, 0xff, 0xb6, 0x7f, 0xff, 0xff, 0xb6, 0x7f, 0xff, 0xff,
+ 0x30, 0x00, 0xff, 0xff, 0xb7, 0xff, 0xff, 0xff, 0xb7, 0xff, 0xff, 0xff,
+ 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
diff --git a/vcl/unx/source/inc/drawcrop_mask.h b/vcl/unx/source/inc/drawcrop_mask.h
new file mode 100644
index 000000000000..ac2e8885bdbb
--- /dev/null
+++ b/vcl/unx/source/inc/drawcrop_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define drawcrop_mask_width 32
+#define drawcrop_mask_height 32
+static char drawcrop_mask_bits[] = {
+ 0x00, 0xf8, 0x01, 0x00, 0x00, 0xf8, 0x01, 0x00, 0xfc, 0xff, 0x0f, 0x00,
+ 0xfc, 0xff, 0x0f, 0x00, 0xfc, 0xff, 0x0f, 0x00, 0xfc, 0xff, 0x0f, 0x00,
+ 0xfc, 0xff, 0x0f, 0x00, 0xfc, 0xff, 0x0f, 0x00, 0xfc, 0xf8, 0x01, 0x00,
+ 0xfc, 0xf8, 0x01, 0x00, 0xfc, 0xf8, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00,
+ 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00,
+ 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xfc, 0x00, 0x00, 0x00,
+ 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/drawellipse_curs.h b/vcl/unx/source/inc/drawellipse_curs.h
new file mode 100644
index 000000000000..bddc330d71d2
--- /dev/null
+++ b/vcl/unx/source/inc/drawellipse_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 drawellipse_curs_width 32
+#define drawellipse_curs_height 32
+#define drawellipse_curs_x_hot 7
+#define drawellipse_curs_y_hot 7
+static char drawellipse_curs_bits[] = {
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbf, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x42, 0x00,
+ 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x81, 0x00,
+ 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/drawellipse_mask.h b/vcl/unx/source/inc/drawellipse_mask.h
new file mode 100644
index 000000000000..0ac5f200eab1
--- /dev/null
+++ b/vcl/unx/source/inc/drawellipse_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define drawellipse_mask_width 32
+#define drawellipse_mask_height 32
+static char drawellipse_mask_bits[] = {
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0x3f, 0x7e, 0x00, 0x00, 0xbf, 0x7e, 0x00, 0x00, 0x3f, 0x7e, 0x00, 0x00,
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x80, 0xe7, 0x01, 0x00, 0x80, 0xc3, 0x01, 0x00, 0x80, 0xc3, 0x01,
+ 0x00, 0x80, 0xe7, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x7e, 0x00,
+ 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/drawfreehand_curs.h b/vcl/unx/source/inc/drawfreehand_curs.h
new file mode 100644
index 000000000000..75795c088c8e
--- /dev/null
+++ b/vcl/unx/source/inc/drawfreehand_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 drawfreehand_curs_width 32
+#define drawfreehand_curs_height 32
+#define drawfreehand_curs_x_hot 8
+#define drawfreehand_curs_y_hot 8
+static char drawfreehand_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xfd, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x70, 0x00, 0x02,
+ 0x00, 0x88, 0x00, 0x02, 0x00, 0x84, 0x00, 0x01, 0x00, 0x84, 0xc0, 0x00,
+ 0x00, 0x04, 0x3f, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/drawfreehand_mask.h b/vcl/unx/source/inc/drawfreehand_mask.h
new file mode 100644
index 000000000000..29edf44a9999
--- /dev/null
+++ b/vcl/unx/source/inc/drawfreehand_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define drawfreehand_mask_width 32
+#define drawfreehand_mask_height 32
+static char drawfreehand_mask_bits[] = {
+ 0x80, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00,
+ 0x80, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00,
+ 0x80, 0x03, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00,
+ 0xff, 0xff, 0x01, 0x00, 0x80, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00,
+ 0x80, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x08,
+ 0x80, 0x03, 0x00, 0x1c, 0x80, 0x73, 0x00, 0x0e, 0x00, 0xf8, 0x00, 0x07,
+ 0x00, 0xfc, 0x01, 0x07, 0x00, 0xce, 0xc1, 0x03, 0x00, 0xce, 0xff, 0x01,
+ 0x00, 0x8e, 0xff, 0x00, 0x00, 0x0e, 0x3f, 0x00, 0x00, 0x0e, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/drawline_curs.h b/vcl/unx/source/inc/drawline_curs.h
new file mode 100644
index 000000000000..2d2aa162fac6
--- /dev/null
+++ b/vcl/unx/source/inc/drawline_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 drawline_curs_width 32
+#define drawline_curs_height 32
+#define drawline_curs_x_hot 7
+#define drawline_curs_y_hot 7
+static char drawline_curs_bits[] = {
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbf, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x03,
+ 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x0c, 0x00,
+ 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/drawline_mask.h b/vcl/unx/source/inc/drawline_mask.h
new file mode 100644
index 000000000000..d66b0fd09aaa
--- /dev/null
+++ b/vcl/unx/source/inc/drawline_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define drawline_mask_width 32
+#define drawline_mask_height 32
+static char drawline_mask_bits[] = {
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0x3f, 0xfe, 0x00, 0x00, 0xbf, 0xfe, 0x00, 0x00, 0x3f, 0xfe, 0x00, 0x00,
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x70,
+ 0xc0, 0x01, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0xc0, 0x0f,
+ 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x3f, 0x00,
+ 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/drawmirror_curs.h b/vcl/unx/source/inc/drawmirror_curs.h
new file mode 100644
index 000000000000..3f61e751befb
--- /dev/null
+++ b/vcl/unx/source/inc/drawmirror_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 drawmirror_curs_width 32
+#define drawmirror_curs_height 32
+#define drawmirror_curs_x_hot 14
+#define drawmirror_curs_y_hot 12
+static char drawmirror_curs_bits[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xff, 0x03, 0xf8, 0xf5, 0xff,
+ 0xfb, 0xfb, 0xee, 0xff, 0x0b, 0xfa, 0xf5, 0xff, 0xeb, 0xfa, 0xfa, 0xff,
+ 0xeb, 0xfa, 0xfa, 0xff, 0xeb, 0x7a, 0xfd, 0xff, 0xeb, 0x7a, 0xfd, 0xff,
+ 0xeb, 0xba, 0x7e, 0xff, 0xeb, 0xba, 0xbe, 0xfe, 0xeb, 0x5a, 0x5f, 0xfd,
+ 0x0b, 0x5a, 0xaf, 0xfa, 0xfb, 0xab, 0xd7, 0xf5, 0x03, 0xa8, 0xeb, 0xeb,
+ 0xff, 0xd7, 0xf5, 0xf5, 0xff, 0xd7, 0xfa, 0xfa, 0xff, 0x6b, 0x7d, 0xfd,
+ 0xff, 0xeb, 0xba, 0xfe, 0xff, 0xf5, 0x55, 0xff, 0xff, 0xf5, 0xab, 0xff,
+ 0xff, 0xfa, 0xd7, 0xff, 0x7f, 0xf7, 0xef, 0xff, 0xff, 0xfa, 0xff, 0xff,
+ 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
diff --git a/vcl/unx/source/inc/drawmirror_mask.h b/vcl/unx/source/inc/drawmirror_mask.h
new file mode 100644
index 000000000000..5394dd74576a
--- /dev/null
+++ b/vcl/unx/source/inc/drawmirror_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define drawmirror_mask_width 32
+#define drawmirror_mask_height 32
+static char drawmirror_mask_bits[] = {
+ 0x00, 0x00, 0x04, 0x00, 0xfe, 0x0f, 0x0e, 0x00, 0xfe, 0x0f, 0x1f, 0x00,
+ 0xfe, 0x8f, 0x3f, 0x00, 0xfe, 0x0f, 0x1f, 0x00, 0xfe, 0x8f, 0x0f, 0x00,
+ 0xbe, 0x8f, 0x0f, 0x00, 0xbe, 0xcf, 0x07, 0x00, 0xbe, 0xcf, 0x87, 0x00,
+ 0xbe, 0xef, 0xc3, 0x01, 0xbe, 0xef, 0xe3, 0x03, 0xfe, 0xff, 0xf1, 0x07,
+ 0xfe, 0xff, 0x79, 0x0f, 0xfe, 0xff, 0x3c, 0x1e, 0xfe, 0xff, 0x1e, 0x3c,
+ 0xfe, 0x7f, 0x0f, 0x1e, 0x00, 0xfc, 0x07, 0x0f, 0x00, 0xfe, 0x83, 0x07,
+ 0x00, 0xbe, 0xc7, 0x03, 0x00, 0x1f, 0xef, 0x01, 0x00, 0x1f, 0xfe, 0x00,
+ 0x80, 0x0f, 0x7c, 0x00, 0xc0, 0x1d, 0x38, 0x00, 0x80, 0x0f, 0x10, 0x00,
+ 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/drawpie_curs.h b/vcl/unx/source/inc/drawpie_curs.h
new file mode 100644
index 000000000000..327b15258d3d
--- /dev/null
+++ b/vcl/unx/source/inc/drawpie_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 drawpie_curs_width 32
+#define drawpie_curs_height 32
+#define drawpie_curs_x_hot 7
+#define drawpie_curs_y_hot 7
+static char drawpie_curs_bits[] = {
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbf, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xf9, 0x00,
+ 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/drawpie_mask.h b/vcl/unx/source/inc/drawpie_mask.h
new file mode 100644
index 000000000000..6b5e5ac4ff0d
--- /dev/null
+++ b/vcl/unx/source/inc/drawpie_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define drawpie_mask_width 32
+#define drawpie_mask_height 32
+static char drawpie_mask_bits[] = {
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0x3f, 0x7e, 0x00, 0x00, 0xbf, 0x7e, 0x00, 0x00, 0x3f, 0x7e, 0x00, 0x00,
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00,
+ 0x00, 0x80, 0x1f, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0x80, 0xff, 0x01,
+ 0x00, 0x80, 0xfb, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x7e, 0x00,
+ 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/drawpolygon_curs.h b/vcl/unx/source/inc/drawpolygon_curs.h
new file mode 100644
index 000000000000..ee68c707444c
--- /dev/null
+++ b/vcl/unx/source/inc/drawpolygon_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 drawpolygon_curs_width 32
+#define drawpolygon_curs_height 32
+#define drawpolygon_curs_x_hot 7
+#define drawpolygon_curs_y_hot 7
+static char drawpolygon_curs_bits[] = {
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbf, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x83, 0x00,
+ 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0x99, 0x00,
+ 0x00, 0x00, 0x89, 0x03, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x01,
+ 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/drawpolygon_mask.h b/vcl/unx/source/inc/drawpolygon_mask.h
new file mode 100644
index 000000000000..8b82e237233c
--- /dev/null
+++ b/vcl/unx/source/inc/drawpolygon_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define drawpolygon_mask_width 32
+#define drawpolygon_mask_height 32
+static char drawpolygon_mask_bits[] = {
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0x3f, 0x7e, 0x00, 0x00, 0xbf, 0x7e, 0x00, 0x00, 0x3f, 0x7e, 0x00, 0x00,
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x1e, 0x06,
+ 0x00, 0x00, 0x1e, 0x07, 0x00, 0x00, 0xbe, 0x07, 0x00, 0x00, 0xfe, 0x07,
+ 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0x7e, 0x1f, 0x00, 0x00, 0x3e, 0x1f,
+ 0x00, 0x00, 0x0e, 0x0e, 0x00, 0x00, 0x0e, 0x07, 0x00, 0x00, 0x0e, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/drawrect_curs.h b/vcl/unx/source/inc/drawrect_curs.h
new file mode 100644
index 000000000000..c2508d37fad5
--- /dev/null
+++ b/vcl/unx/source/inc/drawrect_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 drawrect_curs_width 32
+#define drawrect_curs_height 32
+#define drawrect_curs_x_hot 7
+#define drawrect_curs_y_hot 7
+static char drawrect_curs_bits[] = {
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbf, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x81, 0x00,
+ 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x81, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/drawrect_mask.h b/vcl/unx/source/inc/drawrect_mask.h
new file mode 100644
index 000000000000..955152f312c9
--- /dev/null
+++ b/vcl/unx/source/inc/drawrect_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define drawrect_mask_width 32
+#define drawrect_mask_height 32
+static char drawrect_mask_bits[] = {
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0x3f, 0x7e, 0x00, 0x00, 0xbf, 0x7e, 0x00, 0x00, 0x3f, 0x7e, 0x00, 0x00,
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00,
+ 0x00, 0x80, 0xff, 0x01, 0x00, 0x80, 0xff, 0x01, 0x00, 0x80, 0xff, 0x01,
+ 0x00, 0x80, 0xc3, 0x01, 0x00, 0x80, 0xc3, 0x01, 0x00, 0x80, 0xff, 0x01,
+ 0x00, 0x80, 0xff, 0x01, 0x00, 0x80, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/drawtext_curs.h b/vcl/unx/source/inc/drawtext_curs.h
new file mode 100644
index 000000000000..c5049670b9ec
--- /dev/null
+++ b/vcl/unx/source/inc/drawtext_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 drawtext_curs_width 32
+#define drawtext_curs_height 32
+#define drawtext_curs_x_hot 8
+#define drawtext_curs_y_hot 8
+static char drawtext_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xfd, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x81, 0x0d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0x80, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/drawtext_mask.h b/vcl/unx/source/inc/drawtext_mask.h
new file mode 100644
index 000000000000..e27ce2514306
--- /dev/null
+++ b/vcl/unx/source/inc/drawtext_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define drawtext_mask_width 32
+#define drawtext_mask_height 32
+static char drawtext_mask_bits[] = {
+ 0x80, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00,
+ 0x80, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00,
+ 0x80, 0x03, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00,
+ 0xff, 0xff, 0x01, 0x00, 0x80, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00,
+ 0x80, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x80, 0xc3, 0x1f, 0x00,
+ 0x80, 0xc3, 0x1f, 0x00, 0x80, 0xc3, 0x1f, 0x00, 0x00, 0x00, 0x07, 0x00,
+ 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0xc0, 0x1f, 0x00,
+ 0x00, 0xc0, 0x1f, 0x00, 0x00, 0xc0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/fill_curs.h b/vcl/unx/source/inc/fill_curs.h
new file mode 100644
index 000000000000..792ea50e4f00
--- /dev/null
+++ b/vcl/unx/source/inc/fill_curs.h
@@ -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.
+ *
+ ************************************************************************/
+#define fill_curs_width 32
+#define fill_curs_height 32
+#define fill_curs_x_hot 10
+#define fill_curs_y_hot 22
+static char fill_curs_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x80,0x02,0x00,0x00,0x5c,0x0c,0x00,0x00,
+ 0x2e,0x12,0x00,0x00,0x17,0x38,0x00,0x00,0x0b,0x7c,0x00,0x00,0x5b,0xbe,0x00,
+ 0x00,0x27,0x9f,0x00,0x00,0xa7,0x4f,0x00,0x00,0xc7,0x27,0x00,0x00,0x87,0x13,
+ 0x00,0x00,0x06,0x09,0x00,0x00,0x06,0x06,0x00,0x00,0x04,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/fill_mask.h b/vcl/unx/source/inc/fill_mask.h
new file mode 100644
index 000000000000..67681f243f7b
--- /dev/null
+++ b/vcl/unx/source/inc/fill_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define fill_mask_width 32
+#define fill_mask_height 32
+#define fill_mask_x_hot 10
+#define fill_mask_y_hot 22
+static char fill_mask_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x80,0x03,0x00,0x00,0xdc,0x0f,0x00,0x00,
+ 0xfe,0x1f,0x00,0x00,0xff,0x3f,0x00,0x00,0xff,0x7f,0x00,0x00,0xff,0xff,0x00,
+ 0x00,0xe7,0xff,0x00,0x00,0xe7,0x7f,0x00,0x00,0xc7,0x3f,0x00,0x00,0x87,0x1f,
+ 0x00,0x00,0x06,0x0f,0x00,0x00,0x06,0x06,0x00,0x00,0x04,0x00,0x00,0x00,0x04,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/hshear_curs.h b/vcl/unx/source/inc/hshear_curs.h
new file mode 100644
index 000000000000..7f6092b648de
--- /dev/null
+++ b/vcl/unx/source/inc/hshear_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 hshear_curs_width 32
+#define hshear_curs_height 32
+#define hshear_curs_x_hot 15
+#define hshear_curs_y_hot 15
+static char hshear_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,
+ 0x00, 0x3c, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x0c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/hshear_mask.h b/vcl/unx/source/inc/hshear_mask.h
new file mode 100644
index 000000000000..6d09b3b0af01
--- /dev/null
+++ b/vcl/unx/source/inc/hshear_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define hshear_mask_width 32
+#define hshear_mask_height 32
+static char hshear_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00,
+ 0x80, 0xff, 0xff, 0x01, 0x80, 0xff, 0xff, 0x01, 0x80, 0xff, 0xff, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x01,
+ 0x80, 0xff, 0xff, 0x01, 0x80, 0xff, 0xff, 0x01, 0x00, 0x00, 0x3e, 0x00,
+ 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/invert50.h b/vcl/unx/source/inc/invert50.h
new file mode 100644
index 000000000000..7c0d00ce8fa4
--- /dev/null
+++ b/vcl/unx/source/inc/invert50.h
@@ -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.
+ *
+ ************************************************************************/
+#define invert50_width 32
+#define invert50_height 32
+static char invert50_bits[] = {
+#if 1
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+#else
+ 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
+ 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
+ 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
+ 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
+ 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
+ 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
+ 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
+ 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
+ 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
+ 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
+ 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
+ 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
+ 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
+ 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
+ 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
+ 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
+#endif
+};
diff --git a/vcl/unx/source/inc/linkdata_curs.h b/vcl/unx/source/inc/linkdata_curs.h
new file mode 100644
index 000000000000..c60edc3b99d0
--- /dev/null
+++ b/vcl/unx/source/inc/linkdata_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 linkdata_curs_width 32
+#define linkdata_curs_height 32
+#define linkdata_curs_x_hot 1
+#define linkdata_curs_y_hot 1
+static char linkdata_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00,
+ 0xfe, 0x03, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00,
+ 0x66, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x10, 0x53, 0x00, 0x00,
+ 0x28, 0xa3, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x10, 0xf0, 0x1f, 0x00, 0x08, 0x70, 0x18, 0x00, 0x10, 0xf0, 0x18, 0x00,
+ 0xa8, 0x72, 0x18, 0x00, 0x50, 0x35, 0x1a, 0x00, 0x00, 0x30, 0x1f, 0x00,
+ 0x00, 0xb0, 0x1f, 0x00, 0x00, 0x70, 0x1f, 0x00, 0x00, 0xf0, 0x1f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/linkdata_mask.h b/vcl/unx/source/inc/linkdata_mask.h
new file mode 100644
index 000000000000..cf0f89f63b1b
--- /dev/null
+++ b/vcl/unx/source/inc/linkdata_mask.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 linkdata_mask_width 32
+#define linkdata_mask_height 32
+#define linkdata_mask_x_hot 1
+#define linkdata_mask_y_hot 1
+static char linkdata_mask_bits[] = {
+ 0x07, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
+ 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00,
+ 0xff, 0x07, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0xe7, 0x03, 0x00, 0x00,
+ 0xe0, 0x03, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00,
+ 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0x3c, 0xf8, 0x3f, 0x00,
+ 0x3c, 0xf8, 0x3f, 0x00, 0x3c, 0xf8, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00,
+ 0xfc, 0xff, 0x3f, 0x00, 0xfc, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0x3f, 0x00,
+ 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x3f, 0x00,
+ 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/linkfile_curs.h b/vcl/unx/source/inc/linkfile_curs.h
new file mode 100644
index 000000000000..fb676ae2a04b
--- /dev/null
+++ b/vcl/unx/source/inc/linkfile_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 linkfile_curs_width 32
+#define linkfile_curs_height 32
+#define linkfile_curs_x_hot 9
+#define linkfile_curs_y_hot 9
+static char linkfile_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x02, 0x00, 0x00,
+ 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00,
+ 0xfe, 0x07, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0xfe, 0x04, 0x00, 0x00,
+ 0xfe, 0x02, 0x00, 0x00, 0xfe, 0x06, 0x00, 0x00, 0xfe, 0x0e, 0x00, 0x00,
+ 0xfe, 0x1e, 0x00, 0x00, 0xfe, 0x3e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
+ 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x03, 0x00,
+ 0x00, 0x7e, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00,
+ 0x00, 0xc2, 0xe0, 0x3f, 0x00, 0xc0, 0xe0, 0x30, 0x00, 0x80, 0xe1, 0x31,
+ 0x00, 0x80, 0xe1, 0x30, 0x00, 0x00, 0x63, 0x34, 0x00, 0x00, 0x63, 0x3e,
+ 0x00, 0x00, 0x60, 0x3f, 0x00, 0x00, 0xe0, 0x3e, 0x00, 0x00, 0xe0, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/linkfile_mask.h b/vcl/unx/source/inc/linkfile_mask.h
new file mode 100644
index 000000000000..28ff46c4fae4
--- /dev/null
+++ b/vcl/unx/source/inc/linkfile_mask.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 linkfile_mask_width 32
+#define linkfile_mask_height 32
+#define linkfile_mask_x_hot 9
+#define linkfile_mask_y_hot 9
+static char linkfile_mask_bits[] = {
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00,
+ 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00,
+ 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00,
+ 0xff, 0x0f, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00,
+ 0xff, 0x7f, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00,
+ 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x07, 0x00,
+ 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xf1, 0x7f,
+ 0x00, 0xff, 0xf1, 0x7f, 0x00, 0xe7, 0xf3, 0x7f, 0x00, 0xe0, 0xf3, 0x7f,
+ 0x00, 0xc0, 0xf7, 0x7f, 0x00, 0xc0, 0xf7, 0x7f, 0x00, 0x80, 0xf7, 0x7f,
+ 0x00, 0x80, 0xf7, 0x7f, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0xf0, 0x7f,
+ 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/magnify_curs.h b/vcl/unx/source/inc/magnify_curs.h
new file mode 100644
index 000000000000..76114ca410d5
--- /dev/null
+++ b/vcl/unx/source/inc/magnify_curs.h
@@ -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.
+ *
+ ************************************************************************/
+#define magnify_curs_width 32
+#define magnify_curs_height 32
+#define magnify_curs_x_hot 12
+#define magnify_curs_y_hot 13
+static char magnify_curs_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0x00,0x00,0x00,0x83,
+ 0x01,0x00,0x80,0x00,0x02,0x00,0x40,0x00,0x04,0x00,0x40,0x00,0x04,0x00,0x20,
+ 0x00,0x08,0x00,0x20,0x00,0x08,0x00,0x20,0x00,0x08,0x00,0x20,0x00,0x08,0x00,
+ 0x20,0x00,0x08,0x00,0x40,0x00,0x04,0x00,0x40,0x00,0x04,0x00,0x80,0x00,0x06,
+ 0x00,0x00,0x83,0x0f,0x00,0x00,0x7c,0x1c,0x00,0x00,0x00,0x38,0x00,0x00,0x00,
+ 0x70,0x00,0x00,0x00,0xe0,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/magnify_mask.h b/vcl/unx/source/inc/magnify_mask.h
new file mode 100644
index 000000000000..db4213943b6e
--- /dev/null
+++ b/vcl/unx/source/inc/magnify_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define magnify_mask_width 32
+#define magnify_mask_height 32
+static char magnify_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00,
+ 0x00, 0xff, 0x01, 0x00, 0x80, 0xff, 0x03, 0x00, 0xc0, 0x83, 0x07, 0x00,
+ 0xe0, 0x00, 0x0e, 0x00, 0xe0, 0x00, 0x0e, 0x00, 0x70, 0x00, 0x1c, 0x00,
+ 0x70, 0x00, 0x1c, 0x00, 0x70, 0x00, 0x1c, 0x00, 0x70, 0x00, 0x1c, 0x00,
+ 0x70, 0x00, 0x1c, 0x00, 0xe0, 0x00, 0x0e, 0x00, 0xe0, 0x00, 0x0e, 0x00,
+ 0xc0, 0x83, 0x0f, 0x00, 0x80, 0xff, 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00,
+ 0x00, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xf0, 0x01,
+ 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/mirror_curs.h b/vcl/unx/source/inc/mirror_curs.h
new file mode 100644
index 000000000000..0f0f1b360224
--- /dev/null
+++ b/vcl/unx/source/inc/mirror_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 mirror_curs_width 32
+#define mirror_curs_height 32
+#define mirror_curs_x_hot 14
+#define mirror_curs_y_hot 12
+static char mirror_curs_bits[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xff, 0x03, 0xf8, 0xf5, 0xff,
+ 0xfb, 0xfb, 0xee, 0xff, 0x0b, 0xfa, 0xf5, 0xff, 0xeb, 0xfa, 0xfa, 0xff,
+ 0xeb, 0xfa, 0xfa, 0xff, 0xeb, 0x7a, 0xfd, 0xff, 0xeb, 0x7a, 0xfd, 0xff,
+ 0xeb, 0xba, 0x7e, 0xff, 0xeb, 0xba, 0xbe, 0xfe, 0xeb, 0x5a, 0x5f, 0xfd,
+ 0x0b, 0x5a, 0xaf, 0xfa, 0xfb, 0xab, 0xd7, 0xf5, 0x03, 0xa8, 0xeb, 0xeb,
+ 0xff, 0xd7, 0xf5, 0xf5, 0xff, 0xd7, 0xfa, 0xfa, 0xff, 0x6b, 0x7d, 0xfd,
+ 0xff, 0xeb, 0xba, 0xfe, 0xff, 0xf5, 0x55, 0xff, 0xff, 0xf5, 0xab, 0xff,
+ 0xff, 0xfa, 0xd7, 0xff, 0x7f, 0xf7, 0xef, 0xff, 0xff, 0xfa, 0xff, 0xff,
+ 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
diff --git a/vcl/unx/source/inc/mirror_mask.h b/vcl/unx/source/inc/mirror_mask.h
new file mode 100644
index 000000000000..da9c00435162
--- /dev/null
+++ b/vcl/unx/source/inc/mirror_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define mirror_mask_width 32
+#define mirror_mask_height 32
+static char mirror_mask_bits[] = {
+ 0x00, 0x00, 0x04, 0x00, 0xfe, 0x0f, 0x0e, 0x00, 0xfe, 0x0f, 0x1f, 0x00,
+ 0xfe, 0x8f, 0x3f, 0x00, 0xfe, 0x0f, 0x1f, 0x00, 0xfe, 0x8f, 0x0f, 0x00,
+ 0xbe, 0x8f, 0x0f, 0x00, 0xbe, 0xcf, 0x07, 0x00, 0xbe, 0xcf, 0x87, 0x00,
+ 0xbe, 0xef, 0xc3, 0x01, 0xbe, 0xef, 0xe3, 0x03, 0xfe, 0xff, 0xf1, 0x07,
+ 0xfe, 0xff, 0x79, 0x0f, 0xfe, 0xff, 0x3c, 0x1e, 0xfe, 0xff, 0x1e, 0x3c,
+ 0xfe, 0x7f, 0x0f, 0x1e, 0x00, 0xfc, 0x07, 0x0f, 0x00, 0xfe, 0x83, 0x07,
+ 0x00, 0xbe, 0xc7, 0x03, 0x00, 0x1f, 0xef, 0x01, 0x00, 0x1f, 0xfe, 0x00,
+ 0x80, 0x0f, 0x7c, 0x00, 0xc0, 0x1d, 0x38, 0x00, 0x80, 0x0f, 0x10, 0x00,
+ 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/movebezierweight_curs.h b/vcl/unx/source/inc/movebezierweight_curs.h
new file mode 100644
index 000000000000..a1ece2d925e9
--- /dev/null
+++ b/vcl/unx/source/inc/movebezierweight_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 movebezierweight_curs_width 32
+#define movebezierweight_curs_height 32
+#define movebezierweight_curs_x_hot 0
+#define movebezierweight_curs_y_hot 0
+static char movebezierweight_curs_bits[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff,
+ 0xf1, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xff, 0xff, 0xc1, 0xff, 0xff, 0xff,
+ 0x81, 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xfe, 0xff, 0xff,
+ 0x01, 0xfc, 0xff, 0xff, 0x81, 0xff, 0xff, 0xff, 0x91, 0xff, 0xff, 0xff,
+ 0x99, 0xff, 0xff, 0xef, 0x3d, 0xff, 0xff, 0xef, 0x3f, 0xff, 0xff, 0xef,
+ 0x7f, 0xfe, 0xff, 0xf7, 0x7f, 0xfe, 0xff, 0xf7, 0xff, 0xfc, 0xff, 0xfb,
+ 0xff, 0x7c, 0xff, 0xec, 0xff, 0xbf, 0x0e, 0xd7, 0xff, 0x7f, 0xf3, 0xef,
+ 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff,
+ 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
diff --git a/vcl/unx/source/inc/movebezierweight_mask.h b/vcl/unx/source/inc/movebezierweight_mask.h
new file mode 100644
index 000000000000..27e0d8c703db
--- /dev/null
+++ b/vcl/unx/source/inc/movebezierweight_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define movebezierweight_mask_width 32
+#define movebezierweight_mask_height 32
+static char movebezierweight_mask_bits[] = {
+ 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
+ 0x1f, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00,
+ 0xff, 0x07, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x00, 0x00, 0x10,
+ 0xff, 0x00, 0x00, 0x38, 0xe7, 0x01, 0x00, 0x38, 0xe3, 0x01, 0x00, 0x38,
+ 0xc0, 0x03, 0x00, 0x1c, 0xc0, 0x03, 0x00, 0x1c, 0x80, 0x87, 0x00, 0x1f,
+ 0x80, 0xc7, 0xf1, 0x3f, 0x80, 0xe7, 0xff, 0x7f, 0x00, 0xc0, 0xff, 0x38,
+ 0x00, 0x80, 0x0f, 0x10, 0x00, 0x80, 0x03, 0x00, 0x00, 0x80, 0x03, 0x00,
+ 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00,
+ 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/movedata_curs.h b/vcl/unx/source/inc/movedata_curs.h
new file mode 100644
index 000000000000..b79412bc3f41
--- /dev/null
+++ b/vcl/unx/source/inc/movedata_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 movedata_curs_width 32
+#define movedata_curs_height 32
+#define movedata_curs_x_hot 1
+#define movedata_curs_y_hot 1
+static char movedata_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00,
+ 0xfe, 0x03, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00,
+ 0x66, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x10, 0x53, 0x00, 0x00,
+ 0x28, 0xa3, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00,
+ 0x10, 0x40, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00,
+ 0xa8, 0xaa, 0x00, 0x00, 0x50, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/movedata_mask.h b/vcl/unx/source/inc/movedata_mask.h
new file mode 100644
index 000000000000..e25d0837d8dc
--- /dev/null
+++ b/vcl/unx/source/inc/movedata_mask.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 movedata_mask_width 32
+#define movedata_mask_height 32
+#define movedata_mask_x_hot 1
+#define movedata_mask_y_hot 1
+static char movedata_mask_bits[] = {
+ 0x07, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
+ 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00,
+ 0xff, 0x07, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0xe7, 0x03, 0x00, 0x00,
+ 0xe0, 0x03, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00,
+ 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0x3c, 0xe0, 0x01, 0x00,
+ 0x3c, 0xe0, 0x01, 0x00, 0x3c, 0xe0, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00,
+ 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/movedlnk_curs.h b/vcl/unx/source/inc/movedlnk_curs.h
new file mode 100644
index 000000000000..56608b8153a6
--- /dev/null
+++ b/vcl/unx/source/inc/movedlnk_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 movedlnk_curs_width 32
+#define movedlnk_curs_height 32
+#define movedlnk_curs_x_hot 1
+#define movedlnk_curs_y_hot 1
+static char movedlnk_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00,
+ 0x7e, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00,
+ 0xfe, 0x03, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00,
+ 0x66, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
+ 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x10, 0x53, 0x00, 0x00,
+ 0x28, 0xa3, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0xf0, 0x81, 0x00, 0x00,
+ 0x30, 0x41, 0x00, 0x00, 0x10, 0x81, 0x00, 0x00, 0xd0, 0x41, 0x00, 0x00,
+ 0xf0, 0xa9, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/movedlnk_mask.h b/vcl/unx/source/inc/movedlnk_mask.h
new file mode 100644
index 000000000000..2aa3eb4b277d
--- /dev/null
+++ b/vcl/unx/source/inc/movedlnk_mask.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 movedlnk_mask_width 32
+#define movedlnk_mask_height 32
+#define movedlnk_mask_x_hot 1
+#define movedlnk_mask_y_hot 1
+static char movedlnk_mask_bits[] = {
+ 0x07, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
+ 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00,
+ 0xff, 0x07, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0xe7, 0x03, 0x00, 0x00,
+ 0xe0, 0x03, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00,
+ 0xfc, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x01, 0x00, 0xf8, 0xe3, 0x01, 0x00,
+ 0xf8, 0xe3, 0x01, 0x00, 0xf8, 0xe3, 0x01, 0x00, 0xf8, 0xff, 0x01, 0x00,
+ 0xf8, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x01, 0x00, 0x00, 0xfe, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/movefile_curs.h b/vcl/unx/source/inc/movefile_curs.h
new file mode 100644
index 000000000000..ed3a11e7f49d
--- /dev/null
+++ b/vcl/unx/source/inc/movefile_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 movefile_curs_width 32
+#define movefile_curs_height 32
+#define movefile_curs_x_hot 9
+#define movefile_curs_y_hot 9
+static char movefile_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x02, 0x00, 0x00,
+ 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00,
+ 0xfe, 0x07, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0xfe, 0x04, 0x00, 0x00,
+ 0xfe, 0x02, 0x00, 0x00, 0xfe, 0x06, 0x00, 0x00, 0xfe, 0x0e, 0x00, 0x00,
+ 0xfe, 0x1e, 0x00, 0x00, 0xfe, 0x3e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
+ 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x03, 0x00,
+ 0x00, 0x7e, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00,
+ 0x00, 0xc2, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/movefile_mask.h b/vcl/unx/source/inc/movefile_mask.h
new file mode 100644
index 000000000000..668d8d7e8015
--- /dev/null
+++ b/vcl/unx/source/inc/movefile_mask.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 movefile_mask_width 32
+#define movefile_mask_height 32
+#define movefile_mask_x_hot 9
+#define movefile_mask_y_hot 9
+static char movefile_mask_bits[] = {
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00,
+ 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00,
+ 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00,
+ 0xff, 0x0f, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00,
+ 0xff, 0x7f, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00,
+ 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x07, 0x00,
+ 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x01, 0x00,
+ 0x00, 0xff, 0x01, 0x00, 0x00, 0xe7, 0x03, 0x00, 0x00, 0xe0, 0x03, 0x00,
+ 0x00, 0xc0, 0x07, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x80, 0x07, 0x00,
+ 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/movefiles_curs.h b/vcl/unx/source/inc/movefiles_curs.h
new file mode 100644
index 000000000000..148fe2e72a5e
--- /dev/null
+++ b/vcl/unx/source/inc/movefiles_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 movefiles_curs_width 32
+#define movefiles_curs_height 32
+#define movefiles_curs_x_hot 8
+#define movefiles_curs_y_hot 9
+static char movefiles_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xe0, 0x2f, 0x00, 0x00,
+ 0xe8, 0x0f, 0x00, 0x00, 0xe8, 0x7f, 0x00, 0x00, 0xea, 0x7f, 0x00, 0x00,
+ 0xea, 0x7f, 0x00, 0x00, 0xea, 0x7f, 0x00, 0x00, 0x6a, 0x7e, 0x00, 0x00,
+ 0x6a, 0x7d, 0x00, 0x00, 0x6a, 0x7b, 0x00, 0x00, 0x6a, 0x77, 0x00, 0x00,
+ 0x6a, 0x6f, 0x00, 0x00, 0x6a, 0x5f, 0x00, 0x00, 0x0a, 0x3f, 0x00, 0x00,
+ 0x7a, 0x7f, 0x00, 0x00, 0x02, 0xff, 0x00, 0x00, 0x7e, 0xff, 0x01, 0x00,
+ 0x00, 0x3f, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00,
+ 0x00, 0x61, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/movefiles_mask.h b/vcl/unx/source/inc/movefiles_mask.h
new file mode 100644
index 000000000000..dc990dc5cb61
--- /dev/null
+++ b/vcl/unx/source/inc/movefiles_mask.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 movefiles_mask_width 32
+#define movefiles_mask_height 32
+#define movefiles_mask_x_hot 8
+#define movefiles_mask_y_hot 9
+static char movefiles_mask_bits[] = {
+ 0xf0, 0x1f, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00,
+ 0xfc, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00,
+ 0xff, 0xff, 0x03, 0x00, 0x80, 0x7f, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00,
+ 0x80, 0xff, 0x00, 0x00, 0x80, 0xf3, 0x01, 0x00, 0x00, 0xf0, 0x01, 0x00,
+ 0x00, 0xe0, 0x03, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00,
+ 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/moveflnk_curs.h b/vcl/unx/source/inc/moveflnk_curs.h
new file mode 100644
index 000000000000..7f48bc4506fc
--- /dev/null
+++ b/vcl/unx/source/inc/moveflnk_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 moveflnk_curs_width 32
+#define moveflnk_curs_height 32
+#define moveflnk_curs_x_hot 9
+#define moveflnk_curs_y_hot 9
+static char moveflnk_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x02, 0x00, 0x00,
+ 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00,
+ 0xfe, 0x07, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00,
+ 0xbe, 0x02, 0x00, 0x00, 0xa6, 0x06, 0x00, 0x00, 0xa2, 0x0e, 0x00, 0x00,
+ 0xba, 0x1e, 0x00, 0x00, 0xbe, 0x3e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
+ 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x03, 0x00,
+ 0x00, 0x7e, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00,
+ 0x00, 0xc2, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/moveflnk_mask.h b/vcl/unx/source/inc/moveflnk_mask.h
new file mode 100644
index 000000000000..a25b7ee18960
--- /dev/null
+++ b/vcl/unx/source/inc/moveflnk_mask.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 moveflnk_mask_width 32
+#define moveflnk_mask_height 32
+#define moveflnk_mask_x_hot 9
+#define moveflnk_mask_y_hot 9
+static char moveflnk_mask_bits[] = {
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00,
+ 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00,
+ 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00,
+ 0xff, 0x0f, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00,
+ 0xff, 0x7f, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00,
+ 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x07, 0x00,
+ 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x01, 0x00,
+ 0x00, 0xff, 0x01, 0x00, 0x00, 0xe7, 0x03, 0x00, 0x00, 0xe0, 0x03, 0x00,
+ 0x00, 0xc0, 0x07, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x80, 0x07, 0x00,
+ 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/movepoint_curs.h b/vcl/unx/source/inc/movepoint_curs.h
new file mode 100644
index 000000000000..e3b20bd8edf9
--- /dev/null
+++ b/vcl/unx/source/inc/movepoint_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 movepoint_curs_width 32
+#define movepoint_curs_height 32
+#define movepoint_curs_x_hot 0
+#define movepoint_curs_y_hot 0
+static char movepoint_curs_bits[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff,
+ 0xf1, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xff, 0xff, 0xc1, 0xff, 0xff, 0xff,
+ 0x81, 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x01, 0xfe, 0xff, 0xff,
+ 0x01, 0xfc, 0xff, 0xff, 0x81, 0xff, 0xff, 0xff, 0x91, 0xff, 0xff, 0xff,
+ 0x39, 0xff, 0xff, 0xff, 0x3d, 0xff, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff,
+ 0x7f, 0xfe, 0xff, 0xff, 0xff, 0xfc, 0x83, 0xff, 0xff, 0xfc, 0x83, 0xff,
+ 0xff, 0xff, 0x83, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xff, 0x83, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
diff --git a/vcl/unx/source/inc/movepoint_mask.h b/vcl/unx/source/inc/movepoint_mask.h
new file mode 100644
index 000000000000..e4fae36c023c
--- /dev/null
+++ b/vcl/unx/source/inc/movepoint_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define movepoint_mask_width 32
+#define movepoint_mask_height 32
+static char movepoint_mask_bits[] = {
+ 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
+ 0x1f, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00,
+ 0xff, 0x07, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xef, 0x01, 0x00, 0x00, 0xe7, 0x01, 0x00, 0x00, 0xc3, 0x03, 0x00, 0x00,
+ 0xc0, 0x03, 0xfe, 0x00, 0x80, 0x07, 0xfe, 0x00, 0x80, 0x07, 0xfe, 0x00,
+ 0x80, 0x07, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x00,
+ 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/nodrop_curs.h b/vcl/unx/source/inc/nodrop_curs.h
new file mode 100644
index 000000000000..8e208e32f293
--- /dev/null
+++ b/vcl/unx/source/inc/nodrop_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 nodrop_curs_width 32
+#define nodrop_curs_height 32
+#define nodrop_curs_x_hot 9
+#define nodrop_curs_y_hot 9
+static char nodrop_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00,
+ 0xf8, 0x7f, 0x00, 0x00, 0x7c, 0xf8, 0x00, 0x00, 0x1c, 0xfc, 0x00, 0x00,
+ 0x1e, 0xfe, 0x01, 0x00, 0x0e, 0xdf, 0x01, 0x00, 0x8e, 0xcf, 0x01, 0x00,
+ 0xce, 0xc7, 0x01, 0x00, 0xee, 0xc3, 0x01, 0x00, 0xfe, 0xe1, 0x01, 0x00,
+ 0xfc, 0xe0, 0x00, 0x00, 0x7c, 0xf8, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00,
+ 0xf0, 0x3f, 0x00, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/nodrop_mask.h b/vcl/unx/source/inc/nodrop_mask.h
new file mode 100644
index 000000000000..7cbecef2c60f
--- /dev/null
+++ b/vcl/unx/source/inc/nodrop_mask.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 nodrop_mask_width 32
+#define nodrop_mask_height 32
+#define nodrop_mask_x_hot 9
+#define nodrop_mask_y_hot 9
+static char nodrop_mask_bits[] = {
+ 0xc0, 0x0f, 0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00,
+ 0xfc, 0xff, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0x7e, 0xfe, 0x01, 0x00,
+ 0x3f, 0xff, 0x03, 0x00, 0x9f, 0xff, 0x03, 0x00, 0xdf, 0xff, 0x03, 0x00,
+ 0xff, 0xef, 0x03, 0x00, 0xff, 0xe7, 0x03, 0x00, 0xff, 0xf3, 0x03, 0x00,
+ 0xfe, 0xf9, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfc, 0xff, 0x00, 0x00,
+ 0xf8, 0x7f, 0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00, 0xc0, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/null_curs.h b/vcl/unx/source/inc/null_curs.h
new file mode 100644
index 000000000000..19d4130d4b5d
--- /dev/null
+++ b/vcl/unx/source/inc/null_curs.h
@@ -0,0 +1,31 @@
+/*************************************************************************
+ *
+ * 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 nullcurs_width 4
+#define nullcurs_height 4
+#define nullcurs_x_hot 2
+#define nullcurs_y_hot 2
+static char nullcurs_bits[] = { 0x00, 0x00 };
diff --git a/vcl/unx/source/inc/null_mask.h b/vcl/unx/source/inc/null_mask.h
new file mode 100644
index 000000000000..a657cfa54af4
--- /dev/null
+++ b/vcl/unx/source/inc/null_mask.h
@@ -0,0 +1,29 @@
+/*************************************************************************
+ *
+ * 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 nullmask_width 4
+#define nullmask_height 4
+static char nullmask_bits[] = { 0x00, 0x00 };
diff --git a/vcl/unx/source/inc/paintbrush_curs.h b/vcl/unx/source/inc/paintbrush_curs.h
new file mode 100644
index 000000000000..5dfd18a539a6
--- /dev/null
+++ b/vcl/unx/source/inc/paintbrush_curs.h
@@ -0,0 +1,8 @@
+#define paintbrush_curs_width 16
+#define paintbrush_curs_height 16
+#define paintbrush_curs_x_hot 0
+#define paintbrush_curs_y_hot 10
+static char paintbrush_curs_bits[] = {
+ 0x00, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0x90, 0x80, 0xcb, 0x60, 0x64,
+ 0x90, 0x34, 0x08, 0x19, 0x06, 0x22, 0x11, 0x24, 0x09, 0x18, 0x46, 0x14,
+ 0x24, 0x0a, 0x18, 0x05, 0x90, 0x02, 0xe0, 0x01 };
diff --git a/vcl/unx/source/inc/paintbrush_mask.h b/vcl/unx/source/inc/paintbrush_mask.h
new file mode 100644
index 000000000000..a5b5617b820f
--- /dev/null
+++ b/vcl/unx/source/inc/paintbrush_mask.h
@@ -0,0 +1,7 @@
+#define paintbrush_mask_width 16
+#define paintbrush_mask_height 16
+static char paintbrush_mask_bits[] = {
+ 0x00, 0x80, 0x00, 0xc0, 0x00, 0xe0, 0x00, 0xf0, 0x80, 0xfb, 0xe0, 0x7f,
+ 0xf0, 0x3f, 0xf8, 0x1f, 0xfe, 0x3f, 0xff, 0x3f, 0xff, 0x1f, 0xfe, 0x1f,
+ 0xfc, 0x0f, 0xf8, 0x07, 0xf0, 0x03, 0xe0, 0x01 };
+
diff --git a/vcl/unx/source/inc/pivotcol_curs.h b/vcl/unx/source/inc/pivotcol_curs.h
new file mode 100644
index 000000000000..22873985daf0
--- /dev/null
+++ b/vcl/unx/source/inc/pivotcol_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 pivotcol_curs_width 32
+#define pivotcol_curs_height 32
+#define pivotcol_curs_x_hot 7
+#define pivotcol_curs_y_hot 5
+static char pivotcol_curs_bits[] = {
+ 0xff, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x55, 0x01, 0x00, 0x00,
+ 0x29, 0x01, 0x00, 0x00, 0x15, 0x01, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00,
+ 0x95, 0x01, 0x00, 0x00, 0xa9, 0x02, 0x00, 0x00, 0x95, 0x04, 0x00, 0x00,
+ 0xa9, 0x08, 0x00, 0x00, 0x95, 0x10, 0x00, 0x00, 0xa9, 0x20, 0x00, 0x00,
+ 0x95, 0x40, 0x00, 0x00, 0xa9, 0x80, 0x00, 0x00, 0x95, 0x00, 0x01, 0x00,
+ 0xa9, 0xe0, 0x03, 0x00, 0x95, 0x2c, 0x00, 0x00, 0xbd, 0x4a, 0x00, 0x00,
+ 0xbf, 0x51, 0x00, 0x00, 0x80, 0x90, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00,
+ 0x00, 0x20, 0x01, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0xc0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
diff --git a/vcl/unx/source/inc/pivotcol_mask.h b/vcl/unx/source/inc/pivotcol_mask.h
new file mode 100644
index 000000000000..911eede87ed4
--- /dev/null
+++ b/vcl/unx/source/inc/pivotcol_mask.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 pivotcol_mask_width 32
+#define pivotcol_mask_height 32
+#define pivotcol_mask_x_hot 7
+#define pivotcol_mask_y_hot 5
+static char pivotcol_mask_bits[] = {
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00,
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00,
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00,
+ 0xff, 0x0f, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00,
+ 0xff, 0x7f, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00,
+ 0xff, 0xff, 0x03, 0x00, 0xff, 0x3f, 0x00, 0x00, 0xff, 0x7b, 0x00, 0x00,
+ 0xff, 0x71, 0x00, 0x00, 0x80, 0xf0, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00,
+ 0x00, 0xe0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
diff --git a/vcl/unx/source/inc/pivotdel_curs.h b/vcl/unx/source/inc/pivotdel_curs.h
new file mode 100644
index 000000000000..e0dcbc14a6d6
--- /dev/null
+++ b/vcl/unx/source/inc/pivotdel_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 pivotdel_curs_width 32
+#define pivotdel_curs_height 32
+#define pivotdel_curs_x_hot 9
+#define pivotdel_curs_y_hot 8
+static char pivotdel_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x80, 0x01, 0x00,
+ 0x3c, 0xc0, 0x00, 0x00, 0x73, 0x6f, 0x07, 0x00, 0xe1, 0x30, 0x04, 0x00,
+ 0xc1, 0x1d, 0x04, 0x00, 0x81, 0x0f, 0x04, 0x00, 0x01, 0x07, 0x04, 0x00,
+ 0x81, 0x0f, 0x04, 0x00, 0xc1, 0x1d, 0x04, 0x00, 0xe1, 0x38, 0x04, 0x00,
+ 0x77, 0xaf, 0x07, 0x00, 0x78, 0x40, 0x00, 0x00, 0x3c, 0x80, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
diff --git a/vcl/unx/source/inc/pivotdel_mask.h b/vcl/unx/source/inc/pivotdel_mask.h
new file mode 100644
index 000000000000..147bc2da410d
--- /dev/null
+++ b/vcl/unx/source/inc/pivotdel_mask.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 pivotdel_mask_width 32
+#define pivotdel_mask_height 32
+#define pivotdel_mask_x_hot 9
+#define pivotdel_mask_y_hot 8
+static char pivotdel_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x80, 0x01, 0x00,
+ 0x3c, 0xc0, 0x00, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00,
+ 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00,
+ 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00,
+ 0xff, 0xff, 0x07, 0x00, 0x78, 0x40, 0x00, 0x00, 0x3c, 0x80, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
diff --git a/vcl/unx/source/inc/pivotfld_curs.h b/vcl/unx/source/inc/pivotfld_curs.h
new file mode 100644
index 000000000000..1daf4f553275
--- /dev/null
+++ b/vcl/unx/source/inc/pivotfld_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 pivotfld_curs_width 32
+#define pivotfld_curs_height 32
+#define pivotfld_curs_x_hot 8
+#define pivotfld_curs_y_hot 7
+static char pivotfld_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x07, 0x00,
+ 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00,
+ 0x01, 0x00, 0x04, 0x00, 0x01, 0x01, 0x04, 0x00, 0x01, 0x03, 0x04, 0x00,
+ 0x01, 0x05, 0x04, 0x00, 0x7f, 0xc9, 0x07, 0x00, 0x00, 0x11, 0x00, 0x00,
+ 0x00, 0x21, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00,
+ 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0xc1, 0x07, 0x00,
+ 0x00, 0x59, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00,
+ 0x00, 0x21, 0x01, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x40, 0x02, 0x00,
+ 0x00, 0x80, 0x02, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
diff --git a/vcl/unx/source/inc/pivotfld_mask.h b/vcl/unx/source/inc/pivotfld_mask.h
new file mode 100644
index 000000000000..6d62d8bbda46
--- /dev/null
+++ b/vcl/unx/source/inc/pivotfld_mask.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 pivotfld_mask_width 32
+#define pivotfld_mask_height 32
+#define pivotfld_mask_x_hot 8
+#define pivotfld_mask_y_hot 7
+static char pivotfld_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x07, 0x00,
+ 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00,
+ 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00,
+ 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0x00, 0x1f, 0x00, 0x00,
+ 0x00, 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0xff, 0x01, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x07, 0x00,
+ 0x00, 0x7f, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00, 0xe3, 0x00, 0x00,
+ 0x00, 0xe1, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00,
+ 0x00, 0x80, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
diff --git a/vcl/unx/source/inc/pivotrow_curs.h b/vcl/unx/source/inc/pivotrow_curs.h
new file mode 100644
index 000000000000..75f4965f2582
--- /dev/null
+++ b/vcl/unx/source/inc/pivotrow_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 pivotrow_curs_width 32
+#define pivotrow_curs_height 32
+#define pivotrow_curs_x_hot 8
+#define pivotrow_curs_y_hot 7
+static char pivotrow_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x07, 0x00,
+ 0x01, 0x00, 0x04, 0x00, 0x55, 0x55, 0x07, 0x00, 0xa9, 0xaa, 0x06, 0x00,
+ 0x55, 0x54, 0x07, 0x00, 0x29, 0xa9, 0x06, 0x00, 0x55, 0x53, 0x07, 0x00,
+ 0x29, 0xa5, 0x06, 0x00, 0x7f, 0xc9, 0x07, 0x00, 0x00, 0x11, 0x00, 0x00,
+ 0x00, 0x21, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00,
+ 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0xc1, 0x07, 0x00,
+ 0x00, 0x59, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00,
+ 0x00, 0x21, 0x01, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x40, 0x02, 0x00,
+ 0x00, 0x80, 0x02, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
diff --git a/vcl/unx/source/inc/pivotrow_mask.h b/vcl/unx/source/inc/pivotrow_mask.h
new file mode 100644
index 000000000000..a8896d0975f9
--- /dev/null
+++ b/vcl/unx/source/inc/pivotrow_mask.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 pivotrow_mask_width 32
+#define pivotrow_mask_height 32
+#define pivotrow_curs_x_hot 8
+#define pivotrow_curs_y_hot 7
+static char pivotrow_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x07, 0x00,
+ 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00,
+ 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00,
+ 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x07, 0x00, 0x00, 0x1f, 0x00, 0x00,
+ 0x00, 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0xff, 0x01, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x07, 0x00,
+ 0x00, 0x7f, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00, 0xe3, 0x00, 0x00,
+ 0x00, 0xe1, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00,
+ 0x00, 0x80, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
diff --git a/vcl/unx/source/inc/rotate_curs.h b/vcl/unx/source/inc/rotate_curs.h
new file mode 100644
index 000000000000..f9c57674dfb2
--- /dev/null
+++ b/vcl/unx/source/inc/rotate_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 rotate_curs_width 32
+#define rotate_curs_height 32
+#define rotate_curs_x_hot 15
+#define rotate_curs_y_hot 15
+static char rotate_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xd8, 0x00, 0x00,
+ 0x00, 0x44, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x00,
+ 0x80, 0x00, 0xc0, 0x01, 0x80, 0x00, 0xe0, 0x03, 0x80, 0x00, 0x80, 0x00,
+ 0x00, 0x01, 0x40, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x02, 0x20, 0x00,
+ 0x00, 0x04, 0x10, 0x00, 0x00, 0x18, 0x0c, 0x00, 0x00, 0xe0, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/rotate_mask.h b/vcl/unx/source/inc/rotate_mask.h
new file mode 100644
index 000000000000..9fcff18925f0
--- /dev/null
+++ b/vcl/unx/source/inc/rotate_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define rotate_mask_width 32
+#define rotate_mask_height 32
+static char rotate_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00,
+ 0x00, 0xe0, 0x01, 0x00, 0x00, 0xf8, 0x03, 0x00, 0x00, 0xfc, 0x01, 0x00,
+ 0x00, 0xfe, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00,
+ 0x80, 0x03, 0x00, 0x00, 0xc0, 0x01, 0x80, 0x00, 0xc0, 0x01, 0xc0, 0x01,
+ 0xc0, 0x01, 0xe0, 0x03, 0xc0, 0x01, 0xf0, 0x07, 0xc0, 0x01, 0xf0, 0x07,
+ 0x80, 0x03, 0xe0, 0x00, 0x80, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x70, 0x00,
+ 0x00, 0x1e, 0x3c, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0xf8, 0x0f, 0x00,
+ 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/salcursors.h b/vcl/unx/source/inc/salcursors.h
new file mode 100644
index 000000000000..e8a63d6195aa
--- /dev/null
+++ b/vcl/unx/source/inc/salcursors.h
@@ -0,0 +1,162 @@
+/*************************************************************************
+ *
+ * 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 "nodrop_curs.h"
+#include "nodrop_mask.h"
+#include "magnify_curs.h"
+#include "magnify_mask.h"
+#include "rotate_curs.h"
+#include "rotate_mask.h"
+#include "hshear_curs.h"
+#include "hshear_mask.h"
+#include "vshear_curs.h"
+#include "vshear_mask.h"
+#include "drawline_curs.h"
+#include "drawline_mask.h"
+#include "drawrect_curs.h"
+#include "drawrect_mask.h"
+#include "drawpolygon_curs.h"
+#include "drawpolygon_mask.h"
+#include "drawbezier_curs.h"
+#include "drawbezier_mask.h"
+#include "drawarc_curs.h"
+#include "drawarc_mask.h"
+#include "drawpie_curs.h"
+#include "drawpie_mask.h"
+#include "drawcirclecut_curs.h"
+#include "drawcirclecut_mask.h"
+#include "drawellipse_curs.h"
+#include "drawellipse_mask.h"
+#include "drawconnect_curs.h"
+#include "drawconnect_mask.h"
+#include "drawtext_curs.h"
+#include "drawtext_mask.h"
+#include "mirror_curs.h"
+#include "mirror_mask.h"
+#include "crook_curs.h"
+#include "crook_mask.h"
+#include "crop_curs.h"
+#include "crop_mask.h"
+#include "movepoint_curs.h"
+#include "movepoint_mask.h"
+#include "movebezierweight_curs.h"
+#include "movebezierweight_mask.h"
+#include "drawfreehand_curs.h"
+#include "drawfreehand_mask.h"
+#include "drawcaption_curs.h"
+#include "drawcaption_mask.h"
+#include "movedata_curs.h"
+#include "movedata_mask.h"
+#include "copydata_curs.h"
+#include "copydata_mask.h"
+#include "linkdata_curs.h"
+#include "linkdata_mask.h"
+#include "movedlnk_curs.h"
+#include "movedlnk_mask.h"
+#include "copydlnk_curs.h"
+#include "copydlnk_mask.h"
+#include "movefile_curs.h"
+#include "movefile_mask.h"
+#include "copyfile_curs.h"
+#include "copyfile_mask.h"
+#include "linkfile_curs.h"
+#include "linkfile_mask.h"
+#include "moveflnk_curs.h"
+#include "moveflnk_mask.h"
+#include "copyflnk_curs.h"
+#include "copyflnk_mask.h"
+#include "movefiles_curs.h"
+#include "movefiles_mask.h"
+#include "copyfiles_curs.h"
+#include "copyfiles_mask.h"
+
+#include "chart_curs.h"
+#include "chart_mask.h"
+#include "detective_curs.h"
+#include "detective_mask.h"
+#include "pivotcol_curs.h"
+#include "pivotcol_mask.h"
+#include "pivotfld_curs.h"
+#include "pivotfld_mask.h"
+#include "pivotrow_curs.h"
+#include "pivotrow_mask.h"
+#include "pivotdel_curs.h"
+#include "pivotdel_mask.h"
+
+#include "chain_curs.h"
+#include "chain_mask.h"
+#include "chainnot_curs.h"
+#include "chainnot_mask.h"
+
+#include "timemove_curs.h"
+#include "timemove_mask.h"
+#include "timesize_curs.h"
+#include "timesize_mask.h"
+
+#include "ase_curs.h"
+#include "ase_mask.h"
+#include "asn_curs.h"
+#include "asn_mask.h"
+#include "asne_curs.h"
+#include "asne_mask.h"
+#include "asns_curs.h"
+#include "asns_mask.h"
+#include "asnswe_curs.h"
+#include "asnswe_mask.h"
+#include "asnw_curs.h"
+#include "asnw_mask.h"
+#include "ass_curs.h"
+#include "ass_mask.h"
+#include "asse_curs.h"
+#include "asse_mask.h"
+#include "assw_curs.h"
+#include "assw_mask.h"
+#include "asw_curs.h"
+#include "asw_mask.h"
+#include "aswe_curs.h"
+#include "aswe_mask.h"
+#include "null_curs.h"
+#include "null_mask.h"
+
+#include "airbrush_curs.h"
+#include "airbrush_mask.h"
+#include "fill_curs.h"
+#include "fill_mask.h"
+#include "vertcurs_curs.h"
+#include "vertcurs_mask.h"
+#include "tblsele_curs.h"
+#include "tblsele_mask.h"
+#include "tblsels_curs.h"
+#include "tblsels_mask.h"
+#include "tblselse_curs.h"
+#include "tblselse_mask.h"
+#include "tblselw_curs.h"
+#include "tblselw_mask.h"
+#include "tblselsw_curs.h"
+#include "tblselsw_mask.h"
+#include "paintbrush_curs.h"
+#include "paintbrush_mask.h"
diff --git a/vcl/unx/source/inc/tblsele_curs.h b/vcl/unx/source/inc/tblsele_curs.h
new file mode 100644
index 000000000000..7ad1314d1957
--- /dev/null
+++ b/vcl/unx/source/inc/tblsele_curs.h
@@ -0,0 +1,8 @@
+#define tblsele_curs_width 16
+#define tblsele_curs_height 16
+#define tblsele_curs_x_hot 14
+#define tblsele_curs_y_hot 8
+static char tblsele_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0c,
+ 0x00, 0x1c, 0xfc, 0x3f, 0xfc, 0x7f, 0xfc, 0x3f, 0x00, 0x1c, 0x00, 0x0c,
+ 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
diff --git a/vcl/unx/source/inc/tblsele_mask.h b/vcl/unx/source/inc/tblsele_mask.h
new file mode 100644
index 000000000000..bb35c22c97cb
--- /dev/null
+++ b/vcl/unx/source/inc/tblsele_mask.h
@@ -0,0 +1,7 @@
+#define tblsele_mask_width 16
+#define tblsele_mask_height 16
+static char tblsele_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x1e,
+ 0xfe, 0x3f, 0xfe, 0x7f, 0xfe, 0xff, 0xfe, 0x7f, 0xfe, 0x3f, 0x00, 0x1e,
+ 0x00, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00 };
+
diff --git a/vcl/unx/source/inc/tblsels_curs.h b/vcl/unx/source/inc/tblsels_curs.h
new file mode 100644
index 000000000000..0bf38d4b3fdb
--- /dev/null
+++ b/vcl/unx/source/inc/tblsels_curs.h
@@ -0,0 +1,9 @@
+#define tblsels_curs_width 16
+#define tblsels_curs_height 16
+#define tblsels_curs_x_hot 7
+#define tblsels_curs_y_hot 14
+static char tblsels_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01,
+ 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xf8, 0x0f, 0xf0, 0x07,
+ 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00 };
+
diff --git a/vcl/unx/source/inc/tblsels_mask.h b/vcl/unx/source/inc/tblsels_mask.h
new file mode 100644
index 000000000000..9ba3b51d8d76
--- /dev/null
+++ b/vcl/unx/source/inc/tblsels_mask.h
@@ -0,0 +1,7 @@
+#define tblsels_mask_width 16
+#define tblsels_mask_height 16
+static char tblsels_mask_bits[] = {
+ 0x00, 0x00, 0xe0, 0x03, 0xe0, 0x03, 0xe0, 0x03, 0xe0, 0x03, 0xe0, 0x03,
+ 0xe0, 0x03, 0xe0, 0x03, 0xe0, 0x03, 0xfc, 0x1f, 0xfc, 0x1f, 0xf8, 0x0f,
+ 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00 };
+
diff --git a/vcl/unx/source/inc/tblselse_curs.h b/vcl/unx/source/inc/tblselse_curs.h
new file mode 100644
index 000000000000..208c7c59dc2d
--- /dev/null
+++ b/vcl/unx/source/inc/tblselse_curs.h
@@ -0,0 +1,8 @@
+#define tblselse_curs_width 16
+#define tblselse_curs_height 16
+#define tblselse_curs_x_hot 14
+#define tblselse_curs_y_hot 14
+static char tblselse_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0xf0, 0x00,
+ 0xf0, 0x01, 0xe0, 0x03, 0xc0, 0x47, 0x80, 0x6f, 0x00, 0x7f, 0x00, 0x7e,
+ 0x00, 0x7c, 0x00, 0x7e, 0x00, 0x7f, 0x00, 0x00 };
diff --git a/vcl/unx/source/inc/tblselse_mask.h b/vcl/unx/source/inc/tblselse_mask.h
new file mode 100644
index 000000000000..4c4c97ad4ccf
--- /dev/null
+++ b/vcl/unx/source/inc/tblselse_mask.h
@@ -0,0 +1,7 @@
+#define tblselse_mask_width 16
+#define tblselse_mask_height 16
+static char tblselse_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0xf0, 0x00, 0xf8, 0x01,
+ 0xf8, 0x03, 0xf0, 0xc7, 0xe0, 0xef, 0xc0, 0xff, 0x80, 0xff, 0x00, 0xff,
+ 0x00, 0xfe, 0x00, 0xff, 0x80, 0xff, 0x80, 0xff };
+
diff --git a/vcl/unx/source/inc/tblselsw_curs.h b/vcl/unx/source/inc/tblselsw_curs.h
new file mode 100644
index 000000000000..a3166a27ca52
--- /dev/null
+++ b/vcl/unx/source/inc/tblselsw_curs.h
@@ -0,0 +1,8 @@
+#define tblselsw_curs_width 16
+#define tblselsw_curs_height 16
+#define tblselsw_curs_x_hot 1
+#define tblselsw_curs_y_hot 14
+static char tblselsw_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0f,
+ 0x80, 0x0f, 0xc0, 0x07, 0xe2, 0x03, 0xf6, 0x01, 0xfe, 0x00, 0x7e, 0x00,
+ 0x3e, 0x00, 0x7e, 0x00, 0xfe, 0x00, 0x00, 0x00 };
diff --git a/vcl/unx/source/inc/tblselsw_mask.h b/vcl/unx/source/inc/tblselsw_mask.h
new file mode 100644
index 000000000000..3981cbaa884d
--- /dev/null
+++ b/vcl/unx/source/inc/tblselsw_mask.h
@@ -0,0 +1,7 @@
+#define tblselsw_mask_width 16
+#define tblselsw_mask_height 16
+static char tblselsw_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0f, 0x80, 0x1f,
+ 0xc0, 0x1f, 0xe3, 0x0f, 0xf7, 0x07, 0xff, 0x03, 0xff, 0x01, 0xff, 0x00,
+ 0x7f, 0x00, 0xff, 0x00, 0xff, 0x01, 0xff, 0x01 };
+
diff --git a/vcl/unx/source/inc/tblselw_curs.h b/vcl/unx/source/inc/tblselw_curs.h
new file mode 100644
index 000000000000..9d802d094ef8
--- /dev/null
+++ b/vcl/unx/source/inc/tblselw_curs.h
@@ -0,0 +1,8 @@
+#define tblselw_curs_width 16
+#define tblselw_curs_height 16
+#define tblselw_curs_x_hot 1
+#define tblselw_curs_y_hot 8
+static char tblselw_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x30, 0x00,
+ 0x38, 0x00, 0xfc, 0x3f, 0xfe, 0x3f, 0xfc, 0x3f, 0x38, 0x00, 0x30, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
diff --git a/vcl/unx/source/inc/tblselw_mask.h b/vcl/unx/source/inc/tblselw_mask.h
new file mode 100644
index 000000000000..940668e3db7f
--- /dev/null
+++ b/vcl/unx/source/inc/tblselw_mask.h
@@ -0,0 +1,6 @@
+#define tblselw_mask_width 16
+#define tblselw_mask_height 16
+static char tblselw_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x70, 0x00, 0x78, 0x00,
+ 0xfc, 0x7f, 0xfe, 0x7f, 0xff, 0x7f, 0xfe, 0x7f, 0xfc, 0x7f, 0x78, 0x00,
+ 0x70, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00 };
diff --git a/vcl/unx/source/inc/timemove_curs.h b/vcl/unx/source/inc/timemove_curs.h
new file mode 100644
index 000000000000..252a702caf77
--- /dev/null
+++ b/vcl/unx/source/inc/timemove_curs.h
@@ -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.
+ *
+ ************************************************************************/
+#define timemove_curs_width 32
+#define timemove_curs_height 32
+#define timemove_curs_x_hot 16
+#define timemove_curs_y_hot 16
+static char timemove_curs_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x80,0x03,0x00,0x00,0xc0,0x07,0x00,0x00,
+ 0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0xff,0xff,0x01,
+ 0x00,0x01,0x01,0x01,0x00,0x01,0x01,0x01,0x00,0x01,0x01,0x01,0x00,0xff,0xff,
+ 0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0xc0,
+ 0x07,0x00,0x00,0x80,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/timemove_mask.h b/vcl/unx/source/inc/timemove_mask.h
new file mode 100644
index 000000000000..b7a9542a64c6
--- /dev/null
+++ b/vcl/unx/source/inc/timemove_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define timemove_mask_width 32
+#define timemove_mask_height 32
+#define timemove_mask_x_hot 16
+#define timemove_mask_y_hot 16
+static char timemove_mask_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x00,0x00,0x80,0x03,0x00,0x00,0xc0,0x07,0x00,0x00,0xe0,0x0f,0x00,0x00,
+ 0xc0,0x07,0x00,0x00,0x80,0x03,0x00,0x80,0xff,0xff,0x03,0x80,0xff,0xff,0x03,
+ 0x80,0xff,0xff,0x03,0x80,0xff,0xff,0x03,0x80,0xff,0xff,0x03,0x80,0xff,0xff,
+ 0x03,0x80,0xff,0xff,0x03,0x00,0x80,0x03,0x00,0x00,0xc0,0x07,0x00,0x00,0xe0,
+ 0x0f,0x00,0x00,0xc0,0x07,0x00,0x00,0x80,0x03,0x00,0x00,0x00,0x01,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/timesize_curs.h b/vcl/unx/source/inc/timesize_curs.h
new file mode 100644
index 000000000000..61e53971290e
--- /dev/null
+++ b/vcl/unx/source/inc/timesize_curs.h
@@ -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.
+ *
+ ************************************************************************/
+#define timesize_curs_width 32
+#define timesize_curs_height 32
+#define timesize_curs_x_hot 16
+#define timesize_curs_y_hot 16
+static char timesize_curs_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0xff,0xff,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,
+ 0x01,0x01,0x01,0x00,0x81,0x03,0x01,0x00,0xc1,0x07,0x01,0x00,0x01,0x01,0x01,
+ 0x00,0x01,0x01,0x01,0x00,0x01,0x01,0x01,0x00,0xff,0xff,0x01,0x00,0x00,0x01,
+ 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0xc0,0x07,0x00,0x00,0x80,
+ 0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/timesize_mask.h b/vcl/unx/source/inc/timesize_mask.h
new file mode 100644
index 000000000000..3c4333c5e7b8
--- /dev/null
+++ b/vcl/unx/source/inc/timesize_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define timesize_mask_width 32
+#define timesize_mask_height 32
+#define timesize_mask_x_hot 16
+#define timesize_mask_y_hot 16
+static char timesize_mask_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,
+ 0xff,0x03,0x80,0xff,0xff,0x03,0x80,0xff,0xff,0x03,0x80,0xff,0xff,0x03,0x80,
+ 0xff,0xff,0x03,0x80,0xff,0xff,0x03,0x80,0xff,0xff,0x03,0x80,0xff,0xff,0x03,
+ 0x80,0xff,0xff,0x03,0x80,0xff,0xff,0x03,0x80,0xff,0xff,0x03,0x80,0xff,0xff,
+ 0x03,0x00,0x80,0x03,0x00,0x00,0xc0,0x07,0x00,0x00,0xe0,0x0f,0x00,0x00,0xc0,
+ 0x07,0x00,0x00,0x80,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
diff --git a/vcl/unx/source/inc/vertcurs_curs.h b/vcl/unx/source/inc/vertcurs_curs.h
new file mode 100644
index 000000000000..d67251a1743d
--- /dev/null
+++ b/vcl/unx/source/inc/vertcurs_curs.h
@@ -0,0 +1,8 @@
+#define vertcurs_curs_width 16
+#define vertcurs_curs_height 16
+#define vertcurs_curs_x_hot 8
+#define vertcurs_curs_y_hot 8
+static char vertcurs_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x02, 0x40,
+ 0x06, 0x60, 0xfc, 0x3f, 0x06, 0x60, 0x02, 0x40, 0x02, 0x40, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/vertcurs_mask.h b/vcl/unx/source/inc/vertcurs_mask.h
new file mode 100644
index 000000000000..769d6966571f
--- /dev/null
+++ b/vcl/unx/source/inc/vertcurs_mask.h
@@ -0,0 +1,8 @@
+#define vertcurs_mask_width 16
+#define vertcurs_mask_height 16
+#define vertcurs_mask_x_hot 8
+#define vertcurs_mask_y_hot 8
+static char vertcurs_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xe0, 0x07, 0xe0, 0x0f, 0xf0,
+ 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0x0f, 0xf0, 0x07, 0xe0, 0x07, 0xe0,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/vshear_curs.h b/vcl/unx/source/inc/vshear_curs.h
new file mode 100644
index 000000000000..87357c0a5027
--- /dev/null
+++ b/vcl/unx/source/inc/vshear_curs.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * 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 vshear_curs_width 32
+#define vshear_curs_height 32
+#define vshear_curs_x_hot 15
+#define vshear_curs_y_hot 15
+static char vshear_curs_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x04, 0x00,
+ 0x00, 0x20, 0x04, 0x00, 0x00, 0x30, 0x04, 0x00, 0x00, 0x30, 0x04, 0x00,
+ 0x00, 0x38, 0x04, 0x00, 0x00, 0x38, 0x04, 0x00, 0x00, 0x20, 0x04, 0x00,
+ 0x00, 0x20, 0x04, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0x20, 0x04, 0x00,
+ 0x00, 0x20, 0x1c, 0x00, 0x00, 0x20, 0x1c, 0x00, 0x00, 0x20, 0x0c, 0x00,
+ 0x00, 0x20, 0x0c, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0x20, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/inc/vshear_mask.h b/vcl/unx/source/inc/vshear_mask.h
new file mode 100644
index 000000000000..be77728c13f9
--- /dev/null
+++ b/vcl/unx/source/inc/vshear_mask.h
@@ -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.
+ *
+ ************************************************************************/
+#define vshear_mask_width 32
+#define vshear_mask_height 32
+static char vshear_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x0e, 0x00, 0x00, 0x70, 0x0e, 0x00,
+ 0x00, 0x70, 0x0e, 0x00, 0x00, 0x78, 0x0e, 0x00, 0x00, 0x78, 0x0e, 0x00,
+ 0x00, 0x7c, 0x0e, 0x00, 0x00, 0x7c, 0x0e, 0x00, 0x00, 0x7c, 0x0e, 0x00,
+ 0x00, 0x70, 0x0e, 0x00, 0x00, 0x70, 0x0e, 0x00, 0x00, 0x70, 0x3e, 0x00,
+ 0x00, 0x70, 0x3e, 0x00, 0x00, 0x70, 0x3e, 0x00, 0x00, 0x70, 0x1e, 0x00,
+ 0x00, 0x70, 0x1e, 0x00, 0x00, 0x70, 0x0e, 0x00, 0x00, 0x70, 0x0e, 0x00,
+ 0x00, 0x70, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/vcl/unx/source/plugadapt/makefile.mk b/vcl/unx/source/plugadapt/makefile.mk
new file mode 100644
index 000000000000..af409c04af35
--- /dev/null
+++ b/vcl/unx/source/plugadapt/makefile.mk
@@ -0,0 +1,59 @@
+#*************************************************************************
+#
+# 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=salplug
+
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)"!="unx"
+
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+
+.ELSE # "$(GUIBASE)"!="unx"
+
+CFLAGS+=-DSAL_DLLPOSTFIX=\"$(DLLPOSTFIX)\"
+
+SLOFILES=$(SLO)$/salplug.obj
+
+.ENDIF # "$(GUIBASE)"!="unx"
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
+.INCLUDE : $(PRJ)$/util$/target.pmk
diff --git a/vcl/unx/source/plugadapt/salplug.cxx b/vcl/unx/source/plugadapt/salplug.cxx
new file mode 100644
index 000000000000..a438760cffba
--- /dev/null
+++ b/vcl/unx/source/plugadapt/salplug.cxx
@@ -0,0 +1,300 @@
+/*************************************************************************
+ *
+ * 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/module.h"
+#include "osl/process.h"
+
+#include "rtl/ustrbuf.hxx"
+
+
+#include "vcl/salinst.hxx"
+#include "saldata.hxx"
+
+#include <cstdio>
+#include <unistd.h>
+
+using namespace rtl;
+
+extern "C" {
+typedef SalInstance*(*salFactoryProc)( oslModule pModule);
+}
+
+static oslModule pCloseModule = NULL;
+
+enum {
+ DESKTOP_NONE = 0,
+ DESKTOP_UNKNOWN,
+ DESKTOP_GNOME,
+ DESKTOP_KDE,
+ DESKTOP_KDE4,
+ DESKTOP_CDE
+};
+
+static const char * desktop_strings[] = { "none", "unknown", "GNOME", "KDE", "KDE4", "CDE" };
+
+static SalInstance* tryInstance( const OUString& rModuleBase )
+{
+ SalInstance* pInst = NULL;
+
+ OUStringBuffer aModName( 128 );
+ aModName.appendAscii( SAL_DLLPREFIX"vclplug_" );
+ aModName.append( rModuleBase );
+ aModName.appendAscii( SAL_DLLPOSTFIX );
+ aModName.appendAscii( SAL_DLLEXTENSION );
+ OUString aModule = aModName.makeStringAndClear();
+
+ oslModule aMod = osl_loadModuleRelative(
+ reinterpret_cast< oslGenericFunction >( &tryInstance ), aModule.pData,
+ SAL_LOADMODULE_DEFAULT );
+ if( aMod )
+ {
+ salFactoryProc aProc = (salFactoryProc)osl_getAsciiFunctionSymbol( aMod, "create_SalInstance" );
+ if( aProc )
+ {
+ pInst = aProc( aMod );
+#if OSL_DEBUG_LEVEL > 1
+ std::fprintf( stderr, "sal plugin %s produced instance %p\n",
+ OUStringToOString( aModule, RTL_TEXTENCODING_ASCII_US ).getStr(),
+ pInst );
+#endif
+ if( pInst )
+ {
+ pCloseModule = aMod;
+
+ /*
+ * Recent GTK+ versions load their modules with RTLD_LOCAL, so we can
+ * not access the 'gnome_accessibility_module_shutdown' anymore.
+ * So make sure libgtk+ & co are still mapped into memory when
+ * atk-bridge's atexit handler gets called.
+ */
+ if( rModuleBase.equalsAscii("gtk") )
+ {
+ pCloseModule = NULL;
+ }
+ /*
+ * #i109007# KDE3 seems to have the same problem; an atexit cleanup
+ * handler, which cannot be resolved anymore if the plugin is already unloaded.
+ */
+ else if( rModuleBase.equalsAscii("kde") )
+ {
+ pCloseModule = NULL;
+ }
+
+ GetSalData()->m_pPlugin = aMod;
+ }
+ else
+ osl_unloadModule( aMod );
+ }
+ else
+ {
+#if OSL_DEBUG_LEVEL > 1
+ std::fprintf( stderr, "could not load symbol %s from shared object %s\n",
+ "create_SalInstance",
+ OUStringToOString( aModule, RTL_TEXTENCODING_ASCII_US ).getStr() );
+#endif
+ osl_unloadModule( aMod );
+ }
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ std::fprintf( stderr, "could not load shared object %s\n",
+ OUStringToOString( aModule, RTL_TEXTENCODING_ASCII_US ).getStr() );
+#endif
+
+ return pInst;
+}
+
+static const rtl::OUString& get_desktop_environment()
+{
+ static rtl::OUString aRet;
+ if( ! aRet.getLength() )
+ {
+ OUStringBuffer aModName( 128 );
+ aModName.appendAscii( SAL_DLLPREFIX"desktop_detector" );
+ aModName.appendAscii( SAL_DLLPOSTFIX );
+ aModName.appendAscii( SAL_DLLEXTENSION );
+ OUString aModule = aModName.makeStringAndClear();
+
+ oslModule aMod = osl_loadModuleRelative(
+ reinterpret_cast< oslGenericFunction >( &tryInstance ), aModule.pData,
+ SAL_LOADMODULE_DEFAULT );
+ if( aMod )
+ {
+ rtl::OUString (*pSym)() = (rtl::OUString(*)())
+ osl_getAsciiFunctionSymbol( aMod, "get_desktop_environment" );
+ if( pSym )
+ aRet = pSym();
+ }
+ osl_unloadModule( aMod );
+ }
+ return aRet;
+}
+
+static SalInstance* autodetect_plugin()
+{
+ static const char* pKDEFallbackList[] =
+ {
+ "kde4", "kde", "gtk", "gen", 0
+ };
+
+ static const char* pStandardFallbackList[] =
+ {
+ "gtk", "gen", 0
+ };
+
+ static const char* pHeadlessFallbackList[] =
+ {
+ "svp", 0
+ };
+
+ const rtl::OUString& desktop( get_desktop_environment() );
+ const char ** pList = pStandardFallbackList;
+ int nListEntry = 0;
+
+ // no server at all: dummy plugin
+ if ( desktop.equalsAscii( desktop_strings[DESKTOP_NONE] ) )
+ pList = pHeadlessFallbackList;
+ else if ( desktop.equalsAscii( desktop_strings[DESKTOP_GNOME] ) )
+ pList = pStandardFallbackList;
+ else if( desktop.equalsAscii( desktop_strings[DESKTOP_KDE] ) )
+ {
+ pList = pKDEFallbackList;
+ nListEntry = 1;
+ }
+ else if( desktop.equalsAscii( desktop_strings[DESKTOP_KDE4] ) )
+ pList = pKDEFallbackList;
+
+ SalInstance* pInst = NULL;
+ while( pList[nListEntry] && pInst == NULL )
+ {
+ rtl::OUString aTry( rtl::OUString::createFromAscii( pList[nListEntry] ) );
+ pInst = tryInstance( aTry );
+ #if OSL_DEBUG_LEVEL > 1
+ if( pInst )
+ std::fprintf( stderr, "plugin autodetection: %s\n", pList[nListEntry] );
+ #endif
+ nListEntry++;
+ }
+
+ return pInst;
+}
+
+static SalInstance* check_headless_plugin()
+{
+ int nParams = osl_getCommandArgCount();
+ OUString aParam;
+ for( int i = 0; i < nParams; i++ )
+ {
+ osl_getCommandArg( i, &aParam.pData );
+ if( aParam.equalsAscii( "-headless" ) )
+ return tryInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "svp" ) ) );
+ }
+ return NULL;
+}
+
+SalInstance *CreateSalInstance()
+{
+ SalInstance* pInst = NULL;
+
+ static const char* pUsePlugin = getenv( "SAL_USE_VCLPLUGIN" );
+
+ if( !(pUsePlugin && *pUsePlugin) )
+ pInst = check_headless_plugin();
+ else
+ pInst = tryInstance( OUString::createFromAscii( pUsePlugin ) );
+
+ if( ! pInst )
+ pInst = autodetect_plugin();
+
+ // fallback to gen
+ if( ! pInst )
+ pInst = tryInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "gen" ) ) );
+
+ if( ! pInst )
+ {
+ std::fprintf( stderr, "no suitable windowing system found, exiting.\n" );
+ _exit( 1 );
+ }
+
+ // acquire SolarMutex
+ pInst->AcquireYieldMutex( 1 );
+
+ return pInst;
+}
+
+void DestroySalInstance( SalInstance *pInst )
+{
+ // release SolarMutex
+ pInst->ReleaseYieldMutex();
+
+ delete pInst;
+ if( pCloseModule )
+ osl_unloadModule( pCloseModule );
+}
+
+void InitSalData()
+{
+}
+
+void DeInitSalData()
+{
+}
+
+void InitSalMain()
+{
+}
+
+void DeInitSalMain()
+{
+}
+
+void SalAbort( const XubString& rErrorText )
+{
+ if( !rErrorText.Len() )
+ std::fprintf( stderr, "Application Error" );
+ else
+ std::fprintf( stderr, ByteString( rErrorText, gsl_getSystemTextEncoding() ).GetBuffer() );
+ abort();
+}
+
+const OUString& SalGetDesktopEnvironment()
+{
+ return get_desktop_environment();
+}
+
+SalData::SalData() :
+ m_pInstance(NULL),
+ m_pPlugin(NULL)
+{
+}
+
+SalData::~SalData()
+{
+}
diff --git a/vcl/unx/source/printer/cupsmgr.cxx b/vcl/unx/source/printer/cupsmgr.cxx
new file mode 100644
index 000000000000..e245b2548c79
--- /dev/null
+++ b/vcl/unx/source/printer/cupsmgr.cxx
@@ -0,0 +1,1141 @@
+/*************************************************************************
+ *
+ * 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 ENABLE_CUPS
+#include <cups/cups.h>
+#include <cups/ppd.h>
+
+#else // !ENABLE_CUPS
+typedef void ppd_file_t;
+typedef void cups_dest_t;
+typedef void cups_option_t;
+#endif
+
+#include <unistd.h>
+
+#include "cupsmgr.hxx"
+
+#include "osl/thread.h"
+#include "osl/diagnose.h"
+#include "osl/conditn.hxx"
+
+#include "rtl/ustrbuf.hxx"
+
+#include <algorithm>
+#include <setjmp.h>
+#include <signal.h>
+
+#define CUPS_LIB_NAME "libcups.so.2"
+
+namespace psp
+{
+class CUPSWrapper
+{
+ oslModule m_pLib;
+ osl::Mutex m_aGetPPDMutex;
+ bool m_bPPDThreadRunning;
+
+ int (*m_pcupsPrintFile)(const char*, const char*, const char*, int, cups_option_t*);
+ int (*m_pcupsGetDests)(cups_dest_t**);
+ void (*m_pcupsSetDests)(int,cups_dest_t*);
+ void (*m_pcupsFreeDests)(int,cups_dest_t*);
+ const char* (*m_pcupsGetPPD)(const char*);
+ int (*m_pcupsMarkOptions)(ppd_file_t*,int,cups_option_t*);
+ int (*m_pcupsAddOption)(const char*,const char*,int,cups_option_t**);
+ void (*m_pcupsFreeOptions)(int,cups_option_t*);
+ ppd_file_t* (*m_pppdOpenFile)(const char* pFile);
+ void (*m_pppdClose)(ppd_file_t*);
+ const char* (*m_pcupsServer)();
+ void (*m_pcupsSetPasswordCB)(const char*(cb)(const char*));
+ const char* (*m_pcupsUser)();
+ void (*m_pcupsSetUser)(const char*);
+ const char* (*m_pcupsGetOption)(const char*,int,cups_option_t*);
+
+ oslGenericFunction loadSymbol( const char* );
+public:
+ CUPSWrapper();
+ ~CUPSWrapper();
+
+ bool isValid();
+
+ int cupsGetDests(cups_dest_t** pDests)
+ { return m_pcupsGetDests(pDests); }
+
+ void cupsSetDests( int nDests, cups_dest_t* pDests )
+ { m_pcupsSetDests( nDests, pDests ); }
+
+ void cupsFreeDests(int nDests, cups_dest_t* pDests)
+ { m_pcupsFreeDests(nDests, pDests); }
+
+ int cupsPrintFile( const char* pPrinter,
+ const char* pFileName,
+ const char* pTitle,
+ int nOptions,
+ cups_option_t* pOptions )
+ { return m_pcupsPrintFile( pPrinter, pFileName, pTitle, nOptions, pOptions ); }
+
+ rtl::OString cupsGetPPD( const char* pPrinter );
+
+ int cupsMarkOptions(ppd_file_t* pPPD, int nOptions, cups_option_t* pOptions )
+ { return m_pcupsMarkOptions(pPPD, nOptions, pOptions); }
+
+ int cupsAddOption( const char* pName, const char* pValue, int nOptions, cups_option_t** pOptions )
+ { return m_pcupsAddOption( pName, pValue, nOptions, pOptions ); }
+
+ void cupsFreeOptions( int nOptions, cups_option_t* pOptions )
+ { m_pcupsFreeOptions( nOptions, pOptions ); }
+
+ ppd_file_t* ppdOpenFile( const char* pFileName )
+ { return m_pppdOpenFile( pFileName ); }
+
+ void ppdClose( ppd_file_t* pPPD )
+ { m_pppdClose( pPPD ); }
+
+ const char *cupsServer(void)
+ { return m_pcupsServer(); }
+
+ const char *cupsUser(void)
+ { return m_pcupsUser(); }
+
+ void cupsSetPasswordCB(const char *(*cb)(const char *))
+ { m_pcupsSetPasswordCB( cb ); }
+
+ void cupsSetUser(const char *user)
+ { m_pcupsSetUser( user ); }
+
+ const char* cupsGetOption(const char* name, int num_options, cups_option_t* options)
+ { return m_pcupsGetOption( name, num_options, options ); }
+
+};
+}
+
+using namespace psp;
+using namespace osl;
+using namespace rtl;
+
+/*
+ * CUPSWrapper class
+ */
+
+oslGenericFunction CUPSWrapper::loadSymbol( const char* pSymbol )
+{
+ OUString aSym( OUString::createFromAscii( pSymbol ) );
+ oslGenericFunction pSym = osl_getFunctionSymbol( m_pLib, aSym.pData );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%s %s\n", pSymbol, pSym ? "found" : "not found" );
+#endif
+ return pSym;
+}
+
+CUPSWrapper::CUPSWrapper()
+ : m_pLib( NULL ),
+ m_bPPDThreadRunning( false )
+{
+#ifdef ENABLE_CUPS
+ OUString aLib( RTL_CONSTASCII_USTRINGPARAM( CUPS_LIB_NAME ) );
+ m_pLib = osl_loadModule( aLib.pData, SAL_LOADMODULE_LAZY );
+ if( ! m_pLib )
+ {
+ aLib = OUString( RTL_CONSTASCII_USTRINGPARAM( SAL_MODULENAME( "cups" ) ) );
+ m_pLib = osl_loadModule( aLib.pData, SAL_LOADMODULE_LAZY );
+ }
+#endif
+
+ if( ! m_pLib )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "no cups library found\n" );
+#endif
+ return;
+ }
+
+ m_pcupsPrintFile = (int(*)(const char*,const char*,const char*,int,cups_option_t*))
+ loadSymbol( "cupsPrintFile" );
+ m_pcupsGetDests = (int(*)(cups_dest_t**))
+ loadSymbol( "cupsGetDests" );
+ m_pcupsSetDests = (void(*)(int,cups_dest_t*))
+ loadSymbol( "cupsSetDests" );
+ m_pcupsFreeDests = (void(*)(int,cups_dest_t*))
+ loadSymbol( "cupsFreeDests" );
+ m_pcupsGetPPD = (const char*(*)(const char*))
+ loadSymbol( "cupsGetPPD" );
+ m_pcupsMarkOptions = (int(*)(ppd_file_t*,int,cups_option_t*))
+ loadSymbol( "cupsMarkOptions" );
+ m_pcupsAddOption = (int(*)(const char*,const char*,int,cups_option_t**))
+ loadSymbol( "cupsAddOption" );
+ m_pcupsFreeOptions = (void(*)(int,cups_option_t*))
+ loadSymbol( "cupsFreeOptions" );
+ m_pppdOpenFile = (ppd_file_t*(*)(const char*))
+ loadSymbol( "ppdOpenFile" );
+ m_pppdClose = (void(*)(ppd_file_t*))
+ loadSymbol( "ppdClose" );
+ m_pcupsServer = (const char*(*)())
+ loadSymbol( "cupsServer" );
+ m_pcupsUser = (const char*(*)())
+ loadSymbol( "cupsUser" );
+ m_pcupsSetPasswordCB = (void(*)(const char*(*)(const char*)))
+ loadSymbol( "cupsSetPasswordCB" );
+ m_pcupsSetUser = (void(*)(const char*))
+ loadSymbol( "cupsSetUser" );
+ m_pcupsGetOption = (const char*(*)(const char*,int,cups_option_t*))
+ loadSymbol( "cupsGetOption" );
+
+ if( ! (
+ m_pcupsPrintFile &&
+ m_pcupsGetDests &&
+ m_pcupsSetDests &&
+ m_pcupsFreeDests &&
+ m_pcupsGetPPD &&
+ m_pcupsMarkOptions &&
+ m_pcupsAddOption &&
+ m_pcupsServer &&
+ m_pcupsUser &&
+ m_pcupsSetPasswordCB &&
+ m_pcupsSetUser &&
+ m_pcupsFreeOptions &&
+ m_pppdOpenFile &&
+ m_pppdClose &&
+ m_pcupsGetOption
+ ) )
+ {
+ osl_unloadModule( m_pLib );
+ m_pLib = NULL;
+ }
+}
+
+CUPSWrapper::~CUPSWrapper()
+{
+ if( m_pLib )
+ osl_unloadModule( m_pLib );
+}
+
+bool CUPSWrapper::isValid()
+{
+ return m_pLib != NULL;
+}
+
+typedef const char*(*PPDFunction)(const char*);
+struct GetPPDAttribs
+{
+ PPDFunction m_pFunction;
+ osl::Condition m_aCondition;
+ OString m_aParameter;
+ OString m_aResult;
+ oslThread m_aThread;
+ int m_nRefs;
+ bool* m_pResetRunning;
+ osl::Mutex* m_pSyncMutex;
+
+ GetPPDAttribs( PPDFunction pFn, const char * m_pParameter,
+ bool* pResetRunning, osl::Mutex* pSyncMutex )
+ : m_pFunction( pFn ),
+ m_aParameter( m_pParameter ),
+ m_pResetRunning( pResetRunning ),
+ m_pSyncMutex( pSyncMutex )
+ {
+ m_nRefs = 2;
+ m_aCondition.reset();
+ }
+
+ ~GetPPDAttribs()
+ {
+ if( m_aResult.getLength() )
+ unlink( m_aResult.getStr() );
+ }
+
+ void unref()
+ {
+ if( --m_nRefs == 0 )
+ {
+ *m_pResetRunning = false;
+ delete this;
+ }
+ }
+
+ void executeCall()
+ {
+ // This CUPS method is not at all thread-safe we need
+ // to dup the pointer to a static buffer it returns ASAP
+ OString aResult = m_pFunction( m_aParameter );
+ MutexGuard aGuard( *m_pSyncMutex );
+ m_aResult = aResult;
+ m_aCondition.set();
+ unref();
+ }
+
+ OString waitResult( TimeValue *pDelay )
+ {
+ m_pSyncMutex->release();
+
+ if (m_aCondition.wait( pDelay ) != Condition::result_ok
+ )
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "cupsGetPPD %s timed out\n",
+ (const sal_Char *) m_aParameter
+ );
+ #endif
+ }
+ m_pSyncMutex->acquire();
+
+ OString aRetval = m_aResult;
+ m_aResult = OString();
+ unref();
+
+ return aRetval;
+ }
+};
+
+extern "C" {
+ static void getPPDWorker(void* pData)
+ {
+ GetPPDAttribs* pAttribs = (GetPPDAttribs*)pData;
+ pAttribs->executeCall();
+ }
+}
+
+OString CUPSWrapper::cupsGetPPD( const char* pPrinter )
+{
+ OString aResult;
+
+ m_aGetPPDMutex.acquire();
+ // if one thread hangs in cupsGetPPD already, don't start another
+ if( ! m_bPPDThreadRunning )
+ {
+ m_bPPDThreadRunning = true;
+ GetPPDAttribs* pAttribs = new GetPPDAttribs( m_pcupsGetPPD,
+ pPrinter,
+ &m_bPPDThreadRunning,
+ &m_aGetPPDMutex );
+
+ oslThread aThread = osl_createThread( getPPDWorker, pAttribs );
+
+ TimeValue aValue;
+ aValue.Seconds = 5;
+ aValue.Nanosec = 0;
+
+ // NOTE: waitResult release and acquires the GetPPD mutex
+ aResult = pAttribs->waitResult( &aValue );
+ osl_destroyThread( aThread );
+ }
+ m_aGetPPDMutex.release();
+
+ return aResult;
+}
+
+#ifdef ENABLE_CUPS
+static const char* setPasswordCallback( const char* pIn )
+{
+ const char* pRet = NULL;
+
+ PrinterInfoManager& rMgr = PrinterInfoManager::get();
+ if( rMgr.getType() == PrinterInfoManager::CUPS ) // sanity check
+ pRet = static_cast<CUPSManager&>(rMgr).authenticateUser( pIn );
+ return pRet;
+}
+#endif
+
+/*
+ * CUPSManager class
+ */
+
+CUPSManager* CUPSManager::tryLoadCUPS()
+{
+ CUPSManager* pManager = NULL;
+#ifdef ENABLE_CUPS
+ static const char* pEnv = getenv( "SAL_DISABLE_CUPS" );
+
+ if( ! pEnv || ! *pEnv )
+ {
+ // try to load CUPS
+ CUPSWrapper* pWrapper = new CUPSWrapper();
+ if( pWrapper->isValid() )
+ pManager = new CUPSManager( pWrapper );
+ else
+ delete pWrapper;
+ }
+#endif
+ return pManager;
+}
+
+extern "C"
+{
+static void run_dest_thread_stub( void* pThis )
+{
+ CUPSManager::runDestThread( pThis );
+}
+}
+
+CUPSManager::CUPSManager( CUPSWrapper* pWrapper ) :
+ PrinterInfoManager( CUPS ),
+ m_pCUPSWrapper( pWrapper ),
+ m_nDests( 0 ),
+ m_pDests( NULL ),
+ m_bNewDests( false )
+{
+ m_aDestThread = osl_createThread( run_dest_thread_stub, this );
+}
+
+CUPSManager::~CUPSManager()
+{
+ if( m_aDestThread )
+ {
+ // if the thread is still running here, then
+ // cupsGetDests is hung; terminate the thread instead of joining
+ osl_terminateThread( m_aDestThread );
+ osl_destroyThread( m_aDestThread );
+ }
+
+ if( m_nDests && m_pDests )
+ m_pCUPSWrapper->cupsFreeDests( m_nDests, (cups_dest_t*)m_pDests );
+ delete m_pCUPSWrapper;
+}
+
+void CUPSManager::runDestThread( void* pThis )
+{
+ ((CUPSManager*)pThis)->runDests();
+}
+
+static sigjmp_buf aViolationBuffer;
+
+extern "C"
+{
+ static void lcl_signal_action(int nSignal)
+ {
+ fprintf( stderr, "Signal %d during fontconfig initialization called, ignoring fontconfig\n", nSignal );
+ siglongjmp( aViolationBuffer, 1 );
+ }
+}
+
+void CUPSManager::runDests()
+{
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "starting cupsGetDests\n" );
+#endif
+ int nDests = 0;
+ cups_dest_t* pDests = NULL;
+
+ // #i86306# prepare against really broken CUPS installations / missing servers
+
+ // install signal handler for SEGV, BUS and ABRT
+ struct sigaction act;
+ struct sigaction oact[3];
+
+ act.sa_handler = lcl_signal_action;
+ act.sa_flags = 0;
+ sigemptyset(&(act.sa_mask));
+
+ int nSegvSignalInstalled = sigaction(SIGSEGV, &act, &oact[0]);
+ int nBusSignalInstalled = sigaction(SIGBUS, &act, &oact[1]);
+ int nAbortSignalInstalled = sigaction(SIGABRT, &act, &oact[2]);
+
+ // prepare against a signal during FcInit or FcConfigGetCurrent
+ if( sigsetjmp( aViolationBuffer, ~0 ) == 0 )
+ {
+ nDests = m_pCUPSWrapper->cupsGetDests( &pDests );
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "came out of cupsGetDests\n" );
+ #endif
+
+ osl::MutexGuard aGuard( m_aCUPSMutex );
+ m_nDests = nDests;
+ m_pDests = pDests;
+ m_bNewDests = true;
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "finished cupsGetDests\n" );
+ #endif
+ }
+ else
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "cupsGetDests crashed, not using CUPS\n" );
+ #endif
+ }
+
+ // restore old signal handlers
+ if( nSegvSignalInstalled == 0 )
+ sigaction( SIGSEGV, &oact[0], NULL );
+ if( nBusSignalInstalled == 0 )
+ sigaction( SIGBUS, &oact[1], NULL );
+ if( nAbortSignalInstalled == 0 )
+ sigaction( SIGABRT, &oact[2], NULL );
+}
+
+void CUPSManager::initialize()
+{
+ // get normal printers, clear printer list
+ PrinterInfoManager::initialize();
+
+#ifdef ENABLE_CUPS
+ // check whether thread has completed
+ // if not behave like old printing system
+ osl::MutexGuard aGuard( m_aCUPSMutex );
+
+ if( ! m_bNewDests )
+ return;
+
+ // dest thread has run, clean up
+ if( m_aDestThread )
+ {
+ osl_joinWithThread( m_aDestThread );
+ osl_destroyThread( m_aDestThread );
+ m_aDestThread = NULL;
+ }
+ m_bNewDests = false;
+
+ // clear old stuff
+ m_aCUPSDestMap.clear();
+
+ if( ! (m_nDests && m_pDests ) )
+ return;
+
+ if( isCUPSDisabled() )
+ return;
+
+ // check for CUPS server(?) > 1.2
+ // since there is no API to query, check for options that were
+ // introduced in dests with 1.2
+ // this is needed to check for %%IncludeFeature support
+ // (#i65684#, #i65491#)
+ cups_dest_t* pDest = ((cups_dest_t*)m_pDests);
+ const char* pOpt = m_pCUPSWrapper->cupsGetOption( "printer-info",
+ pDest->num_options,
+ pDest->options );
+ if( pOpt )
+ m_bUseIncludeFeature = true;
+ // do not send include JobPatch; CUPS will insert that itself
+ // TODO: currently unknwon which versions of CUPS insert JobPatches
+ // so currently it is assumed CUPS = don't insert JobPatch files
+ m_bUseJobPatch = false;
+
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ int nPrinter = m_nDests;
+
+ // reset global default PPD options; these are queried on demand from CUPS
+ m_aGlobalDefaults.m_pParser = NULL;
+ m_aGlobalDefaults.m_aContext = PPDContext();
+
+ // add CUPS printers, should there be a printer
+ // with the same name as a CUPS printer, overwrite it
+ while( nPrinter-- )
+ {
+ pDest = ((cups_dest_t*)m_pDests)+nPrinter;
+ OUString aPrinterName = OStringToOUString( pDest->name, aEncoding );
+ if( pDest->instance && *pDest->instance )
+ {
+ OUStringBuffer aBuf( 256 );
+ aBuf.append( aPrinterName );
+ aBuf.append( sal_Unicode( '/' ) );
+ aBuf.append( OStringToOUString( pDest->instance, aEncoding ) );
+ aPrinterName = aBuf.makeStringAndClear();
+ }
+
+ // initialize printer with possible configuration from psprint.conf
+ bool bSetToGlobalDefaults = m_aPrinters.find( aPrinterName ) == m_aPrinters.end();
+ Printer aPrinter = m_aPrinters[ aPrinterName ];
+ if( bSetToGlobalDefaults )
+ aPrinter.m_aInfo = m_aGlobalDefaults;
+ aPrinter.m_aInfo.m_aPrinterName = aPrinterName;
+ if( pDest->is_default )
+ m_aDefaultPrinter = aPrinterName;
+
+ for( int k = 0; k < pDest->num_options; k++ )
+ {
+ if(!strcmp(pDest->options[k].name, "printer-info"))
+ aPrinter.m_aInfo.m_aComment=OStringToOUString(pDest->options[k].value, aEncoding);
+ if(!strcmp(pDest->options[k].name, "printer-location"))
+ aPrinter.m_aInfo.m_aLocation=OStringToOUString(pDest->options[k].value, aEncoding);
+ }
+
+
+ OUStringBuffer aBuf( 256 );
+ aBuf.appendAscii( "CUPS:" );
+ aBuf.append( aPrinterName );
+ // note: the parser that goes with the PrinterInfo
+ // is created implicitly by the JobData::operator=()
+ // when it detects the NULL ptr m_pParser.
+ // if we wanted to fill in the parser here this
+ // would mean we'd have to download PPDs for each and
+ // every printer - which would be really bad runtime
+ // behaviour
+ aPrinter.m_aInfo.m_pParser = NULL;
+ aPrinter.m_aInfo.m_aContext.setParser( NULL );
+ std::hash_map< OUString, PPDContext, OUStringHash >::const_iterator c_it = m_aDefaultContexts.find( aPrinterName );
+ if( c_it != m_aDefaultContexts.end() )
+ {
+ aPrinter.m_aInfo.m_pParser = c_it->second.getParser();
+ aPrinter.m_aInfo.m_aContext = c_it->second;
+ }
+ aPrinter.m_aInfo.m_aDriverName = aBuf.makeStringAndClear();
+ aPrinter.m_bModified = false;
+
+ m_aPrinters[ aPrinter.m_aInfo.m_aPrinterName ] = aPrinter;
+ m_aCUPSDestMap[ aPrinter.m_aInfo.m_aPrinterName ] = nPrinter;
+ }
+
+ // remove everything that is not a CUPS printer and not
+ // a special purpose printer (PDF, Fax)
+ std::list< OUString > aRemovePrinters;
+ for( std::hash_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.begin();
+ it != m_aPrinters.end(); ++it )
+ {
+ if( m_aCUPSDestMap.find( it->first ) != m_aCUPSDestMap.end() )
+ continue;
+
+ if( it->second.m_aInfo.m_aFeatures.getLength() > 0 )
+ continue;
+ aRemovePrinters.push_back( it->first );
+ }
+ while( aRemovePrinters.begin() != aRemovePrinters.end() )
+ {
+ m_aPrinters.erase( aRemovePrinters.front() );
+ aRemovePrinters.pop_front();
+ }
+
+ m_pCUPSWrapper->cupsSetPasswordCB( setPasswordCallback );
+#endif // ENABLE_CUPS
+}
+
+#ifdef ENABLE_CUPS
+static void updatePrinterContextInfo( ppd_group_t* pPPDGroup, PPDContext& rContext )
+{
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ for( int i = 0; i < pPPDGroup->num_options; i++ )
+ {
+ ppd_option_t* pOption = pPPDGroup->options + i;
+ for( int n = 0; n < pOption->num_choices; n++ )
+ {
+ ppd_choice_t* pChoice = pOption->choices + n;
+ if( pChoice->marked )
+ {
+ const PPDKey* pKey = rContext.getParser()->getKey( OStringToOUString( pOption->keyword, aEncoding ) );
+ if( pKey )
+ {
+ const PPDValue* pValue = pKey->getValue( OStringToOUString( pChoice->choice, aEncoding ) );
+ if( pValue )
+ {
+ if( pValue != pKey->getDefaultValue() )
+ {
+ rContext.setValue( pKey, pValue, true );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "key %s is set to %s\n", pOption->keyword, pChoice->choice );
+#endif
+
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "key %s is defaulted to %s\n", pOption->keyword, pChoice->choice );
+#endif
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "caution: value %s not found in key %s\n", pChoice->choice, pOption->keyword );
+#endif
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "caution: key %s not found in parser\n", pOption->keyword );
+#endif
+ }
+ }
+ }
+
+ // recurse through subgroups
+ for( int g = 0; g < pPPDGroup->num_subgroups; g++ )
+ {
+ updatePrinterContextInfo( pPPDGroup->subgroups + g, rContext );
+ }
+}
+#endif // ENABLE_CUPS
+
+const PPDParser* CUPSManager::createCUPSParser( const OUString& rPrinter )
+{
+ const PPDParser* pNewParser = NULL;
+ OUString aPrinter;
+
+ if( rPrinter.compareToAscii( "CUPS:", 5 ) == 0 )
+ aPrinter = rPrinter.copy( 5 );
+ else
+ aPrinter = rPrinter;
+
+#ifdef ENABLE_CUPS
+ if( m_aCUPSMutex.tryToAcquire() )
+ {
+ if( m_nDests && m_pDests && ! isCUPSDisabled() )
+ {
+ std::hash_map< OUString, int, OUStringHash >::iterator dest_it =
+ m_aCUPSDestMap.find( aPrinter );
+ if( dest_it != m_aCUPSDestMap.end() )
+ {
+ cups_dest_t* pDest = ((cups_dest_t*)m_pDests) + dest_it->second;
+ OString aPPDFile = m_pCUPSWrapper->cupsGetPPD( pDest->name );
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "PPD for %s is %s\n", OUStringToOString( aPrinter, osl_getThreadTextEncoding() ).getStr(), aPPDFile.getStr() );
+ #endif
+ if( aPPDFile.getLength() )
+ {
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ OUString aFileName( OStringToOUString( aPPDFile, aEncoding ) );
+ // update the printer info with context information
+ ppd_file_t* pPPD = m_pCUPSWrapper->ppdOpenFile( aPPDFile.getStr() );
+ if( pPPD )
+ {
+ // create the new parser
+ PPDParser* pCUPSParser = new PPDParser( aFileName );
+ pCUPSParser->m_aFile = rPrinter;
+ pNewParser = pCUPSParser;
+
+ /*int nConflicts =*/ m_pCUPSWrapper->cupsMarkOptions( pPPD, pDest->num_options, pDest->options );
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "processing the following options for printer %s (instance %s):\n",
+ pDest->name, pDest->instance );
+ for( int k = 0; k < pDest->num_options; k++ )
+ fprintf( stderr, " \"%s\" = \"%s\"\n",
+ pDest->options[k].name,
+ pDest->options[k].value );
+ #endif
+ PrinterInfo& rInfo = m_aPrinters[ aPrinter ].m_aInfo;
+
+ // remember the default context for later use
+ PPDContext& rContext = m_aDefaultContexts[ aPrinter ];
+ rContext.setParser( pNewParser );
+ // set system default paper; printer CUPS PPD options
+ // may overwrite it
+ setDefaultPaper( rContext );
+ for( int i = 0; i < pPPD->num_groups; i++ )
+ updatePrinterContextInfo( pPPD->groups + i, rContext );
+
+ rInfo.m_pParser = pNewParser;
+ rInfo.m_aContext = rContext;
+
+ // clean up the mess
+ m_pCUPSWrapper->ppdClose( pPPD );
+ }
+ #if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "ppdOpenFile failed, falling back to generic driver\n" );
+ #endif
+
+ // remove temporary PPD file
+ unlink( aPPDFile.getStr() );
+ }
+ #if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "cupsGetPPD failed, falling back to generic driver\n" );
+ #endif
+ }
+ #if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "no dest found for printer %s\n", OUStringToOString( aPrinter, osl_getThreadTextEncoding() ).getStr() );
+ #endif
+ }
+ m_aCUPSMutex.release();
+ }
+ #if OSL_DEBUG_LEVEL >1
+ else
+ fprintf( stderr, "could not acquire CUPS mutex !!!\n" );
+ #endif
+ #endif // ENABLE_CUPS
+
+ if( ! pNewParser )
+ {
+ // get the default PPD
+ pNewParser = PPDParser::getParser( String( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) ) );
+
+ PrinterInfo& rInfo = m_aPrinters[ aPrinter ].m_aInfo;
+
+ rInfo.m_pParser = pNewParser;
+ rInfo.m_aContext.setParser( pNewParser );
+ }
+
+ return pNewParser;
+}
+
+void CUPSManager::setupJobContextData(
+ JobData&
+#ifdef ENABLE_CUPS
+ rData
+#endif
+)
+{
+#ifdef ENABLE_CUPS
+ std::hash_map< OUString, int, OUStringHash >::iterator dest_it =
+ m_aCUPSDestMap.find( rData.m_aPrinterName );
+
+ if( dest_it == m_aCUPSDestMap.end() )
+ return PrinterInfoManager::setupJobContextData( rData );
+
+ std::hash_map< OUString, Printer, OUStringHash >::iterator p_it =
+ m_aPrinters.find( rData.m_aPrinterName );
+ if( p_it == m_aPrinters.end() ) // huh ?
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "CUPS printer list in disorder, no dest for printer %s !\n", OUStringToOString( rData.m_aPrinterName, osl_getThreadTextEncoding() ).getStr() );
+#endif
+ return;
+ }
+
+ if( p_it->second.m_aInfo.m_pParser == NULL )
+ {
+ // in turn calls createCUPSParser
+ // which updates the printer info
+ p_it->second.m_aInfo.m_pParser = PPDParser::getParser( p_it->second.m_aInfo.m_aDriverName );
+ }
+ if( p_it->second.m_aInfo.m_aContext.getParser() == NULL )
+ {
+ OUString aPrinter;
+ if( p_it->second.m_aInfo.m_aDriverName.compareToAscii( "CUPS:", 5 ) == 0 )
+ aPrinter = p_it->second.m_aInfo.m_aDriverName.copy( 5 );
+ else
+ aPrinter = p_it->second.m_aInfo.m_aDriverName;
+
+ p_it->second.m_aInfo.m_aContext = m_aDefaultContexts[ aPrinter ];
+ }
+
+ rData.m_pParser = p_it->second.m_aInfo.m_pParser;
+ rData.m_aContext = p_it->second.m_aInfo.m_aContext;
+#endif
+}
+
+FILE* CUPSManager::startSpool( const OUString& rPrintername, bool bQuickCommand )
+{
+ if( m_aCUPSDestMap.find( rPrintername ) == m_aCUPSDestMap.end() )
+ return PrinterInfoManager::startSpool( rPrintername, bQuickCommand );
+
+#ifdef ENABLE_CUPS
+ OUString aTmpURL, aTmpFile;
+ osl_createTempFile( NULL, NULL, &aTmpURL.pData );
+ osl_getSystemPathFromFileURL( aTmpURL.pData, &aTmpFile.pData );
+ OString aSysFile = OUStringToOString( aTmpFile, osl_getThreadTextEncoding() );
+ FILE* fp = fopen( aSysFile.getStr(), "w" );
+ if( fp )
+ m_aSpoolFiles[fp] = aSysFile;
+
+ return fp;
+#else
+ return NULL;
+#endif
+}
+
+struct less_ppd_key : public ::std::binary_function<double, double, bool>
+{
+ bool operator()(const PPDKey* left, const PPDKey* right)
+ { return left->getOrderDependency() < right->getOrderDependency(); }
+};
+
+void CUPSManager::getOptionsFromDocumentSetup( const JobData& rJob, int& rNumOptions, void** rOptions ) const
+{
+ rNumOptions = 0;
+ *rOptions = NULL;
+ int i;
+
+ // emit features ordered to OrderDependency
+ // ignore features that are set to default
+
+ // sanity check
+ if( rJob.m_pParser == rJob.m_aContext.getParser() && rJob.m_pParser )
+ {
+ int nKeys = rJob.m_aContext.countValuesModified();
+ ::std::vector< const PPDKey* > aKeys( nKeys );
+ for( i = 0; i < nKeys; i++ )
+ aKeys[i] = rJob.m_aContext.getModifiedKey( i );
+ ::std::sort( aKeys.begin(), aKeys.end(), less_ppd_key() );
+
+ for( i = 0; i < nKeys; i++ )
+ {
+ const PPDKey* pKey = aKeys[i];
+ const PPDValue* pValue = rJob.m_aContext.getValue( pKey );
+ if(pValue && pValue->m_eType == eInvocation && pValue->m_aValue.Len() )
+ {
+ OString aKey = OUStringToOString( pKey->getKey(), RTL_TEXTENCODING_ASCII_US );
+ OString aValue = OUStringToOString( pValue->m_aOption, RTL_TEXTENCODING_ASCII_US );
+ rNumOptions = m_pCUPSWrapper->cupsAddOption( aKey.getStr(), aValue.getStr(), rNumOptions, (cups_option_t**)rOptions );
+ }
+ }
+ }
+}
+
+int CUPSManager::endSpool( const OUString& rPrintername, const OUString& rJobTitle, FILE* pFile, const JobData& rDocumentJobData )
+{
+ int nJobID = 0;
+
+ osl::MutexGuard aGuard( m_aCUPSMutex );
+
+ std::hash_map< OUString, int, OUStringHash >::iterator dest_it =
+ m_aCUPSDestMap.find( rPrintername );
+ if( dest_it == m_aCUPSDestMap.end() )
+ return PrinterInfoManager::endSpool( rPrintername, rJobTitle, pFile, rDocumentJobData );
+
+ #ifdef ENABLE_CUPS
+ std::hash_map< FILE*, OString, FPtrHash >::const_iterator it = m_aSpoolFiles.find( pFile );
+ if( it != m_aSpoolFiles.end() )
+ {
+ fclose( pFile );
+ rtl_TextEncoding aEnc = osl_getThreadTextEncoding();
+
+ // setup cups options
+ int nNumOptions = 0;
+ cups_option_t* pOptions = NULL;
+ getOptionsFromDocumentSetup( rDocumentJobData, nNumOptions, (void**)&pOptions );
+
+ cups_dest_t* pDest = ((cups_dest_t*)m_pDests) + dest_it->second;
+ nJobID = m_pCUPSWrapper->cupsPrintFile( pDest->name,
+ it->second.getStr(),
+ OUStringToOString( rJobTitle, aEnc ).getStr(),
+ nNumOptions, pOptions );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "cupsPrintFile( %s, %s, %s, %d, %p ) returns %d\n",
+ pDest->name,
+ it->second.getStr(),
+ OUStringToOString( rJobTitle, aEnc ).getStr(),
+ nNumOptions,
+ pOptions,
+ nJobID
+ );
+ for( int n = 0; n < nNumOptions; n++ )
+ fprintf( stderr, " option %s=%s\n", pOptions[n].name, pOptions[n].value );
+ OString aCmd( "cp " );
+ aCmd = aCmd + it->second;
+ aCmd = aCmd + OString( " $HOME/cupsprint.ps" );
+ system( aCmd.getStr() );
+#endif
+
+ unlink( it->second.getStr() );
+ m_aSpoolFiles.erase( pFile );
+ if( pOptions )
+ m_pCUPSWrapper->cupsFreeOptions( nNumOptions, pOptions );
+ }
+#endif // ENABLE_CUPS
+
+ return nJobID;
+}
+
+
+void CUPSManager::changePrinterInfo( const OUString& rPrinter, const PrinterInfo& rNewInfo )
+{
+ PrinterInfoManager::changePrinterInfo( rPrinter, rNewInfo );
+}
+
+bool CUPSManager::checkPrintersChanged( bool bWait )
+{
+ bool bChanged = false;
+ if( bWait )
+ {
+ if( m_aDestThread )
+ {
+ // initial asynchronous detection still running
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "syncing cups discovery thread\n" );
+ #endif
+ osl_joinWithThread( m_aDestThread );
+ osl_destroyThread( m_aDestThread );
+ m_aDestThread = NULL;
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "done: syncing cups discovery thread\n" );
+ #endif
+ }
+ else
+ {
+ // #i82321# check for cups printer updates
+ // with this change the whole asynchronous detection in a thread is
+ // almost useless. The only relevance left is for some stalled systems
+ // where the user can set SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION
+ // (see vcl/unx/source/gdi/salprnpsp.cxx)
+ // so that checkPrintersChanged( true ) will never be called
+
+ // there is no way to query CUPS whether the printer list has changed
+ // so get the dest list anew
+ if( m_nDests && m_pDests )
+ m_pCUPSWrapper->cupsFreeDests( m_nDests, (cups_dest_t*)m_pDests );
+ m_nDests = 0;
+ m_pDests = NULL;
+ runDests();
+ }
+ }
+ if( m_aCUPSMutex.tryToAcquire() )
+ {
+ bChanged = m_bNewDests;
+ m_aCUPSMutex.release();
+ }
+
+ if( ! bChanged )
+ {
+ bChanged = PrinterInfoManager::checkPrintersChanged( bWait );
+ // #i54375# ensure new merging with CUPS list in :initialize
+ if( bChanged )
+ m_bNewDests = true;
+ }
+
+ if( bChanged )
+ initialize();
+
+ return bChanged;
+}
+
+bool CUPSManager::addPrinter( const OUString& rName, const OUString& rDriver )
+{
+ // don't touch the CUPS printers
+ if( m_aCUPSDestMap.find( rName ) != m_aCUPSDestMap.end() ||
+ rDriver.compareToAscii( "CUPS:", 5 ) == 0
+ )
+ return false;
+ return PrinterInfoManager::addPrinter( rName, rDriver );
+}
+
+bool CUPSManager::removePrinter( const OUString& rName, bool bCheck )
+{
+ // don't touch the CUPS printers
+ if( m_aCUPSDestMap.find( rName ) != m_aCUPSDestMap.end() )
+ return false;
+ return PrinterInfoManager::removePrinter( rName, bCheck );
+}
+
+bool CUPSManager::setDefaultPrinter( const OUString& rName )
+{
+ bool bSuccess = false;
+#ifdef ENABLE_CUPS
+ std::hash_map< OUString, int, OUStringHash >::iterator nit =
+ m_aCUPSDestMap.find( rName );
+ if( nit != m_aCUPSDestMap.end() && m_aCUPSMutex.tryToAcquire() )
+ {
+ cups_dest_t* pDests = (cups_dest_t*)m_pDests;
+ for( int i = 0; i < m_nDests; i++ )
+ pDests[i].is_default = 0;
+ pDests[ nit->second ].is_default = 1;
+ m_pCUPSWrapper->cupsSetDests( m_nDests, (cups_dest_t*)m_pDests );
+ m_aDefaultPrinter = rName;
+ m_aCUPSMutex.release();
+ bSuccess = true;
+ }
+ else
+#endif
+ bSuccess = PrinterInfoManager::setDefaultPrinter( rName );
+
+ return bSuccess;
+}
+
+bool CUPSManager::writePrinterConfig()
+{
+#ifdef ENABLE_CUPS
+ bool bDestModified = false;
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+
+ for( std::hash_map< OUString, Printer, OUStringHash >::iterator prt =
+ m_aPrinters.begin(); prt != m_aPrinters.end(); ++prt )
+ {
+ std::hash_map< OUString, int, OUStringHash >::iterator nit =
+ m_aCUPSDestMap.find( prt->first );
+ if( nit == m_aCUPSDestMap.end() )
+ continue;
+
+ if( ! prt->second.m_bModified )
+ continue;
+
+ if( m_aCUPSMutex.tryToAcquire() )
+ {
+ bDestModified = true;
+ cups_dest_t* pDest = ((cups_dest_t*)m_pDests) + nit->second;
+ PrinterInfo& rInfo = prt->second.m_aInfo;
+
+ // create new option list
+ int nNewOptions = 0;
+ cups_option_t* pNewOptions = NULL;
+ int nValues = rInfo.m_aContext.countValuesModified();
+ for( int i = 0; i < nValues; i++ )
+ {
+ const PPDKey* pKey = rInfo.m_aContext.getModifiedKey( i );
+ const PPDValue* pValue = rInfo.m_aContext.getValue( pKey );
+ if( pKey && pValue ) // sanity check
+ {
+ OString aName = OUStringToOString( pKey->getKey(), aEncoding );
+ OString aValue = OUStringToOString( pValue->m_aOption, aEncoding );
+ nNewOptions = m_pCUPSWrapper->cupsAddOption( aName.getStr(), aValue.getStr(), nNewOptions, &pNewOptions );
+ }
+ }
+ // set PPD options on CUPS dest
+ m_pCUPSWrapper->cupsFreeOptions( pDest->num_options, pDest->options );
+ pDest->num_options = nNewOptions;
+ pDest->options = pNewOptions;
+ m_aCUPSMutex.release();
+ }
+ }
+ if( bDestModified && m_aCUPSMutex.tryToAcquire() )
+ {
+ m_pCUPSWrapper->cupsSetDests( m_nDests, (cups_dest_t*)m_pDests );
+ m_aCUPSMutex.release();
+ }
+#endif // ENABLE_CUPS
+
+ return PrinterInfoManager::writePrinterConfig();
+}
+
+bool CUPSManager::addOrRemovePossible() const
+{
+ return (m_nDests && m_pDests && ! isCUPSDisabled())? false : PrinterInfoManager::addOrRemovePossible();
+}
+
+#include <rtsname.hxx>
+
+const char* CUPSManager::authenticateUser( const char* /*pIn*/ )
+{
+ const char* pRet = NULL;
+
+#ifdef ENABLE_CUPS
+ OUString aLib = OUString::createFromAscii( _XSALSET_LIBNAME );
+ oslModule pLib = osl_loadModule( aLib.pData, SAL_LOADMODULE_LAZY );
+ if( pLib )
+ {
+ OUString aSym( RTL_CONSTASCII_USTRINGPARAM( "Sal_authenticateQuery" ) );
+ bool (*getpw)( const OString& rServer, OString& rUser, OString& rPw) =
+ (bool(*)(const OString&,OString&,OString&))osl_getFunctionSymbol( pLib, aSym.pData );
+ if( getpw )
+ {
+ osl::MutexGuard aGuard( m_aCUPSMutex );
+
+ OString aUser = m_pCUPSWrapper->cupsUser();
+ OString aServer = m_pCUPSWrapper->cupsServer();
+ OString aPassword;
+ if( getpw( aServer, aUser, aPassword ) )
+ {
+ m_aPassword = aPassword;
+ m_aUser = aUser;
+ m_pCUPSWrapper->cupsSetUser( m_aUser.getStr() );
+ pRet = m_aPassword.getStr();
+ }
+ }
+ osl_unloadModule( pLib );
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else fprintf( stderr, "loading of module %s failed\n", OUStringToOString( aLib, osl_getThreadTextEncoding() ).getStr() );
+#endif
+#endif // ENABLE_CUPS
+
+ return pRet;
+}
diff --git a/vcl/unx/source/printer/jobdata.cxx b/vcl/unx/source/printer/jobdata.cxx
new file mode 100644
index 000000000000..a1bca9441f77
--- /dev/null
+++ b/vcl/unx/source/printer/jobdata.cxx
@@ -0,0 +1,226 @@
+/*************************************************************************
+ *
+ * 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/jobdata.hxx"
+#include "vcl/printerinfomanager.hxx"
+
+#include "tools/stream.hxx"
+
+#include "sal/alloca.h"
+
+using namespace psp;
+using namespace rtl;
+
+JobData& JobData::operator=(const JobData& rRight)
+{
+ m_nCopies = rRight.m_nCopies;
+ m_nLeftMarginAdjust = rRight.m_nLeftMarginAdjust;
+ m_nRightMarginAdjust = rRight.m_nRightMarginAdjust;
+ m_nTopMarginAdjust = rRight.m_nTopMarginAdjust;
+ m_nBottomMarginAdjust = rRight.m_nBottomMarginAdjust;
+ m_nColorDepth = rRight.m_nColorDepth;
+ m_eOrientation = rRight.m_eOrientation;
+ m_aPrinterName = rRight.m_aPrinterName;
+ m_pParser = rRight.m_pParser;
+ m_aContext = rRight.m_aContext;
+ m_nPSLevel = rRight.m_nPSLevel;
+ m_nColorDevice = rRight.m_nColorDevice;
+
+ if( ! m_pParser && m_aPrinterName.getLength() )
+ {
+ PrinterInfoManager& rMgr = PrinterInfoManager::get();
+ rMgr.setupJobContextData( *this );
+ }
+ return *this;
+}
+
+void JobData::setCollate( bool bCollate )
+{
+ const PPDParser* pParser = m_aContext.getParser();
+ if( pParser )
+ {
+ const PPDKey* pKey = pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ) );
+ if( pKey )
+ {
+ const PPDValue* pVal = NULL;
+ if( bCollate )
+ pVal = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "True" ) ) );
+ else
+ {
+ pVal = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "False" ) ) );
+ if( ! pVal )
+ pVal = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "None" ) ) );
+ }
+ m_aContext.setValue( pKey, pVal );
+ }
+ }
+}
+
+bool JobData::getStreamBuffer( void*& pData, int& bytes )
+{
+ // consistency checks
+ if( ! m_pParser )
+ m_pParser = m_aContext.getParser();
+ if( m_pParser != m_aContext.getParser() ||
+ ! m_pParser )
+ return false;
+
+ SvMemoryStream aStream;
+ ByteString aLine;
+
+ // write header job data
+ aStream.WriteLine( "JobData 1" );
+
+ aLine = "printer=";
+ aLine += ByteString( String( m_aPrinterName ), RTL_TEXTENCODING_UTF8 );
+ aStream.WriteLine( aLine );
+
+ aLine = "orientation=";
+ aLine += m_eOrientation == orientation::Landscape ? "Landscape" : "Portrait";
+ aStream.WriteLine( aLine );
+
+ aLine = "copies=";
+ aLine += ByteString::CreateFromInt32( m_nCopies );
+ aStream.WriteLine( aLine );
+
+ aLine = "margindajustment=";
+ aLine += ByteString::CreateFromInt32( m_nLeftMarginAdjust );
+ aLine += ',';
+ aLine += ByteString::CreateFromInt32( m_nRightMarginAdjust );
+ aLine += ',';
+ aLine += ByteString::CreateFromInt32( m_nTopMarginAdjust );
+ aLine += ',';
+ aLine += ByteString::CreateFromInt32( m_nBottomMarginAdjust );
+ aStream.WriteLine( aLine );
+
+ aLine = "colordepth=";
+ aLine += ByteString::CreateFromInt32( m_nColorDepth );
+ aStream.WriteLine( aLine );
+
+ aLine = "pslevel=";
+ aLine += ByteString::CreateFromInt32( m_nPSLevel );
+ aStream.WriteLine( aLine );
+
+ aLine = "colordevice=";
+ aLine += ByteString::CreateFromInt32( m_nColorDevice );
+ aStream.WriteLine( aLine );
+
+ // now append the PPDContext stream buffer
+ aStream.WriteLine( "PPDContexData" );
+ ULONG nBytes;
+ void* pContextBuffer = m_aContext.getStreamableBuffer( nBytes );
+ if( nBytes )
+ aStream.Write( pContextBuffer, nBytes );
+
+ // success
+ pData = rtl_allocateMemory( bytes = aStream.Tell() );
+ memcpy( pData, aStream.GetData(), bytes );
+ return true;
+}
+
+bool JobData::constructFromStreamBuffer( void* pData, int bytes, JobData& rJobData )
+{
+ SvMemoryStream aStream( pData, bytes, STREAM_READ );
+ ByteString aLine;
+ bool bVersion = false;
+ bool bPrinter = false;
+ bool bOrientation = false;
+ bool bCopies = false;
+ bool bContext = false;
+ bool bMargin = false;
+ bool bColorDepth = false;
+ bool bColorDevice = false;
+ bool bPSLevel = false;
+ while( ! aStream.IsEof() )
+ {
+ aStream.ReadLine( aLine );
+ if( aLine.CompareTo( "JobData", 7 ) == COMPARE_EQUAL )
+ bVersion = true;
+ else if( aLine.CompareTo( "printer=", 8 ) == COMPARE_EQUAL )
+ {
+ bPrinter = true;
+ rJobData.m_aPrinterName = String( aLine.Copy( 8 ), RTL_TEXTENCODING_UTF8 );
+ }
+ else if( aLine.CompareTo( "orientation=", 12 ) == COMPARE_EQUAL )
+ {
+ bOrientation = true;
+ rJobData.m_eOrientation = aLine.Copy( 12 ).EqualsIgnoreCaseAscii( "landscape" ) ? orientation::Landscape : orientation::Portrait;
+ }
+ else if( aLine.CompareTo( "copies=", 7 ) == COMPARE_EQUAL )
+ {
+ bCopies = true;
+ rJobData.m_nCopies = aLine.Copy( 7 ).ToInt32();
+ }
+ else if( aLine.CompareTo( "margindajustment=",17 ) == COMPARE_EQUAL )
+ {
+ bMargin = true;
+ ByteString aValues( aLine.Copy( 17 ) );
+ rJobData.m_nLeftMarginAdjust = aValues.GetToken( 0, ',' ).ToInt32();
+ rJobData.m_nRightMarginAdjust = aValues.GetToken( 1, ',' ).ToInt32();
+ rJobData.m_nTopMarginAdjust = aValues.GetToken( 2, ',' ).ToInt32();
+ rJobData.m_nBottomMarginAdjust = aValues.GetToken( 3, ',' ).ToInt32();
+ }
+ else if( aLine.CompareTo( "colordepth=", 11 ) == COMPARE_EQUAL )
+ {
+ bColorDepth = true;
+ rJobData.m_nColorDepth = aLine.Copy( 11 ).ToInt32();
+ }
+ else if( aLine.CompareTo( "colordevice=", 12 ) == COMPARE_EQUAL )
+ {
+ bColorDevice = true;
+ rJobData.m_nColorDevice = aLine.Copy( 12 ).ToInt32();
+ }
+ else if( aLine.CompareTo( "pslevel=", 8 ) == COMPARE_EQUAL )
+ {
+ bPSLevel = true;
+ rJobData.m_nPSLevel = aLine.Copy( 8 ).ToInt32();
+ }
+ else if( aLine.Equals( "PPDContexData" ) )
+ {
+ if( bPrinter )
+ {
+ PrinterInfoManager& rManager = PrinterInfoManager::get();
+ const PrinterInfo& rInfo = rManager.getPrinterInfo( rJobData.m_aPrinterName );
+ rJobData.m_pParser = PPDParser::getParser( rInfo.m_aDriverName );
+ if( rJobData.m_pParser )
+ {
+ rJobData.m_aContext.setParser( rJobData.m_pParser );
+ int nBytes = bytes - aStream.Tell();
+ void* pRemain = alloca( bytes - aStream.Tell() );
+ aStream.Read( pRemain, nBytes );
+ rJobData.m_aContext.rebuildFromStreamBuffer( pRemain, nBytes );
+ bContext = true;
+ }
+ }
+ }
+ }
+
+ return bVersion && bPrinter && bOrientation && bCopies && bContext && bMargin && bPSLevel && bColorDevice && bColorDepth;
+}
diff --git a/vcl/unx/source/printer/makefile.mk b/vcl/unx/source/printer/makefile.mk
new file mode 100644
index 000000000000..5cd35088acd9
--- /dev/null
+++ b/vcl/unx/source/printer/makefile.mk
@@ -0,0 +1,70 @@
+#*************************************************************************
+#
+# 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=printer
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+
+.IF "$(ENABLE_CUPS)" != ""
+CDEFS += -DENABLE_CUPS
+.ENDIF
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)"=="aqua"
+
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+
+.ELSE # "$(GUIBASE)"=="aqua"
+
+SLOFILES=\
+ $(SLO)$/ppdparser.obj \
+ $(SLO)$/printerinfomanager.obj \
+ $(SLO)$/jobdata.obj \
+ $(SLO)$/cupsmgr.obj
+
+.ENDIF # GUIBASE = aqua
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
+XSALSETLIBNAME=$(DLLPRE)spa$(DLLPOSTFIX)$(DLLPOST)
+
+$(INCCOM)$/rtsname.hxx:
+ rm -f $(INCCOM)$/rtsname.hxx ; \
+ echo "#define _XSALSET_LIBNAME "\"$(XSALSETLIBNAME)\" > $(INCCOM)$/rtsname.hxx
+
+$(SLO)$/cupsmgr.obj : $(INCCOM)$/rtsname.hxx
+
diff --git a/vcl/unx/source/printer/ppdparser.cxx b/vcl/unx/source/printer/ppdparser.cxx
new file mode 100644
index 000000000000..b2549573d099
--- /dev/null
+++ b/vcl/unx/source/printer/ppdparser.cxx
@@ -0,0 +1,2164 @@
+/*************************************************************************
+ *
+ * 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 <stdio.h>
+
+#include <hash_map>
+
+#include "vcl/ppdparser.hxx"
+#include "vcl/strhelper.hxx"
+#include "vcl/helper.hxx"
+#include "vcl/svapp.hxx"
+#include "cupsmgr.hxx"
+#include "tools/debug.hxx"
+#include "tools/urlobj.hxx"
+#include "tools/stream.hxx"
+#include "tools/zcodec.hxx"
+#include "osl/mutex.hxx"
+#include "osl/file.hxx"
+#include "osl/process.h"
+#include "osl/thread.h"
+#include "rtl/strbuf.hxx"
+#include "rtl/ustrbuf.hxx"
+
+#include "com/sun/star/lang/Locale.hpp"
+
+namespace psp
+{
+ class PPDTranslator
+ {
+ struct LocaleEqual
+ {
+ bool operator()(const com::sun::star::lang::Locale& i_rLeft,
+ const com::sun::star::lang::Locale& i_rRight) const
+ {
+ return i_rLeft.Language.equals( i_rRight.Language ) &&
+ i_rLeft.Country.equals( i_rRight.Country ) &&
+ i_rLeft.Variant.equals( i_rRight.Variant );
+ }
+ };
+
+ struct LocaleHash
+ {
+ size_t operator()(const com::sun::star::lang::Locale& rLocale) const
+ { return
+ (size_t)rLocale.Language.hashCode()
+ ^ (size_t)rLocale.Country.hashCode()
+ ^ (size_t)rLocale.Variant.hashCode()
+ ;
+ }
+ };
+
+ typedef std::hash_map< com::sun::star::lang::Locale, rtl::OUString, LocaleHash, LocaleEqual > translation_map;
+ typedef std::hash_map< rtl::OUString, translation_map, rtl::OUStringHash > key_translation_map;
+
+ key_translation_map m_aTranslations;
+ public:
+ PPDTranslator() {}
+ ~PPDTranslator() {}
+
+
+ void insertValue(
+ const rtl::OUString& i_rKey,
+ const rtl::OUString& i_rOption,
+ const rtl::OUString& i_rValue,
+ const rtl::OUString& i_rTranslation,
+ const com::sun::star::lang::Locale& i_rLocale = com::sun::star::lang::Locale()
+ );
+
+ void insertOption( const rtl::OUString& i_rKey,
+ const rtl::OUString& i_rOption,
+ const rtl::OUString& i_rTranslation,
+ const com::sun::star::lang::Locale& i_rLocale = com::sun::star::lang::Locale() )
+ {
+ insertValue( i_rKey, i_rOption, rtl::OUString(), i_rTranslation, i_rLocale );
+ }
+
+ void insertKey( const rtl::OUString& i_rKey,
+ const rtl::OUString& i_rTranslation,
+ const com::sun::star::lang::Locale& i_rLocale = com::sun::star::lang::Locale() )
+ {
+ insertValue( i_rKey, rtl::OUString(), rtl::OUString(), i_rTranslation, i_rLocale );
+ }
+
+ rtl::OUString translateValue(
+ const rtl::OUString& i_rKey,
+ const rtl::OUString& i_rOption,
+ const rtl::OUString& i_rValue,
+ const com::sun::star::lang::Locale& i_rLocale = com::sun::star::lang::Locale()
+ ) const;
+
+ rtl::OUString translateOption( const rtl::OUString& i_rKey,
+ const rtl::OUString& i_rOption,
+ const com::sun::star::lang::Locale& i_rLocale = com::sun::star::lang::Locale() ) const
+ {
+ return translateValue( i_rKey, i_rOption, rtl::OUString(), i_rLocale );
+ }
+
+ rtl::OUString translateKey( const rtl::OUString& i_rKey,
+ const com::sun::star::lang::Locale& i_rLocale = com::sun::star::lang::Locale() ) const
+ {
+ return translateValue( i_rKey, rtl::OUString(), rtl::OUString(), i_rLocale );
+ }
+ };
+
+ static com::sun::star::lang::Locale normalizeInputLocale(
+ const com::sun::star::lang::Locale& i_rLocale,
+ bool bInsertDefault = false
+ )
+ {
+ com::sun::star::lang::Locale aLoc( i_rLocale );
+ if( bInsertDefault && aLoc.Language.getLength() == 0 )
+ {
+ // empty locale requested, fill in application UI locale
+ aLoc = Application::GetSettings().GetUILocale();
+
+ #if OSL_DEBUG_LEVEL > 1
+ static const char* pEnvLocale = getenv( "SAL_PPDPARSER_LOCALE" );
+ if( pEnvLocale && *pEnvLocale )
+ {
+ rtl::OString aStr( pEnvLocale );
+ sal_Int32 nLen = aStr.getLength();
+ aLoc.Language = rtl::OStringToOUString( aStr.copy( 0, nLen > 2 ? 2 : nLen ), RTL_TEXTENCODING_MS_1252 );
+ if( nLen >=5 && aStr.getStr()[2] == '_' )
+ aLoc.Country = rtl::OStringToOUString( aStr.copy( 3, 2 ), RTL_TEXTENCODING_MS_1252 );
+ else
+ aLoc.Country = rtl::OUString();
+ aLoc.Variant = rtl::OUString();
+ }
+ #endif
+ }
+ aLoc.Language = aLoc.Language.toAsciiLowerCase();
+ aLoc.Country = aLoc.Country.toAsciiUpperCase();
+ aLoc.Variant = aLoc.Variant.toAsciiUpperCase();
+
+ return aLoc;
+ }
+
+ void PPDTranslator::insertValue(
+ const rtl::OUString& i_rKey,
+ const rtl::OUString& i_rOption,
+ const rtl::OUString& i_rValue,
+ const rtl::OUString& i_rTranslation,
+ const com::sun::star::lang::Locale& i_rLocale
+ )
+ {
+ rtl::OUStringBuffer aKey( i_rKey.getLength() + i_rOption.getLength() + i_rValue.getLength() + 2 );
+ aKey.append( i_rKey );
+ if( i_rOption.getLength() || i_rValue.getLength() )
+ {
+ aKey.append( sal_Unicode( ':' ) );
+ aKey.append( i_rOption );
+ }
+ if( i_rValue.getLength() )
+ {
+ aKey.append( sal_Unicode( ':' ) );
+ aKey.append( i_rValue );
+ }
+ if( aKey.getLength() && i_rTranslation.getLength() )
+ {
+ rtl::OUString aK( aKey.makeStringAndClear() );
+ com::sun::star::lang::Locale aLoc;
+ aLoc.Language = i_rLocale.Language.toAsciiLowerCase();
+ aLoc.Country = i_rLocale.Country.toAsciiUpperCase();
+ aLoc.Variant = i_rLocale.Variant.toAsciiUpperCase();
+ m_aTranslations[ aK ][ aLoc ] = i_rTranslation;
+ }
+ }
+
+ rtl::OUString PPDTranslator::translateValue(
+ const rtl::OUString& i_rKey,
+ const rtl::OUString& i_rOption,
+ const rtl::OUString& i_rValue,
+ const com::sun::star::lang::Locale& i_rLocale
+ ) const
+ {
+ rtl::OUString aResult;
+
+ rtl::OUStringBuffer aKey( i_rKey.getLength() + i_rOption.getLength() + i_rValue.getLength() + 2 );
+ aKey.append( i_rKey );
+ if( i_rOption.getLength() || i_rValue.getLength() )
+ {
+ aKey.append( sal_Unicode( ':' ) );
+ aKey.append( i_rOption );
+ }
+ if( i_rValue.getLength() )
+ {
+ aKey.append( sal_Unicode( ':' ) );
+ aKey.append( i_rValue );
+ }
+ if( aKey.getLength() )
+ {
+ rtl::OUString aK( aKey.makeStringAndClear() );
+ key_translation_map::const_iterator it = m_aTranslations.find( aK );
+ if( it != m_aTranslations.end() )
+ {
+ const translation_map& rMap( it->second );
+
+ com::sun::star::lang::Locale aLoc( normalizeInputLocale( i_rLocale, true ) );
+ for( int nTry = 0; nTry < 4; nTry++ )
+ {
+ translation_map::const_iterator tr = rMap.find( aLoc );
+ if( tr != rMap.end() )
+ {
+ aResult = tr->second;
+ break;
+ }
+ switch( nTry )
+ {
+ case 0: aLoc.Variant = rtl::OUString();break;
+ case 1: aLoc.Country = rtl::OUString();break;
+ case 2: aLoc.Language = rtl::OUString();break;
+ }
+ }
+ }
+ }
+ return aResult;
+ }
+}
+
+using namespace psp;
+using namespace rtl;
+
+#undef DBG_ASSERT
+#if defined DBG_UTIL || (OSL_DEBUG_LEVEL > 1)
+#define BSTRING(x) ByteString( x, osl_getThreadTextEncoding() )
+#define DBG_ASSERT( x, y ) { if( ! (x) ) fprintf( stderr, (y) ); }
+#else
+#define DBG_ASSERT( x, y )
+#endif
+
+std::list< PPDParser* > PPDParser::aAllParsers;
+std::hash_map< OUString, OUString, OUStringHash >* PPDParser::pAllPPDFiles = NULL;
+
+class PPDDecompressStream
+{
+ SvFileStream* mpFileStream;
+ SvMemoryStream* mpMemStream;
+ rtl::OUString maFileName;
+
+ // forbid copying
+ PPDDecompressStream( const PPDDecompressStream& );
+ PPDDecompressStream& operator=(const PPDDecompressStream& );
+
+ public:
+ PPDDecompressStream( const rtl::OUString& rFile );
+ ~PPDDecompressStream();
+
+ bool IsOpen() const;
+ bool IsEof() const;
+ void ReadLine( ByteString& o_rLine);
+ void Open( const rtl::OUString& i_rFile );
+ void Close();
+ const rtl::OUString& GetFileName() const { return maFileName; }
+};
+
+PPDDecompressStream::PPDDecompressStream( const rtl::OUString& i_rFile ) :
+ mpFileStream( NULL ),
+ mpMemStream( NULL )
+{
+ Open( i_rFile );
+}
+
+PPDDecompressStream::~PPDDecompressStream()
+{
+ Close();
+}
+
+void PPDDecompressStream::Open( const rtl::OUString& i_rFile )
+{
+ Close();
+
+ mpFileStream = new SvFileStream( i_rFile, STREAM_READ );
+ maFileName = mpFileStream->GetFileName();
+
+ if( ! mpFileStream->IsOpen() )
+ {
+ Close();
+ return;
+ }
+
+ ByteString aLine;
+ mpFileStream->ReadLine( aLine );
+ mpFileStream->Seek( 0 );
+
+ // check for compress'ed or gzip'ed file
+ ULONG nCompressMethod = 0;
+ if( aLine.Len() > 1 && static_cast<unsigned char>(aLine.GetChar( 0 )) == 0x1f )
+ {
+ if( static_cast<unsigned char>(aLine.GetChar( 1 )) == 0x8b ) // check for gzip
+ nCompressMethod = ZCODEC_DEFAULT | ZCODEC_GZ_LIB;
+ }
+
+ if( nCompressMethod != 0 )
+ {
+ // so let's try to decompress the stream
+ mpMemStream = new SvMemoryStream( 4096, 4096 );
+ ZCodec aCodec;
+ aCodec.BeginCompression( nCompressMethod );
+ long nComp = aCodec.Decompress( *mpFileStream, *mpMemStream );
+ aCodec.EndCompression();
+ if( nComp < 0 )
+ {
+ // decompression failed, must be an uncompressed stream after all
+ delete mpMemStream, mpMemStream = NULL;
+ mpFileStream->Seek( 0 );
+ }
+ else
+ {
+ // compression successfull, can get rid of file stream
+ delete mpFileStream, mpFileStream = NULL;
+ mpMemStream->Seek( 0 );
+ }
+ }
+}
+
+void PPDDecompressStream::Close()
+{
+ delete mpMemStream, mpMemStream = NULL;
+ delete mpFileStream, mpFileStream = NULL;
+}
+
+bool PPDDecompressStream::IsOpen() const
+{
+ return (mpMemStream || (mpFileStream && mpFileStream->IsOpen()));
+}
+
+bool PPDDecompressStream::IsEof() const
+{
+ return ( mpMemStream ? mpMemStream->IsEof() : ( mpFileStream ? mpFileStream->IsEof() : true ) );
+}
+
+void PPDDecompressStream::ReadLine( ByteString& o_rLine )
+{
+ if( mpMemStream )
+ mpMemStream->ReadLine( o_rLine );
+ else if( mpFileStream )
+ mpFileStream->ReadLine( o_rLine );
+}
+
+static osl::FileBase::RC resolveLink( const rtl::OUString& i_rURL, rtl::OUString& o_rResolvedURL, rtl::OUString& o_rBaseName, osl::FileStatus::Type& o_rType, int nLinkLevel = 10 )
+{
+ osl::DirectoryItem aLinkItem;
+ osl::FileBase::RC aRet = osl::FileBase::E_None;
+
+ if( ( aRet = osl::DirectoryItem::get( i_rURL, aLinkItem ) ) == osl::FileBase::E_None )
+ {
+ osl::FileStatus aStatus( FileStatusMask_FileName | FileStatusMask_Type | FileStatusMask_LinkTargetURL );
+ if( ( aRet = aLinkItem.getFileStatus( aStatus ) ) == osl::FileBase::E_None )
+ {
+ if( aStatus.getFileType() == osl::FileStatus::Link )
+ {
+ if( nLinkLevel > 0 )
+ aRet = resolveLink( aStatus.getLinkTargetURL(), o_rResolvedURL, o_rBaseName, o_rType, nLinkLevel-1 );
+ else
+ aRet = osl::FileBase::E_MULTIHOP;
+ }
+ else
+ {
+ o_rResolvedURL = i_rURL;
+ o_rBaseName = aStatus.getFileName();
+ o_rType = aStatus.getFileType();
+ }
+ }
+ }
+ return aRet;
+}
+
+void PPDParser::scanPPDDir( const String& rDir )
+{
+ static struct suffix_t
+ {
+ const sal_Char* pSuffix;
+ const sal_Int32 nSuffixLen;
+ } const pSuffixes[] =
+ { { ".PS", 3 }, { ".PPD", 4 }, { ".PS.GZ", 6 }, { ".PPD.GZ", 7 } };
+
+ const int nSuffixes = sizeof(pSuffixes)/sizeof(pSuffixes[0]);
+
+ osl::Directory aDir( rDir );
+ aDir.open();
+ osl::DirectoryItem aItem;
+
+ INetURLObject aPPDDir(rDir);
+ while( aDir.getNextItem( aItem ) == osl::FileBase::E_None )
+ {
+ osl::FileStatus aStatus( FileStatusMask_FileName );
+ if( aItem.getFileStatus( aStatus ) == osl::FileBase::E_None )
+ {
+ rtl::OUStringBuffer aURLBuf( rDir.Len() + 64 );
+ aURLBuf.append( rDir );
+ aURLBuf.append( sal_Unicode( '/' ) );
+ aURLBuf.append( aStatus.getFileName() );
+
+ rtl::OUString aFileURL, aFileName;
+ osl::FileStatus::Type eType = osl::FileStatus::Unknown;
+
+ if( resolveLink( aURLBuf.makeStringAndClear(), aFileURL, aFileName, eType ) == osl::FileBase::E_None )
+ {
+ if( eType == osl::FileStatus::Regular )
+ {
+ INetURLObject aPPDFile = aPPDDir;
+ aPPDFile.Append( aFileName );
+
+ // match extension
+ for( int nSuffix = 0; nSuffix < nSuffixes; nSuffix++ )
+ {
+ if( aFileName.getLength() > pSuffixes[nSuffix].nSuffixLen )
+ {
+ if( aFileName.endsWithIgnoreAsciiCaseAsciiL( pSuffixes[nSuffix].pSuffix, pSuffixes[nSuffix].nSuffixLen ) )
+ {
+ (*pAllPPDFiles)[ aFileName.copy( 0, aFileName.getLength() - pSuffixes[nSuffix].nSuffixLen ) ] = aPPDFile.PathToFileName();
+ break;
+ }
+ }
+ }
+ }
+ else if( eType == osl::FileStatus::Directory )
+ {
+ scanPPDDir( aFileURL );
+ }
+ }
+ }
+ }
+ aDir.close();
+}
+
+void PPDParser::initPPDFiles()
+{
+ if( pAllPPDFiles )
+ return;
+
+ pAllPPDFiles = new std::hash_map< OUString, OUString, OUStringHash >();
+
+ // check installation directories
+ std::list< OUString > aPathList;
+ psp::getPrinterPathList( aPathList, PRINTER_PPDDIR );
+ for( std::list< OUString >::const_iterator ppd_it = aPathList.begin(); ppd_it != aPathList.end(); ++ppd_it )
+ {
+ INetURLObject aPPDDir( *ppd_it, INET_PROT_FILE, INetURLObject::ENCODE_ALL );
+ scanPPDDir( aPPDDir.GetMainURL( INetURLObject::NO_DECODE ) );
+ }
+ if( pAllPPDFiles->find( OUString( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) ) ) == pAllPPDFiles->end() )
+ {
+ // last try: search in directory of executable (mainly for setup)
+ OUString aExe;
+ if( osl_getExecutableFile( &aExe.pData ) == osl_Process_E_None )
+ {
+ INetURLObject aDir( aExe );
+ aDir.removeSegment();
+#ifdef DEBUG
+ fprintf( stderr, "scanning last chance dir: %s\n", OUStringToOString( aDir.GetMainURL( INetURLObject::NO_DECODE ), osl_getThreadTextEncoding() ).getStr() );
+#endif
+ scanPPDDir( aDir.GetMainURL( INetURLObject::NO_DECODE ) );
+#ifdef DEBUG
+ fprintf( stderr, "SGENPRT %s\n", pAllPPDFiles->find( OUString( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) ) ) == pAllPPDFiles->end() ? "not found" : "found" );
+#endif
+ }
+ }
+}
+
+void PPDParser::getKnownPPDDrivers( std::list< rtl::OUString >& o_rDrivers, bool bRefresh )
+{
+ if( bRefresh )
+ {
+ delete pAllPPDFiles;
+ pAllPPDFiles = NULL;
+ }
+
+ initPPDFiles();
+ o_rDrivers.clear();
+
+ std::hash_map< OUString, OUString, OUStringHash >::const_iterator it;
+ for( it = pAllPPDFiles->begin(); it != pAllPPDFiles->end(); ++it )
+ o_rDrivers.push_back( it->first );
+}
+
+String PPDParser::getPPDFile( const String& rFile )
+{
+ INetURLObject aPPD( rFile, INET_PROT_FILE, INetURLObject::ENCODE_ALL );
+ // someone might enter a full qualified name here
+ PPDDecompressStream aStream( aPPD.PathToFileName() );
+ if( ! aStream.IsOpen() )
+ {
+ std::hash_map< OUString, OUString, OUStringHash >::const_iterator it;
+
+ bool bRetry = true;
+ do
+ {
+ initPPDFiles();
+ // some PPD files contain dots beside the extension, so try name first
+ // and cut of points after that
+ rtl::OUString aBase( rFile );
+ sal_Int32 nLastIndex = aBase.lastIndexOf( sal_Unicode( '/' ) );
+ if( nLastIndex >= 0 )
+ aBase = aBase.copy( nLastIndex+1 );
+ do
+ {
+ it = pAllPPDFiles->find( aBase );
+ nLastIndex = aBase.lastIndexOf( sal_Unicode( '.' ) );
+ if( nLastIndex > 0 )
+ aBase = aBase.copy( 0, nLastIndex );
+ } while( it == pAllPPDFiles->end() && nLastIndex > 0 );
+
+ if( it == pAllPPDFiles->end() && bRetry )
+ {
+ // a new file ? rehash
+ delete pAllPPDFiles; pAllPPDFiles = NULL;
+ bRetry = false;
+ // note this is optimized for office start where
+ // no new files occur and initPPDFiles is called only once
+ }
+ } while( ! pAllPPDFiles );
+
+ if( it != pAllPPDFiles->end() )
+ aStream.Open( it->second );
+ }
+
+ String aRet;
+ if( aStream.IsOpen() )
+ {
+ ByteString aLine;
+ aStream.ReadLine( aLine );
+ if( aLine.Search( "*PPD-Adobe" ) == 0 )
+ aRet = aStream.GetFileName();
+ else
+ {
+ // our *Include hack does usually not begin
+ // with *PPD-Adobe, so try some lines for *Include
+ int nLines = 10;
+ while( aLine.Search( "*Include" ) != 0 && --nLines )
+ aStream.ReadLine( aLine );
+ if( nLines )
+ aRet = aStream.GetFileName();
+ }
+ }
+
+ return aRet;
+}
+
+String PPDParser::getPPDPrinterName( const String& rFile )
+{
+ String aPath = getPPDFile( rFile );
+ String aName;
+
+ // read in the file
+ PPDDecompressStream aStream( aPath );
+ if( aStream.IsOpen() )
+ {
+ String aCurLine;
+ while( ! aStream.IsEof() && aStream.IsOpen() )
+ {
+ ByteString aByteLine;
+ aStream.ReadLine( aByteLine );
+ aCurLine = String( aByteLine, RTL_TEXTENCODING_MS_1252 );
+ if( aCurLine.CompareIgnoreCaseToAscii( "*include:", 9 ) == COMPARE_EQUAL )
+ {
+ aCurLine.Erase( 0, 9 );
+ aCurLine.EraseLeadingChars( ' ' );
+ aCurLine.EraseTrailingChars( ' ' );
+ aCurLine.EraseLeadingChars( '\t' );
+ aCurLine.EraseTrailingChars( '\t' );
+ aCurLine.EraseTrailingChars( '\r' );
+ aCurLine.EraseTrailingChars( '\n' );
+ aCurLine.EraseLeadingChars( '"' );
+ aCurLine.EraseTrailingChars( '"' );
+ aStream.Close();
+ aStream.Open( getPPDFile( aCurLine ) );
+ continue;
+ }
+ if( aCurLine.CompareToAscii( "*ModelName:", 11 ) == COMPARE_EQUAL )
+ {
+ aName = aCurLine.GetToken( 1, '"' );
+ break;
+ }
+ else if( aCurLine.CompareToAscii( "*NickName:", 10 ) == COMPARE_EQUAL )
+ aName = aCurLine.GetToken( 1, '"' );
+ }
+ }
+ return aName;
+}
+
+const PPDParser* PPDParser::getParser( const String& rFile )
+{
+ static ::osl::Mutex aMutex;
+ ::osl::Guard< ::osl::Mutex > aGuard( aMutex );
+
+ String aFile = rFile;
+ if( rFile.CompareToAscii( "CUPS:", 5 ) != COMPARE_EQUAL )
+ aFile = getPPDFile( rFile );
+ if( ! aFile.Len() )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "Could not get printer PPD file \"%s\" !\n", OUStringToOString( rFile, osl_getThreadTextEncoding() ).getStr() );
+#endif
+ return NULL;
+ }
+
+ for( ::std::list< PPDParser* >::const_iterator it = aAllParsers.begin(); it != aAllParsers.end(); ++it )
+ if( (*it)->m_aFile == aFile )
+ return *it;
+
+ PPDParser* pNewParser = NULL;
+ if( aFile.CompareToAscii( "CUPS:", 5 ) != COMPARE_EQUAL )
+ pNewParser = new PPDParser( aFile );
+ else
+ {
+ PrinterInfoManager& rMgr = PrinterInfoManager::get();
+ if( rMgr.getType() == PrinterInfoManager::CUPS )
+ {
+ pNewParser = const_cast<PPDParser*>(static_cast<CUPSManager&>(rMgr).createCUPSParser( aFile ));
+ }
+ }
+ if( pNewParser )
+ {
+ // this may actually be the SGENPRT parser,
+ // so ensure uniquness here
+ aAllParsers.remove( pNewParser );
+ // insert new parser to list
+ aAllParsers.push_front( pNewParser );
+ }
+ return pNewParser;
+}
+
+void PPDParser::freeAll()
+{
+ while( aAllParsers.begin() != aAllParsers.end() )
+ {
+ delete aAllParsers.front();
+ aAllParsers.pop_front();
+ }
+ delete pAllPPDFiles;
+ pAllPPDFiles = NULL;
+}
+
+PPDParser::PPDParser( const String& rFile ) :
+ m_aFile( rFile ),
+ m_bType42Capable( false ),
+ m_aFileEncoding( RTL_TEXTENCODING_MS_1252 ),
+ m_pDefaultImageableArea( NULL ),
+ m_pImageableAreas( NULL ),
+ m_pDefaultPaperDimension( NULL ),
+ m_pPaperDimensions( NULL ),
+ m_pDefaultInputSlot( NULL ),
+ m_pInputSlots( NULL ),
+ m_pDefaultResolution( NULL ),
+ m_pResolutions( NULL ),
+ m_pDefaultDuplexType( NULL ),
+ m_pDuplexTypes( NULL ),
+ m_pFontList( NULL ),
+ m_pTranslator( new PPDTranslator() )
+{
+ // read in the file
+ std::list< ByteString > aLines;
+ PPDDecompressStream aStream( m_aFile );
+ bool bLanguageEncoding = false;
+ if( aStream.IsOpen() )
+ {
+ ByteString aCurLine;
+ while( ! aStream.IsEof() )
+ {
+ aStream.ReadLine( aCurLine );
+ if( aCurLine.GetChar( 0 ) == '*' )
+ {
+ if( aCurLine.CompareIgnoreCaseToAscii( "*include:", 9 ) == COMPARE_EQUAL )
+ {
+ aCurLine.Erase( 0, 9 );
+ aCurLine.EraseLeadingChars( ' ' );
+ aCurLine.EraseTrailingChars( ' ' );
+ aCurLine.EraseLeadingChars( '\t' );
+ aCurLine.EraseTrailingChars( '\t' );
+ aCurLine.EraseTrailingChars( '\r' );
+ aCurLine.EraseTrailingChars( '\n' );
+ aCurLine.EraseLeadingChars( '"' );
+ aCurLine.EraseTrailingChars( '"' );
+ aStream.Close();
+ aStream.Open( getPPDFile( String( aCurLine, m_aFileEncoding ) ) );
+ continue;
+ }
+ else if( ! bLanguageEncoding &&
+ aCurLine.CompareIgnoreCaseToAscii( "*languageencoding", 17 ) == COMPARE_EQUAL )
+ {
+ bLanguageEncoding = true; // generally only the first one counts
+ ByteString aLower = aCurLine;
+ aLower.ToLowerAscii();
+ if( aLower.Search( "isolatin1", 17 ) != STRING_NOTFOUND ||
+ aLower.Search( "windowsansi", 17 ) != STRING_NOTFOUND )
+ m_aFileEncoding = RTL_TEXTENCODING_MS_1252;
+ else if( aLower.Search( "isolatin2", 17 ) != STRING_NOTFOUND )
+ m_aFileEncoding = RTL_TEXTENCODING_ISO_8859_2;
+ else if( aLower.Search( "isolatin5", 17 ) != STRING_NOTFOUND )
+ m_aFileEncoding = RTL_TEXTENCODING_ISO_8859_5;
+ else if( aLower.Search( "jis83-rksj", 17 ) != STRING_NOTFOUND )
+ m_aFileEncoding = RTL_TEXTENCODING_SHIFT_JIS;
+ else if( aLower.Search( "macstandard", 17 ) != STRING_NOTFOUND )
+ m_aFileEncoding = RTL_TEXTENCODING_APPLE_ROMAN;
+ else if( aLower.Search( "utf-8", 17 ) != STRING_NOTFOUND )
+ m_aFileEncoding = RTL_TEXTENCODING_UTF8;
+ }
+ }
+ aLines.push_back( aCurLine );
+ }
+ }
+ aStream.Close();
+
+ // now get the Values
+ parse( aLines );
+#if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, "acquired %d Keys from PPD %s:\n", m_aKeys.size(), BSTRING( m_aFile ).GetBuffer() );
+ for( PPDParser::hash_type::const_iterator it = m_aKeys.begin(); it != m_aKeys.end(); ++it )
+ {
+ const PPDKey* pKey = it->second;
+ char* pSetupType = "<unknown>";
+ switch( pKey->m_eSetupType )
+ {
+ case PPDKey::ExitServer: pSetupType = "ExitServer";break;
+ case PPDKey::Prolog: pSetupType = "Prolog";break;
+ case PPDKey::DocumentSetup: pSetupType = "DocumentSetup";break;
+ case PPDKey::PageSetup: pSetupType = "PageSetup";break;
+ case PPDKey::JCLSetup: pSetupType = "JCLSetup";break;
+ case PPDKey::AnySetup: pSetupType = "AnySetup";break;
+ default: break;
+ };
+ fprintf( stderr, "\t\"%s\" (\"%s\") (%d values) OrderDependency: %d %s\n",
+ BSTRING( pKey->getKey() ).GetBuffer(),
+ BSTRING( pKey->m_aUITranslation ).GetBuffer(),
+ pKey->countValues(),
+ pKey->m_nOrderDependency,
+ pSetupType );
+ for( int j = 0; j < pKey->countValues(); j++ )
+ {
+ fprintf( stderr, "\t\t" );
+ const PPDValue* pValue = pKey->getValue( j );
+ if( pValue == pKey->m_pDefaultValue )
+ fprintf( stderr, "(Default:) " );
+ char* pVType = "<unknown>";
+ switch( pValue->m_eType )
+ {
+ case eInvocation: pVType = "invocation";break;
+ case eQuoted: pVType = "quoted";break;
+ case eString: pVType = "string";break;
+ case eSymbol: pVType = "symbol";break;
+ case eNo: pVType = "no";break;
+ default: break;
+ };
+ fprintf( stderr, "option: \"%s\" (\"%s\"), value: type %s \"%s\" (\"%s\")\n",
+ BSTRING( pValue->m_aOption ).GetBuffer(),
+ BSTRING( pValue->m_aOptionTranslation ).GetBuffer(),
+ pVType,
+ BSTRING( pValue->m_aValue ).GetBuffer(),
+ BSTRING( pValue->m_aValueTranslation ).GetBuffer() );
+ }
+ }
+ fprintf( stderr, "constraints: (%d found)\n", m_aConstraints.size() );
+ for( std::list< PPDConstraint >::const_iterator cit = m_aConstraints.begin(); cit != m_aConstraints.end(); ++cit )
+ {
+ fprintf( stderr, "*\"%s\" \"%s\" *\"%s\" \"%s\"\n",
+ BSTRING( cit->m_pKey1->getKey() ).GetBuffer(),
+ cit->m_pOption1 ? BSTRING( cit->m_pOption1->m_aOption ).GetBuffer() : "<nil>",
+ BSTRING( cit->m_pKey2->getKey() ).GetBuffer(),
+ cit->m_pOption2 ? BSTRING( cit->m_pOption2->m_aOption ).GetBuffer() : "<nil>"
+ );
+ }
+#endif
+
+ // fill in shortcuts
+ const PPDKey* pKey;
+
+ m_pImageableAreas = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "ImageableArea" ) ) );
+ if( m_pImageableAreas )
+ m_pDefaultImageableArea = m_pImageableAreas->getDefaultValue();
+ DBG_ASSERT( m_pImageableAreas, "Warning: no ImageableArea in PPD\n" );
+ DBG_ASSERT( m_pDefaultImageableArea, "Warning: no DefaultImageableArea in PPD\n" );
+
+ m_pPaperDimensions = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PaperDimension" ) ) );
+ if( m_pPaperDimensions )
+ m_pDefaultPaperDimension = m_pPaperDimensions->getDefaultValue();
+ DBG_ASSERT( m_pPaperDimensions, "Warning: no PaperDimension in PPD\n" );
+ DBG_ASSERT( m_pDefaultPaperDimension, "Warning: no DefaultPaperDimension in PPD\n" );
+
+ m_pResolutions = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Resolution" ) ) );
+ if( m_pResolutions )
+ m_pDefaultResolution = m_pResolutions->getDefaultValue();
+ DBG_ASSERT( m_pResolutions, "Warning: no Resolution in PPD\n" );
+ DBG_ASSERT( m_pDefaultResolution, "Warning: no DefaultResolution in PPD\n" );
+
+ m_pInputSlots = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) );
+ if( m_pInputSlots )
+ m_pDefaultInputSlot = m_pInputSlots->getDefaultValue();
+ DBG_ASSERT( m_pPaperDimensions, "Warning: no InputSlot in PPD\n" );
+ DBG_ASSERT( m_pDefaultPaperDimension, "Warning: no DefaultInputSlot in PPD\n" );
+
+ m_pDuplexTypes = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) );
+ if( m_pDuplexTypes )
+ m_pDefaultDuplexType = m_pDuplexTypes->getDefaultValue();
+
+ m_pFontList = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Font" ) ) );
+ DBG_ASSERT( m_pFontList, "Warning: no Font in PPD\n" );
+
+ // fill in direct values
+ if( (pKey = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "ModelName" ) ) )) )
+ m_aPrinterName = pKey->getValue( 0 )->m_aValue;
+ if( (pKey = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "NickName" ) ) )) )
+ m_aNickName = pKey->getValue( 0 )->m_aValue;
+ if( (pKey = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "ColorDevice" ) ) )) )
+ m_bColorDevice = pKey->getValue( 0 )->m_aValue.CompareIgnoreCaseToAscii( "true", 4 ) == COMPARE_EQUAL ? true : false;
+
+ if( (pKey = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "LanguageLevel" ) ) )) )
+ m_nLanguageLevel = pKey->getValue( 0 )->m_aValue.ToInt32();
+ if( (pKey = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "TTRasterizer" ) ) )) )
+ m_bType42Capable = pKey->getValue( 0 )->m_aValue.EqualsIgnoreCaseAscii( "Type42" ) ? true : false;
+}
+
+PPDParser::~PPDParser()
+{
+ for( PPDParser::hash_type::iterator it = m_aKeys.begin(); it != m_aKeys.end(); ++it )
+ delete it->second;
+ delete m_pTranslator;
+}
+
+void PPDParser::insertKey( const String& rKey, PPDKey* pKey )
+{
+ m_aKeys[ rKey ] = pKey;
+ m_aOrderedKeys.push_back( pKey );
+}
+
+const PPDKey* PPDParser::getKey( int n ) const
+{
+ return ((unsigned int)n < m_aOrderedKeys.size() && n >= 0) ? m_aOrderedKeys[n] : NULL;
+}
+
+const PPDKey* PPDParser::getKey( const String& rKey ) const
+{
+ PPDParser::hash_type::const_iterator it = m_aKeys.find( rKey );
+ return it != m_aKeys.end() ? it->second : NULL;
+}
+
+bool PPDParser::hasKey( const PPDKey* pKey ) const
+{
+ return
+ pKey ?
+ ( m_aKeys.find( pKey->getKey() ) != m_aKeys.end() ? true : false ) :
+ false;
+}
+
+static sal_uInt8 getNibble( sal_Char cChar )
+{
+ sal_uInt8 nRet = 0;
+ if( cChar >= '0' && cChar <= '9' )
+ nRet = sal_uInt8( cChar - '0' );
+ else if( cChar >= 'A' && cChar <= 'F' )
+ nRet = 10 + sal_uInt8( cChar - 'A' );
+ else if( cChar >= 'a' && cChar <= 'f' )
+ nRet = 10 + sal_uInt8( cChar - 'a' );
+ return nRet;
+}
+
+String PPDParser::handleTranslation( const ByteString& i_rString, bool bIsGlobalized )
+{
+ int nOrigLen = i_rString.Len();
+ OStringBuffer aTrans( nOrigLen );
+ const sal_Char* pStr = i_rString.GetBuffer();
+ const sal_Char* pEnd = pStr + nOrigLen;
+ while( pStr < pEnd )
+ {
+ if( *pStr == '<' )
+ {
+ pStr++;
+ sal_Char cChar;
+ while( *pStr != '>' && pStr < pEnd-1 )
+ {
+ cChar = getNibble( *pStr++ ) << 4;
+ cChar |= getNibble( *pStr++ );
+ aTrans.append( cChar );
+ }
+ pStr++;
+ }
+ else
+ aTrans.append( *pStr++ );
+ }
+ return OStringToOUString( aTrans.makeStringAndClear(), bIsGlobalized ? RTL_TEXTENCODING_UTF8 : m_aFileEncoding );
+}
+
+void PPDParser::parse( ::std::list< ByteString >& rLines )
+{
+ std::list< ByteString >::iterator line = rLines.begin();
+ PPDParser::hash_type::const_iterator keyit;
+ while( line != rLines.end() )
+ {
+ ByteString aCurrentLine( *line );
+ ++line;
+ if( aCurrentLine.GetChar(0) != '*' )
+ continue;
+ if( aCurrentLine.GetChar(1) == '%' )
+ continue;
+
+ ByteString aKey = GetCommandLineToken( 0, aCurrentLine.GetToken( 0, ':' ) );
+ int nPos = aKey.Search( '/' );
+ if( nPos != STRING_NOTFOUND )
+ aKey.Erase( nPos );
+ aKey.Erase( 0, 1 ); // remove the '*'
+
+ if( aKey.Equals( "CloseUI" ) || aKey.Equals( "OpenGroup" ) || aKey.Equals( "CloseGroup" ) || aKey.Equals( "End" ) || aKey.Equals( "OpenSubGroup" ) || aKey.Equals( "CloseSubGroup" ) )
+ continue;
+
+ if( aKey.Equals( "OpenUI" ) )
+ {
+ parseOpenUI( aCurrentLine );
+ continue;
+ }
+ else if( aKey.Equals( "OrderDependency" ) )
+ {
+ parseOrderDependency( aCurrentLine );
+ continue;
+ }
+ else if( aKey.Equals( "UIConstraints" ) || aKey.Equals( "NonUIConstraints" ) )
+ continue; // parsed in pass 2
+ else if( aKey.Equals( "CustomPageSize" ) ) // currently not handled
+ continue;
+
+ // default values are parsed in pass 2
+ if( aKey.CompareTo( "Default", 7 ) == COMPARE_EQUAL )
+ continue;
+
+ bool bQuery = false;
+ if( aKey.GetChar( 0 ) == '?' )
+ {
+ aKey.Erase( 0, 1 );
+ bQuery = true;
+ }
+
+ String aUniKey( aKey, RTL_TEXTENCODING_MS_1252 );
+ // handle CUPS extension for globalized PPDs
+ bool bIsGlobalizedLine = false;
+ com::sun::star::lang::Locale aTransLocale;
+ if( ( aUniKey.Len() > 3 && aUniKey.GetChar( 2 ) == '.' ) ||
+ ( aUniKey.Len() > 5 && aUniKey.GetChar( 2 ) == '_' && aUniKey.GetChar( 5 ) == '.' ) )
+ {
+ if( aUniKey.GetChar( 2 ) == '.' )
+ {
+ aTransLocale.Language = aUniKey.Copy( 0, 2 );
+ aUniKey = aUniKey.Copy( 3 );
+ }
+ else
+ {
+ aTransLocale.Language = aUniKey.Copy( 0, 2 );
+ aTransLocale.Country = aUniKey.Copy( 3, 2 );
+ aUniKey = aUniKey.Copy( 6 );
+ }
+ bIsGlobalizedLine = true;
+ }
+
+ String aOption;
+ nPos = aCurrentLine.Search( ':' );
+ if( nPos != STRING_NOTFOUND )
+ {
+ aOption = String( aCurrentLine.Copy( 1, nPos-1 ), RTL_TEXTENCODING_MS_1252 );
+ aOption = GetCommandLineToken( 1, aOption );
+ int nTransPos = aOption.Search( '/' );
+ if( nTransPos != STRING_NOTFOUND )
+ aOption.Erase( nTransPos );
+ }
+
+ PPDValueType eType = eNo;
+ String aValue;
+ rtl::OUString aOptionTranslation;
+ rtl::OUString aValueTranslation;
+ if( nPos != STRING_NOTFOUND )
+ {
+ // found a colon, there may be an option
+ ByteString aLine = aCurrentLine.Copy( 1, nPos-1 );
+ aLine = WhitespaceToSpace( aLine );
+ int nTransPos = aLine.Search( '/' );
+ if( nTransPos != STRING_NOTFOUND )
+ aOptionTranslation = handleTranslation( aLine.Copy( nTransPos+1 ), bIsGlobalizedLine );
+
+ // read in more lines if necessary for multiline values
+ aLine = aCurrentLine.Copy( nPos+1 );
+ if( aLine.Len() )
+ {
+ while( ! ( aLine.GetTokenCount( '"' ) & 1 ) &&
+ line != rLines.end() )
+ // while there is an even number of tokens; that means
+ // an odd number of doubleqoutes
+ {
+ // copy the newlines also
+ aLine += '\n';
+ aLine += *line;
+ ++line;
+ }
+ }
+ aLine = WhitespaceToSpace( aLine );
+
+ // #i100644# handle a missing value (actually a broken PPD)
+ if( ! aLine.Len() )
+ {
+ if( aOption.Len() &&
+ aUniKey.CompareToAscii( "JCL", 3 ) != COMPARE_EQUAL )
+ eType = eInvocation;
+ else
+ eType = eQuoted;
+ }
+ // check for invocation or quoted value
+ else if( aLine.GetChar(0) == '"' )
+ {
+ aLine.Erase( 0, 1 );
+ nTransPos = aLine.Search( '"' );
+ aValue = String( aLine.Copy( 0, nTransPos ), RTL_TEXTENCODING_MS_1252 );
+ // after the second doublequote can follow a / and a translation
+ aValueTranslation = handleTranslation( aLine.Copy( nTransPos+2 ), bIsGlobalizedLine );
+ // check for quoted value
+ if( aOption.Len() &&
+ aUniKey.CompareToAscii( "JCL", 3 ) != COMPARE_EQUAL )
+ eType = eInvocation;
+ else
+ eType = eQuoted;
+ }
+ // check for symbol value
+ else if( aLine.GetChar(0) == '^' )
+ {
+ aLine.Erase( 0, 1 );
+ aValue = String( aLine, RTL_TEXTENCODING_MS_1252 );
+ eType = eSymbol;
+ }
+ else
+ {
+ // must be a string value then
+ // strictly this is false because string values
+ // can contain any whitespace which is reduced
+ // to one space by now
+ // who cares ...
+ nTransPos = aLine.Search( '/' );
+ if( nTransPos == STRING_NOTFOUND )
+ nTransPos = aLine.Len();
+ aValue = String( aLine.Copy( 0, nTransPos ), RTL_TEXTENCODING_MS_1252 );
+ aValueTranslation = handleTranslation( aLine.Copy( nTransPos+1 ), bIsGlobalizedLine );
+ eType = eString;
+ }
+ }
+
+ // handle globalized PPD entries
+ if( bIsGlobalizedLine )
+ {
+ // handle main key translations of form:
+ // *ll_CC.Translation MainKeyword/translated text: ""
+ if( aUniKey.EqualsAscii( "Translation" ) )
+ {
+ m_pTranslator->insertKey( aOption, aOptionTranslation, aTransLocale );
+ }
+ // handle options translations of for:
+ // *ll_CC.MainKeyword OptionKeyword/translated text: ""
+ else
+ {
+ m_pTranslator->insertOption( aUniKey, aOption, aOptionTranslation, aTransLocale );
+ }
+ continue;
+ }
+
+ PPDKey* pKey = NULL;
+ keyit = m_aKeys.find( aUniKey );
+ if( keyit == m_aKeys.end() )
+ {
+ pKey = new PPDKey( aUniKey );
+ insertKey( aUniKey, pKey );
+ }
+ else
+ pKey = keyit->second;
+
+ if( eType == eNo && bQuery )
+ continue;
+
+ PPDValue* pValue = pKey->insertValue( aOption );
+ if( ! pValue )
+ continue;
+ pValue->m_eType = eType;
+ pValue->m_aValue = aValue;
+
+ if( aOptionTranslation.getLength() )
+ m_pTranslator->insertOption( aUniKey, aOption, aOptionTranslation, aTransLocale );
+ if( aValueTranslation.getLength() )
+ m_pTranslator->insertValue( aUniKey, aOption, aValue, aValueTranslation, aTransLocale );
+
+ // eventually update query and remove from option list
+ if( bQuery && pKey->m_bQueryValue == FALSE )
+ {
+ pKey->m_aQueryValue = *pValue;
+ pKey->m_bQueryValue = true;
+ pKey->eraseValue( pValue->m_aOption );
+ }
+ }
+
+ // second pass: fill in defaults
+ for( line = rLines.begin(); line != rLines.end(); ++line )
+ {
+ ByteString aLine( *line );
+ if( aLine.CompareTo( "*Default", 8 ) == COMPARE_EQUAL )
+ {
+ String aKey( aLine.Copy( 8 ), RTL_TEXTENCODING_MS_1252 );
+ USHORT nPos = aKey.Search( ':' );
+ if( nPos != STRING_NOTFOUND )
+ {
+ aKey.Erase( nPos );
+ String aOption( WhitespaceToSpace( aLine.Copy( nPos+9 ) ), RTL_TEXTENCODING_MS_1252 );
+ keyit = m_aKeys.find( aKey );
+ if( keyit != m_aKeys.end() )
+ {
+ PPDKey* pKey = keyit->second;
+ const PPDValue* pDefValue = pKey->getValue( aOption );
+ if( pKey->m_pDefaultValue == NULL )
+ pKey->m_pDefaultValue = pDefValue;
+ }
+ else
+ {
+ // some PPDs contain defaults for keys that
+ // do not exist otherwise
+ // (example: DefaultResolution)
+ // so invent that key here and have a default value
+ PPDKey* pKey = new PPDKey( aKey );
+ PPDValue* pNewValue = pKey->insertValue( aOption );
+ pNewValue->m_eType = eInvocation; // or what ?
+ insertKey( aKey, pKey );
+ }
+ }
+ }
+ else if( aLine.CompareTo( "*UIConstraints", 14 ) == COMPARE_EQUAL ||
+ aLine.CompareTo( "*NonUIConstraints", 17 ) == COMPARE_EQUAL )
+ parseConstraint( aLine );
+
+ }
+}
+
+void PPDParser::parseOpenUI( const ByteString& rLine )
+{
+ String aTranslation;
+ ByteString aKey = rLine;
+
+ int nPos = aKey.Search( ':' );
+ if( nPos != STRING_NOTFOUND )
+ aKey.Erase( nPos );
+ nPos = aKey.Search( '/' );
+ if( nPos != STRING_NOTFOUND )
+ {
+ aTranslation = handleTranslation( aKey.Copy( nPos + 1 ), false );
+ aKey.Erase( nPos );
+ }
+ aKey = GetCommandLineToken( 1, aKey );
+ aKey.Erase( 0, 1 );
+
+ String aUniKey( aKey, RTL_TEXTENCODING_MS_1252 );
+ PPDParser::hash_type::const_iterator keyit = m_aKeys.find( aUniKey );
+ PPDKey* pKey;
+ if( keyit == m_aKeys.end() )
+ {
+ pKey = new PPDKey( aUniKey );
+ insertKey( aUniKey, pKey );
+ }
+ else
+ pKey = keyit->second;
+
+ pKey->m_bUIOption = true;
+ m_pTranslator->insertKey( pKey->getKey(), aTranslation );
+
+ ByteString aValue = WhitespaceToSpace( rLine.GetToken( 1, ':' ) );
+ if( aValue.CompareIgnoreCaseToAscii( "boolean" ) == COMPARE_EQUAL )
+ pKey->m_eUIType = PPDKey::Boolean;
+ else if( aValue.CompareIgnoreCaseToAscii( "pickmany" ) == COMPARE_EQUAL )
+ pKey->m_eUIType = PPDKey::PickMany;
+ else
+ pKey->m_eUIType = PPDKey::PickOne;
+}
+
+void PPDParser::parseOrderDependency( const ByteString& rLine )
+{
+ ByteString aLine( rLine );
+ int nPos = aLine.Search( ':' );
+ if( nPos != STRING_NOTFOUND )
+ aLine.Erase( 0, nPos+1 );
+
+ int nOrder = GetCommandLineToken( 0, aLine ).ToInt32();
+ ByteString aSetup = GetCommandLineToken( 1, aLine );
+ String aKey( GetCommandLineToken( 2, aLine ), RTL_TEXTENCODING_MS_1252 );
+ if( aKey.GetChar( 0 ) != '*' )
+ return; // invalid order depency
+ aKey.Erase( 0, 1 );
+
+ PPDKey* pKey;
+ PPDParser::hash_type::const_iterator keyit = m_aKeys.find( aKey );
+ if( keyit == m_aKeys.end() )
+ {
+ pKey = new PPDKey( aKey );
+ insertKey( aKey, pKey );
+ }
+ else
+ pKey = keyit->second;
+
+ pKey->m_nOrderDependency = nOrder;
+ if( aSetup.Equals( "ExitServer" ) )
+ pKey->m_eSetupType = PPDKey::ExitServer;
+ else if( aSetup.Equals( "Prolog" ) )
+ pKey->m_eSetupType = PPDKey::Prolog;
+ else if( aSetup.Equals( "DocumentSetup" ) )
+ pKey->m_eSetupType = PPDKey::DocumentSetup;
+ else if( aSetup.Equals( "PageSetup" ) )
+ pKey->m_eSetupType = PPDKey::PageSetup;
+ else if( aSetup.Equals( "JCLSetup" ) )
+ pKey->m_eSetupType = PPDKey::JCLSetup;
+ else
+ pKey->m_eSetupType = PPDKey::AnySetup;
+}
+
+void PPDParser::parseConstraint( const ByteString& rLine )
+{
+ bool bFailed = false;
+
+ String aLine( rLine, RTL_TEXTENCODING_MS_1252 );
+ aLine.Erase( 0, rLine.Search( ':' )+1 );
+ PPDConstraint aConstraint;
+ int nTokens = GetCommandLineTokenCount( aLine );
+ for( int i = 0; i < nTokens; i++ )
+ {
+ String aToken = GetCommandLineToken( i, aLine );
+ if( aToken.GetChar( 0 ) == '*' )
+ {
+ aToken.Erase( 0, 1 );
+ if( aConstraint.m_pKey1 )
+ aConstraint.m_pKey2 = getKey( aToken );
+ else
+ aConstraint.m_pKey1 = getKey( aToken );
+ }
+ else
+ {
+ if( aConstraint.m_pKey2 )
+ {
+ if( ! ( aConstraint.m_pOption2 = aConstraint.m_pKey2->getValue( aToken ) ) )
+ bFailed = true;
+ }
+ else if( aConstraint.m_pKey1 )
+ {
+ if( ! ( aConstraint.m_pOption1 = aConstraint.m_pKey1->getValue( aToken ) ) )
+ bFailed = true;
+ }
+ else
+ // constraint for nonexistent keys; this happens
+ // e.g. in HP4PLUS3 (#75636#)
+ bFailed = true;
+ }
+ }
+ // there must be two keywords
+ if( ! aConstraint.m_pKey1 || ! aConstraint.m_pKey2 || bFailed )
+ {
+#ifdef __DEBUG
+ fprintf( stderr, "Warning: constraint \"%s\" is invalid\n", rLine.GetStr() );
+#endif
+ }
+ else
+ m_aConstraints.push_back( aConstraint );
+}
+
+String PPDParser::getDefaultPaperDimension() const
+{
+ if( m_pDefaultPaperDimension )
+ return m_pDefaultPaperDimension->m_aOption;
+
+ return String();
+}
+
+bool PPDParser::getMargins(
+ const String& rPaperName,
+ int& rLeft, int& rRight,
+ int& rUpper, int& rLower ) const
+{
+ if( ! m_pImageableAreas || ! m_pPaperDimensions )
+ return false;
+
+ int nPDim=-1, nImArea=-1, i;
+ for( i = 0; i < m_pImageableAreas->countValues(); i++ )
+ if( rPaperName == m_pImageableAreas->getValue( i )->m_aOption )
+ nImArea = i;
+ for( i = 0; i < m_pPaperDimensions->countValues(); i++ )
+ if( rPaperName == m_pPaperDimensions->getValue( i )->m_aOption )
+ nPDim = i;
+ if( nPDim == -1 || nImArea == -1 )
+ return false;
+
+ double ImLLx, ImLLy, ImURx, ImURy;
+ double PDWidth, PDHeight;
+ String aArea = m_pImageableAreas->getValue( nImArea )->m_aValue;
+ ImLLx = StringToDouble( GetCommandLineToken( 0, aArea ) );
+ ImLLy = StringToDouble( GetCommandLineToken( 1, aArea ) );
+ ImURx = StringToDouble( GetCommandLineToken( 2, aArea ) );
+ ImURy = StringToDouble( GetCommandLineToken( 3, aArea ) );
+// sscanf( m_pImageableAreas->getValue( nImArea )->m_aValue.GetStr(),
+// "%lg%lg%lg%lg", &ImLLx, &ImLLy, &ImURx, &ImURy );
+ aArea = m_pPaperDimensions->getValue( nPDim )->m_aValue;
+ PDWidth = StringToDouble( GetCommandLineToken( 0, aArea ) );
+ PDHeight = StringToDouble( GetCommandLineToken( 1, aArea ) );
+// sscanf( m_pPaperDimensions->getValue( nPDim )->m_aValue.GetStr(),
+// "%lg%lg", &PDWidth, &PDHeight );
+ rLeft = (int)(ImLLx + 0.5);
+ rLower = (int)(ImLLy + 0.5);
+ rUpper = (int)(PDHeight - ImURy + 0.5);
+ rRight = (int)(PDWidth - ImURx + 0.5);
+
+ return true;
+}
+
+bool PPDParser::getPaperDimension(
+ const String& rPaperName,
+ int& rWidth, int& rHeight ) const
+{
+ if( ! m_pPaperDimensions )
+ return false;
+
+ int nPDim=-1;
+ for( int i = 0; i < m_pPaperDimensions->countValues(); i++ )
+ if( rPaperName == m_pPaperDimensions->getValue( i )->m_aOption )
+ nPDim = i;
+ if( nPDim == -1 )
+ return false;
+
+ double PDWidth, PDHeight;
+ String aArea = m_pPaperDimensions->getValue( nPDim )->m_aValue;
+ PDWidth = StringToDouble( GetCommandLineToken( 0, aArea ) );
+ PDHeight = StringToDouble( GetCommandLineToken( 1, aArea ) );
+ rHeight = (int)(PDHeight + 0.5);
+ rWidth = (int)(PDWidth + 0.5);
+
+ return true;
+}
+
+String PPDParser::matchPaper( int nWidth, int nHeight ) const
+{
+ if( ! m_pPaperDimensions )
+ return String();
+
+ int nPDim = -1;
+ double PDWidth, PDHeight;
+ double fSort = 2e36, fNewSort;
+
+ for( int i = 0; i < m_pPaperDimensions->countValues(); i++ )
+ {
+ String aArea = m_pPaperDimensions->getValue( i )->m_aValue;
+ PDWidth = StringToDouble( GetCommandLineToken( 0, aArea ) );
+ PDHeight = StringToDouble( GetCommandLineToken( 1, aArea ) );
+ PDWidth /= (double)nWidth;
+ PDHeight /= (double)nHeight;
+ if( PDWidth >= 0.9 && PDWidth <= 1.1 &&
+ PDHeight >= 0.9 && PDHeight <= 1.1 )
+ {
+ fNewSort =
+ (1.0-PDWidth)*(1.0-PDWidth) + (1.0-PDHeight)*(1.0-PDHeight);
+ if( fNewSort == 0.0 ) // perfect match
+ return m_pPaperDimensions->getValue( i )->m_aOption;
+
+ if( fNewSort < fSort )
+ {
+ fSort = fNewSort;
+ nPDim = i;
+ }
+ }
+ }
+
+ static bool bDontSwap = false;
+ if( nPDim == -1 && ! bDontSwap )
+ {
+ // swap portrait/landscape and try again
+ bDontSwap = true;
+ String rRet = matchPaper( nHeight, nWidth );
+ bDontSwap = false;
+ return rRet;
+ }
+
+ return nPDim != -1 ? m_pPaperDimensions->getValue( nPDim )->m_aOption : String();
+}
+
+String PPDParser::getDefaultInputSlot() const
+{
+ if( m_pDefaultInputSlot )
+ return m_pDefaultInputSlot->m_aValue;
+ return String();
+}
+
+String PPDParser::getSlot( int nSlot ) const
+{
+ if( ! m_pInputSlots )
+ return String();
+
+ if( nSlot > 0 && nSlot < m_pInputSlots->countValues() )
+ return m_pInputSlots->getValue( nSlot )->m_aOption;
+ else if( m_pInputSlots->countValues() > 0 )
+ return m_pInputSlots->getValue( (ULONG)0 )->m_aOption;
+
+ return String();
+}
+
+String PPDParser::getSlotCommand( int nSlot ) const
+{
+ if( ! m_pInputSlots )
+ return String();
+
+ if( nSlot > 0 && nSlot < m_pInputSlots->countValues() )
+ return m_pInputSlots->getValue( nSlot )->m_aValue;
+ else if( m_pInputSlots->countValues() > 0 )
+ return m_pInputSlots->getValue( (ULONG)0 )->m_aValue;
+
+ return String();
+}
+
+String PPDParser::getSlotCommand( const String& rSlot ) const
+{
+ if( ! m_pInputSlots )
+ return String();
+
+ for( int i=0; i < m_pInputSlots->countValues(); i++ )
+ {
+ const PPDValue* pValue = m_pInputSlots->getValue( i );
+ if( pValue->m_aOption == rSlot )
+ return pValue->m_aValue;
+ }
+ return String();
+}
+
+String PPDParser::getPaperDimension( int nPaperDimension ) const
+{
+ if( ! m_pPaperDimensions )
+ return String();
+
+ if( nPaperDimension > 0 && nPaperDimension < m_pPaperDimensions->countValues() )
+ return m_pPaperDimensions->getValue( nPaperDimension )->m_aOption;
+ else if( m_pPaperDimensions->countValues() > 0 )
+ return m_pPaperDimensions->getValue( (ULONG)0 )->m_aOption;
+
+ return String();
+}
+
+String PPDParser::getPaperDimensionCommand( int nPaperDimension ) const
+{
+ if( ! m_pPaperDimensions )
+ return String();
+
+ if( nPaperDimension > 0 && nPaperDimension < m_pPaperDimensions->countValues() )
+ return m_pPaperDimensions->getValue( nPaperDimension )->m_aValue;
+ else if( m_pPaperDimensions->countValues() > 0 )
+ return m_pPaperDimensions->getValue( (ULONG)0 )->m_aValue;
+
+ return String();
+}
+
+String PPDParser::getPaperDimensionCommand( const String& rPaperDimension ) const
+{
+ if( ! m_pPaperDimensions )
+ return String();
+
+ for( int i=0; i < m_pPaperDimensions->countValues(); i++ )
+ {
+ const PPDValue* pValue = m_pPaperDimensions->getValue( i );
+ if( pValue->m_aOption == rPaperDimension )
+ return pValue->m_aValue;
+ }
+ return String();
+}
+
+void PPDParser::getResolutionFromString(
+ const String& rString,
+ int& rXRes, int& rYRes ) const
+{
+ int nPos = 0, nDPIPos;
+
+ rXRes = rYRes = 300;
+
+ nDPIPos = rString.SearchAscii( "dpi" );
+ if( nDPIPos != STRING_NOTFOUND )
+ {
+ if( ( nPos = rString.Search( 'x' ) ) != STRING_NOTFOUND )
+ {
+ rXRes = rString.Copy( 0, nPos ).ToInt32();
+ rYRes = rString.GetToken( 1, 'x' ).Erase( nDPIPos - nPos - 1 ).ToInt32();
+ }
+ else
+ rXRes = rYRes = rString.Copy( 0, nDPIPos ).ToInt32();
+ }
+}
+
+void PPDParser::getDefaultResolution( int& rXRes, int& rYRes ) const
+{
+ if( m_pDefaultResolution )
+ {
+ getResolutionFromString( m_pDefaultResolution->m_aValue, rXRes, rYRes );
+ return;
+ }
+
+ rXRes = 300;
+ rYRes = 300;
+}
+
+int PPDParser::getResolutions() const
+{
+ if( ( ! m_pResolutions || m_pResolutions->countValues() == 0 ) &&
+ m_pDefaultResolution )
+ return 1;
+ return m_pResolutions ? m_pResolutions->countValues() : 0;
+}
+
+void PPDParser::getResolution( int nNr, int& rXRes, int& rYRes ) const
+{
+ if( ( ! m_pResolutions || m_pResolutions->countValues() == 0 ) && m_pDefaultResolution && nNr == 0 )
+ {
+ getDefaultResolution( rXRes, rYRes );
+ return;
+ }
+ if( ! m_pResolutions )
+ return;
+
+ getResolutionFromString( m_pResolutions->getValue( nNr )->m_aOption,
+ rXRes, rYRes );
+}
+
+String PPDParser::getResolutionCommand( int nXRes, int nYRes ) const
+{
+ if( ( ! m_pResolutions || m_pResolutions->countValues() == 0 ) && m_pDefaultResolution )
+ return m_pDefaultResolution->m_aValue;
+
+ if( ! m_pResolutions )
+ return String();
+
+ int nX, nY;
+ for( int i = 0; i < m_pResolutions->countValues(); i++ )
+ {
+ getResolutionFromString( m_pResolutions->getValue( i )->m_aOption,
+ nX, nY );
+ if( nX == nXRes && nY == nYRes )
+ return m_pResolutions->getValue( i )->m_aValue;
+ }
+ return String();
+}
+
+String PPDParser::getDefaultDuplexType() const
+{
+ if( m_pDefaultDuplexType )
+ return m_pDefaultDuplexType->m_aValue;
+ return String();
+}
+
+String PPDParser::getDuplex( int nDuplex ) const
+{
+ if( ! m_pDuplexTypes )
+ return String();
+
+ if( nDuplex > 0 && nDuplex < m_pDuplexTypes->countValues() )
+ return m_pDuplexTypes->getValue( nDuplex )->m_aOption;
+ else if( m_pDuplexTypes->countValues() > 0 )
+ return m_pDuplexTypes->getValue( (ULONG)0 )->m_aOption;
+
+ return String();
+}
+
+String PPDParser::getDuplexCommand( int nDuplex ) const
+{
+ if( ! m_pDuplexTypes )
+ return String();
+
+ if( nDuplex > 0 && nDuplex < m_pDuplexTypes->countValues() )
+ return m_pDuplexTypes->getValue( nDuplex )->m_aValue;
+ else if( m_pDuplexTypes->countValues() > 0 )
+ return m_pDuplexTypes->getValue( (ULONG)0 )->m_aValue;
+
+ return String();
+}
+
+String PPDParser::getDuplexCommand( const String& rDuplex ) const
+{
+ if( ! m_pDuplexTypes )
+ return String();
+
+ for( int i=0; i < m_pDuplexTypes->countValues(); i++ )
+ {
+ const PPDValue* pValue = m_pDuplexTypes->getValue( i );
+ if( pValue->m_aOption == rDuplex )
+ return pValue->m_aValue;
+ }
+ return String();
+}
+
+void PPDParser::getFontAttributes(
+ int nFont,
+ String& rEncoding,
+ String& rCharset ) const
+{
+ if( m_pFontList && nFont >= 0 && nFont < m_pFontList->countValues() )
+ {
+ String aAttribs =
+ WhitespaceToSpace( m_pFontList->getValue( nFont )->m_aValue );
+ rEncoding = GetCommandLineToken( 0, aAttribs );
+ rCharset = GetCommandLineToken( 2, aAttribs );
+ }
+}
+
+void PPDParser::getFontAttributes(
+ const String& rFont,
+ String& rEncoding,
+ String& rCharset ) const
+{
+ if( m_pFontList )
+ {
+ for( int i = 0; i < m_pFontList->countValues(); i++ )
+ if( m_pFontList->getValue( i )->m_aOption == rFont )
+ getFontAttributes( i, rEncoding, rCharset );
+ }
+}
+
+String PPDParser::getFont( int nFont ) const
+{
+ if( ! m_pFontList )
+ return String();
+
+ if( nFont >=0 && nFont < m_pFontList->countValues() )
+ return m_pFontList->getValue( nFont )->m_aOption;
+ return String();
+}
+
+rtl::OUString PPDParser::translateKey( const rtl::OUString& i_rKey,
+ const com::sun::star::lang::Locale& i_rLocale ) const
+{
+ rtl::OUString aResult( m_pTranslator->translateKey( i_rKey, i_rLocale ) );
+ if( aResult.getLength() == 0 )
+ aResult = i_rKey;
+ return aResult;
+}
+
+rtl::OUString PPDParser::translateOption( const rtl::OUString& i_rKey,
+ const rtl::OUString& i_rOption,
+ const com::sun::star::lang::Locale& i_rLocale ) const
+{
+ rtl::OUString aResult( m_pTranslator->translateOption( i_rKey, i_rOption, i_rLocale ) );
+ if( aResult.getLength() == 0 )
+ aResult = i_rOption;
+ return aResult;
+}
+
+rtl::OUString PPDParser::translateValue( const rtl::OUString& i_rKey,
+ const rtl::OUString& i_rOption,
+ const rtl::OUString& i_rValue,
+ const com::sun::star::lang::Locale& i_rLocale ) const
+{
+ rtl::OUString aResult( m_pTranslator->translateValue( i_rKey, i_rOption, i_rValue, i_rLocale ) );
+ if( aResult.getLength() == 0 )
+ aResult = i_rValue;
+ return aResult;
+}
+
+/*
+ * PPDKey
+ */
+
+PPDKey::PPDKey( const String& rKey ) :
+ m_aKey( rKey ),
+ m_pDefaultValue( NULL ),
+ m_bQueryValue( false ),
+ m_bUIOption( false ),
+ m_eUIType( PickOne ),
+ m_nOrderDependency( 100 ),
+ m_eSetupType( AnySetup )
+{
+}
+
+// -------------------------------------------------------------------
+
+PPDKey::~PPDKey()
+{
+}
+
+// -------------------------------------------------------------------
+
+const PPDValue* PPDKey::getValue( int n ) const
+{
+ return ((unsigned int)n < m_aOrderedValues.size() && n >= 0) ? m_aOrderedValues[n] : NULL;
+}
+
+// -------------------------------------------------------------------
+
+const PPDValue* PPDKey::getValue( const String& rOption ) const
+{
+ PPDKey::hash_type::const_iterator it = m_aValues.find( rOption );
+ return it != m_aValues.end() ? &it->second : NULL;
+}
+
+// -------------------------------------------------------------------
+
+const PPDValue* PPDKey::getValueCaseInsensitive( const String& rOption ) const
+{
+ const PPDValue* pValue = getValue( rOption );
+ if( ! pValue )
+ {
+ for( size_t n = 0; n < m_aOrderedValues.size() && ! pValue; n++ )
+ if( m_aOrderedValues[n]->m_aOption.EqualsIgnoreCaseAscii( rOption ) )
+ pValue = m_aOrderedValues[n];
+ }
+
+ return pValue;
+}
+
+// -------------------------------------------------------------------
+
+void PPDKey::eraseValue( const String& rOption )
+{
+ PPDKey::hash_type::iterator it = m_aValues.find( rOption );
+ if( it == m_aValues.end() )
+ return;
+
+ for( PPDKey::value_type::iterator vit = m_aOrderedValues.begin(); vit != m_aOrderedValues.end(); ++vit )
+ {
+ if( *vit == &(it->second ) )
+ {
+ m_aOrderedValues.erase( vit );
+ break;
+ }
+ }
+ m_aValues.erase( it );
+}
+
+// -------------------------------------------------------------------
+
+PPDValue* PPDKey::insertValue( const String& rOption )
+{
+ if( m_aValues.find( rOption ) != m_aValues.end() )
+ return NULL;
+
+ PPDValue aValue;
+ aValue.m_aOption = rOption;
+ m_aValues[ rOption ] = aValue;
+ PPDValue* pValue = &m_aValues[rOption];
+ m_aOrderedValues.push_back( pValue );
+ return pValue;
+}
+
+// -------------------------------------------------------------------
+
+/*
+ * PPDContext
+ */
+
+PPDContext::PPDContext( const PPDParser* pParser ) :
+ m_pParser( pParser )
+{
+}
+
+// -------------------------------------------------------------------
+
+PPDContext& PPDContext::operator=( const PPDContext& rCopy )
+{
+ m_pParser = rCopy.m_pParser;
+ m_aCurrentValues = rCopy.m_aCurrentValues;
+ return *this;
+}
+
+// -------------------------------------------------------------------
+
+PPDContext::~PPDContext()
+{
+}
+
+// -------------------------------------------------------------------
+
+const PPDKey* PPDContext::getModifiedKey( int n ) const
+{
+ hash_type::const_iterator it;
+ for( it = m_aCurrentValues.begin(); it != m_aCurrentValues.end() && n--; ++it )
+ ;
+ return it != m_aCurrentValues.end() ? it->first : NULL;
+}
+
+// -------------------------------------------------------------------
+
+void PPDContext::setParser( const PPDParser* pParser )
+{
+ if( pParser != m_pParser )
+ {
+ m_aCurrentValues.clear();
+ m_pParser = pParser;
+ }
+}
+
+// -------------------------------------------------------------------
+
+const PPDValue* PPDContext::getValue( const PPDKey* pKey ) const
+{
+ if( ! m_pParser )
+ return NULL;
+
+ hash_type::const_iterator it;
+ it = m_aCurrentValues.find( pKey );
+ if( it != m_aCurrentValues.end() )
+ return it->second;
+
+ if( ! m_pParser->hasKey( pKey ) )
+ return NULL;
+
+ const PPDValue* pValue = pKey->getDefaultValue();
+ if( ! pValue )
+ pValue = pKey->getValue( 0 );
+
+ return pValue;
+}
+
+// -------------------------------------------------------------------
+
+const PPDValue* PPDContext::setValue( const PPDKey* pKey, const PPDValue* pValue, bool bDontCareForConstraints )
+{
+ if( ! m_pParser || ! pKey )
+ return NULL;
+
+ // pValue can be NULL - it means ignore this option
+
+ if( ! m_pParser->hasKey( pKey ) )
+ return NULL;
+
+ // check constraints
+ if( pValue )
+ {
+ if( bDontCareForConstraints )
+ {
+ m_aCurrentValues[ pKey ] = pValue;
+ }
+ else if( checkConstraints( pKey, pValue, true ) )
+ {
+ m_aCurrentValues[ pKey ] = pValue;
+
+ // after setting this value, check all constraints !
+ hash_type::iterator it = m_aCurrentValues.begin();
+ while( it != m_aCurrentValues.end() )
+ {
+ if( it->first != pKey &&
+ ! checkConstraints( it->first, it->second, false ) )
+ {
+#ifdef __DEBUG
+ fprintf( stderr, "PPDContext::setValue: option %s (%s) is constrained after setting %s to %s\n",
+ it->first->getKey().GetStr(),
+ it->second->m_aOption.GetStr(),
+ pKey->getKey().GetStr(),
+ pValue->m_aOption.GetStr() );
+#endif
+ resetValue( it->first, true );
+ it = m_aCurrentValues.begin();
+ }
+ else
+ ++it;
+ }
+ }
+ }
+ else
+ m_aCurrentValues[ pKey ] = NULL;
+
+ return pValue;
+}
+
+// -------------------------------------------------------------------
+
+bool PPDContext::checkConstraints( const PPDKey* pKey, const PPDValue* pValue )
+{
+ if( ! m_pParser || ! pKey || ! pValue )
+ return false;
+
+ // ensure that this key is already in the list if it exists at all
+ if( m_aCurrentValues.find( pKey ) != m_aCurrentValues.end() )
+ return checkConstraints( pKey, pValue, false );
+
+ // it is not in the list, insert it temporarily
+ bool bRet = false;
+ if( m_pParser->hasKey( pKey ) )
+ {
+ const PPDValue* pDefValue = pKey->getDefaultValue();
+ m_aCurrentValues[ pKey ] = pDefValue;
+ bRet = checkConstraints( pKey, pValue, false );
+ m_aCurrentValues.erase( pKey );
+ }
+
+ return bRet;
+}
+
+// -------------------------------------------------------------------
+
+bool PPDContext::resetValue( const PPDKey* pKey, bool bDefaultable )
+{
+ if( ! pKey || ! m_pParser || ! m_pParser->hasKey( pKey ) )
+ return false;
+
+ const PPDValue* pResetValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "None" ) ) );
+ if( ! pResetValue )
+ pResetValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "False" ) ) );
+ if( ! pResetValue && bDefaultable )
+ pResetValue = pKey->getDefaultValue();
+
+ bool bRet = pResetValue ? ( setValue( pKey, pResetValue ) == pResetValue ? true : false ) : false;
+
+ return bRet;
+}
+
+// -------------------------------------------------------------------
+
+bool PPDContext::checkConstraints( const PPDKey* pKey, const PPDValue* pNewValue, bool bDoReset )
+{
+ if( ! pNewValue )
+ return true;
+
+ // sanity checks
+ if( ! m_pParser )
+ return false;
+
+ if( pKey->getValue( pNewValue->m_aOption ) != pNewValue )
+ return false;
+
+ // None / False and the default can always be set, but be careful !
+ // setting them might influence constrained values
+ if( pNewValue->m_aOption.EqualsAscii( "None" ) || pNewValue->m_aOption.EqualsAscii( "False" ) ||
+ pNewValue == pKey->getDefaultValue() )
+ return true;
+
+ const ::std::list< PPDParser::PPDConstraint >& rConstraints( m_pParser->getConstraints() );
+ for( ::std::list< PPDParser::PPDConstraint >::const_iterator it = rConstraints.begin(); it != rConstraints.end(); ++it )
+ {
+ const PPDKey* pLeft = it->m_pKey1;
+ const PPDKey* pRight = it->m_pKey2;
+ if( ! pLeft || ! pRight || ( pKey != pLeft && pKey != pRight ) )
+ continue;
+
+ const PPDKey* pOtherKey = pKey == pLeft ? pRight : pLeft;
+ const PPDValue* pOtherKeyOption = pKey == pLeft ? it->m_pOption2 : it->m_pOption1;
+ const PPDValue* pKeyOption = pKey == pLeft ? it->m_pOption1 : it->m_pOption2;
+
+ // syntax *Key1 option1 *Key2 option2
+ if( pKeyOption && pOtherKeyOption )
+ {
+ if( pNewValue != pKeyOption )
+ continue;
+ if( pOtherKeyOption == getValue( pOtherKey ) )
+ {
+ return false;
+ }
+ }
+ // syntax *Key1 option *Key2 or *Key1 *Key2 option
+ else if( pOtherKeyOption || pKeyOption )
+ {
+ if( pKeyOption )
+ {
+ if( ! ( pOtherKeyOption = getValue( pOtherKey ) ) )
+ continue; // this should not happen, PPD broken
+
+ if( pKeyOption == pNewValue &&
+ ! pOtherKeyOption->m_aOption.EqualsAscii( "None" ) &&
+ ! pOtherKeyOption->m_aOption.EqualsAscii( "False" ) )
+ {
+ // check if the other value can be reset and
+ // do so if possible
+ if( bDoReset && resetValue( pOtherKey ) )
+ continue;
+
+ return false;
+ }
+ }
+ else if( pOtherKeyOption )
+ {
+ if( getValue( pOtherKey ) == pOtherKeyOption &&
+ ! pNewValue->m_aOption.EqualsAscii( "None" ) &&
+ ! pNewValue->m_aOption.EqualsAscii( "False" ) )
+ return false;
+ }
+ else
+ {
+ // this should not happen, PPD is broken
+ }
+ }
+ // syntax *Key1 *Key2
+ else
+ {
+ const PPDValue* pOtherValue = getValue( pOtherKey );
+ if( ! pOtherValue->m_aOption.EqualsAscii( "None" ) &&
+ ! pOtherValue->m_aOption.EqualsAscii( "False" ) &&
+ ! pNewValue->m_aOption.EqualsAscii( "None" ) &&
+ ! pNewValue->m_aOption.EqualsAscii( "False" ) )
+ return false;
+ }
+ }
+ return true;
+}
+
+// -------------------------------------------------------------------
+
+void PPDContext::getUnconstrainedValues( const PPDKey* pKey, ::std::list< const PPDValue* >& rValues )
+{
+ rValues.clear();
+
+ if( ! m_pParser || ! pKey || ! m_pParser->hasKey( pKey ) )
+ return;
+
+ int nValues = pKey->countValues();
+ for( int i = 0; i < nValues; i++ )
+ {
+ const PPDValue* pValue = pKey->getValue( i );
+ if( checkConstraints( pKey, pValue ) )
+ rValues.push_back( pValue );
+ }
+}
+
+
+// -------------------------------------------------------------------
+
+void* PPDContext::getStreamableBuffer( ULONG& rBytes ) const
+{
+ rBytes = 0;
+ if( ! m_aCurrentValues.size() )
+ return NULL;
+ hash_type::const_iterator it;
+ for( it = m_aCurrentValues.begin(); it != m_aCurrentValues.end(); ++it )
+ {
+ ByteString aCopy( it->first->getKey(), RTL_TEXTENCODING_MS_1252 );
+ rBytes += aCopy.Len();
+ rBytes += 1; // for ':'
+ if( it->second )
+ {
+ aCopy = ByteString( it->second->m_aOption, RTL_TEXTENCODING_MS_1252 );
+ rBytes += aCopy.Len();
+ }
+ else
+ rBytes += 4;
+ rBytes += 1; // for '\0'
+ }
+ rBytes += 1;
+ void* pBuffer = new char[ rBytes ];
+ memset( pBuffer, 0, rBytes );
+ char* pRun = (char*)pBuffer;
+ for( it = m_aCurrentValues.begin(); it != m_aCurrentValues.end(); ++it )
+ {
+ ByteString aCopy( it->first->getKey(), RTL_TEXTENCODING_MS_1252 );
+ int nBytes = aCopy.Len();
+ memcpy( pRun, aCopy.GetBuffer(), nBytes );
+ pRun += nBytes;
+ *pRun++ = ':';
+ if( it->second )
+ aCopy = ByteString( it->second->m_aOption, RTL_TEXTENCODING_MS_1252 );
+ else
+ aCopy = "*nil";
+ nBytes = aCopy.Len();
+ memcpy( pRun, aCopy.GetBuffer(), nBytes );
+ pRun += nBytes;
+
+ *pRun++ = 0;
+ }
+ return pBuffer;
+}
+
+// -------------------------------------------------------------------
+
+void PPDContext::rebuildFromStreamBuffer( void* pBuffer, ULONG nBytes )
+{
+ if( ! m_pParser )
+ return;
+
+ m_aCurrentValues.clear();
+
+ char* pRun = (char*)pBuffer;
+ while( nBytes && *pRun )
+ {
+ ByteString aLine( pRun );
+ int nPos = aLine.Search( ':' );
+ if( nPos != STRING_NOTFOUND )
+ {
+ const PPDKey* pKey = m_pParser->getKey( String( aLine.Copy( 0, nPos ), RTL_TEXTENCODING_MS_1252 ) );
+ if( pKey )
+ {
+ const PPDValue* pValue = NULL;
+ String aOption( aLine.Copy( nPos+1 ), RTL_TEXTENCODING_MS_1252 );
+ if( ! aOption.EqualsAscii( "*nil" ) )
+ pValue = pKey->getValue( aOption );
+ m_aCurrentValues[ pKey ] = pValue;
+#ifdef __DEBUG
+ fprintf( stderr, "PPDContext::rebuildFromStreamBuffer: read PPDKeyValue { %s, %s }\n", pKV->m_pKey->getKey().GetStr(), pKV->m_pCurrentValue ? pKV->m_pCurrentValue->m_aOption.GetStr() : "<nil>" );
+#endif
+ }
+ }
+ nBytes -= aLine.Len()+1;
+ pRun += aLine.Len()+1;
+ }
+}
+
+// -------------------------------------------------------------------
+
+int PPDContext::getRenderResolution() const
+{
+ // initialize to reasonable default, if parser is not set
+ int nDPI = 300;
+ if( m_pParser )
+ {
+ int nDPIx = 300, nDPIy = 300;
+ const PPDKey* pKey = m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Resolution" ) ) );
+ if( pKey )
+ {
+ const PPDValue* pValue = getValue( pKey );
+ if( pValue )
+ m_pParser->getResolutionFromString( pValue->m_aOption, nDPIx, nDPIy );
+ else
+ m_pParser->getDefaultResolution( nDPIx, nDPIy );
+ }
+ else
+ m_pParser->getDefaultResolution( nDPIx, nDPIy );
+
+ nDPI = (nDPIx > nDPIy) ? nDPIx : nDPIy;
+ }
+ return nDPI;
+}
+
+// -------------------------------------------------------------------
+
+void PPDContext::getPageSize( String& rPaper, int& rWidth, int& rHeight ) const
+{
+ // initialize to reasonable default, if parser is not set
+ rPaper = String( RTL_CONSTASCII_USTRINGPARAM( "A4" ) );
+ rWidth = 595;
+ rHeight = 842;
+ if( m_pParser )
+ {
+ const PPDKey* pKey = m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
+ if( pKey )
+ {
+ const PPDValue* pValue = getValue( pKey );
+ if( pValue )
+ {
+ rPaper = pValue->m_aOption;
+ m_pParser->getPaperDimension( rPaper, rWidth, rHeight );
+ }
+ else
+ {
+ rPaper = m_pParser->getDefaultPaperDimension();
+ m_pParser->getDefaultPaperDimension( rWidth, rHeight );
+ }
+ }
+ }
+}
diff --git a/vcl/unx/source/printer/printerinfomanager.cxx b/vcl/unx/source/printer/printerinfomanager.cxx
new file mode 100644
index 000000000000..e1d499c40ca5
--- /dev/null
+++ b/vcl/unx/source/printer/printerinfomanager.cxx
@@ -0,0 +1,1404 @@
+/*************************************************************************
+ *
+ * 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 <unistd.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+#include "cupsmgr.hxx"
+#include "vcl/fontmanager.hxx"
+#include "vcl/strhelper.hxx"
+
+#include "tools/urlobj.hxx"
+#include "tools/stream.hxx"
+#include "tools/debug.hxx"
+#include "tools/config.hxx"
+
+#include "i18npool/paper.hxx"
+
+#include "rtl/strbuf.hxx"
+
+#include "osl/thread.hxx"
+#include "osl/mutex.hxx"
+#include "osl/process.h"
+
+// filename of configuration files
+#define PRINT_FILENAME "psprint.conf"
+// the group of the global defaults
+#define GLOBAL_DEFAULTS_GROUP "__Global_Printer_Defaults__"
+
+#include <hash_set>
+
+using namespace psp;
+using namespace rtl;
+using namespace osl;
+
+namespace psp
+{
+ class SystemQueueInfo : public Thread
+ {
+ mutable Mutex m_aMutex;
+ bool m_bChanged;
+ std::list< PrinterInfoManager::SystemPrintQueue >
+ m_aQueues;
+ OUString m_aCommand;
+
+ virtual void run();
+
+ public:
+ SystemQueueInfo();
+ ~SystemQueueInfo();
+
+ bool hasChanged() const;
+ OUString getCommand() const;
+
+ // sets changed status to false; therefore not const
+ void getSystemQueues( std::list< PrinterInfoManager::SystemPrintQueue >& rQueues );
+ };
+} // namespace
+
+/*
+* class PrinterInfoManager
+*/
+
+// -----------------------------------------------------------------
+
+PrinterInfoManager& PrinterInfoManager::get()
+{
+ static PrinterInfoManager* pManager = NULL;
+
+ if( ! pManager )
+ {
+ pManager = CUPSManager::tryLoadCUPS();
+ if( ! pManager )
+ pManager = new PrinterInfoManager();
+
+ if( pManager )
+ pManager->initialize();
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "PrinterInfoManager::get create Manager of type %d\n", pManager->getType() );
+ #endif
+ }
+
+ return *pManager;
+}
+
+// -----------------------------------------------------------------
+
+PrinterInfoManager::PrinterInfoManager( Type eType ) :
+ m_pQueueInfo( NULL ),
+ m_eType( eType ),
+ m_bUseIncludeFeature( false ),
+ m_bUseJobPatch( true ),
+ m_aSystemDefaultPaper( RTL_CONSTASCII_USTRINGPARAM( "A4" ) ),
+ m_bDisableCUPS( false )
+{
+ if( eType == Default )
+ m_pQueueInfo = new SystemQueueInfo();
+ initSystemDefaultPaper();
+}
+
+// -----------------------------------------------------------------
+
+PrinterInfoManager::~PrinterInfoManager()
+{
+ delete m_pQueueInfo;
+}
+
+// -----------------------------------------------------------------
+
+bool PrinterInfoManager::isCUPSDisabled() const
+{
+ return m_bDisableCUPS;
+}
+
+// -----------------------------------------------------------------
+
+void PrinterInfoManager::setCUPSDisabled( bool bDisable )
+{
+ m_bDisableCUPS = bDisable;
+ writePrinterConfig();
+ // actually we know the printers changed
+ // however this triggers reinitialization the right way
+ checkPrintersChanged( true );
+}
+
+// -----------------------------------------------------------------
+
+void PrinterInfoManager::initSystemDefaultPaper()
+{
+ m_aSystemDefaultPaper = rtl::OStringToOUString(
+ PaperInfo::toPSName(PaperInfo::getSystemDefaultPaper().getPaper()),
+ RTL_TEXTENCODING_UTF8);
+}
+
+// -----------------------------------------------------------------
+
+bool PrinterInfoManager::checkPrintersChanged( bool bWait )
+{
+ // check if files were created, deleted or modified since initialize()
+ ::std::list< WatchFile >::const_iterator it;
+ bool bChanged = false;
+ for( it = m_aWatchFiles.begin(); it != m_aWatchFiles.end() && ! bChanged; ++it )
+ {
+ DirectoryItem aItem;
+ if( DirectoryItem::get( it->m_aFilePath, aItem ) )
+ {
+ if( it->m_aModified.Seconds != 0 )
+ bChanged = true; // file probably has vanished
+ }
+ else
+ {
+ FileStatus aStatus( FileStatusMask_ModifyTime );
+ if( aItem.getFileStatus( aStatus ) )
+ bChanged = true; // unlikely but not impossible
+ else
+ {
+ TimeValue aModified = aStatus.getModifyTime();
+ if( aModified.Seconds != it->m_aModified.Seconds )
+ bChanged = true;
+ }
+ }
+ }
+
+ if( bWait && m_pQueueInfo )
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "syncing printer discovery thread\n" );
+ #endif
+ m_pQueueInfo->join();
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "done: syncing printer discovery thread\n" );
+ #endif
+ }
+
+ if( ! bChanged && m_pQueueInfo )
+ bChanged = m_pQueueInfo->hasChanged();
+ if( bChanged )
+ {
+ initialize();
+ }
+
+ return bChanged;
+}
+
+// -----------------------------------------------------------------
+
+void PrinterInfoManager::initialize()
+{
+ m_bUseIncludeFeature = false;
+ rtl_TextEncoding aEncoding = gsl_getSystemTextEncoding();
+ m_aPrinters.clear();
+ m_aWatchFiles.clear();
+ OUString aDefaultPrinter;
+
+ // first initialize the global defaults
+ // have to iterate over all possible files
+ // there should be only one global setup section in all
+ // available config files
+ m_aGlobalDefaults = PrinterInfo();
+
+ // need a parser for the PPDContext. generic printer should do.
+ m_aGlobalDefaults.m_pParser = PPDParser::getParser( String( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) ) );
+ m_aGlobalDefaults.m_aContext.setParser( m_aGlobalDefaults.m_pParser );
+ m_aGlobalDefaults.m_bPerformFontSubstitution = true;
+ m_bDisableCUPS = false;
+
+ if( ! m_aGlobalDefaults.m_pParser )
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "Error: no default PPD file SGENPRT available, shutting down psprint...\n" );
+ #endif
+ return;
+ }
+
+ std::list< OUString > aDirList;
+ psp::getPrinterPathList( aDirList, NULL );
+ std::list< OUString >::const_iterator print_dir_it;
+ for( print_dir_it = aDirList.begin(); print_dir_it != aDirList.end(); ++print_dir_it )
+ {
+ INetURLObject aFile( *print_dir_it, INET_PROT_FILE, INetURLObject::ENCODE_ALL );
+ aFile.Append( String( RTL_CONSTASCII_USTRINGPARAM( PRINT_FILENAME ) ) );
+ Config aConfig( aFile.PathToFileName() );
+ if( aConfig.HasGroup( GLOBAL_DEFAULTS_GROUP ) )
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "found global defaults in %s\n", OUStringToOString( aFile.PathToFileName(), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+ #endif
+ aConfig.SetGroup( GLOBAL_DEFAULTS_GROUP );
+
+ ByteString aValue( aConfig.ReadKey( "Copies" ) );
+ if( aValue.Len() )
+ m_aGlobalDefaults.m_nCopies = aValue.ToInt32();
+
+ aValue = aConfig.ReadKey( "Orientation" );
+ if( aValue.Len() )
+ m_aGlobalDefaults.m_eOrientation = aValue.EqualsIgnoreCaseAscii( "Landscape" ) ? orientation::Landscape : orientation::Portrait;
+
+ aValue = aConfig.ReadKey( "MarginAdjust" );
+ if( aValue.Len() )
+ {
+ m_aGlobalDefaults.m_nLeftMarginAdjust = aValue.GetToken( 0, ',' ).ToInt32();
+ m_aGlobalDefaults.m_nRightMarginAdjust = aValue.GetToken( 1, ',' ).ToInt32();
+ m_aGlobalDefaults.m_nTopMarginAdjust = aValue.GetToken( 2, ',' ).ToInt32();
+ m_aGlobalDefaults.m_nBottomMarginAdjust = aValue.GetToken( 3, ',' ).ToInt32();
+ }
+
+ aValue = aConfig.ReadKey( "ColorDepth", "24" );
+ if( aValue.Len() )
+ m_aGlobalDefaults.m_nColorDepth = aValue.ToInt32();
+
+ aValue = aConfig.ReadKey( "ColorDevice" );
+ if( aValue.Len() )
+ m_aGlobalDefaults.m_nColorDevice = aValue.ToInt32();
+
+ aValue = aConfig.ReadKey( "PSLevel" );
+ if( aValue.Len() )
+ m_aGlobalDefaults.m_nPSLevel = aValue.ToInt32();
+
+ aValue = aConfig.ReadKey( "PerformFontSubstitution" );
+ if( aValue.Len() )
+ {
+ if( ! aValue.Equals( "0" ) && ! aValue.EqualsIgnoreCaseAscii( "false" ) )
+ m_aGlobalDefaults.m_bPerformFontSubstitution = true;
+ else
+ m_aGlobalDefaults.m_bPerformFontSubstitution = false;
+ }
+
+ aValue = aConfig.ReadKey( "DisableCUPS" );
+ if( aValue.Len() )
+ {
+ if( aValue.Equals( "1" ) || aValue.EqualsIgnoreCaseAscii( "true" ) )
+ m_bDisableCUPS = true;
+ else
+ m_bDisableCUPS = false;
+ }
+
+ // get the PPDContext of global JobData
+ for( int nKey = 0; nKey < aConfig.GetKeyCount(); nKey++ )
+ {
+ ByteString aKey( aConfig.GetKeyName( nKey ) );
+ if( aKey.CompareTo( "PPD_", 4 ) == COMPARE_EQUAL )
+ {
+ aValue = aConfig.ReadKey( aKey );
+ const PPDKey* pKey = m_aGlobalDefaults.m_pParser->getKey( String( aKey.Copy( 4 ), RTL_TEXTENCODING_ISO_8859_1 ) );
+ if( pKey )
+ {
+ m_aGlobalDefaults.m_aContext.
+ setValue( pKey,
+ aValue.Equals( "*nil" ) ? NULL : pKey->getValue( String( aValue, RTL_TEXTENCODING_ISO_8859_1 ) ),
+ TRUE );
+ }
+ }
+ else if( aKey.Len() > 10 && aKey.CompareTo("SubstFont_", 10 ) == COMPARE_EQUAL )
+ {
+ aValue = aConfig.ReadKey( aKey );
+ m_aGlobalDefaults.m_aFontSubstitutes[ OStringToOUString( aKey.Copy( 10 ), RTL_TEXTENCODING_ISO_8859_1 ) ] = OStringToOUString( aValue, RTL_TEXTENCODING_ISO_8859_1 );
+ }
+ }
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "global settings: fontsubst = %s, %d substitutes\n", m_aGlobalDefaults.m_bPerformFontSubstitution ? "true" : "false", m_aGlobalDefaults.m_aFontSubstitutes.size() );
+ #endif
+ }
+ }
+ setDefaultPaper( m_aGlobalDefaults.m_aContext );
+ fillFontSubstitutions( m_aGlobalDefaults );
+
+ // now collect all available printers
+ for( print_dir_it = aDirList.begin(); print_dir_it != aDirList.end(); ++print_dir_it )
+ {
+ INetURLObject aDir( *print_dir_it, INET_PROT_FILE, INetURLObject::ENCODE_ALL );
+ INetURLObject aFile( aDir );
+ aFile.Append( String( RTL_CONSTASCII_USTRINGPARAM( PRINT_FILENAME ) ) );
+
+ // check directory validity
+ OUString aUniPath;
+ FileBase::getFileURLFromSystemPath( aDir.PathToFileName(), aUniPath );
+ Directory aDirectory( aUniPath );
+ if( aDirectory.open() )
+ continue;
+ aDirectory.close();
+
+
+ FileBase::getFileURLFromSystemPath( aFile.PathToFileName(), aUniPath );
+ FileStatus aStatus( FileStatusMask_ModifyTime );
+ DirectoryItem aItem;
+
+ // setup WatchFile list
+ WatchFile aWatchFile;
+ aWatchFile.m_aFilePath = aUniPath;
+ if( ! DirectoryItem::get( aUniPath, aItem ) &&
+ ! aItem.getFileStatus( aStatus ) )
+ {
+ aWatchFile.m_aModified = aStatus.getModifyTime();
+ }
+ else
+ {
+ aWatchFile.m_aModified.Seconds = 0;
+ aWatchFile.m_aModified.Nanosec = 0;
+ }
+ m_aWatchFiles.push_back( aWatchFile );
+
+ Config aConfig( aFile.PathToFileName() );
+ for( int nGroup = 0; nGroup < aConfig.GetGroupCount(); nGroup++ )
+ {
+ aConfig.SetGroup( aConfig.GetGroupName( nGroup ) );
+ ByteString aValue = aConfig.ReadKey( "Printer" );
+ if( aValue.Len() )
+ {
+ OUString aPrinterName;
+
+ int nNamePos = aValue.Search( '/' );
+ // check for valid value of "Printer"
+ if( nNamePos == STRING_NOTFOUND )
+ continue;
+
+ Printer aPrinter;
+ // initialize to global defaults
+ aPrinter.m_aInfo = m_aGlobalDefaults;
+ // global settings do not default the printer substitution
+ // list ! the substitution list in there is only used for
+ // newly created printers
+ aPrinter.m_aInfo.m_aFontSubstitutes.clear();
+ aPrinter.m_aInfo.m_aFontSubstitutions.clear();
+
+ aPrinterName = String( aValue.Copy( nNamePos+1 ), RTL_TEXTENCODING_UTF8 );
+ aPrinter.m_aInfo.m_aPrinterName = aPrinterName;
+ aPrinter.m_aInfo.m_aDriverName = String( aValue.Copy( 0, nNamePos ), RTL_TEXTENCODING_UTF8 );
+
+ // set parser, merge settings
+ // don't do this for CUPS printers as this is done
+ // by the CUPS system itself
+ if( aPrinter.m_aInfo.m_aDriverName.compareToAscii( "CUPS:", 5 ) != 0 )
+ {
+ aPrinter.m_aInfo.m_pParser = PPDParser::getParser( aPrinter.m_aInfo.m_aDriverName );
+ aPrinter.m_aInfo.m_aContext.setParser( aPrinter.m_aInfo.m_pParser );
+ // note: setParser also purges the context
+
+ // ignore this printer if its driver is not found
+ if( ! aPrinter.m_aInfo.m_pParser )
+ continue;
+
+ // merge the ppd context keys if the printer has the same keys and values
+ // this is a bit tricky, since it involves mixing two PPDs
+ // without constraints which might end up badly
+ // this feature should be use with caution
+ // it is mainly to select default paper sizes for new printers
+ for( int nPPDValueModified = 0; nPPDValueModified < m_aGlobalDefaults.m_aContext.countValuesModified(); nPPDValueModified++ )
+ {
+ const PPDKey* pDefKey = m_aGlobalDefaults.m_aContext.getModifiedKey( nPPDValueModified );
+ const PPDValue* pDefValue = m_aGlobalDefaults.m_aContext.getValue( pDefKey );
+ const PPDKey* pPrinterKey = pDefKey ? aPrinter.m_aInfo.m_pParser->getKey( pDefKey->getKey() ) : NULL;
+ if( pDefKey && pPrinterKey )
+ // at least the options exist in both PPDs
+ {
+ if( pDefValue )
+ {
+ const PPDValue* pPrinterValue = pPrinterKey->getValue( pDefValue->m_aOption );
+ if( pPrinterValue )
+ // the printer has a corresponding option for the key
+ aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, pPrinterValue );
+ }
+ else
+ aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, NULL );
+ }
+ }
+
+ aValue = aConfig.ReadKey( "Command" );
+ // no printer without a command
+ if( ! aValue.Len() )
+ {
+ /* TODO:
+ * porters: please append your platform to the Solaris
+ * case if your platform has SystemV printing per default.
+ */
+ #if defined SOLARIS
+ aValue = "lp";
+ #else
+ aValue = "lpr";
+ #endif
+ }
+ aPrinter.m_aInfo.m_aCommand = String( aValue, RTL_TEXTENCODING_UTF8 );
+ }
+
+ aValue = aConfig.ReadKey( "QuickCommand" );
+ aPrinter.m_aInfo.m_aQuickCommand = String( aValue, RTL_TEXTENCODING_UTF8 );
+
+ aValue = aConfig.ReadKey( "Features" );
+ aPrinter.m_aInfo.m_aFeatures = String( aValue, RTL_TEXTENCODING_UTF8 );
+
+ // override the settings in m_aGlobalDefaults if keys exist
+ aValue = aConfig.ReadKey( "DefaultPrinter" );
+ if( ! aValue.Equals( "0" ) && ! aValue.EqualsIgnoreCaseAscii( "false" ) )
+ aDefaultPrinter = aPrinterName;
+
+ aValue = aConfig.ReadKey( "Location" );
+ aPrinter.m_aInfo.m_aLocation = String( aValue, RTL_TEXTENCODING_UTF8 );
+
+ aValue = aConfig.ReadKey( "Comment" );
+ aPrinter.m_aInfo.m_aComment = String( aValue, RTL_TEXTENCODING_UTF8 );
+
+ aValue = aConfig.ReadKey( "Copies" );
+ if( aValue.Len() )
+ aPrinter.m_aInfo.m_nCopies = aValue.ToInt32();
+
+ aValue = aConfig.ReadKey( "Orientation" );
+ if( aValue.Len() )
+ aPrinter.m_aInfo.m_eOrientation = aValue.EqualsIgnoreCaseAscii( "Landscape" ) ? orientation::Landscape : orientation::Portrait;
+
+ aValue = aConfig.ReadKey( "MarginAdjust" );
+ if( aValue.Len() )
+ {
+ aPrinter.m_aInfo.m_nLeftMarginAdjust = aValue.GetToken( 0, ',' ).ToInt32();
+ aPrinter.m_aInfo.m_nRightMarginAdjust = aValue.GetToken( 1, ',' ).ToInt32();
+ aPrinter.m_aInfo.m_nTopMarginAdjust = aValue.GetToken( 2, ',' ).ToInt32();
+ aPrinter.m_aInfo.m_nBottomMarginAdjust = aValue.GetToken( 3, ',' ).ToInt32();
+ }
+
+ aValue = aConfig.ReadKey( "ColorDepth" );
+ if( aValue.Len() )
+ aPrinter.m_aInfo.m_nColorDepth = aValue.ToInt32();
+
+ aValue = aConfig.ReadKey( "ColorDevice" );
+ if( aValue.Len() )
+ aPrinter.m_aInfo.m_nColorDevice = aValue.ToInt32();
+
+ aValue = aConfig.ReadKey( "PSLevel" );
+ if( aValue.Len() )
+ aPrinter.m_aInfo.m_nPSLevel = aValue.ToInt32();
+
+ aValue = aConfig.ReadKey( "PerformFontSubstitution" );
+ if( ! aValue.Equals( "0" ) && ! aValue.EqualsIgnoreCaseAscii( "false" ) )
+ aPrinter.m_aInfo.m_bPerformFontSubstitution = true;
+ else
+ aPrinter.m_aInfo.m_bPerformFontSubstitution = false;
+
+ // now iterate over all keys to extract multi key information:
+ // 1. PPDContext information
+ // 2. Font substitution table
+ for( int nKey = 0; nKey < aConfig.GetKeyCount(); nKey++ )
+ {
+ ByteString aKey( aConfig.GetKeyName( nKey ) );
+ if( aKey.CompareTo( "PPD_", 4 ) == COMPARE_EQUAL && aPrinter.m_aInfo.m_pParser )
+ {
+ aValue = aConfig.ReadKey( aKey );
+ const PPDKey* pKey = aPrinter.m_aInfo.m_pParser->getKey( String( aKey.Copy( 4 ), RTL_TEXTENCODING_ISO_8859_1 ) );
+ if( pKey )
+ {
+ aPrinter.m_aInfo.m_aContext.
+ setValue( pKey,
+ aValue.Equals( "*nil" ) ? NULL : pKey->getValue( String( aValue, RTL_TEXTENCODING_ISO_8859_1 ) ),
+ TRUE );
+ }
+ }
+ else if( aKey.Len() > 10 && aKey.CompareTo("SubstFont_", 10 ) == COMPARE_EQUAL )
+ {
+ aValue = aConfig.ReadKey( aKey );
+ aPrinter.m_aInfo.m_aFontSubstitutes[ OStringToOUString( aKey.Copy( 10 ), RTL_TEXTENCODING_ISO_8859_1 ) ] = OStringToOUString( aValue, RTL_TEXTENCODING_ISO_8859_1 );
+ }
+ }
+
+ setDefaultPaper( aPrinter.m_aInfo.m_aContext );
+ fillFontSubstitutions( aPrinter.m_aInfo );
+
+ // finally insert printer
+ FileBase::getFileURLFromSystemPath( aFile.PathToFileName(), aPrinter.m_aFile );
+ aPrinter.m_bModified = false;
+ aPrinter.m_aGroup = aConfig.GetGroupName( nGroup );
+ std::hash_map< OUString, Printer, OUStringHash >::const_iterator find_it =
+ m_aPrinters.find( aPrinterName );
+ if( find_it != m_aPrinters.end() )
+ {
+ aPrinter.m_aAlternateFiles = find_it->second.m_aAlternateFiles;
+ aPrinter.m_aAlternateFiles.push_front( find_it->second.m_aFile );
+ }
+ m_aPrinters[ aPrinterName ] = aPrinter;
+ }
+ }
+ }
+
+ // set default printer
+ if( m_aPrinters.size() )
+ {
+ if( m_aPrinters.find( aDefaultPrinter ) == m_aPrinters.end() )
+ aDefaultPrinter = m_aPrinters.begin()->first;
+ }
+ else
+ aDefaultPrinter = OUString();
+ m_aDefaultPrinter = aDefaultPrinter;
+
+ if( m_eType != Default )
+ return;
+
+ // add a default printer for every available print queue
+ // merge paper and font substitution from default printer,
+ // all else from global defaults
+ PrinterInfo aMergeInfo( m_aGlobalDefaults );
+ aMergeInfo.m_aDriverName = String( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) );
+ aMergeInfo.m_aFeatures = String( RTL_CONSTASCII_USTRINGPARAM( "autoqueue" ) );
+
+ if( m_aDefaultPrinter.getLength() )
+ {
+ PrinterInfo aDefaultInfo( getPrinterInfo( m_aDefaultPrinter ) );
+ aMergeInfo.m_bPerformFontSubstitution = aDefaultInfo.m_bPerformFontSubstitution;
+ fillFontSubstitutions( aMergeInfo );
+
+ const PPDKey* pDefKey = aDefaultInfo.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
+ const PPDKey* pMergeKey = aMergeInfo.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
+ const PPDValue* pDefValue = aDefaultInfo.m_aContext.getValue( pDefKey );
+ const PPDValue* pMergeValue = pMergeKey ? pMergeKey->getValue( pDefValue->m_aOption ) : NULL;
+ if( pMergeKey && pMergeValue )
+ aMergeInfo.m_aContext.setValue( pMergeKey, pMergeValue );
+ }
+
+ getSystemPrintQueues();
+ for( ::std::list< SystemPrintQueue >::iterator it = m_aSystemPrintQueues.begin(); it != m_aSystemPrintQueues.end(); ++it )
+ {
+ String aPrinterName( RTL_CONSTASCII_USTRINGPARAM( "<" ) );
+ aPrinterName += String( it->m_aQueue );
+ aPrinterName.Append( '>' );
+
+ if( m_aPrinters.find( aPrinterName ) != m_aPrinters.end() )
+ // probably user made this one permanent in padmin
+ continue;
+
+ String aCmd( m_aSystemPrintCommand );
+ aCmd.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "(PRINTER)" ) ), it->m_aQueue );
+
+ Printer aPrinter;
+
+ // initialize to merged defaults
+ aPrinter.m_aInfo = aMergeInfo;
+ aPrinter.m_aInfo.m_aPrinterName = aPrinterName;
+ aPrinter.m_aInfo.m_aCommand = aCmd;
+ aPrinter.m_aInfo.m_aComment = it->m_aComment;
+ aPrinter.m_aInfo.m_aLocation = it->m_aLocation;
+ aPrinter.m_bModified = false;
+ aPrinter.m_aGroup = ByteString( aPrinterName, aEncoding ); //provide group name in case user makes this one permanent in padmin
+
+ m_aPrinters[ aPrinterName ] = aPrinter;
+ }
+}
+
+// -----------------------------------------------------------------
+
+void PrinterInfoManager::listPrinters( ::std::list< OUString >& rList ) const
+{
+ ::std::hash_map< OUString, Printer, OUStringHash >::const_iterator it;
+ rList.clear();
+ for( it = m_aPrinters.begin(); it != m_aPrinters.end(); ++it )
+ rList.push_back( it->first );
+}
+
+// -----------------------------------------------------------------
+
+const PrinterInfo& PrinterInfoManager::getPrinterInfo( const OUString& rPrinter ) const
+{
+ static PrinterInfo aEmptyInfo;
+ ::std::hash_map< OUString, Printer, OUStringHash >::const_iterator it = m_aPrinters.find( rPrinter );
+
+ DBG_ASSERT( it != m_aPrinters.end(), "Do not ask for info about nonexistant printers" );
+
+ return it != m_aPrinters.end() ? it->second.m_aInfo : aEmptyInfo;
+}
+
+// -----------------------------------------------------------------
+
+void PrinterInfoManager::changePrinterInfo( const OUString& rPrinter, const PrinterInfo& rNewInfo )
+{
+ ::std::hash_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.find( rPrinter );
+
+ DBG_ASSERT( it != m_aPrinters.end(), "Do not change nonexistant printers" );
+
+ if( it != m_aPrinters.end() )
+ {
+ it->second.m_aInfo = rNewInfo;
+ // recalculate font substitutions
+ fillFontSubstitutions( it->second.m_aInfo );
+ it->second.m_bModified = true;
+ writePrinterConfig();
+ }
+}
+
+// -----------------------------------------------------------------
+
+// need to check writeability / creatability of config files
+static bool checkWriteability( const OUString& rUniPath )
+{
+ bool bRet = false;
+ OUString aSysPath;
+ FileBase::getSystemPathFromFileURL( rUniPath, aSysPath );
+ SvFileStream aStream( aSysPath, STREAM_READ | STREAM_WRITE );
+ if( aStream.IsOpen() && aStream.IsWritable() )
+ bRet = true;
+ return bRet;
+}
+
+bool PrinterInfoManager::writePrinterConfig()
+{
+ // find at least one writeable config
+ ::std::hash_map< OUString, Config*, OUStringHash > files;
+ ::std::hash_map< OUString, int, OUStringHash > rofiles;
+ ::std::hash_map< OUString, Config*, OUStringHash >::iterator file_it;
+
+ for( ::std::list< WatchFile >::const_iterator wit = m_aWatchFiles.begin(); wit != m_aWatchFiles.end(); ++wit )
+ {
+ if( checkWriteability( wit->m_aFilePath ) )
+ {
+ files[ wit->m_aFilePath ] = new Config( wit->m_aFilePath );
+ break;
+ }
+ }
+
+ if( files.empty() )
+ return false;
+
+ Config* pGlobal = files.begin()->second;
+ pGlobal->SetGroup( GLOBAL_DEFAULTS_GROUP );
+ pGlobal->WriteKey( "DisableCUPS", m_bDisableCUPS ? "true" : "false" );
+
+ ::std::hash_map< OUString, Printer, OUStringHash >::iterator it;
+ for( it = m_aPrinters.begin(); it != m_aPrinters.end(); ++it )
+ {
+ if( ! it->second.m_bModified )
+ // printer was not changed, do nothing
+ continue;
+
+ // don't save autoqueue printers
+ sal_Int32 nIndex = 0;
+ bool bAutoQueue = false;
+ while( nIndex != -1 && ! bAutoQueue )
+ {
+ OUString aToken( it->second.m_aInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
+ if( aToken.getLength() && aToken.compareToAscii( "autoqueue" ) == 0 )
+ bAutoQueue = true;
+ }
+ if( bAutoQueue )
+ continue;
+
+ if( it->second.m_aFile.getLength() )
+ {
+ // check if file is writable
+ if( files.find( it->second.m_aFile ) == files.end() )
+ {
+ bool bInsertToNewFile = false;
+ // maybe it is simply not inserted yet
+ if( rofiles.find( it->second.m_aFile ) == rofiles.end() )
+ {
+ if( checkWriteability( it->second.m_aFile ) )
+ files[ it->second.m_aFile ] = new Config( it->second.m_aFile );
+ else
+ bInsertToNewFile = true;
+ }
+ else
+ bInsertToNewFile = true;
+ // original file is read only, insert printer in a new writeable file
+ if( bInsertToNewFile )
+ {
+ rofiles[ it->second.m_aFile ] = 1;
+ // update alternate file list
+ // the remove operation ensures uniqueness of each alternate
+ it->second.m_aAlternateFiles.remove( it->second.m_aFile );
+ it->second.m_aAlternateFiles.remove( files.begin()->first );
+ it->second.m_aAlternateFiles.push_front( it->second.m_aFile );
+ // update file
+ it->second.m_aFile = files.begin()->first;
+ }
+ }
+ }
+ else // a new printer, write it to the first file available
+ it->second.m_aFile = files.begin()->first;
+
+ if( ! it->second.m_aGroup.getLength() ) // probably a new printer
+ it->second.m_aGroup = OString( it->first.getStr(), it->first.getLength(), RTL_TEXTENCODING_UTF8 );
+
+ if( files.find( it->second.m_aFile ) != files.end() )
+ {
+ Config* pConfig = files[ it->second.m_aFile ];
+ pConfig->DeleteGroup( it->second.m_aGroup ); // else some old keys may remain
+ pConfig->SetGroup( it->second.m_aGroup );
+
+ ByteString aValue( String( it->second.m_aInfo.m_aDriverName ), RTL_TEXTENCODING_UTF8 );
+ aValue += '/';
+ aValue += ByteString( String( it->first ), RTL_TEXTENCODING_UTF8 );
+ pConfig->WriteKey( "Printer", aValue );
+ pConfig->WriteKey( "DefaultPrinter", it->first == m_aDefaultPrinter ? "1" : "0" );
+ pConfig->WriteKey( "Location", ByteString( String( it->second.m_aInfo.m_aLocation ), RTL_TEXTENCODING_UTF8 ) );
+ pConfig->WriteKey( "Comment", ByteString( String( it->second.m_aInfo.m_aComment ), RTL_TEXTENCODING_UTF8 ) );
+ pConfig->WriteKey( "Command", ByteString( String( it->second.m_aInfo.m_aCommand ), RTL_TEXTENCODING_UTF8 ) );
+ pConfig->WriteKey( "QuickCommand", ByteString( String( it->second.m_aInfo.m_aQuickCommand ), RTL_TEXTENCODING_UTF8 ) );
+ pConfig->WriteKey( "Features", ByteString( String( it->second.m_aInfo.m_aFeatures ), RTL_TEXTENCODING_UTF8 ) );
+ pConfig->WriteKey( "Copies", ByteString::CreateFromInt32( it->second.m_aInfo.m_nCopies ) );
+ pConfig->WriteKey( "Orientation", it->second.m_aInfo.m_eOrientation == orientation::Landscape ? "Landscape" : "Portrait" );
+ pConfig->WriteKey( "PSLevel", ByteString::CreateFromInt32( it->second.m_aInfo.m_nPSLevel ) );
+ pConfig->WriteKey( "ColorDevice", ByteString::CreateFromInt32( it->second.m_aInfo.m_nColorDevice ) );
+ pConfig->WriteKey( "ColorDepth", ByteString::CreateFromInt32( it->second.m_aInfo.m_nColorDepth ) );
+ aValue = ByteString::CreateFromInt32( it->second.m_aInfo.m_nLeftMarginAdjust );
+ aValue += ',';
+ aValue += ByteString::CreateFromInt32( it->second.m_aInfo.m_nRightMarginAdjust );
+ aValue += ',';
+ aValue += ByteString::CreateFromInt32( it->second.m_aInfo.m_nTopMarginAdjust );
+ aValue += ',';
+ aValue += ByteString::CreateFromInt32( it->second.m_aInfo.m_nBottomMarginAdjust );
+ pConfig->WriteKey( "MarginAdjust", aValue );
+
+ if( it->second.m_aInfo.m_aDriverName.compareToAscii( "CUPS:", 5 ) != 0 )
+ {
+ // write PPDContext (not for CUPS)
+ for( int i = 0; i < it->second.m_aInfo.m_aContext.countValuesModified(); i++ )
+ {
+ const PPDKey* pKey = it->second.m_aInfo.m_aContext.getModifiedKey( i );
+ ByteString aKey( "PPD_" );
+ aKey += ByteString( pKey->getKey(), RTL_TEXTENCODING_ISO_8859_1 );
+
+ const PPDValue* pValue = it->second.m_aInfo.m_aContext.getValue( pKey );
+ aValue = pValue ? ByteString( pValue->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ) : ByteString( "*nil" );
+ pConfig->WriteKey( aKey, aValue );
+ }
+ }
+
+ // write font substitution table
+ pConfig->WriteKey( "PerformFontSubstitution", it->second.m_aInfo.m_bPerformFontSubstitution ? "true" : "false" );
+ for( ::std::hash_map< OUString, OUString, OUStringHash >::const_iterator subst = it->second.m_aInfo.m_aFontSubstitutes.begin();
+ subst != it->second.m_aInfo.m_aFontSubstitutes.end(); ++subst )
+ {
+ ByteString aKey( "SubstFont_" );
+ aKey.Append( OUStringToOString( subst->first, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+ pConfig->WriteKey( aKey, OUStringToOString( subst->second, RTL_TEXTENCODING_ISO_8859_1 ) );
+ }
+ }
+ }
+
+ // get rid of Config objects. this also writes any changes
+ for( file_it = files.begin(); file_it != files.end(); ++file_it )
+ delete file_it->second;
+
+ return true;
+}
+
+// -----------------------------------------------------------------
+
+bool PrinterInfoManager::addPrinter( const OUString& rPrinterName, const OUString& rDriverName )
+{
+ bool bSuccess = false;
+
+ const PPDParser* pParser = NULL;
+ if( m_aPrinters.find( rPrinterName ) == m_aPrinters.end() && ( pParser = PPDParser::getParser( rDriverName ) ) )
+ {
+ Printer aPrinter;
+ aPrinter.m_bModified = true;
+ aPrinter.m_aInfo = m_aGlobalDefaults;
+ aPrinter.m_aInfo.m_aDriverName = rDriverName;
+ aPrinter.m_aInfo.m_pParser = pParser;
+ aPrinter.m_aInfo.m_aContext.setParser( pParser );
+ aPrinter.m_aInfo.m_aPrinterName = rPrinterName;
+
+ fillFontSubstitutions( aPrinter.m_aInfo );
+ // merge PPD values with global defaults
+ for( int nPPDValueModified = 0; nPPDValueModified < m_aGlobalDefaults.m_aContext.countValuesModified(); nPPDValueModified++ )
+ {
+ const PPDKey* pDefKey = m_aGlobalDefaults.m_aContext.getModifiedKey( nPPDValueModified );
+ const PPDValue* pDefValue = m_aGlobalDefaults.m_aContext.getValue( pDefKey );
+ const PPDKey* pPrinterKey = pDefKey ? aPrinter.m_aInfo.m_pParser->getKey( pDefKey->getKey() ) : NULL;
+ if( pDefKey && pPrinterKey )
+ // at least the options exist in both PPDs
+ {
+ if( pDefValue )
+ {
+ const PPDValue* pPrinterValue = pPrinterKey->getValue( pDefValue->m_aOption );
+ if( pPrinterValue )
+ // the printer has a corresponding option for the key
+ aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, pPrinterValue );
+ }
+ else
+ aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, NULL );
+ }
+ }
+
+ m_aPrinters[ rPrinterName ] = aPrinter;
+ bSuccess = true;
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "new printer %s, level = %d, colordevice = %d, depth = %d\n",
+ OUStringToOString( rPrinterName, osl_getThreadTextEncoding() ).getStr(),
+ m_aPrinters[rPrinterName].m_aInfo.m_nPSLevel,
+ m_aPrinters[rPrinterName].m_aInfo.m_nColorDevice,
+ m_aPrinters[rPrinterName].m_aInfo.m_nColorDepth );
+ #endif
+ // comment: logically one should writePrinterConfig() here
+ // but immediately after addPrinter() a changePrinterInfo()
+ // will follow (see padmin code), which writes it again,
+ // so we can currently save some performance here
+ }
+ return bSuccess;
+}
+
+// -----------------------------------------------------------------
+
+bool PrinterInfoManager::removePrinter( const OUString& rPrinterName, bool bCheckOnly )
+{
+ bool bSuccess = true;
+
+ ::std::hash_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.find( rPrinterName );
+ if( it != m_aPrinters.end() )
+ {
+ if( it->second.m_aFile.getLength() )
+ {
+ // this printer already exists in a config file
+
+
+ // check writeability of config file(s)
+ if( ! checkWriteability( it->second.m_aFile ) )
+ bSuccess = false;
+ else
+ {
+ for( std::list< OUString >::const_iterator file_it = it->second.m_aAlternateFiles.begin();
+ file_it != it->second.m_aAlternateFiles.end() && bSuccess; ++file_it )
+ {
+ if( ! checkWriteability( *file_it ) )
+ bSuccess = false;
+ }
+ }
+ if( bSuccess && ! bCheckOnly )
+ {
+
+ Config aConfig( it->second.m_aFile );
+ aConfig.DeleteGroup( it->second.m_aGroup );
+ aConfig.Flush();
+ for( std::list< OUString >::const_iterator file_it = it->second.m_aAlternateFiles.begin();
+ file_it != it->second.m_aAlternateFiles.end() && bSuccess; ++file_it )
+ {
+ Config aAltConfig( *file_it );
+ aAltConfig.DeleteGroup( it->second.m_aGroup );
+ aAltConfig.Flush();
+ }
+ }
+ }
+ if( bSuccess && ! bCheckOnly )
+ {
+ m_aPrinters.erase( it );
+ // need this here because someone may call
+ // checkPrintersChanged after the removal
+ // but then other added printers were not flushed
+ // to disk, so they are discarded
+ writePrinterConfig();
+ }
+ }
+ return bSuccess;
+}
+
+// -----------------------------------------------------------------
+
+bool PrinterInfoManager::setDefaultPrinter( const OUString& rPrinterName )
+{
+ bool bSuccess = false;
+
+ ::std::hash_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.find( rPrinterName );
+ if( it != m_aPrinters.end() )
+ {
+ bSuccess = true;
+ it->second.m_bModified = true;
+ if( ( it = m_aPrinters.find( m_aDefaultPrinter ) ) != m_aPrinters.end() )
+ it->second.m_bModified = true;
+ m_aDefaultPrinter = rPrinterName;
+ writePrinterConfig();
+ }
+ return bSuccess;
+}
+
+// -----------------------------------------------------------------
+bool PrinterInfoManager::addOrRemovePossible() const
+{
+ return true;
+}
+
+// -----------------------------------------------------------------
+
+void PrinterInfoManager::fillFontSubstitutions( PrinterInfo& rInfo ) const
+{
+ PrintFontManager& rFontManager( PrintFontManager::get() );
+ rInfo.m_aFontSubstitutions.clear();
+
+ if( ! rInfo.m_bPerformFontSubstitution ||
+ ! rInfo.m_aFontSubstitutes.size() )
+ return;
+
+ ::std::list< FastPrintFontInfo > aFonts;
+ ::std::hash_map< OUString, ::std::list< FastPrintFontInfo >, OUStringHash > aPrinterFonts;
+ rFontManager.getFontListWithFastInfo( aFonts, rInfo.m_pParser );
+
+ // get builtin fonts
+ ::std::list< FastPrintFontInfo >::const_iterator it;
+ for( it = aFonts.begin(); it != aFonts.end(); ++it )
+ if( it->m_eType == fonttype::Builtin )
+ aPrinterFonts[ it->m_aFamilyName.toAsciiLowerCase() ].push_back( *it );
+
+ // map lower case, so build a local copy of the font substitutions
+ ::std::hash_map< OUString, OUString, OUStringHash > aSubstitutions;
+ ::std::hash_map< OUString, OUString, OUStringHash >::const_iterator subst;
+ for( subst = rInfo.m_aFontSubstitutes.begin(); subst != rInfo.m_aFontSubstitutes.end(); ++subst )
+ {
+ OUString aFamily( subst->first.toAsciiLowerCase() );
+ // first look if there is a builtin of this family
+ // in this case override the substitution table
+ if( aPrinterFonts.find( aFamily ) != aPrinterFonts.end() )
+ aSubstitutions[ aFamily ] = aFamily;
+ else
+ aSubstitutions[ aFamily ] = subst->second.toAsciiLowerCase();
+ }
+
+
+ // now find substitutions
+ for( it = aFonts.begin(); it != aFonts.end(); ++it )
+ {
+ if( it->m_eType != fonttype::Builtin )
+ {
+ OUString aFamily( it->m_aFamilyName.toAsciiLowerCase() );
+ subst = aSubstitutions.find( aFamily );
+ if( subst != aSubstitutions.end() )
+ {
+ // search a substitution
+ const ::std::list< FastPrintFontInfo >& rBuiltins( aPrinterFonts[ aSubstitutions[ aFamily ] ] );
+ ::std::list< FastPrintFontInfo >::const_iterator builtin;
+ int nLastMatch = -10000;
+ fontID nSubstitute = -1;
+ for( builtin = rBuiltins.begin(); builtin != rBuiltins.end(); ++builtin )
+ {
+ int nMatch = 0;
+ int nDiff;
+ if( builtin->m_eItalic == it->m_eItalic )
+ nMatch += 8000;
+
+ nDiff = builtin->m_eWeight - it->m_eWeight;
+ nDiff = nDiff < 0 ? -nDiff : nDiff;
+ nMatch += 4000 - 1000*nDiff;
+
+ nDiff = builtin->m_eWidth - it->m_eWidth;
+ nDiff = nDiff < 0 ? -nDiff : nDiff;
+ nMatch += 2000 - 500*nDiff;
+
+ if( nMatch > nLastMatch )
+ {
+ nLastMatch = nMatch;
+ nSubstitute = builtin->m_nID;
+ }
+ }
+ if( nSubstitute != -1 )
+ {
+ rInfo.m_aFontSubstitutions[ it->m_nID ] = nSubstitute;
+ #if OSL_DEBUG_LEVEL > 2
+ FastPrintFontInfo aInfo;
+ rFontManager.getFontFastInfo( nSubstitute, aInfo );
+ fprintf( stderr,
+ "substitute %s %s %d %d\n"
+ " -> %s %s %d %d\n",
+ OUStringToOString( it->m_aFamilyName, RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ it->m_eItalic == italic::Upright ? "r" : it->m_eItalic == italic::Oblique ? "o" : it->m_eItalic == italic::Italic ? "i" : "u",
+ it->m_eWeight,
+ it->m_eWidth,
+
+ OUStringToOString( aInfo.m_aFamilyName, RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
+ aInfo.m_eItalic == italic::Upright ? "r" : aInfo.m_eItalic == italic::Oblique ? "o" : aInfo.m_eItalic == italic::Italic ? "i" : "u",
+ aInfo.m_eWeight,
+ aInfo.m_eWidth
+ );
+ #endif
+ }
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------
+
+void PrinterInfoManager::getSystemPrintCommands( std::list< OUString >& rCommands )
+{
+ if( m_pQueueInfo && m_pQueueInfo->hasChanged() )
+ {
+ m_aSystemPrintCommand = m_pQueueInfo->getCommand();
+ m_pQueueInfo->getSystemQueues( m_aSystemPrintQueues );
+ delete m_pQueueInfo, m_pQueueInfo = NULL;
+ }
+
+ std::list< SystemPrintQueue >::const_iterator it;
+ rCommands.clear();
+ String aPrinterConst( RTL_CONSTASCII_USTRINGPARAM( "(PRINTER)" ) );
+ for( it = m_aSystemPrintQueues.begin(); it != m_aSystemPrintQueues.end(); ++it )
+ {
+ String aCmd( m_aSystemPrintCommand );
+ aCmd.SearchAndReplace( aPrinterConst, it->m_aQueue );
+ rCommands.push_back( aCmd );
+ }
+}
+
+const std::list< PrinterInfoManager::SystemPrintQueue >& PrinterInfoManager::getSystemPrintQueues()
+{
+ if( m_pQueueInfo && m_pQueueInfo->hasChanged() )
+ {
+ m_aSystemPrintCommand = m_pQueueInfo->getCommand();
+ m_pQueueInfo->getSystemQueues( m_aSystemPrintQueues );
+ delete m_pQueueInfo, m_pQueueInfo = NULL;
+ }
+
+ return m_aSystemPrintQueues;
+}
+
+bool PrinterInfoManager::checkFeatureToken( const rtl::OUString& rPrinterName, const char* pToken ) const
+{
+ const PrinterInfo& rPrinterInfo( getPrinterInfo( rPrinterName ) );
+ sal_Int32 nIndex = 0;
+ while( nIndex != -1 )
+ {
+ OUString aOuterToken = rPrinterInfo.m_aFeatures.getToken( 0, ',', nIndex );
+ sal_Int32 nInnerIndex = 0;
+ OUString aInnerToken = aOuterToken.getToken( 0, '=', nInnerIndex );
+ if( aInnerToken.equalsIgnoreAsciiCaseAscii( pToken ) )
+ return true;
+ }
+ return false;
+}
+
+FILE* PrinterInfoManager::startSpool( const OUString& rPrintername, bool bQuickCommand )
+{
+ const PrinterInfo& rPrinterInfo = getPrinterInfo (rPrintername);
+ const rtl::OUString& rCommand = (bQuickCommand && rPrinterInfo.m_aQuickCommand.getLength() ) ?
+ rPrinterInfo.m_aQuickCommand : rPrinterInfo.m_aCommand;
+ rtl::OString aShellCommand = OUStringToOString (rCommand, RTL_TEXTENCODING_ISO_8859_1);
+ aShellCommand += rtl::OString( " 2>/dev/null" );
+
+ return popen (aShellCommand.getStr(), "w");
+}
+
+int PrinterInfoManager::endSpool( const OUString& /*rPrintername*/, const OUString& /*rJobTitle*/, FILE* pFile, const JobData& /*rDocumentJobData*/ )
+{
+ return (0 == pclose( pFile ));
+}
+
+void PrinterInfoManager::setupJobContextData( JobData& rData )
+{
+ std::hash_map< OUString, Printer, OUStringHash >::iterator it =
+ m_aPrinters.find( rData.m_aPrinterName );
+ if( it != m_aPrinters.end() )
+ {
+ rData.m_pParser = it->second.m_aInfo.m_pParser;
+ rData.m_aContext = it->second.m_aInfo.m_aContext;
+ }
+}
+
+void PrinterInfoManager::setDefaultPaper( PPDContext& rContext ) const
+{
+ if( ! rContext.getParser() )
+ return;
+
+ const PPDKey* pPageSizeKey = rContext.getParser()->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
+ if( ! pPageSizeKey )
+ return;
+
+ int nModified = rContext.countValuesModified();
+ while( nModified-- &&
+ rContext.getModifiedKey( nModified ) != pPageSizeKey )
+ ;
+
+ if( nModified >= 0 ) // paper was set already, do not modify
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "not setting default paper, already set %s\n",
+ OUStringToOString( rContext.getValue( pPageSizeKey )->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+ #endif
+ return;
+ }
+
+ // paper not set, fill in default value
+ const PPDValue* pPaperVal = NULL;
+ int nValues = pPageSizeKey->countValues();
+ for( int i = 0; i < nValues && ! pPaperVal; i++ )
+ {
+ const PPDValue* pVal = pPageSizeKey->getValue( i );
+ if( pVal->m_aOption.EqualsIgnoreCaseAscii( m_aSystemDefaultPaper.getStr() ) )
+ pPaperVal = pVal;
+ }
+ if( pPaperVal )
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "setting default paper %s\n", OUStringToOString( pPaperVal->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+ #endif
+ rContext.setValue( pPageSizeKey, pPaperVal );
+ #if OSL_DEBUG_LEVEL > 1
+ pPaperVal = rContext.getValue( pPageSizeKey );
+ fprintf( stderr, "-> got paper %s\n", OUStringToOString( pPaperVal->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+ #endif
+ }
+}
+
+// -----------------------------------------------------------------
+
+SystemQueueInfo::SystemQueueInfo() :
+ m_bChanged( false )
+{
+ create();
+}
+
+SystemQueueInfo::~SystemQueueInfo()
+{
+ terminate();
+}
+
+bool SystemQueueInfo::hasChanged() const
+{
+ MutexGuard aGuard( m_aMutex );
+ bool bChanged = m_bChanged;
+ return bChanged;
+}
+
+void SystemQueueInfo::getSystemQueues( std::list< PrinterInfoManager::SystemPrintQueue >& rQueues )
+{
+ MutexGuard aGuard( m_aMutex );
+ rQueues = m_aQueues;
+ m_bChanged = false;
+}
+
+OUString SystemQueueInfo::getCommand() const
+{
+ MutexGuard aGuard( m_aMutex );
+ OUString aRet = m_aCommand;
+ return aRet;
+}
+
+struct SystemCommandParameters;
+typedef void(* tokenHandler)(const std::list< rtl::OString >&,
+ std::list< PrinterInfoManager::SystemPrintQueue >&,
+ const SystemCommandParameters*);
+
+struct SystemCommandParameters
+{
+ const char* pQueueCommand;
+ const char* pPrintCommand;
+ const char* pForeToken;
+ const char* pAftToken;
+ unsigned int nForeTokenCount;
+ tokenHandler pHandler;
+};
+
+#if ! (defined(LINUX) || defined(NETBSD) || defined(FREEBSD))
+static void lpgetSysQueueTokenHandler(
+ const std::list< rtl::OString >& i_rLines,
+ std::list< PrinterInfoManager::SystemPrintQueue >& o_rQueues,
+ const SystemCommandParameters* )
+{
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ std::hash_set< OUString, OUStringHash > aUniqueSet;
+ std::hash_set< OUString, OUStringHash > aOnlySet;
+ aUniqueSet.insert( OUString( RTL_CONSTASCII_USTRINGPARAM( "_all" ) ) );
+ aUniqueSet.insert( OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ) );
+
+ // the eventual "all" attribute of the "_all" queue tells us, which
+ // printers are to be used for this user at all
+
+ // find _all: line
+ rtl::OString aAllLine( "_all:" );
+ rtl::OString aAllAttr( "all=" );
+ for( std::list< rtl::OString >::const_iterator it = i_rLines.begin();
+ it != i_rLines.end(); ++it )
+ {
+ if( it->indexOf( aAllLine, 0 ) == 0 )
+ {
+ // now find the "all" attribute
+ ++it;
+ while( it != i_rLines.end() )
+ {
+ rtl::OString aClean( WhitespaceToSpace( *it ) );
+ if( aClean.indexOf( aAllAttr, 0 ) == 0 )
+ {
+ // insert the comma separated entries into the set of printers to use
+ sal_Int32 nPos = aAllAttr.getLength();
+ while( nPos != -1 )
+ {
+ OString aTok( aClean.getToken( 0, ',', nPos ) );
+ if( aTok.getLength() > 0 )
+ aOnlySet.insert( rtl::OStringToOUString( aTok, aEncoding ) );
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ bool bInsertAttribute = false;
+ rtl::OString aDescrStr( "description=" );
+ rtl::OString aLocStr( "location=" );
+ for( std::list< rtl::OString >::const_iterator it = i_rLines.begin();
+ it != i_rLines.end(); ++it )
+ {
+ sal_Int32 nPos = 0;
+ // find the begin of a new printer section
+ nPos = it->indexOf( ':', 0 );
+ if( nPos != -1 )
+ {
+ OUString aSysQueue( rtl::OStringToOUString( it->copy( 0, nPos ), aEncoding ) );
+ // do not insert duplicates (e.g. lpstat tends to produce such lines)
+ // in case there was a "_all" section, insert only those printer explicitly
+ // set in the "all" attribute
+ if( aUniqueSet.find( aSysQueue ) == aUniqueSet.end() &&
+ ( aOnlySet.empty() || aOnlySet.find( aSysQueue ) != aOnlySet.end() )
+ )
+ {
+ o_rQueues.push_back( PrinterInfoManager::SystemPrintQueue() );
+ o_rQueues.back().m_aQueue = aSysQueue;
+ o_rQueues.back().m_aLocation = aSysQueue;
+ aUniqueSet.insert( aSysQueue );
+ bInsertAttribute = true;
+ }
+ else
+ bInsertAttribute = false;
+ continue;
+ }
+ if( bInsertAttribute && ! o_rQueues.empty() )
+ {
+ // look for "description" attribute, insert as comment
+ nPos = it->indexOf( aDescrStr, 0 );
+ if( nPos != -1 )
+ {
+ ByteString aComment( WhitespaceToSpace( it->copy(nPos+12) ) );
+ if( aComment.Len() > 0 )
+ o_rQueues.back().m_aComment = String( aComment, aEncoding );
+ continue;
+ }
+ // look for "location" attribute, inser as location
+ nPos = it->indexOf( aLocStr, 0 );
+ if( nPos != -1 )
+ {
+ ByteString aLoc( WhitespaceToSpace( it->copy(nPos+9) ) );
+ if( aLoc.Len() > 0 )
+ o_rQueues.back().m_aLocation = String( aLoc, aEncoding );
+ continue;
+ }
+ }
+ }
+}
+#endif
+static void standardSysQueueTokenHandler(
+ const std::list< rtl::OString >& i_rLines,
+ std::list< PrinterInfoManager::SystemPrintQueue >& o_rQueues,
+ const SystemCommandParameters* i_pParms)
+{
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ std::hash_set< OUString, OUStringHash > aUniqueSet;
+ rtl::OString aForeToken( i_pParms->pForeToken );
+ rtl::OString aAftToken( i_pParms->pAftToken );
+ /* Normal Unix print queue discovery, also used for Darwin 5 LPR printing
+ */
+ for( std::list< rtl::OString >::const_iterator it = i_rLines.begin();
+ it != i_rLines.end(); ++it )
+ {
+ sal_Int32 nPos = 0;
+
+ // search for a line describing a printer:
+ // find if there are enough tokens before the name
+ for( unsigned int i = 0; i < i_pParms->nForeTokenCount && nPos != -1; i++ )
+ {
+ nPos = it->indexOf( aForeToken, nPos );
+ if( nPos != -1 && it->getLength() >= nPos+aForeToken.getLength() )
+ nPos += aForeToken.getLength();
+ }
+ if( nPos != -1 )
+ {
+ // find if there is the token after the queue
+ sal_Int32 nAftPos = it->indexOf( aAftToken, nPos );
+ if( nAftPos != -1 )
+ {
+ // get the queue name between fore and aft tokens
+ OUString aSysQueue( rtl::OStringToOUString( it->copy( nPos, nAftPos - nPos ), aEncoding ) );
+ // do not insert duplicates (e.g. lpstat tends to produce such lines)
+ if( aUniqueSet.find( aSysQueue ) == aUniqueSet.end() )
+ {
+ o_rQueues.push_back( PrinterInfoManager::SystemPrintQueue() );
+ o_rQueues.back().m_aQueue = aSysQueue;
+ o_rQueues.back().m_aLocation = aSysQueue;
+ aUniqueSet.insert( aSysQueue );
+ }
+ }
+ }
+ }
+}
+
+static const struct SystemCommandParameters aParms[] =
+{
+ #if defined(LINUX) || defined(NETBSD) || defined(FREEBSD)
+ { "/usr/sbin/lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler },
+ { "lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler },
+ { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpstat -s", "lp -d \"(PRINTER)\"", "system for ", ": ", 1, standardSysQueueTokenHandler }
+ #else
+ { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpget list", "lp -d \"(PRINTER)\"", "", ":", 0, lpgetSysQueueTokenHandler },
+ { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpstat -s", "lp -d \"(PRINTER)\"", "system for ", ": ", 1, standardSysQueueTokenHandler },
+ { "/usr/sbin/lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler },
+ { "lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler }
+ #endif
+};
+
+void SystemQueueInfo::run()
+{
+ char pBuffer[1024];
+ FILE *pPipe;
+ std::list< rtl::OString > aLines;
+
+ /* Discover which command we can use to get a list of all printer queues */
+ for( unsigned int i = 0; i < sizeof(aParms)/sizeof(aParms[0]); i++ )
+ {
+ aLines.clear();
+ rtl::OStringBuffer aCmdLine( 128 );
+ aCmdLine.append( aParms[i].pQueueCommand );
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "trying print queue command \"%s\" ... ", aParms[i].pQueueCommand );
+ #endif
+ aCmdLine.append( " 2>/dev/null" );
+ if( (pPipe = popen( aCmdLine.getStr(), "r" )) )
+ {
+ while( fgets( pBuffer, 1024, pPipe ) )
+ aLines.push_back( rtl::OString( pBuffer ) );
+ if( ! pclose( pPipe ) )
+ {
+ std::list< PrinterInfoManager::SystemPrintQueue > aSysPrintQueues;
+ aParms[i].pHandler( aLines, aSysPrintQueues, &(aParms[i]) );
+ MutexGuard aGuard( m_aMutex );
+ m_bChanged = true;
+ m_aQueues = aSysPrintQueues;
+ m_aCommand = rtl::OUString::createFromAscii( aParms[i].pPrintCommand );
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "success\n" );
+ #endif
+ break;
+ }
+ }
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "failed\n" );
+ #endif
+ }
+}
+
diff --git a/vcl/unx/source/printergfx/bitmap_gfx.cxx b/vcl/unx/source/printergfx/bitmap_gfx.cxx
new file mode 100644
index 000000000000..1421fb7433f7
--- /dev/null
+++ b/vcl/unx/source/printergfx/bitmap_gfx.cxx
@@ -0,0 +1,732 @@
+/*************************************************************************
+ *
+ * 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 "psputil.hxx"
+
+#include "vcl/printergfx.hxx"
+#include "vcl/strhelper.hxx"
+
+namespace psp {
+
+const sal_uInt32 nLineLength = 80;
+const sal_uInt32 nBufferSize = 16384;
+
+/*
+ *
+ * Bitmap compression / Hex encoding / Ascii85 Encoding
+ *
+ */
+
+PrinterBmp::~PrinterBmp ()
+{ /* dont need this, but C50 does */ }
+
+/* virtual base class */
+
+class ByteEncoder
+{
+private:
+
+public:
+
+ virtual void EncodeByte (sal_uInt8 nByte) = 0;
+ virtual ~ByteEncoder () = 0;
+};
+
+ByteEncoder::~ByteEncoder ()
+{ /* dont need this, but the C50 does */ }
+
+/* HexEncoder */
+
+class HexEncoder : public ByteEncoder
+{
+private:
+
+ osl::File* mpFile;
+ sal_uInt32 mnColumn;
+ sal_uInt32 mnOffset;
+ sal_Char mpFileBuffer[nBufferSize + 16];
+
+ HexEncoder (); /* dont use */
+
+public:
+
+ HexEncoder (osl::File* pFile);
+ virtual ~HexEncoder ();
+ void WriteAscii (sal_uInt8 nByte);
+ virtual void EncodeByte (sal_uInt8 nByte);
+ void FlushLine ();
+};
+
+HexEncoder::HexEncoder (osl::File* pFile) :
+ mpFile (pFile),
+ mnColumn (0),
+ mnOffset (0)
+{}
+
+HexEncoder::~HexEncoder ()
+{
+ FlushLine ();
+ if (mnColumn > 0)
+ WritePS (mpFile, "\n");
+}
+
+void
+HexEncoder::WriteAscii (sal_uInt8 nByte)
+{
+ sal_uInt32 nOff = psp::getHexValueOf (nByte, mpFileBuffer + mnOffset);
+ mnColumn += nOff;
+ mnOffset += nOff;
+
+ if (mnColumn >= nLineLength)
+ {
+ mnOffset += psp::appendStr ("\n", mpFileBuffer + mnOffset);
+ mnColumn = 0;
+ }
+ if (mnOffset >= nBufferSize)
+ FlushLine ();
+}
+
+void
+HexEncoder::EncodeByte (sal_uInt8 nByte)
+{
+ WriteAscii (nByte);
+}
+
+void
+HexEncoder::FlushLine ()
+{
+ if (mnOffset > 0)
+ {
+ WritePS (mpFile, mpFileBuffer, mnOffset);
+ mnOffset = 0;
+ }
+}
+
+/* Ascii85 encoder, is abi compatible with HexEncoder but writes a ~> to
+ indicate end of data EOD */
+
+class Ascii85Encoder : public ByteEncoder
+{
+private:
+
+ osl::File* mpFile;
+ sal_uInt32 mnByte;
+ sal_uInt8 mpByteBuffer[4];
+
+ sal_uInt32 mnColumn;
+ sal_uInt32 mnOffset;
+ sal_Char mpFileBuffer[nBufferSize + 16];
+
+ Ascii85Encoder (); /* dont use */
+
+ inline void PutByte (sal_uInt8 nByte);
+ inline void PutEOD ();
+ void ConvertToAscii85 ();
+ void FlushLine ();
+
+public:
+
+ Ascii85Encoder (osl::File* pFile);
+ virtual ~Ascii85Encoder ();
+ virtual void EncodeByte (sal_uInt8 nByte);
+ void WriteAscii (sal_uInt8 nByte);
+};
+
+Ascii85Encoder::Ascii85Encoder (osl::File* pFile) :
+ mpFile (pFile),
+ mnByte (0),
+ mnColumn (0),
+ mnOffset (0)
+{}
+
+inline void
+Ascii85Encoder::PutByte (sal_uInt8 nByte)
+{
+ mpByteBuffer [mnByte++] = nByte;
+}
+
+inline void
+Ascii85Encoder::PutEOD ()
+{
+ WritePS (mpFile, "~>\n");
+}
+
+void
+Ascii85Encoder::ConvertToAscii85 ()
+{
+ if (mnByte < 4)
+ std::memset (mpByteBuffer + mnByte, 0, (4 - mnByte) * sizeof(sal_uInt8));
+
+ sal_uInt32 nByteValue = mpByteBuffer[0] * 256 * 256 * 256
+ + mpByteBuffer[1] * 256 * 256
+ + mpByteBuffer[2] * 256
+ + mpByteBuffer[3];
+
+ if (nByteValue == 0 && mnByte == 4)
+ {
+ /* special case of 4 Bytes in row */
+ mpFileBuffer [mnOffset] = 'z';
+
+ mnOffset += 1;
+ mnColumn += 1;
+ }
+ else
+ {
+ /* real ascii85 encoding */
+ mpFileBuffer [mnOffset + 4] = (nByteValue % 85) + 33;
+ nByteValue /= 85;
+ mpFileBuffer [mnOffset + 3] = (nByteValue % 85) + 33;
+ nByteValue /= 85;
+ mpFileBuffer [mnOffset + 2] = (nByteValue % 85) + 33;
+ nByteValue /= 85;
+ mpFileBuffer [mnOffset + 1] = (nByteValue % 85) + 33;
+ nByteValue /= 85;
+ mpFileBuffer [mnOffset + 0] = (nByteValue % 85) + 33;
+
+ mnColumn += (mnByte + 1);
+ mnOffset += (mnByte + 1);
+
+ /* insert a newline if necessary */
+ if (mnColumn > nLineLength)
+ {
+ sal_uInt32 nEolOff = mnColumn - nLineLength;
+ sal_uInt32 nBufOff = mnOffset - nEolOff;
+
+ std::memmove (mpFileBuffer + nBufOff + 1, mpFileBuffer + nBufOff, nEolOff);
+ mpFileBuffer[ nBufOff ] = '\n';
+
+ mnOffset++;
+ mnColumn = nEolOff;
+ }
+ }
+
+ mnByte = 0;
+}
+
+void
+Ascii85Encoder::WriteAscii (sal_uInt8 nByte)
+{
+ PutByte (nByte);
+ if (mnByte == 4)
+ ConvertToAscii85 ();
+
+ if (mnColumn >= nLineLength)
+ {
+ mnOffset += psp::appendStr ("\n", mpFileBuffer + mnOffset);
+ mnColumn = 0;
+ }
+ if (mnOffset >= nBufferSize)
+ FlushLine ();
+}
+
+void
+Ascii85Encoder::EncodeByte (sal_uInt8 nByte)
+{
+ WriteAscii (nByte);
+}
+
+void
+Ascii85Encoder::FlushLine ()
+{
+ if (mnOffset > 0)
+ {
+ WritePS (mpFile, mpFileBuffer, mnOffset);
+ mnOffset = 0;
+ }
+}
+
+Ascii85Encoder::~Ascii85Encoder ()
+{
+ if (mnByte > 0)
+ ConvertToAscii85 ();
+ if (mnOffset > 0)
+ FlushLine ();
+ PutEOD ();
+}
+
+/* LZW encoder */
+
+class LZWEncoder : public Ascii85Encoder
+{
+private:
+
+ struct LZWCTreeNode
+ {
+ LZWCTreeNode* mpBrother; // next node with same parent
+ LZWCTreeNode* mpFirstChild; // first son
+ sal_uInt16 mnCode; // code for the string
+ sal_uInt16 mnValue; // pixelvalue
+ };
+
+ LZWCTreeNode* mpTable; // LZW compression data
+ LZWCTreeNode* mpPrefix; // the compression is as same as the TIFF compression
+ sal_uInt16 mnDataSize;
+ sal_uInt16 mnClearCode;
+ sal_uInt16 mnEOICode;
+ sal_uInt16 mnTableSize;
+ sal_uInt16 mnCodeSize;
+ sal_uInt32 mnOffset;
+ sal_uInt32 mdwShift;
+
+ LZWEncoder ();
+ void WriteBits (sal_uInt16 nCode, sal_uInt16 nCodeLen);
+
+public:
+
+ LZWEncoder (osl::File* pOutputFile);
+ ~LZWEncoder ();
+
+ virtual void EncodeByte (sal_uInt8 nByte);
+};
+
+LZWEncoder::LZWEncoder(osl::File* pOutputFile) :
+ Ascii85Encoder (pOutputFile)
+{
+ mnDataSize = 8;
+
+ mnClearCode = 1 << mnDataSize;
+ mnEOICode = mnClearCode + 1;
+ mnTableSize = mnEOICode + 1;
+ mnCodeSize = mnDataSize + 1;
+
+ mnOffset = 32; // free bits in dwShift
+ mdwShift = 0;
+
+ mpTable = new LZWCTreeNode[ 4096 ];
+
+ for (sal_uInt32 i = 0; i < 4096; i++)
+ {
+ mpTable[i].mpBrother = NULL;
+ mpTable[i].mpFirstChild = NULL;
+ mpTable[i].mnCode = i;
+ mpTable[i].mnValue = (sal_uInt8)mpTable[i].mnCode;
+ }
+
+ mpPrefix = NULL;
+
+ WriteBits( mnClearCode, mnCodeSize );
+}
+
+LZWEncoder::~LZWEncoder()
+{
+ if (mpPrefix)
+ WriteBits (mpPrefix->mnCode, mnCodeSize);
+
+ WriteBits (mnEOICode, mnCodeSize);
+
+ delete[] mpTable;
+}
+
+void
+LZWEncoder::WriteBits (sal_uInt16 nCode, sal_uInt16 nCodeLen)
+{
+ mdwShift |= (nCode << (mnOffset - nCodeLen));
+ mnOffset -= nCodeLen;
+ while (mnOffset < 24)
+ {
+ WriteAscii ((sal_uInt8)(mdwShift >> 24));
+ mdwShift <<= 8;
+ mnOffset += 8;
+ }
+ if (nCode == 257 && mnOffset != 32)
+ WriteAscii ((sal_uInt8)(mdwShift >> 24));
+}
+
+void
+LZWEncoder::EncodeByte (sal_uInt8 nByte )
+{
+ LZWCTreeNode* p;
+ sal_uInt16 i;
+ sal_uInt8 nV;
+
+ if (!mpPrefix)
+ {
+ mpPrefix = mpTable + nByte;
+ }
+ else
+ {
+ nV = nByte;
+ for (p = mpPrefix->mpFirstChild; p != NULL; p = p->mpBrother)
+ {
+ if (p->mnValue == nV)
+ break;
+ }
+
+ if (p != NULL)
+ {
+ mpPrefix = p;
+ }
+ else
+ {
+ WriteBits (mpPrefix->mnCode, mnCodeSize);
+
+ if (mnTableSize == 409)
+ {
+ WriteBits (mnClearCode, mnCodeSize);
+
+ for (i = 0; i < mnClearCode; i++)
+ mpTable[i].mpFirstChild = NULL;
+
+ mnCodeSize = mnDataSize + 1;
+ mnTableSize = mnEOICode + 1;
+ }
+ else
+ {
+ if(mnTableSize == (sal_uInt16)((1 << mnCodeSize) - 1))
+ mnCodeSize++;
+
+ p = mpTable + (mnTableSize++);
+ p->mpBrother = mpPrefix->mpFirstChild;
+ mpPrefix->mpFirstChild = p;
+ p->mnValue = nV;
+ p->mpFirstChild = NULL;
+ }
+
+ mpPrefix = mpTable + nV;
+ }
+ }
+}
+
+/*
+ *
+ * bitmap handling routines
+ *
+ */
+
+void
+PrinterGfx::DrawBitmap (const Rectangle& rDest, const Rectangle& rSrc,
+ const PrinterBmp& rBitmap)
+{
+ double fScaleX = (double)rDest.GetWidth() / (double)rSrc.GetWidth();
+ double fScaleY = (double)rDest.GetHeight() / (double)rSrc.GetHeight();
+
+ PSGSave ();
+ PSTranslate (rDest.BottomLeft());
+ PSScale (fScaleX, fScaleY);
+
+ if (mnPSLevel >= 2)
+ {
+ if (rBitmap.GetDepth() == 1)
+ {
+ DrawPS2MonoImage (rBitmap, rSrc);
+ }
+ else
+ if (rBitmap.GetDepth() == 8 && mbColor)
+ {
+ // if the palette is larger than the image itself print it as a truecolor
+ // image to save diskspace. This is important for printing transparent
+ // bitmaps that are disassembled into small pieces
+ sal_Int32 nImageSz = rSrc.GetWidth() * rSrc.GetHeight();
+ sal_Int32 nPaletteSz = rBitmap.GetPaletteEntryCount();
+ if ((nImageSz < nPaletteSz) || (nImageSz < 24) )
+ DrawPS2TrueColorImage (rBitmap, rSrc);
+ else
+ DrawPS2PaletteImage (rBitmap, rSrc);
+ }
+ else
+ if (rBitmap.GetDepth() == 24 && mbColor)
+ {
+ DrawPS2TrueColorImage (rBitmap, rSrc);
+ }
+ else
+ {
+ DrawPS2GrayImage (rBitmap, rSrc);
+ }
+ }
+ else
+ {
+ DrawPS1GrayImage (rBitmap, rSrc);
+ }
+
+ PSGRestore ();
+}
+
+/* XXX does not work XXX */
+void
+PrinterGfx::DrawBitmap (const Rectangle& rDest, const Rectangle& rSrc,
+ const PrinterBmp& /*rBitmap*/, const PrinterBmp& /*rTransBitmap*/)
+{
+ double fScaleX = (double)rDest.GetWidth() / (double)rSrc.GetWidth();
+ double fScaleY = (double)rDest.GetHeight() / (double)rSrc.GetHeight();
+
+ PSGSave ();
+ PSTranslate (rDest.BottomLeft());
+ PSScale (fScaleX, fScaleY);
+ PSGRestore ();
+}
+
+/* XXX does not work XXX */
+void
+PrinterGfx::DrawMask (const Rectangle& rDest, const Rectangle& rSrc,
+ const PrinterBmp &/*rBitmap*/, PrinterColor& /*rMaskColor*/)
+{
+ double fScaleX = (double)rDest.GetWidth() / (double)rSrc.GetWidth();
+ double fScaleY = (double)rDest.GetHeight() / (double)rSrc.GetHeight();
+
+ PSGSave ();
+ PSTranslate (rDest.BottomLeft());
+ PSScale (fScaleX, fScaleY);
+ PSGRestore ();
+}
+
+/*
+ *
+ * Implementation: PS Level 1
+ *
+ */
+
+void
+PrinterGfx::DrawPS1GrayImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
+{
+ sal_uInt32 nWidth = rArea.GetWidth();
+ sal_uInt32 nHeight = rArea.GetHeight();
+
+ sal_Char pGrayImage [512];
+ sal_Int32 nChar = 0;
+
+ // image header
+ nChar += psp::getValueOf (nWidth, pGrayImage + nChar);
+ nChar += psp::appendStr (" ", pGrayImage + nChar);
+ nChar += psp::getValueOf (nHeight, pGrayImage + nChar);
+ nChar += psp::appendStr (" 8 ", pGrayImage + nChar);
+ nChar += psp::appendStr ("[ 1 0 0 1 0 ", pGrayImage + nChar);
+ nChar += psp::getValueOf (nHeight, pGrayImage + nChar);
+ nChar += psp::appendStr ("]", pGrayImage + nChar);
+ nChar += psp::appendStr (" {currentfile ", pGrayImage + nChar);
+ nChar += psp::getValueOf (nWidth, pGrayImage + nChar);
+ nChar += psp::appendStr (" string readhexstring pop}\n", pGrayImage + nChar);
+ nChar += psp::appendStr ("image\n", pGrayImage + nChar);
+
+ WritePS (mpPageBody, pGrayImage);
+
+ // image body
+ HexEncoder* pEncoder = new HexEncoder (mpPageBody);
+
+ for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
+ {
+ for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
+ {
+ sal_uChar nByte = rBitmap.GetPixelGray (nRow, nColumn);
+ pEncoder->EncodeByte (nByte);
+ }
+ }
+
+ delete pEncoder;
+
+ WritePS (mpPageBody, "\n");
+}
+
+/*
+ *
+ * Implementation: PS Level 2
+ *
+ */
+
+void
+PrinterGfx::writePS2ImageHeader (const Rectangle& rArea, psp::ImageType nType)
+{
+ sal_Int32 nChar = 0;
+ sal_Char pImage [512];
+
+ sal_Int32 nDictType = 0;
+ switch (nType)
+ {
+ case psp::TrueColorImage: nDictType = 0; break;
+ case psp::PaletteImage: nDictType = 1; break;
+ case psp::GrayScaleImage: nDictType = 2; break;
+ case psp::MonochromeImage: nDictType = 3; break;
+ default: break;
+ }
+ sal_Int32 nCompressType = mbCompressBmp ? 1 : 0;
+
+ nChar += psp::getValueOf (rArea.GetWidth(), pImage + nChar);
+ nChar += psp::appendStr (" ", pImage + nChar);
+ nChar += psp::getValueOf (rArea.GetHeight(), pImage + nChar);
+ nChar += psp::appendStr (" ", pImage + nChar);
+ nChar += psp::getValueOf (nDictType, pImage + nChar);
+ nChar += psp::appendStr (" ", pImage + nChar);
+ nChar += psp::getValueOf (nCompressType, pImage + nChar);
+ nChar += psp::appendStr (" psp_imagedict image\n", pImage + nChar);
+
+ WritePS (mpPageBody, pImage);
+}
+
+void
+PrinterGfx::writePS2Colorspace(const PrinterBmp& rBitmap, psp::ImageType nType)
+{
+ switch (nType)
+ {
+ case psp::GrayScaleImage:
+
+ WritePS (mpPageBody, "/DeviceGray setcolorspace\n");
+ break;
+
+ case psp::TrueColorImage:
+
+ WritePS (mpPageBody, "/DeviceRGB setcolorspace\n");
+ break;
+
+ case psp::MonochromeImage:
+ case psp::PaletteImage:
+ {
+
+ sal_Int32 nChar = 0;
+ sal_Char pImage [4096];
+
+ const sal_uInt32 nSize = rBitmap.GetPaletteEntryCount();
+
+ nChar += psp::appendStr ("[/Indexed /DeviceRGB ", pImage + nChar);
+ nChar += psp::getValueOf (nSize - 1, pImage + nChar);
+ if (mbCompressBmp)
+ nChar += psp::appendStr ("\npsp_lzwstring\n", pImage + nChar);
+ else
+ nChar += psp::appendStr ("\npsp_ascii85string\n", pImage + nChar);
+ WritePS (mpPageBody, pImage);
+
+ ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody)
+ : new Ascii85Encoder(mpPageBody);
+ for (sal_uInt32 i = 0; i < nSize; i++)
+ {
+ PrinterColor aColor = rBitmap.GetPaletteColor(i);
+
+ pEncoder->EncodeByte (aColor.GetRed());
+ pEncoder->EncodeByte (aColor.GetGreen());
+ pEncoder->EncodeByte (aColor.GetBlue());
+ }
+ delete pEncoder;
+
+ WritePS (mpPageBody, "pop ] setcolorspace\n");
+ }
+ break;
+ default: break;
+ }
+}
+
+void
+PrinterGfx::DrawPS2GrayImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
+{
+ writePS2Colorspace(rBitmap, psp::GrayScaleImage);
+ writePS2ImageHeader(rArea, psp::GrayScaleImage);
+
+ ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody)
+ : new Ascii85Encoder(mpPageBody);
+
+ for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
+ {
+ for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
+ {
+ sal_uChar nByte = rBitmap.GetPixelGray (nRow, nColumn);
+ pEncoder->EncodeByte (nByte);
+ }
+ }
+
+ delete pEncoder;
+}
+
+void
+PrinterGfx::DrawPS2MonoImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
+{
+ writePS2Colorspace(rBitmap, psp::MonochromeImage);
+ writePS2ImageHeader(rArea, psp::MonochromeImage);
+
+ ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody)
+ : new Ascii85Encoder(mpPageBody);
+
+ for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
+ {
+ long nBitPos = 0;
+ sal_uChar nBit = 0;
+ sal_uChar nByte = 0;
+
+ for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
+ {
+ nBit = rBitmap.GetPixelIdx (nRow, nColumn);
+ nByte |= nBit << (7 - nBitPos);
+
+ if (++nBitPos == 8)
+ {
+ pEncoder->EncodeByte (nByte);
+ nBitPos = 0;
+ nByte = 0;
+ }
+ }
+ // keep the row byte aligned
+ if (nBitPos != 0)
+ pEncoder->EncodeByte (nByte);
+ }
+
+ delete pEncoder;
+}
+
+void
+PrinterGfx::DrawPS2PaletteImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
+{
+ writePS2Colorspace(rBitmap, psp::PaletteImage);
+ writePS2ImageHeader(rArea, psp::PaletteImage);
+
+ ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody)
+ : new Ascii85Encoder(mpPageBody);
+
+ for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
+ {
+ for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
+ {
+ sal_uChar nByte = rBitmap.GetPixelIdx (nRow, nColumn);
+ pEncoder->EncodeByte (nByte);
+ }
+ }
+
+ delete pEncoder;
+}
+
+void
+PrinterGfx::DrawPS2TrueColorImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
+{
+ writePS2Colorspace(rBitmap, psp::TrueColorImage);
+ writePS2ImageHeader(rArea, psp::TrueColorImage);
+
+ ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody)
+ : new Ascii85Encoder(mpPageBody);
+
+ for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
+ {
+ for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
+ {
+ PrinterColor aColor = rBitmap.GetPixelRGB (nRow, nColumn);
+ pEncoder->EncodeByte (aColor.GetRed());
+ pEncoder->EncodeByte (aColor.GetGreen());
+ pEncoder->EncodeByte (aColor.GetBlue());
+ }
+ }
+
+ delete pEncoder;
+}
+
+} /* namespace psp */
diff --git a/vcl/unx/source/printergfx/common_gfx.cxx b/vcl/unx/source/printergfx/common_gfx.cxx
new file mode 100644
index 000000000000..6bb31acfcbbe
--- /dev/null
+++ b/vcl/unx/source/printergfx/common_gfx.cxx
@@ -0,0 +1,1284 @@
+/*************************************************************************
+ *
+ * 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 "psputil.hxx"
+#include "glyphset.hxx"
+
+#include "vcl/printergfx.hxx"
+#include "vcl/printerjob.hxx"
+#include "vcl/fontmanager.hxx"
+#include "vcl/strhelper.hxx"
+#include "vcl/printerinfomanager.hxx"
+
+#include "tools/debug.hxx"
+#include "tools/color.hxx"
+#include "tools/poly.hxx"
+
+using namespace psp ;
+
+static const sal_Int32 nMaxTextColumn = 80;
+
+GraphicsStatus::GraphicsStatus() :
+ mbArtItalic( false ),
+ mbArtBold( false ),
+ mnTextHeight( 0 ),
+ mnTextWidth( 0 ),
+ mfLineWidth( -1 )
+{
+}
+
+/*
+ * non graphics graphics routines
+ */
+
+sal_Bool
+PrinterGfx::Init (PrinterJob &rPrinterJob)
+{
+ mpPageHeader = rPrinterJob.GetCurrentPageHeader ();
+ mpPageBody = rPrinterJob.GetCurrentPageBody ();
+ mnDepth = rPrinterJob.GetDepth ();
+ mnPSLevel = rPrinterJob.GetPostscriptLevel ();
+ mbColor = rPrinterJob.IsColorPrinter ();
+
+ mnDpi = rPrinterJob.GetResolution();
+ rPrinterJob.GetScale (mfScaleX, mfScaleY);
+ const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( rPrinterJob.GetPrinterName() ) );
+ if( mpFontSubstitutes )
+ delete const_cast< ::std::hash_map<fontID,fontID>* >(mpFontSubstitutes);
+ if( rInfo.m_bPerformFontSubstitution )
+ mpFontSubstitutes = new ::std::hash_map< fontID, fontID >( rInfo.m_aFontSubstitutions );
+ else
+ mpFontSubstitutes = NULL;
+ mbUploadPS42Fonts = rInfo.m_pParser ? ( rInfo.m_pParser->isType42Capable() ? sal_True : sal_False ) : sal_False;
+
+ return sal_True;
+}
+
+sal_Bool
+PrinterGfx::Init (const JobData& rData)
+{
+ mpPageHeader = NULL;
+ mpPageBody = NULL;
+ mnDepth = rData.m_nColorDepth;
+ mnPSLevel = rData.m_nPSLevel ? rData.m_nPSLevel : (rData.m_pParser ? rData.m_pParser->getLanguageLevel() : 2 );
+ mbColor = rData.m_nColorDevice ? ( rData.m_nColorDevice == -1 ? sal_False : sal_True ) : (( rData.m_pParser ? (rData.m_pParser->isColorDevice() ? sal_True : sal_False ) : sal_True ) );
+ int nRes = rData.m_aContext.getRenderResolution();
+ mnDpi = nRes;
+ mfScaleX = (double)72.0 / (double)mnDpi;
+ mfScaleY = (double)72.0 / (double)mnDpi;
+ const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( rData.m_aPrinterName ) );
+ if( mpFontSubstitutes )
+ delete const_cast< ::std::hash_map<fontID,fontID>* >(mpFontSubstitutes);
+ if( rInfo.m_bPerformFontSubstitution )
+ mpFontSubstitutes = new ::std::hash_map< fontID, fontID >( rInfo.m_aFontSubstitutions );
+ else
+ mpFontSubstitutes = NULL;
+ mbUploadPS42Fonts = rInfo.m_pParser ? ( rInfo.m_pParser->isType42Capable() ? sal_True : sal_False ) : sal_False;
+
+ return sal_True;
+}
+
+void
+PrinterGfx::GetResolution (sal_Int32 &rDpiX, sal_Int32 &rDpiY) const
+{
+ rDpiX = mnDpi;
+ rDpiY = mnDpi;
+}
+
+sal_uInt16
+PrinterGfx::GetBitCount ()
+{
+ return mnDepth;
+}
+
+PrinterGfx::PrinterGfx() :
+ mpPageHeader (NULL),
+ mpPageBody (NULL),
+ mnFontID (0),
+ mnFallbackID (0),
+ mnTextAngle (0),
+ mbTextVertical (false),
+ mrFontMgr (PrintFontManager::get()),
+ mbCompressBmp (sal_True),
+ maFillColor (0xff,0,0),
+ maTextColor (0,0,0),
+ maLineColor (0, 0xff, 0),
+ mpFontSubstitutes( NULL ),
+ mbStrictSO52Compatibility( false )
+{
+ maVirtualStatus.mfLineWidth = 1.0;
+ maVirtualStatus.mnTextHeight = 12;
+ maVirtualStatus.mnTextWidth = 0;
+
+ maGraphicsStack.push_back( GraphicsStatus() );
+}
+
+PrinterGfx::~PrinterGfx()
+{
+ /*
+ * #95810# the original reasoning why mpFontSubstitutes is a pointer was
+ * that applications should release all PrinterGfx when printers change
+ * because they are really invalid; the corresponding printers may have
+ * changed their settings or even not exist anymore.
+ *
+ * Alas, this is not always done real time. So we keep a local copy of
+ * the font substitutes now in case of bad timing.
+ */
+ delete const_cast< ::std::hash_map<fontID,fontID>* >(mpFontSubstitutes);
+}
+
+void
+PrinterGfx::Clear()
+{
+ mpPageHeader = NULL;
+ mpPageBody = NULL;
+ mnFontID = 0;
+ maVirtualStatus = GraphicsStatus();
+ maVirtualStatus.mnTextHeight = 12;
+ maVirtualStatus.mnTextWidth = 0;
+ maVirtualStatus.mfLineWidth = 1.0;
+ mbTextVertical = false;
+ maLineColor = PrinterColor();
+ maFillColor = PrinterColor();
+ maTextColor = PrinterColor();
+ mbCompressBmp = sal_True;
+ mnDpi = 300;
+ mnDepth = 24;
+ mnPSLevel = 2;
+ mbColor = sal_True;
+ mnTextAngle = 0;
+
+ maClipRegion.clear();
+ maGraphicsStack.clear();
+ maGraphicsStack.push_back( GraphicsStatus() );
+}
+
+/*
+ * clip region handling
+ */
+
+void
+PrinterGfx::ResetClipRegion()
+{
+ maClipRegion.clear();
+ PSGRestore ();
+ PSGSave (); // get "clean" clippath
+}
+
+void
+PrinterGfx::BeginSetClipRegion( sal_uInt32 )
+{
+ maClipRegion.clear();
+}
+
+sal_Bool
+PrinterGfx::UnionClipRegion (sal_Int32 nX,sal_Int32 nY,sal_Int32 nDX,sal_Int32 nDY)
+{
+ if( nDX && nDY )
+ maClipRegion.push_back (Rectangle(Point(nX,nY ), Size(nDX,nDY)));
+ return sal_True;
+}
+
+sal_Bool
+PrinterGfx::JoinVerticalClipRectangles( std::list< Rectangle >::iterator& it,
+ Point& rOldPoint, sal_Int32& rColumn )
+{
+ sal_Bool bSuccess = sal_False;
+
+ std::list< Rectangle >::iterator tempit, nextit;
+ nextit = it;
+ ++nextit;
+ std::list< Point > leftside, rightside;
+
+ Rectangle aLastRect( *it );
+ leftside.push_back( Point( it->Left(), it->Top() ) );
+ rightside.push_back( Point( it->Right()+1, it->Top() ) );
+ while( nextit != maClipRegion.end() )
+ {
+ tempit = nextit;
+ ++tempit;
+ if( nextit->Top() == aLastRect.Bottom()+1 )
+ {
+ if(
+ ( nextit->Left() >= aLastRect.Left() && nextit->Left() <= aLastRect.Right() ) // left endpoint touches last rectangle
+ ||
+ ( nextit->Right() >= aLastRect.Left() && nextit->Right() <= aLastRect.Right() ) // right endpoint touches last rectangle
+ ||
+ ( nextit->Left() <= aLastRect.Left() && nextit->Right() >= aLastRect.Right() ) // whole line touches last rectangle
+ )
+ {
+ if( aLastRect.GetHeight() > 1 ||
+ abs( aLastRect.Left() - nextit->Left() ) > 2 ||
+ abs( aLastRect.Right() - nextit->Right() ) > 2
+ )
+ {
+ leftside.push_back( Point( aLastRect.Left(), aLastRect.Bottom()+1 ) );
+ rightside.push_back( Point( aLastRect.Right()+1, aLastRect.Bottom()+1 ) );
+ }
+ aLastRect = *nextit;
+ leftside.push_back( aLastRect.TopLeft() );
+ rightside.push_back( aLastRect.TopRight() );
+ maClipRegion.erase( nextit );
+ }
+ }
+ nextit = tempit;
+ }
+ if( leftside.size() > 1 )
+ {
+ // push the last coordinates
+ leftside.push_back( Point( aLastRect.Left(), aLastRect.Bottom()+1 ) );
+ rightside.push_back( Point( aLastRect.Right()+1, aLastRect.Bottom()+1 ) );
+
+ // cool, we can concatenate rectangles
+ int nDX = -65536, nDY = 65536;
+ int nNewDX = 0, nNewDY = 0;
+
+ Point aLastPoint = leftside.front();
+ PSBinMoveTo (aLastPoint, rOldPoint, rColumn);
+ leftside.pop_front();
+ while( leftside.begin() != leftside.end() )
+ {
+ Point aPoint (leftside.front());
+ leftside.pop_front();
+ // may have been the last one
+ if( leftside.begin() != leftside.end() )
+ {
+ nNewDX = aPoint.X() - aLastPoint.X();
+ nNewDY = aPoint.Y() - aLastPoint.Y();
+ if( nNewDX == 0 && nDX == 0 )
+ continue;
+ if( nDX != 0 && nNewDX != 0 &&
+ (double)nNewDY/(double)nNewDX == (double)nDY/(double)nDX )
+ continue;
+ }
+ PSBinLineTo (aPoint, rOldPoint, rColumn);
+ aLastPoint = aPoint;
+ }
+
+ aLastPoint = rightside.back();
+ nDX = -65536;
+ nDY = 65536;
+ PSBinLineTo (aLastPoint, rOldPoint, rColumn);
+ rightside.pop_back();
+ while( rightside.begin() != rightside.end() )
+ {
+ Point aPoint (rightside.back());
+ rightside.pop_back();
+ if( rightside.begin() != rightside.end() )
+ {
+ nNewDX = aPoint.X() - aLastPoint.X();
+ nNewDY = aPoint.Y() - aLastPoint.Y();
+ if( nNewDX == 0 && nDX == 0 )
+ continue;
+ if( nDX != 0 && nNewDX != 0 &&
+ (double)nNewDY/(double)nNewDX == (double)nDY/(double)nDX )
+ continue;
+ }
+ PSBinLineTo (aPoint, rOldPoint, rColumn);
+ }
+
+ tempit = it;
+ ++tempit;
+ maClipRegion.erase( it );
+ it = tempit;
+ bSuccess = sal_True;
+ }
+ return bSuccess;
+}
+
+void
+PrinterGfx::EndSetClipRegion()
+{
+ PSGRestore ();
+ PSGSave (); // get "clean" clippath
+
+ PSBinStartPath ();
+ Point aOldPoint (0, 0);
+ sal_Int32 nColumn = 0;
+
+ std::list< Rectangle >::iterator it = maClipRegion.begin();
+ while( it != maClipRegion.end() )
+ {
+ // try to concatenate adjacent rectangles
+ // first try in y direction, then in x direction
+ if( ! JoinVerticalClipRectangles( it, aOldPoint, nColumn ) )
+ {
+ // failed, so it is a single rectangle
+ PSBinMoveTo (it->TopLeft(), aOldPoint, nColumn );
+ PSBinLineTo (Point( it->Left(), it->Bottom()+1 ), aOldPoint, nColumn );
+ PSBinLineTo (Point( it->Right()+1, it->Bottom()+1 ), aOldPoint, nColumn );
+ PSBinLineTo (Point( it->Right()+1, it->Top() ), aOldPoint, nColumn );
+ ++it;
+ }
+ }
+
+ PSBinEndPath ();
+
+ WritePS (mpPageBody, "closepath clip newpath\n");
+ maClipRegion.clear();
+}
+
+/*
+ * draw graphic primitives
+ */
+
+void
+PrinterGfx::DrawRect (const Rectangle& rRectangle )
+{
+ char pRect [128];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::getValueOf (rRectangle.TopLeft().X(), pRect);
+ nChar += psp::appendStr (" ", pRect + nChar);
+ nChar += psp::getValueOf (rRectangle.TopLeft().Y(), pRect + nChar);
+ nChar += psp::appendStr (" ", pRect + nChar);
+ nChar += psp::getValueOf (rRectangle.GetWidth(), pRect + nChar);
+ nChar += psp::appendStr (" ", pRect + nChar);
+ nChar += psp::getValueOf (rRectangle.GetHeight(), pRect + nChar);
+ nChar += psp::appendStr (" ", pRect + nChar);
+
+ if( maFillColor.Is() )
+ {
+ PSSetColor (maFillColor);
+ PSSetColor ();
+ WritePS (mpPageBody, pRect, nChar);
+ WritePS (mpPageBody, "rectfill\n");
+ }
+ if( maLineColor.Is() )
+ {
+ PSSetColor (maLineColor);
+ PSSetColor ();
+ PSSetLineWidth ();
+ WritePS (mpPageBody, pRect, nChar);
+ WritePS (mpPageBody, "rectstroke\n");
+ }
+}
+
+void
+PrinterGfx::DrawLine (const Point& rFrom, const Point& rTo)
+{
+ if( maLineColor.Is() )
+ {
+ PSSetColor (maLineColor);
+ PSSetColor ();
+ PSSetLineWidth ();
+
+ PSMoveTo (rFrom);
+ PSLineTo (rTo);
+ WritePS (mpPageBody, "stroke\n" );
+ }
+}
+
+void
+PrinterGfx::DrawPixel (const Point& rPoint, const PrinterColor& rPixelColor)
+{
+ if( rPixelColor.Is() )
+ {
+ PSSetColor (rPixelColor);
+ PSSetColor ();
+
+ PSMoveTo (rPoint);
+ PSLineTo (Point (rPoint.X ()+1, rPoint.Y ()));
+ PSLineTo (Point (rPoint.X ()+1, rPoint.Y ()+1));
+ PSLineTo (Point (rPoint.X (), rPoint.Y ()+1));
+ WritePS (mpPageBody, "fill\n" );
+ }
+}
+
+void
+PrinterGfx::DrawPolyLine (sal_uInt32 nPoints, const Point* pPath)
+{
+ if( maLineColor.Is() && nPoints && pPath )
+ {
+ PSSetColor (maLineColor);
+ PSSetColor ();
+ PSSetLineWidth ();
+
+ PSBinCurrentPath (nPoints, pPath);
+
+ WritePS (mpPageBody, "stroke\n" );
+ }
+}
+
+void
+PrinterGfx::DrawPolygon (sal_uInt32 nPoints, const Point* pPath)
+{
+ // premature end of operation
+ if (!(nPoints > 1) || (pPath == NULL) || !(maFillColor.Is() || maLineColor.Is()))
+ return;
+
+ // setup closed path
+ Point aPoint( 0, 0 );
+ sal_Int32 nColumn( 0 );
+
+ PSBinStartPath();
+ PSBinMoveTo( pPath[0], aPoint, nColumn );
+ for( unsigned int n = 1; n < nPoints; n++ )
+ PSBinLineTo( pPath[n], aPoint, nColumn );
+ if( pPath[0] != pPath[nPoints-1] )
+ PSBinLineTo( pPath[0], aPoint, nColumn );
+ PSBinEndPath();
+
+ // fill the polygon first, then draw the border, note that fill and
+ // stroke reset the currentpath
+
+ // if fill and stroke, save the current path
+ if( maFillColor.Is() && maLineColor.Is())
+ PSGSave();
+
+ if (maFillColor.Is ())
+ {
+ PSSetColor (maFillColor);
+ PSSetColor ();
+ WritePS (mpPageBody, "eofill\n");
+ }
+
+ // restore the current path
+ if( maFillColor.Is() && maLineColor.Is())
+ PSGRestore();
+
+ if (maLineColor.Is ())
+ {
+ PSSetColor (maLineColor);
+ PSSetColor ();
+ PSSetLineWidth ();
+ WritePS (mpPageBody, "stroke\n");
+ }
+}
+
+void
+PrinterGfx::DrawPolyPolygon (sal_uInt32 nPoly, const sal_uInt32* pSizes, const Point** pPaths )
+{
+ // sanity check
+ if ( !nPoly || !pPaths || !(maFillColor.Is() || maLineColor.Is()))
+ return;
+
+
+ // setup closed path
+ for( unsigned int i = 0; i < nPoly; i++ )
+ {
+ Point aPoint( 0, 0 );
+ sal_Int32 nColumn( 0 );
+
+ PSBinStartPath();
+ PSBinMoveTo( pPaths[i][0], aPoint, nColumn );
+ for( unsigned int n = 1; n < pSizes[i]; n++ )
+ PSBinLineTo( pPaths[i][n], aPoint, nColumn );
+ if( pPaths[i][0] != pPaths[i][pSizes[i]-1] )
+ PSBinLineTo( pPaths[i][0], aPoint, nColumn );
+ PSBinEndPath();
+ }
+
+ // if eofill and stroke, save the current path
+ if( maFillColor.Is() && maLineColor.Is())
+ PSGSave();
+
+ // first draw area
+ if( maFillColor.Is() )
+ {
+ PSSetColor (maFillColor);
+ PSSetColor ();
+ WritePS (mpPageBody, "eofill\n");
+ }
+
+ // restore the current path
+ if( maFillColor.Is() && maLineColor.Is())
+ PSGRestore();
+
+ // now draw outlines
+ if( maLineColor.Is() )
+ {
+ PSSetColor (maLineColor);
+ PSSetColor ();
+ PSSetLineWidth ();
+ WritePS (mpPageBody, "stroke\n");
+ }
+}
+
+/*
+ * Bezier Polygon Drawing methods.
+ */
+
+void
+PrinterGfx::DrawPolyLineBezier (sal_uInt32 nPoints, const Point* pPath, const BYTE* pFlgAry)
+{
+ const sal_uInt32 nBezString = 1024;
+ sal_Char pString[nBezString];
+
+ if ( nPoints > 1 && maLineColor.Is() && pPath )
+ {
+ PSSetColor (maLineColor);
+ PSSetColor ();
+ PSSetLineWidth ();
+
+ snprintf(pString, nBezString, "%li %li moveto\n", pPath[0].X(), pPath[0].Y());
+ WritePS(mpPageBody, pString);
+
+ // Handle the drawing of mixed lines mixed with curves
+ // - a normal point followed by a normal point is a line
+ // - a normal point followed by 2 control points and a normal point is a curve
+ for (unsigned int i=1; i<nPoints;)
+ {
+ if (pFlgAry[i] != POLY_CONTROL) //If the next point is a POLY_NORMAL, we're drawing a line
+ {
+ snprintf(pString, nBezString, "%li %li lineto\n", pPath[i].X(), pPath[i].Y());
+ i++;
+ }
+ else //Otherwise we're drawing a spline
+ {
+ if (i+2 >= nPoints)
+ return; //Error: wrong sequence of contol/normal points somehow
+ if ((pFlgAry[i] == POLY_CONTROL) && (pFlgAry[i+1] == POLY_CONTROL) &&
+ (pFlgAry[i+2] != POLY_CONTROL))
+ {
+ snprintf(pString, nBezString, "%li %li %li %li %li %li curveto\n",
+ pPath[i].X(), pPath[i].Y(),
+ pPath[i+1].X(), pPath[i+1].Y(),
+ pPath[i+2].X(), pPath[i+2].Y());
+ }
+ else
+ {
+ DBG_ERROR( "PrinterGfx::DrawPolyLineBezier: Strange output" );
+ }
+ i+=3;
+ }
+ WritePS(mpPageBody, pString);
+ }
+
+ // now draw outlines
+ WritePS (mpPageBody, "stroke\n");
+ }
+}
+
+void
+PrinterGfx::DrawPolygonBezier (sal_uInt32 nPoints, const Point* pPath, const BYTE* pFlgAry)
+{
+ const sal_uInt32 nBezString = 1024;
+ sal_Char pString[nBezString];
+ // premature end of operation
+ if (!(nPoints > 1) || (pPath == NULL) || !(maFillColor.Is() || maLineColor.Is()))
+ return;
+
+ snprintf(pString, nBezString, "%li %li moveto\n", pPath[0].X(), pPath[0].Y());
+ WritePS(mpPageBody, pString); //Move to the starting point for the PolyPoygon
+ for (unsigned int i=1; i < nPoints;)
+ {
+ if (pFlgAry[i] != POLY_CONTROL)
+ {
+ snprintf(pString, nBezString, "%li %li lineto\n", pPath[i].X(), pPath[i].Y());
+ WritePS(mpPageBody, pString);
+ i++;
+ }
+ else
+ {
+ if (i+2 >= nPoints)
+ return; //Error: wrong sequence of contol/normal points somehow
+ if ((pFlgAry[i] == POLY_CONTROL) && (pFlgAry[i+1] == POLY_CONTROL) &&
+ (pFlgAry[i+2] != POLY_CONTROL))
+ {
+ snprintf(pString, nBezString, "%li %li %li %li %li %li curveto\n",
+ pPath[i].X(), pPath[i].Y(),
+ pPath[i+1].X(), pPath[i+1].Y(),
+ pPath[i+2].X(), pPath[i+2].Y());
+ WritePS(mpPageBody, pString);
+ }
+ else
+ {
+ DBG_ERROR( "PrinterGfx::DrawPolygonBezier: Strange output" );
+ }
+ i+=3;
+ }
+ }
+
+ // if fill and stroke, save the current path
+ if( maFillColor.Is() && maLineColor.Is())
+ PSGSave();
+
+ if (maFillColor.Is ())
+ {
+ PSSetColor (maFillColor);
+ PSSetColor ();
+ WritePS (mpPageBody, "eofill\n");
+ }
+
+ // restore the current path
+ if( maFillColor.Is() && maLineColor.Is())
+ PSGRestore();
+}
+
+void
+PrinterGfx::DrawPolyPolygonBezier (sal_uInt32 nPoly, const sal_uInt32 * pPoints, const Point* const * pPtAry, const BYTE* const* pFlgAry)
+{
+ const sal_uInt32 nBezString = 1024;
+ sal_Char pString[nBezString];
+ if ( !nPoly || !pPtAry || !pPoints || !(maFillColor.Is() || maLineColor.Is()))
+ return;
+
+
+ for (unsigned int i=0; i<nPoly;i++)
+ {
+ sal_uInt32 nPoints = pPoints[i];
+ // #112689# sanity check
+ if( nPoints == 0 || pPtAry[i] == NULL )
+ continue;
+
+ snprintf(pString, nBezString, "%li %li moveto\n", pPtAry[i][0].X(), pPtAry[i][0].Y()); //Move to the starting point
+ WritePS(mpPageBody, pString);
+ for (unsigned int j=1; j < nPoints;)
+ {
+ // if no flag array exists for this polygon, then it must be a regular
+ // polygon without beziers
+ if ( ! pFlgAry[i] || pFlgAry[i][j] != POLY_CONTROL)
+ {
+ snprintf(pString, nBezString, "%li %li lineto\n", pPtAry[i][j].X(), pPtAry[i][j].Y());
+ WritePS(mpPageBody, pString);
+ j++;
+ }
+ else
+ {
+ if (j+2 >= nPoints)
+ break; //Error: wrong sequence of contol/normal points somehow
+ if ((pFlgAry[i][j] == POLY_CONTROL) && (pFlgAry[i][j+1] == POLY_CONTROL) && (pFlgAry[i][j+2] != POLY_CONTROL))
+ {
+ snprintf(pString, nBezString, "%li %li %li %li %li %li curveto\n",
+ pPtAry[i][j].X(), pPtAry[i][j].Y(),
+ pPtAry[i][j+1].X(), pPtAry[i][j+1].Y(),
+ pPtAry[i][j+2].X(), pPtAry[i][j+2].Y());
+ WritePS(mpPageBody, pString);
+ }
+ else
+ {
+ DBG_ERROR( "PrinterGfx::DrawPolyPolygonBezier: Strange output" );
+ }
+ j+=3;
+ }
+ }
+ }
+
+ // if fill and stroke, save the current path
+ if( maFillColor.Is() && maLineColor.Is())
+ PSGSave();
+
+ if (maFillColor.Is ())
+ {
+ PSSetColor (maFillColor);
+ PSSetColor ();
+ WritePS (mpPageBody, "eofill\n");
+ }
+
+ // restore the current path
+ if( maFillColor.Is() && maLineColor.Is())
+ PSGRestore();
+}
+
+
+/*
+ * postscript generating routines
+ */
+void
+PrinterGfx::PSGSave ()
+{
+ WritePS (mpPageBody, "gsave\n" );
+ GraphicsStatus aNewState;
+ if( maGraphicsStack.begin() != maGraphicsStack.end() )
+ aNewState = maGraphicsStack.front();
+ maGraphicsStack.push_front( aNewState );
+}
+
+void
+PrinterGfx::PSGRestore ()
+{
+ WritePS (mpPageBody, "grestore\n" );
+ if( maGraphicsStack.begin() == maGraphicsStack.end() )
+ WritePS (mpPageBody, "Error: too many grestores\n" );
+ else
+ maGraphicsStack.pop_front();
+}
+
+void
+PrinterGfx::PSSetLineWidth ()
+{
+ if( currentState().mfLineWidth != maVirtualStatus.mfLineWidth )
+ {
+ char pBuffer[128];
+ sal_Int32 nChar = 0;
+
+ currentState().mfLineWidth = maVirtualStatus.mfLineWidth;
+ nChar = psp::getValueOfDouble (pBuffer, maVirtualStatus.mfLineWidth, 5);
+ nChar += psp::appendStr (" setlinewidth\n", pBuffer + nChar);
+ WritePS (mpPageBody, pBuffer, nChar);
+ }
+}
+
+void
+PrinterGfx::PSSetColor ()
+{
+ PrinterColor& rColor( maVirtualStatus.maColor );
+
+ if( currentState().maColor != rColor )
+ {
+ currentState().maColor = rColor;
+
+ char pBuffer[128];
+ sal_Int32 nChar = 0;
+
+ if( mbColor )
+ {
+ nChar = psp::getValueOfDouble (pBuffer,
+ (double)rColor.GetRed() / 255.0, 5);
+ nChar += psp::appendStr (" ", pBuffer + nChar);
+ nChar += psp::getValueOfDouble (pBuffer + nChar,
+ (double)rColor.GetGreen() / 255.0, 5);
+ nChar += psp::appendStr (" ", pBuffer + nChar);
+ nChar += psp::getValueOfDouble (pBuffer + nChar,
+ (double)rColor.GetBlue() / 255.0, 5);
+ nChar += psp::appendStr (" setrgbcolor\n", pBuffer + nChar );
+ }
+ else
+ {
+ Color aColor( rColor.GetRed(), rColor.GetGreen(), rColor.GetBlue() );
+ sal_uInt8 nCol = aColor.GetLuminance();
+ nChar = psp::getValueOfDouble( pBuffer, (double)nCol / 255.0, 5 );
+ nChar += psp::appendStr( " setgray\n", pBuffer + nChar );
+ }
+
+ WritePS (mpPageBody, pBuffer, nChar);
+ }
+}
+
+void
+PrinterGfx::PSSetFont ()
+{
+ GraphicsStatus& rCurrent( currentState() );
+ if( maVirtualStatus.maFont != rCurrent.maFont ||
+ maVirtualStatus.mnTextHeight != rCurrent.mnTextHeight ||
+ maVirtualStatus.maEncoding != rCurrent.maEncoding ||
+ maVirtualStatus.mnTextWidth != rCurrent.mnTextWidth ||
+ maVirtualStatus.mbArtBold != rCurrent.mbArtBold ||
+ maVirtualStatus.mbArtItalic != rCurrent.mbArtItalic
+ )
+ {
+ rCurrent.maFont = maVirtualStatus.maFont;
+ rCurrent.maEncoding = maVirtualStatus.maEncoding;
+ rCurrent.mnTextWidth = maVirtualStatus.mnTextWidth;
+ rCurrent.mnTextHeight = maVirtualStatus.mnTextHeight;
+ rCurrent.mbArtItalic = maVirtualStatus.mbArtItalic;
+ rCurrent.mbArtBold = maVirtualStatus.mbArtBold;
+
+ sal_Int32 nTextHeight = rCurrent.mnTextHeight;
+ sal_Int32 nTextWidth = rCurrent.mnTextWidth ? rCurrent.mnTextWidth
+ : rCurrent.mnTextHeight;
+
+ sal_Char pSetFont [256];
+ sal_Int32 nChar = 0;
+
+ // postscript based fonts need reencoding
+ if ( ( rCurrent.maEncoding == RTL_TEXTENCODING_MS_1252)
+ || ( rCurrent.maEncoding == RTL_TEXTENCODING_ISO_8859_1)
+ || ( rCurrent.maEncoding >= RTL_TEXTENCODING_USER_START
+ && rCurrent.maEncoding <= RTL_TEXTENCODING_USER_END)
+ )
+ {
+ rtl::OString aReencodedFont =
+ psp::GlyphSet::GetReencodedFontName (rCurrent.maEncoding,
+ rCurrent.maFont);
+
+ nChar += psp::appendStr ("(", pSetFont + nChar);
+ nChar += psp::appendStr (aReencodedFont.getStr(),
+ pSetFont + nChar);
+ nChar += psp::appendStr (") cvn findfont ",
+ pSetFont + nChar);
+ }
+ else
+ // tt based fonts mustn't reencode, the encoding is implied by the fontname
+ // same for symbol type1 fonts, dont try to touch them
+ {
+ nChar += psp::appendStr ("(", pSetFont + nChar);
+ nChar += psp::appendStr (rCurrent.maFont.getStr(),
+ pSetFont + nChar);
+ nChar += psp::appendStr (") cvn findfont ",
+ pSetFont + nChar);
+ }
+
+ if( ! rCurrent.mbArtItalic )
+ {
+ nChar += psp::getValueOf (nTextWidth, pSetFont + nChar);
+ nChar += psp::appendStr (" ", pSetFont + nChar);
+ nChar += psp::getValueOf (-nTextHeight, pSetFont + nChar);
+ nChar += psp::appendStr (" matrix scale makefont setfont\n", pSetFont + nChar);
+ }
+ else // skew 15 degrees to right
+ {
+ nChar += psp::appendStr ( " [", pSetFont + nChar);
+ nChar += psp::getValueOf (nTextWidth, pSetFont + nChar);
+ nChar += psp::appendStr (" 0 ", pSetFont + nChar);
+ nChar += psp::getValueOfDouble (pSetFont + nChar, 0.27*(double)nTextWidth, 3 );
+ nChar += psp::appendStr ( " ", pSetFont + nChar);
+ nChar += psp::getValueOf (-nTextHeight, pSetFont + nChar);
+
+ nChar += psp::appendStr (" 0 0] makefont setfont\n", pSetFont + nChar);
+ }
+
+ WritePS (mpPageBody, pSetFont);
+ }
+}
+
+void
+PrinterGfx::PSRotate (sal_Int32 nAngle)
+{
+ sal_Int32 nPostScriptAngle = -nAngle;
+ while( nPostScriptAngle < 0 )
+ nPostScriptAngle += 3600;
+
+ if (nPostScriptAngle == 0)
+ return;
+
+ sal_Int32 nFullAngle = nPostScriptAngle / 10;
+ sal_Int32 nTenthAngle = nPostScriptAngle % 10;
+
+ sal_Char pRotate [48];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::getValueOf (nFullAngle, pRotate);
+ nChar += psp::appendStr (".", pRotate + nChar);
+ nChar += psp::getValueOf (nTenthAngle, pRotate + nChar);
+ nChar += psp::appendStr (" rotate\n", pRotate + nChar);
+
+ WritePS (mpPageBody, pRotate);
+}
+
+void
+PrinterGfx::PSPointOp (const Point& rPoint, const sal_Char* pOperator)
+{
+ sal_Char pPSCommand [48];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::getValueOf (rPoint.X(), pPSCommand);
+ nChar += psp::appendStr (" ", pPSCommand + nChar);
+ nChar += psp::getValueOf (rPoint.Y(), pPSCommand + nChar);
+ nChar += psp::appendStr (" ", pPSCommand + nChar);
+ nChar += psp::appendStr (pOperator, pPSCommand + nChar);
+ nChar += psp::appendStr ("\n", pPSCommand + nChar);
+
+ DBG_ASSERT (nChar < 48, "Buffer overflow in PSPointOp");
+
+ WritePS (mpPageBody, pPSCommand);
+}
+
+void
+PrinterGfx::PSTranslate (const Point& rPoint)
+{
+ PSPointOp (rPoint, "translate");
+}
+
+void
+PrinterGfx::PSMoveTo (const Point& rPoint)
+{
+ PSPointOp (rPoint, "moveto");
+}
+
+void
+PrinterGfx::PSLineTo (const Point& rPoint)
+{
+ PSPointOp (rPoint, "lineto");
+}
+
+void
+PrinterGfx::PSRMoveTo (sal_Int32 nDx, sal_Int32 nDy)
+{
+ Point aPoint(nDx, nDy);
+ PSPointOp (aPoint, "rmoveto");
+}
+
+/* get a compressed representation of the path information */
+
+#define DEBUG_BINPATH 0
+
+void
+PrinterGfx::PSBinLineTo (const Point& rCurrent, Point& rOld, sal_Int32& nColumn)
+{
+#if (DEBUG_BINPATH == 1)
+ PSLineTo (rCurrent);
+#else
+ PSBinPath (rCurrent, rOld, lineto, nColumn);
+#endif
+}
+
+void
+PrinterGfx::PSBinMoveTo (const Point& rCurrent, Point& rOld, sal_Int32& nColumn)
+{
+#if (DEBUG_BINPATH == 1)
+ PSMoveTo (rCurrent);
+#else
+ PSBinPath (rCurrent, rOld, moveto, nColumn);
+#endif
+}
+
+void
+PrinterGfx::PSBinStartPath ()
+{
+#if (DEBUG_BINPATH == 1)
+ WritePS (mpPageBody, "% PSBinStartPath\n");
+#else
+ WritePS (mpPageBody, "readpath\n" );
+#endif
+}
+
+void
+PrinterGfx::PSBinEndPath ()
+{
+#if (DEBUG_BINPATH == 1)
+ WritePS (mpPageBody, "% PSBinEndPath\n");
+#else
+ WritePS (mpPageBody, "~\n");
+#endif
+}
+
+void
+PrinterGfx::PSBinCurrentPath (sal_uInt32 nPoints, const Point* pPath)
+{
+ // create the path
+ Point aPoint (0, 0);
+ sal_Int32 nColumn = 0;
+
+ PSBinStartPath ();
+ PSBinMoveTo (*pPath, aPoint, nColumn);
+ for (unsigned int i = 1; i < nPoints; i++)
+ PSBinLineTo (pPath[i], aPoint, nColumn);
+ PSBinEndPath ();
+}
+
+void
+PrinterGfx::PSBinPath (const Point& rCurrent, Point& rOld,
+ pspath_t eType, sal_Int32& nColumn)
+{
+ sal_Char pPath[48];
+ sal_Int32 nChar;
+
+ // create the hex representation of the dx and dy path shift, store the field
+ // width as it is needed for the building the command
+ sal_Int32 nXPrec = getAlignedHexValueOf (rCurrent.X() - rOld.X(), pPath + 1);
+ sal_Int32 nYPrec = getAlignedHexValueOf (rCurrent.Y() - rOld.Y(), pPath + 1 + nXPrec);
+ pPath [ 1 + nXPrec + nYPrec ] = 0;
+
+ // build the command, it is a char with bit represention 000cxxyy
+ // c represents the char, xx and yy repr. the field width of the dx and dy shift,
+ // dx and dy represent the number of bytes to read after the opcode
+ sal_Char cCmd = (eType == lineto ? (sal_Char)0x00 : (sal_Char)0x10);
+ switch (nYPrec)
+ {
+ case 2: break;
+ case 4: cCmd |= 0x01; break;
+ case 6: cCmd |= 0x02; break;
+ case 8: cCmd |= 0x03; break;
+ default: DBG_ERROR ("invalid x precision in binary path");
+ }
+ switch (nXPrec)
+ {
+ case 2: break;
+ case 4: cCmd |= 0x04; break;
+ case 6: cCmd |= 0x08; break;
+ case 8: cCmd |= 0x0c; break;
+ default: DBG_ERROR ("invalid y precision in binary path");
+ }
+ cCmd += 'A';
+ pPath[0] = cCmd;
+
+ // write the command to file,
+ // line breaking at column nMaxTextColumn (80)
+ nChar = 1 + nXPrec + nYPrec;
+ if ((nColumn + nChar) > nMaxTextColumn)
+ {
+ sal_Int32 nSegment = nMaxTextColumn - nColumn;
+
+ WritePS (mpPageBody, pPath, nSegment);
+ WritePS (mpPageBody, "\n", 1);
+ WritePS (mpPageBody, pPath + nSegment, nChar - nSegment);
+
+ nColumn = nChar - nSegment;
+ }
+ else
+ {
+ WritePS (mpPageBody, pPath, nChar);
+
+ nColumn += nChar;
+ }
+
+ rOld = rCurrent;
+}
+
+void
+PrinterGfx::PSScale (double fScaleX, double fScaleY)
+{
+ sal_Char pScale [48];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::getValueOfDouble (pScale, fScaleX, 5);
+ nChar += psp::appendStr (" ", pScale + nChar);
+ nChar += psp::getValueOfDouble (pScale + nChar, fScaleY, 5);
+ nChar += psp::appendStr (" scale\n", pScale + nChar);
+
+ WritePS (mpPageBody, pScale);
+}
+
+/* psshowtext helper routines: draw an hex string for show/xshow */
+void
+PrinterGfx::PSHexString (const sal_uChar* pString, sal_Int16 nLen)
+{
+ sal_Char pHexString [128];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::appendStr ("<", pHexString);
+ for (int i = 0; i < nLen; i++)
+ {
+ if (nChar >= (nMaxTextColumn - 1))
+ {
+ nChar += psp::appendStr ("\n", pHexString + nChar);
+ WritePS (mpPageBody, pHexString, nChar);
+ nChar = 0;
+ }
+ nChar += psp::getHexValueOf ((sal_Int32)pString[i], pHexString + nChar);
+ }
+
+ nChar += psp::appendStr (">\n", pHexString + nChar);
+ WritePS (mpPageBody, pHexString, nChar);
+}
+
+/* psshowtext helper routines: draw an array for xshow ps operator */
+void
+PrinterGfx::PSDeltaArray (const sal_Int32 *pArray, sal_Int16 nEntries)
+{
+ sal_Char pPSArray [128];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::appendStr ("[", pPSArray + nChar);
+ nChar += psp::getValueOf (pArray[0], pPSArray + nChar);
+
+ for (int i = 1; i < nEntries; i++)
+ {
+ if (nChar >= (nMaxTextColumn - 1))
+ {
+ nChar += psp::appendStr ("\n", pPSArray + nChar);
+ WritePS (mpPageBody, pPSArray, nChar);
+ nChar = 0;
+ }
+
+ nChar += psp::appendStr (" ", pPSArray + nChar);
+ nChar += psp::getValueOf (pArray[i] - pArray[i-1], pPSArray + nChar);
+ }
+
+ nChar += psp::appendStr (" 0]\n", pPSArray + nChar);
+ WritePS (mpPageBody, pPSArray);
+}
+
+/* the DrawText equivalent, pDeltaArray may be NULL. For Type1 fonts or single byte
+ * fonts in general nBytes and nGlyphs is the same. For printer resident Composite
+ * fonts it may be different (these fonts may be SJIS encoded for example) */
+void
+PrinterGfx::PSShowText (const sal_uChar* pStr, sal_Int16 nGlyphs, sal_Int16 nBytes,
+ const sal_Int32* pDeltaArray)
+{
+ PSSetColor (maTextColor);
+ PSSetColor ();
+ PSSetFont ();
+ // rotate the user coordinate system
+ if (mnTextAngle != 0)
+ {
+ PSGSave ();
+ PSRotate (mnTextAngle);
+ }
+
+ sal_Char pBuffer[256];
+ if( maVirtualStatus.mbArtBold )
+ {
+ sal_Int32 nLW = maVirtualStatus.mnTextWidth;
+ if( nLW == 0 )
+ nLW = maVirtualStatus.mnTextHeight;
+ else
+ nLW = nLW < maVirtualStatus.mnTextHeight ? nLW : maVirtualStatus.mnTextHeight;
+ psp::getValueOfDouble( pBuffer, (double)nLW / 30.0 );
+ }
+ // dispatch to the drawing method
+ if (pDeltaArray == NULL)
+ {
+ PSHexString (pStr, nBytes);
+
+ if( maVirtualStatus.mbArtBold )
+ {
+ WritePS( mpPageBody, pBuffer );
+ WritePS( mpPageBody, " bshow\n" );
+ }
+ else
+ WritePS (mpPageBody, "show\n");
+ }
+ else
+ {
+ PSHexString (pStr, nBytes);
+ PSDeltaArray (pDeltaArray, nGlyphs - 1);
+ if( maVirtualStatus.mbArtBold )
+ {
+ WritePS( mpPageBody, pBuffer );
+ WritePS( mpPageBody, " bxshow\n" );
+ }
+ else
+ WritePS (mpPageBody, "xshow\n");
+ }
+
+ // restore the user coordinate system
+ if (mnTextAngle != 0)
+ PSGRestore ();
+}
+
+void
+PrinterGfx::PSComment( const sal_Char* pComment )
+{
+ const sal_Char* pLast = pComment;
+ while( pComment && *pComment )
+ {
+ while( *pComment && *pComment != '\n' && *pComment != '\r' )
+ pComment++;
+ if( pComment - pLast > 1 )
+ {
+ WritePS( mpPageBody, "% ", 2 );
+ WritePS( mpPageBody, pLast, pComment - pLast );
+ WritePS( mpPageBody, "\n", 1 );
+ }
+ if( *pComment )
+ pLast = ++pComment;
+ }
+}
+
+sal_Bool
+PrinterGfx::DrawEPS( const Rectangle& rBoundingBox, void* pPtr, sal_uInt32 nSize )
+{
+ if( nSize == 0 )
+ return sal_True;
+ if( ! mpPageBody )
+ return sal_False;
+
+ sal_Bool bSuccess = sal_False;
+
+ // first search the BoundingBox of the EPS data
+ SvMemoryStream aStream( pPtr, nSize, STREAM_READ );
+ aStream.Seek( STREAM_SEEK_TO_BEGIN );
+ ByteString aLine;
+
+ ByteString aDocTitle;
+ double fLeft = 0, fRight = 0, fTop = 0, fBottom = 0;
+ bool bEndComments = false;
+ while( ! aStream.IsEof()
+ && ( ( fLeft == 0 && fRight == 0 && fTop == 0 && fBottom == 0 ) ||
+ ( aDocTitle.Len() == 0 && bEndComments == false ) )
+ )
+ {
+ aStream.ReadLine( aLine );
+ if( aLine.Len() > 1 && aLine.GetChar( 0 ) == '%' )
+ {
+ char cChar = aLine.GetChar(1);
+ if( cChar == '%' )
+ {
+ if( aLine.CompareIgnoreCaseToAscii( "%%BoundingBox:", 14 ) == COMPARE_EQUAL )
+ {
+ aLine = WhitespaceToSpace( aLine.GetToken( 1, ':' ) );
+ if( aLine.Len() && aLine.Search( "atend" ) == STRING_NOTFOUND )
+ {
+ fLeft = StringToDouble( GetCommandLineToken( 0, aLine ) );
+ fBottom = StringToDouble( GetCommandLineToken( 1, aLine ) );
+ fRight = StringToDouble( GetCommandLineToken( 2, aLine ) );
+ fTop = StringToDouble( GetCommandLineToken( 3, aLine ) );
+ }
+ }
+ else if( aLine.CompareIgnoreCaseToAscii( "%%Title:", 8 ) == COMPARE_EQUAL )
+ aDocTitle = WhitespaceToSpace( aLine.Copy( 8 ) );
+ else if( aLine.CompareIgnoreCaseToAscii( "%%EndComments", 13 ) == COMPARE_EQUAL )
+ bEndComments = true;
+ }
+ else if( cChar == ' ' || cChar == '\t' || cChar == '\r' || cChar == '\n' )
+ bEndComments = true;
+ }
+ else
+ bEndComments = true;
+ }
+
+ static sal_uInt16 nEps = 0;
+ if( ! aDocTitle.Len() )
+ aDocTitle = ByteString::CreateFromInt32( (sal_Int32)(nEps++) );
+
+ if( fLeft != fRight && fTop != fBottom )
+ {
+ double fScaleX = (double)rBoundingBox.GetWidth()/(fRight-fLeft);
+ double fScaleY = -(double)rBoundingBox.GetHeight()/(fTop-fBottom);
+ Point aTranslatePoint( (int)(rBoundingBox.Left()-fLeft*fScaleX),
+ (int)(rBoundingBox.Bottom()+1-fBottom*fScaleY) );
+ // prepare EPS
+ WritePS( mpPageBody,
+ "/b4_Inc_state save def\n"
+ "/dict_count countdictstack def\n"
+ "/op_count count 1 sub def\n"
+ "userdict begin\n"
+ "/showpage {} def\n"
+ "0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin\n"
+ "10 setmiterlimit [] 0 setdash newpath\n"
+ "/languagelevel where\n"
+ "{pop languagelevel\n"
+ "1 ne\n"
+ " {false setstrokeadjust false setoverprint\n"
+ " } if\n"
+ "}if\n" );
+ // set up clip path and scale
+ BeginSetClipRegion( 1 );
+ UnionClipRegion( rBoundingBox.Left(), rBoundingBox.Top(), rBoundingBox.GetWidth(), rBoundingBox.GetHeight() );
+ EndSetClipRegion();
+ PSTranslate( aTranslatePoint );
+ PSScale( fScaleX, fScaleY );
+
+ // DSC requires BeginDocument
+ WritePS( mpPageBody, "%%BeginDocument: " );
+ WritePS( mpPageBody, aDocTitle );
+ WritePS( mpPageBody, "\n" );
+
+ // write the EPS data
+ sal_uInt64 nOutLength;
+ mpPageBody->write( pPtr, nSize, nOutLength );
+ bSuccess = nOutLength == nSize;
+
+ // corresponding EndDocument
+ if( ((char*)pPtr)[ nSize-1 ] != '\n' )
+ WritePS( mpPageBody, "\n" );
+ WritePS( mpPageBody, "%%EndDocument\n" );
+
+ // clean up EPS
+ WritePS( mpPageBody,
+ "count op_count sub {pop} repeat\n"
+ "countdictstack dict_count sub {end} repeat\n"
+ "b4_Inc_state restore\n" );
+ }
+ return bSuccess;
+}
diff --git a/vcl/unx/source/printergfx/glyphset.cxx b/vcl/unx/source/printergfx/glyphset.cxx
new file mode 100644
index 000000000000..8885a6b42c1e
--- /dev/null
+++ b/vcl/unx/source/printergfx/glyphset.cxx
@@ -0,0 +1,942 @@
+/*************************************************************************
+ *
+ * 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 "glyphset.hxx"
+#include "psputil.hxx"
+
+#include "sft.hxx"
+
+#include "vcl/printergfx.hxx"
+#include "vcl/fontmanager.hxx"
+#include "vcl/fontsubset.hxx"
+
+#include "osl/thread.h"
+
+#include "sal/alloca.h"
+
+#include "rtl/ustring.hxx"
+#include "rtl/strbuf.hxx"
+
+#include <set>
+#include <map>
+#include <algorithm>
+
+using namespace vcl;
+using namespace psp;
+using namespace rtl;
+
+GlyphSet::GlyphSet ()
+ : mnFontID (-1),
+ mbVertical (0),
+ mbUseFontEncoding (false)
+{}
+
+GlyphSet::GlyphSet (sal_Int32 nFontID, sal_Bool bVertical)
+ : mnFontID (nFontID),
+ mbVertical (bVertical)
+{
+ PrintFontManager &rMgr = PrintFontManager::get();
+ meBaseType = rMgr.getFontType (mnFontID);
+ maBaseName = OUStringToOString (rMgr.getPSName(mnFontID),
+ RTL_TEXTENCODING_ASCII_US);
+ mnBaseEncoding = rMgr.getFontEncoding(mnFontID);
+ mbUseFontEncoding = rMgr.getUseOnlyFontEncoding(mnFontID);
+}
+
+GlyphSet::~GlyphSet ()
+{
+ /* FIXME delete the glyphlist ??? */
+}
+
+sal_Int32
+GlyphSet::GetFontID ()
+{
+ return mnFontID;
+}
+
+fonttype::type
+GlyphSet::GetFontType ()
+{
+ return meBaseType;
+}
+
+sal_Bool
+GlyphSet::IsVertical ()
+{
+ return mbVertical;
+}
+
+sal_Bool
+GlyphSet::SetFont (sal_Int32 nFontID, sal_Bool bVertical)
+{
+ if (mnFontID != -1)
+ return sal_False;
+
+ mnFontID = nFontID;
+ mbVertical = bVertical;
+
+ PrintFontManager &rMgr = PrintFontManager::get();
+ meBaseType = rMgr.getFontType (mnFontID);
+ maBaseName = OUStringToOString (rMgr.getPSName(mnFontID),
+ RTL_TEXTENCODING_ASCII_US);
+ mnBaseEncoding = rMgr.getFontEncoding(mnFontID);
+ mbUseFontEncoding = rMgr.getUseOnlyFontEncoding(mnFontID);
+
+ return sal_True;
+}
+
+sal_Bool
+GlyphSet::GetCharID (
+ sal_Unicode nChar,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID
+ )
+{
+ return LookupCharID (nChar, nOutGlyphID, nOutGlyphSetID)
+ || AddCharID (nChar, nOutGlyphID, nOutGlyphSetID);
+}
+
+sal_Bool
+GlyphSet::GetGlyphID (
+ sal_uInt32 nGlyph,
+ sal_Unicode nUnicode,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID
+ )
+{
+ return LookupGlyphID (nGlyph, nOutGlyphID, nOutGlyphSetID)
+ || AddGlyphID (nGlyph, nUnicode, nOutGlyphID, nOutGlyphSetID);
+}
+
+sal_Bool
+GlyphSet::LookupCharID (
+ sal_Unicode nChar,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID
+ )
+{
+ char_list_t::iterator aGlyphSet;
+ sal_Int32 nGlyphSetID;
+
+ // loop thru all the font subsets
+ for (aGlyphSet = maCharList.begin(), nGlyphSetID = 1;
+ aGlyphSet != maCharList.end();
+ ++aGlyphSet, nGlyphSetID++)
+ {
+ // check every subset if it contains the queried unicode char
+ char_map_t::const_iterator aGlyph = (*aGlyphSet).find (nChar);
+ if (aGlyph != (*aGlyphSet).end())
+ {
+ // success: found the unicode char, return the glyphid and the glyphsetid
+ *nOutGlyphSetID = nGlyphSetID;
+ *nOutGlyphID = (*aGlyph).second;
+ return sal_True;
+ }
+ }
+
+ *nOutGlyphSetID = -1;
+ *nOutGlyphID = 0;
+ return sal_False;
+}
+
+sal_Bool
+GlyphSet::LookupGlyphID (
+ sal_uInt32 nGlyph,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID
+ )
+{
+ glyph_list_t::iterator aGlyphSet;
+ sal_Int32 nGlyphSetID;
+
+ // loop thru all the font subsets
+ for (aGlyphSet = maGlyphList.begin(), nGlyphSetID = 1;
+ aGlyphSet != maGlyphList.end();
+ ++aGlyphSet, nGlyphSetID++)
+ {
+ // check every subset if it contains the queried unicode char
+ glyph_map_t::const_iterator aGlyph = (*aGlyphSet).find (nGlyph);
+ if (aGlyph != (*aGlyphSet).end())
+ {
+ // success: found the glyph id, return the mapped glyphid and the glyphsetid
+ *nOutGlyphSetID = nGlyphSetID;
+ *nOutGlyphID = (*aGlyph).second;
+ return sal_True;
+ }
+ }
+
+ *nOutGlyphSetID = -1;
+ *nOutGlyphID = 0;
+ return sal_False;
+}
+
+sal_uChar
+GlyphSet::GetAnsiMapping (sal_Unicode nUnicodeChar)
+{
+ static rtl_UnicodeToTextConverter aConverter =
+ rtl_createUnicodeToTextConverter(RTL_TEXTENCODING_MS_1252);
+ static rtl_UnicodeToTextContext aContext =
+ rtl_createUnicodeToTextContext( aConverter );
+
+ sal_Char nAnsiChar;
+ sal_uInt32 nCvtInfo;
+ sal_Size nCvtChars;
+ const sal_uInt32 nCvtFlags = RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
+ | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR;
+
+ sal_Size nSize = rtl_convertUnicodeToText( aConverter, aContext,
+ &nUnicodeChar, 1, &nAnsiChar, 1,
+ nCvtFlags, &nCvtInfo, &nCvtChars );
+
+ return nSize == 1 ? (sal_uChar)nAnsiChar : (sal_uChar)0;
+}
+
+sal_uChar
+GlyphSet::GetSymbolMapping (sal_Unicode nUnicodeChar)
+{
+ if (0x0000 < nUnicodeChar && nUnicodeChar < 0x0100)
+ return (sal_uChar)nUnicodeChar;
+ if (0xf000 < nUnicodeChar && nUnicodeChar < 0xf100)
+ return (sal_uChar)nUnicodeChar;
+
+ return 0;
+}
+
+void
+GlyphSet::AddNotdef (char_map_t &rCharMap)
+{
+ if (rCharMap.size() == 0)
+ rCharMap[0] = 0;
+}
+
+void
+GlyphSet::AddNotdef (glyph_map_t &rGlyphMap)
+{
+ if (rGlyphMap.size() == 0)
+ rGlyphMap[0] = 0;
+}
+sal_Bool
+GlyphSet::AddCharID (
+ sal_Unicode nChar,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID
+ )
+{
+ sal_uChar nMappedChar;
+
+ // XXX important: avoid to reencode type1 symbol fonts
+ if (mnBaseEncoding == RTL_TEXTENCODING_SYMBOL)
+ nMappedChar = GetSymbolMapping (nChar);
+ else
+ nMappedChar = GetAnsiMapping (nChar);
+
+ // create an empty glyphmap that is reserved for iso1252 encoded glyphs
+ // (or -- unencoded -- symbol glyphs) and a second map that takes any other
+ if (maCharList.empty())
+ {
+ char_map_t aMap, aMapp;
+
+ maCharList.push_back (aMap);
+ maCharList.push_back (aMapp);
+ }
+ // if the last map is full, create a new one
+ if ((!nMappedChar) && (maCharList.back().size() == 255))
+ {
+ char_map_t aMap;
+ maCharList.push_back (aMap);
+ }
+
+ // insert a new glyph in the font subset
+ if (nMappedChar)
+ {
+ // always put iso1252 chars into the first map, map them on itself
+ char_map_t& aGlyphSet = maCharList.front();
+ AddNotdef (aGlyphSet);
+
+ aGlyphSet [nChar] = nMappedChar;
+ *nOutGlyphSetID = 1;
+ *nOutGlyphID = nMappedChar;
+ }
+ else
+ {
+ // other chars are just appended to the list
+ char_map_t& aGlyphSet = maCharList.back();
+ AddNotdef (aGlyphSet);
+
+ int nSize = aGlyphSet.size();
+
+ aGlyphSet [nChar] = nSize;
+ *nOutGlyphSetID = maCharList.size();
+ *nOutGlyphID = aGlyphSet [nChar];
+ }
+
+ return sal_True;
+}
+
+sal_Bool
+GlyphSet::AddGlyphID (
+ sal_uInt32 nGlyph,
+ sal_Unicode nUnicode,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID
+ )
+{
+ sal_uChar nMappedChar;
+
+ // XXX important: avoid to reencode type1 symbol fonts
+ if (mnBaseEncoding == RTL_TEXTENCODING_SYMBOL)
+ nMappedChar = GetSymbolMapping (nUnicode);
+ else
+ nMappedChar = GetAnsiMapping (nUnicode);
+
+ // create an empty glyphmap that is reserved for iso1252 encoded glyphs
+ // (or -- unencoded -- symbol glyphs) and a second map that takes any other
+ if (maGlyphList.empty())
+ {
+ glyph_map_t aMap, aMapp;
+
+ maGlyphList.push_back (aMap);
+ maGlyphList.push_back (aMapp);
+ }
+ // if the last map is full, create a new one
+ if ((!nMappedChar) && (maGlyphList.back().size() == 255))
+ {
+ glyph_map_t aMap;
+ maGlyphList.push_back (aMap);
+ }
+
+ // insert a new glyph in the font subset
+ if (nMappedChar)
+ {
+ // always put iso1252 chars into the first map, map them on itself
+ glyph_map_t& aGlyphSet = maGlyphList.front();
+ AddNotdef (aGlyphSet);
+
+ aGlyphSet [nGlyph] = nMappedChar;
+ *nOutGlyphSetID = 1;
+ *nOutGlyphID = nMappedChar;
+ }
+ else
+ {
+ // other chars are just appended to the list
+ glyph_map_t& aGlyphSet = maGlyphList.back();
+ AddNotdef (aGlyphSet);
+
+ int nSize = aGlyphSet.size();
+
+ aGlyphSet [nGlyph] = nSize;
+ *nOutGlyphSetID = maGlyphList.size();
+ *nOutGlyphID = aGlyphSet [nGlyph];
+ }
+
+ return sal_True;
+}
+
+OString
+GlyphSet::GetCharSetName (sal_Int32 nGlyphSetID)
+{
+ if (meBaseType == fonttype::TrueType)
+ {
+ OStringBuffer aSetName( maBaseName.getLength() + 32 );
+ aSetName.append( maBaseName );
+ aSetName.append( "FID" );
+ aSetName.append( mnFontID );
+ aSetName.append( mbVertical ? "VCSet" : "HCSet" );
+ aSetName.append( nGlyphSetID );
+ return aSetName.makeStringAndClear();
+ }
+ else
+ /* (meBaseType == fonttype::Type1 || meBaseType == fonttype::Builtin) */
+ {
+ return maBaseName;
+ }
+}
+
+OString
+GlyphSet::GetGlyphSetName (sal_Int32 nGlyphSetID)
+{
+ if (meBaseType == fonttype::TrueType)
+ {
+ OStringBuffer aSetName( maBaseName.getLength() + 32 );
+ aSetName.append( maBaseName );
+ aSetName.append( "FID" );
+ aSetName.append( mnFontID );
+ aSetName.append( mbVertical ? "VGSet" : "HGSet" );
+ aSetName.append( nGlyphSetID );
+ return aSetName.makeStringAndClear();
+ }
+ else
+ /* (meBaseType == fonttype::Type1 || meBaseType == fonttype::Builtin) */
+ {
+ return maBaseName;
+ }
+}
+
+sal_Int32
+GlyphSet::GetGlyphSetEncoding (sal_Int32 nGlyphSetID)
+{
+ if (meBaseType == fonttype::TrueType)
+ return RTL_TEXTENCODING_DONTKNOW;
+ else
+ {
+ /* (meBaseType == fonttype::Type1 || meBaseType == fonttype::Builtin) */
+ if (mnBaseEncoding == RTL_TEXTENCODING_SYMBOL)
+ return RTL_TEXTENCODING_SYMBOL;
+ else
+ return nGlyphSetID == 1 ? RTL_TEXTENCODING_MS_1252
+ : RTL_TEXTENCODING_USER_START + nGlyphSetID;
+ }
+}
+
+OString
+GlyphSet::GetGlyphSetEncodingName (rtl_TextEncoding nEnc, const OString &rFontName)
+{
+ if ( nEnc == RTL_TEXTENCODING_MS_1252
+ || nEnc == RTL_TEXTENCODING_ISO_8859_1)
+ {
+ return OString("ISO1252Encoding");
+ }
+ else
+ if (nEnc >= RTL_TEXTENCODING_USER_START && nEnc <= RTL_TEXTENCODING_USER_END)
+ {
+ return rFontName
+ + OString("Enc")
+ + OString::valueOf ((sal_Int32)(nEnc - RTL_TEXTENCODING_USER_START));
+ }
+ else
+ {
+ return OString();
+ }
+}
+
+OString
+GlyphSet::GetGlyphSetEncodingName (sal_Int32 nGlyphSetID)
+{
+ return GetGlyphSetEncodingName (GetGlyphSetEncoding(nGlyphSetID), maBaseName);
+}
+
+void
+GlyphSet::PSDefineReencodedFont (osl::File* pOutFile, sal_Int32 nGlyphSetID)
+{
+ // only for ps fonts
+ if ((meBaseType != fonttype::Builtin) && (meBaseType != fonttype::Type1))
+ return;
+
+ sal_Char pEncodingVector [256];
+ sal_Int32 nSize = 0;
+
+ nSize += psp::appendStr ("(", pEncodingVector + nSize);
+ nSize += psp::appendStr (GetReencodedFontName(nGlyphSetID),
+ pEncodingVector + nSize);
+ nSize += psp::appendStr (") cvn (", pEncodingVector + nSize);
+ nSize += psp::appendStr (maBaseName.getStr(),
+ pEncodingVector + nSize);
+ nSize += psp::appendStr (") cvn ", pEncodingVector + nSize);
+ nSize += psp::appendStr (GetGlyphSetEncodingName(nGlyphSetID),
+ pEncodingVector + nSize);
+ nSize += psp::appendStr (" psp_definefont\n",
+ pEncodingVector + nSize);
+
+ psp::WritePS (pOutFile, pEncodingVector);
+}
+
+OString
+GlyphSet::GetReencodedFontName (rtl_TextEncoding nEnc, const OString &rFontName)
+{
+ if ( nEnc == RTL_TEXTENCODING_MS_1252
+ || nEnc == RTL_TEXTENCODING_ISO_8859_1)
+ {
+ return rFontName
+ + OString("-iso1252");
+ }
+ else
+ if (nEnc >= RTL_TEXTENCODING_USER_START && nEnc <= RTL_TEXTENCODING_USER_END)
+ {
+ return rFontName
+ + OString("-enc")
+ + OString::valueOf ((sal_Int32)(nEnc - RTL_TEXTENCODING_USER_START));
+ }
+ else
+ {
+ return OString();
+ }
+}
+
+OString
+GlyphSet::GetReencodedFontName (sal_Int32 nGlyphSetID)
+{
+ return GetReencodedFontName (GetGlyphSetEncoding(nGlyphSetID), maBaseName);
+}
+
+void GlyphSet::DrawGlyphs(
+ PrinterGfx& rGfx,
+ const Point& rPoint,
+ const sal_uInt32* pGlyphIds,
+ const sal_Unicode* pUnicodes,
+ sal_Int16 nLen,
+ const sal_Int32* pDeltaArray )
+{
+ sal_uChar *pGlyphID = (sal_uChar*)alloca (nLen * sizeof(sal_uChar));
+ sal_Int32 *pGlyphSetID = (sal_Int32*)alloca (nLen * sizeof(sal_Int32));
+ std::set< sal_Int32 > aGlyphSet;
+
+ // convert unicode to font glyph id and font subset
+ for (int nChar = 0; nChar < nLen; nChar++)
+ {
+ GetGlyphID (pGlyphIds[nChar], pUnicodes[nChar], pGlyphID + nChar, pGlyphSetID + nChar);
+ aGlyphSet.insert (pGlyphSetID[nChar]);
+ }
+
+ // loop over all glyph sets to detect substrings that can be xshown together
+ // without changing the postscript font
+ sal_Int32 *pDeltaSubset = (sal_Int32*)alloca (nLen * sizeof(sal_Int32));
+ sal_uChar *pGlyphSubset = (sal_uChar*)alloca (nLen * sizeof(sal_uChar));
+
+ std::set< sal_Int32 >::iterator aSet;
+ for (aSet = aGlyphSet.begin(); aSet != aGlyphSet.end(); ++aSet)
+ {
+ Point aPoint = rPoint;
+ sal_Int32 nOffset = 0;
+ sal_Int32 nGlyphs = 0;
+ sal_Int32 nChar;
+
+ // get offset to first glyph
+ for (nChar = 0; (nChar < nLen) && (pGlyphSetID[nChar] != *aSet); nChar++)
+ {
+ nOffset = pDeltaArray [nChar];
+ }
+
+ // loop over all chars to extract those that share the current glyph set
+ for (nChar = 0; nChar < nLen; nChar++)
+ {
+ if (pGlyphSetID[nChar] == *aSet)
+ {
+ pGlyphSubset [nGlyphs] = pGlyphID [nChar];
+ // the offset to the next glyph is determined by the glyph in
+ // front of the next glyph with the same glyphset id
+ // most often, this will be the current glyph
+ while ((nChar + 1) < nLen)
+ {
+ if (pGlyphSetID[nChar + 1] == *aSet)
+ break;
+ else
+ nChar += 1;
+ }
+ pDeltaSubset [nGlyphs] = pDeltaArray[nChar] - nOffset;
+
+ nGlyphs += 1;
+ }
+ }
+
+ // show the text using the PrinterGfx text api
+ aPoint.Move (nOffset, 0);
+
+ OString aGlyphSetName(GetGlyphSetName(*aSet));
+ rGfx.PSSetFont (aGlyphSetName, GetGlyphSetEncoding(*aSet));
+ rGfx.PSMoveTo (aPoint);
+ rGfx.PSShowText (pGlyphSubset, nGlyphs, nGlyphs, nGlyphs > 1 ? pDeltaSubset : NULL);
+ }
+}
+
+void
+GlyphSet::DrawText (PrinterGfx &rGfx, const Point& rPoint,
+ const sal_Unicode* pStr, sal_Int16 nLen, const sal_Int32* pDeltaArray)
+{
+ // dispatch to the impl method
+ if (pDeltaArray == NULL)
+ ImplDrawText (rGfx, rPoint, pStr, nLen);
+ else
+ ImplDrawText (rGfx, rPoint, pStr, nLen, pDeltaArray);
+}
+
+void
+GlyphSet::ImplDrawText (PrinterGfx &rGfx, const Point& rPoint,
+ const sal_Unicode* pStr, sal_Int16 nLen)
+{
+ rGfx.PSMoveTo (rPoint);
+
+ if( mbUseFontEncoding )
+ {
+ OString aPSName( OUStringToOString( rGfx.GetFontMgr().getPSName( mnFontID ), RTL_TEXTENCODING_ISO_8859_1 ) );
+ OString aBytes( OUStringToOString( OUString( pStr, nLen ), mnBaseEncoding ) );
+ rGfx.PSSetFont( aPSName, mnBaseEncoding );
+ rGfx.PSShowText( (const unsigned char*)aBytes.getStr(), nLen, aBytes.getLength() );
+ return;
+ }
+
+ int nChar;
+ sal_uChar *pGlyphID = (sal_uChar*)alloca (nLen * sizeof(sal_uChar));
+ sal_Int32 *pGlyphSetID = (sal_Int32*)alloca (nLen * sizeof(sal_Int32));
+
+ // convert unicode to glyph id and char set (font subset)
+ for (nChar = 0; nChar < nLen; nChar++)
+ GetCharID (pStr[nChar], pGlyphID + nChar, pGlyphSetID + nChar);
+
+ // loop over the string to draw subsequent pieces of chars
+ // with the same postscript font
+ for (nChar = 0; nChar < nLen; /* atend */)
+ {
+ sal_Int32 nGlyphSetID = pGlyphSetID [nChar];
+ sal_Int32 nGlyphs = 1;
+ for (int nNextChar = nChar + 1; nNextChar < nLen; nNextChar++)
+ {
+ if (pGlyphSetID[nNextChar] == nGlyphSetID)
+ nGlyphs++;
+ else
+ break;
+ }
+
+ // show the text using the PrinterGfx text api
+ OString aGlyphSetName(GetCharSetName(nGlyphSetID));
+ rGfx.PSSetFont (aGlyphSetName, GetGlyphSetEncoding(nGlyphSetID));
+ rGfx.PSShowText (pGlyphID + nChar, nGlyphs, nGlyphs);
+
+ nChar += nGlyphs;
+ }
+}
+
+void
+GlyphSet::ImplDrawText (PrinterGfx &rGfx, const Point& rPoint,
+ const sal_Unicode* pStr, sal_Int16 nLen, const sal_Int32* pDeltaArray)
+{
+ if( mbUseFontEncoding )
+ {
+ OString aPSName( OUStringToOString( rGfx.GetFontMgr().getPSName( mnFontID ), RTL_TEXTENCODING_ISO_8859_1 ) );
+ OString aBytes( OUStringToOString( OUString( pStr, nLen ), mnBaseEncoding ) );
+ rGfx.PSMoveTo( rPoint );
+ rGfx.PSSetFont( aPSName, mnBaseEncoding );
+ rGfx.PSShowText( (const unsigned char*)aBytes.getStr(), nLen, aBytes.getLength(), pDeltaArray );
+ return;
+ }
+
+ sal_uChar *pGlyphID = (sal_uChar*)alloca (nLen * sizeof(sal_uChar));
+ sal_Int32 *pGlyphSetID = (sal_Int32*)alloca (nLen * sizeof(sal_Int32));
+ std::set< sal_Int32 > aGlyphSet;
+
+ // convert unicode to font glyph id and font subset
+ for (int nChar = 0; nChar < nLen; nChar++)
+ {
+ GetCharID (pStr[nChar], pGlyphID + nChar, pGlyphSetID + nChar);
+ aGlyphSet.insert (pGlyphSetID[nChar]);
+ }
+
+ // loop over all glyph sets to detect substrings that can be xshown together
+ // without changing the postscript font
+ sal_Int32 *pDeltaSubset = (sal_Int32*)alloca (nLen * sizeof(sal_Int32));
+ sal_uChar *pGlyphSubset = (sal_uChar*)alloca (nLen * sizeof(sal_uChar));
+
+ std::set< sal_Int32 >::iterator aSet;
+ for (aSet = aGlyphSet.begin(); aSet != aGlyphSet.end(); ++aSet)
+ {
+ Point aPoint = rPoint;
+ sal_Int32 nOffset = 0;
+ sal_Int32 nGlyphs = 0;
+ sal_Int32 nChar;
+
+ // get offset to first glyph
+ for (nChar = 0; (nChar < nLen) && (pGlyphSetID[nChar] != *aSet); nChar++)
+ {
+ nOffset = pDeltaArray [nChar];
+ }
+
+ // loop over all chars to extract those that share the current glyph set
+ for (nChar = 0; nChar < nLen; nChar++)
+ {
+ if (pGlyphSetID[nChar] == *aSet)
+ {
+ pGlyphSubset [nGlyphs] = pGlyphID [nChar];
+ // the offset to the next glyph is determined by the glyph in
+ // front of the next glyph with the same glyphset id
+ // most often, this will be the current glyph
+ while ((nChar + 1) < nLen)
+ {
+ if (pGlyphSetID[nChar + 1] == *aSet)
+ break;
+ else
+ nChar += 1;
+ }
+ pDeltaSubset [nGlyphs] = pDeltaArray[nChar] - nOffset;
+
+ nGlyphs += 1;
+ }
+ }
+
+ // show the text using the PrinterGfx text api
+ aPoint.Move (nOffset, 0);
+
+ OString aGlyphSetName(GetCharSetName(*aSet));
+ rGfx.PSSetFont (aGlyphSetName, GetGlyphSetEncoding(*aSet));
+ rGfx.PSMoveTo (aPoint);
+ rGfx.PSShowText (pGlyphSubset, nGlyphs, nGlyphs, nGlyphs > 1 ? pDeltaSubset : NULL);
+ }
+}
+
+sal_Bool
+GlyphSet::PSUploadEncoding(osl::File* pOutFile, PrinterGfx &rGfx)
+{
+ // only for ps fonts
+ if ((meBaseType != fonttype::Builtin) && (meBaseType != fonttype::Type1))
+ return sal_False;
+ if (mnBaseEncoding == RTL_TEXTENCODING_SYMBOL)
+ return sal_False;
+
+ PrintFontManager &rMgr = rGfx.GetFontMgr();
+
+ // loop thru all the font subsets
+ sal_Int32 nGlyphSetID = 0;
+ char_list_t::iterator aGlyphSet;
+ for (aGlyphSet = maCharList.begin(); aGlyphSet != maCharList.end(); aGlyphSet++)
+ {
+ ++nGlyphSetID;
+
+ if (nGlyphSetID == 1) // latin1 page uses global reencoding table
+ {
+ PSDefineReencodedFont (pOutFile, nGlyphSetID);
+ continue;
+ }
+ if ((*aGlyphSet).size() == 0) // empty set, doesn't need reencoding
+ {
+ continue;
+ }
+
+ // create reencoding table
+
+ sal_Char pEncodingVector [256];
+ sal_Int32 nSize = 0;
+
+ nSize += psp::appendStr ("/",
+ pEncodingVector + nSize);
+ nSize += psp::appendStr (GetGlyphSetEncodingName(nGlyphSetID),
+ pEncodingVector + nSize);
+ nSize += psp::appendStr (" [ ",
+ pEncodingVector + nSize);
+
+ // need a list of glyphs, sorted by glyphid
+ typedef std::map< sal_uInt8, sal_Unicode > ps_mapping_t;
+ typedef ps_mapping_t::value_type ps_value_t;
+ ps_mapping_t aSortedGlyphSet;
+
+ char_map_t::const_iterator aUnsortedGlyph;
+ for (aUnsortedGlyph = (*aGlyphSet).begin();
+ aUnsortedGlyph != (*aGlyphSet).end();
+ ++aUnsortedGlyph)
+ {
+ aSortedGlyphSet.insert(ps_value_t((*aUnsortedGlyph).second,
+ (*aUnsortedGlyph).first));
+ }
+
+ ps_mapping_t::const_iterator aSortedGlyph;
+ // loop thru all the glyphs in the subset
+ for (aSortedGlyph = (aSortedGlyphSet).begin();
+ aSortedGlyph != (aSortedGlyphSet).end();
+ ++aSortedGlyph)
+ {
+ nSize += psp::appendStr ("/",
+ pEncodingVector + nSize);
+
+ std::list< OString > aName( rMgr.getAdobeNameFromUnicode((*aSortedGlyph).second) );
+
+ if( aName.begin() != aName.end() )
+ nSize += psp::appendStr ( aName.front(), pEncodingVector + nSize);
+ else
+ nSize += psp::appendStr (".notdef", pEncodingVector + nSize );
+ nSize += psp::appendStr (" ", pEncodingVector + nSize);
+ // flush line
+ if (nSize >= 70)
+ {
+ nSize += psp::appendStr ("\n", pEncodingVector + nSize);
+ psp::WritePS (pOutFile, pEncodingVector);
+ nSize = 0;
+ }
+ }
+
+ nSize += psp::appendStr ("] def\n", pEncodingVector + nSize);
+ psp::WritePS (pOutFile, pEncodingVector);
+
+ PSDefineReencodedFont (pOutFile, nGlyphSetID);
+ }
+
+ return sal_True;
+}
+
+struct EncEntry
+{
+ sal_uChar aEnc;
+ long aGID;
+
+ EncEntry() : aEnc( 0 ), aGID( 0 ) {}
+
+ bool operator<( const EncEntry& rRight ) const
+ { return aEnc < rRight.aEnc; }
+};
+
+static void CreatePSUploadableFont( TrueTypeFont* pSrcFont, FILE* pTmpFile,
+ const char* pGlyphSetName, int nGlyphCount,
+ /*const*/ sal_uInt16* pRequestedGlyphs, /*const*/ sal_uChar* pEncoding,
+ bool bAllowType42, bool /*bAllowCID*/ )
+{
+ // match the font-subset to the printer capabilities
+ // TODO: allow CFF for capable printers
+ int nTargetMask = FontSubsetInfo::TYPE1_PFA | FontSubsetInfo::TYPE3_FONT;
+ if( bAllowType42 )
+ nTargetMask |= FontSubsetInfo::TYPE42_FONT;
+
+ std::vector< EncEntry > aSorted( nGlyphCount, EncEntry() );
+ for( int i = 0; i < nGlyphCount; i++ )
+ {
+ aSorted[i].aEnc = pEncoding[i];
+ aSorted[i].aGID = pRequestedGlyphs[i];
+ }
+
+ std::stable_sort( aSorted.begin(), aSorted.end() );
+
+ std::vector< sal_uChar > aEncoding( nGlyphCount );
+ std::vector< long > aRequestedGlyphs( nGlyphCount );
+
+ for( int i = 0; i < nGlyphCount; i++ )
+ {
+ aEncoding[i] = aSorted[i].aEnc;
+ aRequestedGlyphs[i] = aSorted[i].aGID;
+ }
+
+ FontSubsetInfo aInfo;
+ aInfo.LoadFont( pSrcFont );
+
+ aInfo.CreateFontSubset( nTargetMask, pTmpFile, pGlyphSetName,
+ &aRequestedGlyphs[0], &aEncoding[0], nGlyphCount, NULL );
+}
+
+sal_Bool
+GlyphSet::PSUploadFont (osl::File& rOutFile, PrinterGfx &rGfx, bool bAllowType42, std::list< OString >& rSuppliedFonts )
+{
+ // only for truetype fonts
+ if (meBaseType != fonttype::TrueType)
+ return sal_False;
+
+ TrueTypeFont *pTTFont;
+ OString aTTFileName (rGfx.GetFontMgr().getFontFileSysPath(mnFontID));
+ int nFace = rGfx.GetFontMgr().getFontFaceNumber(mnFontID);
+ sal_Int32 nSuccess = OpenTTFontFile(aTTFileName.getStr(), nFace < 0 ? 0 : nFace, &pTTFont);
+ if (nSuccess != SF_OK)
+ return sal_False;
+ FILE* pTmpFile = tmpfile();
+ if (pTmpFile == NULL)
+ return sal_False;
+
+ // array of unicode source characters
+ sal_Unicode pUChars[256];
+
+ // encoding vector maps character encoding to the ordinal number
+ // of the glyph in the output file
+ sal_uChar pEncoding[256];
+ sal_uInt16 pTTGlyphMapping[256];
+ const bool bAllowCID = false; // TODO: nPSLanguageLevel>=3
+
+ // loop thru all the font subsets
+ sal_Int32 nCharSetID;
+ char_list_t::iterator aCharSet;
+ for (aCharSet = maCharList.begin(), nCharSetID = 1;
+ aCharSet != maCharList.end();
+ ++aCharSet, nCharSetID++)
+ {
+ if ((*aCharSet).size() == 0)
+ continue;
+
+ // loop thru all the chars in the subset
+ char_map_t::const_iterator aChar;
+ sal_Int32 n = 0;
+ for (aChar = (*aCharSet).begin(); aChar != (*aCharSet).end(); aChar++)
+ {
+ pUChars [n] = (*aChar).first;
+ pEncoding [n] = (*aChar).second;
+ n++;
+ }
+ // create a mapping from the unicode chars to the char encoding in
+ // source TrueType font
+ MapString (pTTFont, pUChars, (*aCharSet).size(), pTTGlyphMapping, mbVertical);
+
+ // create the current subset
+ OString aCharSetName = GetCharSetName(nCharSetID);
+ fprintf( pTmpFile, "%%%%BeginResource: font %s\n", aCharSetName.getStr() );
+ CreatePSUploadableFont( pTTFont, pTmpFile, aCharSetName.getStr(), (*aCharSet).size(),
+ pTTGlyphMapping, pEncoding, bAllowType42, bAllowCID );
+ fprintf( pTmpFile, "%%%%EndResource\n" );
+ rSuppliedFonts.push_back( aCharSetName );
+ }
+
+ // loop thru all the font glyph subsets
+ sal_Int32 nGlyphSetID;
+ glyph_list_t::iterator aGlyphSet;
+ for (aGlyphSet = maGlyphList.begin(), nGlyphSetID = 1;
+ aGlyphSet != maGlyphList.end();
+ ++aGlyphSet, nGlyphSetID++)
+ {
+ if ((*aGlyphSet).size() == 0)
+ continue;
+
+ // loop thru all the glyphs in the subset
+ glyph_map_t::const_iterator aGlyph;
+ sal_Int32 n = 0;
+ for (aGlyph = (*aGlyphSet).begin(); aGlyph != (*aGlyphSet).end(); aGlyph++)
+ {
+ pTTGlyphMapping [n] = (*aGlyph).first;
+ pEncoding [n] = (*aGlyph).second;
+ n++;
+ }
+
+ // create the current subset
+ OString aGlyphSetName = GetGlyphSetName(nGlyphSetID);
+ fprintf( pTmpFile, "%%%%BeginResource: font %s\n", aGlyphSetName.getStr() );
+ CreatePSUploadableFont( pTTFont, pTmpFile, aGlyphSetName.getStr(), (*aGlyphSet).size(),
+ pTTGlyphMapping, pEncoding, bAllowType42, bAllowCID );
+ fprintf( pTmpFile, "%%%%EndResource\n" );
+ rSuppliedFonts.push_back( aGlyphSetName );
+ }
+
+ // copy the file into the page header
+ rewind(pTmpFile);
+ fflush(pTmpFile);
+
+ sal_uChar pBuffer[0x2000];
+ sal_uInt64 nIn;
+ sal_uInt64 nOut;
+ do
+ {
+ nIn = fread(pBuffer, 1, sizeof(pBuffer), pTmpFile);
+ rOutFile.write (pBuffer, nIn, nOut);
+ }
+ while ((nIn == nOut) && !feof(pTmpFile));
+
+ // cleanup
+ CloseTTFont (pTTFont);
+ fclose (pTmpFile);
+
+ return sal_True;
+}
diff --git a/vcl/unx/source/printergfx/glyphset.hxx b/vcl/unx/source/printergfx/glyphset.hxx
new file mode 100644
index 000000000000..320e8e071955
--- /dev/null
+++ b/vcl/unx/source/printergfx/glyphset.hxx
@@ -0,0 +1,135 @@
+/*************************************************************************
+ *
+ * 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 _PSPRINT_GLYPHSET_HXX_
+#define _PSPRINT_GLYPHSET_HXX_
+
+#include "vcl/fontmanager.hxx"
+
+#include "osl/file.hxx"
+
+#include "rtl/string.hxx"
+
+#include "tools/gen.hxx"
+
+#include <list>
+#include <hash_map>
+
+namespace psp {
+
+class PrinterGfx;
+class PrintFontManager;
+
+class GlyphSet
+{
+private:
+
+ sal_Int32 mnFontID;
+ sal_Bool mbVertical;
+ rtl::OString maBaseName;
+ fonttype::type meBaseType;
+ rtl_TextEncoding mnBaseEncoding;
+ bool mbUseFontEncoding;
+
+ typedef std::hash_map< sal_Unicode, sal_uInt8 > char_map_t;
+ typedef std::list< char_map_t > char_list_t;
+ typedef std::hash_map< sal_uInt32, sal_uInt8 > glyph_map_t;
+ typedef std::list< glyph_map_t > glyph_list_t;
+
+ char_list_t maCharList;
+ glyph_list_t maGlyphList;
+
+ rtl::OString GetGlyphSetName (sal_Int32 nGlyphSetID);
+ rtl::OString GetCharSetName (sal_Int32 nGlyphSetID);
+ sal_Int32 GetGlyphSetEncoding (sal_Int32 nGlyphSetID);
+ rtl::OString GetGlyphSetEncodingName (sal_Int32 nGlyphSetID);
+
+ rtl::OString GetReencodedFontName (sal_Int32 nGlyphSetID);
+ void PSDefineReencodedFont (osl::File* pOutFile,
+ sal_Int32 nGlyphSetID);
+
+ sal_Bool GetCharID (sal_Unicode nChar,
+ sal_uChar* nOutGlyphID, sal_Int32* nOutGlyphSetID);
+ sal_Bool LookupCharID (sal_Unicode nChar,
+ sal_uChar* nOutGlyphID, sal_Int32* nOutGlyphSetID);
+ sal_Bool AddCharID (sal_Unicode nChar,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID);
+ sal_Bool GetGlyphID (sal_uInt32 nGlyph, sal_Unicode nUnicode,
+ sal_uChar* nOutGlyphID, sal_Int32* nOutGlyphSetID);
+ sal_Bool LookupGlyphID (sal_uInt32 nGlyph,
+ sal_uChar* nOutGlyphID, sal_Int32* nOutGlyphSetID);
+ sal_Bool AddGlyphID (sal_uInt32 nGlyph, sal_Unicode nUnicode,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID);
+ void AddNotdef (char_map_t &rCharMap);
+ void AddNotdef (glyph_map_t &rGlyphMap);
+ sal_uChar GetAnsiMapping (sal_Unicode nUnicodeChar);
+ sal_uChar GetSymbolMapping (sal_Unicode nUnicodeChar);
+
+ void ImplDrawText (PrinterGfx &rGfx, const Point& rPoint,
+ const sal_Unicode* pStr, sal_Int16 nLen);
+ void ImplDrawText (PrinterGfx &rGfx, const Point& rPoint,
+ const sal_Unicode* pStr, sal_Int16 nLen,
+ const sal_Int32* pDeltaArray);
+
+public:
+
+ GlyphSet ();
+ GlyphSet (sal_Int32 nFontID, sal_Bool bVertical);
+ ~GlyphSet ();
+
+ sal_Int32 GetFontID ();
+ fonttype::type GetFontType ();
+ static rtl::OString
+ GetReencodedFontName (rtl_TextEncoding nEnc,
+ const rtl::OString &rFontName);
+ static rtl::OString
+ GetGlyphSetEncodingName (rtl_TextEncoding nEnc,
+ const rtl::OString &rFontName);
+ sal_Bool IsVertical ();
+
+ sal_Bool SetFont (sal_Int32 nFontID, sal_Bool bVertical);
+
+ void DrawText (PrinterGfx &rGfx, const Point& rPoint,
+ const sal_Unicode* pStr, sal_Int16 nLen,
+ const sal_Int32* pDeltaArray = NULL);
+ void DrawGlyphs (PrinterGfx& rGfx,
+ const Point& rPoint,
+ const sal_uInt32* pGlyphIds,
+ const sal_Unicode* pUnicodes,
+ sal_Int16 nLen,
+ const sal_Int32* pDeltaArray );
+ sal_Bool PSUploadEncoding(osl::File* pOutFile, PrinterGfx &rGfx);
+ sal_Bool PSUploadFont (osl::File& rOutFile, PrinterGfx &rGfx, bool bAsType42, std::list< rtl::OString >& rSuppliedFonts );
+};
+
+
+} /* namespace psp */
+
+#endif
+
diff --git a/vcl/unx/source/printergfx/makefile.mk b/vcl/unx/source/printergfx/makefile.mk
new file mode 100644
index 000000000000..cc5692e951f5
--- /dev/null
+++ b/vcl/unx/source/printergfx/makefile.mk
@@ -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.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+
+PRJNAME=vcl
+TARGET=printergfx
+
+# --- Settings -----------------------------------------------------
+
+ENABLE_EXCEPTIONS=true
+
+.INCLUDE : settings.mk
+
+.IF "$(ENABLE_CUPS)" != ""
+CDEFS += -DENABLE_CUPS
+.ENDIF
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)"=="aqua"
+
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+
+.ELSE # "$(GUIBASE)"=="aqua"
+
+SLOFILES=\
+ $(SLO)$/printerjob.obj \
+ $(SLO)$/text_gfx.obj \
+ $(SLO)$/psputil.obj \
+ $(SLO)$/common_gfx.obj \
+ $(SLO)$/glyphset.obj \
+ $(SLO)$/bitmap_gfx.obj
+
+.ENDIF
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
diff --git a/vcl/unx/source/printergfx/printerjob.cxx b/vcl/unx/source/printergfx/printerjob.cxx
new file mode 100644
index 000000000000..5e18849b8dfe
--- /dev/null
+++ b/vcl/unx/source/printergfx/printerjob.cxx
@@ -0,0 +1,1199 @@
+/*************************************************************************
+ *
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pwd.h>
+
+#include "psputil.hxx"
+#include "glyphset.hxx"
+
+#include "vcl/printerjob.hxx"
+#include "vcl/ppdparser.hxx"
+#include "vcl/strhelper.hxx"
+#include "vcl/printerinfomanager.hxx"
+#include "vcl/printergfx.hxx"
+
+#include "rtl/ustring.hxx"
+#include "rtl/strbuf.hxx"
+#include "rtl/ustrbuf.hxx"
+
+#include "osl/thread.h"
+#include "sal/alloca.h"
+
+#include <algorithm>
+#include <vector>
+
+using namespace psp;
+using namespace rtl;
+
+// forward declaration
+
+#define nBLOCKSIZE 0x2000
+
+namespace psp
+{
+
+sal_Bool
+AppendPS (FILE* pDst, osl::File* pSrc, sal_uChar* pBuffer,
+ sal_uInt32 nBlockSize = nBLOCKSIZE)
+{
+ if ((pDst == NULL) || (pSrc == NULL))
+ return sal_False;
+
+ if (nBlockSize == 0)
+ nBlockSize = nBLOCKSIZE;
+ if (pBuffer == NULL)
+ pBuffer = (sal_uChar*)alloca (nBlockSize);
+
+ pSrc->setPos (osl_Pos_Absolut, 0);
+
+ sal_uInt64 nIn = 0;
+ sal_uInt64 nOut = 0;
+ do
+ {
+ pSrc->read (pBuffer, nBlockSize, nIn);
+ if (nIn > 0)
+ nOut = fwrite (pBuffer, 1, sal::static_int_cast<sal_uInt32>(nIn), pDst);
+ }
+ while ((nIn > 0) && (nIn == nOut));
+
+ return sal_True;
+}
+
+} // namespace psp
+
+/*
+ * private convenience routines for file handling
+ */
+
+osl::File*
+PrinterJob::CreateSpoolFile (const rtl::OUString& rName, const rtl::OUString& rExtension)
+{
+ osl::File::RC nError = osl::File::E_None;
+ osl::File* pFile = NULL;
+
+ rtl::OUString aFile = rName + rExtension;
+ rtl::OUString aFileURL;
+ nError = osl::File::getFileURLFromSystemPath( aFile, aFileURL );
+ if (nError != osl::File::E_None)
+ return NULL;
+ aFileURL = maSpoolDirName + rtl::OUString::createFromAscii ("/") + aFileURL;
+
+ pFile = new osl::File (aFileURL);
+ nError = pFile->open (OpenFlag_Read | OpenFlag_Write | OpenFlag_Create);
+ if (nError != osl::File::E_None)
+ {
+ delete pFile;
+ return NULL;
+ }
+
+ pFile->setAttributes (aFileURL,
+ osl_File_Attribute_OwnWrite | osl_File_Attribute_OwnRead);
+ return pFile;
+}
+
+/*
+ * public methods of PrinterJob: for use in PrinterGfx
+ */
+
+void
+PrinterJob::GetScale (double &rXScale, double &rYScale) const
+{
+ rXScale = mfXScale;
+ rYScale = mfYScale;
+}
+
+sal_uInt16
+PrinterJob::GetDepth () const
+{
+ sal_Int32 nLevel = GetPostscriptLevel();
+ sal_Bool bColor = IsColorPrinter ();
+
+ return nLevel > 1 && bColor ? 24 : 8;
+}
+
+sal_uInt16
+PrinterJob::GetPostscriptLevel (const JobData *pJobData) const
+{
+ sal_uInt16 nPSLevel = 2;
+
+ if( pJobData == NULL )
+ pJobData = &m_aLastJobData;
+
+ if( pJobData->m_nPSLevel )
+ nPSLevel = pJobData->m_nPSLevel;
+ else
+ if( pJobData->m_pParser )
+ nPSLevel = pJobData->m_pParser->getLanguageLevel();
+
+ return nPSLevel;
+}
+
+sal_Bool
+PrinterJob::IsColorPrinter () const
+{
+ sal_Bool bColor = sal_False;
+
+ if( m_aLastJobData.m_nColorDevice )
+ bColor = m_aLastJobData.m_nColorDevice == -1 ? sal_False : sal_True;
+ else if( m_aLastJobData.m_pParser )
+ bColor = m_aLastJobData.m_pParser->isColorDevice() ? sal_True : sal_False;
+
+ return bColor;
+}
+
+osl::File*
+PrinterJob::GetDocumentHeader ()
+{
+ return mpJobHeader;
+}
+
+osl::File*
+PrinterJob::GetDocumentTrailer ()
+{
+ return mpJobTrailer;
+}
+
+osl::File*
+PrinterJob::GetCurrentPageHeader ()
+{
+ return maHeaderList.back();
+}
+
+osl::File*
+PrinterJob::GetCurrentPageBody ()
+{
+ return maPageList.back();
+}
+
+/*
+ * public methods of PrinterJob: the actual job / spool handling
+ */
+
+PrinterJob::PrinterJob () :
+ mpJobHeader( NULL ),
+ mpJobTrailer( NULL ),
+ m_bQuickJob( false )
+{
+}
+
+namespace psp
+{
+
+/* check whether the given name points to a directory which is
+ usable for the user */
+sal_Bool
+existsTmpDir (const char* pName)
+{
+ struct stat aFileStatus;
+
+ if (pName == NULL)
+ return sal_False;
+ if (stat(pName, &aFileStatus) != 0)
+ return sal_False;
+ if (! S_ISDIR(aFileStatus.st_mode))
+ return sal_False;
+
+ return access(pName, W_OK | R_OK) == 0 ? sal_True : sal_False;
+}
+
+/* return the username in the given buffer */
+sal_Bool
+getUserName (char* pName, int nSize)
+{
+ struct passwd *pPWEntry;
+ struct passwd aPWEntry;
+ sal_Char pPWBuffer[256];
+
+ sal_Bool bSuccess = sal_False;
+
+#ifdef FREEBSD
+ pPWEntry = getpwuid( getuid());
+#else
+ if (getpwuid_r(getuid(), &aPWEntry, pPWBuffer, sizeof(pPWBuffer), &pPWEntry) != 0)
+ pPWEntry = NULL;
+#endif
+
+ if (pPWEntry != NULL && pPWEntry->pw_name != NULL)
+ {
+ sal_Int32 nLen = strlen(pPWEntry->pw_name);
+ if (nLen > 0 && nLen < nSize)
+ {
+ memcpy (pName, pPWEntry->pw_name, nLen);
+ pName[nLen] = '\0';
+
+ bSuccess = sal_True;
+ }
+ }
+
+ // wipe the passwd off the stack
+ memset (pPWBuffer, 0, sizeof(pPWBuffer));
+
+ return bSuccess;
+}
+
+/* remove all our temporary files, uses external program "rm", since
+ osl functionality is inadequate */
+void
+removeSpoolDir (const rtl::OUString& rSpoolDir)
+{
+ rtl::OUString aSysPath;
+ if( osl::File::E_None != osl::File::getSystemPathFromFileURL( rSpoolDir, aSysPath ) )
+ {
+ // Conversion did not work, as this is quite a dangerous action,
+ // we should abort here ....
+ OSL_ENSURE( 0, "psprint: couldn't remove spool directory" );
+ return;
+ }
+ rtl::OString aSysPathByte =
+ rtl::OUStringToOString (aSysPath, osl_getThreadTextEncoding());
+ sal_Char pSystem [128];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::appendStr ("rm -rf ", pSystem);
+ nChar += psp::appendStr (aSysPathByte.getStr(), pSystem + nChar);
+
+ if (system (pSystem) == -1)
+ OSL_ENSURE( 0, "psprint: couldn't remove spool directory" );
+}
+
+/* creates a spool directory with a "pidgin random" value based on
+ current system time */
+rtl::OUString
+createSpoolDir ()
+{
+ TimeValue aCur;
+ osl_getSystemTime( &aCur );
+ sal_Int32 nRand = aCur.Seconds ^ (aCur.Nanosec/1000);
+
+ rtl::OUString aTmpDir;
+ osl_getTempDirURL( &aTmpDir.pData );
+
+ do
+ {
+ rtl::OUStringBuffer aDir( aTmpDir.getLength() + 16 );
+ aDir.append( aTmpDir );
+ aDir.appendAscii( "/psp" );
+ aDir.append(nRand);
+ rtl::OUString aResult = aDir.makeStringAndClear();
+ if( osl::Directory::create( aResult ) == osl::FileBase::E_None )
+ {
+ osl::File::setAttributes( aResult,
+ osl_File_Attribute_OwnWrite
+ | osl_File_Attribute_OwnRead
+ | osl_File_Attribute_OwnExe );
+ return aResult;
+ }
+ nRand++;
+ } while( nRand );
+ return rtl::OUString();
+}
+
+} // namespace psp
+
+PrinterJob::~PrinterJob ()
+{
+ std::list< osl::File* >::iterator pPage;
+ for (pPage = maPageList.begin(); pPage != maPageList.end(); pPage++)
+ {
+ //(*pPage)->remove();
+ delete *pPage;
+ }
+ for (pPage = maHeaderList.begin(); pPage != maHeaderList.end(); pPage++)
+ {
+ //(*pPage)->remove();
+ delete *pPage;
+ }
+ // mpJobHeader->remove();
+ delete mpJobHeader;
+ // mpJobTrailer->remove();
+ delete mpJobTrailer;
+
+ // XXX should really call osl::remove routines
+ removeSpoolDir (maSpoolDirName);
+
+ // osl::Directory::remove (maSpoolDirName);
+}
+
+namespace psp
+{
+
+// get locale invariant, 7bit clean current local time string
+sal_Char*
+getLocalTime(sal_Char* pBuffer)
+{
+ time_t nTime = time (NULL);
+ struct tm aTime;
+ struct tm *pLocalTime = localtime_r (&nTime, &aTime);
+
+ return asctime_r(pLocalTime, pBuffer);
+}
+
+}
+
+static bool isAscii( const rtl::OUString& rStr )
+{
+ const sal_Unicode* pStr = rStr;
+ sal_Int32 nLen = rStr.getLength();
+ for( sal_Int32 i = 0; i < nLen; i++ )
+ if( pStr[i] > 127 )
+ return false;
+ return true;
+}
+
+sal_Bool
+PrinterJob::StartJob (
+ const rtl::OUString& rFileName,
+ int nMode,
+ const rtl::OUString& rJobName,
+ const rtl::OUString& rAppName,
+ const JobData& rSetupData,
+ PrinterGfx* pGraphics,
+ bool bIsQuickJob
+ )
+{
+ m_bQuickJob = bIsQuickJob;
+ mnMaxWidthPt = mnMaxHeightPt = 0;
+ mnLandscapes = mnPortraits = 0;
+ m_pGraphics = pGraphics;
+ InitPaperSize (rSetupData);
+
+ // create file container for document header and trailer
+ maFileName = rFileName;
+ mnFileMode = nMode;
+ maSpoolDirName = createSpoolDir ();
+ maJobTitle = rJobName;
+
+ rtl::OUString aExt = rtl::OUString::createFromAscii (".ps");
+ mpJobHeader = CreateSpoolFile (rtl::OUString::createFromAscii("psp_head"), aExt);
+ mpJobTrailer = CreateSpoolFile (rtl::OUString::createFromAscii("psp_tail"), aExt);
+ if( ! (mpJobHeader && mpJobTrailer) ) // existing files are removed in destructor
+ return sal_False;
+
+ // write document header according to Document Structuring Conventions (DSC)
+ WritePS (mpJobHeader,
+ "%!PS-Adobe-3.0\n"
+ "%%BoundingBox: (atend)\n" );
+
+ rtl::OUString aFilterWS;
+
+ // Creator (this application)
+ aFilterWS = WhitespaceToSpace( rAppName, FALSE );
+ WritePS (mpJobHeader, "%%Creator: (");
+ WritePS (mpJobHeader, aFilterWS);
+ WritePS (mpJobHeader, ")\n");
+
+ // For (user name)
+ sal_Char pUserName[64];
+ if (getUserName(pUserName, sizeof(pUserName)))
+ {
+ WritePS (mpJobHeader, "%%For: (");
+ WritePS (mpJobHeader, pUserName);
+ WritePS (mpJobHeader, ")\n");
+ }
+
+ // Creation Date (locale independent local time)
+ sal_Char pCreationDate [256];
+ WritePS (mpJobHeader, "%%CreationDate: (");
+ getLocalTime(pCreationDate);
+ for( unsigned int i = 0; i < sizeof(pCreationDate)/sizeof(pCreationDate[0]); i++ )
+ {
+ if( pCreationDate[i] == '\n' )
+ {
+ pCreationDate[i] = 0;
+ break;
+ }
+ }
+ WritePS (mpJobHeader, pCreationDate );
+ WritePS (mpJobHeader, ")\n");
+
+ // Document Title
+ /* #i74335#
+ * The title should be clean ascii; rJobName however may
+ * contain any Unicode character. So implement the following
+ * algorithm:
+ * use rJobName, if it contains only ascii
+ * use the filename, if it contains only ascii
+ * else omit %%Title
+ */
+ aFilterWS = WhitespaceToSpace( rJobName, FALSE );
+ rtl::OUString aTitle( aFilterWS );
+ if( ! isAscii( aTitle ) )
+ {
+ sal_Int32 nIndex = 0;
+ while( nIndex != -1 )
+ aTitle = rFileName.getToken( 0, '/', nIndex );
+ aTitle = WhitespaceToSpace( aTitle, FALSE );
+ if( ! isAscii( aTitle ) )
+ aTitle = rtl::OUString();
+ }
+
+ maJobTitle = aFilterWS;
+ if( aTitle.getLength() )
+ {
+ WritePS (mpJobHeader, "%%Title: (");
+ WritePS (mpJobHeader, aTitle);
+ WritePS (mpJobHeader, ")\n");
+ }
+
+ // Language Level
+ sal_Char pLevel[16];
+ sal_Int32 nSz = getValueOf(GetPostscriptLevel(&rSetupData), pLevel);
+ pLevel[nSz++] = '\n';
+ pLevel[nSz ] = '\0';
+ WritePS (mpJobHeader, "%%LanguageLevel: ");
+ WritePS (mpJobHeader, pLevel);
+
+ // Other
+ WritePS (mpJobHeader, "%%DocumentData: Clean7Bit\n");
+ WritePS (mpJobHeader, "%%Pages: (atend)\n");
+ WritePS (mpJobHeader, "%%Orientation: (atend)\n");
+ WritePS (mpJobHeader, "%%PageOrder: Ascend\n");
+ WritePS (mpJobHeader, "%%EndComments\n");
+
+ // write Prolog
+ writeProlog (mpJobHeader, rSetupData);
+
+ // mark last job setup as not set
+ m_aLastJobData.m_pParser = NULL;
+ m_aLastJobData.m_aContext.setParser( NULL );
+
+ return sal_True;
+}
+
+sal_Bool
+PrinterJob::EndJob ()
+{
+ // write document setup (done here because it
+ // includes the accumulated fonts
+ if( mpJobHeader )
+ writeSetup( mpJobHeader, m_aDocumentJobData );
+ m_pGraphics->OnEndJob();
+ if( ! (mpJobHeader && mpJobTrailer) )
+ return sal_False;
+
+ // write document trailer according to Document Structuring Conventions (DSC)
+ rtl::OStringBuffer aTrailer(512);
+ aTrailer.append( "%%Trailer\n" );
+ aTrailer.append( "%%BoundingBox: 0 0 " );
+ aTrailer.append( (sal_Int32)mnMaxWidthPt );
+ aTrailer.append( " " );
+ aTrailer.append( (sal_Int32)mnMaxHeightPt );
+ if( mnLandscapes > mnPortraits )
+ aTrailer.append("\n%%Orientation: Landscape");
+ else
+ aTrailer.append("\n%%Orientation: Portrait");
+ aTrailer.append( "\n%%Pages: " );
+ aTrailer.append( (sal_Int32)maPageList.size() );
+ aTrailer.append( "\n%%EOF\n" );
+ WritePS (mpJobTrailer, aTrailer.getStr());
+
+ /*
+ * spool the set of files to their final destination, this is U**X dependent
+ */
+
+ FILE* pDestFILE = NULL;
+
+ /* create a destination either as file or as a pipe */
+ sal_Bool bSpoolToFile = maFileName.getLength() > 0 ? sal_True : sal_False;
+ if (bSpoolToFile)
+ {
+ const rtl::OString aFileName = rtl::OUStringToOString (maFileName,
+ osl_getThreadTextEncoding());
+ if( mnFileMode )
+ {
+ int nFile = open( aFileName.getStr(), O_CREAT | O_EXCL | O_RDWR, mnFileMode );
+ if( nFile != -1 )
+ {
+ pDestFILE = fdopen( nFile, "w" );
+ if( pDestFILE == NULL )
+ {
+ close( nFile );
+ unlink( aFileName.getStr() );
+ return sal_False;
+ }
+ }
+ else
+ chmod( aFileName.getStr(), mnFileMode );
+ }
+ if (pDestFILE == NULL)
+ pDestFILE = fopen (aFileName.getStr(), "w");
+
+ if (pDestFILE == NULL)
+ return sal_False;
+ }
+ else
+ {
+ PrinterInfoManager& rPrinterInfoManager = PrinterInfoManager::get ();
+ pDestFILE = rPrinterInfoManager.startSpool( m_aLastJobData.m_aPrinterName, m_bQuickJob );
+ if (pDestFILE == NULL)
+ return sal_False;
+ }
+
+ /* spool the document parts to the destination */
+
+ sal_uChar pBuffer[ nBLOCKSIZE ];
+
+ AppendPS (pDestFILE, mpJobHeader, pBuffer);
+ mpJobHeader->close();
+
+ sal_Bool bSuccess = sal_True;
+ std::list< osl::File* >::iterator pPageBody;
+ std::list< osl::File* >::iterator pPageHead;
+ for (pPageBody = maPageList.begin(), pPageHead = maHeaderList.begin();
+ pPageBody != maPageList.end() && pPageHead != maHeaderList.end();
+ pPageBody++, pPageHead++)
+ {
+ if( *pPageHead )
+ {
+ osl::File::RC nError = (*pPageHead)->open(OpenFlag_Read);
+ if (nError == osl::File::E_None)
+ {
+ AppendPS (pDestFILE, *pPageHead, pBuffer);
+ (*pPageHead)->close();
+ }
+ }
+ else
+ bSuccess = sal_False;
+ if( *pPageBody )
+ {
+ osl::File::RC nError = (*pPageBody)->open(OpenFlag_Read);
+ if (nError == osl::File::E_None)
+ {
+ AppendPS (pDestFILE, *pPageBody, pBuffer);
+ (*pPageBody)->close();
+ }
+ }
+ else
+ bSuccess = sal_False;
+ }
+
+ AppendPS (pDestFILE, mpJobTrailer, pBuffer);
+ mpJobTrailer->close();
+
+ /* well done */
+
+ if (bSpoolToFile)
+ fclose (pDestFILE);
+ else
+ {
+ PrinterInfoManager& rPrinterInfoManager = PrinterInfoManager::get();
+ if (0 == rPrinterInfoManager.endSpool( m_aLastJobData.m_aPrinterName,
+ maJobTitle, pDestFILE, m_aDocumentJobData ))
+ {
+ bSuccess = sal_False;
+ }
+ }
+
+ return bSuccess;
+}
+
+sal_Bool
+PrinterJob::AbortJob ()
+{
+ m_pGraphics->OnEndJob();
+ return sal_False;
+}
+
+void
+PrinterJob::InitPaperSize (const JobData& rJobSetup)
+{
+ int nRes = rJobSetup.m_aContext.getRenderResolution ();
+
+ String aPaper;
+ int nWidth, nHeight;
+ rJobSetup.m_aContext.getPageSize (aPaper, nWidth, nHeight);
+
+ int nLeft = 0, nRight = 0, nUpper = 0, nLower = 0;
+ const PPDParser* pParser = rJobSetup.m_aContext.getParser();
+ if (pParser != NULL)
+ pParser->getMargins (aPaper, nLeft, nRight, nUpper, nLower);
+
+ mnResolution = nRes;
+
+ mnWidthPt = nWidth;
+ mnHeightPt = nHeight;
+
+ if( mnWidthPt > mnMaxWidthPt )
+ mnMaxWidthPt = mnWidthPt;
+ if( mnHeightPt > mnMaxHeightPt )
+ mnMaxHeightPt = mnHeightPt;
+
+ mnLMarginPt = nLeft;
+ mnRMarginPt = nRight;
+ mnTMarginPt = nUpper;
+ mnBMarginPt = nLower;
+
+ mfXScale = (double)72.0 / (double)mnResolution;
+ mfYScale = -1.0 * (double)72.0 / (double)mnResolution;
+}
+
+
+sal_Bool
+PrinterJob::StartPage (const JobData& rJobSetup)
+{
+ InitPaperSize (rJobSetup);
+
+ rtl::OUString aPageNo = rtl::OUString::valueOf ((sal_Int32)maPageList.size()+1); // sequential page number must start with 1
+ rtl::OUString aExt = aPageNo + rtl::OUString::createFromAscii (".ps");
+
+ osl::File* pPageHeader = CreateSpoolFile (
+ rtl::OUString::createFromAscii("psp_pghead"), aExt);
+ osl::File* pPageBody = CreateSpoolFile (
+ rtl::OUString::createFromAscii("psp_pgbody"), aExt);
+
+ maHeaderList.push_back (pPageHeader);
+ maPageList.push_back (pPageBody);
+
+ if( ! (pPageHeader && pPageBody) )
+ return sal_False;
+
+ // write page header according to Document Structuring Conventions (DSC)
+ WritePS (pPageHeader, "%%Page: ");
+ WritePS (pPageHeader, aPageNo);
+ WritePS (pPageHeader, " ");
+ WritePS (pPageHeader, aPageNo);
+ WritePS (pPageHeader, "\n");
+
+ if( rJobSetup.m_eOrientation == orientation::Landscape )
+ {
+ WritePS (pPageHeader, "%%PageOrientation: Landscape\n");
+ mnLandscapes++;
+ }
+ else
+ {
+ WritePS (pPageHeader, "%%PageOrientation: Portrait\n");
+ mnPortraits++;
+ }
+
+ sal_Char pBBox [256];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::appendStr ("%%PageBoundingBox: ", pBBox);
+ nChar += psp::getValueOf (mnLMarginPt, pBBox + nChar);
+ nChar += psp::appendStr (" ", pBBox + nChar);
+ nChar += psp::getValueOf (mnBMarginPt, pBBox + nChar);
+ nChar += psp::appendStr (" ", pBBox + nChar);
+ nChar += psp::getValueOf (mnWidthPt - mnRMarginPt, pBBox + nChar);
+ nChar += psp::appendStr (" ", pBBox + nChar);
+ nChar += psp::getValueOf (mnHeightPt - mnTMarginPt, pBBox + nChar);
+ nChar += psp::appendStr ("\n", pBBox + nChar);
+
+ WritePS (pPageHeader, pBBox);
+
+ /* #i7262# #i65491# write setup only before first page
+ * (to %%Begin(End)Setup, instead of %%Begin(End)PageSetup)
+ * don't do this in StartJob since the jobsetup there may be
+ * different.
+ */
+ bool bWriteFeatures = true;
+ if( 1 == maPageList.size() )
+ {
+ m_aDocumentJobData = rJobSetup;
+ bWriteFeatures = false;
+ }
+
+ if ( writePageSetup( pPageHeader, rJobSetup, bWriteFeatures ) )
+ {
+ m_aLastJobData = rJobSetup;
+ return true;
+ }
+
+ return false;
+}
+
+sal_Bool
+PrinterJob::EndPage ()
+{
+ m_pGraphics->OnEndPage();
+
+ osl::File* pPageHeader = maHeaderList.back();
+ osl::File* pPageBody = maPageList.back();
+
+ if( ! (pPageBody && pPageHeader) )
+ return sal_False;
+
+ // copy page to paper and write page trailer according to DSC
+
+ sal_Char pTrailer[256];
+ sal_Int32 nChar = 0;
+ nChar = psp::appendStr ("grestore grestore\n", pTrailer);
+ nChar += psp::appendStr ("showpage\n", pTrailer + nChar);
+ nChar += psp::appendStr ("%%PageTrailer\n\n", pTrailer + nChar);
+ WritePS (pPageBody, pTrailer);
+
+ // this page is done for now, close it to avoid having too many open fd's
+
+ pPageHeader->close();
+ pPageBody->close();
+
+ return sal_True;
+}
+
+sal_uInt32
+PrinterJob::GetErrorCode ()
+{
+ /* TODO */
+ return 0;
+}
+
+struct less_ppd_key : public ::std::binary_function<double, double, bool>
+{
+ bool operator()(const PPDKey* left, const PPDKey* right)
+ { return left->getOrderDependency() < right->getOrderDependency(); }
+};
+
+static bool writeFeature( osl::File* pFile, const PPDKey* pKey, const PPDValue* pValue, bool bUseIncluseFeature )
+{
+ if( ! pKey || ! pValue )
+ return true;
+
+ OStringBuffer aFeature(256);
+ aFeature.append( "[{\n" );
+ if( bUseIncluseFeature )
+ aFeature.append( "%%IncludeFeature:" );
+ else
+ aFeature.append( "%%BeginFeature:" );
+ aFeature.append( " *" );
+ aFeature.append( OUStringToOString( pKey->getKey(), RTL_TEXTENCODING_ASCII_US ) );
+ aFeature.append( ' ' );
+ aFeature.append( OUStringToOString( pValue->m_aOption, RTL_TEXTENCODING_ASCII_US ) );
+ if( !bUseIncluseFeature )
+ {
+ aFeature.append( '\n' );
+ aFeature.append( OUStringToOString( pValue->m_aValue, RTL_TEXTENCODING_ASCII_US ) );
+ aFeature.append( "\n%%EndFeature" );
+ }
+ aFeature.append( "\n} stopped cleartomark\n" );
+ sal_uInt64 nWritten = 0;
+ return pFile->write( aFeature.getStr(), aFeature.getLength(), nWritten )
+ || nWritten != (sal_uInt64)aFeature.getLength() ? false : true;
+}
+
+bool PrinterJob::writeFeatureList( osl::File* pFile, const JobData& rJob, bool bDocumentSetup )
+{
+ bool bSuccess = true;
+ int i;
+
+ // emit features ordered to OrderDependency
+ // ignore features that are set to default
+
+ // sanity check
+ if( rJob.m_pParser == rJob.m_aContext.getParser() &&
+ rJob.m_pParser &&
+ ( m_aLastJobData.m_pParser == rJob.m_pParser || m_aLastJobData.m_pParser == NULL )
+ )
+ {
+ int nKeys = rJob.m_aContext.countValuesModified();
+ ::std::vector< const PPDKey* > aKeys( nKeys );
+ for( i = 0; i < nKeys; i++ )
+ aKeys[i] = rJob.m_aContext.getModifiedKey( i );
+ ::std::sort( aKeys.begin(), aKeys.end(), less_ppd_key() );
+
+ for( i = 0; i < nKeys && bSuccess; i++ )
+ {
+ const PPDKey* pKey = aKeys[i];
+ bool bEmit = false;
+ if( bDocumentSetup )
+ {
+ if( pKey->getSetupType() == PPDKey::DocumentSetup )
+ bEmit = true;
+ }
+ if( pKey->getSetupType() == PPDKey::PageSetup ||
+ pKey->getSetupType() == PPDKey::AnySetup )
+ bEmit = true;
+ if( bEmit )
+ {
+ const PPDValue* pValue = rJob.m_aContext.getValue( pKey );
+ if( pValue
+ && pValue->m_eType == eInvocation
+ && ( m_aLastJobData.m_pParser == NULL
+ || m_aLastJobData.m_aContext.getValue( pKey ) != pValue
+ || bDocumentSetup
+ )
+ )
+ {
+ // try to avoid PS level 2 feature commands if level is set to 1
+ if( GetPostscriptLevel( &rJob ) == 1 )
+ {
+ bool bHavePS2 =
+ ( pValue->m_aValue.SearchAscii( "<<" ) != STRING_NOTFOUND )
+ ||
+ ( pValue->m_aValue.SearchAscii( ">>" ) != STRING_NOTFOUND );
+ if( bHavePS2 )
+ continue;
+ }
+ bSuccess = writeFeature( pFile, pKey, pValue, PrinterInfoManager::get().getUseIncludeFeature() );
+ }
+ }
+ }
+ }
+ else
+ bSuccess = false;
+
+ return bSuccess;
+}
+
+bool PrinterJob::writePageSetup( osl::File* pFile, const JobData& rJob, bool bWriteFeatures )
+{
+ bool bSuccess = true;
+
+ WritePS (pFile, "%%BeginPageSetup\n%\n");
+ if ( bWriteFeatures )
+ bSuccess = writeFeatureList( pFile, rJob, false );
+ WritePS (pFile, "%%EndPageSetup\n");
+
+ sal_Char pTranslate [128];
+ sal_Int32 nChar = 0;
+
+ if( rJob.m_eOrientation == orientation::Portrait )
+ {
+ nChar = psp::appendStr ("gsave\n[", pTranslate);
+ nChar += psp::getValueOfDouble ( pTranslate + nChar, mfXScale, 5);
+ nChar += psp::appendStr (" 0 0 ", pTranslate + nChar);
+ nChar += psp::getValueOfDouble ( pTranslate + nChar, mfYScale, 5);
+ nChar += psp::appendStr (" ", pTranslate + nChar);
+ nChar += psp::getValueOf (mnRMarginPt, pTranslate + nChar);
+ nChar += psp::appendStr (" ", pTranslate + nChar);
+ nChar += psp::getValueOf (mnHeightPt-mnTMarginPt,
+ pTranslate + nChar);
+ nChar += psp::appendStr ("] concat\ngsave\n",
+ pTranslate + nChar);
+ }
+ else
+ {
+ nChar = psp::appendStr ("gsave\n", pTranslate);
+ nChar += psp::appendStr ("[ 0 ", pTranslate + nChar);
+ nChar += psp::getValueOfDouble ( pTranslate + nChar, -mfYScale, 5);
+ nChar += psp::appendStr (" ", pTranslate + nChar);
+ nChar += psp::getValueOfDouble ( pTranslate + nChar, mfXScale, 5);
+ nChar += psp::appendStr (" 0 ", pTranslate + nChar );
+ nChar += psp::getValueOfDouble ( pTranslate + nChar, mnLMarginPt, 5 );
+ nChar += psp::appendStr (" ", pTranslate + nChar);
+ nChar += psp::getValueOf (mnBMarginPt, pTranslate + nChar );
+ nChar += psp::appendStr ("] concat\ngsave\n",
+ pTranslate + nChar);
+ }
+
+ WritePS (pFile, pTranslate);
+
+ return bSuccess;
+}
+
+void PrinterJob::writeJobPatch( osl::File* pFile, const JobData& rJobData )
+{
+ if( ! PrinterInfoManager::get().getUseJobPatch() )
+ return;
+
+ const PPDKey* pKey = NULL;
+
+ if( rJobData.m_pParser )
+ pKey = rJobData.m_pParser->getKey( OUString( RTL_CONSTASCII_USTRINGPARAM( "JobPatchFile" ) ) );
+ if( ! pKey )
+ return;
+
+ // order the patch files
+ // according to PPD spec the JobPatchFile options must be int
+ // and should be emitted in order
+ std::list< sal_Int32 > patch_order;
+ int nValueCount = pKey->countValues();
+ for( int i = 0; i < nValueCount; i++ )
+ {
+ const PPDValue* pVal = pKey->getValue( i );
+ patch_order.push_back( pVal->m_aOption.ToInt32() );
+ if( patch_order.back() == 0 && ! pVal->m_aOption.EqualsAscii( "0" ) )
+ {
+ WritePS( pFile, "% Warning: left out JobPatchFile option \"" );
+ OString aOption = OUStringToOString( pVal->m_aOption, RTL_TEXTENCODING_ASCII_US );
+ WritePS( pFile, aOption.getStr() );
+ WritePS( pFile,
+ "\"\n% as it violates the PPD spec;\n"
+ "% JobPatchFile options need to be numbered for ordering.\n" );
+ }
+ }
+
+ patch_order.sort();
+ patch_order.unique();
+
+ while( patch_order.begin() != patch_order.end() )
+ {
+ // note: this discards patch files not adhering to the "int" scheme
+ // as there won't be a value for them
+ writeFeature( pFile, pKey, pKey->getValue( OUString::valueOf( patch_order.front() ) ), false );
+ patch_order.pop_front();
+ }
+}
+
+bool PrinterJob::writeProlog (osl::File* pFile, const JobData& rJobData )
+{
+ WritePS( pFile, "%%BeginProlog\n" );
+
+ // JobPatchFile feature needs to be emitted at begin of prolog
+ writeJobPatch( pFile, rJobData );
+
+ static const sal_Char pProlog[] = {
+ "%%BeginResource: procset PSPrint-Prolog 1.0 0\n"
+ "/ISO1252Encoding [\n"
+ "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
+ "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
+ "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
+ "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
+ "/space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quotesingle\n"
+ "/parenleft /parenright /asterisk /plus /comma /hyphen /period /slash\n"
+ "/zero /one /two /three /four /five /six /seven\n"
+ "/eight /nine /colon /semicolon /less /equal /greater /question\n"
+ "/at /A /B /C /D /E /F /G\n"
+ "/H /I /J /K /L /M /N /O\n"
+ "/P /Q /R /S /T /U /V /W\n"
+ "/X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore\n"
+ "/grave /a /b /c /d /e /f /g\n"
+ "/h /i /j /k /l /m /n /o\n"
+ "/p /q /r /s /t /u /v /w\n"
+ "/x /y /z /braceleft /bar /braceright /asciitilde /unused\n"
+ "/Euro /unused /quotesinglbase /florin /quotedblbase /ellipsis /dagger /daggerdbl\n"
+ "/circumflex /perthousand /Scaron /guilsinglleft /OE /unused /Zcaron /unused\n"
+ "/unused /quoteleft /quoteright /quotedblleft /quotedblright /bullet /endash /emdash\n"
+ "/tilde /trademark /scaron /guilsinglright /oe /unused /zcaron /Ydieresis\n"
+ "/space /exclamdown /cent /sterling /currency /yen /brokenbar /section\n"
+ "/dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron\n"
+ "/degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered\n"
+ "/cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf /threequarters /questiondown\n"
+ "/Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla\n"
+ "/Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis\n"
+ "/Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply\n"
+ "/Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls\n"
+ "/agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla\n"
+ "/egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis\n"
+ "/eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide\n"
+ "/oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis] def\n"
+ "\n"
+ "/psp_definefont { exch dup findfont dup length dict begin { 1 index /FID ne\n"
+ "{ def } { pop pop } ifelse } forall /Encoding 3 -1 roll def\n"
+ "currentdict end exch pop definefont pop } def\n"
+ "\n"
+ "/pathdict dup 8 dict def load begin\n"
+ "/rcmd { { currentfile 1 string readstring pop 0 get dup 32 gt { exit }\n"
+ "{ pop } ifelse } loop dup 126 eq { pop exit } if 65 sub dup 16#3 and 1\n"
+ "add exch dup 16#C and -2 bitshift 16#3 and 1 add exch 16#10 and 16#10\n"
+ "eq 3 1 roll exch } def\n"
+ "/rhex { dup 1 sub exch currentfile exch string readhexstring pop dup 0\n"
+ "get dup 16#80 and 16#80 eq dup 3 1 roll { 16#7f and } if 2 index 0 3\n"
+ "-1 roll put 3 1 roll 0 0 1 5 -1 roll { 2 index exch get add 256 mul }\n"
+ "for 256 div exch pop exch { neg } if } def\n"
+ "/xcmd { rcmd exch rhex exch rhex exch 5 -1 roll add exch 4 -1 roll add\n"
+ "1 index 1 index 5 -1 roll { moveto } { lineto } ifelse } def end\n"
+ "/readpath { 0 0 pathdict begin { xcmd } loop end pop pop } def\n"
+ "\n"
+ "systemdict /languagelevel known not {\n"
+ "/xshow { exch dup length 0 1 3 -1 roll 1 sub { dup 3 index exch get\n"
+ "exch 2 index exch get 1 string dup 0 4 -1 roll put currentpoint 3 -1\n"
+ "roll show moveto 0 rmoveto } for pop pop } def\n"
+ "/rectangle { 4 -2 roll moveto 1 index 0 rlineto 0 exch rlineto neg 0\n"
+ "rlineto closepath } def\n"
+ "/rectfill { rectangle fill } def\n"
+ "/rectstroke { rectangle stroke } def } if\n"
+ "/bshow { currentlinewidth 3 1 roll currentpoint 3 index show moveto\n"
+ "setlinewidth false charpath stroke setlinewidth } def\n"
+ "/bxshow { currentlinewidth 4 1 roll setlinewidth exch dup length 1 sub\n"
+ "0 1 3 -1 roll { 1 string 2 index 2 index get 1 index exch 0 exch put dup\n"
+ "currentpoint 3 -1 roll show moveto currentpoint 3 -1 roll false charpath\n"
+ "stroke moveto 2 index exch get 0 rmoveto } for pop pop setlinewidth } def\n"
+ "\n"
+ "/psp_lzwfilter { currentfile /ASCII85Decode filter /LZWDecode filter } def\n"
+ "/psp_ascii85filter { currentfile /ASCII85Decode filter } def\n"
+ "/psp_lzwstring { psp_lzwfilter 1024 string readstring } def\n"
+ "/psp_ascii85string { psp_ascii85filter 1024 string readstring } def\n"
+ "/psp_imagedict {\n"
+ "/psp_bitspercomponent { 3 eq { 1 }{ 8 } ifelse } def\n"
+ "/psp_decodearray { [ [0 1 0 1 0 1] [0 255] [0 1] [0 255] ] exch get }\n"
+ "def 7 dict dup\n"
+ "/ImageType 1 put dup\n"
+ "/Width 7 -1 roll put dup\n"
+ "/Height 5 index put dup\n"
+ "/BitsPerComponent 4 index psp_bitspercomponent put dup\n"
+ "/Decode 5 -1 roll psp_decodearray put dup\n"
+ "/ImageMatrix [1 0 0 1 0 0] dup 5 8 -1 roll put put dup\n"
+ "/DataSource 4 -1 roll 1 eq { psp_lzwfilter } { psp_ascii85filter } ifelse put\n"
+ "} def\n"
+ "%%EndResource\n"
+ "%%EndProlog\n"
+ };
+ static const sal_Char pSO52CompatProlog[] = {
+ "%%BeginResource: procset PSPrint-Prolog 1.0 0\n"
+ "/ISO1252Encoding [\n"
+ "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
+ "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
+ "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
+ "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
+ "/space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quoteright\n"
+ "/parenleft /parenright /asterisk /plus /comma /minus /period /slash\n"
+ "/zero /one /two /three /four /five /six /seven\n"
+ "/eight /nine /colon /semicolon /less /equal /greater /question\n"
+ "/at /A /B /C /D /E /F /G\n"
+ "/H /I /J /K /L /M /N /O\n"
+ "/P /Q /R /S /T /U /V /W\n"
+ "/X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore\n"
+ "/grave /a /b /c /d /e /f /g\n"
+ "/h /i /j /k /l /m /n /o\n"
+ "/p /q /r /s /t /u /v /w\n"
+ "/x /y /z /braceleft /bar /braceright /asciitilde /unused\n"
+ "/Euro /unused /quotesinglbase /florin /quotedblbase /ellipsis /dagger /daggerdbl\n"
+ "/circumflex /perthousand /Scaron /guilsinglleft /OE /unused /Zcaron /unused\n"
+ "/unused /quoteleft /quoteright /quotedblleft /quotedblright /bullet /endash /emdash\n"
+ "/tilde /trademark /scaron /guilsinglright /oe /unused /zcaron /Ydieresis\n"
+ "/space /exclamdown /cent /sterling /currency /yen /brokenbar /section\n"
+ "/dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron\n"
+ "/degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered\n"
+ "/cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf /threequarters /questiondown\n"
+ "/Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla\n"
+ "/Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis\n"
+ "/Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply\n"
+ "/Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls\n"
+ "/agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla\n"
+ "/egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis\n"
+ "/eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide\n"
+ "/oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis] def\n"
+ "\n"
+ "/psp_definefont { exch dup findfont dup length dict begin { 1 index /FID ne\n"
+ "{ def } { pop pop } ifelse } forall /Encoding 3 -1 roll def\n"
+ "currentdict end exch pop definefont pop } def\n"
+ "\n"
+ "/pathdict dup 8 dict def load begin\n"
+ "/rcmd { { currentfile 1 string readstring pop 0 get dup 32 gt { exit }\n"
+ "{ pop } ifelse } loop dup 126 eq { pop exit } if 65 sub dup 16#3 and 1\n"
+ "add exch dup 16#C and -2 bitshift 16#3 and 1 add exch 16#10 and 16#10\n"
+ "eq 3 1 roll exch } def\n"
+ "/rhex { dup 1 sub exch currentfile exch string readhexstring pop dup 0\n"
+ "get dup 16#80 and 16#80 eq dup 3 1 roll { 16#7f and } if 2 index 0 3\n"
+ "-1 roll put 3 1 roll 0 0 1 5 -1 roll { 2 index exch get add 256 mul }\n"
+ "for 256 div exch pop exch { neg } if } def\n"
+ "/xcmd { rcmd exch rhex exch rhex exch 5 -1 roll add exch 4 -1 roll add\n"
+ "1 index 1 index 5 -1 roll { moveto } { lineto } ifelse } def end\n"
+ "/readpath { 0 0 pathdict begin { xcmd } loop end pop pop } def\n"
+ "\n"
+ "systemdict /languagelevel known not {\n"
+ "/xshow { exch dup length 0 1 3 -1 roll 1 sub { dup 3 index exch get\n"
+ "exch 2 index exch get 1 string dup 0 4 -1 roll put currentpoint 3 -1\n"
+ "roll show moveto 0 rmoveto } for pop pop } def\n"
+ "/rectangle { 4 -2 roll moveto 1 index 0 rlineto 0 exch rlineto neg 0\n"
+ "rlineto closepath } def\n"
+ "/rectfill { rectangle fill } def\n"
+ "/rectstroke { rectangle stroke } def } if\n"
+ "/bshow { currentlinewidth 3 1 roll currentpoint 3 index show moveto\n"
+ "setlinewidth false charpath stroke setlinewidth } def\n"
+ "/bxshow { currentlinewidth 4 1 roll setlinewidth exch dup length 1 sub\n"
+ "0 1 3 -1 roll { 1 string 2 index 2 index get 1 index exch 0 exch put dup\n"
+ "currentpoint 3 -1 roll show moveto currentpoint 3 -1 roll false charpath\n"
+ "stroke moveto 2 index exch get 0 rmoveto } for pop pop setlinewidth } def\n"
+ "\n"
+ "/psp_lzwfilter { currentfile /ASCII85Decode filter /LZWDecode filter } def\n"
+ "/psp_ascii85filter { currentfile /ASCII85Decode filter } def\n"
+ "/psp_lzwstring { psp_lzwfilter 1024 string readstring } def\n"
+ "/psp_ascii85string { psp_ascii85filter 1024 string readstring } def\n"
+ "/psp_imagedict {\n"
+ "/psp_bitspercomponent { 3 eq { 1 }{ 8 } ifelse } def\n"
+ "/psp_decodearray { [ [0 1 0 1 0 1] [0 255] [0 1] [0 255] ] exch get }\n"
+ "def 7 dict dup\n"
+ "/ImageType 1 put dup\n"
+ "/Width 7 -1 roll put dup\n"
+ "/Height 5 index put dup\n"
+ "/BitsPerComponent 4 index psp_bitspercomponent put dup\n"
+ "/Decode 5 -1 roll psp_decodearray put dup\n"
+ "/ImageMatrix [1 0 0 1 0 0] dup 5 8 -1 roll put put dup\n"
+ "/DataSource 4 -1 roll 1 eq { psp_lzwfilter } { psp_ascii85filter } ifelse put\n"
+ "} def\n"
+ "%%EndResource\n"
+ "%%EndProlog\n"
+ };
+ WritePS (pFile, m_pGraphics && m_pGraphics->getStrictSO52Compatibility() ? pSO52CompatProlog : pProlog);
+
+ return true;
+}
+
+bool PrinterJob::writeSetup( osl::File* pFile, const JobData& rJob )
+{
+ WritePS (pFile, "%%BeginSetup\n%\n");
+
+ // download fonts
+ std::list< rtl::OString > aFonts[2];
+ m_pGraphics->writeResources( pFile, aFonts[0], aFonts[1] );
+
+ for( int i = 0; i < 2; i++ )
+ {
+ if( !aFonts[i].empty() )
+ {
+ std::list< rtl::OString >::const_iterator it = aFonts[i].begin();
+ rtl::OStringBuffer aLine( 256 );
+ if( i == 0 )
+ aLine.append( "%%DocumentSuppliedResources: font " );
+ else
+ aLine.append( "%%DocumentNeededResources: font " );
+ aLine.append( *it );
+ aLine.append( "\n" );
+ WritePS ( pFile, aLine.getStr() );
+ while( (++it) != aFonts[i].end() )
+ {
+ aLine.setLength(0);
+ aLine.append( "%%+ font " );
+ aLine.append( *it );
+ aLine.append( "\n" );
+ WritePS ( pFile, aLine.getStr() );
+ }
+ }
+ }
+
+ bool bSuccess = true;
+ // in case of external print dialog the number of copies is prepended
+ // to the job, let us not complicate things by emitting our own copy count
+ bool bExternalDialog = PrinterInfoManager::get().checkFeatureToken( GetPrinterName(), "external_dialog" );
+ if( ! bExternalDialog && rJob.m_nCopies > 1 )
+ {
+ // setup code
+ ByteString aLine( "/#copies " );
+ aLine += ByteString::CreateFromInt32( rJob.m_nCopies );
+ aLine += " def\n";
+ sal_uInt64 nWritten = 0;
+ bSuccess = pFile->write( aLine.GetBuffer(), aLine.Len(), nWritten )
+ || nWritten != aLine.Len() ? false : true;
+
+ if( bSuccess && GetPostscriptLevel( &rJob ) >= 2 )
+ WritePS (pFile, "<< /NumCopies null /Policies << /NumCopies 1 >> >> setpagedevice\n" );
+ }
+
+ bool bFeatureSuccess = writeFeatureList( pFile, rJob, true );
+
+ WritePS (pFile, "%%EndSetup\n");
+
+ return bSuccess && bFeatureSuccess;
+}
diff --git a/vcl/unx/source/printergfx/psheader.ps b/vcl/unx/source/printergfx/psheader.ps
new file mode 100644
index 000000000000..6a0e350d9ddc
--- /dev/null
+++ b/vcl/unx/source/printergfx/psheader.ps
@@ -0,0 +1,368 @@
+%*************************************************************************
+%
+% 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.
+%
+%*************************************************************************
+
+%
+%
+% readpath
+%
+% The intention of readpath is to save disk space since the vcl clip region routines
+% produce a huge amount of lineto/moveto commands
+%
+% The principal idea is to maintain the current point on stack and to provide only deltas
+% in the command. These deltas are added to the current point. The new point is used for
+% the lineto and moveto command and saved on stack for the next command.
+%
+% pathdict implements binary/hex representation of lineto and moveto commands.
+% The command consists of a 1byte opcode to switch between lineto and moveto and the size
+% of the following delta-x and delta-y values. The opcode is read with /rcmd, the two
+% coordinates are read with /rhex. The whole command is executed with /xcmd
+%
+%
+
+/pathdict dup 8 dict def load
+begin
+
+ % the command is of the bit format cxxyy
+ % with c=0 meaning lineto
+ % c=1 meaning moveto
+ % xx is a 2bit value for the number of bytes for x position
+ % yy is the same for y, values are off by one: 00 means 1; 11 means 4 !
+ % the command has been added to 'A' to be always in the ascii character
+ % range. the command is followed by 2*xx + 2*yy hexchars.
+ % '~' denotes the special case of EOD
+ /rcmd {
+ {
+ currentfile 1 string readstring % s bool
+ pop % s
+ 0 get % s[0]
+ % --- check wether s[0] is CR, LF ...
+ dup 32 gt % s > ' ' ? then read on
+ { exit }
+ { pop }
+ ifelse
+ }
+ loop
+
+ dup 126 eq { pop exit } if % -- Exit loop if cmd is '~'
+ 65 sub % cmd=s[0]-'A'
+ % -- Separate yy bits
+ dup 16#3 and 1 add % cmd yy
+ % -- Separate xx bits
+ exch % yy cmd
+ dup 16#C and -2 bitshift
+ 16#3 and 1 add exch % yy xx cmd
+ % -- Separate command bit
+ 16#10 and 16#10 eq % yy xx bool
+ 3 1 roll exch % bool xx yy
+ } def
+
+ % length rhex -- reads a signed hex value of given length
+ % the left most bit of char 0 is considered as the sign (0 means '+', 1 means '-')
+ % the rest of the bits is considered to be the abs value. Please note that this
+ % does not match the C binary representation of integers
+ /rhex {
+ dup 1 sub exch % l-1 l
+ currentfile exch string readhexstring % l-1 substring[l] bool
+ pop
+ dup 0 get dup % l-1 s s[0] s[0]
+ % -- Extract the sign
+ 16#80 and 16#80 eq dup % l-1 s s[0] sign=- sign=-
+ % -- Mask out the sign bit and put value back
+ 3 1 roll % l-1 s sign=- s[0] sign=-
+ { 16#7f and } if % l-1 s sign=- +s[0]
+ 2 index 0 % l-1 s sign=- +s[0] s 0
+ 3 -1 roll put % l-1 s sign=- s 0 +s[0]
+ % -- Read loop: add to prev sum, mul with 256
+ 3 1 roll 0 % sign=- l-1 s Sum=0
+ 0 1 5 -1 roll % sign=- s Sum=0 0 1 l-1
+ { % sign=- s Sum idx
+ 2 index exch % sign=- s Sum s idx
+ get % sign=- s Sum s[idx]
+ add 256 mul % sign=- s Sum=(s[idx]+Sum)*256
+ }
+ for
+ % -- mul was once too often, weave in the sign
+ 256 div % sign=- s Sum/256
+ exch pop % sign=- Sum/256
+ exch { neg } if % (sign=- ? -Sum : Sum)
+ } def
+
+ % execute a single command, the former x and y position is already on stack
+ % only offsets are read from cmdstring
+ /xcmd { % x y
+ rcmd % x y bool wx wy
+ exch rhex % x y bool wy Dx
+ exch rhex % x y bool Dx Dy
+ exch 5 -1 roll % y bool Dy Dx x
+ add exch % y bool X Dy
+ 4 -1 roll add % bool X Y
+ 1 index 1 index % bool X Y X Y
+ 5 -1 roll % X Y X Y bool
+ { moveto }
+ { lineto }
+ ifelse % X Y
+ } def
+end
+
+/readpath
+{
+ 0 0 % push initial-x initial-y
+ pathdict begin
+ { xcmd } loop
+ end
+ pop pop % pop final-x final-y
+} def
+
+%
+%
+% if languagelevel is not in the systemdict then its level 1 interpreter:
+% provide compatibility routines
+%
+%
+
+systemdict /languagelevel known not
+{
+ % string numarray xxshow -
+ % does only work for single byte fonts
+ /xshow {
+ exch dup % a s s
+ length 0 1 % a s l(s) 1 1
+ 3 -1 roll 1 sub % a s 0 1 l(s)-1
+ { % a s idx
+ dup % a s idx idx
+ % -- extract the delta offset
+ 3 index exch get % a s idx a[idx]
+ % -- extract the character
+ exch % a s a[idx] idx
+ 2 index exch get % a s a[idx] s[idx]
+ % -- create a tmp string for show
+ 1 string dup 0 % a s a[idx] s[idx] s1 s1 0
+ 4 -1 roll % a s a[idx] s1 s1 0 s[idx]
+ put % a s a[idx] s1
+ % -- store the current point
+ currentpoint 3 -1 roll % a s a[idx] x y s1
+ % -- draw the character
+ show % a s a[idx] x y
+ % -- move to the offset
+ moveto 0 rmoveto % a s
+ }
+ for
+ pop pop % -
+ } def
+
+ % x y width height rectfill
+ % x y width height rectshow
+ % in contrast to the languagelevel 2 operator
+ % they use and change the currentpath
+ /rectangle {
+ 4 -2 roll % width height x y
+ moveto % width height
+ 1 index 0 rlineto % width height % rmoveto(width, 0)
+ 0 exch rlineto % width % rmoveto(0, height)
+ neg 0 rlineto % - % rmoveto(-width, 0)
+ closepath
+ } def
+
+ /rectfill { rectangle fill } def
+ /rectstroke { rectangle stroke } def
+}
+if
+
+% -- small test program
+% 75 75 moveto /Times-Roman findfont 12 scalefont setfont
+% <292a2b2c2d2e2f30313233343536373839>
+% [5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 5] xshow <21>[0] xshow
+% showpage
+
+%
+%
+% shortcuts for image header with compression
+%
+%
+
+/psp_lzwfilter {
+ currentfile /ASCII85Decode filter /LZWDecode filter
+} def
+/psp_ascii85filter {
+ currentfile /ASCII85Decode filter
+} def
+/psp_lzwstring {
+ psp_lzwfilter 1024 string readstring
+} def
+/psp_ascii85string {
+ psp_ascii85filter 1024 string readstring
+} def
+/psp_imagedict {
+ /psp_bitspercomponent {
+ 3 eq
+ { 1 }
+ { 8 }
+ ifelse
+ } def
+ /psp_decodearray {
+ [ [0 1 0 1 0 1] [0 255] [0 1] [0 255] ] exch get
+ } def
+
+ 7 dict dup
+ /ImageType 1 put dup
+ /Width 7 -1 roll put dup
+ /Height 5 index put dup
+ /BitsPerComponent 4 index
+ psp_bitspercomponent put dup
+ /Decode 5 -1 roll
+ psp_decodearray put dup
+ /ImageMatrix [1 0 0 1 0 0] dup
+ 5 8 -1 roll put put dup
+ /DataSource 4 -1 roll
+ 1 eq
+ { psp_lzwfilter }
+ { psp_ascii85filter }
+ ifelse put
+} def
+
+
+%
+%
+% font encoding and reencoding
+%
+%
+
+/ISO1252Encoding [
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quotesingle
+ /parenleft /parenright /asterisk /plus /comma /hyphen /period /slash
+ /zero /one /two /three /four /five /six /seven
+ /eight /nine /colon /semicolon /less /equal /greater /question
+ /at /A /B /C /D /E /F /G
+ /H /I /J /K /L /M /N /O
+ /P /Q /R /S /T /U /V /W
+ /X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore
+ /grave /a /b /c /d /e /f /g
+ /h /i /j /k /l /m /n /o
+ /p /q /r /s /t /u /v /w
+ /x /y /z /braceleft /bar /braceright /asciitilde /unused
+ /Euro /unused /quotesinglbase /florin /quotedblbase /ellipsis /dagger /daggerdbl
+ /circumflex /perthousand /Scaron /guilsinglleft /OE /unused /Zcaron /unused
+ /unused /quoteleft /quoteright /quotedblleft /quotedblright /bullet /endash /emdash
+ /tilde /trademark /scaron /guilsinglright /oe /unused /zcaron /Ydieresis
+ /space /exclamdown /cent /sterling /currency /yen /brokenbar /section
+ /dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron
+ /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered
+ /cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf /threequarters /questiondown
+ /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla
+ /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis
+ /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply
+ /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls
+ /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla
+ /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis
+ /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide
+ /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis
+] def
+
+% /fontname /encoding psp_findfont
+/psp_findfont {
+ exch dup % encoding fontname fontname
+ findfont % encoding fontname
+ dup length dict
+ begin
+ {
+ 1 index /FID ne
+ { def }
+ { pop pop }
+ ifelse
+ } forall
+ /Encoding 3 -1 roll def
+ currentdict
+ end
+ /psp_reencodedfont exch definefont
+} def
+
+% bshow shows a text in artificial bold
+% this is achieved by first showing the text
+% then stroking its outline over it with
+% the linewidth set to the second parameter
+% usage: (string) num bshow
+
+/bshow {
+ currentlinewidth % save current linewidth
+ 3 1 roll % move it to the last stack position
+ currentpoint % save the current point
+ 3 index % copy the string to show
+ show % show it
+ moveto % move to the original coordinates again
+ setlinewidth % set the linewidth
+ false charpath % create the outline path of the shown string
+ stroke % and stroke it
+ setlinewidth % reset the stored linewidth
+} def
+
+% bxshow shows a text with a delta array in artificial bold
+% that is it does what bshow does for show
+% usage: (string) [deltaarray] num bxshow
+
+/bxshow {
+ currentlinewidth % save linewidth
+ 4 1 roll % move it to the last stack position
+ setlinewidth % set the new linewidth
+ exch % exchange string and delta array
+ dup
+ length % get length of string
+ 1 sub % prepare parameters for {} for
+ 0 1
+ 3 -1 roll
+ {
+ 1 string % create a string object length 1
+ 2 index % get the text
+ 2 index % get charpos (for index variable)
+ get % have char value at charpos
+ 1 index % prepare string for put
+ exch
+ 0
+ exch
+ put % put into string of length 1
+ dup % duplicate the it
+ currentpoint % save current position
+ 3 -1 roll % prepare show
+ show % show the character
+ moveto % move back to beginning
+ currentpoint % save current position
+ 3 -1 roll % prepare outline path of character
+ false charpath
+ stroke % stroke it
+ moveto % move back
+ % now move to next point
+ 2 index % get advance array
+ exch % get charpos
+ get % get advance element
+ 0 rmoveto % advance current position
+ } for
+ pop pop % remove string and delta array
+ setlinewidth % restore linewidth
+} def
diff --git a/vcl/unx/source/printergfx/psputil.cxx b/vcl/unx/source/printergfx/psputil.cxx
new file mode 100644
index 000000000000..370114be47cb
--- /dev/null
+++ b/vcl/unx/source/printergfx/psputil.cxx
@@ -0,0 +1,268 @@
+/*************************************************************************
+ *
+ * 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 "psputil.hxx"
+
+#include "tools/debug.hxx"
+
+namespace psp {
+
+/*
+ * string convenience routines
+ */
+
+sal_Int32
+getHexValueOf (sal_Int32 nValue, sal_Char* pBuffer)
+{
+ const static sal_Char pHex [0x10] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+ pBuffer[0] = pHex [(nValue & 0xF0) >> 4];
+ pBuffer[1] = pHex [(nValue & 0x0F) ];
+
+ return 2;
+}
+
+sal_Int32
+getAlignedHexValueOf (sal_Int32 nValue, sal_Char* pBuffer)
+{
+ // get sign
+ sal_Bool bNegative = nValue < 0;
+ nValue = bNegative ? -nValue : nValue;
+
+ // get required buffer size, must be a multiple of two
+ sal_Int32 nPrecision;
+ if (nValue < 0x80)
+ nPrecision = 2;
+ else
+ if (nValue < 0x8000)
+ nPrecision = 4;
+ else
+ if (nValue < 0x800000)
+ nPrecision = 6;
+ else
+ nPrecision = 8;
+
+ // convert the int into its hex representation, write it into the buffer
+ sal_Int32 nRet = nPrecision;
+ while (nPrecision)
+ {
+ nPrecision -= getHexValueOf (nValue % 256, pBuffer + nPrecision - 2 );
+ nValue /= 256;
+ }
+
+ // set sign bit
+ if (bNegative)
+ {
+ switch (pBuffer[0])
+ {
+ case '0' : pBuffer[0] = '8'; break;
+ case '1' : pBuffer[0] = '9'; break;
+ case '2' : pBuffer[0] = 'A'; break;
+ case '3' : pBuffer[0] = 'B'; break;
+ case '4' : pBuffer[0] = 'C'; break;
+ case '5' : pBuffer[0] = 'D'; break;
+ case '6' : pBuffer[0] = 'E'; break;
+ case '7' : pBuffer[0] = 'F'; break;
+ default: DBG_ERROR("Already a signed value");
+ }
+ }
+
+ // report precision
+ return nRet;
+}
+
+
+sal_Int32
+getValueOf (sal_Int32 nValue, sal_Char* pBuffer)
+{
+ sal_Int32 nChar = 0;
+ if (nValue < 0)
+ {
+ pBuffer [nChar++] = '-';
+ nValue *= -1;
+ }
+ else
+ if (nValue == 0)
+ {
+ pBuffer [nChar++] = '0';
+ return nChar;
+ }
+
+ sal_Char pInvBuffer [32];
+ sal_Int32 nInvChar = 0;
+ while (nValue > 0)
+ {
+ pInvBuffer [nInvChar++] = '0' + nValue % 10;
+ nValue /= 10;
+ }
+ while (nInvChar > 0)
+ {
+ pBuffer [nChar++] = pInvBuffer [--nInvChar];
+ }
+
+ return nChar;
+}
+
+sal_Int32
+appendStr (const sal_Char* pSrc, sal_Char* pDst)
+{
+ sal_Int32 nBytes = strlen (pSrc);
+ strncpy (pDst, pSrc, nBytes + 1);
+
+ return nBytes;
+}
+
+sal_Int32
+appendStr (const sal_Char* pSrc, sal_Char* pDst, sal_Int32 nBytes)
+{
+ strncpy (pDst, pSrc, nBytes);
+ pDst [nBytes] = '\0';
+ return nBytes;
+}
+
+/*
+ * copy strings to file
+ */
+
+sal_Bool
+WritePS (osl::File* pFile, const sal_Char* pString)
+{
+ sal_uInt64 nInLength = rtl_str_getLength (pString);
+ sal_uInt64 nOutLength = 0;
+
+ if (nInLength > 0 && pFile)
+ pFile->write (pString, nInLength, nOutLength);
+
+ return nInLength == nOutLength;
+}
+
+sal_Bool
+WritePS (osl::File* pFile, const sal_Char* pString, sal_uInt64 nInLength)
+{
+ sal_uInt64 nOutLength = 0;
+
+ if (nInLength > 0 && pFile)
+ pFile->write (pString, nInLength, nOutLength);
+
+ return nInLength == nOutLength;
+}
+
+sal_Bool
+WritePS (osl::File* pFile, const rtl::OString &rString)
+{
+ sal_uInt64 nInLength = rString.getLength();
+ sal_uInt64 nOutLength = 0;
+
+ if (nInLength > 0 && pFile)
+ pFile->write (rString, nInLength, nOutLength);
+
+ return nInLength == nOutLength;
+}
+
+sal_Bool
+WritePS (osl::File* pFile, const rtl::OUString &rString)
+{
+ return WritePS (pFile, rtl::OUStringToOString(rString, RTL_TEXTENCODING_ASCII_US));
+}
+
+/*
+ * cache converter for use in postscript drawing routines
+ */
+
+ConverterFactory::ConverterFactory()
+{
+}
+
+ConverterFactory::~ConverterFactory ()
+{
+ for( std::map< rtl_TextEncoding, rtl_UnicodeToTextConverter >::const_iterator it = m_aConverters.begin(); it != m_aConverters.end(); ++it )
+ rtl_destroyUnicodeToTextConverter (it->second);
+}
+
+rtl_UnicodeToTextConverter
+ConverterFactory::Get (rtl_TextEncoding nEncoding)
+{
+ if (rtl_isOctetTextEncoding( nEncoding ))
+ {
+ std::map< rtl_TextEncoding, rtl_UnicodeToTextConverter >::const_iterator it =
+ m_aConverters.find( nEncoding );
+ rtl_UnicodeToTextConverter aConverter;
+ if (it == m_aConverters.end())
+ {
+ aConverter = rtl_createUnicodeToTextConverter (nEncoding);
+ m_aConverters[nEncoding] = aConverter;
+ }
+ else
+ aConverter = it->second;
+ return aConverter;
+ }
+ return NULL;
+}
+
+// wrapper for rtl_convertUnicodeToText that handles the usual cases for
+// textconversion in drawtext
+sal_Size
+ConverterFactory::Convert (const sal_Unicode *pText, int nTextLen,
+ sal_uChar *pBuffer, sal_Size nBufferSize, rtl_TextEncoding nEncoding)
+{
+ const sal_uInt32 nCvtFlags = RTL_UNICODETOTEXT_FLAGS_UNDEFINED_QUESTIONMARK
+ | RTL_UNICODETOTEXT_FLAGS_INVALID_QUESTIONMARK ;
+ sal_uInt32 nCvtInfo;
+ sal_Size nCvtChars;
+
+ rtl_UnicodeToTextConverter aConverter = Get (nEncoding);
+ rtl_UnicodeToTextContext aContext = rtl_createUnicodeToTextContext (aConverter);
+
+ sal_Size nSize = rtl_convertUnicodeToText (aConverter, aContext,
+ pText, nTextLen, (sal_Char*)pBuffer, nBufferSize,
+ nCvtFlags, &nCvtInfo, &nCvtChars);
+
+ rtl_destroyUnicodeToTextContext (aConverter, aContext);
+
+ return nSize;
+}
+
+ConverterFactory*
+GetConverterFactory ()
+{
+ static ConverterFactory* pCvt = NULL;
+
+ if (pCvt == NULL)
+ pCvt = new ConverterFactory;
+
+ return pCvt;
+}
+
+
+} /* namespace psp */
diff --git a/vcl/unx/source/printergfx/psputil.hxx b/vcl/unx/source/printergfx/psputil.hxx
new file mode 100644
index 000000000000..d4af41bb95ed
--- /dev/null
+++ b/vcl/unx/source/printergfx/psputil.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _PSPRINT_PRINTERUTIL_HXX_
+#define _PSPRINT_PRINTERUTIL_HXX_
+
+#include "osl/file.hxx"
+
+#include "rtl/ustring.hxx"
+#include "rtl/string.hxx"
+#include "rtl/tencinfo.h"
+#include "rtl/textcvt.h"
+
+#include <map>
+
+namespace psp {
+
+/*
+ * string convenience routines
+ * sizeof(pBuffer) must be at least 2 Bytes, 0x00 <= nValue <= 0xFF,
+ * effective buffer of get*ValueOf() is NOT NULL-terminated
+ */
+sal_Int32 getHexValueOf (sal_Int32 nValue, sal_Char* pBuffer);
+sal_Int32 getAlignedHexValueOf (sal_Int32 nValue, sal_Char* pBuffer);
+sal_Int32 getValueOf (sal_Int32 nValue, sal_Char* pBuffer);
+sal_Int32 appendStr (const sal_Char* pSrc, sal_Char* pDst);
+sal_Int32 appendStr (const sal_Char* pSrc, sal_Char* pDst, sal_Int32 nBytes);
+
+sal_Bool WritePS (osl::File* pFile, const sal_Char* pString);
+sal_Bool WritePS (osl::File* pFile, const sal_Char* pString, sal_uInt64 nInLength);
+sal_Bool WritePS (osl::File* pFile, const rtl::OString &rString);
+sal_Bool WritePS (osl::File* pFile, const rtl::OUString &rString);
+
+class ConverterFactory
+{
+
+public:
+ ConverterFactory();
+ ~ConverterFactory();
+ rtl_UnicodeToTextConverter Get (rtl_TextEncoding nEncoding);
+ sal_Size Convert (const sal_Unicode *pText, int nTextLen,
+ sal_uChar *pBuffer, sal_Size nBufferSize,
+ rtl_TextEncoding nEncoding);
+private:
+
+ std::map< rtl_TextEncoding, rtl_UnicodeToTextConverter > m_aConverters;
+};
+
+ConverterFactory* GetConverterFactory ();
+
+} /* namespace psp */
+
+#endif /* _PSPRINT_PRINTERUTIL_HXX_ */
+
diff --git a/vcl/unx/source/printergfx/text_gfx.cxx b/vcl/unx/source/printergfx/text_gfx.cxx
new file mode 100644
index 000000000000..1901aa0d004a
--- /dev/null
+++ b/vcl/unx/source/printergfx/text_gfx.cxx
@@ -0,0 +1,862 @@
+/*************************************************************************
+ *
+ * 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 "psputil.hxx"
+#include "glyphset.hxx"
+
+#include "vcl/printergfx.hxx"
+#include "vcl/fontmanager.hxx"
+#include "vcl/helper.hxx"
+
+#include "osl/thread.h"
+
+#include "sal/alloca.h"
+
+using namespace psp ;
+
+namespace psp {
+/*
+ container for a font and its helper fonts:
+ 1st font is the font substitute e.g. helvetica substitutes arial on the printer
+ 2nd is the font itself
+ 3rd is a fallback font, usually a font with unicode glyph repertoir (e.g. andale)
+ symbol fonts (adobe-fontspecific) may need special glyphmapping
+ (symbol page vc. latin page)
+*/
+class Font3
+{
+ private:
+
+ #define Font3Size 3
+
+ fontID mpFont [Font3Size];
+ bool mbSymbol;
+
+ public:
+
+ fontID GetFont (int nIdx) const
+ { return nIdx < Font3Size ? mpFont[nIdx] : -1 ; }
+ bool IsSymbolFont () const
+ { return mbSymbol; }
+
+ Font3 (const PrinterGfx &rGfx);
+ ~Font3 () {}
+};
+
+Font3::Font3(const PrinterGfx &rGfx)
+{
+ mpFont[0] = rGfx.getFontSubstitute();
+ mpFont[1] = rGfx.GetFontID();
+ mpFont[2] = rGfx.getFallbackID();
+ // mpFont[2] = rGfx.GetFontID();
+
+ PrintFontManager &rMgr = PrintFontManager::get();
+ mbSymbol = mpFont[1] != -1 ?
+ rMgr.getFontEncoding(mpFont[1]) == RTL_TEXTENCODING_SYMBOL : false;
+}
+
+} // namespace psp
+
+static int getVerticalDeltaAngle( sal_Unicode nChar )
+{
+ int nAngle = 0;
+ if( ( nChar >= 0x1100 && nChar < 0x11fa ) ||
+ ( nChar >= 0x3000 && nChar < 0xfb00 ) ||
+ ( nChar >= 0xfe20 && nChar < 0xfe70 ) ||
+ ( nChar >= 0xff00 && nChar < 0xff64 )
+ )
+ {
+ /* #i52932# remember:
+ nChar == 0x2010 || nChar == 0x2015
+ nChar == 0x2016 || nChar == 0x2026
+
+ are nAngle = 0 also, but already handled in the first if
+ */
+ if( ( nChar >= 0x3008 && nChar < 0x3019 && nChar != 0x3012 ) ||
+ nChar == 0xff3b || nChar == 0xff3d ||
+ (nChar >= 0xff6b && nChar < 0xff64 ) ||
+ nChar == 0xffe3
+ )
+ nAngle = 0;
+ else if( nChar == 0x30fc )
+ nAngle = -900;
+ else
+ nAngle = 900;
+ }
+ return nAngle;
+}
+
+void
+PrinterGfx::PSUploadPS1Font (sal_Int32 nFontID)
+{
+ std::list< sal_Int32 >::iterator aFont;
+ // already in the document header ?
+ for (aFont = maPS1Font.begin(); aFont != maPS1Font.end(); ++aFont )
+ if( nFontID == *aFont )
+ return;
+
+ // no occurrenc yet, mark for download
+ // add the fontid to the list
+ maPS1Font.push_back (nFontID);
+}
+
+/*
+ * implement text handling printer routines,
+ */
+
+sal_uInt16
+PrinterGfx::SetFont(
+ sal_Int32 nFontID,
+ sal_Int32 nHeight,
+ sal_Int32 nWidth,
+ sal_Int32 nAngle,
+ bool bVertical,
+ bool bArtItalic,
+ bool bArtBold
+ )
+{
+ // font and encoding will be set by drawText again immediately
+ // before PSShowText
+ mnFontID = nFontID;
+ maVirtualStatus.maFont = rtl::OString();
+ maVirtualStatus.maEncoding = RTL_TEXTENCODING_DONTKNOW;
+ maVirtualStatus.mnTextHeight = nHeight;
+ maVirtualStatus.mnTextWidth = nWidth;
+ maVirtualStatus.mbArtItalic = bArtItalic;
+ maVirtualStatus.mbArtBold = bArtBold;
+ mnTextAngle = nAngle;
+ mbTextVertical = bVertical;
+
+ return 0;
+}
+
+sal_uInt16
+PrinterGfx::SetFallbackFont ( sal_Int32 nFontID )
+{
+ mnFallbackID = nFontID;
+ return 0;
+}
+
+void PrinterGfx::drawGlyphs(
+ const Point& rPoint,
+ sal_uInt32* pGlyphIds,
+ sal_Unicode* pUnicodes,
+ sal_Int16 nLen,
+ sal_Int32* pDeltaArray
+ )
+{
+
+ // draw the string
+ // search for a glyph set matching the set font
+ std::list< GlyphSet >::iterator aIter;
+ for (aIter = maPS3Font.begin(); aIter != maPS3Font.end(); aIter++)
+ if ( ((*aIter).GetFontID() == mnFontID)
+ && ((*aIter).IsVertical() == mbTextVertical))
+ {
+ (*aIter).DrawGlyphs (*this, rPoint, pGlyphIds, pUnicodes, nLen, pDeltaArray);
+ break;
+ }
+
+ // not found ? create a new one
+ if (aIter == maPS3Font.end())
+ {
+ maPS3Font.push_back (GlyphSet(mnFontID, mbTextVertical));
+ maPS3Font.back().DrawGlyphs (*this, rPoint, pGlyphIds, pUnicodes, nLen, pDeltaArray);
+ }
+}
+
+void PrinterGfx::DrawGlyphs(
+ const Point& rPoint,
+ sal_GlyphId* pGlyphIds,
+ sal_Unicode* pUnicodes,
+ sal_Int16 nLen,
+ sal_Int32* pDeltaArray
+ )
+{
+ if( nLen <= 0 )
+ return;
+
+ if ( !mrFontMgr.isFontDownloadingAllowed( mnFontID ) )
+ {
+ LicenseWarning(rPoint, pUnicodes, nLen, pDeltaArray);
+ return;
+ }
+
+ if( mrFontMgr.getFontType( mnFontID ) != fonttype::TrueType )
+ {
+ DrawText( rPoint, pUnicodes, nLen, pDeltaArray );
+ return;
+ }
+
+ // move and rotate the user coordinate system
+ // avoid the gsave/grestore for the simple cases since it allows
+ // reuse of the current font if it hasn't changed
+ sal_Int32 nCurrentTextAngle = mnTextAngle;
+ Point aPoint( rPoint );
+
+ if (nCurrentTextAngle != 0)
+ {
+ PSGSave ();
+ PSTranslate (rPoint);
+ PSRotate (nCurrentTextAngle);
+ mnTextAngle = 0;
+ aPoint = Point( 0, 0 );
+ }
+
+ if( mbTextVertical )
+ {
+ // vertical glyphs can have an additional rotation ... sigh.
+ // so break up text in chunks of normal glyphs and print out
+ // specially rotated glyphs extra
+ sal_uInt32* pTempGlyphIds = (sal_uInt32*)alloca(sizeof(sal_Int32)*nLen);
+ sal_Int32* pTempDelta = (sal_Int32*)alloca(sizeof(sal_Int32)*nLen);
+ sal_Unicode* pTempUnicodes = (sal_Unicode*)alloca(sizeof(sal_Unicode)*nLen);
+ sal_Int16 nTempLen = 0;
+ sal_Int32 nTempFirstDelta = 0;
+ Point aRotPoint;
+ sal_Int32 nTextHeight = maVirtualStatus.mnTextHeight;
+ sal_Int32 nTextWidth = maVirtualStatus.mnTextWidth ? maVirtualStatus.mnTextWidth : maVirtualStatus.mnTextHeight;
+ sal_Int32 nAscend = mrFontMgr.getFontAscend( mnFontID );
+ sal_Int32 nDescend = mrFontMgr.getFontDescend( mnFontID );
+
+ nDescend = nDescend * nTextHeight / 1000;
+ nAscend = nAscend * nTextHeight / 1000;
+
+ for( sal_Int16 i = 0; i < nLen; i++ )
+ {
+ const sal_GlyphId nRot = pGlyphIds[i] & GF_ROTMASK;
+ if( nRot == GF_NONE )
+ {
+ pTempUnicodes[nTempLen] = pUnicodes[i];
+ pTempGlyphIds[nTempLen] = pGlyphIds[i];
+ if( nTempLen > 0 )
+ pTempDelta[nTempLen-1] = pDeltaArray[i-1]-nTempFirstDelta;
+ else
+ {
+ // the first element in pDeltaArray shows
+ // the offset of the second character
+ // so if the first glyph is normal
+ // then we do not need to move the delta indices
+ // else we have to move them down by one and
+ // recalculate aPoint and all deltas
+ if( i != 0 )
+ nTempFirstDelta = pDeltaArray[ i-1 ];
+ }
+ nTempLen++;
+ }
+ else
+ {
+ sal_Int32 nOffset = i > 0 ? pDeltaArray[i-1] : 0;
+ sal_Int32 nRotAngle = 0;
+ switch( nRot )
+ {
+ case GF_ROTR:
+ nRotAngle = 2700;
+ aRotPoint = Point( -nAscend*nTextWidth/nTextHeight, -nDescend*nTextWidth/nTextHeight - nOffset );
+ break;
+ case GF_VERT:
+ nRotAngle = 1800;
+ aRotPoint = Point( -nOffset, (nAscend+nDescend) );
+ break;
+ case GF_ROTL:
+ nRotAngle = 900;
+ aRotPoint = Point( -nDescend*nTextWidth/nTextHeight, nOffset + nAscend*nTextWidth/nTextHeight );
+ break;
+ }
+ sal_GlyphId nRotGlyphId = pGlyphIds[i];
+ sal_Unicode nRotUnicode = pUnicodes[i];
+ sal_Int32 nRotDelta = 0;
+
+ // transform matrix to new individual direction
+ PSGSave ();
+ GraphicsStatus aSaveStatus = maVirtualStatus;
+ if( nRot != 2 ) // switch font aspect
+ {
+ maVirtualStatus.mnTextWidth = nTextHeight;
+ maVirtualStatus.mnTextHeight = nTextWidth;
+ }
+ if( aPoint.X() || aPoint.Y() )
+ PSTranslate( aPoint );
+ PSRotate (nRotAngle);
+ // draw the rotated glyph
+ drawGlyphs( aRotPoint, &nRotGlyphId, &nRotUnicode, 1, &nRotDelta );
+
+ // restore previous state
+ maVirtualStatus = aSaveStatus;
+ PSGRestore();
+ }
+ }
+
+ pGlyphIds = pTempGlyphIds;
+ pUnicodes = pTempUnicodes;
+ pDeltaArray = pTempDelta;
+ nLen = nTempLen;
+
+ aPoint.X() += nTempFirstDelta;
+ }
+
+ if( nLen > 0 )
+ drawGlyphs( aPoint, pGlyphIds, pUnicodes, nLen, pDeltaArray );
+
+ // restore the user coordinate system
+ if (nCurrentTextAngle != 0)
+ {
+ PSGRestore ();
+ mnTextAngle = nCurrentTextAngle;
+ }
+}
+
+void
+PrinterGfx::DrawText (
+ const Point& rPoint,
+ const sal_Unicode* pStr,
+ sal_Int16 nLen,
+ const sal_Int32* pDeltaArray
+ )
+{
+ fontID nRestoreFont = mnFontID;
+
+ // setup font[substitutes] and map the string into the symbol area in case of
+ // symbol font
+ Font3 aFont(*this);
+ sal_Unicode *pEffectiveStr;
+ if ( aFont.IsSymbolFont() )
+ {
+ pEffectiveStr = (sal_Unicode*)alloca(nLen * sizeof(pStr[0]));
+ for (int i = 0; i < nLen; i++)
+ pEffectiveStr[i] = pStr[i] < 256 ? pStr[i] + 0xF000 : pStr[i];
+ }
+ else
+ {
+ pEffectiveStr = const_cast<sal_Unicode*>(pStr);
+ }
+
+ fontID *pFontMap = (fontID*) alloca(nLen * sizeof(fontID));
+ sal_Int32 *pCharWidth = (sal_Int32*) alloca(nLen * sizeof(sal_Int32));
+
+ for( int n = 0; n < nLen; n++ )
+ {
+ CharacterMetric aBBox;
+ pFontMap[n] = getCharMetric (aFont, pEffectiveStr[n], &aBBox);
+ pCharWidth[n] = getCharWidth (mbTextVertical, pEffectiveStr[n], &aBBox);
+ }
+
+ // setup a new delta array, use virtual resolution of 1000
+ sal_Int32* pNewDeltaArray = (sal_Int32*)alloca( sizeof( sal_Int32 )*nLen );
+ if ( pDeltaArray != 0)
+ {
+ for (int i = 0; i < nLen - 1; i++)
+ pNewDeltaArray[i] = 1000 * pDeltaArray[i];
+ pNewDeltaArray[nLen - 1] = 0;
+ }
+ else
+ {
+ pNewDeltaArray[0] = pCharWidth[0];
+ for (int i = 1; i < nLen; i++)
+ pNewDeltaArray[i] = pNewDeltaArray[i-1] + pCharWidth[i];
+ }
+
+ // move and rotate the user coordinate system
+ // avoid the gsave/grestore for the simple cases since it allows
+ // reuse of the current font if it hasn't changed
+ sal_Int32 nCurrentTextAngle = mnTextAngle;
+ sal_Int32 nCurrentPointX;
+ sal_Int32 nCurrentPointY;
+
+ if (nCurrentTextAngle != 0)
+ {
+ PSGSave ();
+ PSTranslate (rPoint);
+ PSRotate (nCurrentTextAngle);
+ mnTextAngle = 0;
+
+ nCurrentPointX = 0;
+ nCurrentPointY = 0;
+ }
+ else
+ {
+ nCurrentPointX = rPoint.X();
+ nCurrentPointY = rPoint.Y();
+ }
+
+ // draw the string
+ sal_Int32 nDelta = 0;
+ for (int nTo = 0; nTo < nLen; )
+ {
+ int nFrom = nTo;
+ fontID nFont = pFontMap[ nFrom ];
+
+ while ((nTo < nLen) && (nFont == pFontMap[nTo]))
+ {
+ pNewDeltaArray[ nTo ] = (sal_Int32)(((0.5 + pNewDeltaArray[ nTo ]) / 1000.0) - nDelta);
+ nTo++ ;
+ }
+
+ SetFont( nFont,
+ maVirtualStatus.mnTextHeight, maVirtualStatus.mnTextWidth,
+ mnTextAngle,
+ mbTextVertical,
+ maVirtualStatus.mbArtItalic,
+ maVirtualStatus.mbArtBold
+ );
+
+ if (mbTextVertical)
+ {
+ drawVerticalizedText(
+ Point(nCurrentPointX + nDelta, nCurrentPointY),
+ pEffectiveStr + nFrom, nTo - nFrom,
+ pNewDeltaArray + nFrom );
+ }
+ else
+ {
+ drawText(
+ Point(nCurrentPointX + nDelta, nCurrentPointY),
+ pEffectiveStr + nFrom, nTo - nFrom,
+ pDeltaArray == NULL ? NULL : pNewDeltaArray + nFrom );
+ }
+ nDelta += pNewDeltaArray[ nTo - 1 ];
+ }
+
+ // restore the user coordinate system
+ if (nCurrentTextAngle != 0)
+ {
+ PSGRestore ();
+ mnTextAngle = nCurrentTextAngle;
+ }
+
+ // restore the original font settings
+ SetFont( nRestoreFont,
+ maVirtualStatus.mnTextHeight, maVirtualStatus.mnTextWidth,
+ mnTextAngle, mbTextVertical,
+ maVirtualStatus.mbArtItalic,
+ maVirtualStatus.mbArtBold
+ );
+}
+
+void PrinterGfx::drawVerticalizedText(
+ const Point& rPoint,
+ const sal_Unicode* pStr,
+ sal_Int16 nLen,
+ const sal_Int32* pDeltaArray
+ )
+{
+ sal_Int32* pDelta = (sal_Int32*)alloca( nLen * sizeof(sal_Int32) );
+
+ int nTextScale = maVirtualStatus.mnTextWidth ? maVirtualStatus.mnTextWidth : maVirtualStatus.mnTextHeight;
+ int nNormalAngle = mnTextAngle;
+ int nDeltaAngle, nLastPos = 0;
+
+ double fSin = sin( -2.0*M_PI*nNormalAngle/3600 );
+ double fCos = cos( -2.0*M_PI*nNormalAngle/3600 );
+
+ PrintFontManager &rMgr = PrintFontManager::get();
+ PrintFontInfo aInfo;
+ rMgr.getFontInfo( mnFontID, aInfo );
+
+ bool* pGsubFlags = (bool*)alloca( nLen * sizeof(bool) );
+ rMgr.hasVerticalSubstitutions( mnFontID, pStr, nLen, pGsubFlags );
+
+ Point aPoint( rPoint );
+ for( int i = 0; i < nLen; )
+ {
+ while( ( nDeltaAngle = getVerticalDeltaAngle( pStr[i] ) ) == 0 && i < nLen )
+ i++;
+ if( i <= nLen && i > nLastPos )
+ {
+ for( int n = nLastPos; n < i; n++ )
+ pDelta[n] = pDeltaArray[n] - (aPoint.X() - rPoint.X() );
+
+ SetFont( mnFontID,
+ maVirtualStatus.mnTextHeight, maVirtualStatus.mnTextWidth,
+ nNormalAngle, mbTextVertical,
+ maVirtualStatus.mbArtItalic,
+ maVirtualStatus.mbArtBold );
+ drawText( aPoint, pStr + nLastPos, i - nLastPos, pDelta + nLastPos );
+
+ aPoint.X() = (sal_Int32)(rPoint.X() + ((double)pDeltaArray[i-1] * fCos));
+ aPoint.Y() = (sal_Int32)(rPoint.Y() + ((double)pDeltaArray[i-1] * fSin));
+ }
+ if( i < nLen )
+ {
+ int nOldWidth = maVirtualStatus.mnTextWidth;
+ int nOldHeight = maVirtualStatus.mnTextHeight;
+ SetFont( mnFontID,
+ nTextScale,
+ maVirtualStatus.mnTextHeight,
+ nNormalAngle + nDeltaAngle,
+ mbTextVertical,
+ maVirtualStatus.mbArtItalic,
+ maVirtualStatus.mbArtBold );
+
+ double nA = nTextScale * aInfo.m_nAscend / 1000.0;
+ double nD = nTextScale * aInfo.m_nDescend / 1000.0;
+ double fStretch = (double)maVirtualStatus.mnTextWidth / maVirtualStatus.mnTextHeight;
+ if( !pGsubFlags[i] )
+ nD *= fStretch;
+
+ Point aPos( aPoint );
+ switch( nDeltaAngle )
+ {
+ case +900:
+ aPos.X() += (sal_Int32)(+nA * fCos + nD * fSin);
+ aPos.Y() += (sal_Int32)(-nA * fSin + nD * fCos);
+ break;
+ case -900:
+ aPos.X() += (sal_Int32)(+nA * fSin + nD * fCos);
+ aPos.Y() += (sal_Int32)(-(nTextScale*fStretch - nD) * fCos);
+ break;
+ }
+ drawText( aPos, pStr+i, 1, NULL );
+ if( i < nLen-1 && pDeltaArray )
+ {
+ aPoint.X() = (sal_Int32)(rPoint.X() + ((double)pDeltaArray[i] * fCos));
+ aPoint.Y() = (sal_Int32)(rPoint.Y() + ((double)pDeltaArray[i] * fSin));
+ }
+
+ // swap text width/height again
+ SetFont( mnFontID,
+ nOldHeight,
+ nOldWidth,
+ nNormalAngle,
+ mbTextVertical,
+ maVirtualStatus.mbArtItalic,
+ maVirtualStatus.mbArtBold );
+ }
+ i++;
+ nLastPos = i;
+ }
+ mnTextAngle = nNormalAngle;
+}
+
+void
+PrinterGfx::LicenseWarning(const Point& rPoint, const sal_Unicode* pStr,
+ sal_Int16 nLen, const sal_Int32* pDeltaArray)
+{
+ // treat it like a builtin font in case a user has that font also in the
+ // printer. This is not so unlikely as it may seem; no print embedding
+ // licensed fonts are often used (or so they say) in companies:
+ // they are installed on displays and printers, but get not embedded in
+ // they are installed on displays and printers, but get not embedded in
+ // print files or documents because they are not licensed for use outside
+ // the company.
+ rtl::OString aMessage( "The font " );
+ aMessage += rtl::OUStringToOString( mrFontMgr.getPSName(mnFontID),
+ RTL_TEXTENCODING_ASCII_US );
+ aMessage += " could not be downloaded\nbecause its license does not allow for that";
+ PSComment( aMessage.getStr() );
+
+ rtl::OString aFontName = rtl::OUStringToOString(
+ mrFontMgr.getPSName(mnFontID),
+ RTL_TEXTENCODING_ASCII_US);
+ PSSetFont (aFontName, RTL_TEXTENCODING_ISO_8859_1);
+
+ sal_Size nSize = 4 * nLen;
+ sal_uChar* pBuffer = (sal_uChar*)alloca (nSize* sizeof(sal_uChar));
+
+ ConverterFactory* pCvt = GetConverterFactory ();
+ nSize = pCvt->Convert (pStr, nLen, pBuffer, nSize, RTL_TEXTENCODING_ISO_8859_1);
+
+ PSMoveTo (rPoint);
+ PSShowText (pBuffer, nLen, nSize, pDeltaArray);
+}
+
+void
+PrinterGfx::drawText(
+ const Point& rPoint,
+ const sal_Unicode* pStr,
+ sal_Int16 nLen,
+ const sal_Int32* pDeltaArray
+ )
+{
+ if (!(nLen > 0))
+ return;
+
+ fonttype::type eType = mrFontMgr.getFontType (mnFontID);
+
+ if (eType == fonttype::Type1)
+ PSUploadPS1Font (mnFontID);
+
+ if ( eType == fonttype::TrueType
+ && !mrFontMgr.isFontDownloadingAllowed(mnFontID))
+ {
+ LicenseWarning(rPoint, pStr, nLen, pDeltaArray);
+ return;
+ }
+
+ if( mrFontMgr.getUseOnlyFontEncoding( mnFontID ) )
+ {
+ GlyphSet aGSet( mnFontID, mbTextVertical );
+ aGSet.DrawText( *this, rPoint, pStr, nLen, pDeltaArray );
+ return;
+ }
+
+ // search for a glyph set matching the set font
+ std::list< GlyphSet >::iterator aIter;
+ for (aIter = maPS3Font.begin(); aIter != maPS3Font.end(); aIter++)
+ if ( ((*aIter).GetFontID() == mnFontID)
+ && ((*aIter).IsVertical() == mbTextVertical))
+ {
+ (*aIter).DrawText (*this, rPoint, pStr, nLen, pDeltaArray);
+ break;
+ }
+
+ // not found ? create a new one
+ if (aIter == maPS3Font.end())
+ {
+ maPS3Font.push_back (GlyphSet(mnFontID, mbTextVertical));
+ maPS3Font.back().DrawText (*this, rPoint, pStr, nLen, pDeltaArray);
+ }
+}
+
+int
+PrinterGfx::getCharWidth (sal_Bool b_vert, sal_Unicode n_char, CharacterMetric *p_bbox)
+{
+ b_vert = b_vert && (getVerticalDeltaAngle(n_char) != 0);
+ int w = b_vert ? p_bbox->height : p_bbox->width;
+ w *= maVirtualStatus.mnTextWidth ? maVirtualStatus.mnTextWidth : maVirtualStatus.mnTextHeight;
+ return w;
+}
+
+fontID
+PrinterGfx::getCharMetric (const Font3 &rFont, sal_Unicode n_char, CharacterMetric *p_bbox)
+{
+ p_bbox->width = -1;
+ p_bbox->height = -1;
+
+ for (fontID n = 0; n < 3; n++)
+ {
+ fontID n_font = rFont.GetFont(n);
+ if (n_font != -1)
+ {
+ if( mbStrictSO52Compatibility )
+ {
+ fonttype::type eType = mrFontMgr.getFontType( n_font );
+ if( (eType == fonttype::Builtin || eType == fonttype::Type1) )
+ {
+ // note: any character exchanged here MUST also be changed
+ // in the compatibility ISO encoding vector in the prolog
+ // in printerjob.cxx
+ sal_Unicode aRepl = 0;
+ if( n_char == 0x2d )
+ aRepl = 0x2212;
+ else if( n_char == 0x27 )
+ aRepl = 0x2019;
+ /*
+ additional characters that may need backwards compatibility:
+ ISO5589 StdEnc Unicode suggested n_char -> aRepl
+ 0264 0302 0x00B4 0x00B4 (acute) -> 0x2019 (quiteright)
+ 0246 - 0x00A6 0x00A6 (brokenbar) -> 0x007C (bar)
+ 0225 0267 0x0095 0x0095 () -> 0x2022 (bullet)
+ 0140 0301 0x0060 0x0060 (grave) -> ?
+ */
+ if( aRepl )
+ {
+ mrFontMgr.getMetrics( n_font, aRepl, aRepl, p_bbox );
+ if (p_bbox->width >= 0 && p_bbox->height >= 0)
+ return n_font;
+ }
+ }
+ }
+ mrFontMgr.getMetrics( n_font, n_char, n_char, p_bbox );
+ }
+ if (p_bbox->width >= 0 && p_bbox->height >= 0)
+ return n_font;
+ }
+ if (n_char != '?')
+ return getCharMetric (rFont, '?', p_bbox);
+
+ return rFont.GetFont(0) != -1 ? rFont.GetFont(0) : rFont.GetFont(1);
+}
+
+fontID
+PrinterGfx::getFontSubstitute () const
+{
+ if( mpFontSubstitutes )
+ {
+ ::std::hash_map< fontID, fontID >::const_iterator it =
+ mpFontSubstitutes->find( mnFontID );
+ if( it != mpFontSubstitutes->end() )
+ return it->second;
+ }
+
+ return -1;
+}
+
+sal_Int32
+PrinterGfx::GetCharWidth (sal_Unicode nFrom, sal_Unicode nTo, long *pWidthArray)
+{
+ Font3 aFont(*this);
+ if (aFont.IsSymbolFont() && (nFrom < 256) && (nTo < 256))
+ {
+ nFrom += 0xF000;
+ nTo += 0xF000;
+ }
+
+ for( int n = 0; n < (nTo - nFrom + 1); n++ )
+ {
+ CharacterMetric aBBox;
+ getCharMetric (aFont, n + nFrom, &aBBox);
+ pWidthArray[n] = getCharWidth (mbTextVertical, n + nFrom, &aBBox);
+ }
+
+ // returned metrics have postscript precision
+ return 1000;
+}
+
+const ::std::list< KernPair >& PrinterGfx::getKernPairs( bool bVertical ) const
+{
+ /*
+ * Note: this is only a 80% solution: if a font is only
+ * partially substituted in a string due to missing glyphs
+ * the results may not be perfect; the more so the more the
+ * substitution differs from the original metricwise. But
+ * vcl only asks for KernPairs for each font once and NOT
+ * in a string context this is the best we can do.
+ * In future the kerning should be done on a per string basis.
+ */
+ fontID nFont = mnFontID;
+ if( mpFontSubstitutes )
+ {
+ ::std::hash_map< fontID, fontID >::const_iterator it =
+ mpFontSubstitutes->find( mnFontID );
+ if( it != mpFontSubstitutes->end() )
+ nFont = it->second;
+ }
+ return mrFontMgr.getKernPairs( nFont, bVertical );
+}
+
+/*
+ * advanced glyph handling
+ */
+
+sal_Bool
+PrinterGfx::GetGlyphBoundRect (sal_Unicode /*c*/, Rectangle& /*rOutRect*/)
+{
+ return 0;
+}
+
+sal_uInt32
+PrinterGfx::GetGlyphOutline (sal_Unicode /*c*/,
+ sal_uInt16 **/*ppPolySizes*/, Point **/*ppPoints*/, sal_uInt8 **/*ppFlags*/)
+{
+ return 0;
+}
+
+/*
+ * spool the converted truetype fonts to the page header after the page body is
+ * complete
+ * for Type1 fonts spool additional reencoding vectors that are necessary to access the
+ * whole font
+ */
+
+void
+PrinterGfx::OnEndPage ()
+{
+}
+
+void
+PrinterGfx::OnEndJob ()
+{
+ maPS3Font.clear();
+ maPS1Font.clear();
+}
+
+void
+PrinterGfx::writeResources( osl::File* pFile, std::list< rtl::OString >& rSuppliedFonts, std::list< rtl::OString >& rNeededFonts )
+{
+ // write all type 1 fonts
+ std::list< sal_Int32 >::iterator aFont;
+ // already in the document header ?
+ for (aFont = maPS1Font.begin(); aFont != maPS1Font.end(); ++aFont)
+ {
+ const rtl::OString& rSysPath (mrFontMgr.getFontFileSysPath(*aFont) );
+ rtl::OUString aUNCPath;
+ osl::File::getFileURLFromSystemPath (OStringToOUString (rSysPath, osl_getThreadTextEncoding()), aUNCPath);
+ osl::File aFontFile (aUNCPath);
+
+ // provide the pfb or pfa font as a (pfa-)font resource
+ rtl::OString aPostScriptName =
+ rtl::OUStringToOString ( mrFontMgr.getPSName(*aFont),
+ RTL_TEXTENCODING_ASCII_US );
+
+ WritePS (pFile, "%%BeginResource: font ");
+ WritePS (pFile, aPostScriptName.getStr());
+ WritePS (pFile, "\n");
+
+ osl::File::RC nError = aFontFile.open (OpenFlag_Read);
+ if (nError == osl::File::E_None)
+ {
+ convertPfbToPfa (aFontFile, *pFile);
+ aFontFile.close ();
+
+ pFile->setPos(osl_Pos_Current, -1);
+ char lastchar = '\n';
+ sal_uInt64 uBytes(1);
+ pFile->read((void *)(&lastchar), uBytes, uBytes);
+ if (lastchar != '\n')
+ WritePS (pFile, "\n");
+ }
+ WritePS (pFile, "%%EndResource\n");
+ rSuppliedFonts.push_back( aPostScriptName );
+ }
+
+ // write glyphsets and reencodings
+ std::list< GlyphSet >::iterator aIter;
+ for (aIter = maPS3Font.begin(); aIter != maPS3Font.end(); ++aIter)
+ {
+ if (aIter->GetFontType() == fonttype::TrueType)
+ {
+ aIter->PSUploadFont (*pFile, *this, mbUploadPS42Fonts ? true : false, rSuppliedFonts );
+ }
+ else
+ // ( aIter->GetFontType() == fonttype::Type1
+ // || aIter->GetFontType() == fonttype::Builtin )
+ {
+ aIter->PSUploadEncoding (pFile, *this);
+ if( aIter->GetFontType() == fonttype::Builtin )
+ rNeededFonts.push_back(
+ rtl::OUStringToOString(
+ mrFontMgr.getPSName( aIter->GetFontID() ),
+ RTL_TEXTENCODING_ASCII_US ) );
+ }
+ }
+}
+
+bool PrinterGfx::getStrictSO52Compatibility() const
+{
+ return mbStrictSO52Compatibility;
+}
+
+void PrinterGfx::setStrictSO52Compatibility( bool bCompat)
+{
+ mbStrictSO52Compatibility = bCompat;
+}
diff --git a/vcl/unx/source/window/FWS.cxx b/vcl/unx/source/window/FWS.cxx
new file mode 100644
index 000000000000..4683864fd116
--- /dev/null
+++ b/vcl/unx/source/window/FWS.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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include "FWS.hxx"
+
+static Atom fwsIconAtom;
+
+static Atom FWS_CLIENT;
+static Atom FWS_COMM_WINDOW;
+static Atom FWS_PROTOCOLS;
+static Atom FWS_STACK_UNDER;
+static Atom FWS_PARK_ICONS;
+static Atom FWS_PASS_ALL_INPUT;
+static Atom FWS_PASSES_INPUT;
+static Atom FWS_HANDLES_FOCUS;
+
+static Atom FWS_REGISTER_WINDOW;
+static Atom FWS_STATE_CHANGE;
+static Atom FWS_UNSEEN_STATE;
+static Atom FWS_NORMAL_STATE;
+static Atom WM_PROTOCOLS;
+static Atom WM_CHANGE_STATE;
+
+static Bool fwsStackUnder;
+static Bool fwsParkIcons;
+static Bool fwsPassesInput;
+static Bool fwsHandlesFocus;
+
+static Window fwsCommWindow;
+
+/*************************************<->***********************************
+ *
+ * WMSupportsFWS() -
+ *
+ * Initialize our atoms and determine if the current window manager is
+ * providing FWS extension support.
+ *
+ *************************************<->***********************************/
+
+Bool
+WMSupportsFWS (Display *display, int screen)
+{
+ unsigned int i;
+ Atom protocol;
+ Atom propType;
+ int propFormat;
+ unsigned long propItems;
+ unsigned long propBytesAfter;
+ unsigned char *propData;
+ char propName[64];
+
+ FWS_CLIENT = XInternAtom(display, "_SUN_FWS_CLIENT", False);
+ FWS_COMM_WINDOW = XInternAtom(display, "_SUN_FWS_COMM_WINDOW", False);
+ FWS_PROTOCOLS = XInternAtom(display, "_SUN_FWS_PROTOCOLS", False);
+ FWS_STACK_UNDER = XInternAtom(display, "_SUN_FWS_STACK_UNDER", False);
+ FWS_PARK_ICONS = XInternAtom(display, "_SUN_FWS_PARK_ICONS", False);
+ FWS_PASS_ALL_INPUT = XInternAtom(display, "_SUN_FWS_PASS_ALL_INPUT", False);
+ FWS_PASSES_INPUT = XInternAtom(display, "_SUN_FWS_PASSES_INPUT", False);
+ FWS_HANDLES_FOCUS = XInternAtom(display, "_SUN_FWS_HANDLES_FOCUS", False);
+ FWS_REGISTER_WINDOW= XInternAtom(display, "_SUN_FWS_REGISTER_WINDOW",False);
+ FWS_STATE_CHANGE = XInternAtom(display, "_SUN_FWS_STATE_CHANGE", False);
+ FWS_UNSEEN_STATE = XInternAtom(display, "_SUN_FWS_UNSEEN_STATE", False);
+ FWS_NORMAL_STATE = XInternAtom(display, "_SUN_FWS_NORMAL_STATE", False);
+ WM_PROTOCOLS = XInternAtom(display, "WM_PROTOCOLS", False);
+ WM_CHANGE_STATE = XInternAtom(display, "WM_CHANGE_STATE", False);
+
+ snprintf (propName, sizeof(propName), "_SUN_FWS_NEXT_ICON_%d", screen);
+ fwsIconAtom = XInternAtom(display, propName, False);
+
+ if (XGetWindowProperty (display, DefaultRootWindow (display),
+ FWS_COMM_WINDOW, 0, 1,
+ False, AnyPropertyType, &propType,
+ &propFormat, &propItems,
+ &propBytesAfter, &propData) != Success)
+ return False;
+
+ if (propFormat != 32 ||
+ propItems != 1 ||
+ propBytesAfter != 0)
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf (stderr, "Bad FWS_COMM_WINDOW property on root window.\n");
+ #endif
+ XFree (propData);
+ return False;
+ }
+
+ fwsCommWindow = *(Window *) propData;
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf (stderr, "Using fwsCommWindow = 0x%lx.\n", fwsCommWindow);
+ #endif
+ XFree (propData);
+
+
+ if (XGetWindowProperty (display, DefaultRootWindow (display),
+ FWS_PROTOCOLS, 0, 10,
+ False, AnyPropertyType, &propType,
+ &propFormat, &propItems,
+ &propBytesAfter, &propData) != Success)
+ {
+ return False;
+ }
+
+ if (propFormat != 32 ||
+ propBytesAfter != 0)
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf (stderr, "Bad FWS_PROTOCOLS property on root window.\n");
+ #endif
+ XFree (propData);
+ return False;
+ }
+
+ for (i = 0; i < propItems; ++i)
+ {
+ protocol = ((Atom *) propData)[i];
+ if (protocol == FWS_STACK_UNDER)
+ {
+ fwsStackUnder = True;
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf (stderr, "Using fwsStackUnder.\n");
+ #endif
+ }
+ else
+ if (protocol == FWS_PARK_ICONS)
+ {
+ fwsParkIcons = True;
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf (stderr, "Using fwsParkIcons.\n");
+ #endif
+ }
+ else
+ if (protocol == FWS_PASSES_INPUT)
+ {
+ fwsPassesInput = True;
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf (stderr, "Using fwsPassesInput.\n");
+ #endif
+ }
+ else
+ if (protocol == FWS_HANDLES_FOCUS)
+ {
+ fwsHandlesFocus = True;
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf (stderr, "Using fwsHandlesFocus.\n");
+ #endif
+ }
+ }
+
+ XFree (propData);
+ return True;
+}
+
+/*************************************<->***********************************
+ *
+ * newHandler() -
+ *
+ * Handle X errors (temporarily) to record the occurance of BadWindow
+ * errors without crashing. Used to detect the FWS_COMM_WINDOW root window
+ * property containing an old or obsolete window id.
+ *
+ *************************************<->***********************************/
+
+extern "C" {
+
+static Bool badWindowFound;
+static int (* oldHandler) (Display *, XErrorEvent *);
+
+static int
+newHandler (Display *display, XErrorEvent *xerror)
+{
+ if (xerror->error_code != BadWindow)
+ (*oldHandler)(display, xerror);
+ else
+ badWindowFound = True;
+
+ return 0;
+}
+
+}
+
+/*************************************<->***********************************
+ *
+ * RegisterFwsWindow() -
+ *
+ * Send a client message to the FWS_COMM_WINDOW indicating the existance
+ * of a new FWS client window. Be careful to avoid BadWindow errors on
+ * the XSendEvent in case the FWS_COMM_WINDOW root window property had
+ * old/obsolete junk in it.
+ *
+ *************************************<->***********************************/
+
+Bool
+RegisterFwsWindow (Display *display, Window window)
+{
+ XClientMessageEvent msg;
+
+ msg.type = ClientMessage;
+ msg.window = fwsCommWindow;
+ msg.message_type = FWS_REGISTER_WINDOW;
+ msg.format = 32;
+ msg.data.l[0] = window;
+
+ XSync (display, False);
+ badWindowFound = False;
+ oldHandler = XSetErrorHandler (newHandler);
+
+ XSendEvent (display, fwsCommWindow, False, NoEventMask,
+ (XEvent *) &msg);
+ XSync (display, False);
+
+ XSetErrorHandler (oldHandler);
+ #if OSL_DEBUG_LEVEL > 1
+ if (badWindowFound)
+ fprintf (stderr, "No FWS client window to register with.\n");
+ #endif
+
+ return !badWindowFound;
+}
+
+/*************************************<->***********************************
+ *
+ * AddFwsProtocols -
+ *
+ * Add the FWS protocol atoms to the WMProtocols property for the window.
+ *
+ *************************************<->***********************************/
+
+void
+AddFwsProtocols (Display *display, Window window)
+{
+ #define MAX_FWS_PROTOS 10
+
+ Atom fwsProtocols[ MAX_FWS_PROTOS ];
+ int nProtos = 0;
+
+ fwsProtocols[ nProtos++ ] = FWS_CLIENT;
+ fwsProtocols[ nProtos++ ] = FWS_STACK_UNDER;
+ fwsProtocols[ nProtos++ ] = FWS_STATE_CHANGE;
+ fwsProtocols[ nProtos++ ] = FWS_PASS_ALL_INPUT;
+ XChangeProperty (display, window, WM_PROTOCOLS,
+ XA_ATOM, 32, PropModeAppend,
+ (unsigned char *) fwsProtocols, nProtos);
+}
+
diff --git a/vcl/unx/source/window/FWS.hxx b/vcl/unx/source/window/FWS.hxx
new file mode 100644
index 000000000000..a687870ede4a
--- /dev/null
+++ b/vcl/unx/source/window/FWS.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _FOREIGN_WINDOW_SYSTEM_HXX
+#define _FOREIGN_WINDOW_SYSTEM_HXX
+
+#include <X11/Xlib.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* Initialize our atoms and determine if the current window manager is
+ * providing FWS extension support.
+ */
+
+Bool
+WMSupportsFWS (Display *display, int screen);
+
+/* Send a client message to the FWS_COMM_WINDOW indicating the existance
+ * of a new FWS client window. Be careful to avoid BadWindow errors on
+ * the XSendEvent in case the FWS_COMM_WINDOW root window property had
+ * old/obsolete junk in it.
+ */
+
+Bool
+RegisterFwsWindow (Display *display, Window window);
+
+/* Add the FWS protocol atoms to the WMProtocols property for the window.
+ */
+
+void
+AddFwsProtocols (Display *display, Window window);
+
+#if defined(__cplusplus)
+} /* extern "C" */
+#endif
+
+#endif // _FOREIGN_WINDOW_SYSTEM_HXX
+
diff --git a/vcl/unx/source/window/makefile.mk b/vcl/unx/source/window/makefile.mk
new file mode 100644
index 000000000000..808b712903f3
--- /dev/null
+++ b/vcl/unx/source/window/makefile.mk
@@ -0,0 +1,59 @@
+#*************************************************************************
+#
+# 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=salwin
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+ENABLE_EXCEPTIONS=TRUE
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)"!="unx"
+
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+
+.ELSE # "$(GUIBASE)"!="unx"
+
+SLOFILES= \
+ $(SLO)/FWS.obj $(SLO)/salframe.obj $(SLO)/salobj.obj $(SLO)/salmenu.obj
+
+.ENDIF # "$(GUIBASE)"!="unx"
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
+.INCLUDE : $(PRJ)$/util$/target.pmk
diff --git a/vcl/unx/source/window/salframe.cxx b/vcl/unx/source/window/salframe.cxx
new file mode 100644
index 000000000000..6d243e41db8c
--- /dev/null
+++ b/vcl/unx/source/window/salframe.cxx
@@ -0,0 +1,4388 @@
+/*************************************************************************
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <tools/prex.h>
+#include <X11/Xatom.h>
+#include <X11/keysym.h>
+#include "FWS.hxx"
+#include <X11/extensions/shape.h>
+#ifndef SOLARIS
+#include <X11/extensions/dpms.h>
+#endif
+#include <tools/postx.h>
+
+#include "salunx.h"
+#include "saldata.hxx"
+#include "saldisp.hxx"
+#include "salgdi.h"
+#include "salframe.h"
+#include "soicon.hxx"
+#include "dtint.hxx"
+#include "sm.hxx"
+#include "wmadaptor.hxx"
+#include "salprn.h"
+#include "salbmp.h"
+#include "i18n_ic.hxx"
+#include "i18n_keysym.hxx"
+#include "i18n_status.hxx"
+
+#include "vcl/salinst.hxx"
+#include "vcl/floatwin.hxx"
+#include "vcl/sallayout.hxx"
+#include "vcl/svapp.hxx"
+#include "vcl/keycodes.hxx"
+#include "vcl/printerinfomanager.hxx"
+#include "vcl/settings.hxx"
+
+#include "tools/debug.hxx"
+
+#include "sal/alloca.h"
+#include <com/sun/star/uno/Exception.hpp>
+
+#include <algorithm>
+
+#ifndef Button6
+# define Button6 6
+#endif
+#ifndef Button7
+# define Button7 7
+#endif
+
+using namespace vcl_sal;
+using namespace vcl;
+
+// -=-= #defines -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#define CLIENT_EVENTS StructureNotifyMask \
+ | SubstructureNotifyMask \
+ | KeyPressMask \
+ | KeyReleaseMask \
+ | ButtonPressMask \
+ | ButtonReleaseMask \
+ | PointerMotionMask \
+ | EnterWindowMask \
+ | LeaveWindowMask \
+ | FocusChangeMask \
+ | ExposureMask \
+ | VisibilityChangeMask \
+ | PropertyChangeMask \
+ | ColormapChangeMask
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+static XLIB_Window hPresentationWindow = None, hPresFocusWindow = None;
+static ::std::list< XLIB_Window > aPresentationReparentList;
+static int nVisibleFloats = 0;
+
+X11SalFrame* X11SalFrame::s_pSaveYourselfFrame = NULL;
+
+// -=-= C++ statics =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+static void doReparentPresentationDialogues( SalDisplay* pDisplay )
+{
+ pDisplay->GetXLib()->PushXErrorLevel( true );
+ while( aPresentationReparentList.begin() != aPresentationReparentList.end() )
+ {
+ int x, y;
+ XLIB_Window aRoot, aChild;
+ unsigned int w, h, bw, d;
+ XGetGeometry( pDisplay->GetDisplay(),
+ aPresentationReparentList.front(),
+ &aRoot,
+ &x, &y, &w, &h, &bw, &d );
+ XTranslateCoordinates( pDisplay->GetDisplay(),
+ hPresentationWindow,
+ aRoot,
+ x, y,
+ &x, &y,
+ &aChild );
+ XReparentWindow( pDisplay->GetDisplay(),
+ aPresentationReparentList.front(),
+ aRoot,
+ x, y );
+ aPresentationReparentList.pop_front();
+ }
+ if( hPresFocusWindow )
+ XSetInputFocus( pDisplay->GetDisplay(), hPresFocusWindow, PointerRoot, CurrentTime );
+ XSync( pDisplay->GetDisplay(), False );
+ pDisplay->GetXLib()->PopXErrorLevel();
+}
+
+// -=-= SalFrame / X11SalFrame =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+bool X11SalFrame::IsOverrideRedirect() const
+{
+ return
+ ((nStyle_ & SAL_FRAME_STYLE_INTRO) && !pDisplay_->getWMAdaptor()->supportsSplash())
+ ||
+ (!( nStyle_ & ~SAL_FRAME_STYLE_DEFAULT ) && !pDisplay_->getWMAdaptor()->supportsFullScreen())
+ ;
+}
+
+bool X11SalFrame::IsFloatGrabWindow() const
+{
+ static const char* pDisableGrab = getenv( "SAL_DISABLE_FLOATGRAB" );
+
+ return
+ ( ( !pDisableGrab || !*pDisableGrab ) &&
+ (
+ (nStyle_ & SAL_FRAME_STYLE_FLOAT) &&
+ ! (nStyle_ & SAL_FRAME_STYLE_TOOLTIP) &&
+ ! (nStyle_ & SAL_FRAME_STYLE_OWNERDRAWDECORATION)
+ )
+ );
+}
+
+void X11SalFrame::setXEmbedInfo()
+{
+ if( m_bXEmbed )
+ {
+ long aInfo[2];
+ aInfo[0] = 1; // XEMBED protocol version
+ aInfo[1] = (bMapped_ ? 1 : 0); // XEMBED_MAPPED
+ XChangeProperty( pDisplay_->GetDisplay(),
+ mhWindow,
+ pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::XEMBED_INFO ),
+ pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::XEMBED_INFO ),
+ 32,
+ PropModeReplace,
+ reinterpret_cast<unsigned char*>(aInfo),
+ sizeof(aInfo)/sizeof(aInfo[0]) );
+ }
+}
+
+void X11SalFrame::askForXEmbedFocus( sal_Int32 i_nTimeCode )
+{
+ XEvent aEvent;
+
+ rtl_zeroMemory( &aEvent, sizeof(aEvent) );
+ aEvent.xclient.window = mhForeignParent;
+ aEvent.xclient.type = ClientMessage;
+ aEvent.xclient.message_type = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::XEMBED );
+ aEvent.xclient.format = 32;
+ aEvent.xclient.data.l[0] = i_nTimeCode ? i_nTimeCode : CurrentTime;
+ aEvent.xclient.data.l[1] = 3; // XEMBED_REQUEST_FOCUS
+ aEvent.xclient.data.l[2] = 0;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = 0;
+
+ GetDisplay()->GetXLib()->PushXErrorLevel( true );
+ XSendEvent( pDisplay_->GetDisplay(),
+ mhForeignParent,
+ False, NoEventMask, &aEvent );
+ XSync( pDisplay_->GetDisplay(), False );
+ GetDisplay()->GetXLib()->PopXErrorLevel();
+}
+
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalFrame::Init( ULONG nSalFrameStyle, int nScreen, SystemParentData* pParentData, bool bUseGeometry )
+{
+ if( nScreen < 0 || nScreen >= GetDisplay()->GetScreenCount() )
+ nScreen = GetDisplay()->GetDefaultScreenNumber();
+ if( mpParent )
+ nScreen = mpParent->m_nScreen;
+
+ m_nScreen = nScreen;
+ nStyle_ = nSalFrameStyle;
+ XWMHints Hints;
+ Hints.flags = InputHint;
+ Hints.input = (nSalFrameStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) ? False : True;
+
+ int x = 0, y = 0;
+ unsigned int w = 500, h = 500;
+ XSetWindowAttributes Attributes;
+
+ int nAttrMask = CWBorderPixel
+ | CWBackPixmap
+ | CWColormap
+ | CWOverrideRedirect
+ | CWEventMask
+ ;
+ Attributes.border_pixel = 0;
+ Attributes.background_pixmap = None;
+ Attributes.colormap = GetDisplay()->GetColormap( m_nScreen ).GetXColormap();
+ Attributes.override_redirect = False;
+ Attributes.event_mask = CLIENT_EVENTS;
+
+ const SalVisual& rVis = GetDisplay()->GetVisual( m_nScreen );
+ XLIB_Window aFrameParent = pParentData ? pParentData->aWindow : GetDisplay()->GetRootWindow( m_nScreen );
+ XLIB_Window aClientLeader = None;
+
+ if( bUseGeometry )
+ {
+ x = maGeometry.nX;
+ y = maGeometry.nY;
+ w = maGeometry.nWidth;
+ h = maGeometry.nHeight;
+ }
+
+ if( (nSalFrameStyle & SAL_FRAME_STYLE_FLOAT) &&
+ ! (nSalFrameStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION)
+ )
+ {
+ if( nShowState_ == SHOWSTATE_UNKNOWN )
+ {
+ w = 10;
+ h = 10;
+ }
+ Attributes.override_redirect = True;
+ }
+ else if( (nSalFrameStyle & SAL_FRAME_STYLE_SYSTEMCHILD ) )
+ {
+ DBG_ASSERT( mpParent, "SAL_FRAME_STYLE_SYSTEMCHILD window without parent" );
+ if( mpParent )
+ {
+ aFrameParent = mpParent->mhWindow;
+ // FIXME: since with SAL_FRAME_STYLE_SYSTEMCHILD
+ // multiple X11SalFrame objects can have the same shell window
+ // dispatching events in saldisp.cxx is unclear (the first frame)
+ // wins. HTH this correctly is unclear yet
+ // for the time being, treat set the shell window to own window
+ // like for a normal frame
+ // mhShellWindow = mpParent->GetShellWindow();
+ }
+ }
+ else if( pParentData )
+ {
+ // plugin parent may be killed unexpectedly by
+ // plugging process; ignore XErrors in that case
+ GetDisplay()->setHaveSystemChildFrame();
+
+ nStyle_ |= SAL_FRAME_STYLE_PLUG;
+ Attributes.override_redirect = True;
+ if( pParentData->nSize >= sizeof(SystemParentData) )
+ m_bXEmbed = pParentData->bXEmbedSupport;
+
+ int x_ret, y_ret;
+ unsigned int bw, d;
+ XLIB_Window aRoot, aParent;
+
+ XGetGeometry( GetXDisplay(), pParentData->aWindow,
+ &aRoot, &x_ret, &y_ret, &w, &h, &bw, &d );
+ mhForeignParent = pParentData->aWindow;
+
+ mhShellWindow = aParent = mhForeignParent;
+ XLIB_Window* pChildren;
+ unsigned int nChildren;
+ bool bBreak = false;
+ do
+ {
+ XQueryTree( GetDisplay()->GetDisplay(), mhShellWindow,
+ &aRoot, &aParent, &pChildren, &nChildren );
+ XFree( pChildren );
+ if( aParent != aRoot )
+ mhShellWindow = aParent;
+ int nCount = 0;
+ Atom* pProps = XListProperties( GetDisplay()->GetDisplay(),
+ mhShellWindow,
+ &nCount );
+ for( int i = 0; i < nCount && ! bBreak; ++i )
+ bBreak = (pProps[i] == XA_WM_HINTS);
+ if( pProps )
+ XFree( pProps );
+ } while( aParent != aRoot && ! bBreak );
+
+ // check if this is really one of our own frames
+ // do not change the input mask in that case
+ const std::list< SalFrame* >& rFrames = GetDisplay()->getFrames();
+ std::list< SalFrame* >::const_iterator it = rFrames.begin();
+ while( it != rFrames.end() && mhForeignParent != static_cast<const X11SalFrame*>(*it)->GetWindow() )
+ ++it;
+
+ if( it == rFrames.end() )
+ {
+ XSelectInput( GetDisplay()->GetDisplay(), mhForeignParent, StructureNotifyMask | FocusChangeMask );
+ XSelectInput( GetDisplay()->GetDisplay(), mhShellWindow, StructureNotifyMask | FocusChangeMask );
+ }
+ }
+ else
+ {
+ if( ! bUseGeometry )
+ {
+ Size aScreenSize( GetDisplay()->getDataForScreen( m_nScreen ).m_aSize );
+ w = aScreenSize.Width();
+ h = aScreenSize.Height();
+ if( nSalFrameStyle & SAL_FRAME_STYLE_SIZEABLE &&
+ nSalFrameStyle & SAL_FRAME_STYLE_MOVEABLE )
+ {
+ // fill in holy default values brought to us by product management
+ if( aScreenSize.Width() >= 800 )
+ w = 785;
+ if( aScreenSize.Width() >= 1024 )
+ w = 920;
+
+ if( aScreenSize.Height() >= 600 )
+ h = 550;
+ if( aScreenSize.Height() >= 768 )
+ h = 630;
+ if( aScreenSize.Height() >= 1024 )
+ h = 875;
+ }
+ if( ! mpParent )
+ {
+ // find the last document window (if any)
+ const X11SalFrame* pFrame = NULL;
+ const std::list< SalFrame* >& rFrames = GetDisplay()->getFrames();
+ std::list< SalFrame* >::const_iterator it = rFrames.begin();
+ while( it != rFrames.end() )
+ {
+ pFrame = static_cast< const X11SalFrame* >(*it);
+ if( ! ( pFrame->mpParent
+ || pFrame->mbFullScreen
+ || ! ( pFrame->nStyle_ & SAL_FRAME_STYLE_SIZEABLE )
+ || ! pFrame->GetUnmirroredGeometry().nWidth
+ || ! pFrame->GetUnmirroredGeometry().nHeight
+ )
+ )
+ break;
+ ++it;
+ }
+
+ if( it != rFrames.end() )
+ {
+ // set a document position and size
+ // the first frame gets positioned by the window manager
+ const SalFrameGeometry& rGeom( pFrame->GetUnmirroredGeometry() );
+ x = rGeom.nX;
+ y = rGeom.nY;
+ if( x+(int)w+40 <= (int)aScreenSize.Width() &&
+ y+(int)h+40 <= (int)aScreenSize.Height()
+ )
+ {
+ y += 40;
+ x += 40;
+ }
+ else
+ {
+ x = 10; // leave some space for decoration
+ y = 20;
+ }
+ }
+ else if( GetDisplay()->IsXinerama() )
+ {
+ // place frame on same screen as mouse pointer
+ XLIB_Window aRoot, aChild;
+ int root_x = 0, root_y = 0, lx, ly;
+ unsigned int mask;
+ XQueryPointer( GetXDisplay(),
+ GetDisplay()->GetRootWindow( m_nScreen ),
+ &aRoot, &aChild,
+ &root_x, &root_y, &lx, &ly, &mask );
+ const std::vector< Rectangle >& rScreens = GetDisplay()->GetXineramaScreens();
+ for( unsigned int i = 0; i < rScreens.size(); i++ )
+ if( rScreens[i].IsInside( Point( root_x, root_y ) ) )
+ {
+ x = rScreens[i].Left();
+ y = rScreens[i].Top();
+ break;
+ }
+ }
+ }
+ }
+ Attributes.win_gravity = pDisplay_->getWMAdaptor()->getInitWinGravity();
+ nAttrMask |= CWWinGravity;
+ if( mpParent )
+ {
+ Attributes.save_under = True;
+ nAttrMask |= CWSaveUnder;
+ }
+ if( IsOverrideRedirect() )
+ Attributes.override_redirect = True;
+ // default icon
+ if( (nStyle_ & SAL_FRAME_STYLE_INTRO) == 0 )
+ {
+ bool bOk=false;
+ try
+ {
+ bOk=SelectAppIconPixmap( pDisplay_, m_nScreen,
+ mnIconID != 1 ? mnIconID :
+ (mpParent ? mpParent->mnIconID : 1), 32,
+ Hints.icon_pixmap, Hints.icon_mask );
+ }
+ catch( com::sun::star::uno::Exception& )
+ {
+ // can happen - no ucb during early startup
+ }
+ if( bOk )
+ {
+ Hints.flags |= IconPixmapHint;
+ if( Hints.icon_mask )
+ Hints.flags |= IconMaskHint;
+ }
+ }
+
+ // find the top level frame of the transience hierarchy
+ X11SalFrame* pFrame = this;
+ while( pFrame->mpParent )
+ pFrame = pFrame->mpParent;
+ if( (pFrame->nStyle_ & SAL_FRAME_STYLE_PLUG ) )
+ {
+ // if the top level window is a plugin window,
+ // then we should place us in the same window group as
+ // the parent application (or none if there is no window group
+ // hint in the parent).
+ if( pFrame->GetShellWindow() )
+ {
+ XWMHints* pWMHints = XGetWMHints( pDisplay_->GetDisplay(),
+ pFrame->GetShellWindow() );
+ if( pWMHints )
+ {
+ if( (pWMHints->flags & WindowGroupHint) )
+ {
+ Hints.flags |= WindowGroupHint;
+ Hints.window_group = pWMHints->window_group;
+ }
+ XFree( pWMHints );
+ }
+ }
+ }
+ else
+ {
+ Hints.flags |= WindowGroupHint;
+ Hints.window_group = pFrame->GetShellWindow();
+ // note: for a normal document window this will produce None
+ // as the window is not yet created and the shell window is
+ // initialized to None. This must be corrected after window creation.
+ aClientLeader = GetDisplay()->GetDrawable( m_nScreen );
+ }
+ }
+
+ nShowState_ = SHOWSTATE_UNKNOWN;
+ bViewable_ = TRUE;
+ bMapped_ = FALSE;
+ nVisibility_ = VisibilityFullyObscured;
+ mhWindow = XCreateWindow( GetXDisplay(),
+ aFrameParent,
+ x, y,
+ w, h,
+ 0,
+ rVis.GetDepth(),
+ InputOutput,
+ rVis.GetVisual(),
+ nAttrMask,
+ &Attributes );
+ // FIXME: see above: fake shell window for now to own window
+ if( /*! IsSysChildWindow() &&*/ pParentData == NULL )
+ {
+ mhShellWindow = mhWindow;
+ }
+
+ // correct window group if necessary
+ if( (Hints.flags & WindowGroupHint) == WindowGroupHint )
+ {
+ if( Hints.window_group == None )
+ Hints.window_group = GetShellWindow();
+ }
+
+ maGeometry.nX = x;
+ maGeometry.nY = y;
+ maGeometry.nWidth = w;
+ maGeometry.nHeight = h;
+ updateScreenNumber();
+
+ XSync( GetXDisplay(), False );
+ setXEmbedInfo();
+
+ XLIB_Time nUserTime = (nStyle_ & (SAL_FRAME_STYLE_OWNERDRAWDECORATION | SAL_FRAME_STYLE_TOOLWINDOW) ) == 0 ?
+ pDisplay_->GetLastUserEventTime() : 0;
+ pDisplay_->getWMAdaptor()->setUserTime( this, nUserTime );
+
+ if( ! pParentData && ! IsChildWindow() && ! Attributes.override_redirect )
+ {
+ XSetWMHints( GetXDisplay(), mhWindow, &Hints );
+ // WM Protocols && internals
+ Atom a[4];
+ int n = 0;
+ a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_DELETE_WINDOW );
+ if( pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_PING ) )
+ a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_PING );
+ if( ! s_pSaveYourselfFrame && ! mpParent)
+ {
+ // at all times have only one frame with SaveYourself
+ a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_SAVE_YOURSELF );
+ s_pSaveYourselfFrame = this;
+ }
+ if( (nSalFrameStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) )
+ a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_TAKE_FOCUS );
+ XSetWMProtocols( GetXDisplay(), GetShellWindow(), a, n );
+
+ XClassHint* pClass = XAllocClassHint();
+ pClass->res_name = const_cast<char*>(X11SalData::getFrameResName());
+ pClass->res_class = const_cast<char*>(X11SalData::getFrameClassName());
+ XSetClassHint( GetXDisplay(), GetShellWindow(), pClass );
+ XFree( pClass );
+
+ XSizeHints* pHints = XAllocSizeHints();
+ pHints->flags = PWinGravity | PPosition;
+ pHints->win_gravity = GetDisplay()->getWMAdaptor()->getPositionWinGravity();
+ pHints->x = 0;
+ pHints->y = 0;
+ if( mbFullScreen )
+ {
+ pHints->flags |= PMaxSize | PMinSize;
+ pHints->max_width = w+100;
+ pHints->max_height = h+100;
+ pHints->min_width = w;
+ pHints->min_height = h;
+ }
+ XSetWMNormalHints( GetXDisplay(),
+ GetShellWindow(),
+ pHints );
+ XFree (pHints);
+
+ // set PID and WM_CLIENT_MACHINE
+ pDisplay_->getWMAdaptor()->setClientMachine( this );
+ pDisplay_->getWMAdaptor()->setPID( this );
+
+ // set client leader
+ if( aClientLeader )
+ {
+ XChangeProperty( GetXDisplay(),
+ mhWindow,
+ pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_CLIENT_LEADER),
+ XA_WINDOW,
+ 32,
+ PropModeReplace,
+ (unsigned char*)&aClientLeader,
+ 1
+ );
+ }
+#define DECOFLAGS (SAL_FRAME_STYLE_MOVEABLE | SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_CLOSEABLE)
+ int nDecoFlags = WMAdaptor::decoration_All;
+ if( (nStyle_ & SAL_FRAME_STYLE_PARTIAL_FULLSCREEN) ||
+ (nStyle_ & SAL_FRAME_STYLE_OWNERDRAWDECORATION)
+ )
+ nDecoFlags = 0;
+ else if( (nStyle_ & DECOFLAGS ) != DECOFLAGS || (nStyle_ & SAL_FRAME_STYLE_TOOLWINDOW) )
+ {
+ if( nStyle_ & DECOFLAGS )
+ // if any decoration, then show a border
+ nDecoFlags = WMAdaptor::decoration_Border;
+ else
+ nDecoFlags = 0;
+
+ if( ! mpParent && (nStyle_ & DECOFLAGS) )
+ // don't add a min button if window should be decorationless
+ nDecoFlags |= WMAdaptor::decoration_MinimizeBtn;
+ if( nStyle_ & SAL_FRAME_STYLE_CLOSEABLE )
+ nDecoFlags |= WMAdaptor::decoration_CloseBtn;
+ if( nStyle_ & SAL_FRAME_STYLE_SIZEABLE )
+ {
+ nDecoFlags |= WMAdaptor::decoration_Resize;
+ if( ! (nStyle_ & SAL_FRAME_STYLE_TOOLWINDOW) )
+ nDecoFlags |= WMAdaptor::decoration_MaximizeBtn;
+ }
+ if( nStyle_ & SAL_FRAME_STYLE_MOVEABLE )
+ nDecoFlags |= WMAdaptor::decoration_Title;
+ }
+
+ WMAdaptor::WMWindowType eType = WMAdaptor::windowType_Normal;
+ if( nStyle_ & SAL_FRAME_STYLE_INTRO )
+ eType = WMAdaptor::windowType_Splash;
+ if( (nStyle_ & SAL_FRAME_STYLE_DIALOG) && hPresentationWindow == None )
+ eType = WMAdaptor::windowType_ModelessDialogue;
+ if( nStyle_ & SAL_FRAME_STYLE_TOOLWINDOW )
+ eType = WMAdaptor::windowType_Utility;
+ if( nStyle_ & SAL_FRAME_STYLE_OWNERDRAWDECORATION )
+ eType = WMAdaptor::windowType_Toolbar;
+ if( (nStyle_ & SAL_FRAME_STYLE_PARTIAL_FULLSCREEN)
+ && GetDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() )
+ eType = WMAdaptor::windowType_Dock;
+
+ GetDisplay()->getWMAdaptor()->
+ setFrameTypeAndDecoration( this,
+ eType,
+ nDecoFlags,
+ hPresentationWindow ? NULL : mpParent );
+
+ if( (nStyle_ & (SAL_FRAME_STYLE_DEFAULT |
+ SAL_FRAME_STYLE_OWNERDRAWDECORATION|
+ SAL_FRAME_STYLE_FLOAT |
+ SAL_FRAME_STYLE_INTRO |
+ SAL_FRAME_STYLE_PARTIAL_FULLSCREEN) )
+ == SAL_FRAME_STYLE_DEFAULT )
+ pDisplay_->getWMAdaptor()->maximizeFrame( this, true, true );
+ }
+
+ m_nWorkArea = GetDisplay()->getWMAdaptor()->getCurrentWorkArea();
+
+ // Pointer
+ SetPointer( POINTER_ARROW );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+X11SalFrame::X11SalFrame( SalFrame *pParent, ULONG nSalFrameStyle, SystemParentData* pSystemParent )
+{
+ X11SalData* pSalData = GetX11SalData();
+
+ // initialize frame geometry
+ memset( &maGeometry, 0, sizeof(maGeometry) );
+
+ mpParent = static_cast< X11SalFrame* >( pParent );
+
+ mbTransientForRoot = false;
+
+ pDisplay_ = pSalData->GetDisplay();
+ // insert frame in framelist
+ pDisplay_->registerFrame( this );
+
+ mhWindow = None;
+ mhShellWindow = None;
+ mhStackingWindow = None;
+ mhForeignParent = None;
+ mhBackgroundPixmap = None;
+
+ pGraphics_ = NULL;
+ pFreeGraphics_ = NULL;
+
+ hCursor_ = None;
+ nCaptured_ = 0;
+
+ nReleaseTime_ = 0;
+ nKeyCode_ = 0;
+ nKeyState_ = 0;
+ nCompose_ = -1;
+ mbKeyMenu = false;
+ mbSendExtKeyModChange = false;
+ mnExtKeyMod = 0;
+
+ nShowState_ = SHOWSTATE_UNKNOWN;
+ nWidth_ = 0;
+ nHeight_ = 0;
+ nStyle_ = 0;
+ mnExtStyle = 0;
+ bAlwaysOnTop_ = FALSE;
+
+ // set bViewable_ to TRUE: hack GetClientSize to report something
+ // different to 0/0 before first map
+ bViewable_ = TRUE;
+ bMapped_ = FALSE;
+ bDefaultPosition_ = TRUE;
+ nVisibility_ = VisibilityFullyObscured;
+ m_nWorkArea = 0;
+ mbInShow = FALSE;
+ m_bXEmbed = false;
+
+ nScreenSaversTimeout_ = 0;
+
+ mpInputContext = NULL;
+ mbInputFocus = False;
+
+ maAlwaysOnTopRaiseTimer.SetTimeoutHdl( LINK( this, X11SalFrame, HandleAlwaysOnTopRaise ) );
+ maAlwaysOnTopRaiseTimer.SetTimeout( 100 );
+
+ meWindowType = WMAdaptor::windowType_Normal;
+ mnDecorationFlags = WMAdaptor::decoration_All;
+ mbMaximizedVert = false;
+ mbMaximizedHorz = false;
+ mbShaded = false;
+ mbFullScreen = false;
+
+ mnIconID = 1; // ICON_DEFAULT
+
+ m_pClipRectangles = NULL;
+ m_nCurClipRect = 0;
+ m_nMaxClipRect = 0;
+
+ if( mpParent )
+ mpParent->maChildren.push_back( this );
+
+ Init( nSalFrameStyle, GetDisplay()->GetDefaultScreenNumber(), pSystemParent );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalFrame::passOnSaveYourSelf()
+{
+ if( this == s_pSaveYourselfFrame )
+ {
+ // pass on SaveYourself
+ const X11SalFrame* pFrame = NULL;
+ const std::list< SalFrame* >& rFrames = GetDisplay()->getFrames();
+ std::list< SalFrame* >::const_iterator it = rFrames.begin();
+ while( it != rFrames.end() )
+ {
+ pFrame = static_cast< const X11SalFrame* >(*it);
+ if( ! ( IsChildWindow() || pFrame->mpParent )
+ && pFrame != s_pSaveYourselfFrame )
+ break;
+ ++it;
+ }
+
+ s_pSaveYourselfFrame = (it != rFrames.end() ) ? const_cast<X11SalFrame*>(pFrame) : NULL;
+ if( s_pSaveYourselfFrame )
+ {
+ Atom a[4];
+ int n = 0;
+ a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_DELETE_WINDOW );
+ a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_SAVE_YOURSELF );
+ if( pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_PING ) )
+ a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_PING );
+ XSetWMProtocols( GetXDisplay(), s_pSaveYourselfFrame->GetShellWindow(), a, n );
+ }
+ }
+}
+
+X11SalFrame::~X11SalFrame()
+{
+ notifyDelete();
+
+ if( m_pClipRectangles )
+ {
+ delete [] m_pClipRectangles;
+ m_pClipRectangles = NULL;
+ m_nCurClipRect = m_nMaxClipRect = 0;
+ }
+
+ if( mhBackgroundPixmap )
+ {
+ XSetWindowBackgroundPixmap( GetXDisplay(), GetWindow(), None );
+ XFreePixmap( GetXDisplay(), mhBackgroundPixmap );
+ }
+
+ if( mhStackingWindow )
+ aPresentationReparentList.remove( mhStackingWindow );
+
+ // remove from parent's list
+ if( mpParent )
+ mpParent->maChildren.remove( this );
+
+ // deregister on SalDisplay
+ pDisplay_->deregisterFrame( this );
+
+ // unselect all events, some may be still in the queue anyway
+ if( ! IsSysChildWindow() )
+ XSelectInput( GetXDisplay(), GetShellWindow(), 0 );
+ XSelectInput( GetXDisplay(), GetWindow(), 0 );
+
+ ShowFullScreen( FALSE, 0 );
+
+ if( bMapped_ )
+ Show( FALSE );
+
+ if( mpInputContext )
+ {
+ mpInputContext->UnsetICFocus( this );
+ mpInputContext->Unmap( this );
+ delete mpInputContext;
+ }
+
+ if( GetWindow() == hPresentationWindow )
+ {
+ hPresentationWindow = None;
+ doReparentPresentationDialogues( GetDisplay() );
+ }
+
+ if( pGraphics_ )
+ {
+ pGraphics_->DeInit();
+ delete pGraphics_;
+ }
+
+ if( pFreeGraphics_ )
+ {
+ pFreeGraphics_->DeInit();
+ delete pFreeGraphics_;
+ }
+
+
+ XDestroyWindow( GetXDisplay(), mhWindow );
+
+ /*
+ * check if there is only the status frame left
+ * if so, free it
+ */
+ if( ! GetDisplay()->getFrames().empty() && I18NStatus::exists() )
+ {
+ SalFrame* pStatusFrame = I18NStatus::get().getStatusFrame();
+ std::list< SalFrame* >::const_iterator sit = GetDisplay()->getFrames().begin();
+ if( pStatusFrame
+ && *sit == pStatusFrame
+ && ++sit == GetDisplay()->getFrames().end() )
+ vcl::I18NStatus::free();
+ }
+
+ passOnSaveYourSelf();
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalFrame::SetExtendedFrameStyle( SalExtStyle nStyle )
+{
+ if( nStyle != mnExtStyle && ! IsChildWindow() )
+ {
+ mnExtStyle = nStyle;
+
+ XClassHint* pClass = XAllocClassHint();
+ rtl::OString aResHint = X11SalData::getFrameResName( mnExtStyle );
+ pClass->res_name = const_cast<char*>(aResHint.getStr());
+ pClass->res_class = const_cast<char*>(X11SalData::getFrameClassName());
+ XSetClassHint( GetXDisplay(), GetShellWindow(), pClass );
+ XFree( pClass );
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalFrame::SetBackgroundBitmap( SalBitmap* pBitmap )
+{
+ if( mhBackgroundPixmap )
+ {
+ XSetWindowBackgroundPixmap( GetXDisplay(), GetWindow(), None );
+ XFreePixmap( GetXDisplay(), mhBackgroundPixmap );
+ mhBackgroundPixmap = None;
+ }
+ if( pBitmap )
+ {
+ X11SalBitmap* pBM = static_cast<X11SalBitmap*>(pBitmap);
+ Size aSize = pBM->GetSize();
+ if( aSize.Width() && aSize.Height() )
+ {
+ mhBackgroundPixmap =
+ XCreatePixmap( GetXDisplay(),
+ GetWindow(),
+ aSize.Width(),
+ aSize.Height(),
+ GetDisplay()->GetVisual( m_nScreen ).GetDepth() );
+ if( mhBackgroundPixmap )
+ {
+ SalTwoRect aTwoRect;
+ aTwoRect.mnSrcX = aTwoRect.mnSrcY = aTwoRect.mnDestX = aTwoRect.mnDestY = 0;
+ aTwoRect.mnSrcWidth = aTwoRect.mnDestWidth = aSize.Width();
+ aTwoRect.mnSrcHeight = aTwoRect.mnDestHeight = aSize.Height();
+ pBM->ImplDraw( mhBackgroundPixmap,
+ m_nScreen,
+ GetDisplay()->GetVisual( m_nScreen ).GetDepth(),
+ aTwoRect, GetDisplay()->GetCopyGC( m_nScreen ) );
+ XSetWindowBackgroundPixmap( GetXDisplay(), GetWindow(), mhBackgroundPixmap );
+ }
+ }
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+const SystemChildData* X11SalFrame::GetSystemData() const
+{
+ X11SalFrame *pFrame = const_cast<X11SalFrame*>(this);
+ pFrame->maSystemChildData.nSize = sizeof( SystemChildData );
+ pFrame->maSystemChildData.pDisplay = GetXDisplay();
+ pFrame->maSystemChildData.aWindow = pFrame->GetWindow();
+ pFrame->maSystemChildData.pSalFrame = pFrame;
+ pFrame->maSystemChildData.pWidget = NULL;
+ pFrame->maSystemChildData.pVisual = GetDisplay()->GetVisual( m_nScreen ).GetVisual();
+ pFrame->maSystemChildData.nScreen = m_nScreen;
+ pFrame->maSystemChildData.nDepth = GetDisplay()->GetVisual( m_nScreen ).GetDepth();
+ pFrame->maSystemChildData.aColormap = GetDisplay()->GetColormap( m_nScreen ).GetXColormap();
+ pFrame->maSystemChildData.pAppContext = NULL;
+ pFrame->maSystemChildData.aShellWindow = pFrame->GetShellWindow();
+ pFrame->maSystemChildData.pShellWidget = NULL;
+ return &maSystemChildData;
+}
+
+SalGraphics *X11SalFrame::GetGraphics()
+{
+ if( pGraphics_ )
+ return NULL;
+
+ if( pFreeGraphics_ )
+ {
+ pGraphics_ = pFreeGraphics_;
+ pFreeGraphics_ = NULL;
+ }
+ else
+ {
+ pGraphics_ = new X11SalGraphics();
+ pGraphics_->Init( this, GetWindow(), m_nScreen );
+ }
+
+ return pGraphics_;
+}
+
+void X11SalFrame::ReleaseGraphics( SalGraphics *pGraphics )
+{
+ DBG_ASSERT( pGraphics == pGraphics_, "SalFrame::ReleaseGraphics pGraphics!=pGraphics_" );
+
+ if( pGraphics != pGraphics_ )
+ return;
+
+ pFreeGraphics_ = pGraphics_;
+ pGraphics_ = NULL;
+}
+
+void X11SalFrame::updateGraphics( bool bClear )
+{
+ Drawable aDrawable = bClear ? None : GetWindow();
+ if( pGraphics_ )
+ pGraphics_->SetDrawable( aDrawable, m_nScreen );
+ if( pFreeGraphics_ )
+ pFreeGraphics_->SetDrawable( aDrawable, m_nScreen );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalFrame::Enable( BOOL /*bEnable*/ )
+{
+ // NYI: enable/disable frame
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalFrame::SetIcon( USHORT nIcon )
+{
+ if ( ! IsChildWindow() )
+ {
+ // 0 == default icon -> #1
+ if ( nIcon == 0 )
+ nIcon = 1;
+
+ mnIconID = nIcon;
+
+ XIconSize *pIconSize = NULL;
+ int nSizes = 0;
+ int iconSize = 32;
+ if ( XGetIconSizes( GetXDisplay(), GetDisplay()->GetRootWindow( m_nScreen ), &pIconSize, &nSizes ) )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf(stderr, "X11SalFrame::SetIcon(): found %d IconSizes:\n", nSizes);
+#endif
+
+ const int ourLargestIconSize = 48;
+ bool bFoundIconSize = false;
+
+ int i;
+ for( i=0; i<nSizes; i++)
+ {
+ // select largest supported icon
+
+ // Note: olwm/olvwm reports a huge max icon size of
+ // 160x160 pixels; always choosing the max as the
+ // preferred icon size is apparently wrong under olvwm
+ // - so we keep the safe default |iconSize| when we see
+ // unreasonable large max icon sizes (> twice of our
+ // largest available icon) reported by XGetIconSizes.
+ if( pIconSize[i].max_width > iconSize
+ && pIconSize[i].max_width <= 2*ourLargestIconSize )
+ {
+ iconSize = pIconSize[i].max_width;
+ bFoundIconSize = true;
+ }
+ iconSize = pIconSize[i].max_width;
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf(stderr, "min: %d, %d\nmax: %d, %d\ninc: %d, %d\n\n",
+ pIconSize[i].min_width, pIconSize[i].min_height,
+ pIconSize[i].max_width, pIconSize[i].max_height,
+ pIconSize[i].width_inc, pIconSize[i].height_inc);
+#endif
+ }
+
+ if ( !bFoundIconSize )
+ {
+ // Unless someone has fixed olwm/olvwm, we have rejected
+ // the max icon size from |XGetIconSizes()|. Provide a
+ // better icon size default value, in case our window manager
+ // is olwm/olvwm.
+ const String& rWM( pDisplay_->getWMAdaptor()->getWindowManagerName() );
+
+ if ( rWM.EqualsAscii( "Olwm" ) )
+ iconSize = 48;
+ }
+
+ XFree( pIconSize );
+ }
+ else
+ {
+ const String& rWM( pDisplay_->getWMAdaptor()->getWindowManagerName() );
+ if( rWM.EqualsAscii( "KWin" ) ) // assume KDE is running
+ iconSize = 48;
+ static bool bGnomeIconSize = false;
+ static bool bGnomeChecked = false;
+ if( ! bGnomeChecked )
+ {
+ bGnomeChecked=true;
+ int nCount = 0;
+ Atom* pProps = XListProperties( GetXDisplay(),
+ GetDisplay()->GetRootWindow( m_nScreen ),
+ &nCount );
+ for( int i = 0; i < nCount && !bGnomeIconSize; i++ )
+ {
+ char* pName = XGetAtomName( GetXDisplay(), pProps[i] );
+ if( !strcmp( pName, "GNOME_PANEL_DESKTOP_AREA" ) )
+ bGnomeIconSize = true;
+ if( pName )
+ XFree( pName );
+ }
+ if( pProps )
+ XFree( pProps );
+ }
+ if( bGnomeIconSize )
+ iconSize = 48;
+ }
+
+ XWMHints Hints;
+ Hints.flags = 0;
+ XWMHints *pHints = XGetWMHints( GetXDisplay(), GetShellWindow() );
+ if( pHints )
+ {
+ memcpy(&Hints, pHints, sizeof( XWMHints ));
+ XFree( pHints );
+ }
+ pHints = &Hints;
+
+ BOOL bOk = SelectAppIconPixmap( GetDisplay(), m_nScreen,
+ nIcon, iconSize,
+ pHints->icon_pixmap, pHints->icon_mask );
+ if ( !bOk )
+ {
+ // load default icon (0)
+ bOk = SelectAppIconPixmap( GetDisplay(), m_nScreen,
+ 0, iconSize,
+ pHints->icon_pixmap, pHints->icon_mask );
+ }
+ if( bOk )
+ {
+ pHints->flags |= IconPixmapHint;
+ if( pHints->icon_mask )
+ pHints->flags |= IconMaskHint;
+
+ XSetWMHints( GetXDisplay(), GetShellWindow(), pHints );
+ }
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalFrame::SetMaxClientSize( long nWidth, long nHeight )
+{
+ if( ! IsChildWindow() )
+ {
+ if( GetShellWindow() && (nStyle_ & (SAL_FRAME_STYLE_FLOAT|SAL_FRAME_STYLE_OWNERDRAWDECORATION) ) != SAL_FRAME_STYLE_FLOAT )
+ {
+ XSizeHints* pHints = XAllocSizeHints();
+ long nSupplied = 0;
+ XGetWMNormalHints( GetXDisplay(),
+ GetShellWindow(),
+ pHints,
+ &nSupplied
+ );
+ pHints->max_width = nWidth;
+ pHints->max_height = nHeight;
+ pHints->flags |= PMaxSize;
+ XSetWMNormalHints( GetXDisplay(),
+ GetShellWindow(),
+ pHints );
+ XFree( pHints );
+ }
+ }
+}
+
+void X11SalFrame::SetMinClientSize( long nWidth, long nHeight )
+{
+ if( ! IsChildWindow() )
+ {
+ if( GetShellWindow() && (nStyle_ & (SAL_FRAME_STYLE_FLOAT|SAL_FRAME_STYLE_OWNERDRAWDECORATION) ) != SAL_FRAME_STYLE_FLOAT )
+ {
+ XSizeHints* pHints = XAllocSizeHints();
+ long nSupplied = 0;
+ XGetWMNormalHints( GetXDisplay(),
+ GetShellWindow(),
+ pHints,
+ &nSupplied
+ );
+ pHints->min_width = nWidth;
+ pHints->min_height = nHeight;
+ pHints->flags |= PMinSize;
+ XSetWMNormalHints( GetXDisplay(),
+ GetShellWindow(),
+ pHints );
+ XFree( pHints );
+ }
+ }
+}
+
+// Show + Pos (x,y,z) + Size (width,height)
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::Show( BOOL bVisible, BOOL bNoActivate )
+{
+ if( ( bVisible && bMapped_ )
+ || ( !bVisible && !bMapped_ ) )
+ return;
+
+ // HACK: this is a workaround for (at least) kwin
+ // even though transient frames should be kept above their parent
+ // this does not necessarily hold true for DOCK type windows
+ // so artificially set ABOVE and remove it again on hide
+ if( mpParent && (mpParent->nStyle_ & SAL_FRAME_STYLE_PARTIAL_FULLSCREEN ) && pDisplay_->getWMAdaptor()->isLegacyPartialFullscreen())
+ pDisplay_->getWMAdaptor()->enableAlwaysOnTop( this, bVisible );
+
+ bMapped_ = bVisible;
+ bViewable_ = bVisible;
+ setXEmbedInfo();
+ if( bVisible )
+ {
+ SessionManagerClient::open(); // will simply return after the first time
+
+ mbInShow = TRUE;
+ if( ! (nStyle_ & SAL_FRAME_STYLE_INTRO) )
+ {
+ // hide all INTRO frames
+ const std::list< SalFrame* >& rFrames = GetDisplay()->getFrames();
+ for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it )
+ {
+ const X11SalFrame* pFrame = static_cast< const X11SalFrame* >(*it);
+ // look for intro bit map; if present, hide it
+ if( pFrame->nStyle_ & SAL_FRAME_STYLE_INTRO )
+ {
+ if( pFrame->bMapped_ )
+ const_cast<X11SalFrame*>(pFrame)->Show( FALSE );
+ }
+ }
+ }
+
+ // update NET_WM_STATE which may have been deleted due to earlier Show(FALSE)
+ if( nShowState_ == SHOWSTATE_HIDDEN )
+ GetDisplay()->getWMAdaptor()->frameIsMapping( this );
+
+ /*
+ * #95097#
+ * Actually this is rather exotic and currently happens only in conjunction
+ * with the basic dialogue editor,
+ * which shows a frame and instantly hides it again. After that the
+ * editor window is shown and the WM takes this as an opportunity
+ * to show our hidden transient frame also. So Show( FALSE ) must
+ * withdraw the frame AND delete the WM_TRANSIENT_FOR property.
+ * In case the frame is shown again, the transient hint must be restored here.
+ */
+ if( ! IsChildWindow()
+ && ! IsOverrideRedirect()
+ && ! IsFloatGrabWindow()
+ && mpParent
+ )
+ {
+ GetDisplay()->getWMAdaptor()->changeReferenceFrame( this, mpParent );
+ }
+
+ // #i45160# switch to desktop where a dialog with parent will appear
+ if( mpParent && mpParent->m_nWorkArea != m_nWorkArea )
+ GetDisplay()->getWMAdaptor()->switchToWorkArea( mpParent->m_nWorkArea );
+
+ if( IsFloatGrabWindow() &&
+ mpParent &&
+ nVisibleFloats == 0 &&
+ ! GetDisplay()->GetCaptureFrame() )
+ {
+ /* #i39420#
+ * outsmart KWin's "focus strictly under mouse" mode
+ * which insists on taking the focus from the document
+ * to the new float. Grab focus to parent frame BEFORE
+ * showing the float (cannot grab it to the float
+ * before show).
+ */
+ XGrabPointer( GetXDisplay(),
+ mpParent->GetWindow(),
+ True,
+ PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
+ GrabModeAsync,
+ GrabModeAsync,
+ None,
+ mpParent ? mpParent->GetCursor() : None,
+ CurrentTime
+ );
+ }
+
+ XLIB_Time nUserTime = 0;
+ if( ! bNoActivate && (nStyle_ & (SAL_FRAME_STYLE_OWNERDRAWDECORATION|SAL_FRAME_STYLE_TOOLWINDOW)) == 0 )
+ {
+ if( GetDisplay()->getWMAdaptor()->getWindowManagerName().EqualsAscii("Metacity") )
+ nUserTime = pDisplay_->GetLastUserEventTime( true );
+ else
+ nUserTime = pDisplay_->GetLastUserEventTime();
+ }
+ GetDisplay()->getWMAdaptor()->setUserTime( this, nUserTime );
+
+ // actually map the window
+ if( m_bXEmbed )
+ askForXEmbedFocus( 0 );
+ else
+ {
+ if( GetWindow() != GetShellWindow() && ! IsSysChildWindow() )
+ {
+ if( IsChildWindow() )
+ XMapWindow( GetXDisplay(), GetShellWindow() );
+ XSelectInput( GetXDisplay(), GetShellWindow(), CLIENT_EVENTS );
+ }
+ if( nStyle_ & SAL_FRAME_STYLE_FLOAT )
+ XMapRaised( GetXDisplay(), GetWindow() );
+ else
+ XMapWindow( GetXDisplay(), GetWindow() );
+ }
+ XSelectInput( GetXDisplay(), GetWindow(), CLIENT_EVENTS );
+
+ if( maGeometry.nWidth > 0
+ && maGeometry.nHeight > 0
+ && ( nWidth_ != (int)maGeometry.nWidth
+ || nHeight_ != (int)maGeometry.nHeight ) )
+ {
+ nWidth_ = maGeometry.nWidth;
+ nHeight_ = maGeometry.nHeight;
+ }
+
+ XSync( GetXDisplay(), False );
+
+ if( IsFloatGrabWindow() )
+ {
+ /*
+ * #95453#
+ * Sawfish and twm can be switched to enter-exit focus behaviour. In this case
+ * we must grab the pointer else the dumb WM will put the focus to the
+ * override-redirect float window. The application window will be deactivated
+ * which causes that the floats are destroyed, so the user can never click on
+ * a menu because it vanishes as soon as he enters it.
+ */
+ nVisibleFloats++;
+ if( nVisibleFloats == 1 && ! GetDisplay()->GetCaptureFrame() )
+ {
+ /* #i39420# now move grab to the new float window */
+ XGrabPointer( GetXDisplay(),
+ GetWindow(),
+ True,
+ PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
+ GrabModeAsync,
+ GrabModeAsync,
+ None,
+ mpParent ? mpParent->GetCursor() : None,
+ CurrentTime
+ );
+ }
+ }
+ CallCallback( SALEVENT_RESIZE, NULL );
+
+ /*
+ * sometimes a message box/dialogue is brought up when a frame is not mapped
+ * the corresponding TRANSIENT_FOR hint is then set to the root window
+ * so that the dialogue shows in all cases. Correct it here if the
+ * frame is shown afterwards.
+ */
+ if( ! IsChildWindow()
+ && ! IsOverrideRedirect()
+ && ! IsFloatGrabWindow()
+ )
+ {
+ for( std::list< X11SalFrame* >::const_iterator it = maChildren.begin();
+ it != maChildren.end(); ++it )
+ {
+ if( (*it)->mbTransientForRoot )
+ GetDisplay()->getWMAdaptor()->changeReferenceFrame( *it, this );
+ }
+ }
+ /*
+ * leave SHOWSTATE_UNKNOWN as this indicates first mapping
+ * and is only reset int HandleSizeEvent
+ */
+ if( nShowState_ != SHOWSTATE_UNKNOWN )
+ nShowState_ = SHOWSTATE_NORMAL;
+
+ /*
+ * #98107# plugged windows don't necessarily get the
+ * focus on show because the parent may already be mapped
+ * and have the focus. So try to set the focus
+ * to the child on Show(TRUE)
+ */
+ if( (nStyle_ & SAL_FRAME_STYLE_PLUG) && ! m_bXEmbed )
+ XSetInputFocus( GetXDisplay(),
+ GetWindow(),
+ RevertToParent,
+ CurrentTime );
+
+ if( mpParent )
+ {
+ // push this frame so it will be in front of its siblings
+ // only necessary for insane transient behaviour of Dtwm/olwm
+ mpParent->maChildren.remove( this );
+ mpParent->maChildren.push_front(this);
+ }
+ }
+ else
+ {
+ if( getInputContext() )
+ getInputContext()->Unmap( this );
+
+ if( ! IsChildWindow() )
+ {
+ /* FIXME: Is deleting the property really necessary ? It hurts
+ * owner drawn windows at least.
+ */
+ if( mpParent && ! (nStyle_ & SAL_FRAME_STYLE_OWNERDRAWDECORATION) )
+ XDeleteProperty( GetXDisplay(), GetShellWindow(), GetDisplay()->getWMAdaptor()->getAtom( WMAdaptor::WM_TRANSIENT_FOR ) );
+ XWithdrawWindow( GetXDisplay(), GetShellWindow(), m_nScreen );
+ }
+ else if( ! m_bXEmbed )
+ XUnmapWindow( GetXDisplay(), GetWindow() );
+
+ nShowState_ = SHOWSTATE_HIDDEN;
+ if( IsFloatGrabWindow() && nVisibleFloats )
+ {
+ nVisibleFloats--;
+ if( nVisibleFloats == 0 && ! GetDisplay()->GetCaptureFrame() )
+ XUngrabPointer( GetXDisplay(),
+ CurrentTime );
+ }
+ // flush here; there may be a very seldom race between
+ // the display connection used for clipboard and our connection
+ Flush();
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::ToTop( USHORT nFlags )
+{
+ if( ( nFlags & SAL_FRAME_TOTOP_RESTOREWHENMIN )
+ && ! ( nStyle_ & SAL_FRAME_STYLE_FLOAT )
+ && nShowState_ != SHOWSTATE_HIDDEN
+ && nShowState_ != SHOWSTATE_UNKNOWN
+ )
+ {
+ GetDisplay()->getWMAdaptor()->frameIsMapping( this );
+ if( GetWindow() != GetShellWindow() && ! IsSysChildWindow() )
+ XMapWindow( GetXDisplay(), GetShellWindow() );
+ XMapWindow( GetXDisplay(), GetWindow() );
+ }
+
+ XLIB_Window aToTopWindow = IsSysChildWindow() ? GetWindow() : GetShellWindow();
+ if( ! (nFlags & SAL_FRAME_TOTOP_GRABFOCUS_ONLY) )
+ {
+ XRaiseWindow( GetXDisplay(), aToTopWindow );
+ if( ! GetDisplay()->getWMAdaptor()->isTransientBehaviourAsExpected() )
+ for( std::list< X11SalFrame* >::const_iterator it = maChildren.begin();
+ it != maChildren.end(); ++it )
+ (*it)->ToTop( nFlags & ~SAL_FRAME_TOTOP_GRABFOCUS );
+ }
+
+ if( ( ( nFlags & SAL_FRAME_TOTOP_GRABFOCUS ) || ( nFlags & SAL_FRAME_TOTOP_GRABFOCUS_ONLY ) )
+ && bMapped_ )
+ {
+ if( m_bXEmbed )
+ askForXEmbedFocus( 0 );
+ else
+ XSetInputFocus( GetXDisplay(), aToTopWindow, RevertToParent, CurrentTime );
+ }
+}
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::GetWorkArea( Rectangle& rWorkArea )
+{
+ rWorkArea = pDisplay_->getWMAdaptor()->getWorkArea( 0 );
+}
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::GetClientSize( long &rWidth, long &rHeight )
+{
+ if( ! bViewable_ )
+ {
+ rWidth = rHeight = 0;
+ return;
+ }
+
+ rWidth = maGeometry.nWidth;
+ rHeight = maGeometry.nHeight;
+
+ if( !rWidth || !rHeight )
+ {
+ XWindowAttributes aAttrib;
+
+ XGetWindowAttributes( GetXDisplay(), GetWindow(), &aAttrib );
+
+ maGeometry.nWidth = rWidth = aAttrib.width;
+ maGeometry.nHeight = rHeight = aAttrib.height;
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalFrame::SetWindowGravity (int nGravity) const
+{
+ if( ! IsChildWindow() )
+ {
+ XSizeHints* pHint = XAllocSizeHints();
+ long nFlag;
+
+ XGetWMNormalHints (GetXDisplay(), GetShellWindow(), pHint, &nFlag);
+ pHint->flags |= PWinGravity;
+ pHint->win_gravity = nGravity;
+
+ XSetWMNormalHints (GetXDisplay(), GetShellWindow(), pHint);
+ XSync (GetXDisplay(), False);
+
+ XFree (pHint);
+ }
+}
+
+void X11SalFrame::Center( )
+{
+ int nX, nY, nScreenWidth, nScreenHeight;
+ int nRealScreenWidth, nRealScreenHeight;
+ int nScreenX = 0, nScreenY = 0;
+
+ const Size& aScreenSize = GetDisplay()->getDataForScreen( m_nScreen ).m_aSize;
+ nScreenWidth = aScreenSize.Width();
+ nScreenHeight = aScreenSize.Height();
+ nRealScreenWidth = nScreenWidth;
+ nRealScreenHeight = nScreenHeight;
+
+ if( GetDisplay()->IsXinerama() )
+ {
+ // get xinerama screen we are on
+ // if there is a parent, use its center for screen determination
+ // else use the pointer
+ XLIB_Window aRoot, aChild;
+ int root_x, root_y, x, y;
+ unsigned int mask;
+ if( mpParent )
+ {
+ root_x = mpParent->maGeometry.nX + mpParent->maGeometry.nWidth/2;
+ root_y = mpParent->maGeometry.nY + mpParent->maGeometry.nHeight/2;
+ }
+ else
+ XQueryPointer( GetXDisplay(),
+ GetShellWindow(),
+ &aRoot, &aChild,
+ &root_x, &root_y,
+ &x, &y,
+ &mask );
+ const std::vector< Rectangle >& rScreens = GetDisplay()->GetXineramaScreens();
+ for( unsigned int i = 0; i < rScreens.size(); i++ )
+ if( rScreens[i].IsInside( Point( root_x, root_y ) ) )
+ {
+ nScreenX = rScreens[i].Left();
+ nScreenY = rScreens[i].Top();
+ nRealScreenWidth = rScreens[i].GetWidth();
+ nRealScreenHeight = rScreens[i].GetHeight();
+ break;
+ }
+ }
+
+ if( mpParent )
+ {
+ X11SalFrame* pFrame = mpParent;
+ while( pFrame->mpParent )
+ pFrame = pFrame->mpParent;
+ if( pFrame->maGeometry.nWidth < 1 || pFrame->maGeometry.nHeight < 1 )
+ {
+ Rectangle aRect;
+ pFrame->GetPosSize( aRect );
+ pFrame->maGeometry.nX = aRect.Left();
+ pFrame->maGeometry.nY = aRect.Top();
+ pFrame->maGeometry.nWidth = aRect.GetWidth();
+ pFrame->maGeometry.nHeight = aRect.GetHeight();
+ }
+
+ if( pFrame->nStyle_ & SAL_FRAME_STYLE_PLUG )
+ {
+ XLIB_Window aRoot;
+ unsigned int bw, depth;
+ XGetGeometry( GetXDisplay(),
+ pFrame->GetShellWindow(),
+ &aRoot,
+ &nScreenX, &nScreenY,
+ (unsigned int*)&nScreenWidth,
+ (unsigned int*)&nScreenHeight,
+ &bw, &depth );
+ }
+ else
+ {
+ nScreenX = pFrame->maGeometry.nX;
+ nScreenY = pFrame->maGeometry.nY;
+ nScreenWidth = pFrame->maGeometry.nWidth;
+ nScreenHeight = pFrame->maGeometry.nHeight;
+ }
+ }
+
+ if( mpParent && mpParent->nShowState_ == SHOWSTATE_NORMAL )
+ {
+ if( maGeometry.nWidth >= mpParent->maGeometry.nWidth &&
+ maGeometry.nHeight >= mpParent->maGeometry.nHeight )
+ {
+ nX = nScreenX + 40;
+ nY = nScreenY + 40;
+ }
+ else
+ {
+ // center the window relative to the top level frame
+ nX = (nScreenWidth - (int)maGeometry.nWidth ) / 2 + nScreenX;
+ nY = (nScreenHeight - (int)maGeometry.nHeight) / 2 + nScreenY;
+ }
+ }
+ else
+ {
+ // center the window relative to screen
+ nX = (nRealScreenWidth - (int)maGeometry.nWidth ) / 2 + nScreenX;
+ nY = (nRealScreenHeight - (int)maGeometry.nHeight) / 2 + nScreenY;
+ }
+ nX = nX < 0 ? 0 : nX;
+ nY = nY < 0 ? 0 : nY;
+
+ bDefaultPosition_ = False;
+ if( mpParent )
+ {
+ nX -= mpParent->maGeometry.nX;
+ nY -= mpParent->maGeometry.nY;
+ }
+
+ Point aPoint(nX, nY);
+ SetPosSize( Rectangle( aPoint, Size( maGeometry.nWidth, maGeometry.nHeight ) ) );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::updateScreenNumber()
+{
+ if( GetDisplay()->IsXinerama() && GetDisplay()->GetXineramaScreens().size() > 1 )
+ {
+ Point aPoint( maGeometry.nX, maGeometry.nY );
+ const std::vector<Rectangle>& rScreenRects( GetDisplay()->GetXineramaScreens() );
+ size_t nScreens = rScreenRects.size();
+ for( size_t i = 0; i < nScreens; i++ )
+ {
+ if( rScreenRects[i].IsInside( aPoint ) )
+ {
+ maGeometry.nScreenNumber = static_cast<unsigned int>(i);
+ break;
+ }
+ }
+ }
+ else
+ maGeometry.nScreenNumber = static_cast<unsigned int>(m_nScreen);
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::SetPosSize( long nX, long nY, long nWidth, long nHeight, USHORT nFlags )
+{
+ if( nStyle_ & SAL_FRAME_STYLE_PLUG )
+ return;
+
+ // relative positioning in X11SalFrame::SetPosSize
+ Rectangle aPosSize( Point( maGeometry.nX, maGeometry.nY ), Size( maGeometry.nWidth, maGeometry.nHeight ) );
+ aPosSize.Justify();
+
+ if( ! ( nFlags & SAL_FRAME_POSSIZE_X ) )
+ {
+ nX = aPosSize.Left();
+ if( mpParent )
+ nX -= mpParent->maGeometry.nX;
+ }
+ if( ! ( nFlags & SAL_FRAME_POSSIZE_Y ) )
+ {
+ nY = aPosSize.Top();
+ if( mpParent )
+ nY -= mpParent->maGeometry.nY;
+ }
+ if( ! ( nFlags & SAL_FRAME_POSSIZE_WIDTH ) )
+ nWidth = aPosSize.GetWidth();
+ if( ! ( nFlags & SAL_FRAME_POSSIZE_HEIGHT ) )
+ nHeight = aPosSize.GetHeight();
+
+ aPosSize = Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) );
+
+ if( ! ( nFlags & ( SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y ) ) )
+ {
+ if( bDefaultPosition_ )
+ {
+ maGeometry.nWidth = aPosSize.GetWidth();
+ maGeometry.nHeight = aPosSize.GetHeight();
+ Center();
+ }
+ else
+ SetSize( Size( nWidth, nHeight ) );
+ }
+ else
+ SetPosSize( aPosSize );
+
+ bDefaultPosition_ = False;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::SetAlwaysOnTop( BOOL bOnTop )
+{
+ if( ! IsOverrideRedirect() )
+ {
+ bAlwaysOnTop_ = bOnTop;
+ pDisplay_->getWMAdaptor()->enableAlwaysOnTop( this, bOnTop );
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+#define _FRAMESTATE_MASK_GEOMETRY \
+ (SAL_FRAMESTATE_MASK_X | SAL_FRAMESTATE_MASK_Y | \
+ SAL_FRAMESTATE_MASK_WIDTH | SAL_FRAMESTATE_MASK_HEIGHT)
+#define _FRAMESTATE_MASK_MAXIMIZED_GEOMETRY \
+ (SAL_FRAMESTATE_MASK_MAXIMIZED_X | SAL_FRAMESTATE_MASK_MAXIMIZED_Y | \
+ SAL_FRAMESTATE_MASK_MAXIMIZED_WIDTH | SAL_FRAMESTATE_MASK_MAXIMIZED_HEIGHT)
+
+void X11SalFrame::SetWindowState( const SalFrameState *pState )
+{
+ if (pState == NULL)
+ return;
+
+ // Request for position or size change
+ if (pState->mnMask & _FRAMESTATE_MASK_GEOMETRY)
+ {
+ Rectangle aPosSize;
+ bool bDoAdjust = false;
+
+ /* #i44325#
+ * if maximized, set restore size and guess maximized size from last time
+ * in state change below maximize window
+ */
+ if( ! IsChildWindow() &&
+ (pState->mnMask & SAL_FRAMESTATE_MASK_STATE) &&
+ (pState->mnState & SAL_FRAMESTATE_MAXIMIZED) &&
+ (pState->mnMask & _FRAMESTATE_MASK_GEOMETRY) == _FRAMESTATE_MASK_GEOMETRY &&
+ (pState->mnMask & _FRAMESTATE_MASK_MAXIMIZED_GEOMETRY) == _FRAMESTATE_MASK_MAXIMIZED_GEOMETRY
+ )
+ {
+ XSizeHints* pHints = XAllocSizeHints();
+ long nSupplied = 0;
+ XGetWMNormalHints( GetXDisplay(),
+ GetShellWindow(),
+ pHints,
+ &nSupplied );
+ pHints->flags |= PPosition | PWinGravity;
+ pHints->x = pState->mnX;
+ pHints->y = pState->mnY;
+ pHints->win_gravity = pDisplay_->getWMAdaptor()->getPositionWinGravity();
+ XSetWMNormalHints( GetXDisplay(),
+ GetShellWindow(),
+ pHints );
+ XFree( pHints );
+
+ XMoveResizeWindow( GetXDisplay(), GetShellWindow(),
+ pState->mnX, pState->mnY,
+ pState->mnWidth, pState->mnHeight );
+ // guess maximized geometry from last time
+ maGeometry.nX = pState->mnMaximizedX;
+ maGeometry.nY = pState->mnMaximizedY;
+ maGeometry.nWidth = pState->mnMaximizedWidth;
+ maGeometry.nHeight = pState->mnMaximizedHeight;
+ updateScreenNumber();
+ }
+ else
+ {
+ // initialize with current geometry
+ if ((pState->mnMask & _FRAMESTATE_MASK_GEOMETRY) != _FRAMESTATE_MASK_GEOMETRY)
+ GetPosSize (aPosSize);
+
+ // change requested properties
+ if (pState->mnMask & SAL_FRAMESTATE_MASK_X)
+ {
+ aPosSize.setX (pState->mnX);
+ }
+ if (pState->mnMask & SAL_FRAMESTATE_MASK_Y)
+ {
+ aPosSize.setY (pState->mnY);
+ }
+ if (pState->mnMask & SAL_FRAMESTATE_MASK_WIDTH)
+ {
+ long nWidth = pState->mnWidth > 0 ? pState->mnWidth - 1 : 0;
+ aPosSize.setWidth (nWidth);
+ bDoAdjust = true;
+ }
+ if (pState->mnMask & SAL_FRAMESTATE_MASK_HEIGHT)
+ {
+ int nHeight = pState->mnHeight > 0 ? pState->mnHeight - 1 : 0;
+ aPosSize.setHeight (nHeight);
+ bDoAdjust = true;
+ }
+
+ const Size& aScreenSize = pDisplay_->getDataForScreen( m_nScreen ).m_aSize;
+ const WMAdaptor *pWM = GetDisplay()->getWMAdaptor();
+
+ if( bDoAdjust && aPosSize.GetWidth() <= aScreenSize.Width()
+ && aPosSize.GetHeight() <= aScreenSize.Height() )
+ {
+ SalFrameGeometry aGeom = maGeometry;
+
+ if( ! (nStyle_ & ( SAL_FRAME_STYLE_FLOAT | SAL_FRAME_STYLE_PLUG ) ) &&
+ mpParent &&
+ aGeom.nLeftDecoration == 0 &&
+ aGeom.nTopDecoration == 0 )
+ {
+ aGeom = mpParent->maGeometry;
+ if( aGeom.nLeftDecoration == 0 &&
+ aGeom.nTopDecoration == 0 )
+ {
+ aGeom.nLeftDecoration = 5;
+ aGeom.nTopDecoration = 20;
+ aGeom.nRightDecoration = 5;
+ aGeom.nBottomDecoration = 5;
+ }
+ }
+
+ // adjust position so that frame fits onto screen
+ if( aPosSize.Right()+(long)aGeom.nRightDecoration > aScreenSize.Width()-1 )
+ aPosSize.Move( (long)aScreenSize.Width() - (long)aPosSize.Right() - (long)aGeom.nRightDecoration, 0 );
+ if( aPosSize.Bottom()+(long)aGeom.nBottomDecoration > aScreenSize.Height()-1 )
+ aPosSize.Move( 0, (long)aScreenSize.Height() - (long)aPosSize.Bottom() - (long)aGeom.nBottomDecoration );
+ if( aPosSize.Left() < (long)aGeom.nLeftDecoration )
+ aPosSize.Move( (long)aGeom.nLeftDecoration - (long)aPosSize.Left(), 0 );
+ if( aPosSize.Top() < (long)aGeom.nTopDecoration )
+ aPosSize.Move( 0, (long)aGeom.nTopDecoration - (long)aPosSize.Top() );
+ }
+
+ // resize with new args
+ if (pWM->supportsICCCMPos())
+ {
+ if( mpParent )
+ aPosSize.Move( -mpParent->maGeometry.nX,
+ -mpParent->maGeometry.nY );
+ SetPosSize( aPosSize );
+ bDefaultPosition_ = False;
+ }
+ else
+ SetPosSize( 0, 0, aPosSize.GetWidth(), aPosSize.GetHeight(), SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT );
+ }
+ }
+
+ // request for status change
+ if (pState->mnMask & SAL_FRAMESTATE_MASK_STATE)
+ {
+ if (pState->mnState & SAL_FRAMESTATE_MAXIMIZED)
+ {
+ nShowState_ = SHOWSTATE_NORMAL;
+ if( ! (pState->mnState & (SAL_FRAMESTATE_MAXIMIZED_HORZ|SAL_FRAMESTATE_MAXIMIZED_VERT) ) )
+ Maximize();
+ else
+ {
+ bool bHorz = (pState->mnState & SAL_FRAMESTATE_MAXIMIZED_HORZ) ? true : false;
+ bool bVert = (pState->mnState & SAL_FRAMESTATE_MAXIMIZED_VERT) ? true : false;
+ GetDisplay()->getWMAdaptor()->maximizeFrame( this, bHorz, bVert );
+ }
+ maRestorePosSize.Left() = pState->mnX;
+ maRestorePosSize.Top() = pState->mnY;
+ maRestorePosSize.Right() = maRestorePosSize.Left() + pState->mnWidth;
+ maRestorePosSize.Right() = maRestorePosSize.Left() + pState->mnHeight;
+ }
+ else if( mbMaximizedHorz || mbMaximizedVert )
+ GetDisplay()->getWMAdaptor()->maximizeFrame( this, false, false );
+
+ if (pState->mnState & SAL_FRAMESTATE_MINIMIZED)
+ {
+ if (nShowState_ == SHOWSTATE_UNKNOWN)
+ nShowState_ = SHOWSTATE_NORMAL;
+ Minimize();
+ }
+ if (pState->mnState & SAL_FRAMESTATE_NORMAL)
+ {
+ if (nShowState_ != SHOWSTATE_NORMAL)
+ Restore();
+ }
+ if (pState->mnState & SAL_FRAMESTATE_ROLLUP)
+ GetDisplay()->getWMAdaptor()->shade( this, true );
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+BOOL X11SalFrame::GetWindowState( SalFrameState* pState )
+{
+ if( SHOWSTATE_MINIMIZED == nShowState_ )
+ pState->mnState = SAL_FRAMESTATE_MINIMIZED;
+ else
+ pState->mnState = SAL_FRAMESTATE_NORMAL;
+
+ Rectangle aPosSize;
+ if( maRestorePosSize.IsEmpty() )
+ GetPosSize( aPosSize );
+ else
+ aPosSize = maRestorePosSize;
+
+ if( mbMaximizedHorz )
+ pState->mnState |= SAL_FRAMESTATE_MAXIMIZED_HORZ;
+ if( mbMaximizedVert )
+ pState->mnState |= SAL_FRAMESTATE_MAXIMIZED_VERT;
+ if( mbShaded )
+ pState->mnState |= SAL_FRAMESTATE_ROLLUP;
+
+ pState->mnX = aPosSize.Left();
+ pState->mnY = aPosSize.Top();
+ pState->mnWidth = aPosSize.GetWidth();
+ pState->mnHeight = aPosSize.GetHeight();
+
+ pState->mnMask = _FRAMESTATE_MASK_GEOMETRY | SAL_FRAMESTATE_MASK_STATE;
+
+
+ if (! maRestorePosSize.IsEmpty() )
+ {
+ GetPosSize( aPosSize );
+ pState->mnState |= SAL_FRAMESTATE_MAXIMIZED;
+ pState->mnMaximizedX = aPosSize.Left();
+ pState->mnMaximizedY = aPosSize.Top();
+ pState->mnMaximizedWidth = aPosSize.GetWidth();
+ pState->mnMaximizedHeight = aPosSize.GetHeight();
+ pState->mnMask |= _FRAMESTATE_MASK_MAXIMIZED_GEOMETRY;
+ }
+
+ return TRUE;
+}
+
+// ----------------------------------------------------------------------------
+// get a screenshot of the current frame including window manager decoration
+SalBitmap* X11SalFrame::SnapShot()
+{
+ Display* pDisplay = GetXDisplay();
+
+ // make sure the frame has been reparented and all paint timer have been
+ // expired
+ do
+ {
+ XSync(pDisplay, False);
+ Application::Reschedule ();
+ }
+ while (XPending(pDisplay));
+ TimeValue aVal;
+ aVal.Seconds = 0;
+ aVal.Nanosec = 50000000;
+ osl_waitThread( &aVal );
+ do
+ {
+ XSync(pDisplay, False);
+ Application::Reschedule ();
+ }
+ while (XPending(pDisplay));
+
+ // get the most outer window, usually the window manager decoration
+ Drawable hWindow = None;
+ if (IsOverrideRedirect())
+ hWindow = GetDrawable();
+ else
+ if (hPresentationWindow != None)
+ hWindow = hPresentationWindow;
+ else
+ hWindow = GetStackingWindow();
+
+ // query the contents of the window
+ if (hWindow != None)
+ {
+ X11SalBitmap *pBmp = new X11SalBitmap;
+ if (pBmp->SnapShot (pDisplay, hWindow))
+ return pBmp;
+ else
+ delete pBmp;
+ }
+
+ return NULL;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+// native menu implementation - currently empty
+void X11SalFrame::DrawMenuBar()
+{
+}
+
+void X11SalFrame::SetMenu( SalMenu* )
+{
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::GetPosSize( Rectangle &rPosSize )
+{
+ if( maGeometry.nWidth < 1 || maGeometry.nHeight < 1 )
+ {
+ const Size& aScreenSize = pDisplay_->getDataForScreen( m_nScreen ).m_aSize;
+ long w = aScreenSize.Width() - maGeometry.nLeftDecoration - maGeometry.nRightDecoration;
+ long h = aScreenSize.Height() - maGeometry.nTopDecoration - maGeometry.nBottomDecoration;
+
+ rPosSize = Rectangle( Point( maGeometry.nX, maGeometry.nY ), Size( w, h ) );
+ }
+ else
+ rPosSize = Rectangle( Point( maGeometry.nX, maGeometry.nY ),
+ Size( maGeometry.nWidth, maGeometry.nHeight ) );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::SetSize( const Size &rSize )
+{
+ if( rSize.Width() > 0 && rSize.Height() > 0 )
+ {
+ if( ! ( nStyle_ & SAL_FRAME_STYLE_SIZEABLE )
+ && ! IsChildWindow()
+ && ( nStyle_ & (SAL_FRAME_STYLE_FLOAT|SAL_FRAME_STYLE_OWNERDRAWDECORATION) ) != SAL_FRAME_STYLE_FLOAT )
+ {
+ XSizeHints* pHints = XAllocSizeHints();
+ long nSupplied = 0;
+ XGetWMNormalHints( GetXDisplay(),
+ GetShellWindow(),
+ pHints,
+ &nSupplied
+ );
+ pHints->min_width = rSize.Width();
+ pHints->min_height = rSize.Height();
+ pHints->max_width = rSize.Width();
+ pHints->max_height = rSize.Height();
+ pHints->flags |= PMinSize | PMaxSize;
+ XSetWMNormalHints( GetXDisplay(),
+ GetShellWindow(),
+ pHints );
+ XFree( pHints );
+ }
+ XResizeWindow( GetXDisplay(), IsSysChildWindow() ? GetWindow() : GetShellWindow(), rSize.Width(), rSize.Height() );
+ if( GetWindow() != GetShellWindow() )
+ {
+ if( (nStyle_ & SAL_FRAME_STYLE_PLUG ) )
+ XMoveResizeWindow( GetXDisplay(), GetWindow(), 0, 0, rSize.Width(), rSize.Height() );
+ else
+ XResizeWindow( GetXDisplay(), GetWindow(), rSize.Width(), rSize.Height() );
+ }
+
+ maGeometry.nWidth = rSize.Width();
+ maGeometry.nHeight = rSize.Height();
+
+ // allow the external status window to reposition
+ if (mbInputFocus && mpInputContext != NULL)
+ mpInputContext->SetICFocus ( this );
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalFrame::SetPosSize( const Rectangle &rPosSize )
+{
+ XWindowChanges values;
+ values.x = rPosSize.Left();
+ values.y = rPosSize.Top();
+ values.width = rPosSize.GetWidth();
+ values.height = rPosSize.GetHeight();
+
+ if( !values.width || !values.height )
+ return;
+
+ if( mpParent && ! IsSysChildWindow() )
+ {
+ // --- RTL --- (mirror window pos)
+ if( Application::GetSettings().GetLayoutRTL() )
+ values.x = mpParent->maGeometry.nWidth-values.width-1-values.x;
+
+ XLIB_Window aChild;
+ // coordinates are relative to parent, so translate to root coordinates
+ XTranslateCoordinates( GetDisplay()->GetDisplay(),
+ mpParent->GetWindow(),
+ GetDisplay()->GetRootWindow( m_nScreen ),
+ values.x, values.y,
+ &values.x, &values.y,
+ & aChild );
+ }
+
+ bool bMoved = false;
+ bool bSized = false;
+ if( values.x != maGeometry.nX || values.y != maGeometry.nY )
+ bMoved = true;
+ if( values.width != (int)maGeometry.nWidth || values.height != (int)maGeometry.nHeight )
+ bSized = true;
+
+ if( ! ( nStyle_ & ( SAL_FRAME_STYLE_PLUG | SAL_FRAME_STYLE_FLOAT ) )
+ && !(pDisplay_->GetProperties() & PROPERTY_SUPPORT_WM_ClientPos) )
+ {
+ values.x -= maGeometry.nLeftDecoration;
+ values.y -= maGeometry.nTopDecoration;
+ }
+
+ // do net set WMNormalHints for ..
+ if(
+ // child windows
+ ! IsChildWindow()
+ // popups (menu, help window, etc.)
+ && (nStyle_ & (SAL_FRAME_STYLE_FLOAT|SAL_FRAME_STYLE_OWNERDRAWDECORATION) ) != SAL_FRAME_STYLE_FLOAT
+ // shown, sizeable windows
+ && ( nShowState_ == SHOWSTATE_UNKNOWN ||
+ nShowState_ == SHOWSTATE_HIDDEN ||
+ ! ( nStyle_ & SAL_FRAME_STYLE_SIZEABLE )
+ )
+ )
+ {
+ XSizeHints* pHints = XAllocSizeHints();
+ long nSupplied = 0;
+ XGetWMNormalHints( GetXDisplay(),
+ GetShellWindow(),
+ pHints,
+ &nSupplied
+ );
+ if( ! ( nStyle_ & SAL_FRAME_STYLE_SIZEABLE ) )
+ {
+ pHints->min_width = rPosSize.GetWidth();
+ pHints->min_height = rPosSize.GetHeight();
+ pHints->max_width = rPosSize.GetWidth();
+ pHints->max_height = rPosSize.GetHeight();
+ pHints->flags |= PMinSize | PMaxSize;
+ }
+ if( nShowState_ == SHOWSTATE_UNKNOWN || nShowState_ == SHOWSTATE_HIDDEN )
+ {
+ pHints->flags |= PPosition | PWinGravity;
+ pHints->x = values.x;
+ pHints->y = values.y;
+ pHints->win_gravity = pDisplay_->getWMAdaptor()->getPositionWinGravity();
+ }
+ if( mbFullScreen )
+ {
+ pHints->max_width = 10000;
+ pHints->max_height = 10000;
+ pHints->flags |= PMaxSize;
+ }
+ XSetWMNormalHints( GetXDisplay(),
+ GetShellWindow(),
+ pHints );
+ XFree( pHints );
+ }
+
+ XMoveResizeWindow( GetXDisplay(), IsSysChildWindow() ? GetWindow() : GetShellWindow(), values.x, values.y, values.width, values.height );
+ if( GetShellWindow() != GetWindow() )
+ {
+ if( (nStyle_ & SAL_FRAME_STYLE_PLUG ) )
+ XMoveResizeWindow( GetXDisplay(), GetWindow(), 0, 0, values.width, values.height );
+ else
+ XMoveResizeWindow( GetXDisplay(), GetWindow(), values.x, values.y, values.width, values.height );
+ }
+
+ maGeometry.nX = values.x;
+ maGeometry.nY = values.y;
+ maGeometry.nWidth = values.width;
+ maGeometry.nHeight = values.height;
+ if( IsSysChildWindow() && mpParent )
+ {
+ // translate back to root coordinates
+ maGeometry.nX += mpParent->maGeometry.nX;
+ maGeometry.nY += mpParent->maGeometry.nY;
+ }
+
+ updateScreenNumber();
+ if( bSized && ! bMoved )
+ CallCallback( SALEVENT_RESIZE, NULL );
+ else if( bMoved && ! bSized )
+ CallCallback( SALEVENT_MOVE, NULL );
+ else
+ CallCallback( SALEVENT_MOVERESIZE, NULL );
+
+ // allow the external status window to reposition
+ if (mbInputFocus && mpInputContext != NULL)
+ mpInputContext->SetICFocus ( this );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::Minimize()
+{
+ if( IsSysChildWindow() )
+ return;
+
+ if( SHOWSTATE_UNKNOWN == nShowState_ || SHOWSTATE_HIDDEN == nShowState_ )
+ {
+ stderr0( "X11SalFrame::Minimize on withdrawn window\n" );
+ return;
+ }
+
+ if( XIconifyWindow( GetXDisplay(),
+ GetShellWindow(),
+ pDisplay_->GetDefaultScreenNumber() ) )
+ nShowState_ = SHOWSTATE_MINIMIZED;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::Maximize()
+{
+ if( IsSysChildWindow() )
+ return;
+
+ if( SHOWSTATE_MINIMIZED == nShowState_ )
+ {
+ GetDisplay()->getWMAdaptor()->frameIsMapping( this );
+ XMapWindow( GetXDisplay(), GetShellWindow() );
+ nShowState_ = SHOWSTATE_NORMAL;
+ }
+
+ pDisplay_->getWMAdaptor()->maximizeFrame( this, true, true );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::Restore()
+{
+ if( IsSysChildWindow() )
+ return;
+
+ if( SHOWSTATE_UNKNOWN == nShowState_ || SHOWSTATE_HIDDEN == nShowState_ )
+ {
+ stderr0( "X11SalFrame::Restore on withdrawn window\n" );
+ return;
+ }
+
+ if( SHOWSTATE_MINIMIZED == nShowState_ )
+ {
+ GetDisplay()->getWMAdaptor()->frameIsMapping( this );
+ XMapWindow( GetXDisplay(), GetShellWindow() );
+ nShowState_ = SHOWSTATE_NORMAL;
+ }
+
+ pDisplay_->getWMAdaptor()->maximizeFrame( this, false, false );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalFrame::SetScreenNumber( unsigned int nNewScreen )
+{
+ if( nNewScreen == maGeometry.nScreenNumber )
+ return;
+
+ if( GetDisplay()->IsXinerama() && GetDisplay()->GetXineramaScreens().size() > 1 )
+ {
+ if( nNewScreen >= GetDisplay()->GetXineramaScreens().size() )
+ return;
+
+ Rectangle aOldScreenRect( GetDisplay()->GetXineramaScreens()[maGeometry.nScreenNumber] );
+ Rectangle aNewScreenRect( GetDisplay()->GetXineramaScreens()[nNewScreen] );
+ bool bVisible = bMapped_;
+ if( bVisible )
+ Show( FALSE );
+ maGeometry.nX = aNewScreenRect.Left() + (maGeometry.nX - aOldScreenRect.Left());
+ maGeometry.nY = aNewScreenRect.Top() + (maGeometry.nY - aOldScreenRect.Top());
+ createNewWindow( None, m_nScreen );
+ if( bVisible )
+ Show( TRUE );
+ maGeometry.nScreenNumber = nNewScreen;
+ }
+ else if( sal_Int32(nNewScreen) < GetDisplay()->GetScreenCount() )
+ {
+ bool bVisible = bMapped_;
+ if( bVisible )
+ Show( FALSE );
+ createNewWindow( None, nNewScreen );
+ if( bVisible )
+ Show( TRUE );
+ maGeometry.nScreenNumber = nNewScreen;
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalFrame::ShowFullScreen( BOOL bFullScreen, sal_Int32 nScreen )
+{
+ if( GetDisplay()->IsXinerama() && GetDisplay()->GetXineramaScreens().size() > 1 )
+ {
+ if( mbFullScreen == (bool)bFullScreen )
+ return;
+ if( bFullScreen )
+ {
+ maRestorePosSize = Rectangle( Point( maGeometry.nX, maGeometry.nY ),
+ Size( maGeometry.nWidth, maGeometry.nHeight ) );
+ Rectangle aRect;
+ if( nScreen < 0 || nScreen >= static_cast<int>(GetDisplay()->GetXineramaScreens().size()) )
+ aRect = Rectangle( Point(0,0), GetDisplay()->GetScreenSize( m_nScreen ) );
+ else
+ aRect = GetDisplay()->GetXineramaScreens()[nScreen];
+ nStyle_ |= SAL_FRAME_STYLE_PARTIAL_FULLSCREEN;
+ bool bVisible = bMapped_;
+ if( bVisible )
+ Show( FALSE );
+ maGeometry.nX = aRect.Left();
+ maGeometry.nY = aRect.Top();
+ maGeometry.nWidth = aRect.GetWidth();
+ maGeometry.nHeight = aRect.GetHeight();
+ mbMaximizedHorz = mbMaximizedVert = false;
+ mbFullScreen = true;
+ createNewWindow( None, m_nScreen );
+ if( GetDisplay()->getWMAdaptor()->isLegacyPartialFullscreen() )
+ GetDisplay()->getWMAdaptor()->enableAlwaysOnTop( this, true );
+ else
+ GetDisplay()->getWMAdaptor()->showFullScreen( this, true );
+ if( bVisible )
+ Show(TRUE);
+
+ }
+ else
+ {
+ mbFullScreen = false;
+ nStyle_ &= ~SAL_FRAME_STYLE_PARTIAL_FULLSCREEN;
+ bool bVisible = bMapped_;
+ Rectangle aRect = maRestorePosSize;
+ maRestorePosSize = Rectangle();
+ if( bVisible )
+ Show( FALSE );
+ createNewWindow( None, m_nScreen );
+ if( !aRect.IsEmpty() )
+ SetPosSize( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(),
+ SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y |
+ SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT );
+ if( bVisible )
+ Show( TRUE );
+ }
+ }
+ else
+ {
+ if( nScreen < 0 || nScreen >= GetDisplay()->GetScreenCount() )
+ nScreen = m_nScreen;
+ if( nScreen != m_nScreen )
+ {
+ bool bVisible = bMapped_;
+ if( mbFullScreen )
+ pDisplay_->getWMAdaptor()->showFullScreen( this, false );
+ if( bVisible )
+ Show( FALSE );
+ createNewWindow( None, nScreen );
+ if( mbFullScreen )
+ pDisplay_->getWMAdaptor()->showFullScreen( this, true );
+ if( bVisible )
+ Show( TRUE );
+ }
+ if( mbFullScreen == (bool)bFullScreen )
+ return;
+
+ pDisplay_->getWMAdaptor()->showFullScreen( this, bFullScreen );
+ if( IsOverrideRedirect()
+ && WMSupportsFWS( GetXDisplay(), GetDisplay()->GetRootWindow( m_nScreen ) ) )
+ {
+ AddFwsProtocols( GetXDisplay(), GetShellWindow() );
+ RegisterFwsWindow( GetXDisplay(), GetShellWindow() );
+ }
+ }
+}
+
+/* ---------------------------------------------------------------------
+ the xautolock pseudo screen saver needs special treatment since it
+ doesn't cooperate with XxxxScreenSaver settings
+ ------------------------------------------------------------------- */
+
+static Bool
+IsRunningXAutoLock( Display *p_display, XLIB_Window a_window )
+{
+ const char *p_atomname = "XAUTOLOCK_SEMAPHORE_PID";
+ Atom a_pidatom;
+
+ // xautolock interns this atom
+ a_pidatom = XInternAtom( p_display, p_atomname, True );
+ if ( a_pidatom == None )
+ return False;
+
+ Atom a_type;
+ int n_format;
+ unsigned long n_items;
+ unsigned long n_bytes_after;
+ pid_t *p_pid;
+ pid_t n_pid;
+ // get pid of running xautolock
+ XGetWindowProperty (p_display, a_window, a_pidatom, 0L, 2L, False,
+ AnyPropertyType, &a_type, &n_format, &n_items, &n_bytes_after,
+ (unsigned char**) &p_pid );
+ n_pid = *p_pid;
+ XFree( p_pid );
+
+ if ( a_type == XA_INTEGER )
+ {
+ // check if xautolock pid points to a running process
+ if ( kill(n_pid, 0) == -1 )
+ return False;
+ else
+ return True;
+ }
+
+ return False;
+}
+
+/* definitions from xautolock.c (pl15) */
+#define XAUTOLOCK_DISABLE 1
+#define XAUTOLOCK_ENABLE 2
+
+static Bool
+MessageToXAutoLock( Display *p_display, int n_message )
+{
+ const char *p_atomname = "XAUTOLOCK_MESSAGE" ;
+ Atom a_messageatom;
+ XLIB_Window a_rootwindow;
+
+ a_rootwindow = RootWindowOfScreen( ScreenOfDisplay(p_display, 0) );
+ if ( ! IsRunningXAutoLock(p_display, a_rootwindow) )
+ {
+ // remove any pending messages
+ a_messageatom = XInternAtom( p_display, p_atomname, True );
+ if ( a_messageatom != None )
+ XDeleteProperty( p_display, a_rootwindow, a_messageatom );
+ return False;
+ }
+
+ a_messageatom = XInternAtom( p_display, p_atomname, False );
+ XChangeProperty (p_display, a_rootwindow, a_messageatom, XA_INTEGER,
+ 8, PropModeReplace, (unsigned char*)&n_message, sizeof(n_message) );
+
+ return True;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::StartPresentation( BOOL bStart )
+{
+ I18NStatus::get().show( !bStart, I18NStatus::presentation );
+ if ( bStart )
+ MessageToXAutoLock( GetXDisplay(), XAUTOLOCK_DISABLE );
+ else
+ MessageToXAutoLock( GetXDisplay(), XAUTOLOCK_ENABLE );
+
+ if( ! bStart && hPresentationWindow != None )
+ doReparentPresentationDialogues( GetDisplay() );
+ hPresentationWindow = (bStart && IsOverrideRedirect() ) ? GetWindow() : None;
+
+
+ // needs static here to save DPMS settings
+ int dummy;
+ static bool DPMSExtensionAvailable =
+#ifndef SOLARIS
+ (DPMSQueryExtension(GetXDisplay(), &dummy, &dummy) != 0);
+ static XLIB_BOOL DPMSEnabled = false;
+#else
+ false;
+ bool DPMSEnabled = false;
+ (void)dummy;
+#define CARD16 unsigned short
+#endif
+ static CARD16 dpms_standby_timeout=0;
+ static CARD16 dpms_suspend_timeout=0;
+ static CARD16 dpms_off_timeout=0;
+
+
+ if( bStart || nScreenSaversTimeout_ || DPMSEnabled)
+ {
+ if( hPresentationWindow )
+ {
+ /* #i10559# workaround for WindowMaker: try to restore
+ * current focus after presentation window is gone
+ */
+ int revert_to = 0;
+ XGetInputFocus( GetXDisplay(), &hPresFocusWindow, &revert_to );
+ }
+ int timeout, interval, prefer_blanking, allow_exposures;
+ XGetScreenSaver( GetXDisplay(),
+ &timeout,
+ &interval,
+ &prefer_blanking,
+ &allow_exposures );
+
+
+ // get the DPMS state right before the start
+ if (DPMSExtensionAvailable)
+ {
+#ifndef SOLARIS
+ CARD16 state; // card16 is defined in Xdm.h
+ DPMSInfo( GetXDisplay(),
+ &state,
+ &DPMSEnabled);
+#endif
+ }
+ if( bStart ) // start show
+ {
+ if ( timeout )
+ {
+ nScreenSaversTimeout_ = timeout;
+ XResetScreenSaver( GetXDisplay() );
+ XSetScreenSaver( GetXDisplay(),
+ 0,
+ interval,
+ prefer_blanking,
+ allow_exposures );
+ }
+#ifndef SOLARIS
+ if( DPMSEnabled )
+ {
+ if ( DPMSExtensionAvailable )
+ {
+ DPMSGetTimeouts( GetXDisplay(),
+ &dpms_standby_timeout,
+ &dpms_suspend_timeout,
+ &dpms_off_timeout);
+ DPMSSetTimeouts(GetXDisplay(), 0,0,0);
+ }
+ }
+#endif
+ }
+ else // if( !bStart ) // end of show
+ {
+ if( nScreenSaversTimeout_ )
+ {
+ XSetScreenSaver( GetXDisplay(),
+ nScreenSaversTimeout_,
+ interval,
+ prefer_blanking,
+ allow_exposures );
+ nScreenSaversTimeout_ = 0;
+ }
+#ifndef SOLARIS
+ if ( DPMSEnabled )
+ {
+ if ( DPMSExtensionAvailable )
+ {
+ // restore timeouts
+ DPMSSetTimeouts(GetXDisplay(), dpms_standby_timeout,
+ dpms_suspend_timeout, dpms_off_timeout);
+ }
+ }
+#endif
+ }
+ }
+}
+
+// Pointer
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::SetPointer( PointerStyle ePointerStyle )
+{
+ hCursor_ = pDisplay_->GetPointer( ePointerStyle );
+ XDefineCursor( GetXDisplay(), GetWindow(), hCursor_ );
+
+ if( IsCaptured() || nVisibleFloats > 0 )
+ XChangeActivePointerGrab( GetXDisplay(),
+ PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
+ hCursor_,
+ CurrentTime );
+}
+
+void X11SalFrame::SetPointerPos(long nX, long nY)
+{
+ /* #87921# when the application tries to center the mouse in the dialog the
+ * window isn't mapped already. So use coordinates relative to the root window.
+ */
+ unsigned int nWindowLeft = maGeometry.nX + nX;
+ unsigned int nWindowTop = maGeometry.nY + nY;
+
+ XWarpPointer( GetXDisplay(), None, pDisplay_->GetRootWindow( pDisplay_->GetDefaultScreenNumber() ),
+ 0, 0, 0, 0, nWindowLeft, nWindowTop);
+}
+
+// delay handling of extended text input
+#if !defined(__synchronous_extinput__)
+void
+X11SalFrame::PostExtTextEvent (sal_uInt16 nExtTextEventType, void *pExtTextEvent)
+{
+ XLIB_Window nFocusWindow = GetWindow();
+ Atom nEventAtom = GetDisplay()->getWMAdaptor()->getAtom( WMAdaptor::SAL_EXTTEXTEVENT );
+
+ XEvent aEvent;
+ aEvent.xclient.type = ClientMessage;
+ aEvent.xclient.serial = 0;
+ aEvent.xclient.send_event = True;
+ aEvent.xclient.display = GetXDisplay();
+ aEvent.xclient.window = nFocusWindow;
+ aEvent.xclient.message_type = nEventAtom;
+ aEvent.xclient.format = 32;
+
+#if SAL_TYPES_SIZEOFLONG > 4
+ aEvent.xclient.data.l[0] = (sal_uInt32)((long)pExtTextEvent & 0xffffffff);
+ aEvent.xclient.data.l[1] = (sal_uInt32)((long)pExtTextEvent >> 32);
+#else
+ aEvent.xclient.data.l[0] = (sal_uInt32)((long)pExtTextEvent);
+ aEvent.xclient.data.l[1] = 0;
+#endif
+ aEvent.xclient.data.l[2] = (sal_uInt32)nExtTextEventType;
+ aEvent.xclient.data.l[3] = 0;
+ aEvent.xclient.data.l[4] = 0;
+
+ XPutBackEvent( GetXDisplay(), &aEvent );
+}
+
+void
+X11SalFrame::HandleExtTextEvent (XClientMessageEvent *pEvent)
+{
+ #if SAL_TYPES_SIZEOFLONG > 4
+ void* pExtTextEvent = (void*)( (pEvent->data.l[0] & 0xffffffff)
+ | (pEvent->data.l[1] << 32) );
+ #else
+ void* pExtTextEvent = (void*)(pEvent->data.l[0]);
+ #endif
+ sal_uInt16 nExtTextEventType = sal_uInt16(pEvent->data.l[2]);
+
+ CallCallback(nExtTextEventType, pExtTextEvent);
+
+ switch (nExtTextEventType)
+ {
+ case SALEVENT_ENDEXTTEXTINPUT:
+ break;
+
+ case SALEVENT_EXTTEXTINPUT:
+ break;
+
+ default:
+
+ fprintf(stderr, "X11SalFrame::HandleExtTextEvent: invalid extended input\n");
+ }
+}
+#endif /* defined(__synchronous_extinput__) */
+
+// PostEvent
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+BOOL X11SalFrame::PostEvent( void *pData )
+{
+ GetDisplay()->SendInternalEvent( this, pData );
+ return TRUE;
+}
+
+// Title
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::SetTitle( const XubString& rTitle )
+{
+ if( ! ( IsChildWindow() || (nStyle_ & SAL_FRAME_STYLE_FLOAT ) ) )
+ {
+ m_aTitle = rTitle;
+ GetDisplay()->getWMAdaptor()->setWMName( this, rTitle );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalFrame::Flush()
+{
+ XFlush( GetDisplay()->GetDisplay() );
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalFrame::Sync()
+{
+ XSync( GetDisplay()->GetDisplay(), False );
+}
+
+// Keyboard
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+// -----------------------------------------------------------------------
+
+void X11SalFrame::SetInputContext( SalInputContext* pContext )
+{
+ if (pContext == NULL)
+ return;
+
+ // 1. We should create an input context for this frame
+ // only when SAL_INPUTCONTEXT_TEXT is set.
+
+ if (!(pContext->mnOptions & SAL_INPUTCONTEXT_TEXT))
+ {
+ if( mpInputContext )
+ mpInputContext->Unmap( this );
+ return;
+ }
+
+ // 2. We should use on-the-spot inputstyle
+ // only when SAL_INPUTCONTEXT_EXTTEXTINPUT is set.
+
+ if (mpInputContext == NULL)
+ {
+ I18NStatus& rStatus( I18NStatus::get() );
+ rStatus.setParent( this );
+ mpInputContext = new SalI18N_InputContext( this );
+ if (mpInputContext->UseContext())
+ {
+ mpInputContext->ExtendEventMask( GetShellWindow() );
+ if (pContext->mnOptions & SAL_INPUTCONTEXT_CHANGELANGUAGE)
+ mpInputContext->SetLanguage(pContext->meLanguage);
+ if (mbInputFocus)
+ mpInputContext->SetICFocus( this );
+ }
+ }
+ else
+ mpInputContext->Map( this );
+ return;
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalFrame::EndExtTextInput( USHORT nFlags )
+{
+ if (mpInputContext != NULL)
+ mpInputContext->EndExtTextInput( nFlags );
+}
+
+// -----------------------------------------------------------------------
+
+XubString X11SalFrame::GetKeyName( USHORT nKeyCode )
+{
+ return GetDisplay()->GetKeyName( nKeyCode );
+}
+
+XubString X11SalFrame::GetSymbolKeyName( const XubString&, USHORT nKeyCode )
+{
+ return GetKeyName( nKeyCode );
+}
+
+BOOL X11SalFrame::MapUnicodeToKeyCode( sal_Unicode , LanguageType , KeyCode& )
+{
+ // not supported yet
+ return FALSE;
+}
+
+LanguageType X11SalFrame::GetInputLanguage()
+{
+ // could be improved by checking unicode ranges of the last input
+ return LANGUAGE_DONTKNOW;
+}
+
+// Settings
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+inline Color getColorFromLong( long nColor )
+{
+ return Color( (nColor & 0xff), (nColor & 0xff00)>>8, (nColor & 0xff0000)>>16);
+}
+
+void X11SalFrame::UpdateSettings( AllSettings& rSettings )
+{
+
+ DtIntegrator* pIntegrator = GetDisplay()->getDtIntegrator();
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "DtIntegrator: %d\n", pIntegrator ? pIntegrator->GetDtType() : -1 );
+#endif
+ if( pIntegrator )
+ pIntegrator->GetSystemLook( rSettings );
+}
+
+void X11SalFrame::CaptureMouse( BOOL bCapture )
+{
+ nCaptured_ = pDisplay_->CaptureMouse( bCapture ? this : NULL );
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+void X11SalFrame::SetParent( SalFrame* pNewParent )
+{
+ if( mpParent != pNewParent )
+ {
+ if( mpParent )
+ mpParent->maChildren.remove( this );
+
+ mpParent = static_cast<X11SalFrame*>(pNewParent);
+ mpParent->maChildren.push_back( this );
+ if( mpParent->m_nScreen != m_nScreen )
+ createNewWindow( None, mpParent->m_nScreen );
+ GetDisplay()->getWMAdaptor()->changeReferenceFrame( this, mpParent );
+ }
+}
+
+SalFrame* X11SalFrame::GetParent() const
+{
+ return mpParent;
+}
+
+void X11SalFrame::createNewWindow( XLIB_Window aNewParent, int nScreen )
+{
+ bool bWasVisible = bMapped_;
+ if( bWasVisible )
+ Show( FALSE );
+
+ if( nScreen < 0 || nScreen >= GetDisplay()->GetScreenCount() )
+ nScreen = m_nScreen;
+
+ SystemParentData aParentData;
+ aParentData.aWindow = aNewParent;
+ aParentData.bXEmbedSupport = (aNewParent != None && m_bXEmbed); // caution: this is guesswork
+ if( aNewParent == None )
+ {
+ aNewParent = GetDisplay()->GetRootWindow(nScreen);
+ aParentData.aWindow = None;
+ m_bXEmbed = false;
+ }
+ else
+ {
+ // is new parent a root window ?
+ Display* pDisp = GetDisplay()->GetDisplay();
+ int nScreens = GetDisplay()->GetScreenCount();
+ for( int i = 0; i < nScreens; i++ )
+ {
+ if( aNewParent == RootWindow( pDisp, i ) )
+ {
+ nScreen = i;
+ aParentData.aWindow = None;
+ m_bXEmbed = false;
+ break;
+ }
+ }
+ }
+
+ // first deinit frame
+ updateGraphics(true);
+ if( mpInputContext )
+ {
+ mpInputContext->UnsetICFocus( this );
+ mpInputContext->Unmap( this );
+ }
+ if( GetWindow() == hPresentationWindow )
+ {
+ hPresentationWindow = None;
+ doReparentPresentationDialogues( GetDisplay() );
+ }
+ XDestroyWindow( GetXDisplay(), mhWindow );
+ mhWindow = None;
+
+ passOnSaveYourSelf();
+
+ // now init with new parent again
+ if ( aParentData.aWindow != None )
+ Init( nStyle_ | SAL_FRAME_STYLE_PLUG, nScreen, &aParentData );
+ else
+ Init( nStyle_ & ~SAL_FRAME_STYLE_PLUG, nScreen, NULL, true );
+
+ // update graphics if necessary
+ updateGraphics(false);
+
+ if( m_aTitle.Len() )
+ SetTitle( m_aTitle );
+
+ if( mpParent )
+ {
+ if( mpParent->m_nScreen != m_nScreen )
+ SetParent( NULL );
+ else
+ pDisplay_->getWMAdaptor()->changeReferenceFrame( this, mpParent );
+ }
+
+ if( bWasVisible )
+ Show( TRUE );
+
+ std::list< X11SalFrame* > aChildren = maChildren;
+ for( std::list< X11SalFrame* >::iterator it = aChildren.begin(); it != aChildren.end(); ++it )
+ (*it)->createNewWindow( None, m_nScreen );
+
+ // FIXME: SalObjects
+}
+
+bool X11SalFrame::SetPluginParent( SystemParentData* pNewParent )
+{
+ if( pNewParent->nSize >= sizeof(SystemParentData) )
+ m_bXEmbed = pNewParent->aWindow != None && pNewParent->bXEmbedSupport;
+ createNewWindow( pNewParent ? pNewParent->aWindow : None );
+
+ return true;
+}
+
+// Sound
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+void X11SalFrame::Beep( SoundType eSoundType ) // not fully suported
+{
+ switch( eSoundType )
+ {
+ case SOUND_DEFAULT:
+ case SOUND_ERROR:
+ GetDisplay()->Beep();
+ break;
+ default:
+ // Excessive beeping averted
+ break;
+ }
+}
+
+// Event Handling
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+static USHORT sal_GetCode( int state )
+{
+ USHORT nCode = 0;
+
+ if( state & Button1Mask )
+ nCode |= MOUSE_LEFT;
+ if( state & Button2Mask )
+ nCode |= MOUSE_MIDDLE;
+ if( state & Button3Mask )
+ nCode |= MOUSE_RIGHT;
+
+ if( state & ShiftMask )
+ nCode |= KEY_SHIFT;
+ if( state & ControlMask )
+ nCode |= KEY_MOD1;
+ if( state & Mod1Mask )
+ nCode |= KEY_MOD2;
+
+ // Map Meta/Super modifier to MOD3 on all Unix systems
+ // except Mac OS X
+ if( (state & Mod3Mask) )
+ nCode |= KEY_MOD3;
+
+ return nCode;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+SalFrame::SalPointerState X11SalFrame::GetPointerState()
+{
+ SalPointerState aState;
+ XLIB_Window aRoot, aChild;
+ int rx, ry, wx, wy;
+ unsigned int nMask = 0;
+ XQueryPointer( GetXDisplay(),
+ GetShellWindow(),
+ &aRoot,
+ &aChild,
+ &rx, &ry,
+ &wx, &wy,
+ &nMask
+ );
+
+ aState.maPos = Point(wx, wy);
+ aState.mnState = sal_GetCode( nMask );
+ return aState;
+}
+
+long X11SalFrame::HandleMouseEvent( XEvent *pEvent )
+{
+ SalMouseEvent aMouseEvt;
+ USHORT nEvent = 0;
+ bool bClosePopups = false;
+
+ if( nVisibleFloats && pEvent->type == EnterNotify )
+ return 0;
+
+ // Solaris X86: clicking the right button on a two-button mouse
+ // generates a button2 event not a button3 event
+ if (pDisplay_->GetProperties() & PROPERTY_SUPPORT_3ButtonMouse )
+ {
+ switch (pEvent->type)
+ {
+ case EnterNotify:
+ case LeaveNotify:
+ if ( pEvent->xcrossing.state & Button2Mask )
+ {
+ pEvent->xcrossing.state &= ~Button2Mask;
+ pEvent->xcrossing.state |= Button3Mask;
+ }
+ break;
+
+ case MotionNotify:
+ if ( pEvent->xmotion.state & Button2Mask )
+ {
+ pEvent->xmotion.state &= ~Button2Mask;
+ pEvent->xmotion.state |= Button3Mask;
+ }
+ break;
+
+ default:
+ if ( Button2 == pEvent->xbutton.button )
+ {
+ pEvent->xbutton.state &= ~Button2Mask;
+ pEvent->xbutton.state |= Button3Mask;
+ pEvent->xbutton.button = Button3;
+ }
+ break;
+ }
+ }
+
+
+ if( LeaveNotify == pEvent->type || EnterNotify == pEvent->type )
+ {
+ /*
+ * #89075# #89335#
+ *
+ * some WMs (and/or) applications have a passive grab on
+ * mouse buttons (XGrabButton). This leads to enter/leave notifies
+ * with mouse buttons pressed in the state mask before the actual
+ * ButtonPress event gets dispatched. But EnterNotify
+ * is reported in vcl as MouseMove event. Some office code
+ * decides that a pressed button in a MouseMove belongs to
+ * a drag operation which leads to doing things differently.
+ *
+ * #95901#
+ * ignore Enter/LeaveNotify resulting from grabs so that
+ * help windows do not disappear just after appearing
+ *
+ * hopefully this workaround will not break anything.
+ */
+ if( pEvent->xcrossing.mode == NotifyGrab || pEvent->xcrossing.mode == NotifyUngrab )
+ return 0;
+
+ aMouseEvt.mnX = pEvent->xcrossing.x;
+ aMouseEvt.mnY = pEvent->xcrossing.y;
+ aMouseEvt.mnTime = pEvent->xcrossing.time;
+ aMouseEvt.mnCode = sal_GetCode( pEvent->xcrossing.state );
+ aMouseEvt.mnButton = 0;
+
+ nEvent = LeaveNotify == pEvent->type
+ ? SALEVENT_MOUSELEAVE
+ : SALEVENT_MOUSEMOVE;
+ }
+ else if( pEvent->type == MotionNotify )
+ {
+ aMouseEvt.mnX = pEvent->xmotion.x;
+ aMouseEvt.mnY = pEvent->xmotion.y;
+ aMouseEvt.mnTime = pEvent->xmotion.time;
+ aMouseEvt.mnCode = sal_GetCode( pEvent->xmotion.state );
+
+ aMouseEvt.mnButton = 0;
+
+ nEvent = SALEVENT_MOUSEMOVE;
+ if( nVisibleFloats > 0 && mpParent )
+ {
+ XLIB_Cursor aCursor = mpParent->GetCursor();
+ if( pEvent->xmotion.x >= 0 && pEvent->xmotion.x < (int)maGeometry.nWidth &&
+ pEvent->xmotion.y >= 0 && pEvent->xmotion.y < (int)maGeometry.nHeight )
+ aCursor = None;
+
+ XChangeActivePointerGrab( GetXDisplay(),
+ PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
+ aCursor,
+ CurrentTime );
+ }
+ }
+ else
+ {
+ // let mouse events reach the correct window
+ if( nVisibleFloats < 1 )
+ {
+ if( ! (nStyle_ & SAL_FRAME_STYLE_OWNERDRAWDECORATION) )
+ XUngrabPointer( GetXDisplay(), CurrentTime );
+ }
+ else if( pEvent->type == ButtonPress )
+ {
+ // see if the user clicks outside all of the floats
+ // if yes release the grab
+ bool bInside = false;
+ const std::list< SalFrame* >& rFrames = GetDisplay()->getFrames();
+ for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it )
+ {
+ const X11SalFrame* pFrame = static_cast< const X11SalFrame* >(*it);
+ if( pFrame->IsFloatGrabWindow() &&
+ pFrame->bMapped_ &&
+ pEvent->xbutton.x_root >= pFrame->maGeometry.nX &&
+ pEvent->xbutton.x_root < pFrame->maGeometry.nX + (int)pFrame->maGeometry.nWidth &&
+ pEvent->xbutton.y_root >= pFrame->maGeometry.nY &&
+ pEvent->xbutton.y_root < pFrame->maGeometry.nY + (int)pFrame->maGeometry.nHeight )
+ {
+ bInside = true;
+ break;
+ }
+ }
+ if( ! bInside )
+ {
+ // need not take care of the XUngrabPointer in Show( FALSE )
+ // because XUngrabPointer does not produce errors if pointer
+ // is not grabbed
+ XUngrabPointer( GetXDisplay(), CurrentTime );
+ bClosePopups = true;
+
+ /* #i15246# only close popups if pointer is outside all our frames
+ * cannot use our own geometry data here because stacking
+ * is unknown (the above case implicitly assumes
+ * that floats are on top which should be true)
+ */
+ XLIB_Window aRoot, aChild;
+ int root_x, root_y, win_x, win_y;
+ unsigned int mask_return;
+ if( XQueryPointer( GetXDisplay(),
+ GetDisplay()->GetRootWindow( m_nScreen ),
+ &aRoot, &aChild,
+ &root_x, &root_y,
+ &win_x, &win_y,
+ &mask_return )
+ && aChild // pointer may not be in any child
+ )
+ {
+ for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it )
+ {
+ const X11SalFrame* pFrame = static_cast< const X11SalFrame* >(*it);
+ if( ! pFrame->IsFloatGrabWindow()
+ && ( pFrame->GetWindow() == aChild ||
+ pFrame->GetShellWindow() == aChild ||
+ pFrame->GetStackingWindow() == aChild )
+ )
+ {
+ // #i63638# check that pointer is inside window, not
+ // only inside stacking window
+ if( root_x >= pFrame->maGeometry.nX && root_x < sal::static_int_cast< int >(pFrame->maGeometry.nX+pFrame->maGeometry.nWidth) &&
+ root_y >= pFrame->maGeometry.nY && root_y < sal::static_int_cast< int >(pFrame->maGeometry.nX+pFrame->maGeometry.nHeight) )
+ {
+ bClosePopups = false;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if( m_bXEmbed && pEvent->xbutton.button == Button1 )
+ askForXEmbedFocus( pEvent->xbutton.time );
+
+ if( pEvent->xbutton.button == Button1 ||
+ pEvent->xbutton.button == Button2 ||
+ pEvent->xbutton.button == Button3 )
+ {
+ aMouseEvt.mnX = pEvent->xbutton.x;
+ aMouseEvt.mnY = pEvent->xbutton.y;
+ aMouseEvt.mnTime = pEvent->xbutton.time;
+ aMouseEvt.mnCode = sal_GetCode( pEvent->xbutton.state );
+
+ if( Button1 == pEvent->xbutton.button )
+ aMouseEvt.mnButton = MOUSE_LEFT;
+ else if( Button2 == pEvent->xbutton.button )
+ aMouseEvt.mnButton = MOUSE_MIDDLE;
+ else if( Button3 == pEvent->xbutton.button )
+ aMouseEvt.mnButton = MOUSE_RIGHT;
+
+ nEvent = ButtonPress == pEvent->type
+ ? SALEVENT_MOUSEBUTTONDOWN
+ : SALEVENT_MOUSEBUTTONUP;
+ }
+ else if( pEvent->xbutton.button == Button4 ||
+ pEvent->xbutton.button == Button5 ||
+ pEvent->xbutton.button == Button6 ||
+ pEvent->xbutton.button == Button7 )
+ {
+ const bool bIncrement(
+ pEvent->xbutton.button == Button4 ||
+ pEvent->xbutton.button == Button6 );
+ const bool bHoriz(
+ pEvent->xbutton.button == Button6 ||
+ pEvent->xbutton.button == Button7 );
+
+ if( pEvent->type == ButtonRelease )
+ return 0;
+
+ static ULONG nLines = 0;
+ if( ! nLines )
+ {
+ char* pEnv = getenv( "SAL_WHEELLINES" );
+ nLines = pEnv ? atoi( pEnv ) : 3;
+ if( nLines > 10 )
+ nLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
+ }
+
+ SalWheelMouseEvent aWheelEvt;
+ aWheelEvt.mnTime = pEvent->xbutton.time;
+ aWheelEvt.mnX = pEvent->xbutton.x;
+ aWheelEvt.mnY = pEvent->xbutton.y;
+ aWheelEvt.mnDelta = bIncrement ? 120 : -120;
+ aWheelEvt.mnNotchDelta = bIncrement ? 1 : -1;
+ aWheelEvt.mnScrollLines = nLines;
+ aWheelEvt.mnCode = sal_GetCode( pEvent->xbutton.state );
+ aWheelEvt.mbHorz = bHoriz;
+
+ nEvent = SALEVENT_WHEELMOUSE;
+
+ // --- RTL --- (mirror mouse pos)
+ if( Application::GetSettings().GetLayoutRTL() )
+ aWheelEvt.mnX = nWidth_-1-aWheelEvt.mnX;
+ return CallCallback( nEvent, &aWheelEvt );
+ }
+ }
+
+ int nRet = 0;
+ if( nEvent == SALEVENT_MOUSELEAVE
+ || ( aMouseEvt.mnX < nWidth_ && aMouseEvt.mnX > -1 &&
+ aMouseEvt.mnY < nHeight_ && aMouseEvt.mnY > -1 )
+ || pDisplay_->MouseCaptured( this )
+ )
+ {
+ // --- RTL --- (mirror mouse pos)
+ if( Application::GetSettings().GetLayoutRTL() )
+ aMouseEvt.mnX = nWidth_-1-aMouseEvt.mnX;
+ nRet = CallCallback( nEvent, &aMouseEvt );
+ }
+
+ if( bClosePopups )
+ {
+ /* #108213# close popups after dispatching the event outside the popup;
+ * applications do weird things.
+ */
+ ImplSVData* pSVData = ImplGetSVData();
+ if ( pSVData->maWinData.mpFirstFloat )
+ {
+ static const char* pEnv = getenv( "SAL_FLOATWIN_NOAPPFOCUSCLOSE" );
+ if ( !(pSVData->maWinData.mpFirstFloat->GetPopupModeFlags() & FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE) && !(pEnv && *pEnv) )
+ pSVData->maWinData.mpFirstFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL );
+ }
+ }
+
+ return nRet;
+}
+
+// F10 means either KEY_F10 or KEY_MENU, which has to be decided
+// in the independent part.
+struct KeyAlternate
+{
+ USHORT nKeyCode;
+ sal_Unicode nCharCode;
+ KeyAlternate() : nKeyCode( 0 ), nCharCode( 0 ) {}
+ KeyAlternate( USHORT nKey, sal_Unicode nChar = 0 ) : nKeyCode( nKey ), nCharCode( nChar ) {}
+};
+
+inline KeyAlternate
+GetAlternateKeyCode( const USHORT nKeyCode )
+{
+ KeyAlternate aAlternate;
+
+ switch( nKeyCode )
+ {
+ case KEY_F10: aAlternate = KeyAlternate( KEY_MENU );break;
+ case KEY_F24: aAlternate = KeyAlternate( KEY_SUBTRACT, '-' );break;
+ }
+
+ return aAlternate;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+long X11SalFrame::HandleKeyEvent( XKeyEvent *pEvent )
+{
+ KeySym nKeySym;
+ KeySym nUnmodifiedKeySym;
+ int nLen = 2048;
+ unsigned char *pPrintable = (unsigned char*)alloca( nLen );
+
+ // singlebyte code composed by input method, the new default
+ if (mpInputContext != NULL && mpInputContext->UseContext())
+ {
+ // returns a keysym as well as the pPrintable (in system encoding)
+ // printable may be empty.
+ Status nStatus;
+ nKeySym = pDisplay_->GetKeySym( pEvent, pPrintable, &nLen,
+ &nUnmodifiedKeySym,
+ &nStatus, mpInputContext->GetContext() );
+ if ( nStatus == XBufferOverflow )
+ {
+ nLen *= 2;
+ pPrintable = (unsigned char*)alloca( nLen );
+ nKeySym = pDisplay_->GetKeySym( pEvent, pPrintable, &nLen,
+ &nUnmodifiedKeySym,
+ &nStatus, mpInputContext->GetContext() );
+ }
+ }
+ else
+ {
+ // fallback, this should never ever be called
+ Status nStatus = 0;
+ nKeySym = pDisplay_->GetKeySym( pEvent, pPrintable, &nLen, &nUnmodifiedKeySym, &nStatus );
+ }
+
+ SalKeyEvent aKeyEvt;
+ USHORT nKeyCode;
+ USHORT nModCode = 0;
+ char aDummy;
+
+ if( pEvent->state & ShiftMask )
+ nModCode |= KEY_SHIFT;
+ if( pEvent->state & ControlMask )
+ nModCode |= KEY_MOD1;
+ if( pEvent->state & Mod1Mask )
+ nModCode |= KEY_MOD2;
+
+ if( nKeySym == XK_Shift_L || nKeySym == XK_Shift_R
+ || nKeySym == XK_Control_L || nKeySym == XK_Control_R
+ || nKeySym == XK_Alt_L || nKeySym == XK_Alt_R
+ || nKeySym == XK_Meta_L || nKeySym == XK_Meta_R
+ || nKeySym == XK_Super_L || nKeySym == XK_Super_R )
+ {
+ SalKeyModEvent aModEvt;
+ aModEvt.mnModKeyCode = 0;
+ if( pEvent->type == XLIB_KeyPress && mnExtKeyMod == 0 )
+ mbSendExtKeyModChange = true;
+ else if( pEvent->type == KeyRelease && mbSendExtKeyModChange )
+ {
+ aModEvt.mnModKeyCode = mnExtKeyMod;
+ mnExtKeyMod = 0;
+ }
+
+ // pressing just the ctrl key leads to a keysym of XK_Control but
+ // the event state does not contain ControlMask. In the release
+ // event its the other way round: it does contain the Control mask.
+ // The modifier mode therefore has to be adapted manually.
+ USHORT nExtModMask = 0;
+ USHORT nModMask = 0;
+ switch( nKeySym )
+ {
+ case XK_Control_L:
+ nExtModMask = MODKEY_LMOD1;
+ nModMask = KEY_MOD1;
+ break;
+ case XK_Control_R:
+ nExtModMask = MODKEY_RMOD1;
+ nModMask = KEY_MOD1;
+ break;
+ case XK_Alt_L:
+ nExtModMask = MODKEY_LMOD2;
+ nModMask = KEY_MOD2;
+ break;
+ case XK_Alt_R:
+ nExtModMask = MODKEY_RMOD2;
+ nModMask = KEY_MOD2;
+ break;
+ case XK_Shift_L:
+ nExtModMask = MODKEY_LSHIFT;
+ nModMask = KEY_SHIFT;
+ break;
+ case XK_Shift_R:
+ nExtModMask = MODKEY_RSHIFT;
+ nModMask = KEY_SHIFT;
+ break;
+ // Map Meta/Super keys to MOD3 modifier on all Unix systems
+ // except Mac OS X
+ case XK_Meta_L:
+ case XK_Super_L:
+ nExtModMask = MODKEY_LMOD3;
+ nModMask = KEY_MOD3;
+ break;
+ case XK_Meta_R:
+ case XK_Super_R:
+ nExtModMask = MODKEY_RMOD3;
+ nModMask = KEY_MOD3;
+ break;
+ }
+ if( pEvent->type == KeyRelease )
+ {
+ nModCode &= ~nModMask;
+ mnExtKeyMod &= ~nExtModMask;
+ }
+ else
+ {
+ nModCode |= nModMask;
+ mnExtKeyMod |= nExtModMask;
+ }
+
+ aModEvt.mnCode = nModCode;
+ aModEvt.mnTime = pEvent->time;
+
+ int nRet = CallCallback( SALEVENT_KEYMODCHANGE, &aModEvt );
+
+ // emulate KEY_MENU
+ if ( ( (nKeySym == XK_Alt_L) || (nKeySym == XK_Alt_R) ) &&
+ ( (nModCode & ~(KEY_MOD3|KEY_MOD2)) == 0 ) )
+ {
+ if( pEvent->type == XLIB_KeyPress )
+ mbKeyMenu = true;
+ else if( mbKeyMenu )
+ {
+ // simulate KEY_MENU
+ aKeyEvt.mnCode = KEY_MENU | nModCode;
+ aKeyEvt.mnRepeat = 0;
+ aKeyEvt.mnTime = pEvent->time;
+ aKeyEvt.mnCharCode = 0;
+ nRet = CallCallback( SALEVENT_KEYINPUT, &aKeyEvt );
+ nRet = CallCallback( SALEVENT_KEYUP, &aKeyEvt );
+ }
+ }
+ else
+ mbKeyMenu = false;
+ return nRet;
+ }
+
+ mbSendExtKeyModChange = mbKeyMenu = false;
+
+ // try to figure out the vcl code for the keysym
+ // #i52338# use the unmodified KeySym if there is none for the real KeySym
+ // because the independent part has only keycodes for unshifted keys
+ nKeyCode = pDisplay_->GetKeyCode( nKeySym, &aDummy );
+ if( nKeyCode == 0 )
+ nKeyCode = pDisplay_->GetKeyCode( nUnmodifiedKeySym, &aDummy );
+
+ // try to figure out a printable if XmbLookupString returns only a keysym
+ // and NOT a printable. Do not store it in pPrintable[0] since it is expected to
+ // be in system encoding, not unicode.
+ // #i8988##, if KeySym and printable look equally promising then prefer KeySym
+ // the printable is bound to the encoding so the KeySym might contain more
+ // information (in et_EE locale: "Compose + Z + <" delivers "," in printable and
+ // (the desired) Zcaron in KeySym
+ sal_Unicode nKeyString = 0x0;
+ if ( (nLen == 0)
+ || ((nLen == 1) && (nKeySym > 0)) )
+ nKeyString = KeysymToUnicode (nKeySym);
+ // if we have nothing we give up
+ if( !nKeyCode && !nLen && !nKeyString)
+ return 0;
+
+ rtl_TextEncoding nEncoding;
+
+ if (mpInputContext != NULL && mpInputContext->IsMultiLingual() )
+ nEncoding = RTL_TEXTENCODING_UTF8;
+ else
+ nEncoding = osl_getThreadTextEncoding();
+
+ sal_Unicode *pBuffer;
+ sal_Unicode *pString;
+ sal_Size nBufferSize = nLen * 2;
+ sal_Size nSize;
+ pBuffer = (sal_Unicode*) malloc( nBufferSize + 2 );
+ pBuffer[ 0 ] = 0;
+
+ if (nKeyString != 0)
+ {
+ pString = &nKeyString;
+ nSize = 1;
+ }
+ else
+ if (nLen > 0 && nEncoding != RTL_TEXTENCODING_UNICODE)
+ {
+ // create text converter
+ rtl_TextToUnicodeConverter aConverter =
+ rtl_createTextToUnicodeConverter( nEncoding );
+ rtl_TextToUnicodeContext aContext =
+ rtl_createTextToUnicodeContext( aConverter );
+
+ sal_uInt32 nConversionInfo;
+ sal_Size nConvertedChars;
+
+ // convert to single byte text stream
+ nSize = rtl_convertTextToUnicode(
+ aConverter, aContext,
+ (char*)pPrintable, nLen,
+ pBuffer, nBufferSize,
+ RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_IGNORE |
+ RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE,
+ &nConversionInfo, &nConvertedChars );
+
+ // destroy converter
+ rtl_destroyTextToUnicodeContext( aConverter, aContext );
+ rtl_destroyTextToUnicodeConverter( aConverter );
+
+ pString = pBuffer;
+ }
+ else
+ if (nLen > 0 /* nEncoding == RTL_TEXTENCODING_UNICODE */)
+ {
+ pString = (sal_Unicode*)pPrintable;
+ nSize = nLen;
+ }
+ else
+ {
+ pString = pBuffer;
+ nSize = 0;
+ }
+
+ DeletionListener aDeleteWatch( this );
+
+ if ( mpInputContext != NULL
+ && mpInputContext->UseContext()
+ && KeyRelease != pEvent->type
+ && ( (nSize > 1)
+ || (nSize > 0 && mpInputContext->IsPreeditMode())) )
+ {
+ mpInputContext->CommitKeyEvent(pString, nSize);
+ }
+ else
+ // normal single character keyinput
+ {
+ aKeyEvt.mnCode = nKeyCode | nModCode;
+ aKeyEvt.mnRepeat = 0;
+ aKeyEvt.mnTime = pEvent->time;
+ aKeyEvt.mnCharCode = pString[ 0 ];
+
+ if( KeyRelease == pEvent->type )
+ {
+ CallCallback( SALEVENT_KEYUP, &aKeyEvt );
+ }
+ else
+ {
+ if ( ! CallCallback(SALEVENT_KEYINPUT, &aKeyEvt) )
+ {
+ // independent layer doesnt want to handle key-event, so check
+ // whether the keycode may have an alternate meaning
+ KeyAlternate aAlternate = GetAlternateKeyCode( nKeyCode );
+ if ( aAlternate.nKeyCode != 0 )
+ {
+ aKeyEvt.mnCode = aAlternate.nKeyCode | nModCode;
+ if( aAlternate.nCharCode )
+ aKeyEvt.mnCharCode = aAlternate.nCharCode;
+ CallCallback(SALEVENT_KEYINPUT, &aKeyEvt);
+ }
+ }
+ }
+ }
+
+ //
+ // update the spot location for PreeditPosition IME style
+ //
+ if (! aDeleteWatch.isDeleted())
+ {
+ if (mpInputContext != NULL && mpInputContext->UseContext())
+ mpInputContext->UpdateSpotLocation();
+ }
+
+ free (pBuffer);
+ return True;
+}
+
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+long X11SalFrame::HandleFocusEvent( XFocusChangeEvent *pEvent )
+{
+ // #107739# ReflectionX in Windows mode changes focus while mouse is grabbed
+ if( nVisibleFloats > 0 && GetDisplay()->getWMAdaptor()->getWindowManagerName().EqualsAscii( "ReflectionX Windows" ) )
+ return 1;
+
+ /* #55691# ignore focusout resulting from keyboard grabs
+ * we do not grab it and are not interested when
+ * someone else does CDE e.g. does a XGrabKey on arrow keys
+ * #73179# handle focus events with mode NotifyWhileGrabbed
+ * because with CDE alt-tab focus changing we do not get
+ * normal focus events
+ * #71791# cast focus event to the input context, otherwise the
+ * status window does not follow the application frame
+ */
+
+ if ( mpInputContext != NULL )
+ {
+ if( FocusIn == pEvent->type )
+ mpInputContext->SetICFocus( this );
+ else
+ {
+ /*
+ * do not unset the IC focuse here because would kill
+ * a lookup choice windows that might have the focus now
+ * mpInputContext->UnsetICFocus( this );
+ */
+ I18NStatus::get().show( false, I18NStatus::focus );
+ }
+ }
+
+
+ if ( pEvent->mode == NotifyNormal || pEvent->mode == NotifyWhileGrabbed ||
+ ( ( nStyle_ & SAL_FRAME_STYLE_PLUG ) && pEvent->window == GetShellWindow() )
+ )
+ {
+ if( hPresentationWindow != None && hPresentationWindow != GetShellWindow() )
+ return 0;
+
+ if( FocusIn == pEvent->type )
+ {
+#ifndef _USE_PRINT_EXTENSION_
+ vcl_sal::PrinterUpdate::update();
+#endif
+ mbInputFocus = True;
+ ImplSVData* pSVData = ImplGetSVData();
+
+
+
+ long nRet = CallCallback( SALEVENT_GETFOCUS, 0 );
+ if ((mpParent != NULL && nStyle_ == 0)
+ && pSVData->maWinData.mpFirstFloat )
+ {
+ ULONG nMode = pSVData->maWinData.mpFirstFloat->GetPopupModeFlags();
+ pSVData->maWinData.mpFirstFloat->SetPopupModeFlags(
+ nMode & ~(FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE));
+ }
+ return nRet;
+ }
+ else
+ {
+ mbInputFocus = False;
+ mbSendExtKeyModChange = mbKeyMenu = false;
+ mnExtKeyMod = 0;
+ return CallCallback( SALEVENT_LOSEFOCUS, 0 );
+ }
+ }
+
+ return 0;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+long X11SalFrame::HandleExposeEvent( XEvent *pEvent )
+{
+ XRectangle aRect = { 0, 0, 0, 0 };
+ USHORT nCount = 0;
+
+ if( pEvent->type == Expose )
+ {
+ aRect.x = pEvent->xexpose.x;
+ aRect.y = pEvent->xexpose.y;
+ aRect.width = pEvent->xexpose.width;
+ aRect.height = pEvent->xexpose.height;
+ nCount = pEvent->xexpose.count;
+ }
+ else if( pEvent->type == GraphicsExpose )
+ {
+ aRect.x = pEvent->xgraphicsexpose.x;
+ aRect.y = pEvent->xgraphicsexpose.y;
+ aRect.width = pEvent->xgraphicsexpose.width;
+ aRect.height = pEvent->xgraphicsexpose.height;
+ nCount = pEvent->xgraphicsexpose.count;
+ }
+
+ if( IsOverrideRedirect() && mbFullScreen &&
+ aPresentationReparentList.begin() == aPresentationReparentList.end() )
+ // we are in fullscreen mode -> override redirect
+ // focus is possibly lost, so reget it
+ XSetInputFocus( GetXDisplay(), GetShellWindow(), RevertToNone, CurrentTime );
+
+ // width and height are extents, so they are of by one for rectangle
+ maPaintRegion.Union( Rectangle( Point(aRect.x, aRect.y), Size(aRect.width+1, aRect.height+1) ) );
+
+ if( nCount )
+ // wait for last expose rectangle, do not wait for resize timer
+ // if a completed graphics expose sequence is available
+ return 1;
+
+ SalPaintEvent aPEvt( maPaintRegion.Left(), maPaintRegion.Top(), maPaintRegion.GetWidth(), maPaintRegion.GetHeight() );
+
+ CallCallback( SALEVENT_PAINT, &aPEvt );
+ maPaintRegion = Rectangle();
+
+ return 1;
+}
+
+void X11SalFrame::RestackChildren( XLIB_Window* pTopLevelWindows, int nTopLevelWindows )
+{
+ if( maChildren.begin() != maChildren.end() )
+ {
+ int nWindow = nTopLevelWindows;
+ while( nWindow-- )
+ if( pTopLevelWindows[nWindow] == GetStackingWindow() )
+ break;
+ if( nWindow < 0 )
+ return;
+
+ std::list< X11SalFrame* >::const_iterator it;
+ for( it = maChildren.begin(); it != maChildren.end(); ++it )
+ {
+ X11SalFrame* pData = *it;
+ if( pData->bMapped_ )
+ {
+ int nChild = nWindow;
+ while( nChild-- )
+ {
+ if( pTopLevelWindows[nChild] == pData->GetStackingWindow() )
+ {
+ // if a child is behind its parent, place it above the
+ // parent (for insane WMs like Dtwm and olwm)
+ XWindowChanges aCfg;
+ aCfg.sibling = GetStackingWindow();
+ aCfg.stack_mode = Above;
+ XConfigureWindow( GetXDisplay(), pData->GetStackingWindow(), CWSibling|CWStackMode, &aCfg );
+ break;
+ }
+ }
+ }
+ }
+ for( it = maChildren.begin(); it != maChildren.end(); ++it )
+ {
+ X11SalFrame* pData = *it;
+ pData->RestackChildren( pTopLevelWindows, nTopLevelWindows );
+ }
+ }
+}
+
+void X11SalFrame::RestackChildren()
+{
+ if( ! GetDisplay()->getWMAdaptor()->isTransientBehaviourAsExpected()
+ && maChildren.begin() != maChildren.end() )
+ {
+ XLIB_Window aRoot, aParent, *pChildren = NULL;
+ unsigned int nChildren;
+ if( XQueryTree( GetXDisplay(),
+ GetDisplay()->GetRootWindow( m_nScreen ),
+ &aRoot,
+ &aParent,
+ &pChildren,
+ &nChildren ) )
+ {
+ RestackChildren( pChildren, nChildren );
+ XFree( pChildren );
+ }
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+long X11SalFrame::HandleSizeEvent( XConfigureEvent *pEvent )
+{
+ if ( pEvent->window != GetShellWindow()
+ && pEvent->window != GetWindow()
+ && pEvent->window != GetForeignParent()
+ && pEvent->window != GetStackingWindow()
+ )
+ {
+ // could be as well a sys-child window (aka SalObject)
+ return 1;
+ }
+
+
+ if( ( nStyle_ & SAL_FRAME_STYLE_PLUG ) && pEvent->window == GetShellWindow() )
+ {
+ // just update the children's positions
+ RestackChildren();
+ return 1;
+ }
+
+ if( pEvent->window == GetForeignParent() )
+ XResizeWindow( GetXDisplay(),
+ GetWindow(),
+ pEvent->width,
+ pEvent->height );
+
+ XLIB_Window hDummy;
+ XTranslateCoordinates( GetXDisplay(),
+ GetWindow(),
+ pDisplay_->GetRootWindow( pDisplay_->GetDefaultScreenNumber() ),
+ 0, 0,
+ &pEvent->x, &pEvent->y,
+ &hDummy );
+
+ if( pEvent->window == GetStackingWindow() )
+ {
+ if( maGeometry.nX != pEvent->x || maGeometry.nY != pEvent->y )
+ {
+ maGeometry.nX = pEvent->x;
+ maGeometry.nY = pEvent->y;
+ CallCallback( SALEVENT_MOVE, NULL );
+ }
+ return 1;
+ }
+
+ // check size hints in first time SalFrame::Show
+ if( SHOWSTATE_UNKNOWN == nShowState_ && bMapped_ )
+ nShowState_ = SHOWSTATE_NORMAL;
+
+ nWidth_ = pEvent->width;
+ nHeight_ = pEvent->height;
+
+ bool bMoved = ( pEvent->x != maGeometry.nX || pEvent->y != maGeometry.nY );
+ bool bSized = ( pEvent->width != (int)maGeometry.nWidth || pEvent->height != (int)maGeometry.nHeight );
+
+ maGeometry.nX = pEvent->x;
+ maGeometry.nY = pEvent->y;
+ maGeometry.nWidth = pEvent->width;
+ maGeometry.nHeight = pEvent->height;
+ updateScreenNumber();
+
+ // update children's position
+ RestackChildren();
+
+ if( bSized && ! bMoved )
+ CallCallback( SALEVENT_RESIZE, NULL );
+ else if( bMoved && ! bSized )
+ CallCallback( SALEVENT_MOVE, NULL );
+ else if( bMoved && bSized )
+ CallCallback( SALEVENT_MOVERESIZE, NULL );
+
+ return 1;
+}
+
+IMPL_LINK( X11SalFrame, HandleAlwaysOnTopRaise, void*, EMPTYARG )
+{
+ if( bMapped_ )
+ ToTop( 0 );
+ return 0;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+long X11SalFrame::HandleReparentEvent( XReparentEvent *pEvent )
+{
+ Display *pDisplay = pEvent->display;
+ XLIB_Window hWM_Parent;
+ XLIB_Window hRoot, *Children, hDummy;
+ unsigned int nChildren;
+ BOOL bNone = pDisplay_->GetProperties()
+ & PROPERTY_SUPPORT_WM_Parent_Pixmap_None;
+ BOOL bAccessParentWindow = ! (pDisplay_->GetProperties()
+ & PROPERTY_FEATURE_TrustedSolaris);
+
+ static const char* pDisableStackingCheck = getenv( "SAL_DISABLE_STACKING_CHECK" );
+
+ GetDisplay()->GetXLib()->PushXErrorLevel( true );
+
+ /*
+ * #89186# don't rely on the new parent from the event.
+ * the event may be "out of date", that is the window manager
+ * window may not exist anymore. This can happen if someone
+ * shows a frame and hides it again quickly (not that that would
+ * be very sensible)
+ */
+ hWM_Parent = GetShellWindow();
+ do
+ {
+ Children = NULL;
+ XQueryTree( pDisplay,
+ hWM_Parent,
+ &hRoot,
+ &hDummy,
+ &Children,
+ &nChildren );
+ if( GetDisplay()->GetXLib()->HasXErrorOccured() )
+ {
+ hWM_Parent = GetShellWindow();
+ break;
+ }
+ /* #107048# this sometimes happens if a Show(TRUE) is
+ * immediately followed by Show(FALSE) (which is braindead anyway)
+ */
+ if( hDummy == hWM_Parent )
+ hDummy = hRoot;
+ if( hDummy != hRoot )
+ {
+ hWM_Parent = hDummy;
+ if( bAccessParentWindow && bNone )
+ XSetWindowBackgroundPixmap( pDisplay, hWM_Parent, None );
+ }
+ if( Children )
+ XFree( Children );
+ } while( hDummy != hRoot );
+
+ if( GetStackingWindow() == None
+ && hWM_Parent != hPresentationWindow
+ && hWM_Parent != GetShellWindow()
+ && ( ! pDisableStackingCheck || ! *pDisableStackingCheck )
+ )
+ {
+ mhStackingWindow = hWM_Parent;
+ if (bAccessParentWindow)
+ XSelectInput( pDisplay, GetStackingWindow(), StructureNotifyMask );
+ }
+
+ if( hWM_Parent == pDisplay_->GetRootWindow( pDisplay_->GetDefaultScreenNumber() )
+ || hWM_Parent == GetForeignParent()
+ || pEvent->parent == pDisplay_->GetRootWindow( pDisplay_->GetDefaultScreenNumber() )
+ || ( nStyle_ & SAL_FRAME_STYLE_FLOAT ) )
+ {
+ // Reparenting before Destroy
+ aPresentationReparentList.remove( GetStackingWindow() );
+ mhStackingWindow = None;
+ GetDisplay()->GetXLib()->PopXErrorLevel();
+ return 0;
+ }
+
+ /*
+ * evil hack to show decorated windows on top
+ * of override redirect presentation windows:
+ * reparent the window manager window to the presentation window
+ * does not work with non-reparenting WMs
+ * in future this should not be necessary anymore with
+ * _NET_WM_STATE_FULLSCREEN available
+ */
+ if( hPresentationWindow != None
+ && hPresentationWindow != GetWindow()
+ && GetStackingWindow() != None
+ && GetStackingWindow() != GetDisplay()->GetRootWindow( m_nScreen )
+ )
+ {
+ int x = 0, y = 0;
+ XLIB_Window aChild;
+ XTranslateCoordinates( GetXDisplay(),
+ GetStackingWindow(),
+ GetDisplay()->GetRootWindow( m_nScreen ),
+ 0, 0,
+ &x, &y,
+ &aChild
+ );
+ XReparentWindow( GetXDisplay(),
+ GetStackingWindow(),
+ hPresentationWindow,
+ x, y
+ );
+ aPresentationReparentList.push_back( GetStackingWindow() );
+ }
+
+ int nLeft = 0, nTop = 0;
+ XTranslateCoordinates( GetXDisplay(),
+ GetShellWindow(),
+ hWM_Parent,
+ 0, 0,
+ &nLeft,
+ &nTop,
+ &hDummy );
+ maGeometry.nLeftDecoration = nLeft > 0 ? nLeft-1 : 0;
+ maGeometry.nTopDecoration = nTop > 0 ? nTop-1 : 0;
+
+ /*
+ * decorations are not symmetric,
+ * so need real geometries here
+ * (this will fail with virtual roots ?)
+ */
+ GetDisplay()->GetXLib()->ResetXErrorOccured();
+ int xp, yp, x, y;
+ unsigned int wp, w, hp, h, bw, d;
+ XGetGeometry( GetXDisplay(),
+ GetShellWindow(),
+ &hRoot,
+ &x, &y, &w, &h, &bw, &d );
+ XGetGeometry( GetXDisplay(),
+ hWM_Parent,
+ &hRoot,
+ &xp, &yp, &wp, &hp, &bw, &d );
+ bool bResized = false;
+ if( ! GetDisplay()->GetXLib()->HasXErrorOccured() )
+ {
+ maGeometry.nRightDecoration = wp - w - maGeometry.nLeftDecoration;
+ maGeometry.nBottomDecoration = hp - h - maGeometry.nTopDecoration;
+ /*
+ * note: this works because hWM_Parent is direct child of root,
+ * not necessarily parent of GetShellWindow()
+ */
+ maGeometry.nX = xp + nLeft;
+ maGeometry.nY = yp + nTop;
+ bResized = w != maGeometry.nWidth || h != maGeometry.nHeight;
+ maGeometry.nWidth = w;
+ maGeometry.nHeight = h;
+ }
+
+
+ // limit width and height if we are too large: #47757
+ // olwm and fvwm need this, it doesnt harm the rest
+
+ // #i81311# do this only for sizable frames
+ if( (nStyle_ & SAL_FRAME_STYLE_SIZEABLE) != 0 )
+ {
+ Size aScreenSize = GetDisplay()->GetScreenSize( m_nScreen );
+ int nScreenWidth = aScreenSize.Width();
+ int nScreenHeight = aScreenSize.Height();
+ int nFrameWidth = maGeometry.nWidth + maGeometry.nLeftDecoration + maGeometry.nRightDecoration;
+ int nFrameHeight = maGeometry.nHeight + maGeometry.nTopDecoration + maGeometry.nBottomDecoration;
+
+ if ((nFrameWidth > nScreenWidth) || (nFrameHeight > nScreenHeight))
+ {
+ Size aSize(maGeometry.nWidth, maGeometry.nHeight);
+
+ if (nFrameWidth > nScreenWidth)
+ aSize.Width() = nScreenWidth - maGeometry.nRightDecoration - maGeometry.nLeftDecoration;
+ if (nFrameHeight > nScreenHeight)
+ aSize.Height() = nScreenHeight - maGeometry.nBottomDecoration - maGeometry.nTopDecoration;
+
+ SetSize( aSize );
+ bResized = false;
+ }
+ }
+ if( bResized )
+ CallCallback( SALEVENT_RESIZE, NULL );
+
+ GetDisplay()->GetXLib()->PopXErrorLevel();
+
+ return 1;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+long X11SalFrame::HandleColormapEvent( XColormapEvent* )
+{
+ return 0;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+long X11SalFrame::HandleStateEvent( XPropertyEvent *pEvent )
+{
+ Atom actual_type;
+ int actual_format;
+ unsigned long nitems, bytes_after;
+ unsigned char *prop = NULL;
+
+ if( 0 != XGetWindowProperty( GetXDisplay(),
+ GetShellWindow(),
+ pEvent->atom, // property
+ 0, // long_offset (32bit)
+ 2, // long_length (32bit)
+ False, // delete
+ pEvent->atom, // req_type
+ &actual_type,
+ &actual_format,
+ &nitems,
+ &bytes_after,
+ &prop )
+ || ! prop
+ )
+ return 0;
+
+ DBG_ASSERT( actual_type = pEvent->atom
+ && 32 == actual_format
+ && 2 == nitems
+ && 0 == bytes_after, "HandleStateEvent" );
+
+ if( *(unsigned long*)prop == NormalState )
+ nShowState_ = SHOWSTATE_NORMAL;
+ else if( *(unsigned long*)prop == IconicState )
+ nShowState_ = SHOWSTATE_MINIMIZED;
+
+ XFree( prop );
+ return 1;
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+long X11SalFrame::HandleClientMessage( XClientMessageEvent *pEvent )
+{
+ const WMAdaptor& rWMAdaptor( *pDisplay_->getWMAdaptor() );
+
+#if !defined(__synchronous_extinput__)
+ if( pEvent->message_type == rWMAdaptor.getAtom( WMAdaptor::SAL_EXTTEXTEVENT ) )
+ {
+ HandleExtTextEvent (pEvent);
+ return 1;
+ }
+#endif
+ else if( pEvent->message_type == rWMAdaptor.getAtom( WMAdaptor::SAL_QUITEVENT ) )
+ {
+ stderr0( "X11SalFrame::Dispatch Quit\n" );
+ Close(); // ???
+ return 1;
+ }
+ else if( pEvent->message_type == rWMAdaptor.getAtom( WMAdaptor::WM_PROTOCOLS ) )
+ {
+ if( (Atom)pEvent->data.l[0] == rWMAdaptor.getAtom( WMAdaptor::NET_WM_PING ) )
+ rWMAdaptor.answerPing( this, pEvent );
+ else if( ! ( nStyle_ & SAL_FRAME_STYLE_PLUG )
+ && ! (( nStyle_ & SAL_FRAME_STYLE_FLOAT ) && (nStyle_ & SAL_FRAME_STYLE_OWNERDRAWDECORATION))
+ )
+ {
+ if( (Atom)pEvent->data.l[0] == rWMAdaptor.getAtom( WMAdaptor::WM_DELETE_WINDOW ) )
+ {
+ Close();
+ return 1;
+ }
+ else if( (Atom)pEvent->data.l[0] == rWMAdaptor.getAtom( WMAdaptor::WM_TAKE_FOCUS ) )
+ {
+ // do nothing, we set the input focus in ToTop() if necessary
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "got WM_TAKE_FOCUS on %s window\n",
+ (nStyle_&SAL_FRAME_STYLE_OWNERDRAWDECORATION) ?
+ "ownerdraw" : "NON OWNERDRAW" );
+ #endif
+ }
+ else if( (Atom)pEvent->data.l[0] == rWMAdaptor.getAtom( WMAdaptor::WM_SAVE_YOURSELF ) )
+ {
+ bool bSession = rWMAdaptor.getWindowManagerName().EqualsAscii( "Dtwm" );
+
+ if( ! bSession )
+ {
+ if( this == s_pSaveYourselfFrame )
+ {
+ ByteString aExec( SessionManagerClient::getExecName(), osl_getThreadTextEncoding() );
+ const char* argv[2];
+ argv[0] = "/bin/sh";
+ argv[1] = const_cast<char*>(aExec.GetBuffer());
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "SaveYourself request, setting command: %s %s\n", argv[0], argv[1] );
+ #endif
+ XSetCommand( GetXDisplay(), GetShellWindow(), (char**)argv, 2 );
+ }
+ else
+ // can only happen in race between WM and window closing
+ XChangeProperty( GetXDisplay(), GetShellWindow(), rWMAdaptor.getAtom( WMAdaptor::WM_COMMAND ), XA_STRING, 8, PropModeReplace, (unsigned char*)"", 0 );
+ }
+ else
+ {
+ // save open documents; would be good for non Dtwm, too,
+ // but there is no real Shutdown message in the ancient
+ // SM protocol; on Dtwm SaveYourself really means Shutdown, too.
+ IceSalSession::handleOldX11SaveYourself( this );
+ }
+ }
+ }
+ }
+ else if( pEvent->message_type == rWMAdaptor.getAtom( WMAdaptor::XEMBED ) &&
+ pEvent->window == GetWindow() )
+ {
+ if( pEvent->data.l[1] == 1 || // XEMBED_WINDOW_ACTIVATE
+ pEvent->data.l[1] == 2 ) // XEMBED_WINDOW_DEACTIVATE
+ {
+ XFocusChangeEvent aEvent;
+ aEvent.type = (pEvent->data.l[1] == 1 ? FocusIn : FocusOut);
+ aEvent.serial = pEvent->serial;
+ aEvent.send_event = True;
+ aEvent.display = pEvent->display;
+ aEvent.window = pEvent->window;
+ aEvent.mode = NotifyNormal;
+ aEvent.detail = NotifyDetailNone;
+ HandleFocusEvent( &aEvent );
+ }
+ }
+ return 0;
+}
+
+void X11SalFrame::SaveYourselfDone( SalFrame* pSaveFrame )
+{
+ // session save was done, inform dtwm
+ if( s_pSaveYourselfFrame && pSaveFrame )
+ {
+ ByteString aExec( SessionManagerClient::getExecName(), osl_getThreadTextEncoding() );
+ const char* argv[2];
+ argv[0] = "/bin/sh";
+ argv[1] = const_cast<char*>(aExec.GetBuffer());
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "SaveYourself request, setting command: %s %s\n", argv[0], argv[1] );
+#endif
+ XSetCommand( s_pSaveYourselfFrame->GetXDisplay(),
+ s_pSaveYourselfFrame->GetShellWindow(),
+ (char**)argv, 2 );
+ if( pSaveFrame != s_pSaveYourselfFrame )
+ {
+ // check if it still exists
+ const X11SalFrame* pFrame = NULL;
+ const std::list< SalFrame* >& rFrames = static_cast<X11SalFrame*>(pSaveFrame)->GetDisplay()->getFrames();
+ std::list< SalFrame* >::const_iterator it = rFrames.begin();
+ while( it != rFrames.end() )
+ {
+ pFrame = static_cast< const X11SalFrame* >(*it);
+ if( pFrame == pSaveFrame )
+ break;
+ ++it;
+ }
+ if( pFrame == pSaveFrame )
+ {
+ const WMAdaptor& rWMAdaptor( *pFrame->pDisplay_->getWMAdaptor() );
+ XChangeProperty( pFrame->GetXDisplay(),
+ pFrame->GetShellWindow(),
+ rWMAdaptor.getAtom( WMAdaptor::WM_COMMAND ), XA_STRING, 8, PropModeReplace, (unsigned char*)"", 0 );
+ }
+ }
+ s_pSaveYourselfFrame->ShutDown();
+ }
+}
+
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+extern "C"
+{
+Bool call_checkKeyReleaseForRepeat( Display* pDisplay, XEvent* pCheck, XPointer pX11SalFrame )
+{
+ return X11SalFrame::checkKeyReleaseForRepeat( pDisplay, pCheck, pX11SalFrame );
+}
+}
+
+Bool X11SalFrame::checkKeyReleaseForRepeat( Display*, XEvent* pCheck, XPointer pX11SalFrame )
+{
+ X11SalFrame* pThis = (X11SalFrame*)pX11SalFrame;
+ return
+ pCheck->type == XLIB_KeyPress &&
+ pCheck->xkey.state == pThis->nKeyState_ &&
+ pCheck->xkey.keycode == pThis->nKeyCode_ &&
+ pCheck->xkey.time == pThis->nReleaseTime_ ? True : False;
+}
+
+long X11SalFrame::Dispatch( XEvent *pEvent )
+{
+ long nRet = 0;
+
+ if( -1 == nCaptured_ )
+ {
+ CaptureMouse( TRUE );
+#ifdef DBG_UTIL
+ if( -1 != nCaptured_ )
+ pDisplay_->PrintEvent( "Captured", pEvent );
+#endif
+ }
+
+ if( pEvent->xany.window == GetShellWindow() || pEvent->xany.window == GetWindow() )
+ {
+ switch( pEvent->type )
+ {
+ case XLIB_KeyPress:
+ nKeyCode_ = pEvent->xkey.keycode;
+ nKeyState_ = pEvent->xkey.state;
+ nRet = HandleKeyEvent( &pEvent->xkey );
+ break;
+
+ case KeyRelease:
+ if( -1 == nCompose_ )
+ {
+ nReleaseTime_ = pEvent->xkey.time;
+ XEvent aEvent;
+ if( XCheckIfEvent( pEvent->xkey.display, &aEvent, call_checkKeyReleaseForRepeat, (XPointer)this ) )
+ XPutBackEvent( pEvent->xkey.display, &aEvent );
+ else
+ nRet = HandleKeyEvent( &pEvent->xkey );
+ }
+ break;
+
+ case ButtonPress:
+ // #74406# if we loose the focus in presentation mode
+ // there are good chances that we never get it back
+ // since the WM ignores us
+ if( IsOverrideRedirect() )
+ {
+ XSetInputFocus( GetXDisplay(), GetShellWindow(),
+ RevertToNone, CurrentTime );
+ }
+
+ case ButtonRelease:
+ case MotionNotify:
+ case EnterNotify:
+ case LeaveNotify:
+ nRet = HandleMouseEvent( pEvent );
+ break;
+
+ case FocusIn:
+ case FocusOut:
+ nRet = HandleFocusEvent( &pEvent->xfocus );
+ break;
+
+ case Expose:
+ case GraphicsExpose:
+ nRet = HandleExposeEvent( pEvent );
+ break;
+
+ case MapNotify:
+ if( pEvent->xmap.window == GetShellWindow() )
+ {
+ if( nShowState_ == SHOWSTATE_HIDDEN )
+ {
+ /*
+ * #95097# workaround for (at least) KWin 2.2.2
+ * which will map windows that were once transient
+ * even if they are withdrawn when the respective
+ * document is mapped.
+ */
+ if( ! (nStyle_ & SAL_FRAME_STYLE_PLUG) )
+ XUnmapWindow( GetXDisplay(), GetShellWindow() );
+ break;
+ }
+ bMapped_ = TRUE;
+ bViewable_ = TRUE;
+ nRet = TRUE;
+ if ( mpInputContext != NULL )
+ mpInputContext->Map( this );
+ CallCallback( SALEVENT_RESIZE, NULL );
+ if( pDisplay_->GetServerVendor() == vendor_hummingbird )
+ {
+ /*
+ * With Exceed sometimes there does not seem to be
+ * an Expose after the MapNotify.
+ * so start a delayed paint here
+ */
+ maPaintRegion.Union( Rectangle( Point( 0, 0 ), Size( maGeometry.nWidth, maGeometry.nHeight ) ) );
+ XEvent aEvent;
+ aEvent.xexpose.type = Expose;
+ aEvent.xexpose.display = pDisplay_->GetDisplay();
+ aEvent.xexpose.x = 0;
+ aEvent.xexpose.y = 0;
+ aEvent.xexpose.width = maGeometry.nWidth;
+ aEvent.xexpose.height = maGeometry.nHeight;
+ aEvent.xexpose.count = 0;
+ XSendEvent( pDisplay_->GetDisplay(),
+ GetWindow(),
+ True,
+ ExposureMask,
+ &aEvent );
+ }
+
+ /* #99570# another workaround for sawfish: if a transient window for the same parent is shown
+ * sawfish does not set the focus to it. Applies only for click to focus mode.
+ */
+ if( ! (nStyle_ & SAL_FRAME_STYLE_FLOAT ) && mbInShow && GetDisplay()->getWMAdaptor()->getWindowManagerName().EqualsAscii( "Sawfish" ) )
+ {
+ // #101775# don't set the focus into the IME status window
+ // since this will lead to a parent loose-focus, close status,
+ // reget focus, open status, .... flicker loop
+ if ( (I18NStatus::get().getStatusFrame() != this) )
+ XSetInputFocus( GetXDisplay(), GetShellWindow(), RevertToParent, CurrentTime );
+ }
+
+ /*
+ * sometimes a message box/dialogue is brought up when a frame is not mapped
+ * the corresponding TRANSIENT_FOR hint is then set to the root window
+ * so that the dialogue shows in all cases. Correct it here if the
+ * frame is shown afterwards.
+ */
+ if( ! IsChildWindow()
+ && ! IsOverrideRedirect()
+ && ! IsFloatGrabWindow()
+ )
+ {
+ for( std::list< X11SalFrame* >::const_iterator it = maChildren.begin();
+ it != maChildren.end(); ++it )
+ {
+ if( (*it)->mbTransientForRoot )
+ pDisplay_->getWMAdaptor()->changeReferenceFrame( *it, this );
+ }
+ }
+
+ if( hPresentationWindow != None && GetShellWindow() == hPresentationWindow )
+ XSetInputFocus( GetXDisplay(), GetShellWindow(), RevertToParent, CurrentTime );
+ /* For unknown reasons Dtwm does respect the input_hint
+ * set to False, but not when mapping the window. So
+ * emulate the correct behaviour and set the focus back
+ * to where it most probably should have been.
+ */
+ if( (nStyle_ & SAL_FRAME_STYLE_OWNERDRAWDECORATION) &&
+ mpParent &&
+ GetDisplay()->getWMAdaptor()->getWindowManagerName().EqualsAscii( "Dtwm" )
+ )
+ {
+ XSetInputFocus( GetXDisplay(),
+ mpParent->GetShellWindow(),
+ RevertToParent,
+ CurrentTime );
+ }
+
+ RestackChildren();
+ mbInShow = FALSE;
+ }
+ break;
+
+ case UnmapNotify:
+ if( pEvent->xunmap.window == GetShellWindow() )
+ {
+ bMapped_ = FALSE;
+ bViewable_ = FALSE;
+ nRet = TRUE;
+ if ( mpInputContext != NULL )
+ mpInputContext->Unmap( this );
+ CallCallback( SALEVENT_RESIZE, NULL );
+ }
+ break;
+
+ case ConfigureNotify:
+ if( pEvent->xconfigure.window == GetShellWindow()
+ || pEvent->xconfigure.window == GetWindow() )
+ nRet = HandleSizeEvent( &pEvent->xconfigure );
+ break;
+
+ case VisibilityNotify:
+ nVisibility_ = pEvent->xvisibility.state;
+ nRet = TRUE;
+ if( bAlwaysOnTop_
+ && bMapped_
+ && ! GetDisplay()->getWMAdaptor()->isAlwaysOnTopOK()
+ && nVisibility_ != VisibilityUnobscured )
+ maAlwaysOnTopRaiseTimer.Start();
+ break;
+
+ case ReparentNotify:
+ nRet = HandleReparentEvent( &pEvent->xreparent );
+ break;
+
+ case MappingNotify:
+ if( MappingPointer != pEvent->xmapping.request )
+ nRet = CallCallback( SALEVENT_KEYBOARDCHANGED, 0 );
+ break;
+
+ case ColormapNotify:
+ nRet = HandleColormapEvent( &pEvent->xcolormap );
+ break;
+
+ case PropertyNotify:
+ {
+ if( pEvent->xproperty.atom == pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_STATE ) )
+ nRet = HandleStateEvent( &pEvent->xproperty );
+ else
+ nRet = pDisplay_->getWMAdaptor()->handlePropertyNotify( this, &pEvent->xproperty );
+ break;
+ }
+
+ case ClientMessage:
+ nRet = HandleClientMessage( &pEvent->xclient );
+ break;
+ }
+ }
+ else
+ {
+ switch( pEvent->type )
+ {
+ case FocusIn:
+ case FocusOut:
+ if( ( nStyle_ & SAL_FRAME_STYLE_PLUG )
+ && ( pEvent->xfocus.window == GetShellWindow()
+ || pEvent->xfocus.window == GetForeignParent() )
+ )
+ {
+ nRet = HandleFocusEvent( &pEvent->xfocus );
+ }
+ break;
+
+ case ConfigureNotify:
+ if( pEvent->xconfigure.window == GetForeignParent() ||
+ pEvent->xconfigure.window == GetShellWindow() )
+ nRet = HandleSizeEvent( &pEvent->xconfigure );
+
+ if( pEvent->xconfigure.window == GetStackingWindow() )
+ nRet = HandleSizeEvent( &pEvent->xconfigure );
+
+ RestackChildren();
+ break;
+ }
+ }
+
+ return nRet;
+}
+
+void X11SalFrame::ResetClipRegion()
+{
+ delete [] m_pClipRectangles;
+ m_pClipRectangles = NULL;
+ m_nCurClipRect = m_nMaxClipRect = 0;
+
+ const int dest_kind = ShapeBounding;
+ const int op = ShapeSet;
+ const int ordering = YSorted;
+
+ XWindowAttributes win_attrib;
+ XRectangle win_size;
+
+ XLIB_Window aShapeWindow = mhShellWindow;
+
+ XGetWindowAttributes ( GetDisplay()->GetDisplay(),
+ aShapeWindow,
+ &win_attrib );
+
+ win_size.x = 0;
+ win_size.y = 0;
+ win_size.width = win_attrib.width;
+ win_size.height = win_attrib.height;
+
+ XShapeCombineRectangles ( GetDisplay()->GetDisplay(),
+ aShapeWindow,
+ dest_kind,
+ 0, 0, // x_off, y_off
+ &win_size, // list of rectangles
+ 1, // number of rectangles
+ op, ordering );
+}
+
+void X11SalFrame::BeginSetClipRegion( ULONG nRects )
+{
+ if( m_pClipRectangles )
+ delete [] m_pClipRectangles;
+ if( nRects )
+ m_pClipRectangles = new XRectangle[nRects];
+ else
+ m_pClipRectangles = NULL;
+ m_nMaxClipRect = static_cast<int>(nRects);
+ m_nCurClipRect = 0;
+}
+
+void X11SalFrame::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
+{
+ if( m_pClipRectangles && m_nCurClipRect < m_nMaxClipRect )
+ {
+ m_pClipRectangles[m_nCurClipRect].x = nX;
+ m_pClipRectangles[m_nCurClipRect].y = nY;
+ m_pClipRectangles[m_nCurClipRect].width = nWidth;
+ m_pClipRectangles[m_nCurClipRect].height = nHeight;
+ m_nCurClipRect++;
+ }
+}
+
+void X11SalFrame::EndSetClipRegion()
+{
+ const int dest_kind = ShapeBounding;
+ const int ordering = YSorted;
+ const int op = ShapeSet;
+
+ XLIB_Window aShapeWindow = mhShellWindow;
+ XShapeCombineRectangles ( GetDisplay()->GetDisplay(),
+ aShapeWindow,
+ dest_kind,
+ 0, 0, // x_off, y_off
+ m_pClipRectangles,
+ m_nCurClipRect,
+ op, ordering );
+
+}
+
diff --git a/vcl/unx/source/window/salmenu.cxx b/vcl/unx/source/window/salmenu.cxx
new file mode 100644
index 000000000000..0739b6cd5352
--- /dev/null
+++ b/vcl/unx/source/window/salmenu.cxx
@@ -0,0 +1,132 @@
+/*************************************************************************
+ *
+ * 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 <saldata.hxx>
+#include <salinst.h>
+#include <salmenu.h>
+
+
+// =======================================================================
+
+// X11SalInst factory methods
+
+SalMenu* X11SalInstance::CreateMenu( BOOL /*bMenuBar*/ )
+{
+ return NULL; // no support for native menues
+}
+
+void X11SalInstance::DestroyMenu( SalMenu* pSalMenu )
+{
+ delete pSalMenu;
+}
+
+
+SalMenuItem* X11SalInstance::CreateMenuItem( const SalItemParams* )
+{
+ return NULL; // no support for native menues
+}
+
+void X11SalInstance::DestroyMenuItem( SalMenuItem* pSalMenuItem )
+{
+ delete pSalMenuItem;
+}
+
+
+// =======================================================================
+
+
+/*
+ * X11SalMenu
+ */
+
+
+X11SalMenu::~X11SalMenu()
+{
+}
+
+BOOL X11SalMenu::VisibleMenuBar()
+{
+ return FALSE;
+}
+
+void X11SalMenu::SetFrame( const SalFrame* )
+{
+}
+
+void X11SalMenu::InsertItem( SalMenuItem*, unsigned )
+{
+}
+
+void X11SalMenu::RemoveItem( unsigned )
+{
+}
+
+void X11SalMenu::SetSubMenu( SalMenuItem*, SalMenu*, unsigned )
+{
+}
+
+void X11SalMenu::CheckItem( unsigned, BOOL )
+{
+}
+
+void X11SalMenu::EnableItem( unsigned, BOOL )
+{
+}
+
+void X11SalMenu::SetItemImage( unsigned, SalMenuItem*, const Image& )
+{
+}
+
+void X11SalMenu::SetItemText( unsigned, SalMenuItem*, const XubString& )
+{
+}
+
+void X11SalMenu::SetAccelerator( unsigned, SalMenuItem*, const KeyCode&, const XubString& )
+{
+}
+
+void X11SalMenu::GetSystemMenuData( SystemMenuData* )
+{
+}
+
+// =======================================================================
+
+/*
+ * SalMenuItem
+ */
+
+
+X11SalMenuItem::~X11SalMenuItem()
+{
+}
+
+// -------------------------------------------------------------------
+
diff --git a/vcl/unx/source/window/salobj.cxx b/vcl/unx/source/window/salobj.cxx
new file mode 100644
index 000000000000..647b95ae032c
--- /dev/null
+++ b/vcl/unx/source/window/salobj.cxx
@@ -0,0 +1,561 @@
+/*************************************************************************
+ *
+ * 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/prex.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/shape.h>
+#include <tools/postx.h>
+
+#include <salunx.h>
+#include <salstd.hxx>
+#include <saldata.hxx>
+#ifndef _SV_SALINST_HXX
+#include <salinst.h>
+#endif
+#include <saldisp.hxx>
+#ifndef _SV_SALFRAME_HXX
+#include <salframe.h>
+#endif
+#include <salobj.h>
+#include <vcl/salwtype.hxx>
+#include <vcl/keycodes.hxx>
+
+#include <tools/debug.hxx>
+#if OSL_DEBUG_LEVEL > 1
+#include <stdio.h>
+#endif
+
+// =======================================================================
+// SalInstance member to create and destroy a SalObject
+
+SalObject* X11SalInstance::CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, BOOL bShow )
+{
+ return X11SalObject::CreateObject( pParent, pWindowData, bShow );
+}
+
+X11SalObject* X11SalObject::CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, BOOL bShow )
+{
+ int error_base, event_base;
+ X11SalObject* pObject = new X11SalObject();
+ SystemChildData* pObjData = const_cast<SystemChildData*>(pObject->GetSystemData());
+
+ if ( ! XShapeQueryExtension( (Display*)pObjData->pDisplay,
+ &event_base, &error_base ) )
+ {
+ delete pObject;
+ return NULL;
+ }
+
+ pObject->mpParent = pParent;
+
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ const SystemEnvData* pEnv = pParent->GetSystemData();
+ Display* pDisp = pSalDisp->GetDisplay();
+ XLIB_Window aObjectParent = (XLIB_Window)pEnv->aWindow;
+
+ // find out on which screen that window is
+ XWindowAttributes aParentAttr;
+ XGetWindowAttributes( pDisp, aObjectParent, &aParentAttr );
+ int nScreen = XScreenNumberOfScreen( aParentAttr.screen );
+ Visual* pVisual = (pWindowData && pWindowData->pVisual) ?
+ (Visual*)pWindowData->pVisual :
+ pSalDisp->GetVisual( nScreen ).GetVisual();
+ // get visual info
+ VisualID aVisID = XVisualIDFromVisual( pVisual );
+ XVisualInfo aTemplate;
+ aTemplate.visualid = aVisID;
+ int nVisuals = 0;
+ XVisualInfo* pInfos = XGetVisualInfo( pDisp, VisualIDMask, &aTemplate, &nVisuals );
+ // only one VisualInfo structure can match the visual id
+ DBG_ASSERT( nVisuals == 1, "match count for visual id is not 1" );
+ unsigned int nDepth = pInfos->depth;
+ XFree( pInfos );
+ XSetWindowAttributes aAttribs;
+ aAttribs.event_mask = StructureNotifyMask
+ | ButtonPressMask
+ | ButtonReleaseMask
+ | PointerMotionMask
+ | EnterWindowMask
+ | LeaveWindowMask
+ | FocusChangeMask
+ | ExposureMask
+ ;
+
+ pObject->maPrimary =
+ XCreateSimpleWindow( pDisp,
+ aObjectParent,
+ 0, 0,
+ 1, 1, 0,
+ pSalDisp->GetColormap( nScreen ).GetBlackPixel(),
+ pSalDisp->GetColormap( nScreen ).GetWhitePixel()
+ );
+ if( aVisID == pSalDisp->GetVisual( nScreen ).GetVisualId() )
+ {
+ pObject->maSecondary =
+ XCreateSimpleWindow( pDisp,
+ pObject->maPrimary,
+ 0, 0,
+ 1, 1, 0,
+ pSalDisp->GetColormap( nScreen ).GetBlackPixel(),
+ pSalDisp->GetColormap( nScreen ).GetWhitePixel()
+ );
+ }
+ else
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "visual id of vcl %x, of visual %x\n",
+ static_cast<unsigned int> (pSalDisp->GetVisual( nScreen ).GetVisualId()),
+ static_cast<unsigned int> (aVisID) );
+ #endif
+ pSalDisp->GetXLib()->PushXErrorLevel( true );
+
+ // create colormap for visual - there might not be one
+ pObject->maColormap = aAttribs.colormap = XCreateColormap(
+ pDisp,
+ pSalDisp->GetRootWindow( nScreen ),
+ pVisual,
+ AllocNone );
+
+ pObject->maSecondary =
+ XCreateWindow( pDisp,
+ pSalDisp->GetRootWindow( nScreen ),
+ 0, 0,
+ 1, 1, 0,
+ nDepth, InputOutput,
+ pVisual,
+ CWEventMask|CWColormap, &aAttribs );
+ XSync( pDisp, False );
+ BOOL bWasXError = pSalDisp->GetXLib()->HasXErrorOccured();
+ pSalDisp->GetXLib()->PopXErrorLevel();
+ if( bWasXError )
+ {
+ pObject->maSecondary = None;
+ delete pObject;
+ return NULL;
+ }
+ XReparentWindow( pDisp, pObject->maSecondary, pObject->maPrimary, 0, 0 );
+ }
+
+ pSalDisp->GetXLib()->PushXErrorLevel( true );
+ if( bShow ) {
+ XMapWindow( pDisp, pObject->maSecondary );
+ XMapWindow( pDisp, pObject->maPrimary );
+ }
+
+ pObjData->pDisplay = pDisp;
+ pObjData->aWindow = pObject->maSecondary;
+ pObjData->pWidget = NULL;
+ pObjData->pVisual = pVisual;
+ pObjData->nDepth = nDepth;
+ pObjData->aColormap = aVisID == pSalDisp->GetVisual( nScreen ).GetVisualId() ?
+ pSalDisp->GetColormap( nScreen ).GetXColormap() : None;
+ pObjData->pAppContext = NULL;
+
+ XSync(pDisp, False);
+ BOOL bWasXError = pSalDisp->GetXLib()->HasXErrorOccured();
+ pSalDisp->GetXLib()->PopXErrorLevel();
+ if( bWasXError )
+ {
+ delete pObject;
+ return NULL;
+ }
+
+ return pObject;
+}
+
+
+void X11SalInstance::DestroyObject( SalObject* pObject )
+{
+ delete pObject;
+}
+
+
+// ======================================================================
+// SalClipRegion is a member of SalObject
+// definition of SalClipRegion my be found in unx/inc/salobj.h
+
+
+SalClipRegion::SalClipRegion()
+{
+ ClipRectangleList = NULL;
+ numClipRectangles = 0;
+ maxClipRectangles = 0;
+ nClipRegionType = SAL_OBJECT_CLIP_INCLUDERECTS;
+}
+
+
+SalClipRegion::~SalClipRegion()
+{
+ if ( ClipRectangleList )
+ delete [] ClipRectangleList;
+}
+
+
+void
+SalClipRegion::BeginSetClipRegion( ULONG nRects )
+{
+ if (ClipRectangleList)
+ delete [] ClipRectangleList;
+
+ ClipRectangleList = new XRectangle[nRects];
+ numClipRectangles = 0;
+ maxClipRectangles = nRects;
+}
+
+
+void
+SalClipRegion::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
+{
+ if ( nWidth && nHeight && (numClipRectangles < maxClipRectangles) )
+ {
+ XRectangle *aRect = ClipRectangleList + numClipRectangles;
+
+ aRect->x = (short) nX;
+ aRect->y = (short) nY;
+ aRect->width = (unsigned short) nWidth;
+ aRect->height= (unsigned short) nHeight;
+
+ numClipRectangles++;
+ }
+}
+
+
+// =======================================================================
+// SalObject Implementation
+
+
+X11SalObject::X11SalObject()
+{
+ maSystemChildData.nSize = sizeof( SystemChildData );
+ maSystemChildData.pDisplay = GetX11SalData()->GetDisplay()->GetDisplay();
+ maSystemChildData.aWindow = None;
+ maSystemChildData.pSalFrame = 0;
+ maSystemChildData.pWidget = 0;
+ maSystemChildData.pVisual = 0;
+ maSystemChildData.nDepth = 0;
+ maSystemChildData.aColormap = 0;
+ maSystemChildData.pAppContext = NULL;
+ maSystemChildData.aShellWindow = 0;
+ maSystemChildData.pShellWidget = NULL;
+ maPrimary = 0;
+ maSecondary = 0;
+ maColormap = 0;
+
+ std::list< SalObject* >& rObjects = GetX11SalData()->GetDisplay()->getSalObjects();
+ rObjects.push_back( this );
+}
+
+
+X11SalObject::~X11SalObject()
+{
+ std::list< SalObject* >& rObjects = GetX11SalData()->GetDisplay()->getSalObjects();
+ rObjects.remove( this );
+ SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
+ pSalDisp->GetXLib()->PushXErrorLevel( true );
+ if ( maSecondary )
+ XDestroyWindow( (Display*)maSystemChildData.pDisplay, maSecondary );
+ if ( maPrimary )
+ XDestroyWindow( (Display*)maSystemChildData.pDisplay, maPrimary );
+ if ( maColormap )
+ XFreeColormap((Display*)maSystemChildData.pDisplay, maColormap);
+ XSync( (Display*)maSystemChildData.pDisplay, False );
+ pSalDisp->GetXLib()->PopXErrorLevel();
+}
+
+
+void
+X11SalObject::ResetClipRegion()
+{
+ maClipRegion.ResetClipRegion();
+
+ const int dest_kind = ShapeBounding;
+ const int op = ShapeSet;
+ const int ordering = YSorted;
+
+ XWindowAttributes win_attrib;
+ XRectangle win_size;
+
+ XLIB_Window aShapeWindow = maPrimary;
+
+ XGetWindowAttributes ( (Display*)maSystemChildData.pDisplay,
+ aShapeWindow,
+ &win_attrib );
+
+ win_size.x = 0;
+ win_size.y = 0;
+ win_size.width = win_attrib.width;
+ win_size.height = win_attrib.height;
+
+ XShapeCombineRectangles ( (Display*)maSystemChildData.pDisplay,
+ aShapeWindow,
+ dest_kind,
+ 0, 0, // x_off, y_off
+ &win_size, // list of rectangles
+ 1, // number of rectangles
+ op, ordering );
+}
+
+
+void
+X11SalObject::BeginSetClipRegion( ULONG nRectCount )
+{
+ maClipRegion.BeginSetClipRegion ( nRectCount );
+}
+
+
+void
+X11SalObject::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
+{
+ maClipRegion.UnionClipRegion ( nX, nY, nWidth, nHeight );
+}
+
+
+void
+X11SalObject::EndSetClipRegion()
+{
+ XRectangle *pRectangles = maClipRegion.EndSetClipRegion ();
+ const int nType = maClipRegion.GetClipRegionType();
+ const int nRectangles = maClipRegion.GetRectangleCount();
+
+ const int dest_kind = ShapeBounding;
+ const int ordering = YSorted;
+ int op;
+
+ switch ( nType )
+ {
+ case SAL_OBJECT_CLIP_INCLUDERECTS :
+ op = ShapeSet;
+ break;
+ case SAL_OBJECT_CLIP_EXCLUDERECTS :
+ op = ShapeSubtract;
+ break;
+ case SAL_OBJECT_CLIP_ABSOLUTE :
+ op = ShapeSet;
+ break;
+ default :
+ op = ShapeUnion;
+ }
+
+ XLIB_Window aShapeWindow = maPrimary;
+
+ XShapeCombineRectangles ( (Display*)maSystemChildData.pDisplay,
+ aShapeWindow,
+ dest_kind,
+ 0, 0, // x_off, y_off
+ pRectangles,
+ nRectangles,
+ op, ordering );
+}
+
+
+USHORT
+X11SalObject::GetClipRegionType()
+{
+ return maClipRegion.GetClipRegionType();
+}
+
+// -----------------------------------------------------------------------
+
+void
+X11SalObject::SetPosSize( long nX, long nY, long nWidth, long nHeight )
+{
+ if ( maPrimary && maSecondary && nWidth && nHeight )
+ {
+ XMoveResizeWindow( (Display*)maSystemChildData.pDisplay,
+ maPrimary,
+ nX, nY, nWidth, nHeight );
+ XMoveResizeWindow( (Display*)maSystemChildData.pDisplay,
+ maSecondary,
+ 0, 0, nWidth, nHeight );
+ }
+}
+
+
+void
+X11SalObject::Show( BOOL bVisible )
+{
+ if ( ! maSystemChildData.aWindow )
+ return;
+
+ if ( bVisible ) {
+ XMapWindow( (Display*)maSystemChildData.pDisplay,
+ maSecondary );
+ XMapWindow( (Display*)maSystemChildData.pDisplay,
+ maPrimary );
+ } else {
+ XUnmapWindow( (Display*)maSystemChildData.pDisplay,
+ maPrimary );
+ XUnmapWindow( (Display*)maSystemChildData.pDisplay,
+ maSecondary );
+ }
+ mbVisible = bVisible;
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalObject::Enable( BOOL )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalObject::GrabFocus()
+{
+ if( mbVisible )
+ XSetInputFocus( (Display*)maSystemChildData.pDisplay,
+ maSystemChildData.aWindow,
+ RevertToNone,
+ CurrentTime );
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalObject::SetBackground()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void X11SalObject::SetBackground( SalColor )
+{
+}
+
+// -----------------------------------------------------------------------
+
+const SystemChildData* X11SalObject::GetSystemData() const
+{
+ return &maSystemChildData;
+}
+
+static USHORT sal_GetCode( int state )
+{
+ USHORT nCode = 0;
+
+ if( state & Button1Mask )
+ nCode |= MOUSE_LEFT;
+ if( state & Button2Mask )
+ nCode |= MOUSE_MIDDLE;
+ if( state & Button3Mask )
+ nCode |= MOUSE_RIGHT;
+
+ if( state & ShiftMask )
+ nCode |= KEY_SHIFT;
+ if( state & ControlMask )
+ nCode |= KEY_MOD1;
+ if( state & Mod1Mask )
+ nCode |= KEY_MOD2;
+ if( state & Mod3Mask )
+ nCode |= KEY_MOD3;
+
+ return nCode;
+}
+
+long X11SalObject::Dispatch( XEvent* pEvent )
+{
+ std::list< SalObject* >& rObjects = GetX11SalData()->GetDisplay()->getSalObjects();
+
+ for( std::list< SalObject* >::iterator it = rObjects.begin(); it != rObjects.end(); ++it )
+ {
+ X11SalObject* pObject = static_cast<X11SalObject*>(*it);
+ if( pEvent->xany.window == pObject->maPrimary ||
+ pEvent->xany.window == pObject->maSecondary )
+ {
+ if( pObject->IsMouseTransparent() && (
+ pEvent->type == ButtonPress ||
+ pEvent->type == ButtonRelease ||
+ pEvent->type == EnterNotify ||
+ pEvent->type == LeaveNotify ||
+ pEvent->type == MotionNotify
+ )
+ )
+ {
+ SalMouseEvent aEvt;
+ const SystemEnvData* pParentData = pObject->mpParent->GetSystemData();
+ int dest_x, dest_y;
+ XLIB_Window aChild = None;
+ XTranslateCoordinates( pEvent->xbutton.display,
+ pEvent->xbutton.root,
+ pParentData->aWindow,
+ pEvent->xbutton.x_root,
+ pEvent->xbutton.y_root,
+ &dest_x, &dest_y,
+ &aChild );
+ aEvt.mnX = dest_x;
+ aEvt.mnY = dest_y;
+ aEvt.mnTime = pEvent->xbutton.time;
+ aEvt.mnCode = sal_GetCode( pEvent->xbutton.state );
+ aEvt.mnButton = 0;
+ USHORT nEvent = 0;
+ if( pEvent->type == ButtonPress ||
+ pEvent->type == ButtonRelease )
+ {
+ switch( pEvent->xbutton.button )
+ {
+ case Button1: aEvt.mnButton = MOUSE_LEFT;break;
+ case Button2: aEvt.mnButton = MOUSE_MIDDLE;break;
+ case Button3: aEvt.mnButton = MOUSE_RIGHT;break;
+ }
+ nEvent = (pEvent->type == ButtonPress) ?
+ SALEVENT_MOUSEBUTTONDOWN :
+ SALEVENT_MOUSEBUTTONUP;
+ }
+ else if( pEvent->type == EnterNotify )
+ nEvent = SALEVENT_MOUSELEAVE;
+ else
+ nEvent = SALEVENT_MOUSEMOVE;
+ pObject->mpParent->CallCallback( nEvent, &aEvt );
+ }
+ else
+ {
+ switch( pEvent->type )
+ {
+ case UnmapNotify:
+ pObject->mbVisible = FALSE;
+ return 1;
+ case MapNotify:
+ pObject->mbVisible = TRUE;
+ return 1;
+ case ButtonPress:
+ pObject->CallCallback( SALOBJ_EVENT_TOTOP, NULL );
+ return 1;
+ case FocusIn:
+ pObject->CallCallback( SALOBJ_EVENT_GETFOCUS, NULL );
+ return 1;
+ case FocusOut:
+ pObject->CallCallback( SALOBJ_EVENT_LOSEFOCUS, NULL );
+ return 1;
+ default: break;
+ }
+ }
+ return 0;
+ }
+ }
+ return 0;
+}
diff --git a/vcl/util/hidother.src b/vcl/util/hidother.src
new file mode 100644
index 000000000000..f966fcded1b3
--- /dev/null
+++ b/vcl/util/hidother.src
@@ -0,0 +1,31 @@
+/*************************************************************************
+ *
+ * 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"
+
+hidspecial HID_PRINTDLG { HelpID = HID_PRINTDLG; };
+
diff --git a/vcl/util/linksvp/makefile.mk b/vcl/util/linksvp/makefile.mk
new file mode 100644
index 000000000000..99d1c4537111
--- /dev/null
+++ b/vcl/util/linksvp/makefile.mk
@@ -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.
+#
+#*************************************************************************
+
+PRJ=..$/..
+
+PRJNAME=vcl
+TARGET=svp
+TARGETTYPE=CUI
+
+# --- Settings -----------------------------------------------------------
+
+.INCLUDE : settings.mk
+
+.IF "$(OS)" == "SOLARIS"
+LINKFLAGSRUNPATH_OOO := -R/usr/sfw/lib $(LINKFLAGSRUNPATH_OOO)
+.ENDIF
+
+.IF "$(GUIBASE)" == "unx"
+# headless plugin
+LIB1TARGET=$(SLB)$/isvpplug
+LIB1FILES= $(SLB)$/svpplug.lib \
+ $(SLB)$/printergfx.lib
+SHL1TARGET=vclplug_svp$(DLLPOSTFIX)
+SHL1IMPLIB=isvpplug
+SHL1LIBS=$(LIB1TARGET)
+SHL1DEPN=$(LB)$/libvcl$(DLLPOSTFIX)$(DLLPOST)
+SHL1STDLIBS=\
+ $(VCLLIB)\
+ $(I18NPAPERLIB)\
+ $(BASEBMPLIB)\
+ $(BASEGFXLIB)\
+ $(TOOLSLIB) \
+ $(VOSLIB) \
+ $(SALLIB)
+.ENDIF # GUIBASE unx
+
+
+# --- Allgemein ----------------------------------------------------------
+
+.INCLUDE : target.mk
+
diff --git a/vcl/util/makefile.mk b/vcl/util/makefile.mk
new file mode 100644
index 000000000000..eb54531c375c
--- /dev/null
+++ b/vcl/util/makefile.mk
@@ -0,0 +1,460 @@
+#*************************************************************************
+#
+# 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=vcl
+TARGETTYPE=GUI
+USE_DEFFILE=TRUE
+GEN_HID_OTHER=TRUE
+
+.IF "$(SNDFILE_LIBS)"!=""
+SNDFILELIB=$(SNDFILE_LIBS)
+.ENDIF
+
+# --- Settings -----------------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : makefile.pmk
+.INCLUDE : makefile2.pmk
+
+.IF "$(OS)" == "SOLARIS"
+.IF "$(CPUNAME)" == "SPARC" && "$(CPU)" == "U"
+LINKFLAGSRUNPATH_OOO := -R/usr/sfw/lib/64 $(LINKFLAGSRUNPATH_OOO)
+.ELSE
+LINKFLAGSRUNPATH_OOO := -R/usr/sfw/lib $(LINKFLAGSRUNPATH_OOO)
+.ENDIF
+.ENDIF
+
+# --- Allgemein ----------------------------------------------------------
+
+HXXDEPNLST= $(INC)$/vcl$/accel.hxx \
+ $(INC)$/vcl$/animate.hxx \
+ $(INC)$/vcl$/apptypes.hxx \
+ $(INC)$/vcl$/bitmap.hxx \
+ $(INC)$/vcl$/bitmapex.hxx \
+ $(INC)$/vcl$/bmpacc.hxx \
+ $(INC)$/vcl$/btndlg.hxx \
+ $(INC)$/vcl$/button.hxx \
+ $(INC)$/vcl$/ctrl.hxx \
+ $(INC)$/vcl$/cursor.hxx \
+ $(INC)$/vcl$/cmdevt.hxx \
+ $(INC)$/vcl$/decoview.hxx \
+ $(INC)$/vcl$/dialog.hxx \
+ $(INC)$/vcl$/dllapi.h \
+ $(INC)$/vcl$/dockwin.hxx \
+ $(INC)$/vcl$/edit.hxx \
+ $(INC)$/vcl$/event.hxx \
+ $(INC)$/vcl$/field.hxx \
+ $(INC)$/vcl$/fixed.hxx \
+ $(INC)$/vcl$/floatwin.hxx \
+ $(INC)$/vcl$/font.hxx \
+ $(INC)$/vcl$/floatwin.hxx \
+ $(INC)$/vcl$/graph.hxx \
+ $(INC)$/vcl$/group.hxx \
+ $(INC)$/vcl$/help.hxx \
+ $(INC)$/vcl$/jobset.hxx \
+ $(INC)$/vcl$/keycodes.hxx \
+ $(INC)$/vcl$/keycod.hxx \
+ $(INC)$/vcl$/image.hxx \
+ $(INC)$/vcl$/lstbox.h \
+ $(INC)$/vcl$/lstbox.hxx \
+ $(INC)$/vcl$/mapmod.hxx \
+ $(INC)$/vcl$/metaact.hxx \
+ $(INC)$/vcl$/menu.hxx \
+ $(INC)$/vcl$/menubtn.hxx \
+ $(INC)$/vcl$/metric.hxx \
+ $(INC)$/vcl$/morebtn.hxx \
+ $(INC)$/vcl$/msgbox.hxx \
+ $(INC)$/vcl$/octree.hxx \
+ $(INC)$/vcl$/outdev.hxx \
+ $(INC)$/vcl$/pointr.hxx \
+ $(INC)$/vcl$/ptrstyle.hxx \
+ $(INC)$/vcl$/prntypes.hxx \
+ $(INC)$/vcl$/print.hxx \
+ $(INC)$/vcl$/prndlg.hxx \
+ $(INC)$/vcl$/region.hxx \
+ $(INC)$/vcl$/salbtype.hxx \
+ $(INC)$/vcl$/scrbar.hxx \
+ $(INC)$/vcl$/slider.hxx \
+ $(INC)$/vcl$/seleng.hxx \
+ $(INC)$/vcl$/settings.hxx \
+ $(INC)$/vcl$/sound.hxx \
+ $(INC)$/vcl$/sndstyle.hxx \
+ $(INC)$/vcl$/split.hxx \
+ $(INC)$/vcl$/splitwin.hxx \
+ $(INC)$/vcl$/spin.hxx \
+ $(INC)$/vcl$/spinfld.hxx \
+ $(INC)$/vcl$/status.hxx \
+ $(INC)$/vcl$/stdtext.hxx \
+ $(INC)$/vcl$/sv.h \
+ $(INC)$/vcl$/svapp.hxx \
+ $(INC)$/vcl$/syschild.hxx \
+ $(INC)$/vcl$/sysdata.hxx \
+ $(INC)$/vcl$/syswin.hxx \
+ $(INC)$/vcl$/tabctrl.hxx \
+ $(INC)$/vcl$/tabdlg.hxx \
+ $(INC)$/vcl$/tabpage.hxx \
+ $(INC)$/vcl$/toolbox.hxx \
+ $(INC)$/vcl$/timer.hxx \
+ $(INC)$/vcl$/virdev.hxx \
+ $(INC)$/vcl$/wall.hxx \
+ $(INC)$/vcl$/waitobj.hxx \
+ $(INC)$/vcl$/wintypes.hxx \
+ $(INC)$/vcl$/window.hxx \
+ $(INC)$/vcl$/wrkwin.hxx
+
+.IF "$(linkinc)" != ""
+SHL11FILE= $(MISC)$/app.slo
+SHL12FILE= $(MISC)$/gdi.slo
+SHL13FILE= $(MISC)$/win.slo
+SHL14FILE= $(MISC)$/ctrl.slo
+#SHL15FILE= $(MISC)$/ex.slo
+SHL16FILE= $(MISC)$/salapp.slo
+SHL17FILE= $(MISC)$/salwin.slo
+SHL18FILE= $(MISC)$/salgdi.slo
+.ENDIF
+
+LIB1TARGET= $(SLB)$/$(TARGET).lib
+LIB1FILES= $(SLB)$/app.lib \
+ $(SLB)$/gdi.lib \
+ $(SLB)$/win.lib \
+ $(SLB)$/ctrl.lib \
+ $(SLB)$/helper.lib \
+ $(SLB)$/fontsubset.lib \
+ $(SLB)$/components.lib
+
+.IF "$(GUI)" == "UNX" && "$(GUIBASE)"!="aqua"
+LIB1FILES+= $(SLB)$/salplug.lib \
+ $(SLB)$/fontman.lib \
+ $(SLB)$/printer.lib
+.ELSE
+LIB1FILES+= \
+ $(SLB)$/salwin.lib \
+ $(SLB)$/salgdi.lib \
+ $(SLB)$/salapp.lib
+.IF "$(GUIBASE)" == "aqua"
+LIB1FILES+= $(SLB)$/dtransaqua.lib
+.ENDIF
+.ENDIF
+
+SHL1TARGET= vcl$(DLLPOSTFIX)
+SHL1IMPLIB= ivcl
+SHL1STDLIBS+=\
+ $(SOTLIB) \
+ $(UNOTOOLSLIB) \
+ $(TOOLSLIB) \
+ $(I18NPAPERLIB) \
+ $(I18NISOLANGLIB) \
+ $(I18NUTILLIB) \
+ $(COMPHELPERLIB) \
+ $(UCBHELPERLIB) \
+ $(CPPUHELPERLIB) \
+ $(CPPULIB) \
+ $(VOSLIB) \
+ $(SALLIB) \
+ $(BASEGFXLIB) \
+ $(ICUUCLIB) \
+ $(ICUDATALIB) \
+ $(ICULELIB) \
+ $(JVMACCESSLIB)
+
+.IF "$(GUI)" == "UNX"
+.IF "$(ENABLE_GRAPHITE)" != ""
+.IF "$(SYSTEM_GRAPHITE)" == "YES"
+SHL1STDLIBS+= $(GRAPHITE_LIBS)
+.ELSE
+SHL1STDLIBS+= $(SOLARVERSION)/$(INPATH)/lib$(UPDMINOREXT)/libgraphite.a
+.ENDIF
+.ENDIF
+.ENDIF
+SHL1USE_EXPORTS=name
+
+.IF "$(GUIBASE)"=="aqua"
+SHL1STDLIBS+= \
+ $(BASEBMPLIB) \
+ -lAppleRemote$(DLLPOSTFIX) \
+ -framework QuickTime
+
+LIB1FILES+= \
+ $(SLB)$/sala11y.lib
+.ENDIF
+
+.IF "$(USE_BUILTIN_RASTERIZER)"!=""
+ LIB1FILES += $(SLB)$/glyphs.lib
+ SHL1STDLIBS+= $(FREETYPELIB)
+.ELSE
+.IF "$(ENABLE_GRAPHITE)" == "TRUE"
+ LIB1FILES += $(SLB)$/glyphs.lib
+.ENDIF
+.ENDIF # USE_BUILTIN_RASTERIZER
+
+SHL1LIBS= $(LIB1TARGET)
+.IF "$(GUI)"!="UNX"
+.IF "$(COM)"!="GCC"
+#SHL1OBJS= $(SLO)$/salshl.obj
+.ENDIF
+.ENDIF
+
+.IF "$(GUI)" != "UNX"
+SHL1RES= $(RES)$/salsrc.res
+.ENDIF
+
+SHL1DEF= $(MISC)$/$(SHL1TARGET).def
+
+DEF1NAME =$(SHL1TARGET)
+DEF1DEPN = $(HXXDEPNLST) \
+ $(LIB1TARGET)
+DEF1DES =VCL
+DEFLIB1NAME =vcl
+
+# --- W32 ----------------------------------------------------------------
+
+.IF "$(GUI)" == "WNT"
+
+.IF "$(ENABLE_GRAPHITE)" == "TRUE"
+.IF "$(COM)" == "GCC"
+SHL1STDLIBS += -lgraphite
+.ELSE
+SHL1STDLIBS += graphite_dll.lib
+.ENDIF
+.ENDIF
+
+SHL1STDLIBS += $(UWINAPILIB) \
+ $(GDI32LIB) \
+ $(GDIPLUSLIB) \
+ $(MSIMG32LIB) \
+ $(WINSPOOLLIB) \
+ $(OLE32LIB) \
+ $(SHELL32LIB) \
+ $(ADVAPI32LIB)
+
+SHL1STDLIBS += $(IMM32LIB)
+
+.IF "$(GUI)$(COM)$(CPU)" == "WNTMSCI"
+LINKFLAGSSHL += /ENTRY:LibMain@12
+.ENDIF
+.ENDIF
+
+# --- OS2 ----------------------------------------------------------------
+
+.IF "$(GUI)" == "OS2"
+STDSHL1 += ft2lib.lib
+.ENDIF
+
+# --- UNX ----------------------------------------------------------------
+
+# UNX sal plugins
+.IF "$(GUI)" == "UNX" && "$(GUIBASE)" != "aqua"
+
+# desktop detector
+LIB7TARGET=$(SLB)$/idet
+LIB7FILES=$(SLB)$/dtdetect.lib
+SHL7TARGET=desktop_detector$(DLLPOSTFIX)
+SHL7STDLIBS=\
+ $(SALLIB) \
+ $(X11LINK_DYNAMIC)
+SHL7IMPLIB=idet
+SHL7LIBS=$(LIB7TARGET)
+
+# basic pure X11 plugin
+LIB2TARGET=$(SLB)$/ipure_x
+LIB2FILES= \
+ $(SLB)$/dtransX11.lib \
+ $(SLB)$/printergfx.lib \
+ $(SLB)$/salwin.lib \
+ $(SLB)$/salgdi.lib \
+ $(SLB)$/salapp.lib
+SHL2TARGET=vclplug_gen$(DLLPOSTFIX)
+SHL2IMPLIB=ipure_x
+SHL2LIBS=$(LIB2TARGET)
+SHL2DEPN=$(SHL1IMPLIBN) $(SHL1TARGETN)
+
+# libs for generic plugin
+SHL2STDLIBS=\
+ $(VCLLIB)\
+ $(I18NPAPERLIB) \
+ $(I18NISOLANGLIB) \
+ $(TOOLSLIB) \
+ $(VOSLIB) \
+ $(BASEGFXLIB) \
+ $(UNOTOOLSLIB) \
+ $(COMPHELPERLIB) \
+ $(CPPUHELPERLIB) \
+ $(CPPULIB) \
+ $(SALLIB)
+
+# prepare linking of Xinerama
+.IF "$(USE_XINERAMA)" != "NO"
+
+.IF "$(OS)"=="MACOSX"
+XINERAMALIBS=-lXinerama
+.ELSE
+.IF "$(OS)" != "SOLARIS" || "$(USE_XINERAMA_VERSION)" == "Xorg"
+.IF "$(XINERAMA_LINK)" == "dynamic"
+XINERAMALIBS= -lXinerama
+.ELSE
+XINERAMALIBS= -Wl,-Bstatic -lXinerama -Wl,-Bdynamic
+.ENDIF # XINERAMA_LINK == dynamic
+.ENDIF # OS == SOLARIS
+.ENDIF # OS == MACOSX
+
+SHL2STDLIBS += $(XINERAMALIBS)
+.ENDIF # USE_XINERAMA != NO
+
+.IF "$(XRENDER_LINK)" == "YES"
+SHL2STDLIBS+=`pkg-config --libs xrender`
+.ENDIF
+
+.IF "$(GUIBASE)"=="unx"
+
+SHL2STDLIBS += -lXext -lSM -lICE -lX11
+.IF "$(OS)"!="MACOSX" && "$(OS)"!="FREEBSD" && "$(OS)"!="NETBSD"
+# needed by salprnpsp.cxx
+SHL2STDLIBS+= -ldl
+.ENDIF
+
+.IF "$(ENABLE_RANDR)" != ""
+.IF "$(XRANDR_DLOPEN)" == "FALSE"
+SHL2STDLIBS+= $(XRANDR_LIBS)
+.ENDIF
+.ENDIF
+
+.ENDIF # "$(GUIBASE)"=="unx"
+
+# gtk plugin
+.IF "$(ENABLE_GTK)" != ""
+PKGCONFIG_MODULES=gtk+-2.0 gthread-2.0
+.IF "$(ENABLE_DBUS)" != ""
+PKGCONFIG_MODULES+= dbus-glib-1
+.ENDIF
+.INCLUDE: pkg_config.mk
+
+LIB4TARGET=$(SLB)$/igtk_plug_
+LIB4FILES=\
+ $(SLB)$/gtkapp.lib\
+ $(SLB)$/gtka11y.lib \
+ $(SLB)$/gtkgdi.lib\
+ $(SLB)$/gtkwin.lib
+
+SHL4TARGET=vclplug_gtk$(DLLPOSTFIX)
+SHL4IMPLIB=igtk_plug_
+SHL4LIBS=$(LIB4TARGET)
+SHL4DEPN=$(SHL1IMPLIBN) $(SHL1TARGETN) $(SHL2IMPLIBN) $(SHL2TARGETN)
+# libs for gtk plugin
+SHL4STDLIBS+=$(PKGCONFIG_LIBS:s/ -lpangoxft-1.0//)
+# hack for faked SO environment
+.IF "$(PKGCONFIG_ROOT)"!=""
+SHL4SONAME+=-z nodefs
+SHL4NOCHECK=TRUE
+.ENDIF # "$(PKGCONFIG_ROOT)"!=""
+
+
+SHL4STDLIBS+=-l$(SHL2TARGET)
+SHL4STDLIBS+=\
+ $(VCLLIB) \
+ $(TOOLSLIB) \
+ $(CPPUHELPERLIB) \
+ $(CPPULIB) \
+ $(VOSLIB) \
+ $(SALLIB) \
+ $(X11LINK_DYNAMIC)
+
+.IF "$(ENABLE_RANDR)" != ""
+.IF "$(XRANDR_DLOPEN)" == "FALSE"
+SHL4STDLIBS+= $(XRANDR_LIBS)
+.ENDIF
+.ENDIF
+
+.ENDIF # "$(ENABLE_GTK)" != ""
+
+# KDE plugin
+.IF "$(ENABLE_KDE)" != ""
+.IF "$(KDE_ROOT)"!=""
+EXTRALIBPATHS+=-L$(KDE_ROOT)$/lib
+.ENDIF
+LIB5TARGET=$(SLB)$/ikde_plug_
+LIB5FILES=$(SLB)$/kdeplug.lib
+SHL5TARGET=vclplug_kde$(DLLPOSTFIX)
+SHL5IMPLIB=ikde_plug_
+SHL5LIBS=$(LIB5TARGET)
+SHL5DEPN=$(SHL2TARGETN)
+# libs for KDE plugin
+SHL5LINKFLAGS+=$(KDE_LIBS)
+SHL5STDLIBS+=-l$(SHL2TARGET)
+SHL5STDLIBS+=\
+ $(VCLLIB) \
+ $(TOOLSLIB) \
+ $(VOSLIB) \
+ $(SALLIB) \
+ $(X11LINK_DYNAMIC)
+
+.IF "$(ENABLE_RANDR)" != ""
+.IF "$(XRANDR_DLOPEN)" == "FALSE"
+SHL5STDLIBS+= $(XRANDR_LIBS)
+.ENDIF
+.ENDIF
+
+.ENDIF # "$(ENABLE_KDE)" != ""
+
+# KDE4 plugin
+.IF "$(ENABLE_KDE4)" != ""
+.IF "$(KDE4_ROOT)"!=""
+EXTRALIBPATHS+=-L$(KDE4_ROOT)$/lib
+.ENDIF
+LIB6TARGET=$(SLB)$/ikde4_plug_
+LIB6FILES=$(SLB)$/kde4plug.lib
+SHL6TARGET=vclplug_kde4$(DLLPOSTFIX)
+SHL6IMPLIB=ikde4_plug_
+SHL6LIBS=$(LIB6TARGET)
+SHL6DEPN=$(SHL2TARGETN)
+# libs for KDE4 plugin
+SHL6LINKFLAGS+=$(KDE4_LIBS)
+SHL6STDLIBS+=-l$(SHL2TARGET)
+SHL6STDLIBS+=\
+ $(VCLLIB) \
+ $(PSPLIB) \
+ $(TOOLSLIB) \
+ $(VOSLIB) \
+ $(SALLIB) \
+ $(X11LINK_DYNAMIC)
+
+.IF "$(ENABLE_RANDR)" != ""
+.IF "$(XRANDR_DLOPEN)" == "FALSE"
+SHL6STDLIBS+= $(XRANDR_LIBS)
+.ENDIF
+.ENDIF
+
+.ENDIF # "$(ENABLE_KDE4)" != ""
+
+.ENDIF # UNX
+
+# --- Allgemein ----------------------------------------------------------
+
+.INCLUDE : target.mk
+
diff --git a/vcl/util/makefile.pmk b/vcl/util/makefile.pmk
new file mode 100644
index 000000000000..884eb499b532
--- /dev/null
+++ b/vcl/util/makefile.pmk
@@ -0,0 +1,34 @@
+#*************************************************************************
+#
+# 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.
+#
+#*************************************************************************
+
+.IF "$(GUI)" == "UNX" && "$(GUIBASE)"!="aqua"
+USE_BUILTIN_RASTERIZER=true
+.ENDIF
+
+.IF "$(USE_BUILTIN_RASTERIZER)" != ""
+ADDCDEFS += -DUSE_BUILTIN_RASTERIZER
+.ENDIF
diff --git a/vcl/util/makefile2.pmk b/vcl/util/makefile2.pmk
new file mode 100644
index 000000000000..df9ba1a214d7
--- /dev/null
+++ b/vcl/util/makefile2.pmk
@@ -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.
+#
+#*************************************************************************
+
+# Reduction of exported symbols:
+CDEFS += -DVCL_DLLIMPLEMENTATION
+VISIBILITY_HIDDEN=TRUE
+
+.IF "$(GUIBASE)"=="aqua"
+CFLAGSCXX+=$(OBJCXXFLAGS)
+.ENDIF # "$(GUIBASE)"=="aqua"
+
+#building with stlport, but graphite was not built with stlport
+.IF "$(USE_SYSTEM_STL)"!="YES"
+.IF "$(SYSTEM_GRAPHITE)"=="YES"
+CDEFS += -DADAPT_EXT_STL
+.ENDIF
+.ENDIF
diff --git a/vcl/util/target.pmk b/vcl/util/target.pmk
new file mode 100644
index 000000000000..3144acc4bc05
--- /dev/null
+++ b/vcl/util/target.pmk
@@ -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.
+#
+#*************************************************************************
+ALLSLO: $(SLOFILES)
+
+SOSHL: $(SHL1TARGETN)
+
+WHOLEPRJ .SETDIR=$(PRJ)$/prj:
+ make debug linkinc prjpch compinc
+ @echo "READY"
+
+ONLYDLL .SETDIR=$(PRJ)$/util: $(SLOFILES)
+ $(RM) ..$/$(OUTPATH)$/bin$/sv$(DLLPOSTFIX).dll
+ dmake debug=t prjpch=t linkinc=t compinc=t ..$/$(OUTPATH)$/bin$/sv$(DLLPOSTFIX).dll
+ @echo "READY"
+
+.IF "$(USE_XPRINT)"!="TRUE"
+.ELSE
+CFLAGS+=-D_USE_PRINT_EXTENSION_=1
+.ENDIF
+
diff --git a/vcl/win/inc/salbmp.h b/vcl/win/inc/salbmp.h
new file mode 100644
index 000000000000..7a31add2ae19
--- /dev/null
+++ b/vcl/win/inc/salbmp.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALBMP_H
+#define _SV_SALBMP_H
+
+#include <wincomp.hxx>
+#include <tools/gen.hxx>
+#include <vcl/sv.h>
+#include <vcl/salbmp.hxx>
+
+// --------------
+// - SalBitmap -
+// --------------
+
+struct BitmapBuffer;
+class BitmapColor;
+class BitmapPalette;
+class SalGraphics;
+
+class WinSalBitmap : public SalBitmap
+{
+private:
+
+ Size maSize;
+ HGLOBAL mhDIB;
+ HBITMAP mhDDB;
+ USHORT mnBitCount;
+
+public:
+
+ HGLOBAL ImplGethDIB() const { return mhDIB; }
+ HBITMAP ImplGethDDB() const { return mhDDB; }
+
+ static HGLOBAL ImplCreateDIB( const Size& rSize, USHORT nBitCount, const BitmapPalette& rPal );
+ static HANDLE ImplCopyDIBOrDDB( HANDLE hHdl, bool bDIB );
+ static USHORT ImplGetDIBColorCount( HGLOBAL hDIB );
+ static void ImplDecodeRLEBuffer( const BYTE* pSrcBuf, BYTE* pDstBuf,
+ const Size& rSizePixel, bool bRLE4 );
+
+public:
+
+ WinSalBitmap();
+ virtual ~WinSalBitmap();
+
+public:
+
+ bool Create( HANDLE hBitmap, bool bDIB, bool bCopyHandle );
+ virtual bool Create( const Size& rSize, USHORT nBitCount, const BitmapPalette& rPal );
+ virtual bool Create( const SalBitmap& rSalBmpImpl );
+ virtual bool Create( const SalBitmap& rSalBmpImpl, SalGraphics* pGraphics );
+ virtual bool Create( const SalBitmap& rSalBmpImpl, USHORT nNewBitCount );
+
+ virtual void Destroy();
+
+ virtual Size GetSize() const { return maSize; }
+ virtual USHORT GetBitCount() const { return mnBitCount; }
+
+ virtual BitmapBuffer* AcquireBuffer( bool bReadOnly );
+ virtual void ReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly );
+ virtual bool GetSystemData( BitmapSystemData& rData );
+};
+
+#endif // _SV_SALBMP_HXX
diff --git a/vcl/win/inc/saldata.hxx b/vcl/win/inc/saldata.hxx
new file mode 100644
index 000000000000..ec67272ed07f
--- /dev/null
+++ b/vcl/win/inc/saldata.hxx
@@ -0,0 +1,372 @@
+/*************************************************************************
+ *
+ * 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_SALDATA_HXX
+#define _SV_SALDATA_HXX
+
+#include <vcl/sv.h>
+#include <vcl/svdata.hxx>
+#include <vcl/salwtype.hxx>
+#include <wincomp.hxx>
+
+#include <set> // for hMenu validation
+#include <map>
+
+class AutoTimer;
+class WinSalInstance;
+class WinSalObject;
+class WinSalFrame;
+class WinSalVirtualDevice;
+class WinSalPrinter;
+class Font;
+struct HDCCache;
+struct TempFontItem;
+
+// --------------------
+// - Standard-Defines -
+// --------------------
+
+#define MAX_STOCKPEN 4
+#define MAX_STOCKBRUSH 4
+#define SAL_CLIPRECT_COUNT 16
+
+// --------------------
+// - Icon cache -
+// --------------------
+
+struct SalIcon
+{
+ int nId;
+ HICON hIcon;
+ HICON hSmallIcon;
+ SalIcon *pNext;
+};
+
+// -----------
+// - SalData -
+// -----------
+
+class SalData
+{
+public:
+ SalData();
+ ~SalData();
+
+ // native widget framework
+ void initNWF();
+ void deInitNWF();
+
+ // fill maVKMap;
+ void initKeyCodeMap();
+
+ // checks if the menuhandle was created by VCL
+ BOOL IsKnownMenuHandle( HMENU hMenu );
+
+public:
+ HINSTANCE mhInst; // default instance handle
+ HINSTANCE mhPrevInst; // previous instance handle
+ int mnCmdShow; // default frame show style
+ HPALETTE mhDitherPal; // dither palette
+ HGLOBAL mhDitherDIB; // dither memory handle
+ BYTE* mpDitherDIB; // dither memory
+ BYTE* mpDitherDIBData; // beginning of DIB data
+ long* mpDitherDiff; // Dither mapping table
+ BYTE* mpDitherLow; // Dither mapping table
+ BYTE* mpDitherHigh; // Dither mapping table
+ ULONG mnTimerMS; // Current Time (in MS) of the Timer
+ ULONG mnTimerOrgMS; // Current Original Time (in MS)
+ DWORD mnNextTimerTime;
+ DWORD mnLastEventTime;
+ UINT mnTimerId; // windows timer id
+ BOOL mbInTimerProc; // timer event is currently being dispatched
+ HHOOK mhSalObjMsgHook; // hook to get interesting msg for SalObject
+ HWND mhWantLeaveMsg; // window handle, that want a MOUSELEAVE message
+ AutoTimer* mpMouseLeaveTimer; // Timer for MouseLeave Test
+ WinSalInstance* mpFirstInstance; // pointer of first instance
+ WinSalFrame* mpFirstFrame; // pointer of first frame
+ WinSalObject* mpFirstObject; // pointer of first object window
+ WinSalVirtualDevice* mpFirstVD; // first VirDev
+ WinSalPrinter* mpFirstPrinter; // first printing printer
+ HDCCache* mpHDCCache; // Cache for three DC's
+ HBITMAP mh50Bmp; // 50% Bitmap
+ HBRUSH mh50Brush; // 50% Brush
+ COLORREF maStockPenColorAry[MAX_STOCKPEN];
+ COLORREF maStockBrushColorAry[MAX_STOCKBRUSH];
+ HPEN mhStockPenAry[MAX_STOCKPEN];
+ HBRUSH mhStockBrushAry[MAX_STOCKBRUSH];
+ USHORT mnStockPenCount; // count of static pens
+ USHORT mnStockBrushCount; // count of static brushes
+ WPARAM mnSalObjWantKeyEvt; // KeyEvent, welcher vom SalObj-Hook verarbeitet werden soll
+ BYTE mnCacheDCInUse; // count of CacheDC in use
+ BOOL mbObjClassInit; // is SALOBJECTCLASS initialised
+ BOOL mbInPalChange; // is in WM_QUERYNEWPALETTE
+ DWORD mnAppThreadId; // Id from Applikation-Thread
+ WIN_BOOL mbScrSvrEnabled; // ScreenSaver enabled
+ int mnSageStatus; // status of Sage-DLL (DISABLE_AGENT == nicht vorhanden)
+ SysAgt_Enable_PROC mpSageEnableProc; // funktion to deactivate the system agent
+ SalIcon* mpFirstIcon; // icon cache, points to first icon, NULL if none
+ TempFontItem* mpTempFontItem;
+ BOOL mbThemeChanged; // true if visual theme was changed: throw away theme handles
+
+ // for GdiPlus GdiplusStartup/GdiplusShutdown
+ ULONG_PTR gdiplusToken;
+
+ std::set< HMENU > mhMenuSet; // keeps track of menu handles created by VCL, used by IsKnownMenuHandle()
+ std::map< UINT,USHORT > maVKMap; // map some dynamic VK_* entries
+};
+
+inline void SetSalData( SalData* pData ) { ImplGetSVData()->mpSalData = (void*)pData; }
+inline SalData* GetSalData() { return (SalData*)ImplGetSVData()->mpSalData; }
+inline SalData* GetAppSalData() { return (SalData*)ImplGetAppSVData()->mpSalData; }
+
+// --------------
+// - SalShlData -
+// --------------
+
+struct SalShlData
+{
+ HINSTANCE mhInst; // Instance of SAL-DLL
+ UINT mnWheelScrollLines; // WheelScrollLines
+ UINT mnWheelScrollChars; // WheelScrollChars
+ UINT mnWheelMsgId; // Wheel-Message-Id fuer W95
+ WORD mnVersion; // System-Version (311 == 3.11)
+ WIN_BOOL mbWNT; // kein W16/W95/W98 sondern ein NT
+ WIN_BOOL mbW40; // Is System-Version >= 4.0
+ WIN_BOOL mbWXP; // Windows XP
+ WIN_BOOL mbWPrinter; // true: use unicode printer functions
+ // false: use anis compat printer functions
+ OSVERSIONINFO maVersionInfo;
+};
+
+extern SalShlData aSalShlData;
+
+// ------------
+// - GDICache -
+// ------------
+
+#define CACHESIZE_HDC 3
+#define CACHED_HDC_1 0
+#define CACHED_HDC_2 1
+#define CACHED_HDC_DRAW 2
+#define CACHED_HDC_DEFEXT 64
+
+struct HDCCache
+{
+ HDC mhDC;
+ HPALETTE mhDefPal;
+ HBITMAP mhDefBmp;
+ HBITMAP mhSelBmp;
+ HBITMAP mhActBmp;
+};
+
+void ImplClearHDCCache( SalData* pData );
+HDC ImplGetCachedDC( ULONG nID, HBITMAP hBmp = 0 );
+void ImplReleaseCachedDC( ULONG nID );
+
+bool ImplAddTempFont( SalData&, const String& rFontFileURL );
+void ImplReleaseTempFonts( SalData& );
+
+// --------------------------------------------
+// - SALSHL.CXX - for accessing DLL resources -
+// --------------------------------------------
+
+HCURSOR ImplLoadSalCursor( int nId );
+HBITMAP ImplLoadSalBitmap( int nId );
+BOOL ImplLoadSalIcon( int nId, HICON& rIcon, HICON& rSmallIcon );
+
+// SALGDI.CXX
+void ImplInitSalGDI();
+void ImplFreeSalGDI();
+
+// --------------
+// - Prototypes -
+// --------------
+
+// \\WIN\SOURCE\APP\SALINST.CXX
+void ImplSalYieldMutexAcquireWithWait();
+BOOL ImplSalYieldMutexTryToAcquire();
+void ImplSalYieldMutexAcquire();
+void ImplSalYieldMutexRelease();
+ULONG ImplSalReleaseYieldMutex();
+void ImplSalAcquireYieldMutex( ULONG nCount );
+
+// \\WIN\SOURCE\WINDOW\SALFRAME.CXX
+LRESULT CALLBACK SalFrameWndProcA( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam );
+LRESULT CALLBACK SalFrameWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam );
+// \SV\WIN\SOURCE\APP\SALTIMER.CXX
+#define SALTIMERPROC_RECURSIVE 0xffffffff
+void CALLBACK SalTimerProc( HWND hWnd, UINT nMsg, UINT_PTR nId, DWORD nTime );
+
+// \WIN\SOURCE\WINDOW\SALFRAME.CXX
+void SalTestMouseLeave();
+BOOL ImplWriteLastError( DWORD lastError, const char *szApiCall );
+
+// \WIN\SOURCE\WINDOW\SALFRAME.CXX
+long ImplHandleSalObjKeyMsg( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam );
+long ImplHandleSalObjSysCharMsg( HWND hWnd, WPARAM wParam, LPARAM lParam );
+BOOL ImplHandleGlobalMsg( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, LRESULT& rlResult );
+
+// \WIN\SOURCE\WINDOW\SALOBJ.CXX
+WinSalObject* ImplFindSalObject( HWND hWndChild );
+BOOL ImplSalPreDispatchMsg( MSG* pMsg );
+void ImplSalPostDispatchMsg( MSG* pMsg, LRESULT nDispatchResult );
+
+// \WIN\SOURCE\GDI\SALGDI3.CXX
+void ImplSalLogFontToFontA( HDC hDC, const LOGFONTA& rLogFont, Font& rFont );
+void ImplSalLogFontToFontW( HDC hDC, const LOGFONTW& rLogFont, Font& rFont );
+bool ImplIsFontAvailable( HDC hDC, const UniString& rName );
+
+// \WIN\SOURCE\APP\SALDATA.CXX
+rtl_TextEncoding ImplSalGetSystemEncoding();
+ByteString ImplSalGetWinAnsiString( const UniString& rStr, BOOL bFileName = FALSE );
+UniString ImplSalGetUniString( const sal_Char* pStr, xub_StrLen nLen = STRING_LEN );
+int ImplSalWICompareAscii( const wchar_t* pStr1, const char* pStr2 );
+
+// -----------
+// - Defines -
+// -----------
+
+#define SAL_FRAME_WNDEXTRA sizeof( DWORD )
+#define SAL_FRAME_THIS 0
+#define SAL_FRAME_CLASSNAMEA "SALFRAME"
+#define SAL_FRAME_CLASSNAMEW L"SALFRAME"
+#define SAL_SUBFRAME_CLASSNAMEA "SALSUBFRAME"
+#define SAL_SUBFRAME_CLASSNAMEW L"SALSUBFRAME"
+#define SAL_TMPSUBFRAME_CLASSNAMEW L"SALTMPSUBFRAME"
+#define SAL_OBJECT_WNDEXTRA sizeof( DWORD )
+#define SAL_OBJECT_THIS 0
+#define SAL_OBJECT_CLASSNAMEA "SALOBJECT"
+#define SAL_OBJECT_CLASSNAMEW L"SALOBJECT"
+#define SAL_OBJECT_CHILDCLASSNAMEA "SALOBJECTCHILD"
+#define SAL_OBJECT_CHILDCLASSNAMEW L"SALOBJECTCHILD"
+#define SAL_COM_CLASSNAMEA "SALCOMWND"
+#define SAL_COM_CLASSNAMEW L"SALCOMWND"
+
+#define SAL_MOUSELEAVE_TIMEOUT 300
+
+// wParam == hDC; lParam == 0
+#define SAL_MSG_PRINTABORTJOB (WM_USER+110)
+// wParam == bWait; lParam == 0
+#define SAL_MSG_THREADYIELD (WM_USER+111)
+// wParam == 0; lParam == 0
+#define SAL_MSG_RELEASEWAITYIELD (WM_USER+112)
+// wParam == 0; lParam == nMS
+#define SAL_MSG_STARTTIMER (WM_USER+113)
+// wParam == nFrameStyle; lParam == pParent; lResult == pFrame
+#define SAL_MSG_CREATEFRAME (WM_USER+114)
+// wParam == 0; lParam == 0
+#define SAL_MSG_DESTROYFRAME (WM_USER+115)
+// wParam == 0; lParam == pParent; lResult == pObject
+#define SAL_MSG_CREATEOBJECT (WM_USER+116)
+// wParam == 0; lParam == pObject;
+#define SAL_MSG_DESTROYOBJECT (WM_USER+117)
+// wParam == hWnd; lParam == 0; lResult == hDC
+#define SAL_MSG_GETDC (WM_USER+120)
+// wParam == hWnd; lParam == 0
+#define SAL_MSG_RELEASEDC (WM_USER+121)
+// wParam == newParentHwnd; lParam == oldHwnd; lResult == newhWnd
+#define SAL_MSG_RECREATEHWND (WM_USER+122)
+// wParam == newParentHwnd; lParam == oldHwnd; lResult == newhWnd
+#define SAL_MSG_RECREATECHILDHWND (WM_USER+123)
+// wParam == 0; lParam == HWND;
+#define SAL_MSG_DESTROYHWND (WM_USER+124)
+
+// wParam == 0; lParam == pData
+#define SAL_MSG_USEREVENT (WM_USER+130)
+// wParam == 0; lParam == MousePosition relativ to upper left of screen
+#define SAL_MSG_MOUSELEAVE (WM_USER+131)
+// NULL-Message, soll nicht verarbeitet werden
+#define SAL_MSG_DUMMY (WM_USER+132)
+// wParam == 0; lParam == 0
+#define SAL_MSG_POSTFOCUS (WM_USER+133)
+// wParam == wParam; lParam == lParam
+#define SAL_MSG_POSTQUERYNEWPAL (WM_USER+134)
+// wParam == wParam; lParam == lParam
+#define SAL_MSG_POSTPALCHANGED (WM_USER+135)
+// wParam == wParam; lParam == lParam
+#define SAL_MSG_POSTMOVE (WM_USER+136)
+// wParam == wParam; lParam == lParam
+#define SAL_MSG_POSTCALLSIZE (WM_USER+137)
+// wParam == pRECT; lParam == 0
+#define SAL_MSG_POSTPAINT (WM_USER+138)
+// wParam == 0; lParam == pFrame; lResult 0
+#define SAL_MSG_FORCEPALETTE (WM_USER+139)
+// wParam == 0; lParam == 0
+#define SAL_MSG_CAPTUREMOUSE (WM_USER+140)
+// wParam == 0; lParam == 0
+#define SAL_MSG_RELEASEMOUSE (WM_USER+141)
+// wParam == nFlags; lParam == 0
+#define SAL_MSG_TOTOP (WM_USER+142)
+// wParam == bVisible; lParam == 0
+#define SAL_MSG_SHOW (WM_USER+143)
+// wParam == 0; lParam == SalInputContext
+#define SAL_MSG_SETINPUTCONTEXT (WM_USER+144)
+// wParam == nFlags; lParam == 0
+#define SAL_MSG_ENDEXTTEXTINPUT (WM_USER+145)
+// POSTTIMER-Message; wparam = 0, lParam == time
+#define SAL_MSG_POSTTIMER (WM_USER+161)
+
+// SysChild-ToTop; wParam = 0; lParam = 0
+#define SALOBJ_MSG_TOTOP (WM_USER+160)
+// POSTFOCUS-Message; wParam == bFocus; lParam == 0
+#define SALOBJ_MSG_POSTFOCUS (WM_USER+161)
+
+
+// -----------------
+// - Helpfunctions -
+// -----------------
+
+// A/W-Wrapper
+LONG ImplSetWindowLong( HWND hWnd, int nIndex, DWORD dwNewLong );
+LONG ImplGetWindowLong( HWND hWnd, int nIndex );
+WIN_BOOL ImplPostMessage( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam );
+WIN_BOOL ImplSendMessage( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam );
+WIN_BOOL ImplGetMessage( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax );
+WIN_BOOL ImplPeekMessage( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg );
+LONG ImplDispatchMessage( CONST MSG *lpMsg );
+
+inline void SetWindowPtr( HWND hWnd, WinSalFrame* pThis )
+{
+ ImplSetWindowLong( hWnd, SAL_FRAME_THIS, (LONG)pThis );
+}
+
+inline WinSalFrame* GetWindowPtr( HWND hWnd )
+{
+ return (WinSalFrame*)ImplGetWindowLong( hWnd, SAL_FRAME_THIS );
+}
+
+inline void SetSalObjWindowPtr( HWND hWnd, WinSalObject* pThis )
+{
+ ImplSetWindowLong( hWnd, SAL_OBJECT_THIS, (LONG)pThis );
+}
+
+inline WinSalObject* GetSalObjWindowPtr( HWND hWnd )
+{
+ return (WinSalObject*)ImplGetWindowLong( hWnd, SAL_OBJECT_THIS );
+}
+
+#endif // _SV_SALDATA_HXX
diff --git a/vcl/win/inc/salframe.h b/vcl/win/inc/salframe.h
new file mode 100644
index 000000000000..f9aa8ef9dc4b
--- /dev/null
+++ b/vcl/win/inc/salframe.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALFRAME_H
+#define _SV_SALFRAME_H
+
+#include <vcl/sv.h>
+#include <vcl/sysdata.hxx>
+#include <vcl/salframe.hxx>
+
+class WinSalGraphics;
+
+// ----------------
+// - WinSalFrame -
+// ----------------
+
+class WinSalFrame : public SalFrame
+{
+public:
+ HWND mhWnd; // Window handle
+ HCURSOR mhCursor; // cursor handle
+ HIMC mhDefIMEContext; // default IME-Context
+ WinSalGraphics* mpGraphics; // current frame graphics
+ WinSalGraphics* mpGraphics2; // current frame graphics for other threads
+ WinSalFrame* mpNextFrame; // pointer to next frame
+ HMENU mSelectedhMenu; // the menu where highlighting is currently going on
+ HMENU mLastActivatedhMenu; // the menu that was most recently opened
+ SystemEnvData maSysData; // system data
+ SalFrameState maState; // frame state
+ int mnShowState; // show state
+ long mnWidth; // client width in pixeln
+ long mnHeight; // client height in pixeln
+ int mnMinWidth; // min. client width in pixeln
+ int mnMinHeight; // min. client height in pixeln
+ int mnMaxWidth; // max. client width in pixeln
+ int mnMaxHeight; // max. client height in pixeln
+ RECT maFullScreenRect; // fullscreen rect
+ int mnFullScreenShowState; // fullscreen restore show state
+ UINT mnInputLang; // current Input Language
+ UINT mnInputCodePage; // current Input CodePage
+ ULONG mnStyle; // style
+ BOOL mbGraphics; // is Graphics used
+ BOOL mbCaption; // has window a caption
+ BOOL mbBorder; // has window a border
+ BOOL mbFixBorder; // has window a fixed border
+ BOOL mbSizeBorder; // has window a sizeable border
+ BOOL mbNoIcon; // is an window without an icon
+ BOOL mbFloatWin; // is a FloatingWindow
+ BOOL mbFullScreen; // TRUE: in full screen mode
+ BOOL mbPresentation; // TRUE: Presentation Mode running
+ BOOL mbInShow; // innerhalb eines Show-Aufrufs
+ BOOL mbRestoreMaximize; // Restore-Maximize
+ BOOL mbInMoveMsg; // Move-Message wird verarbeitet
+ BOOL mbInSizeMsg; // Size-Message wird verarbeitet
+ BOOL mbFullScreenToolWin; // WS_EX_TOOLWINDOW reset in FullScreenMode
+ BOOL mbDefPos; // default-position
+ BOOL mbOverwriteState; // TRUE: WindowState darf umgesetzt werden
+ BOOL mbIME; // TRUE: We are in IME Mode
+ BOOL mbHandleIME; // TRUE: Wir handeln die IME-Messages
+ BOOL mbSpezIME; // TRUE: Spez IME
+ BOOL mbAtCursorIME; // TRUE: Wir behandeln nur einige IME-Messages
+ BOOL mbCandidateMode; // TRUE: Wir befinden uns im Candidate-Modus
+ static BOOL mbInReparent; // TRUE: ignore focus lost and gain due to reparenting
+
+ RGNDATA* mpClipRgnData;
+ RECT* mpNextClipRect;
+ BOOL mbFirstClipRect;
+ sal_Int32 mnDisplay; // Display used for Fullscreen, 0 is primary monitor
+
+ void updateScreenNumber();
+public:
+ WinSalFrame();
+ virtual ~WinSalFrame();
+
+ virtual SalGraphics* GetGraphics();
+ virtual void ReleaseGraphics( SalGraphics* pGraphics );
+ virtual BOOL PostEvent( void* pData );
+ virtual void SetTitle( const XubString& rTitle );
+ virtual void SetIcon( USHORT nIcon );
+ virtual void SetMenu( SalMenu* pSalMenu );
+ virtual void DrawMenuBar();
+ virtual void SetExtendedFrameStyle( SalExtStyle nExtStyle );
+ virtual void Show( BOOL bVisible, BOOL bNoActivate = FALSE );
+ virtual void Enable( BOOL bEnable );
+ virtual void SetMinClientSize( long nWidth, long nHeight );
+ virtual void SetMaxClientSize( long nWidth, long nHeight );
+ virtual void SetPosSize( long nX, long nY, long nWidth, long nHeight, USHORT nFlags );
+ virtual void GetClientSize( long& rWidth, long& rHeight );
+ virtual void GetWorkArea( Rectangle& rRect );
+ virtual SalFrame* GetParent() const;
+ virtual void SetWindowState( const SalFrameState* pState );
+ virtual BOOL GetWindowState( SalFrameState* pState );
+ virtual void ShowFullScreen( BOOL bFullScreen, sal_Int32 nDisplay );
+ virtual void StartPresentation( BOOL bStart );
+ virtual void SetAlwaysOnTop( BOOL bOnTop );
+ virtual void ToTop( USHORT nFlags );
+ virtual void SetPointer( PointerStyle ePointerStyle );
+ virtual void CaptureMouse( BOOL bMouse );
+ virtual void SetPointerPos( long nX, long nY );
+ using SalFrame::Flush;
+ virtual void Flush();
+ virtual void Sync();
+ virtual void SetInputContext( SalInputContext* pContext );
+ virtual void EndExtTextInput( USHORT nFlags );
+ virtual String GetKeyName( USHORT nKeyCode );
+ virtual String GetSymbolKeyName( const XubString& rFontName, USHORT nKeyCode );
+ virtual BOOL MapUnicodeToKeyCode( sal_Unicode aUnicode, LanguageType aLangType, KeyCode& rKeyCode );
+ virtual LanguageType GetInputLanguage();
+ virtual SalBitmap* SnapShot();
+ virtual void UpdateSettings( AllSettings& rSettings );
+ virtual void Beep( SoundType eSoundType );
+ virtual const SystemEnvData* GetSystemData() const;
+ virtual SalPointerState GetPointerState();
+ virtual void SetParent( SalFrame* pNewParent );
+ virtual bool SetPluginParent( SystemParentData* pNewParent );
+ virtual void SetBackgroundBitmap( SalBitmap* );
+ virtual void SetScreenNumber( unsigned int );
+ virtual void ResetClipRegion();
+ virtual void BeginSetClipRegion( ULONG nRects );
+ virtual void UnionClipRegion( long nX, long nY, long nWidth, long nHeight );
+ virtual void EndSetClipRegion();
+};
+
+void ImplSalGetWorkArea( HWND hWnd, RECT *pRect, const RECT *pParentRect );
+
+#endif // _SV_SALFRAME_H
diff --git a/vcl/win/inc/salgdi.h b/vcl/win/inc/salgdi.h
new file mode 100644
index 000000000000..b1bfcbee96f4
--- /dev/null
+++ b/vcl/win/inc/salgdi.h
@@ -0,0 +1,403 @@
+/*************************************************************************
+ *
+ * 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_SALGDI_H
+#define _SV_SALGDI_H
+
+#include <vcl/sv.h>
+#include <vcl/sallayout.hxx>
+#include <vcl/salgdi.hxx>
+#include <vcl/outfont.hxx>
+#include <vcl/impfont.hxx>
+
+#include "boost/scoped_ptr.hpp"
+#include <hash_set>
+
+class ImplFontSelectData;
+class ImplWinFontEntry;
+class ImplFontAttrCache;
+
+// -----------
+// - Defines -
+// -----------
+
+#define RGB_TO_PALRGB(nRGB) ((nRGB)|0x02000000)
+#define PALRGB_TO_RGB(nPalRGB) ((nPalRGB)&0x00ffffff)
+
+// win32 platform specific options. Move them to the PMK file?
+
+#define GCP_KERN_HACK
+#define GNG_VERT_HACK
+
+// win32 specific physically available font face
+class ImplWinFontData : public ImplFontData
+{
+public:
+ ImplWinFontData( const ImplDevFontAttributes&,
+ int nFontHeight, WIN_BYTE eWinCharSet,
+ WIN_BYTE nPitchAndFamily );
+ ~ImplWinFontData();
+
+ virtual ImplFontData* Clone() const;
+ virtual ImplFontEntry* CreateFontInstance( ImplFontSelectData& ) const;
+ virtual sal_IntPtr GetFontId() const;
+ void SetFontId( sal_IntPtr nId ) { mnId = nId; }
+ void UpdateFromHDC( HDC ) const;
+
+ bool HasChar( sal_uInt32 cChar ) const;
+
+ WIN_BYTE GetCharSet() const { return meWinCharSet; }
+ WIN_BYTE GetPitchAndFamily() const { return mnPitchAndFamily; }
+ bool IsGlyphApiDisabled() const { return mbDisableGlyphApi; }
+ bool SupportsKorean() const { return mbHasKoreanRange; }
+ bool SupportsCJK() const { return mbHasCJKSupport; }
+ bool SupportsArabic() const { return mbHasArabicSupport; }
+ bool AliasSymbolsHigh() const { return mbAliasSymbolsHigh; }
+ bool AliasSymbolsLow() const { return mbAliasSymbolsLow; }
+#ifdef ENABLE_GRAPHITE
+ bool SupportsGraphite() const { return mbHasGraphiteSupport; }
+#endif
+
+ ImplFontCharMap* GetImplFontCharMap() const;
+ const Ucs2SIntMap* GetEncodingVector() const { return mpEncodingVector; }
+ void SetEncodingVector( const Ucs2SIntMap* pNewVec ) const
+ {
+ if( mpEncodingVector )
+ delete mpEncodingVector;
+ mpEncodingVector = pNewVec;
+ }
+private:
+ sal_IntPtr mnId;
+
+ // some members that are initalized lazily when the font gets selected into a HDC
+ mutable bool mbDisableGlyphApi;
+ mutable bool mbHasKoreanRange;
+ mutable bool mbHasCJKSupport;
+#ifdef ENABLE_GRAPHITE
+ mutable bool mbHasGraphiteSupport;
+#endif
+ mutable bool mbHasArabicSupport;
+ mutable ImplFontCharMap* mpUnicodeMap;
+ mutable const Ucs2SIntMap* mpEncodingVector;
+
+ // TODO: get rid of the members below needed to work with the Win9x non-unicode API
+ BYTE* mpFontCharSets; // all Charsets for the current font (used on W98 for kerning)
+ BYTE mnFontCharSetCount; // Number of Charsets of the current font; 0 - if not queried
+ WIN_BYTE meWinCharSet;
+ WIN_BYTE mnPitchAndFamily;
+ bool mbAliasSymbolsHigh;
+ bool mbAliasSymbolsLow;
+private:
+ void ReadCmapTable( HDC ) const;
+ void ReadOs2Table( HDC ) const;
+
+#ifdef GNG_VERT_HACK
+ void ReadGsubTable( HDC ) const;
+
+ typedef std::hash_set<sal_UCS4> UcsHashSet;
+ mutable UcsHashSet maGsubTable;
+ mutable bool mbGsubRead;
+public:
+ bool HasGSUBstitutions( HDC ) const;
+ bool IsGSUBstituted( sal_UCS4 ) const;
+#endif // GNG_VERT_HACK
+};
+
+// -------------------
+// - SalGraphicsData -
+// -------------------
+
+class WinSalGraphics : public SalGraphics
+{
+public:
+ HDC mhDC; // HDC
+ HWND mhWnd; // Window-Handle, when Window-Graphics
+ HFONT mhFonts[ MAX_FALLBACK ]; // Font + Fallbacks
+ const ImplWinFontData* mpWinFontData[ MAX_FALLBACK ]; // pointer to the most recent font face
+ ImplWinFontEntry* mpWinFontEntry[ MAX_FALLBACK ]; // pointer to the most recent font instance
+ float mfFontScale; // allows metrics emulation of huge font sizes
+ HPEN mhPen; // Pen
+ HBRUSH mhBrush; // Brush
+ HRGN mhRegion; // Region Handle
+ HPEN mhDefPen; // DefaultPen
+ HBRUSH mhDefBrush; // DefaultBrush
+ HFONT mhDefFont; // DefaultFont
+ HPALETTE mhDefPal; // DefaultPalette
+ COLORREF mnPenColor; // PenColor
+ COLORREF mnBrushColor; // BrushColor
+ COLORREF mnTextColor; // TextColor
+ RGNDATA* mpClipRgnData; // ClipRegion-Data
+ RGNDATA* mpStdClipRgnData; // Cache Standard-ClipRegion-Data
+ RECT* mpNextClipRect; // Naechstes ClipRegion-Rect
+ BOOL mbFirstClipRect; // Flag for first cliprect to insert
+ LOGFONTA* mpLogFont; // LOG-Font which is currently selected (only W9x)
+ ImplFontAttrCache* mpFontAttrCache; // Cache font attributes from files in so/share/fonts
+ BYTE* mpFontCharSets; // All Charsets for the current font
+ BYTE mnFontCharSetCount; // Number of Charsets of the current font; 0 - if not queried
+ BOOL mbFontKernInit; // FALSE: FontKerns must be queried
+ KERNINGPAIR* mpFontKernPairs; // Kerning Pairs of the current Font
+ ULONG mnFontKernPairCount;// Number of Kerning Pairs of the current Font
+ int mnPenWidth; // Linienbreite
+ BOOL mbStockPen; // is Pen a stockpen
+ BOOL mbStockBrush; // is Brush a stcokbrush
+ BOOL mbPen; // is Pen (FALSE == NULL_PEN)
+ BOOL mbBrush; // is Brush (FALSE == NULL_BRUSH)
+ BOOL mbPrinter; // is Printer
+ BOOL mbVirDev; // is VirDev
+ BOOL mbWindow; // is Window
+ BOOL mbScreen; // is Screen compatible
+ bool mbXORMode; // _every_ output with RasterOp XOR
+
+ // remember RGB values for SetLineColor/SetFillColor
+ SalColor maLineColor;
+ SalColor maFillColor;
+
+ HFONT ImplDoSetFont( ImplFontSelectData* i_pFont, float& o_rFontScale, HFONT& o_rOldFont );
+
+public:
+ WinSalGraphics();
+ virtual ~WinSalGraphics();
+
+protected:
+ virtual BOOL unionClipRegion( long nX, long nY, long nWidth, long nHeight );
+ virtual bool unionClipRegion( const ::basegfx::B2DPolyPolygon& );
+ // draw --> LineColor and FillColor and RasterOp and ClipRegion
+ virtual void drawPixel( long nX, long nY );
+ virtual void drawPixel( long nX, long nY, SalColor nSalColor );
+ virtual void drawLine( long nX1, long nY1, long nX2, long nY2 );
+ virtual void drawRect( long nX, long nY, long nWidth, long nHeight );
+ virtual void drawPolyLine( ULONG nPoints, const SalPoint* pPtAry );
+ virtual void drawPolygon( ULONG nPoints, const SalPoint* pPtAry );
+ virtual void drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry );
+ virtual bool drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double fTransparency );
+ virtual bool drawPolyLine( const ::basegfx::B2DPolygon&, double fTransparency, const ::basegfx::B2DVector& rLineWidth, basegfx::B2DLineJoin );
+ virtual sal_Bool drawPolyLineBezier( ULONG nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry );
+ virtual sal_Bool drawPolygonBezier( ULONG nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry );
+ virtual sal_Bool drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* pPoints, const SalPoint* const* pPtAry, const BYTE* const* pFlgAry );
+
+ // CopyArea --> No RasterOp, but ClipRegion
+ virtual void copyArea( long nDestX, long nDestY, long nSrcX, long nSrcY, long nSrcWidth,
+ long nSrcHeight, USHORT nFlags );
+
+ // CopyBits and DrawBitmap --> RasterOp and ClipRegion
+ // CopyBits() --> pSrcGraphics == NULL, then CopyBits on same Graphics
+ virtual void copyBits( const SalTwoRect* pPosAry, SalGraphics* pSrcGraphics );
+ virtual void drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap );
+ virtual void drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ SalColor nTransparentColor );
+ virtual void drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ const SalBitmap& rTransparentBitmap );
+ virtual void drawMask( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ SalColor nMaskColor );
+
+ virtual SalBitmap* getBitmap( long nX, long nY, long nWidth, long nHeight );
+ virtual SalColor getPixel( long nX, long nY );
+
+ // invert --> ClipRegion (only Windows or VirDevs)
+ virtual void invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags);
+ virtual void invert( ULONG nPoints, const SalPoint* pPtAry, SalInvert nFlags );
+
+ virtual BOOL drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, ULONG nSize );
+
+ // native widget rendering methods that require mirroring
+ virtual BOOL hitTestNativeControl( ControlType nType, ControlPart nPart, const Region& rControlRegion,
+ const Point& aPos, BOOL& rIsInside );
+ virtual BOOL drawNativeControl( ControlType nType, ControlPart nPart, const Region& rControlRegion,
+ ControlState nState, const ImplControlValue& aValue,
+ const rtl::OUString& aCaption );
+ virtual BOOL drawNativeControlText( ControlType nType, ControlPart nPart, const Region& rControlRegion,
+ ControlState nState, const ImplControlValue& aValue,
+ const rtl::OUString& aCaption );
+ virtual BOOL getNativeControlRegion( ControlType nType, ControlPart nPart, const Region& rControlRegion, ControlState nState,
+ const ImplControlValue& aValue, const rtl::OUString& aCaption,
+ Region &rNativeBoundingRegion, Region &rNativeContentRegion );
+
+ virtual bool drawAlphaBitmap( const SalTwoRect&,
+ const SalBitmap& rSourceBitmap,
+ const SalBitmap& rAlphaBitmap );
+ virtual bool drawAlphaRect( long nX, long nY, long nWidth, long nHeight, sal_uInt8 nTransparency );
+
+public:
+ // public SalGraphics methods, the interface to teh independent vcl part
+
+ // get device resolution
+ virtual void GetResolution( long& rDPIX, long& rDPIY );
+ // get the depth of the device
+ virtual USHORT GetBitCount();
+ // get the width of the device
+ virtual long GetGraphicsWidth() const;
+
+ // set the clip region to empty
+ virtual void ResetClipRegion();
+ // begin setting the clip region, add rectangles to the
+ // region with the UnionClipRegion call
+ virtual void BeginSetClipRegion( ULONG nCount );
+ // all rectangles were added and the clip region should be set now
+ virtual void EndSetClipRegion();
+
+ // set the line color to transparent (= don't draw lines)
+ virtual void SetLineColor();
+ // set the line color to a specific color
+ virtual void SetLineColor( SalColor nSalColor );
+ // set the fill color to transparent (= don't fill)
+ virtual void SetFillColor();
+ // set the fill color to a specific color, shapes will be
+ // filled accordingly
+ virtual void SetFillColor( SalColor nSalColor );
+ // enable/disable XOR drawing
+ virtual void SetXORMode( bool bSet, bool );
+ // set line color for raster operations
+ virtual void SetROPLineColor( SalROPColor nROPColor );
+ // set fill color for raster operations
+ virtual void SetROPFillColor( SalROPColor nROPColor );
+ // set the text color to a specific color
+ virtual void SetTextColor( SalColor nSalColor );
+ // set the font
+ virtual USHORT SetFont( ImplFontSelectData*, int nFallbackLevel );
+ // get the current font's etrics
+ virtual void GetFontMetric( ImplFontMetricData* );
+ // get kernign pairs of the current font
+ // return only PairCount if (pKernPairs == NULL)
+ virtual ULONG GetKernPairs( ULONG nPairs, ImplKernPairData* pKernPairs );
+ // get the repertoire of the current font
+ virtual ImplFontCharMap* GetImplFontCharMap() const;
+ // graphics must fill supplied font list
+ virtual void GetDevFontList( ImplDevFontList* );
+ // graphics should call ImplAddDevFontSubstitute on supplied
+ // OutputDevice for all its device specific preferred font substitutions
+ virtual void GetDevFontSubstList( OutputDevice* );
+ virtual bool AddTempDevFont( ImplDevFontList*, const String& rFileURL, const String& rFontName );
+ // CreateFontSubset: a method to get a subset of glyhps of a font
+ // inside a new valid font file
+ // returns TRUE if creation of subset was successfull
+ // parameters: rToFile: contains a osl file URL to write the subset to
+ // pFont: describes from which font to create a subset
+ // pGlyphIDs: the glyph ids to be extracted
+ // pEncoding: the character code corresponding to each glyph
+ // pWidths: the advance widths of the correspoding glyphs (in PS font units)
+ // nGlyphs: the number of glyphs
+ // rInfo: additional outgoing information
+ // implementation note: encoding 0 with glyph id 0 should be added implicitly
+ // as "undefined character"
+ virtual BOOL CreateFontSubset( const rtl::OUString& rToFile,
+ const ImplFontData*,
+ long* pGlyphIDs,
+ sal_uInt8* pEncoding,
+ sal_Int32* pWidths,
+ int nGlyphs,
+ FontSubsetInfo& rInfo // out parameter
+ );
+
+ // GetFontEncodingVector: a method to get the encoding map Unicode
+ // to font encoded character; this is only used for type1 fonts and
+ // may return NULL in case of unknown encoding vector
+ // if ppNonEncoded is set and non encoded characters (that is type1
+ // glyphs with only a name) exist it is set to the corresponding
+ // map for non encoded glyphs; the encoding vector contains -1
+ // as encoding for these cases
+ virtual const Ucs2SIntMap* GetFontEncodingVector( const ImplFontData*, const Ucs2OStrMap** ppNonEncoded );
+
+ // GetEmbedFontData: gets the font data for a font marked
+ // embeddable by GetDevFontList or NULL in case of error
+ // parameters: pFont: describes the font in question
+ // pWidths: the widths of all glyphs from char code 0 to 255
+ // pWidths MUST support at least 256 members;
+ // rInfo: additional outgoing information
+ // pDataLen: out parameter, contains the byte length of the returned buffer
+ virtual const void* GetEmbedFontData( const ImplFontData*,
+ const sal_Ucs* pUnicodes,
+ sal_Int32* pWidths,
+ FontSubsetInfo& rInfo,
+ long* pDataLen );
+ // frees the font data again
+ virtual void FreeEmbedFontData( const void* pData, long nDataLen );
+ virtual void GetGlyphWidths( const ImplFontData*,
+ bool bVertical,
+ Int32Vector& rWidths,
+ Ucs2UIntMap& rUnicodeEnc );
+ virtual int GetMinKashidaWidth();
+
+ virtual BOOL GetGlyphBoundRect( long nIndex, Rectangle& );
+ virtual BOOL GetGlyphOutline( long nIndex, ::basegfx::B2DPolyPolygon& );
+
+ virtual SalLayout* GetTextLayout( ImplLayoutArgs&, int nFallbackLevel );
+ virtual void DrawServerFontLayout( const ServerFontLayout& );
+
+ virtual bool supportsOperation( OutDevSupportType ) const;
+ // Query the platform layer for control support
+ virtual BOOL IsNativeControlSupported( ControlType nType, ControlPart nPart );
+
+ virtual SystemGraphicsData GetGraphicsData() const;
+ virtual SystemFontData GetSysFontData( int nFallbacklevel ) const;
+};
+
+// Init/Deinit Graphics
+void ImplSalInitGraphics( WinSalGraphics* mpData );
+void ImplSalDeInitGraphics( WinSalGraphics* mpData );
+void ImplUpdateSysColorEntries();
+int ImplIsSysColorEntry( SalColor nSalColor );
+void ImplGetLogFontFromFontSelect( HDC hDC, const ImplFontSelectData*,
+ LOGFONTW&, bool bTestVerticalAvail );
+
+// -----------
+// - Defines -
+// -----------
+
+#define MAX_64KSALPOINTS ((((USHORT)0xFFFF)-8)/sizeof(POINTS))
+
+// -----------
+// - Inlines -
+// -----------
+
+// #102411# Win's GCP mishandles kerning => we need to do it ourselves
+// SalGraphicsData::mpFontKernPairs is sorted by
+inline bool ImplCmpKernData( const KERNINGPAIR& a, const KERNINGPAIR& b )
+{
+ if( a.wFirst < b.wFirst )
+ return true;
+ if( a.wFirst > b.wFirst )
+ return false;
+ return (a.wSecond < b.wSecond);
+}
+
+// called extremely often from just one spot => inline
+inline bool ImplWinFontData::HasChar( sal_uInt32 cChar ) const
+{
+ if( mpUnicodeMap->HasChar( cChar ) )
+ return true;
+ // second chance to allow symbol aliasing
+ if( mbAliasSymbolsLow && ((cChar-0xF000) <= 0xFF) )
+ cChar -= 0xF000;
+ else if( mbAliasSymbolsHigh && (cChar <= 0xFF) )
+ cChar += 0xF000;
+ return mpUnicodeMap->HasChar( cChar );
+}
+
+#endif // _SV_SALGDI_H
diff --git a/vcl/win/inc/salids.hrc b/vcl/win/inc/salids.hrc
new file mode 100644
index 000000000000..3049f11b551b
--- /dev/null
+++ b/vcl/win/inc/salids.hrc
@@ -0,0 +1,120 @@
+/*************************************************************************
+ *
+ * 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_SALIDS_HRC
+#define _SV_SALIDS_HRC
+
+// Cursor
+#define SAL_RESID_POINTER_NULL 10000
+#ifndef W40ONLY
+#define SAL_RESID_POINTER_HELP 10001
+#endif
+#ifndef WNT
+#define SAL_RESID_POINTER_HSIZE 10002
+#define SAL_RESID_POINTER_VSIZE 10003
+#define SAL_RESID_POINTER_NESWSIZE 10004
+#define SAL_RESID_POINTER_NWSESIZE 10005
+#endif
+#define SAL_RESID_POINTER_CROSS 10006
+#define SAL_RESID_POINTER_MOVE 10007
+#define SAL_RESID_POINTER_HSPLIT 10008
+#define SAL_RESID_POINTER_VSPLIT 10009
+#define SAL_RESID_POINTER_HSIZEBAR 10010
+#define SAL_RESID_POINTER_VSIZEBAR 10011
+#define SAL_RESID_POINTER_HAND 10012
+#define SAL_RESID_POINTER_REFHAND 10013
+#define SAL_RESID_POINTER_PEN 10014
+#define SAL_RESID_POINTER_MAGNIFY 10015
+#define SAL_RESID_POINTER_FILL 10016
+#define SAL_RESID_POINTER_ROTATE 10017
+#define SAL_RESID_POINTER_HSHEAR 10018
+#define SAL_RESID_POINTER_VSHEAR 10019
+#define SAL_RESID_POINTER_MIRROR 10020
+#define SAL_RESID_POINTER_CROOK 10021
+#define SAL_RESID_POINTER_CROP 10022
+#define SAL_RESID_POINTER_MOVEPOINT 10023
+#define SAL_RESID_POINTER_MOVEBEZIERWEIGHT 10024
+#define SAL_RESID_POINTER_MOVEDATA 10025
+#define SAL_RESID_POINTER_COPYDATA 10026
+#define SAL_RESID_POINTER_LINKDATA 10027
+#define SAL_RESID_POINTER_MOVEDATALINK 10028
+#define SAL_RESID_POINTER_COPYDATALINK 10029
+#define SAL_RESID_POINTER_MOVEFILE 10030
+#define SAL_RESID_POINTER_COPYFILE 10031
+#define SAL_RESID_POINTER_LINKFILE 10032
+#define SAL_RESID_POINTER_MOVEFILELINK 10033
+#define SAL_RESID_POINTER_COPYFILELINK 10034
+#define SAL_RESID_POINTER_MOVEFILES 10035
+#define SAL_RESID_POINTER_COPYFILES 10036
+#define SAL_RESID_POINTER_NOTALLOWED 10037
+#define SAL_RESID_POINTER_DRAW_LINE 10038
+#define SAL_RESID_POINTER_DRAW_RECT 10039
+#define SAL_RESID_POINTER_DRAW_POLYGON 10040
+#define SAL_RESID_POINTER_DRAW_BEZIER 10041
+#define SAL_RESID_POINTER_DRAW_ARC 10042
+#define SAL_RESID_POINTER_DRAW_PIE 10043
+#define SAL_RESID_POINTER_DRAW_CIRCLECUT 10044
+#define SAL_RESID_POINTER_DRAW_ELLIPSE 10045
+#define SAL_RESID_POINTER_DRAW_FREEHAND 10046
+#define SAL_RESID_POINTER_DRAW_CONNECT 10047
+#define SAL_RESID_POINTER_DRAW_TEXT 10048
+#define SAL_RESID_POINTER_DRAW_CAPTION 10049
+#define SAL_RESID_POINTER_CHART 10050
+#define SAL_RESID_POINTER_DETECTIVE 10051
+#define SAL_RESID_POINTER_PIVOT_COL 10052
+#define SAL_RESID_POINTER_PIVOT_ROW 10053
+#define SAL_RESID_POINTER_PIVOT_FIELD 10054
+#define SAL_RESID_POINTER_CHAIN 10055
+#define SAL_RESID_POINTER_CHAIN_NOTALLOWED 10056
+#define SAL_RESID_POINTER_TIMEEVENT_MOVE 10057
+#define SAL_RESID_POINTER_TIMEEVENT_SIZE 10058
+#define SAL_RESID_POINTER_AUTOSCROLL_N 10059
+#define SAL_RESID_POINTER_AUTOSCROLL_S 10060
+#define SAL_RESID_POINTER_AUTOSCROLL_W 10061
+#define SAL_RESID_POINTER_AUTOSCROLL_E 10062
+#define SAL_RESID_POINTER_AUTOSCROLL_NW 10063
+#define SAL_RESID_POINTER_AUTOSCROLL_NE 10064
+#define SAL_RESID_POINTER_AUTOSCROLL_SW 10065
+#define SAL_RESID_POINTER_AUTOSCROLL_SE 10066
+#define SAL_RESID_POINTER_AUTOSCROLL_NS 10067
+#define SAL_RESID_POINTER_AUTOSCROLL_WE 10068
+#define SAL_RESID_POINTER_AUTOSCROLL_NSWE 10069
+#define SAL_RESID_POINTER_AIRBRUSH 10070
+#define SAL_RESID_POINTER_TEXT_VERTICAL 10071
+#define SAL_RESID_POINTER_PIVOT_DELETE 10072
+#define SAL_RESID_POINTER_TAB_SELECT_S 10073
+#define SAL_RESID_POINTER_TAB_SELECT_E 10074
+#define SAL_RESID_POINTER_TAB_SELECT_SE 10075
+#define SAL_RESID_POINTER_TAB_SELECT_W 10076
+#define SAL_RESID_POINTER_TAB_SELECT_SW 10077
+#define SAL_RESID_POINTER_PAINTBRUSH 10078
+
+#define SAL_RESID_BITMAP_50 11000
+
+#define SAL_RESID_ICON_DEFAULT 1
+
+#endif // _SV_SALIDS_HRC
diff --git a/vcl/win/inc/salinst.h b/vcl/win/inc/salinst.h
new file mode 100644
index 000000000000..f3005e3ad30b
--- /dev/null
+++ b/vcl/win/inc/salinst.h
@@ -0,0 +1,103 @@
+/*************************************************************************
+ *
+ * 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_SALINST_H
+#define _SV_SALINST_H
+
+#include <vcl/sv.h>
+#include <vcl/salinst.hxx>
+
+namespace vos { class OMutex; }
+
+// -------------------
+// - SalInstanceData -
+// -------------------
+
+class SalYieldMutex;
+
+class WinSalInstance : public SalInstance
+{
+public:
+ HINSTANCE mhInst; // Instance Handle
+ HWND mhComWnd; // window, for communication (between threads and the main thread)
+ SalYieldMutex* mpSalYieldMutex; // Sal-Yield-Mutex
+ vos::OMutex* mpSalWaitMutex; // Sal-Wait-Mutex
+ USHORT mnYieldWaitCount; // Wait-Count
+public:
+ WinSalInstance();
+ virtual ~WinSalInstance();
+
+ virtual SalFrame* CreateChildFrame( SystemParentData* pParent, ULONG nStyle );
+ virtual SalFrame* CreateFrame( SalFrame* pParent, ULONG nStyle );
+ virtual void DestroyFrame( SalFrame* pFrame );
+ virtual SalObject* CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, BOOL bShow = TRUE );
+ virtual void DestroyObject( SalObject* pObject );
+ virtual SalVirtualDevice* CreateVirtualDevice( SalGraphics* pGraphics,
+ long nDX, long nDY,
+ USHORT nBitCount, const SystemGraphicsData *pData );
+ virtual void DestroyVirtualDevice( SalVirtualDevice* pDevice );
+
+ virtual SalInfoPrinter* CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
+ ImplJobSetup* pSetupData );
+ virtual void DestroyInfoPrinter( SalInfoPrinter* pPrinter );
+ virtual SalPrinter* CreatePrinter( SalInfoPrinter* pInfoPrinter );
+ virtual void DestroyPrinter( SalPrinter* pPrinter );
+ virtual void GetPrinterQueueInfo( ImplPrnQueueList* pList );
+ virtual void GetPrinterQueueState( SalPrinterQueueInfo* pInfo );
+ virtual void DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo );
+ virtual String GetDefaultPrinter();
+ virtual SalTimer* CreateSalTimer();
+ virtual SalI18NImeStatus* CreateI18NImeStatus();
+ virtual SalSystem* CreateSalSystem();
+ virtual SalBitmap* CreateSalBitmap();
+ virtual vos::IMutex* GetYieldMutex();
+ virtual ULONG ReleaseYieldMutex();
+ virtual void AcquireYieldMutex( ULONG nCount );
+ virtual void Yield( bool bWait, bool bHandleAllCurrentEvents );
+ virtual bool AnyInput( USHORT nType );
+ virtual SalMenu* CreateMenu( BOOL bMenuBar );
+ virtual void DestroyMenu( SalMenu* );
+ virtual SalMenuItem* CreateMenuItem( const SalItemParams* pItemData );
+ virtual void DestroyMenuItem( SalMenuItem* );
+ virtual SalSession* CreateSalSession();
+ virtual void* GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes );
+ virtual void AddToRecentDocumentList(const rtl::OUString& rFileUrl, const rtl::OUString& rMimeType);
+
+ static int WorkaroundExceptionHandlingInUSER32Lib(int nExcept, LPEXCEPTION_POINTERS pExceptionInfo);
+};
+
+// --------------
+// - Prototypen -
+// --------------
+
+SalFrame* ImplSalCreateFrame( WinSalInstance* pInst, HWND hWndParent, ULONG nSalFrameStyle );
+SalObject* ImplSalCreateObject( WinSalInstance* pInst, WinSalFrame* pParent );
+HWND ImplSalReCreateHWND( HWND hWndParent, HWND oldhWnd, BOOL bAsChild );
+void ImplSalStartTimer( ULONG nMS, BOOL bMutex = FALSE );
+void ImplSalPrinterAbortJobAsync( HDC hPrnDC );
+
+#endif // _SV_SALINST_H
diff --git a/vcl/win/inc/salmenu.h b/vcl/win/inc/salmenu.h
new file mode 100644
index 000000000000..7f1774b61975
--- /dev/null
+++ b/vcl/win/inc/salmenu.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALMENU_H
+#define _SV_SALMENU_H
+
+#include <vcl/sv.h>
+#include <vcl/bitmap.hxx>
+#include <vcl/salmenu.hxx>
+
+
+class WinSalMenu : public SalMenu
+{
+public:
+ WinSalMenu();
+ virtual ~WinSalMenu();
+ virtual BOOL VisibleMenuBar(); // must return TRUE to actually DISPLAY native menu bars
+ // otherwise only menu messages are processed (eg, OLE on Windows)
+
+ virtual void InsertItem( SalMenuItem* pSalMenuItem, unsigned nPos );
+ virtual void RemoveItem( unsigned nPos );
+ virtual void SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos );
+ virtual void SetFrame( const SalFrame* pFrame );
+ virtual void CheckItem( unsigned nPos, BOOL bCheck );
+ virtual void EnableItem( unsigned nPos, BOOL bEnable );
+ virtual void SetItemText( unsigned nPos, SalMenuItem* pSalMenuItem, const XubString& rText );
+ virtual void SetItemImage( unsigned nPos, SalMenuItem* pSalMenuItem, const Image& rImage );
+ virtual void SetAccelerator( unsigned nPos, SalMenuItem* pSalMenuItem, const KeyCode& rKeyCode, const XubString& rKeyName );
+ virtual void GetSystemMenuData( SystemMenuData* pData );
+
+ HMENU mhMenu; // the menu handle
+ BOOL mbMenuBar; // true for menu bars
+ HWND mhWnd; // the window handle where the menubar is attached, may be NULL
+ WinSalMenu *mpParentMenu; // the parent menu
+};
+
+class WinSalMenuItem : public SalMenuItem
+{
+public:
+ WinSalMenuItem();
+ virtual ~WinSalMenuItem();
+
+
+ MENUITEMINFOW mInfo;
+ void* mpMenu; // pointer to corresponding VCL menu
+ XubString mText; // the item text
+ XubString mAccelText; // the accelerator string
+ Bitmap maBitmap; // item image
+ int mnId; // item id
+ WinSalMenu* mpSalMenu; // the menu where this item is inserted
+};
+
+#endif // _SV_SALMENU_H
+
diff --git a/vcl/win/inc/salnativewidgets.h b/vcl/win/inc/salnativewidgets.h
new file mode 100644
index 000000000000..fceee1076595
--- /dev/null
+++ b/vcl/win/inc/salnativewidgets.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_NATIVEWIDGETS_H
+#define _SV_NATIVEWIDGETS_H
+
+
+#ifdef __cplusplus
+
+#include <vcl/sv.h>
+
+/* SalControlHandleData:
+ *
+ * Holds platform specific theming data.
+ */
+
+class SalControlHandleData
+{
+ public:
+ SalControlHandleData( void );
+ ~SalControlHandleData( void );
+
+ public:
+ // nothing needed on Win32
+};
+
+
+#endif /* __cplusplus */
+
+#endif
diff --git a/vcl/win/inc/salobj.h b/vcl/win/inc/salobj.h
new file mode 100644
index 000000000000..11ae96931321
--- /dev/null
+++ b/vcl/win/inc/salobj.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALOBJ_H
+#define _SV_SALOBJ_H
+
+#include <vcl/sv.h>
+#include <vcl/salobj.hxx>
+
+// -----------------
+// - SalObjectData -
+// -----------------
+
+class WinSalObject : public SalObject
+{
+public:
+ HWND mhWnd; // Window handle
+ HWND mhWndChild; // Child Window handle
+ HWND mhLastFocusWnd; // Child-Window, welches als letztes den Focus hatte
+ SystemChildData maSysData; // SystemEnvData
+ RGNDATA* mpClipRgnData; // ClipRegion-Data
+ RGNDATA* mpStdClipRgnData; // Cache Standard-ClipRegion-Data
+ RECT* mpNextClipRect; // Naechstes ClipRegion-Rect
+ BOOL mbFirstClipRect; // Flag for first cliprect to insert
+ WinSalObject* mpNextObject; // pointer to next object
+
+
+ WinSalObject();
+ virtual ~WinSalObject();
+
+ virtual void ResetClipRegion();
+ virtual USHORT GetClipRegionType();
+ virtual void BeginSetClipRegion( ULONG nRects );
+ virtual void UnionClipRegion( long nX, long nY, long nWidth, long nHeight );
+ virtual void EndSetClipRegion();
+ virtual void SetPosSize( long nX, long nY, long nWidth, long nHeight );
+ virtual void Show( BOOL bVisible );
+ virtual void Enable( BOOL nEnable );
+ virtual void GrabFocus();
+ virtual void SetBackground();
+ virtual void SetBackground( SalColor nSalColor );
+ virtual const SystemEnvData* GetSystemData() const;
+};
+
+#endif // _SV_SALOBJ_H
diff --git a/vcl/win/inc/salprn.h b/vcl/win/inc/salprn.h
new file mode 100644
index 000000000000..57ae8eae55e3
--- /dev/null
+++ b/vcl/win/inc/salprn.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALPRN_H
+#define _SV_SALPRN_H
+
+#include <vcl/sv.h>
+#include <vcl/salprn.hxx>
+
+// -----------------
+// - SalDriverData -
+// -----------------
+
+// WNT3
+#define SAL_DRIVERDATA_SYSSIGN ((ULONG)0x574E5433)
+#define SAL_DRIVERDATA_VERSION_A 1
+#define SAL_DRIVERDATA_VERSION_W 2
+
+#pragma pack( 1 )
+
+struct SalDriverData
+{
+ ULONG mnSysSignature;
+ USHORT mnVersion;
+ USHORT mnDriverOffset;
+ BYTE maDriverData[1];
+};
+
+#pragma pack()
+
+// ---------------------
+// - WinSalInfoPrinter -
+// ---------------------
+
+class WinSalGraphics;
+
+class WinSalInfoPrinter : public SalInfoPrinter
+{
+public:
+ WinSalGraphics* mpGraphics; // current Printer graphics
+ XubString maDriverName; // printer driver name
+ XubString maDeviceName; // printer device name
+ XubString maPortName; // printer port name
+ HDC mhDC; // printer hdc
+ BOOL mbGraphics; // is Graphics used
+public:
+ WinSalInfoPrinter();
+ virtual ~WinSalInfoPrinter();
+
+ virtual SalGraphics* GetGraphics();
+ virtual void ReleaseGraphics( SalGraphics* pGraphics );
+ virtual BOOL Setup( SalFrame* pFrame, ImplJobSetup* pSetupData );
+ virtual BOOL SetPrinterData( ImplJobSetup* pSetupData );
+ virtual BOOL SetData( ULONG nFlags, ImplJobSetup* pSetupData );
+ virtual void GetPageInfo( const ImplJobSetup* pSetupData,
+ long& rOutWidth, long& rOutHeight,
+ long& rPageOffX, long& rPageOffY,
+ long& rPageWidth, long& rPageHeight );
+ virtual ULONG GetCapabilities( const ImplJobSetup* pSetupData, USHORT nType );
+ virtual ULONG GetPaperBinCount( const ImplJobSetup* pSetupData );
+ virtual String GetPaperBinName( const ImplJobSetup* pSetupData, ULONG nPaperBin );
+ virtual void InitPaperFormats( const ImplJobSetup* pSetupData );
+ virtual int GetLandscapeAngle( const ImplJobSetup* pSetupData );
+};
+
+// -----------------
+// - WinSalPrinter -
+// -----------------
+
+class WinSalPrinter : public SalPrinter
+{
+public:
+ WinSalGraphics* mpGraphics; // current Printer graphics
+ WinSalInfoPrinter* mpInfoPrinter; // pointer to the compatible InfoPrinter
+ WinSalPrinter* mpNextPrinter; // next printing printer
+ HDC mhDC; // printer hdc
+ ULONG mnError; // Error Code
+ ULONG mnCopies; // Kopien
+ BOOL mbCollate; // Sortierte Kopien
+ BOOL mbAbort; // Job Aborted
+
+ bool mbValid;
+
+public:
+ WinSalPrinter();
+ virtual ~WinSalPrinter();
+
+ using SalPrinter::StartJob;
+ virtual BOOL StartJob( const XubString* pFileName,
+ const XubString& rJobName,
+ const XubString& rAppName,
+ ULONG nCopies,
+ bool bCollate,
+ bool bDirect,
+ ImplJobSetup* pSetupData );
+ virtual BOOL EndJob();
+ virtual BOOL AbortJob();
+ virtual SalGraphics* StartPage( ImplJobSetup* pSetupData, BOOL bNewJobData );
+ virtual BOOL EndPage();
+ virtual ULONG GetErrorCode();
+
+ void markInvalid();
+ bool isValid() const { return mbValid; }
+};
+
+#endif // _SV_SALPRN_H
diff --git a/vcl/win/inc/salsys.h b/vcl/win/inc/salsys.h
new file mode 100644
index 000000000000..b6eadc6e6818
--- /dev/null
+++ b/vcl/win/inc/salsys.h
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_SALSYS_H
+#define _SV_SALSYS_H
+
+#include <vcl/salsys.hxx>
+
+#include <vector>
+#include <map>
+
+class WinSalSystem : public SalSystem
+{
+ public:
+ struct DisplayMonitor
+ {
+ rtl::OUString m_aName;
+ rtl::OUString m_aDeviceName;
+ Rectangle m_aArea;
+ Rectangle m_aWorkArea;
+ sal_Int32 m_nStateFlags;
+
+ DisplayMonitor() : m_nStateFlags( 0 ) {}
+ DisplayMonitor( const rtl::OUString& rName,
+ const rtl::OUString& rDevName,
+ const Rectangle& rArea,
+ const Rectangle& rWorkArea,
+ DWORD nStateFlags )
+ : m_aName( rName ),
+ m_aDeviceName( rDevName ),
+ m_aArea( rArea ),
+ m_aWorkArea( rWorkArea ),
+ m_nStateFlags( nStateFlags )
+ {
+ }
+ ~DisplayMonitor() {}
+ };
+ private:
+ std::vector<DisplayMonitor> m_aMonitors;
+ std::map<rtl::OUString, unsigned int> m_aDeviceNameToMonitor;
+ unsigned int m_nPrimary;
+public:
+ WinSalSystem() : m_nPrimary( 0 ) {}
+ virtual ~WinSalSystem();
+
+ virtual unsigned int GetDisplayScreenCount();
+ virtual bool IsMultiDisplay();
+ virtual unsigned int GetDefaultDisplayNumber();
+ virtual Rectangle GetDisplayScreenPosSizePixel( unsigned int nScreen );
+ virtual Rectangle GetDisplayWorkAreaPosSizePixel( unsigned int nScreen );
+ virtual rtl::OUString GetScreenName( unsigned int nScreen );
+ virtual int ShowNativeMessageBox( const String& rTitle,
+ const String& rMessage,
+ int nButtonCombination,
+ int nDefaultButton);
+ bool initMonitors();
+ // discards monitorinfo; used by WM_DISPLAYCHANGED handler
+ void clearMonitors();
+ const std::vector<DisplayMonitor>& getMonitors()
+ { initMonitors(); return m_aMonitors;}
+
+ BOOL handleMonitorCallback( sal_IntPtr /*HMONITOR*/,
+ sal_IntPtr /*HDC*/,
+ sal_IntPtr /*LPRECT*/ );
+};
+
+#endif // _SV_SALSYS_H
+
diff --git a/vcl/win/inc/saltimer.h b/vcl/win/inc/saltimer.h
new file mode 100644
index 000000000000..c24af459aa97
--- /dev/null
+++ b/vcl/win/inc/saltimer.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 _SV_SALTIMER_H
+#define _SV_SALTIMER_H
+
+#include <vcl/saltimer.hxx>
+
+class WinSalTimer : public SalTimer
+{
+public:
+ WinSalTimer() {}
+ virtual ~WinSalTimer();
+
+ // overload all pure virtual methods
+ void Start( ULONG nMS );
+ void Stop();
+};
+
+#endif
diff --git a/vcl/win/inc/salvd.h b/vcl/win/inc/salvd.h
new file mode 100644
index 000000000000..d0f32a6460a9
--- /dev/null
+++ b/vcl/win/inc/salvd.h
@@ -0,0 +1,61 @@
+/*************************************************************************
+ *
+ * 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_SALVD_H
+#define _SV_SALVD_H
+
+#include <vcl/sv.h>
+#include <vcl/salvd.hxx>
+
+class WinSalGraphics;
+
+// -----------------
+// - SalVirDevData -
+// -----------------
+
+class WinSalVirtualDevice : public SalVirtualDevice
+{
+public:
+ HDC mhDC; // HDC or 0 for Cache Device
+ HBITMAP mhBmp; // Memory Bitmap
+ HBITMAP mhDefBmp; // Default Bitmap
+ WinSalGraphics* mpGraphics; // current VirDev graphics
+ WinSalVirtualDevice* mpNext; // next VirDev
+ USHORT mnBitCount; // BitCount (0 or 1)
+ BOOL mbGraphics; // is Graphics used
+ BOOL mbForeignDC; // uses a foreign DC instead of a bitmap
+
+ WinSalVirtualDevice();
+ virtual ~WinSalVirtualDevice();
+
+ virtual SalGraphics* GetGraphics();
+ virtual void ReleaseGraphics( SalGraphics* pGraphics );
+ virtual BOOL SetSize( long nNewDX, long nNewDY );
+ virtual void GetSize( long& rWidth, long& rHeight );
+};
+
+#endif // _SV_SALVD_H
diff --git a/vcl/win/inc/svsys.h b/vcl/win/inc/svsys.h
new file mode 100644
index 000000000000..7b0e87304d59
--- /dev/null
+++ b/vcl/win/inc/svsys.h
@@ -0,0 +1,33 @@
+/*************************************************************************
+ *
+ * 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_SVSYS_H
+#define _SV_SVSYS_H
+
+#include <tools/svwin.h>
+
+#endif // _SV_SVSYS_H
diff --git a/vcl/win/inc/wincomp.hxx b/vcl/win/inc/wincomp.hxx
new file mode 100644
index 000000000000..61e04779dbce
--- /dev/null
+++ b/vcl/win/inc/wincomp.hxx
@@ -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.
+ *
+ ************************************************************************/
+
+#ifndef _SV_WINCOMP_HXX
+#define _SV_WINCOMP_HXX
+
+#ifndef _STRING_H
+#include <string.h>
+#endif
+#include <vcl/sv.h>
+
+// ----------
+// - Strict -
+// ----------
+
+// Anpassungen fuer TypeChecking
+
+inline HPEN SelectPen( HDC hDC, HPEN hPen )
+{
+ return (HPEN)SelectObject( hDC, (HGDIOBJ)hPen );
+}
+
+inline void DeletePen( HPEN hPen )
+{
+ DeleteObject( (HGDIOBJ)hPen );
+}
+
+inline HPEN GetStockPen( int nObject )
+{
+ return (HPEN)GetStockObject( nObject );
+}
+
+inline HBRUSH SelectBrush( HDC hDC, HBRUSH hBrush )
+{
+ return (HBRUSH)SelectObject( hDC, (HGDIOBJ)hBrush );
+}
+
+inline void DeleteBrush( HBRUSH hBrush )
+{
+ DeleteObject( (HGDIOBJ)hBrush );
+}
+
+inline HBRUSH GetStockBrush( int nObject )
+{
+ return (HBRUSH)GetStockObject( nObject );
+}
+
+inline HFONT SelectFont( HDC hDC, HFONT hFont )
+{
+ return (HFONT)SelectObject( hDC, (HGDIOBJ)hFont );
+}
+
+inline void DeleteFont( HFONT hFont )
+{
+ DeleteObject( (HGDIOBJ)hFont );
+}
+
+inline HFONT GetStockFont( int nObject )
+{
+ return (HFONT)GetStockObject( nObject );
+}
+
+inline HBITMAP SelectBitmap( HDC hDC, HBITMAP hBitmap )
+{
+ return (HBITMAP)SelectObject( hDC, (HGDIOBJ)hBitmap );
+}
+
+inline void DeleteBitmap( HBITMAP hBitmap )
+{
+ DeleteObject( (HGDIOBJ)hBitmap );
+}
+
+inline void DeleteRegion( HRGN hRegion )
+{
+ DeleteObject( (HGDIOBJ)hRegion );
+}
+
+inline HPALETTE GetStockPalette( int nObject )
+{
+ return (HPALETTE)GetStockObject( nObject );
+}
+
+inline void DeletePalette( HPALETTE hPalette )
+{
+ DeleteObject( (HGDIOBJ)hPalette );
+}
+
+inline void SetWindowStyle( HWND hWnd, DWORD nStyle )
+{
+ SetWindowLong( hWnd, GWL_STYLE, nStyle );
+}
+
+inline DWORD GetWindowStyle( HWND hWnd )
+{
+ return GetWindowLong( hWnd, GWL_STYLE );
+}
+
+inline void SetWindowExStyle( HWND hWnd, DWORD nStyle )
+{
+ SetWindowLong( hWnd, GWL_EXSTYLE, nStyle );
+}
+
+inline DWORD GetWindowExStyle( HWND hWnd )
+{
+ return GetWindowLong( hWnd, GWL_EXSTYLE );
+}
+
+inline WIN_BOOL IsMinimized( HWND hWnd )
+{
+ return IsIconic( hWnd );
+}
+
+inline WIN_BOOL IsMaximized( HWND hWnd )
+{
+ return IsZoomed( hWnd );
+}
+
+inline void SetWindowFont( HWND hWnd, HFONT hFont, WIN_BOOL bRedraw )
+{
+ SendMessage( hWnd, WM_SETFONT, (WPARAM)hFont, MAKELPARAM((UINT)bRedraw,0) );
+}
+
+inline HFONT GetWindowFont( HWND hWnd )
+{
+ return (HFONT)(UINT)SendMessage( hWnd, WM_GETFONT, 0, 0 );
+}
+
+inline void SetClassCursor( HWND hWnd, HCURSOR hCursor )
+{
+ SetClassLong( hWnd, GCL_HCURSOR, (DWORD)hCursor );
+}
+
+inline HCURSOR GetClassCursor( HWND hWnd )
+{
+ return (HCURSOR)GetClassLong( hWnd, GCL_HCURSOR );
+}
+
+inline void SetClassIcon( HWND hWnd, HICON hIcon )
+{
+ SetClassLong( hWnd, GCL_HICON, (DWORD)hIcon );
+}
+
+inline HICON GetClassIcon( HWND hWnd )
+{
+ return (HICON)GetClassLong( hWnd, GCL_HICON );
+}
+
+inline HBRUSH SetClassBrush( HWND hWnd, HBRUSH hBrush )
+{
+ return (HBRUSH)SetClassLong( hWnd, GCL_HBRBACKGROUND, (DWORD)hBrush );
+}
+
+inline HBRUSH GetClassBrush( HWND hWnd )
+{
+ return (HBRUSH)GetClassLong( hWnd, GCL_HBRBACKGROUND );
+}
+
+inline HINSTANCE GetWindowInstance( HWND hWnd )
+{
+ return (HINSTANCE)GetWindowLong( hWnd, GWL_HINSTANCE );
+}
+
+// ------------------------
+// - ZMouse Erweiterungen -
+// ------------------------
+
+#define MSH_MOUSEWHEEL "MSWHEEL_ROLLMSG"
+
+#define MOUSEZ_CLASSNAME "MouseZ" // wheel window class
+#define MOUSEZ_TITLE "Magellan MSWHEEL" // wheel window title
+
+#define MSH_WHEELMODULE_CLASS (MOUSEZ_CLASSNAME)
+#define MSH_WHEELMODULE_TITLE (MOUSEZ_TITLE)
+
+#define MSH_SCROLL_LINES "MSH_SCROLL_LINES_MSG"
+
+#ifndef WHEEL_DELTA
+#define WHEEL_DELTA 120
+#endif
+#ifndef WM_MOUSEWHEEL
+#define WM_MOUSEWHEEL 0x020A
+#endif
+#ifndef SPI_GETWHEELSCROLLLINES
+#define SPI_GETWHEELSCROLLLINES 104
+#endif
+#ifndef SPI_SETWHEELSCROLLLINES
+#define SPI_SETWHEELSCROLLLINES 105
+#endif
+#ifndef WHEEL_PAGESCROLL
+#define WHEEL_PAGESCROLL (UINT_MAX)
+#endif
+
+
+// -----------------------------
+// - SystemAgent Erweiterungen -
+// -----------------------------
+
+#define ENABLE_AGENT 1
+#define DISABLE_AGENT 2
+#define GET_AGENT_STATUS 3
+typedef int (APIENTRY* SysAgt_Enable_PROC)( int );
+
+// ---------------------
+// - 5.0-Erweiterungen -
+// ---------------------
+
+#ifndef COLOR_GRADIENTACTIVECAPTION
+#define COLOR_GRADIENTACTIVECAPTION 27
+#endif
+#ifndef COLOR_GRADIENTINACTIVECAPTION
+#define COLOR_GRADIENTINACTIVECAPTION 28
+#endif
+
+#ifndef SPI_GETFLATMENU
+#define SPI_GETFLATMENU 0x1022
+#endif
+#ifndef COLOR_MENUBAR
+#define COLOR_MENUBAR 30
+#endif
+#ifndef COLOR_MENUHILIGHT
+#define COLOR_MENUHILIGHT 29
+#endif
+
+#ifndef CS_DROPSHADOW
+#define CS_DROPSHADOW 0x00020000
+#endif
+
+// -------------------------------------------------------
+// MT 12/03: From winuser.h, only needed in salframe.cxx
+// Better change salframe.cxx to include winuser.h
+// -------------------------------------------------------
+
+#define WS_EX_LAYERED 0x00080000
+
+#ifndef WM_UNICHAR
+#define WM_UNICHAR 0x0109
+#define UNICODE_NOCHAR 0xFFFF
+#endif
+
+#endif // _SV_WINCOMP_HXX
diff --git a/vcl/win/source/app/MAKEFILE.MK b/vcl/win/source/app/MAKEFILE.MK
new file mode 100644
index 000000000000..9b3237567eff
--- /dev/null
+++ b/vcl/win/source/app/MAKEFILE.MK
@@ -0,0 +1,53 @@
+#*************************************************************************
+#
+# 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=salapp
+ENABLE_EXCEPTIONS=TRUE
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+# --- #105371#
+CFLAGS += -DWINVER=0x0400
+
+# --- Files --------------------------------------------------------
+
+SLOFILES= $(SLO)$/salshl.obj \
+ $(SLO)$/saldata.obj \
+ $(SLO)$/salinst.obj \
+ $(SLO)$/saltimer.obj \
+ $(SLO)$/salinfo.obj
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
diff --git a/vcl/win/source/app/saldata.cxx b/vcl/win/source/app/saldata.cxx
new file mode 100644
index 000000000000..bb8a198a96e6
--- /dev/null
+++ b/vcl/win/source/app/saldata.cxx
@@ -0,0 +1,190 @@
+/*************************************************************************
+ *
+ * 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/svwin.h>
+#include "rtl/tencinfo.h"
+#include <saldata.hxx>
+#include <vcl/svapp.hxx>
+
+
+// =======================================================================
+
+rtl_TextEncoding ImplSalGetSystemEncoding()
+{
+ static UINT nOldAnsiCodePage = 0;
+ static rtl_TextEncoding eEncoding = RTL_TEXTENCODING_MS_1252;
+
+ UINT nAnsiCodePage = GetACP();
+ if ( nAnsiCodePage != nOldAnsiCodePage )
+ {
+ rtl_TextEncoding nEnc
+ = rtl_getTextEncodingFromWindowsCodePage(nAnsiCodePage);
+ if (nEnc != RTL_TEXTENCODING_DONTKNOW)
+ eEncoding = nEnc;
+ }
+
+ return eEncoding;
+}
+
+// -----------------------------------------------------------------------
+
+ByteString ImplSalGetWinAnsiString( const UniString& rStr, BOOL bFileName )
+{
+ rtl_TextEncoding eEncoding = ImplSalGetSystemEncoding();
+ if ( bFileName )
+ {
+ return ByteString( rStr, eEncoding,
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_UNDERLINE |
+ RTL_UNICODETOTEXT_FLAGS_INVALID_UNDERLINE |
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACE |
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACESTR |
+ RTL_UNICODETOTEXT_FLAGS_PRIVATE_MAPTO0 );
+ }
+ else
+ {
+ return ByteString( rStr, eEncoding,
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_DEFAULT |
+ RTL_UNICODETOTEXT_FLAGS_INVALID_DEFAULT |
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACE |
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACESTR |
+ RTL_UNICODETOTEXT_FLAGS_PRIVATE_MAPTO0 );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+UniString ImplSalGetUniString( const sal_Char* pStr, xub_StrLen nLen )
+{
+ return UniString( pStr, nLen, ImplSalGetSystemEncoding(),
+ RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_DEFAULT |
+ RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT |
+ RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT );
+}
+
+// =======================================================================
+
+int ImplSalWICompareAscii( const wchar_t* pStr1, const char* pStr2 )
+{
+ int nRet;
+ wchar_t c1;
+ char c2;
+ do
+ {
+ // Ist das Zeichen zwischen 'A' und 'Z' dann umwandeln
+ c1 = *pStr1;
+ c2 = *pStr2;
+ if ( (c1 >= 65) && (c1 <= 90) )
+ c1 += 32;
+ if ( (c2 >= 65) && (c2 <= 90) )
+ c2 += 32;
+ nRet = ((sal_Int32)c1)-((sal_Int32)((unsigned char)c2));
+ if ( nRet != 0 )
+ break;
+
+ pStr1++;
+ pStr2++;
+ }
+ while ( c2 );
+
+ return nRet;
+}
+
+// =======================================================================
+
+LONG ImplSetWindowLong( HWND hWnd, int nIndex, DWORD dwNewLong )
+{
+ if ( aSalShlData.mbWNT )
+ return SetWindowLongW( hWnd, nIndex, dwNewLong );
+ else
+ return SetWindowLongA( hWnd, nIndex, dwNewLong );
+}
+
+// -----------------------------------------------------------------------
+
+LONG ImplGetWindowLong( HWND hWnd, int nIndex )
+{
+ if ( aSalShlData.mbWNT )
+ return GetWindowLongW( hWnd, nIndex );
+ else
+ return GetWindowLongA( hWnd, nIndex );
+}
+
+// -----------------------------------------------------------------------
+
+WIN_BOOL ImplPostMessage( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
+{
+ if ( aSalShlData.mbWNT )
+ return PostMessageW( hWnd, nMsg, wParam, lParam );
+ else
+ return PostMessageA( hWnd, nMsg, wParam, lParam );
+}
+
+// -----------------------------------------------------------------------
+
+WIN_BOOL ImplSendMessage( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
+{
+ WIN_BOOL bRet;
+ if ( aSalShlData.mbWNT )
+ bRet = SendMessageW( hWnd, nMsg, wParam, lParam );
+ else
+ bRet = SendMessageA( hWnd, nMsg, wParam, lParam );
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+WIN_BOOL ImplGetMessage( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax )
+{
+ if ( aSalShlData.mbWNT )
+ return GetMessageW( lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax );
+ else
+ return GetMessageA( lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax );
+}
+
+// -----------------------------------------------------------------------
+
+WIN_BOOL ImplPeekMessage( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg )
+{
+ if ( aSalShlData.mbWNT )
+ return PeekMessageW( lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg );
+ else
+ return PeekMessageA( lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg );
+}
+
+// -----------------------------------------------------------------------
+
+LONG ImplDispatchMessage( CONST MSG *lpMsg )
+{
+ if ( aSalShlData.mbWNT )
+ return DispatchMessageW( lpMsg );
+ else
+ return DispatchMessageA( lpMsg );
+}
+
diff --git a/vcl/win/source/app/salinfo.cxx b/vcl/win/source/app/salinfo.cxx
new file mode 100644
index 000000000000..14cb5d63437a
--- /dev/null
+++ b/vcl/win/source/app/salinfo.cxx
@@ -0,0 +1,301 @@
+/*************************************************************************
+ *
+ * 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"
+
+// rely on unicows on for multimon functions for older versions
+#if WINVER < 0x0500
+#undef WINVER
+#define WINVER 0x0500
+#endif
+
+#define VCL_NEED_BASETSD
+#include "tools/presys.h"
+#if defined _MSC_VER
+#pragma warning(push, 1)
+#endif
+#include <windows.h>
+#include <winuser.h>
+#if defined _MSC_VER
+#pragma warning(pop)
+#endif
+#include "tools/postsys.h"
+
+#include "tools/string.hxx"
+#include "salsys.h"
+#include "salframe.h"
+#include "salinst.h"
+#include "saldata.hxx"
+#include "tools/debug.hxx"
+#include "vcl/svdata.hxx"
+#include "vcl/window.hxx"
+
+#include "rtl/ustrbuf.hxx"
+
+#include <hash_map>
+
+SalSystem* WinSalInstance::CreateSalSystem()
+{
+ return new WinSalSystem();
+}
+
+WinSalSystem::~WinSalSystem()
+{
+}
+
+// -----------------------------------------------------------------------
+
+static WIN_BOOL CALLBACK ImplEnumMonitorProc( HMONITOR hMonitor,
+ HDC hDC,
+ LPRECT lpRect,
+ LPARAM dwData )
+{
+ WinSalSystem* pSys = reinterpret_cast<WinSalSystem*>(dwData);
+ return pSys->handleMonitorCallback( reinterpret_cast<sal_IntPtr>(hMonitor),
+ reinterpret_cast<sal_IntPtr>(hDC),
+ reinterpret_cast<sal_IntPtr>(lpRect) );
+}
+
+BOOL WinSalSystem::handleMonitorCallback( sal_IntPtr hMonitor, sal_IntPtr, sal_IntPtr )
+{
+ MONITORINFOEXW aInfo;
+ aInfo.cbSize = sizeof( aInfo );
+ if( GetMonitorInfoW( reinterpret_cast<HMONITOR>(hMonitor), &aInfo ) )
+ {
+ aInfo.szDevice[CCHDEVICENAME-1] = 0;
+ rtl::OUString aDeviceName( reinterpret_cast<const sal_Unicode *>(aInfo.szDevice) );
+ std::map< rtl::OUString, unsigned int >::const_iterator it =
+ m_aDeviceNameToMonitor.find( aDeviceName );
+ if( it != m_aDeviceNameToMonitor.end() )
+ {
+ DisplayMonitor& rMon( m_aMonitors[ it->second ] );
+ rMon.m_aArea = Rectangle( Point( aInfo.rcMonitor.left,
+ aInfo.rcMonitor.top ),
+ Size( aInfo.rcMonitor.right - aInfo.rcMonitor.left,
+ aInfo.rcMonitor.bottom - aInfo.rcMonitor.top ) );
+ rMon.m_aWorkArea = Rectangle( Point( aInfo.rcWork.left,
+ aInfo.rcWork.top ),
+ Size( aInfo.rcWork.right - aInfo.rcWork.left,
+ aInfo.rcWork.bottom - aInfo.rcWork.top ) );
+ if( (aInfo.dwFlags & MONITORINFOF_PRIMARY) != 0 )
+ m_nPrimary = it->second;
+ }
+ }
+ return TRUE;
+}
+
+void WinSalSystem::clearMonitors()
+{
+ m_aMonitors.clear();
+ m_nPrimary = 0;
+}
+
+bool WinSalSystem::initMonitors()
+{
+ if( m_aMonitors.size() > 0 )
+ return true;
+
+ bool winVerOk = true;
+
+ // multi monitor calls not available on Win95/NT
+ if ( aSalShlData.maVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
+ {
+ if ( aSalShlData.maVersionInfo.dwMajorVersion <= 4 )
+ winVerOk = false; // NT
+ }
+ else if( aSalShlData.maVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
+ {
+ if ( aSalShlData.maVersionInfo.dwMajorVersion == 4 && aSalShlData.maVersionInfo.dwMinorVersion == 0 )
+ winVerOk = false; // Win95
+ }
+ if( winVerOk )
+ {
+ int nMonitors = GetSystemMetrics( SM_CMONITORS );
+ if( nMonitors == 1 )
+ {
+ int w = GetSystemMetrics( SM_CXSCREEN );
+ int h = GetSystemMetrics( SM_CYSCREEN );
+ m_aMonitors.push_back( DisplayMonitor( rtl::OUString(),
+ rtl::OUString(),
+ Rectangle( Point(), Size( w, h ) ),
+ Rectangle( Point(), Size( w, h ) ),
+ 0 ) );
+ m_aDeviceNameToMonitor[ rtl::OUString() ] = 0;
+ m_nPrimary = 0;
+ RECT aWorkRect;
+ if( SystemParametersInfo( SPI_GETWORKAREA, 0, &aWorkRect, 0 ) )
+ m_aMonitors.back().m_aWorkArea = Rectangle( aWorkRect.left, aWorkRect.top,
+ aWorkRect.right, aWorkRect.bottom );
+ }
+ else
+ {
+ DISPLAY_DEVICEW aDev;
+ aDev.cb = sizeof( aDev );
+ DWORD nDevice = 0;
+ std::hash_map< rtl::OUString, int, rtl::OUStringHash > aDeviceStringCount;
+ while( EnumDisplayDevicesW( NULL, nDevice++, &aDev, 0 ) )
+ {
+ if( (aDev.StateFlags & DISPLAY_DEVICE_ACTIVE)
+ && !(aDev.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) ) // sort out non/disabled monitors
+ {
+ aDev.DeviceName[31] = 0;
+ aDev.DeviceString[127] = 0;
+ rtl::OUString aDeviceName( reinterpret_cast<const sal_Unicode *>(aDev.DeviceName) );
+ rtl::OUString aDeviceString( reinterpret_cast<const sal_Unicode *>(aDev.DeviceString) );
+ if( aDeviceStringCount.find( aDeviceString ) == aDeviceStringCount.end() )
+ aDeviceStringCount[ aDeviceString ] = 1;
+ else
+ aDeviceStringCount[ aDeviceString ]++;
+ m_aDeviceNameToMonitor[ aDeviceName ] = m_aMonitors.size();
+ m_aMonitors.push_back( DisplayMonitor( aDeviceString,
+ aDeviceName,
+ Rectangle(),
+ Rectangle(),
+ aDev.StateFlags ) );
+ }
+ }
+ HDC aDesktopRC = GetDC( NULL );
+ EnumDisplayMonitors( aDesktopRC, NULL, ImplEnumMonitorProc, reinterpret_cast<LPARAM>(this) );
+
+ // append monitor numbers to name strings
+ std::hash_map< rtl::OUString, int, rtl::OUStringHash > aDevCount( aDeviceStringCount );
+ unsigned int nMonitors = m_aMonitors.size();
+ for( unsigned int i = 0; i < nMonitors; i++ )
+ {
+ const rtl::OUString& rDev( m_aMonitors[i].m_aName );
+ if( aDeviceStringCount[ rDev ] > 1 )
+ {
+ int nInstance = aDeviceStringCount[ rDev ] - (-- aDevCount[ rDev ] );
+ rtl::OUStringBuffer aBuf( rDev.getLength() + 8 );
+ aBuf.append( rDev );
+ aBuf.appendAscii( " (" );
+ aBuf.append( sal_Int32( nInstance ) );
+ aBuf.append( sal_Unicode(')') );
+ m_aMonitors[ i ].m_aName = aBuf.makeStringAndClear();
+ }
+ }
+ }
+ }
+ else
+ {
+ int w = GetSystemMetrics( SM_CXSCREEN );
+ int h = GetSystemMetrics( SM_CYSCREEN );
+ m_aMonitors.push_back( DisplayMonitor( rtl::OUString(),
+ rtl::OUString(),
+ Rectangle( Point(), Size( w, h ) ),
+ Rectangle( Point(), Size( w, h ) ),
+ 0 ) );
+ m_aDeviceNameToMonitor[ rtl::OUString() ] = 0;
+ m_nPrimary = 0;
+ RECT aWorkRect;
+ if( SystemParametersInfo( SPI_GETWORKAREA, 0, &aWorkRect, 0 ) )
+ m_aMonitors.back().m_aWorkArea = Rectangle( aWorkRect.left, aWorkRect.top,
+ aWorkRect.right, aWorkRect.bottom );
+ }
+
+ return m_aMonitors.size() > 0;
+}
+
+unsigned int WinSalSystem::GetDisplayScreenCount()
+{
+ initMonitors();
+ return m_aMonitors.size();
+}
+
+bool WinSalSystem::IsMultiDisplay()
+{
+ return false;
+}
+
+unsigned int WinSalSystem::GetDefaultDisplayNumber()
+{
+ initMonitors();
+ return m_nPrimary;
+}
+
+Rectangle WinSalSystem::GetDisplayScreenPosSizePixel( unsigned int nScreen )
+{
+ initMonitors();
+ return (nScreen < m_aMonitors.size()) ? m_aMonitors[nScreen].m_aArea : Rectangle();
+}
+
+Rectangle WinSalSystem::GetDisplayWorkAreaPosSizePixel( unsigned int nScreen )
+{
+ initMonitors();
+ return (nScreen < m_aMonitors.size()) ? m_aMonitors[nScreen].m_aWorkArea : Rectangle();
+}
+
+rtl::OUString WinSalSystem::GetScreenName( unsigned int nScreen )
+{
+ initMonitors();
+ return (nScreen < m_aMonitors.size()) ? m_aMonitors[nScreen].m_aName : rtl::OUString();
+}
+
+// -----------------------------------------------------------------------
+/* We have to map the button identifier to the identifier used by the Win32
+ Platform SDK to specify the default button for the MessageBox API.
+ The first dimension is the button combination, the second dimension
+ is the button identifier.
+*/
+static int DEFAULT_BTN_MAPPING_TABLE[][8] =
+{
+ // Undefined OK CANCEL ABORT RETRY IGNORE YES NO
+ { MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1 }, //OK
+ { MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON2, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1 }, //OK_CANCEL
+ { MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON2, MB_DEFBUTTON3, MB_DEFBUTTON1, MB_DEFBUTTON1 }, //ABORT_RETRY_IGNO
+ { MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON3, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON2 }, //YES_NO_CANCEL
+ { MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON2 }, //YES_NO
+ { MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON2, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1 } //RETRY_CANCEL
+};
+
+int WinSalSystem::ShowNativeMessageBox(const String& rTitle, const String& rMessage, int nButtonCombination, int nDefaultButton)
+{
+ DBG_ASSERT( nButtonCombination >= SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_OK &&
+ nButtonCombination <= SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_RETRY_CANCEL &&
+ nDefaultButton >= SALSYSTEM_SHOWNATIVEMSGBOX_BTN_OK &&
+ nDefaultButton <= SALSYSTEM_SHOWNATIVEMSGBOX_BTN_NO, "Invalid arguments!" );
+
+ int nFlags = MB_TASKMODAL | MB_SETFOREGROUND | MB_ICONWARNING | nButtonCombination;
+
+ if (nButtonCombination >= SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_OK &&
+ nButtonCombination <= SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_RETRY_CANCEL &&
+ nDefaultButton >= SALSYSTEM_SHOWNATIVEMSGBOX_BTN_OK &&
+ nDefaultButton <= SALSYSTEM_SHOWNATIVEMSGBOX_BTN_NO)
+ nFlags |= DEFAULT_BTN_MAPPING_TABLE[nButtonCombination][nDefaultButton];
+
+ //#107209 hide the splash screen if active
+ ImplSVData* pSVData = ImplGetSVData();
+ if (pSVData->mpIntroWindow)
+ pSVData->mpIntroWindow->Hide();
+
+ return MessageBoxW(
+ 0,
+ reinterpret_cast<LPCWSTR>(rMessage.GetBuffer()),
+ reinterpret_cast<LPCWSTR>(rTitle.GetBuffer()),
+ nFlags);
+}
diff --git a/vcl/win/source/app/salinst.cxx b/vcl/win/source/app/salinst.cxx
new file mode 100644
index 000000000000..97dbb5285cca
--- /dev/null
+++ b/vcl/win/source/app/salinst.cxx
@@ -0,0 +1,1173 @@
+/*************************************************************************
+ *
+ * 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/svwin.h>
+#ifdef WNT
+#include <process.h>
+#endif
+#ifdef __MINGW32__
+#include <excpt.h>
+#endif
+#include <osl/file.hxx>
+#include <vos/mutex.hxx>
+#include <tools/debug.hxx>
+#include <wincomp.hxx>
+#include <salids.hrc>
+#include <saldata.hxx>
+#include <salinst.h>
+#include <salframe.h>
+#include <salobj.h>
+#include <vcl/salsys.hxx>
+#include <saltimer.h>
+#include <vcl/salatype.hxx>
+#include <salbmp.h>
+#include <vcl/salimestatus.hxx>
+#include <vcl/timer.hxx>
+#include <wincomp.hxx> // CS_DROPSHADOW
+#include <tools/solarmutex.hxx>
+
+#ifndef min
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+#ifndef max
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#if defined _MSC_VER
+#pragma warning(push, 1)
+#pragma warning( disable: 4917 )
+#endif
+
+#include <GdiPlus.h>
+#include <GdiPlusEnums.h>
+#include <GdiPlusColor.h>
+#include <Shlobj.h>
+
+#if defined _MSC_VER
+#pragma warning(pop)
+#endif
+
+// =======================================================================
+
+void SalAbort( const XubString& rErrorText )
+{
+ ImplFreeSalGDI();
+
+ if ( !rErrorText.Len() )
+ {
+ // #112255# make sure crash reporter is triggered
+ RaiseException( 0, EXCEPTION_NONCONTINUABLE, 0, NULL );
+ FatalAppExit( 0, "Application Error" );
+ }
+ else
+ {
+ // #112255# make sure crash reporter is triggered
+ RaiseException( 0, EXCEPTION_NONCONTINUABLE, 0, NULL );
+ ByteString aErrorText( ImplSalGetWinAnsiString( rErrorText ) );
+ FatalAppExit( 0, aErrorText.GetBuffer() );
+ }
+}
+
+// =======================================================================
+
+LRESULT CALLBACK SalComWndProcA( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam );
+LRESULT CALLBACK SalComWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam );
+
+// =======================================================================
+
+class SalYieldMutex : public vos::OMutex
+{
+public: // for ImplSalYield()
+ WinSalInstance* mpInstData;
+ ULONG mnCount;
+ DWORD mnThreadId;
+
+public:
+ SalYieldMutex( WinSalInstance* pInstData );
+
+ virtual void SAL_CALL acquire();
+ virtual void SAL_CALL release();
+ virtual sal_Bool SAL_CALL tryToAcquire();
+
+ ULONG GetAcquireCount( ULONG nThreadId );
+};
+
+// -----------------------------------------------------------------------
+
+SalYieldMutex::SalYieldMutex( WinSalInstance* pInstData )
+{
+ mpInstData = pInstData;
+ mnCount = 0;
+ mnThreadId = 0;
+}
+
+// -----------------------------------------------------------------------
+
+void SAL_CALL SalYieldMutex::acquire()
+{
+ OMutex::acquire();
+ mnCount++;
+ mnThreadId = GetCurrentThreadId();
+}
+
+// -----------------------------------------------------------------------
+
+void SAL_CALL SalYieldMutex::release()
+{
+ DWORD nThreadId = GetCurrentThreadId();
+ if ( mnThreadId != nThreadId )
+ OMutex::release();
+ else
+ {
+ SalData* pSalData = GetSalData();
+ if ( pSalData->mnAppThreadId != nThreadId )
+ {
+ if ( mnCount == 1 )
+ {
+ // If we don't call these message, the Output from the
+ // Java clients doesn't come in the right order
+ GdiFlush();
+
+ mpInstData->mpSalWaitMutex->acquire();
+ if ( mpInstData->mnYieldWaitCount )
+ ImplPostMessage( mpInstData->mhComWnd, SAL_MSG_RELEASEWAITYIELD, 0, 0 );
+ mnThreadId = 0;
+ mnCount--;
+ OMutex::release();
+ mpInstData->mpSalWaitMutex->release();
+ }
+ else
+ {
+ mnCount--;
+ OMutex::release();
+ }
+ }
+ else
+ {
+ if ( mnCount == 1 )
+ mnThreadId = 0;
+ mnCount--;
+ OMutex::release();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool SAL_CALL SalYieldMutex::tryToAcquire()
+{
+ if( OMutex::tryToAcquire() )
+ {
+ mnCount++;
+ mnThreadId = GetCurrentThreadId();
+ return sal_True;
+ }
+ else
+ return sal_False;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG SalYieldMutex::GetAcquireCount( ULONG nThreadId )
+{
+ if ( nThreadId == mnThreadId )
+ return mnCount;
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplSalYieldMutexAcquireWithWait()
+{
+ WinSalInstance* pInst = GetSalData()->mpFirstInstance;
+ if ( !pInst )
+ return;
+
+ // If we are the main thread, then we must wait with wait, because
+ // in if we don't reschedule, then we create deadlocks if a Windows
+ // Function is called from another thread. If we arn't the main thread,
+ // than we call qcquire directly.
+ DWORD nThreadId = GetCurrentThreadId();
+ SalData* pSalData = GetSalData();
+ if ( pSalData->mnAppThreadId == nThreadId )
+ {
+ // Wenn wir den Mutex nicht bekommen, muessen wir solange
+ // warten, bis wir Ihn bekommen
+ BOOL bAcquire = FALSE;
+ do
+ {
+ if ( pInst->mpSalYieldMutex->tryToAcquire() )
+ bAcquire = TRUE;
+ else
+ {
+ pInst->mpSalWaitMutex->acquire();
+ if ( pInst->mpSalYieldMutex->tryToAcquire() )
+ {
+ bAcquire = TRUE;
+ pInst->mpSalWaitMutex->release();
+ }
+ else
+ {
+ pInst->mnYieldWaitCount++;
+ pInst->mpSalWaitMutex->release();
+ MSG aTmpMsg;
+ ImplGetMessage( &aTmpMsg, pInst->mhComWnd, SAL_MSG_RELEASEWAITYIELD, SAL_MSG_RELEASEWAITYIELD );
+ pInst->mnYieldWaitCount--;
+ if ( pInst->mnYieldWaitCount )
+ ImplPostMessage( pInst->mhComWnd, SAL_MSG_RELEASEWAITYIELD, 0, 0 );
+ }
+ }
+ }
+ while ( !bAcquire );
+ }
+ else
+ pInst->mpSalYieldMutex->acquire();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplSalYieldMutexTryToAcquire()
+{
+ WinSalInstance* pInst = GetSalData()->mpFirstInstance;
+ if ( pInst )
+ return pInst->mpSalYieldMutex->tryToAcquire();
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplSalYieldMutexAcquire()
+{
+ WinSalInstance* pInst = GetSalData()->mpFirstInstance;
+ if ( pInst )
+ pInst->mpSalYieldMutex->acquire();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplSalYieldMutexRelease()
+{
+ WinSalInstance* pInst = GetSalData()->mpFirstInstance;
+ if ( pInst )
+ {
+ GdiFlush();
+ pInst->mpSalYieldMutex->release();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ULONG ImplSalReleaseYieldMutex()
+{
+ WinSalInstance* pInst = GetSalData()->mpFirstInstance;
+ if ( !pInst )
+ return 0;
+
+ SalYieldMutex* pYieldMutex = pInst->mpSalYieldMutex;
+ ULONG nCount = pYieldMutex->GetAcquireCount( GetCurrentThreadId() );
+ ULONG n = nCount;
+ while ( n )
+ {
+ pYieldMutex->release();
+ n--;
+ }
+
+ return nCount;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplSalAcquireYieldMutex( ULONG nCount )
+{
+ WinSalInstance* pInst = GetSalData()->mpFirstInstance;
+ if ( !pInst )
+ return;
+
+ SalYieldMutex* pYieldMutex = pInst->mpSalYieldMutex;
+ while ( nCount )
+ {
+ pYieldMutex->acquire();
+ nCount--;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+#ifdef DBG_UTIL
+
+void ImplDbgTestSolarMutex()
+{
+ SalData* pSalData = GetSalData();
+ DWORD nCurThreadId = GetCurrentThreadId();
+ if ( pSalData->mnAppThreadId != nCurThreadId )
+ {
+ if ( pSalData->mpFirstInstance )
+ {
+ SalYieldMutex* pYieldMutex = pSalData->mpFirstInstance->mpSalYieldMutex;
+ if ( pYieldMutex->mnThreadId != nCurThreadId )
+ {
+ DBG_ERROR( "SolarMutex not locked, and not thread save code in VCL is called from outside of the main thread" );
+ }
+ }
+ }
+ else
+ {
+ if ( pSalData->mpFirstInstance )
+ {
+ SalYieldMutex* pYieldMutex = pSalData->mpFirstInstance->mpSalYieldMutex;
+ if ( pYieldMutex->mnThreadId != nCurThreadId )
+ {
+ DBG_ERROR( "SolarMutex not locked in the main thread" );
+ }
+ }
+ }
+}
+
+#endif
+
+// =======================================================================
+
+void SalData::initKeyCodeMap()
+{
+ UINT nKey = 0xffffffff;
+ #define initKey( a, b )\
+ nKey = LOWORD( VkKeyScan( a ) );\
+ if( nKey < 0xffff )\
+ maVKMap[ nKey ] = b;
+
+ initKey( '+', KEY_ADD );
+ initKey( '-', KEY_SUBTRACT );
+ initKey( '*', KEY_MULTIPLY );
+ initKey( '/', KEY_DIVIDE );
+ initKey( '.', KEY_POINT );
+ initKey( ',', KEY_COMMA );
+ initKey( '<', KEY_LESS );
+ initKey( '>', KEY_GREATER );
+ initKey( '=', KEY_EQUAL );
+ initKey( '~', KEY_TILDE );
+ initKey( '`', KEY_QUOTELEFT );
+}
+
+// =======================================================================
+// -------
+// SalData
+// -------
+
+SalData::SalData()
+{
+ mhInst = 0; // default instance handle
+ mhPrevInst = 0; // previous instance handle
+ mnCmdShow = 0; // default frame show style
+ mhDitherPal = 0; // dither palette
+ mhDitherDIB = 0; // dither memory handle
+ mpDitherDIB = 0; // dither memory
+ mpDitherDIBData = 0; // beginning of DIB data
+ mpDitherDiff = 0; // Dither mapping table
+ mpDitherLow = 0; // Dither mapping table
+ mpDitherHigh = 0; // Dither mapping table
+ mnTimerMS = 0; // Current Time (in MS) of the Timer
+ mnTimerOrgMS = 0; // Current Original Time (in MS)
+ mnNextTimerTime = 0;
+ mnLastEventTime = 0;
+ mnTimerId = 0; // windows timer id
+ mbInTimerProc = FALSE; // timer event is currently being dispatched
+ mhSalObjMsgHook = 0; // hook to get interesting msg for SalObject
+ mhWantLeaveMsg = 0; // window handle, that want a MOUSELEAVE message
+ mpMouseLeaveTimer = 0; // Timer for MouseLeave Test
+ mpFirstInstance = 0; // pointer of first instance
+ mpFirstFrame = 0; // pointer of first frame
+ mpFirstObject = 0; // pointer of first object window
+ mpFirstVD = 0; // first VirDev
+ mpFirstPrinter = 0; // first printing printer
+ mpHDCCache = 0; // Cache for three DC's
+ mh50Bmp = 0; // 50% Bitmap
+ mh50Brush = 0; // 50% Brush
+ int i;
+ for(i=0; i<MAX_STOCKPEN; i++)
+ {
+ maStockPenColorAry[i] = 0;
+ mhStockPenAry[i] = 0;
+ }
+ for(i=0; i<MAX_STOCKBRUSH; i++)
+ {
+ maStockBrushColorAry[i] = 0;
+ mhStockBrushAry[i] = 0;
+ }
+ mnStockPenCount = 0; // count of static pens
+ mnStockBrushCount = 0; // count of static brushes
+ mnSalObjWantKeyEvt = 0; // KeyEvent, welcher vom SalObj-Hook verarbeitet werden soll
+ mnCacheDCInUse = 0; // count of CacheDC in use
+ mbObjClassInit = FALSE; // is SALOBJECTCLASS initialised
+ mbInPalChange = FALSE; // is in WM_QUERYNEWPALETTE
+ mnAppThreadId = 0; // Id from Applikation-Thread
+ mbScrSvrEnabled = FALSE; // ScreenSaver enabled
+ mnSageStatus = 0; // status of Sage-DLL (DISABLE_AGENT == nicht vorhanden)
+ mpSageEnableProc = 0; // funktion to deactivate the system agent
+ mpFirstIcon = 0; // icon cache, points to first icon, NULL if none
+ mpTempFontItem = 0;
+ mbThemeChanged = FALSE; // true if visual theme was changed: throw away theme handles
+
+ // init with NULL
+ gdiplusToken = 0;
+
+ initKeyCodeMap();
+
+ SetSalData( this );
+ initNWF();
+}
+
+SalData::~SalData()
+{
+ deInitNWF();
+ SetSalData( NULL );
+}
+
+void InitSalData()
+{
+ SalData* pSalData = new SalData;
+ CoInitialize(0);
+
+ // init GDIPlus
+ static Gdiplus::GdiplusStartupInput gdiplusStartupInput;
+ Gdiplus::GdiplusStartup(&pSalData->gdiplusToken, &gdiplusStartupInput, NULL);
+}
+
+
+void DeInitSalData()
+{
+ CoUninitialize();
+ SalData* pSalData = GetSalData();
+
+ // deinit GDIPlus
+ if(pSalData)
+ {
+ Gdiplus::GdiplusShutdown(pSalData->gdiplusToken);
+ }
+
+ delete pSalData;
+}
+
+// -----------------------------------------------------------------------
+
+void InitSalMain()
+{
+ // remember data, copied from WinMain
+ SalData* pData = GetAppSalData();
+ if ( pData ) // Im AppServer NULL
+ {
+ STARTUPINFO aSI;
+ aSI.cb = sizeof( aSI );
+ GetStartupInfo( &aSI );
+ pData->mhInst = GetModuleHandle( NULL );
+ pData->mhPrevInst = NULL;
+ pData->mnCmdShow = aSI.wShowWindow;
+ }
+}
+
+void DeInitSalMain()
+{
+}
+
+// -----------------------------------------------------------------------
+
+SalInstance* CreateSalInstance()
+{
+ SalData* pSalData = GetSalData();
+
+ // determine the windows version
+ aSalShlData.mbWNT = 0;
+ aSalShlData.mbWXP = 0;
+ aSalShlData.mbWPrinter = 0;
+ WORD nVer = (WORD)GetVersion();
+ aSalShlData.mnVersion = (((WORD)LOBYTE(nVer)) * 100) + HIBYTE(nVer);
+ if ( aSalShlData.mnVersion >= 400 )
+ aSalShlData.mbW40 = 1;
+ rtl_zeroMemory( &aSalShlData.maVersionInfo, sizeof(aSalShlData.maVersionInfo) );
+ aSalShlData.maVersionInfo.dwOSVersionInfoSize = sizeof( aSalShlData.maVersionInfo );
+ if ( GetVersionEx( &aSalShlData.maVersionInfo ) )
+ {
+ if ( aSalShlData.maVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
+ {
+ aSalShlData.mbWNT = 1;
+ // Windows XP ?
+ if ( aSalShlData.maVersionInfo.dwMajorVersion > 5 ||
+ ( aSalShlData.maVersionInfo.dwMajorVersion == 5 && aSalShlData.maVersionInfo.dwMinorVersion >= 1 ) )
+ aSalShlData.mbWXP = 1;
+ if( aSalShlData.maVersionInfo.dwMajorVersion >= 5 )
+ aSalShlData.mbWPrinter = 1;
+ }
+ }
+
+ pSalData->mnAppThreadId = GetCurrentThreadId();
+
+ // register frame class
+ if ( !pSalData->mhPrevInst )
+ {
+ if ( aSalShlData.mbWNT )
+ {
+ WNDCLASSEXW aWndClassEx;
+ aWndClassEx.cbSize = sizeof( aWndClassEx );
+ aWndClassEx.style = CS_OWNDC;
+ aWndClassEx.lpfnWndProc = SalFrameWndProcW;
+ aWndClassEx.cbClsExtra = 0;
+ aWndClassEx.cbWndExtra = SAL_FRAME_WNDEXTRA;
+ aWndClassEx.hInstance = pSalData->mhInst;
+ aWndClassEx.hCursor = 0;
+ aWndClassEx.hbrBackground = 0;
+ aWndClassEx.lpszMenuName = 0;
+ aWndClassEx.lpszClassName = SAL_FRAME_CLASSNAMEW;
+ ImplLoadSalIcon( SAL_RESID_ICON_DEFAULT, aWndClassEx.hIcon, aWndClassEx.hIconSm );
+ if ( !RegisterClassExW( &aWndClassEx ) )
+ return NULL;
+
+ aWndClassEx.hIcon = 0;
+ aWndClassEx.hIconSm = 0;
+ aWndClassEx.style |= CS_SAVEBITS;
+ aWndClassEx.lpszClassName = SAL_SUBFRAME_CLASSNAMEW;
+ if ( !RegisterClassExW( &aWndClassEx ) )
+ return NULL;
+
+ // shadow effect for popups on XP
+ if( aSalShlData.mbWXP )
+ aWndClassEx.style |= CS_DROPSHADOW;
+ aWndClassEx.lpszClassName = SAL_TMPSUBFRAME_CLASSNAMEW;
+ if ( !RegisterClassExW( &aWndClassEx ) )
+ return NULL;
+
+ aWndClassEx.style = 0;
+ aWndClassEx.lpfnWndProc = SalComWndProcW;
+ aWndClassEx.cbWndExtra = 0;
+ aWndClassEx.lpszClassName = SAL_COM_CLASSNAMEW;
+ if ( !RegisterClassExW( &aWndClassEx ) )
+ return NULL;
+ }
+ else
+ {
+ WNDCLASSEXA aWndClassEx;
+ aWndClassEx.cbSize = sizeof( aWndClassEx );
+ aWndClassEx.style = CS_OWNDC;
+ aWndClassEx.lpfnWndProc = SalFrameWndProcA;
+ aWndClassEx.cbClsExtra = 0;
+ aWndClassEx.cbWndExtra = SAL_FRAME_WNDEXTRA;
+ aWndClassEx.hInstance = pSalData->mhInst;
+ aWndClassEx.hCursor = 0;
+ aWndClassEx.hbrBackground = 0;
+ aWndClassEx.lpszMenuName = 0;
+ aWndClassEx.lpszClassName = SAL_FRAME_CLASSNAMEA;
+ ImplLoadSalIcon( SAL_RESID_ICON_DEFAULT, aWndClassEx.hIcon, aWndClassEx.hIconSm );
+ if ( !RegisterClassExA( &aWndClassEx ) )
+ return NULL;
+
+ aWndClassEx.hIcon = 0;
+ aWndClassEx.hIconSm = 0;
+ aWndClassEx.style |= CS_SAVEBITS;
+ aWndClassEx.lpszClassName = SAL_SUBFRAME_CLASSNAMEA;
+ if ( !RegisterClassExA( &aWndClassEx ) )
+ return NULL;
+
+ aWndClassEx.style = 0;
+ aWndClassEx.lpfnWndProc = SalComWndProcA;
+ aWndClassEx.cbWndExtra = 0;
+ aWndClassEx.lpszClassName = SAL_COM_CLASSNAMEA;
+ if ( !RegisterClassExA( &aWndClassEx ) )
+ return NULL;
+ }
+ }
+
+ HWND hComWnd;
+ if ( aSalShlData.mbWNT )
+ {
+ hComWnd = CreateWindowExW( WS_EX_TOOLWINDOW, SAL_COM_CLASSNAMEW,
+ L"", WS_POPUP, 0, 0, 0, 0, 0, 0,
+ pSalData->mhInst, NULL );
+ }
+ else
+ {
+ hComWnd = CreateWindowExA( WS_EX_TOOLWINDOW, SAL_COM_CLASSNAMEA,
+ "", WS_POPUP, 0, 0, 0, 0, 0, 0,
+ pSalData->mhInst, NULL );
+ }
+ if ( !hComWnd )
+ return NULL;
+
+ WinSalInstance* pInst = new WinSalInstance;
+
+ // init instance (only one instance in this version !!!)
+ pSalData->mpFirstInstance = pInst;
+ pInst->mhInst = pSalData->mhInst;
+ pInst->mhComWnd = hComWnd;
+
+ // init static GDI Data
+ ImplInitSalGDI();
+
+ return pInst;
+}
+
+// -----------------------------------------------------------------------
+
+void DestroySalInstance( SalInstance* pInst )
+{
+ SalData* pSalData = GetSalData();
+
+ // (only one instance in this version !!!)
+
+ ImplFreeSalGDI();
+
+ // reset instance
+ if ( pSalData->mpFirstInstance == pInst )
+ pSalData->mpFirstInstance = NULL;
+
+ delete pInst;
+}
+
+// -----------------------------------------------------------------------
+
+WinSalInstance::WinSalInstance()
+{
+ mhComWnd = 0;
+ mpSalYieldMutex = new SalYieldMutex( this );
+ mpSalWaitMutex = new vos::OMutex;
+ mnYieldWaitCount = 0;
+ mpSalYieldMutex->acquire();
+ ::tools::SolarMutex::SetSolarMutex( mpSalYieldMutex );
+}
+
+// -----------------------------------------------------------------------
+
+WinSalInstance::~WinSalInstance()
+{
+ ::tools::SolarMutex::SetSolarMutex( 0 );
+ mpSalYieldMutex->release();
+ delete mpSalYieldMutex;
+ delete mpSalWaitMutex;
+ DestroyWindow( mhComWnd );
+}
+
+// -----------------------------------------------------------------------
+
+vos::IMutex* WinSalInstance::GetYieldMutex()
+{
+ return mpSalYieldMutex;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG WinSalInstance::ReleaseYieldMutex()
+{
+ return ImplSalReleaseYieldMutex();
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalInstance::AcquireYieldMutex( ULONG nCount )
+{
+ ImplSalAcquireYieldMutex( nCount );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplSalDispatchMessage( MSG* pMsg )
+{
+ SalData* pSalData = GetSalData();
+ if ( pSalData->mpFirstObject )
+ {
+ if ( ImplSalPreDispatchMsg( pMsg ) )
+ return;
+ }
+ LRESULT lResult = ImplDispatchMessage( pMsg );
+ if ( pSalData->mpFirstObject )
+ ImplSalPostDispatchMsg( pMsg, lResult );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplSalYield( BOOL bWait, BOOL bHandleAllCurrentEvents )
+{
+ MSG aMsg;
+ bool bWasMsg = false, bOneEvent = false;
+
+ int nMaxEvents = bHandleAllCurrentEvents ? 100 : 1;
+ do
+ {
+ if ( ImplPeekMessage( &aMsg, 0, 0, 0, PM_REMOVE ) )
+ {
+ TranslateMessage( &aMsg );
+ ImplSalDispatchMessage( &aMsg );
+ bOneEvent = bWasMsg = true;
+ }
+ else
+ bOneEvent = false;
+ } while( --nMaxEvents && bOneEvent );
+
+ if ( bWait && ! bWasMsg )
+ {
+ if ( ImplGetMessage( &aMsg, 0, 0, 0 ) )
+ {
+ TranslateMessage( &aMsg );
+ ImplSalDispatchMessage( &aMsg );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents )
+{
+ SalYieldMutex* pYieldMutex = mpSalYieldMutex;
+ SalData* pSalData = GetSalData();
+ DWORD nCurThreadId = GetCurrentThreadId();
+ ULONG nCount = pYieldMutex->GetAcquireCount( nCurThreadId );
+ ULONG n = nCount;
+ while ( n )
+ {
+ pYieldMutex->release();
+ n--;
+ }
+ if ( pSalData->mnAppThreadId != nCurThreadId )
+ {
+ // #97739# A SendMessage call blocks until the called thread (here: the main thread)
+ // returns. During a yield however, messages are processed in the main thread that might
+ // result in a new message loop due to opening a dialog. Thus, SendMessage would not
+ // return which will block this thread!
+ // Solution: just give up the time slice and hope that messages are processed
+ // by the main thread anyway (where all windows are created)
+ // If the mainthread is not currently handling messages, then our SendMessage would
+ // also do nothing, so this seems to be reasonable.
+
+ // #i18883# only sleep if potential deadlock scenario, ie, when a dialog is open
+ if( ImplGetSVData()->maAppData.mnModalMode )
+ Sleep(1);
+ else
+ ImplSendMessage( mhComWnd, SAL_MSG_THREADYIELD, (WPARAM)bWait, (LPARAM)bHandleAllCurrentEvents );
+
+ n = nCount;
+ while ( n )
+ {
+ pYieldMutex->acquire();
+ n--;
+ }
+ }
+ else
+ {
+ ImplSalYield( bWait, bHandleAllCurrentEvents );
+
+ n = nCount;
+ while ( n )
+ {
+ ImplSalYieldMutexAcquireWithWait();
+ n--;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+LRESULT CALLBACK SalComWndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, int& rDef )
+{
+ LRESULT nRet = 0;
+
+
+ switch ( nMsg )
+ {
+ case SAL_MSG_PRINTABORTJOB:
+ ImplSalPrinterAbortJobAsync( (HDC)wParam );
+ rDef = FALSE;
+ break;
+ case SAL_MSG_THREADYIELD:
+ ImplSalYield( (BOOL)wParam, (BOOL)lParam );
+ rDef = FALSE;
+ break;
+ // If we get this message, because another GetMessage() call
+ // has recieved this message, we must post this message to
+ // us again, because in the other case we wait forever.
+ case SAL_MSG_RELEASEWAITYIELD:
+ {
+ WinSalInstance* pInst = GetSalData()->mpFirstInstance;
+ if ( pInst && pInst->mnYieldWaitCount )
+ ImplPostMessage( hWnd, SAL_MSG_RELEASEWAITYIELD, wParam, lParam );
+ }
+ rDef = FALSE;
+ break;
+ case SAL_MSG_STARTTIMER:
+ ImplSalStartTimer( (ULONG) lParam, FALSE );
+ rDef = FALSE;
+ break;
+ case SAL_MSG_CREATEFRAME:
+ nRet = (LRESULT)ImplSalCreateFrame( GetSalData()->mpFirstInstance, (HWND)lParam, (ULONG)wParam );
+ rDef = FALSE;
+ break;
+ case SAL_MSG_RECREATEHWND:
+ nRet = (LRESULT)ImplSalReCreateHWND( (HWND)wParam, (HWND)lParam, FALSE );
+ rDef = FALSE;
+ break;
+ case SAL_MSG_RECREATECHILDHWND:
+ nRet = (LRESULT)ImplSalReCreateHWND( (HWND)wParam, (HWND)lParam, TRUE );
+ rDef = FALSE;
+ break;
+ case SAL_MSG_DESTROYFRAME:
+ delete (SalFrame*)lParam;
+ rDef = FALSE;
+ break;
+ case SAL_MSG_DESTROYHWND:
+ //We only destroy the native window here. We do NOT destroy the SalFrame contained
+ //in the structure (GetWindowPtr()).
+ if (DestroyWindow((HWND)lParam) == 0)
+ {
+ OSL_ENSURE(0, "DestroyWindow failed!");
+ //Failure: We remove the SalFrame from the window structure. So we avoid that
+ // the window structure may contain an invalid pointer, once the SalFrame is deleted.
+ SetWindowPtr((HWND)lParam, 0);
+ }
+ rDef = FALSE;
+ break;
+ case SAL_MSG_CREATEOBJECT:
+ nRet = (LRESULT)ImplSalCreateObject( GetSalData()->mpFirstInstance, (WinSalFrame*)lParam );
+ rDef = FALSE;
+ break;
+ case SAL_MSG_DESTROYOBJECT:
+ delete (SalObject*)lParam;
+ rDef = FALSE;
+ break;
+ case SAL_MSG_GETDC:
+ nRet = (LRESULT)GetDCEx( (HWND)wParam, 0, DCX_CACHE );
+ rDef = FALSE;
+ break;
+ case SAL_MSG_RELEASEDC:
+ ReleaseDC( (HWND)wParam, (HDC)lParam );
+ rDef = FALSE;
+ break;
+ case SAL_MSG_POSTTIMER:
+ SalTimerProc( 0, 0, SALTIMERPROC_RECURSIVE, lParam );
+ break;
+ }
+
+ return nRet;
+}
+
+LRESULT CALLBACK SalComWndProcA( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
+{
+ int bDef = TRUE;
+ LRESULT nRet = 0;
+#ifdef __MINGW32__
+ jmp_buf jmpbuf;
+ __SEHandler han;
+ if (__builtin_setjmp(jmpbuf) == 0)
+ {
+ han.Set(jmpbuf, NULL, (__SEHandler::PF)EXCEPTION_EXECUTE_HANDLER);
+#else
+ __try
+ {
+#endif
+ nRet = SalComWndProc( hWnd, nMsg, wParam, lParam, bDef );
+ }
+#ifdef __MINGW32__
+ han.Reset();
+#else
+ __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))
+ {
+ }
+#endif
+ if ( bDef )
+ {
+ if ( !ImplHandleGlobalMsg( hWnd, nMsg, wParam, lParam, nRet ) )
+ nRet = DefWindowProcA( hWnd, nMsg, wParam, lParam );
+ }
+ return nRet;
+}
+
+LRESULT CALLBACK SalComWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
+{
+ int bDef = TRUE;
+ LRESULT nRet = 0;
+#ifdef __MINGW32__
+ jmp_buf jmpbuf;
+ __SEHandler han;
+ if (__builtin_setjmp(jmpbuf) == 0)
+ {
+ han.Set(jmpbuf, NULL, (__SEHandler::PF)EXCEPTION_EXECUTE_HANDLER);
+#else
+ __try
+ {
+#endif
+ nRet = SalComWndProc( hWnd, nMsg, wParam, lParam, bDef );
+ }
+#ifdef __MINGW32__
+ han.Reset();
+#else
+ __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))
+ {
+ }
+#endif
+ if ( bDef )
+ {
+ if ( !ImplHandleGlobalMsg( hWnd, nMsg, wParam, lParam, nRet ) )
+ nRet = DefWindowProcW( hWnd, nMsg, wParam, lParam );
+ }
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+bool WinSalInstance::AnyInput( USHORT nType )
+{
+ MSG aMsg;
+
+ if ( (nType & (INPUT_ANY)) == (INPUT_ANY) )
+ {
+ // revert bugfix for #108919# which never reported timeouts when called from the timer handler
+ // which made the application completely unresponsive during background formatting
+ if ( ImplPeekMessage( &aMsg, 0, 0, 0, PM_NOREMOVE | PM_NOYIELD ) )
+ return true;
+ }
+ else
+ {
+ if ( nType & INPUT_MOUSE )
+ {
+ // Test for mouse input
+ if ( ImplPeekMessage( &aMsg, 0, WM_MOUSEFIRST, WM_MOUSELAST,
+ PM_NOREMOVE | PM_NOYIELD ) )
+ return true;
+ }
+
+ if ( nType & INPUT_KEYBOARD )
+ {
+ // Test for key input
+ if ( ImplPeekMessage( &aMsg, 0, WM_KEYDOWN, WM_KEYDOWN,
+ PM_NOREMOVE | PM_NOYIELD ) )
+ {
+ if ( (aMsg.wParam == VK_SHIFT) ||
+ (aMsg.wParam == VK_CONTROL) ||
+ (aMsg.wParam == VK_MENU) )
+ return false;
+ else
+ return true;
+ }
+ }
+
+ if ( nType & INPUT_PAINT )
+ {
+ // Test for paint input
+ if ( ImplPeekMessage( &aMsg, 0, WM_PAINT, WM_PAINT,
+ PM_NOREMOVE | PM_NOYIELD ) )
+ return true;
+
+ if ( ImplPeekMessage( &aMsg, 0, WM_SIZE, WM_SIZE,
+ PM_NOREMOVE | PM_NOYIELD ) )
+ return true;
+
+ if ( ImplPeekMessage( &aMsg, 0, SAL_MSG_POSTCALLSIZE, SAL_MSG_POSTCALLSIZE,
+ PM_NOREMOVE | PM_NOYIELD ) )
+ return true;
+
+ if ( ImplPeekMessage( &aMsg, 0, WM_MOVE, WM_MOVE,
+ PM_NOREMOVE | PM_NOYIELD ) )
+ return true;
+
+ if ( ImplPeekMessage( &aMsg, 0, SAL_MSG_POSTMOVE, SAL_MSG_POSTMOVE,
+ PM_NOREMOVE | PM_NOYIELD ) )
+ return true;
+ }
+
+ if ( nType & INPUT_TIMER )
+ {
+ // Test for timer input
+ if ( ImplPeekMessage( &aMsg, 0, WM_TIMER, WM_TIMER,
+ PM_NOREMOVE | PM_NOYIELD ) )
+ return true;
+
+ }
+
+ if ( nType & INPUT_OTHER )
+ {
+ // Test for any input
+ if ( ImplPeekMessage( &aMsg, 0, 0, 0, PM_NOREMOVE | PM_NOYIELD ) )
+ return true;
+ }
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void SalTimer::Start( ULONG nMS )
+{
+ // Um auf Main-Thread umzuschalten
+ SalData* pSalData = GetSalData();
+ if ( pSalData->mpFirstInstance )
+ {
+ if ( pSalData->mnAppThreadId != GetCurrentThreadId() )
+ ImplPostMessage( pSalData->mpFirstInstance->mhComWnd, SAL_MSG_STARTTIMER, 0, (LPARAM)nMS );
+ else
+ ImplSendMessage( pSalData->mpFirstInstance->mhComWnd, SAL_MSG_STARTTIMER, 0, (LPARAM)nMS );
+ }
+ else
+ ImplSalStartTimer( nMS, FALSE );
+}
+
+// -----------------------------------------------------------------------
+
+SalFrame* WinSalInstance::CreateChildFrame( SystemParentData* pSystemParentData, ULONG nSalFrameStyle )
+{
+ // Um auf Main-Thread umzuschalten
+ return (SalFrame*)ImplSendMessage( mhComWnd, SAL_MSG_CREATEFRAME, nSalFrameStyle, (LPARAM)pSystemParentData->hWnd );
+}
+
+// -----------------------------------------------------------------------
+
+SalFrame* WinSalInstance::CreateFrame( SalFrame* pParent, ULONG nSalFrameStyle )
+{
+ // Um auf Main-Thread umzuschalten
+ HWND hWndParent;
+ if ( pParent )
+ hWndParent = static_cast<WinSalFrame*>(pParent)->mhWnd;
+ else
+ hWndParent = 0;
+ return (SalFrame*)ImplSendMessage( mhComWnd, SAL_MSG_CREATEFRAME, nSalFrameStyle, (LPARAM)hWndParent );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalInstance::DestroyFrame( SalFrame* pFrame )
+{
+ ImplSendMessage( mhComWnd, SAL_MSG_DESTROYFRAME, 0, (LPARAM)pFrame );
+}
+
+// -----------------------------------------------------------------------
+
+SalObject* WinSalInstance::CreateObject( SalFrame* pParent,
+ SystemWindowData* /*pWindowData*/, // SystemWindowData meaningless on Windows
+ BOOL /*bShow*/ )
+{
+ // Um auf Main-Thread umzuschalten
+ return (SalObject*)ImplSendMessage( mhComWnd, SAL_MSG_CREATEOBJECT, 0, (LPARAM)static_cast<WinSalFrame*>(pParent) );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalInstance::DestroyObject( SalObject* pObject )
+{
+ ImplSendMessage( mhComWnd, SAL_MSG_DESTROYOBJECT, 0, (LPARAM)pObject );
+}
+
+// -----------------------------------------------------------------------
+
+void* WinSalInstance::GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes )
+{
+ rReturnedBytes = 1;
+ rReturnedType = AsciiCString;
+ return const_cast<char *>("");
+}
+
+// -----------------------------------------------------------------------
+
+/** Add a file to the system shells recent document list if there is any.
+ This function may have no effect under Unix because there is no
+ standard API among the different desktop managers.
+
+ @param aFileUrl
+ The file url of the document.
+*/
+void WinSalInstance::AddToRecentDocumentList(const rtl::OUString& rFileUrl, const rtl::OUString& /*rMimeType*/)
+{
+ rtl::OUString system_path;
+ osl::FileBase::RC rc = osl::FileBase::getSystemPathFromFileURL(rFileUrl, system_path);
+
+ OSL_ENSURE(osl::FileBase::E_None == rc, "Invalid file url");
+
+ if (osl::FileBase::E_None == rc)
+ SHAddToRecentDocs(SHARD_PATHW, system_path.getStr());
+}
+
+// -----------------------------------------------------------------------
+
+SalTimer* WinSalInstance::CreateSalTimer()
+{
+ return new WinSalTimer();
+}
+
+// -----------------------------------------------------------------------
+
+SalBitmap* WinSalInstance::CreateSalBitmap()
+{
+ return new WinSalBitmap();
+}
+
+class WinImeStatus : public SalI18NImeStatus
+{
+ public:
+ WinImeStatus() {}
+ virtual ~WinImeStatus() {}
+
+ // asks whether there is a status window available
+ // to toggle into menubar
+ virtual bool canToggle() { return false; }
+ virtual void toggle() {}
+};
+
+SalI18NImeStatus* WinSalInstance::CreateI18NImeStatus()
+{
+ return new WinImeStatus();
+}
+
+// -----------------------------------------------------------------------
+
+const ::rtl::OUString& SalGetDesktopEnvironment()
+{
+ static ::rtl::OUString aDesktopEnvironment( RTL_CONSTASCII_USTRINGPARAM( "Windows" ) );
+ return aDesktopEnvironment;
+}
+
+SalSession* WinSalInstance::CreateSalSession()
+{
+ return NULL;
+}
+
+#ifndef __MINGW32__
+// -----------------------------------------------------------------------
+int WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(int, LPEXCEPTION_POINTERS pExceptionInfo)
+{
+ // Decide if an exception is a c++ (mostly UNO) exception or a process violation.
+ // Depending on this information we pass process violations directly to our signal handler ...
+ // and c++ (UNO) exceptions are sended to the following code on the current stack.
+ // Problem behind: user32.dll sometime consumes exceptions/process violations .-)
+ // see also #112221#
+
+ static DWORD EXCEPTION_MSC_CPP_EXCEPTION = 0xE06D7363;
+
+ if (pExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_MSC_CPP_EXCEPTION)
+ return EXCEPTION_CONTINUE_SEARCH;
+
+ return UnhandledExceptionFilter( pExceptionInfo );
+}
+#endif
diff --git a/vcl/win/source/app/salshl.cxx b/vcl/win/source/app/salshl.cxx
new file mode 100644
index 000000000000..0f3b0c41e258
--- /dev/null
+++ b/vcl/win/source/app/salshl.cxx
@@ -0,0 +1,164 @@
+/*************************************************************************
+ *
+ * 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/svwin.h>
+#include <saldata.hxx>
+#include <tools/debug.hxx>
+
+// =======================================================================
+
+SalShlData aSalShlData;
+
+// =======================================================================
+
+#ifdef WNT
+
+extern "C"
+{
+
+#ifdef __MINGW32__
+BOOL WINAPI DllMain( HINSTANCE hInst, DWORD nReason, LPVOID pReserved )
+#else
+#ifdef ICC
+int _CRT_init(void);
+#else
+WIN_BOOL WINAPI _CRT_INIT( HINSTANCE hInst, DWORD nReason, LPVOID pReserved );
+#endif
+
+WIN_BOOL WINAPI LibMain( HINSTANCE hInst, DWORD nReason, LPVOID pReserved )
+#endif
+{
+ // Unsere DLL-Initialisierung
+ if ( nReason == DLL_PROCESS_ATTACH )
+ aSalShlData.mhInst = hInst;
+
+#ifndef __MINGW32__
+#ifdef ICC
+ if ( _CRT_init() == -1 )
+#else
+ if ( !_CRT_INIT( hInst, nReason, pReserved ) )
+#endif
+ return 0;
+#endif
+
+ return 1;
+}
+
+}
+
+#endif
+
+// =======================================================================
+
+HCURSOR ImplLoadSalCursor( int nId )
+{
+ DBG_ASSERT( aSalShlData.mhInst, "no DLL instance handle" );
+
+ HCURSOR hCursor = LoadCursor( aSalShlData.mhInst, MAKEINTRESOURCE( nId ) );
+
+ DBG_ASSERT( hCursor, "cursor not found in sal resource" );
+
+ return hCursor;
+}
+
+// -----------------------------------------------------------------------
+
+HBITMAP ImplLoadSalBitmap( int nId )
+{
+ DBG_ASSERT( aSalShlData.mhInst, "no DLL instance handle" );
+
+ HBITMAP hBitmap = LoadBitmap( aSalShlData.mhInst, MAKEINTRESOURCE( nId ) );
+
+ DBG_ASSERT( hBitmap, "bitmap not found in sal resource" );
+
+ return hBitmap;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplLoadSalIcon( int nId, HICON& rIcon, HICON& rSmallIcon )
+{
+ DBG_ASSERT( aSalShlData.mhInst, "no DLL instance handle" );
+
+ SalData* pSalData = GetSalData();
+
+ // check the cache first
+ SalIcon *pSalIcon = pSalData->mpFirstIcon;
+ while( pSalIcon )
+ {
+ if( pSalIcon->nId != nId )
+ pSalIcon = pSalIcon->pNext;
+ else
+ {
+ rIcon = pSalIcon->hIcon;
+ rSmallIcon = pSalIcon->hSmallIcon;
+ return (rSmallIcon != 0);
+ }
+ }
+
+ // Try at first to load the icons from the application exe file
+ rIcon = (HICON)LoadImage( pSalData->mhInst, MAKEINTRESOURCE( nId ),
+ IMAGE_ICON, GetSystemMetrics( SM_CXICON ), GetSystemMetrics( SM_CYICON ),
+ LR_DEFAULTCOLOR );
+ if ( !rIcon )
+ {
+ // If the application don't provide these icons, then we try
+ // to load the icon from the VCL resource
+ rIcon = (HICON)LoadImage( aSalShlData.mhInst, MAKEINTRESOURCE( nId ),
+ IMAGE_ICON, GetSystemMetrics( SM_CXICON ), GetSystemMetrics( SM_CYICON ),
+ LR_DEFAULTCOLOR );
+ if ( rIcon )
+ {
+ rSmallIcon = (HICON)LoadImage( aSalShlData.mhInst, MAKEINTRESOURCE( nId ),
+ IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ),
+ LR_DEFAULTCOLOR );
+ }
+ else
+ rSmallIcon = 0;
+ }
+ else
+ {
+ rSmallIcon = (HICON)LoadImage( pSalData->mhInst, MAKEINTRESOURCE( nId ),
+ IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ),
+ LR_DEFAULTCOLOR );
+ }
+
+ if( rIcon )
+ {
+ // add to icon cache
+ pSalIcon = new SalIcon();
+ pSalIcon->nId = nId;
+ pSalIcon->hIcon = rIcon;
+ pSalIcon->hSmallIcon = rSmallIcon;
+ pSalIcon->pNext = pSalData->mpFirstIcon;
+ pSalData->mpFirstIcon = pSalIcon;
+ }
+
+ return (rSmallIcon != 0);
+}
diff --git a/vcl/win/source/app/saltimer.cxx b/vcl/win/source/app/saltimer.cxx
new file mode 100644
index 000000000000..d512be753f9c
--- /dev/null
+++ b/vcl/win/source/app/saltimer.cxx
@@ -0,0 +1,154 @@
+/*************************************************************************
+ *
+ * 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/svwin.h>
+#ifdef __MINGW32__
+#include <excpt.h>
+#endif
+#include <saldata.hxx>
+#include <saltimer.h>
+#include <salinst.h>
+
+// =======================================================================
+
+// Maximale Periode
+#define MAX_SYSPERIOD 65533
+
+// =======================================================================
+
+void ImplSalStartTimer( ULONG nMS, BOOL bMutex )
+{
+ SalData* pSalData = GetSalData();
+
+ // Remenber the time of the timer
+ pSalData->mnTimerMS = nMS;
+ if ( !bMutex )
+ pSalData->mnTimerOrgMS = nMS;
+
+ // Periode darf nicht zu gross sein, da Windows mit USHORT arbeitet
+ if ( nMS > MAX_SYSPERIOD )
+ nMS = MAX_SYSPERIOD;
+
+ // Gibt es einen Timer, dann zerstoren
+ if ( pSalData->mnTimerId )
+ KillTimer( 0, pSalData->mnTimerId );
+
+ // Make a new timer with new period
+ pSalData->mnTimerId = SetTimer( 0, 0, (UINT)nMS, SalTimerProc );
+ pSalData->mnNextTimerTime = pSalData->mnLastEventTime + nMS;
+}
+
+// -----------------------------------------------------------------------
+
+WinSalTimer::~WinSalTimer()
+{
+}
+
+void WinSalTimer::Start( ULONG nMS )
+{
+ // switch to main thread
+ SalData* pSalData = GetSalData();
+ if ( pSalData->mpFirstInstance )
+ {
+ if ( pSalData->mnAppThreadId != GetCurrentThreadId() )
+ ImplPostMessage( pSalData->mpFirstInstance->mhComWnd, SAL_MSG_STARTTIMER, 0, (LPARAM)nMS );
+ else
+ ImplSendMessage( pSalData->mpFirstInstance->mhComWnd, SAL_MSG_STARTTIMER, 0, (LPARAM)nMS );
+ }
+ else
+ ImplSalStartTimer( nMS, FALSE );
+}
+
+void WinSalTimer::Stop()
+{
+ SalData* pSalData = GetSalData();
+
+ // If we have a timer, than
+ if ( pSalData->mnTimerId )
+ {
+ KillTimer( 0, pSalData->mnTimerId );
+ pSalData->mnTimerId = 0;
+ pSalData->mnNextTimerTime = 0;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void CALLBACK SalTimerProc( HWND, UINT, UINT_PTR nId, DWORD )
+{
+#ifdef __MINGW32__
+ jmp_buf jmpbuf;
+ __SEHandler han;
+ if (__builtin_setjmp(jmpbuf) == 0)
+ {
+ han.Set(jmpbuf, NULL, (__SEHandler::PF)EXCEPTION_EXECUTE_HANDLER);
+#else
+ __try
+ {
+#endif
+ SalData* pSalData = GetSalData();
+ ImplSVData* pSVData = ImplGetSVData();
+
+ // Test for MouseLeave
+ SalTestMouseLeave();
+
+ bool bRecursive = pSalData->mbInTimerProc && (nId != SALTIMERPROC_RECURSIVE);
+ if ( pSVData->mpSalTimer && ! bRecursive )
+ {
+ // Try to aquire the mutex. If we don't get the mutex then we
+ // try this a short time later again.
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ bRecursive = pSalData->mbInTimerProc && (nId != SALTIMERPROC_RECURSIVE);
+ if ( pSVData->mpSalTimer && ! bRecursive )
+ {
+ pSalData->mbInTimerProc = TRUE;
+ pSVData->mpSalTimer->CallCallback();
+ pSalData->mbInTimerProc = FALSE;
+ ImplSalYieldMutexRelease();
+
+ // Run the timer in the correct time, if we start this
+ // with a small timeout, because we don't get the mutex
+ if ( pSalData->mnTimerId &&
+ (pSalData->mnTimerMS != pSalData->mnTimerOrgMS) )
+ ImplSalStartTimer( pSalData->mnTimerOrgMS, FALSE );
+ }
+ }
+ else
+ ImplSalStartTimer( 10, TRUE );
+ }
+ }
+#ifdef __MINGW32__
+ han.Reset();
+#else
+ __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))
+ {
+ }
+#endif
+}
diff --git a/vcl/win/source/gdi/MAKEFILE.MK b/vcl/win/source/gdi/MAKEFILE.MK
new file mode 100644
index 000000000000..7489be633f2b
--- /dev/null
+++ b/vcl/win/source/gdi/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=salgdi
+
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+# --- #105371#
+.IF "$(COM)"=="GCC"
+.ELSE
+CFLAGS += -DWINVER=0x0400
+.ENDIF
+
+# --- Files --------------------------------------------------------
+
+SLOFILES= $(SLO)$/salgdi.obj \
+ $(SLO)$/salgdi2.obj \
+ $(SLO)$/salgdi3.obj \
+ $(SLO)$/salgdi_gdiplus.obj \
+ $(SLO)$/salvd.obj \
+ $(SLO)$/salprn.obj \
+ $(SLO)$/salbmp.obj \
+ $(SLO)$/winlayout.obj \
+ $(SLO)$/wntgdi.obj \
+ $(SLO)$/salnativewidgets-luna.obj
+
+
+EXCEPTIONSFILES= $(SLO)$/salprn.obj
+
+.IF "$(ENABLE_GRAPHITE)" == "TRUE"
+CFLAGS+=-DENABLE_GRAPHITE
+.ENDIF
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
diff --git a/vcl/win/source/gdi/salbmp.cxx b/vcl/win/source/gdi/salbmp.cxx
new file mode 100644
index 000000000000..444df039dd69
--- /dev/null
+++ b/vcl/win/source/gdi/salbmp.cxx
@@ -0,0 +1,632 @@
+/*************************************************************************
+ *
+ * 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/svwin.h>
+#include <wincomp.hxx>
+#include <vcl/salbtype.hxx>
+#include <salgdi.h>
+#include <saldata.hxx>
+#include <salbmp.h>
+#include <vcl/bitmap.hxx> // for BitmapSystemData
+#include <string.h>
+
+// -----------
+// - Inlines -
+// -----------
+
+inline void ImplSetPixel4( const HPBYTE pScanline, long nX, const BYTE cIndex )
+{
+ BYTE& rByte = pScanline[ nX >> 1 ];
+
+ ( nX & 1 ) ? ( rByte &= 0xf0, rByte |= ( cIndex & 0x0f ) ) :
+ ( rByte &= 0x0f, rByte |= ( cIndex << 4 ) );
+}
+
+// ----------------
+// - WinSalBitmap -
+// ----------------
+
+WinSalBitmap::WinSalBitmap() :
+ mhDIB ( 0 ),
+ mhDDB ( 0 ),
+ mnBitCount ( 0 )
+{
+}
+
+// ------------------------------------------------------------------
+
+WinSalBitmap::~WinSalBitmap()
+{
+ Destroy();
+}
+
+// ------------------------------------------------------------------
+
+bool WinSalBitmap::Create( HANDLE hBitmap, bool bDIB, bool bCopyHandle )
+{
+ bool bRet = TRUE;
+
+ if( bDIB )
+ mhDIB = (HGLOBAL) ( bCopyHandle ? ImplCopyDIBOrDDB( hBitmap, TRUE ) : hBitmap );
+ else
+ mhDDB = (HBITMAP) ( bCopyHandle ? ImplCopyDIBOrDDB( hBitmap, FALSE ) : hBitmap );
+
+ if( mhDIB )
+ {
+ PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) GlobalLock( mhDIB );
+
+ maSize = Size( pBIH->biWidth, pBIH->biHeight );
+ mnBitCount = pBIH->biBitCount;
+
+ if( mnBitCount )
+ mnBitCount = ( mnBitCount <= 1 ) ? 1 : ( mnBitCount <= 4 ) ? 4 : ( mnBitCount <= 8 ) ? 8 : 24;
+
+ GlobalUnlock( mhDIB );
+ }
+ else if( mhDDB )
+ {
+ BITMAP aDDBInfo;
+
+ if( WIN_GetObject( mhDDB, sizeof( BITMAP ), &aDDBInfo ) )
+ {
+ maSize = Size( aDDBInfo.bmWidth, aDDBInfo.bmHeight );
+ mnBitCount = aDDBInfo.bmPlanes * aDDBInfo.bmBitsPixel;
+
+ if( mnBitCount )
+ {
+ mnBitCount = ( mnBitCount <= 1 ) ? 1 :
+ ( mnBitCount <= 4 ) ? 4 :
+ ( mnBitCount <= 8 ) ? 8 : 24;
+ }
+ }
+ else
+ {
+ mhDDB = 0;
+ bRet = FALSE;
+ }
+ }
+ else
+ bRet = FALSE;
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+bool WinSalBitmap::Create( const Size& rSize, USHORT nBitCount, const BitmapPalette& rPal )
+{
+ bool bRet = FALSE;
+
+ mhDIB = ImplCreateDIB( rSize, nBitCount, rPal );
+
+ if( mhDIB )
+ {
+ maSize = rSize;
+ mnBitCount = nBitCount;
+ bRet = TRUE;
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+bool WinSalBitmap::Create( const SalBitmap& rSSalBitmap )
+{
+ bool bRet = FALSE;
+ const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(rSSalBitmap);
+
+ if ( rSalBitmap.mhDIB || rSalBitmap.mhDDB )
+ {
+ HANDLE hNewHdl = ImplCopyDIBOrDDB( rSalBitmap.mhDIB ? rSalBitmap.mhDIB : rSalBitmap.mhDDB,
+ rSalBitmap.mhDIB != 0 );
+
+ if ( hNewHdl )
+ {
+ if( rSalBitmap.mhDIB )
+ mhDIB = (HGLOBAL) hNewHdl;
+ else if( rSalBitmap.mhDDB )
+ mhDDB = (HBITMAP) hNewHdl;
+
+ maSize = rSalBitmap.maSize;
+ mnBitCount = rSalBitmap.mnBitCount;
+
+ bRet = TRUE;
+ }
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+bool WinSalBitmap::Create( const SalBitmap& rSSalBmp, SalGraphics* pSGraphics )
+{
+ bool bRet = FALSE;
+
+ const WinSalBitmap& rSalBmp = static_cast<const WinSalBitmap&>(rSSalBmp);
+ WinSalGraphics* pGraphics = static_cast<WinSalGraphics*>(pSGraphics);
+
+ if( rSalBmp.mhDIB )
+ {
+ PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( rSalBmp.mhDIB );
+ PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) pBI;
+ HDC hDC = pGraphics->mhDC;
+ HBITMAP hNewDDB;
+ BITMAP aDDBInfo;
+ PBYTE pBits = (PBYTE) pBI + *(DWORD*) pBI +
+ ImplGetDIBColorCount( rSalBmp.mhDIB ) * sizeof( RGBQUAD );
+
+ if( pBIH->biBitCount == 1 )
+ {
+ hNewDDB = CreateBitmap( pBIH->biWidth, pBIH->biHeight, 1, 1, NULL );
+
+ if( hNewDDB )
+ SetDIBits( hDC, hNewDDB, 0, pBIH->biHeight, pBits, pBI, DIB_RGB_COLORS );
+ }
+ else
+ hNewDDB = CreateDIBitmap( hDC, (PBITMAPINFOHEADER) pBI, CBM_INIT, pBits, pBI, DIB_RGB_COLORS );
+
+ GlobalUnlock( rSalBmp.mhDIB );
+
+ if( hNewDDB && WIN_GetObject( hNewDDB, sizeof( BITMAP ), &aDDBInfo ) )
+ {
+ mhDDB = hNewDDB;
+ maSize = Size( aDDBInfo.bmWidth, aDDBInfo.bmHeight );
+ mnBitCount = aDDBInfo.bmPlanes * aDDBInfo.bmBitsPixel;
+
+ bRet = TRUE;
+ }
+ else if( hNewDDB )
+ DeleteObject( hNewDDB );
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+bool WinSalBitmap::Create( const SalBitmap& rSSalBmp, USHORT nNewBitCount )
+{
+ bool bRet = FALSE;
+
+ const WinSalBitmap& rSalBmp = static_cast<const WinSalBitmap&>(rSSalBmp);
+
+ if( rSalBmp.mhDDB )
+ {
+ mhDIB = ImplCreateDIB( rSalBmp.maSize, nNewBitCount, BitmapPalette() );
+
+ if( mhDIB )
+ {
+ PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( mhDIB );
+ const int nLines = (int) rSalBmp.maSize.Height();
+ HDC hDC = GetDC( 0 );
+ PBYTE pBits = (PBYTE) pBI + *(DWORD*) pBI +
+ ImplGetDIBColorCount( mhDIB ) * sizeof( RGBQUAD );
+ SalData* pSalData = GetSalData();
+ HPALETTE hOldPal = 0;
+
+ if ( pSalData->mhDitherPal )
+ {
+ hOldPal = SelectPalette( hDC, pSalData->mhDitherPal, TRUE );
+ RealizePalette( hDC );
+ }
+
+ if( GetDIBits( hDC, rSalBmp.mhDDB, 0, nLines, pBits, pBI, DIB_RGB_COLORS ) == nLines )
+ {
+ GlobalUnlock( mhDIB );
+ maSize = rSalBmp.maSize;
+ mnBitCount = nNewBitCount;
+ bRet = TRUE;
+ }
+ else
+ {
+ GlobalUnlock( mhDIB );
+ GlobalFree( mhDIB );
+ mhDIB = 0;
+ }
+
+ if( hOldPal )
+ SelectPalette( hDC, hOldPal, TRUE );
+
+ ReleaseDC( 0, hDC );
+ }
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+void WinSalBitmap::Destroy()
+{
+ if( mhDIB )
+ GlobalFree( mhDIB );
+ else if( mhDDB )
+ DeleteObject( mhDDB );
+
+ maSize = Size();
+ mnBitCount = 0;
+}
+
+// ------------------------------------------------------------------
+
+USHORT WinSalBitmap::ImplGetDIBColorCount( HGLOBAL hDIB )
+{
+ USHORT nColors = 0;
+
+ if( hDIB )
+ {
+ PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( hDIB );
+ PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) pBI;
+
+ if ( pBIH->biSize != sizeof( BITMAPCOREHEADER ) )
+ {
+ if( pBIH->biBitCount <= 8 )
+ {
+ if ( pBIH->biClrUsed )
+ nColors = (USHORT) pBIH->biClrUsed;
+ else
+ nColors = 1 << pBIH->biBitCount;
+ }
+ }
+ else if( ( (PBITMAPCOREHEADER) pBI )->bcBitCount <= 8 )
+ nColors = 1 << ( (PBITMAPCOREHEADER) pBI )->bcBitCount;
+
+ GlobalUnlock( hDIB );
+ }
+
+ return nColors;
+}
+
+// ------------------------------------------------------------------
+
+HGLOBAL WinSalBitmap::ImplCreateDIB( const Size& rSize, USHORT nBits, const BitmapPalette& rPal )
+{
+ DBG_ASSERT( nBits == 1 || nBits == 4 || nBits == 8 || nBits == 16 || nBits == 24, "Unsupported BitCount!" );
+
+ HGLOBAL hDIB = 0;
+
+ if ( rSize.Width() && rSize.Height() )
+ {
+ const ULONG nImageSize = AlignedWidth4Bytes( nBits * rSize.Width() ) * rSize.Height();
+ const USHORT nColors = ( nBits <= 8 ) ? ( 1 << nBits ) : 0;
+
+ hDIB = GlobalAlloc( GHND, sizeof( BITMAPINFOHEADER ) + nColors * sizeof( RGBQUAD ) + nImageSize );
+
+ if( hDIB )
+ {
+ PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( hDIB );
+ PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) pBI;
+
+ pBIH->biSize = sizeof( BITMAPINFOHEADER );
+ pBIH->biWidth = rSize.Width();
+ pBIH->biHeight = rSize.Height();
+ pBIH->biPlanes = 1;
+ pBIH->biBitCount = nBits;
+ pBIH->biCompression = BI_RGB;
+ pBIH->biSizeImage = nImageSize;
+ pBIH->biXPelsPerMeter = 0;
+ pBIH->biYPelsPerMeter = 0;
+ pBIH->biClrUsed = 0;
+ pBIH->biClrImportant = 0;
+
+ if ( nColors )
+ {
+ const USHORT nMinCount = Min( nColors, rPal.GetEntryCount() );
+
+ if( nMinCount )
+ memcpy( pBI->bmiColors, rPal.ImplGetColorBuffer(), nMinCount * sizeof( RGBQUAD ) );
+ }
+
+ GlobalUnlock( hDIB );
+ }
+ }
+
+ return hDIB;
+}
+
+// ------------------------------------------------------------------
+
+HANDLE WinSalBitmap::ImplCopyDIBOrDDB( HANDLE hHdl, bool bDIB )
+{
+ HANDLE hCopy = 0;
+
+ if ( bDIB && hHdl )
+ {
+ const ULONG nSize = GlobalSize( hHdl );
+
+ if ( (hCopy = GlobalAlloc( GHND, nSize )) != 0 )
+ {
+ memcpy( (LPSTR) GlobalLock( hCopy ), (LPSTR) GlobalLock( hHdl ), nSize );
+
+ GlobalUnlock( hCopy );
+ GlobalUnlock( hHdl );
+ }
+ }
+ else if ( hHdl )
+ {
+ BITMAP aBmp;
+
+ // Source-Bitmap nach Groesse befragen
+ WIN_GetObject( hHdl, sizeof( BITMAP ), (LPSTR) &aBmp );
+
+ // Destination-Bitmap erzeugen
+ if ( (hCopy = CreateBitmapIndirect( &aBmp )) != 0 )
+ {
+ HDC hBmpDC = CreateCompatibleDC( 0 );
+ HBITMAP hBmpOld = (HBITMAP) SelectObject( hBmpDC, hHdl );
+ HDC hCopyDC = CreateCompatibleDC( hBmpDC );
+ HBITMAP hCopyOld = (HBITMAP) SelectObject( hCopyDC, hCopy );
+
+ BitBlt( hCopyDC, 0, 0, aBmp.bmWidth, aBmp.bmHeight, hBmpDC, 0, 0, SRCCOPY );
+
+ SelectObject( hCopyDC, hCopyOld );
+ DeleteDC( hCopyDC );
+
+ SelectObject( hBmpDC, hBmpOld );
+ DeleteDC( hBmpDC );
+ }
+ }
+
+ return hCopy;
+}
+
+// ------------------------------------------------------------------
+
+BitmapBuffer* WinSalBitmap::AcquireBuffer( bool /*bReadOnly*/ )
+{
+ BitmapBuffer* pBuffer = NULL;
+
+ if( mhDIB )
+ {
+ PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( mhDIB );
+ PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) pBI;
+
+ if( ( pBIH->biCompression == BI_RLE4 ) || ( pBIH->biCompression == BI_RLE8 ) )
+ {
+ Size aSizePix( pBIH->biWidth, pBIH->biHeight );
+ HGLOBAL hNewDIB = ImplCreateDIB( aSizePix, pBIH->biBitCount, BitmapPalette() );
+
+ if( hNewDIB )
+ {
+ PBITMAPINFO pNewBI = (PBITMAPINFO) GlobalLock( hNewDIB );
+ PBITMAPINFOHEADER pNewBIH = (PBITMAPINFOHEADER) pNewBI;
+ const USHORT nColorCount = ImplGetDIBColorCount( hNewDIB );
+ const ULONG nOffset = *(DWORD*) pBI + nColorCount * sizeof( RGBQUAD );
+ BYTE* pOldBits = (PBYTE) pBI + nOffset;
+ BYTE* pNewBits = (PBYTE) pNewBI + nOffset;
+
+ memcpy( pNewBI, pBI, nOffset );
+ pNewBIH->biCompression = 0;
+ ImplDecodeRLEBuffer( pOldBits, pNewBits, aSizePix, pBIH->biCompression == BI_RLE4 );
+
+ GlobalUnlock( mhDIB );
+ GlobalFree( mhDIB );
+ mhDIB = hNewDIB;
+ pBI = pNewBI;
+ pBIH = pNewBIH;
+ }
+ }
+
+ if( pBIH->biPlanes == 1 )
+ {
+ pBuffer = new BitmapBuffer;
+
+ pBuffer->mnFormat = BMP_FORMAT_BOTTOM_UP |
+ ( pBIH->biBitCount == 1 ? BMP_FORMAT_1BIT_MSB_PAL :
+ pBIH->biBitCount == 4 ? BMP_FORMAT_4BIT_MSN_PAL :
+ pBIH->biBitCount == 8 ? BMP_FORMAT_8BIT_PAL :
+ pBIH->biBitCount == 16 ? BMP_FORMAT_16BIT_TC_LSB_MASK :
+ pBIH->biBitCount == 24 ? BMP_FORMAT_24BIT_TC_BGR :
+ pBIH->biBitCount == 32 ? BMP_FORMAT_32BIT_TC_MASK : 0UL );
+
+ if( BMP_SCANLINE_FORMAT( pBuffer->mnFormat ) )
+ {
+ pBuffer->mnWidth = maSize.Width();
+ pBuffer->mnHeight = maSize.Height();
+ pBuffer->mnScanlineSize = AlignedWidth4Bytes( maSize.Width() * pBIH->biBitCount );
+ pBuffer->mnBitCount = (USHORT) pBIH->biBitCount;
+
+ if( pBuffer->mnBitCount <= 8 )
+ {
+ const USHORT nPalCount = ImplGetDIBColorCount( mhDIB );
+
+ pBuffer->maPalette.SetEntryCount( nPalCount );
+ memcpy( pBuffer->maPalette.ImplGetColorBuffer(), pBI->bmiColors, nPalCount * sizeof( RGBQUAD ) );
+ pBuffer->mpBits = (PBYTE) pBI + *(DWORD*) pBI + nPalCount * sizeof( RGBQUAD );
+ }
+ else if( ( pBIH->biBitCount == 16 ) || ( pBIH->biBitCount == 32 ) )
+ {
+ ULONG nOffset = 0UL;
+
+ if( pBIH->biCompression == BI_BITFIELDS )
+ {
+ nOffset = 3 * sizeof( RGBQUAD );
+ pBuffer->maColorMask = ColorMask( *(UINT32*) &pBI->bmiColors[ 0 ],
+ *(UINT32*) &pBI->bmiColors[ 1 ],
+ *(UINT32*) &pBI->bmiColors[ 2 ] );
+ }
+ else if( pBIH->biBitCount == 16 )
+ pBuffer->maColorMask = ColorMask( 0x00007c00UL, 0x000003e0UL, 0x0000001fUL );
+ else
+ pBuffer->maColorMask = ColorMask( 0x00ff0000UL, 0x0000ff00UL, 0x000000ffUL );
+
+ pBuffer->mpBits = (PBYTE) pBI + *(DWORD*) pBI + nOffset;
+ }
+ else
+ pBuffer->mpBits = (PBYTE) pBI + *(DWORD*) pBI;
+ }
+ else
+ {
+ GlobalUnlock( mhDIB );
+ delete pBuffer;
+ pBuffer = NULL;
+ }
+ }
+ else
+ GlobalUnlock( mhDIB );
+ }
+
+ return pBuffer;
+}
+
+// ------------------------------------------------------------------
+
+void WinSalBitmap::ReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly )
+{
+ if( pBuffer )
+ {
+ if( mhDIB )
+ {
+ if( !bReadOnly && !!pBuffer->maPalette )
+ {
+ PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( mhDIB );
+ const USHORT nCount = pBuffer->maPalette.GetEntryCount();
+
+ memcpy( pBI->bmiColors, pBuffer->maPalette.ImplGetColorBuffer(), nCount * sizeof( RGBQUAD ) );
+ GlobalUnlock( mhDIB );
+ }
+
+ GlobalUnlock( mhDIB );
+ }
+
+ delete pBuffer;
+ }
+}
+
+// ------------------------------------------------------------------
+
+void WinSalBitmap::ImplDecodeRLEBuffer( const BYTE* pSrcBuf, BYTE* pDstBuf,
+ const Size& rSizePixel, bool bRLE4 )
+{
+ HPBYTE pRLE = (HPBYTE) pSrcBuf;
+ HPBYTE pDIB = (HPBYTE) pDstBuf;
+ HPBYTE pRow = (HPBYTE) pDstBuf;
+ ULONG nWidthAl = AlignedWidth4Bytes( rSizePixel.Width() * ( bRLE4 ? 4UL : 8UL ) );
+ HPBYTE pLast = pDIB + rSizePixel.Height() * nWidthAl - 1;
+ ULONG nCountByte;
+ ULONG nRunByte;
+ ULONG nX = 0;
+ ULONG i;
+ BYTE cTmp;
+ bool bEndDecoding = FALSE;
+
+ if( pRLE && pDIB )
+ {
+ do
+ {
+ if( ( nCountByte = *pRLE++ ) == 0 )
+ {
+ nRunByte = *pRLE++;
+
+ if( nRunByte > 2UL )
+ {
+ if( bRLE4 )
+ {
+ nCountByte = nRunByte >> 1UL;
+
+ for( i = 0; i < nCountByte; i++ )
+ {
+ cTmp = *pRLE++;
+ ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
+ ImplSetPixel4( pDIB, nX++, cTmp & 0x0f );
+ }
+
+ if( nRunByte & 1 )
+ ImplSetPixel4( pDIB, nX++, *pRLE++ >> 4 );
+
+ if( ( ( nRunByte + 1 ) >> 1 ) & 1 )
+ pRLE++;
+ }
+ else
+ {
+ memcpy( &pDIB[ nX ], pRLE, nRunByte );
+ pRLE += nRunByte;
+ nX += nRunByte;
+
+ if( nRunByte & 1 )
+ pRLE++;
+ }
+ }
+ else if( !nRunByte )
+ {
+ pDIB = ( pRow += nWidthAl );
+ nX = 0UL;
+ }
+ else if( nRunByte == 1 )
+ bEndDecoding = TRUE;
+ else
+ {
+ nX += *pRLE++;
+ pDIB = ( pRow += ( *pRLE++ ) * nWidthAl );
+ }
+ }
+ else
+ {
+ cTmp = *pRLE++;
+
+ if( bRLE4 )
+ {
+ nRunByte = nCountByte >> 1;
+
+ for( i = 0; i < nRunByte; i++ )
+ {
+ ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
+ ImplSetPixel4( pDIB, nX++, cTmp & 0x0f );
+ }
+
+ if( nCountByte & 1 )
+ ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
+ }
+ else
+ {
+ for( i = 0; i < nCountByte; i++ )
+ pDIB[ nX++ ] = cTmp;
+ }
+ }
+ }
+ while( !bEndDecoding && ( pDIB <= pLast ) );
+ }
+}
+
+bool WinSalBitmap::GetSystemData( BitmapSystemData& rData )
+{
+ bool bRet = false;
+ if( mhDIB || mhDDB )
+ {
+ bRet = true;
+ rData.pDIB = mhDIB;
+ rData.pDDB = mhDDB;
+ const Size& rSize = GetSize ();
+ rData.mnWidth = rSize.Width();
+ rData.mnHeight = rSize.Height();
+ }
+ return bRet;
+}
diff --git a/vcl/win/source/gdi/salgdi.cxx b/vcl/win/source/gdi/salgdi.cxx
new file mode 100644
index 000000000000..eb260eb808c6
--- /dev/null
+++ b/vcl/win/source/gdi/salgdi.cxx
@@ -0,0 +1,1798 @@
+/*************************************************************************
+ *
+ * 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 <string.h>
+#include <tools/svwin.h>
+#include <wincomp.hxx>
+#include <saldata.hxx>
+#include <salgdi.h>
+#include <tools/debug.hxx>
+#include <salframe.h>
+#include <tools/poly.hxx>
+#ifndef _RTL_STRINGBUF_HXX
+#include <rtl/strbuf.hxx>
+#endif
+
+using namespace rtl;
+
+// =======================================================================
+
+// comment out to prevent use of beziers on GDI functions
+#define USE_GDI_BEZIERS
+
+// =======================================================================
+
+#define DITHER_PAL_DELTA 51
+#define DITHER_PAL_STEPS 6
+#define DITHER_PAL_COUNT (DITHER_PAL_STEPS*DITHER_PAL_STEPS*DITHER_PAL_STEPS)
+#define DITHER_MAX_SYSCOLOR 16
+#define DITHER_EXTRA_COLORS 1
+#define DMAP( _def_nVal, _def_nThres ) ((pDitherDiff[_def_nVal]>(_def_nThres))?pDitherHigh[_def_nVal]:pDitherLow[_def_nVal])
+
+// =======================================================================
+
+struct SysColorEntry
+{
+ DWORD nRGB;
+ SysColorEntry* pNext;
+};
+
+// =======================================================================
+
+static SysColorEntry* pFirstSysColor = NULL;
+static SysColorEntry* pActSysColor = NULL;
+
+// -----------------------------------------------------------------------------
+
+// Blue7
+static PALETTEENTRY aImplExtraColor1 =
+{
+ 0, 184, 255, 0
+};
+
+// -----------------------------------------------------------------------------
+
+static PALETTEENTRY aImplSalSysPalEntryAry[ DITHER_MAX_SYSCOLOR ] =
+{
+{ 0, 0, 0, 0 },
+{ 0, 0, 0x80, 0 },
+{ 0, 0x80, 0, 0 },
+{ 0, 0x80, 0x80, 0 },
+{ 0x80, 0, 0, 0 },
+{ 0x80, 0, 0x80, 0 },
+{ 0x80, 0x80, 0, 0 },
+{ 0x80, 0x80, 0x80, 0 },
+{ 0xC0, 0xC0, 0xC0, 0 },
+{ 0, 0, 0xFF, 0 },
+{ 0, 0xFF, 0, 0 },
+{ 0, 0xFF, 0xFF, 0 },
+{ 0xFF, 0, 0, 0 },
+{ 0xFF, 0, 0xFF, 0 },
+{ 0xFF, 0xFF, 0, 0 },
+{ 0xFF, 0xFF, 0xFF, 0 }
+};
+
+// -----------------------------------------------------------------------------
+
+static BYTE aOrdDither8Bit[8][8] =
+{
+ 0, 38, 9, 48, 2, 40, 12, 50,
+ 25, 12, 35, 22, 28, 15, 37, 24,
+ 6, 44, 3, 41, 8, 47, 5, 44,
+ 32, 19, 28, 16, 34, 21, 31, 18,
+ 1, 40, 11, 49, 0, 39, 10, 48,
+ 27, 14, 36, 24, 26, 13, 36, 23,
+ 8, 46, 4, 43, 7, 45, 4, 42,
+ 33, 20, 30, 17, 32, 20, 29, 16
+};
+
+// -----------------------------------------------------------------------------
+
+static BYTE aOrdDither16Bit[8][8] =
+{
+ 0, 6, 1, 7, 0, 6, 1, 7,
+ 4, 2, 5, 3, 4, 2, 5, 3,
+ 1, 7, 0, 6, 1, 7, 0, 6,
+ 5, 3, 4, 2, 5, 3, 4, 2,
+ 0, 6, 1, 7, 0, 6, 1, 7,
+ 4, 2, 5, 3, 4, 2, 5, 3,
+ 1, 7, 0, 6, 1, 7, 0, 6,
+ 5, 3, 4, 2, 5, 3, 4, 2
+};
+
+// =======================================================================
+
+// Pens muessen wir mit 1 Pixel-Breite erzeugen, da ansonsten die S3-Karte
+// viele Paintprobleme hat, wenn Polygone/PolyLines gezeichnet werden und
+// eine komplexe ClipRegion gesetzt ist
+#define GSL_PEN_WIDTH 1
+
+// =======================================================================
+
+#define SAL_POLYPOLYCOUNT_STACKBUF 8
+#define SAL_POLYPOLYPOINTS_STACKBUF 64
+
+// =======================================================================
+
+void ImplInitSalGDI()
+{
+ SalData* pSalData = GetSalData();
+
+ // init stock brushes
+ pSalData->maStockPenColorAry[0] = PALETTERGB( 0, 0, 0 );
+ pSalData->maStockPenColorAry[1] = PALETTERGB( 0xFF, 0xFF, 0xFF );
+ pSalData->maStockPenColorAry[2] = PALETTERGB( 0xC0, 0xC0, 0xC0 );
+ pSalData->maStockPenColorAry[3] = PALETTERGB( 0x80, 0x80, 0x80 );
+ pSalData->mhStockPenAry[0] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[0] );
+ pSalData->mhStockPenAry[1] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[1] );
+ pSalData->mhStockPenAry[2] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[2] );
+ pSalData->mhStockPenAry[3] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[3] );
+ pSalData->mnStockPenCount = 4;
+
+ pSalData->maStockBrushColorAry[0] = PALETTERGB( 0, 0, 0 );
+ pSalData->maStockBrushColorAry[1] = PALETTERGB( 0xFF, 0xFF, 0xFF );
+ pSalData->maStockBrushColorAry[2] = PALETTERGB( 0xC0, 0xC0, 0xC0 );
+ pSalData->maStockBrushColorAry[3] = PALETTERGB( 0x80, 0x80, 0x80 );
+ pSalData->mhStockBrushAry[0] = CreateSolidBrush( pSalData->maStockBrushColorAry[0] );
+ pSalData->mhStockBrushAry[1] = CreateSolidBrush( pSalData->maStockBrushColorAry[1] );
+ pSalData->mhStockBrushAry[2] = CreateSolidBrush( pSalData->maStockBrushColorAry[2] );
+ pSalData->mhStockBrushAry[3] = CreateSolidBrush( pSalData->maStockBrushColorAry[3] );
+ pSalData->mnStockBrushCount = 4;
+
+ // initialize cache of device contexts
+ pSalData->mpHDCCache = new HDCCache[ CACHESIZE_HDC ];
+ memset( pSalData->mpHDCCache, 0, CACHESIZE_HDC * sizeof( HDCCache ) );
+
+ // initialize temporary font list
+ pSalData->mpTempFontItem = NULL;
+
+ // support palettes for 256 color displays
+ HDC hDC = GetDC( 0 );
+ int nBitsPixel = GetDeviceCaps( hDC, BITSPIXEL );
+ int nPlanes = GetDeviceCaps( hDC, PLANES );
+ int nRasterCaps = GetDeviceCaps( hDC, RASTERCAPS );
+ int nBitCount = nBitsPixel * nPlanes;
+
+ if ( (nBitCount > 8) && (nBitCount < 24) )
+ {
+ // test, if we have to dither
+ HDC hMemDC = ::CreateCompatibleDC( hDC );
+ HBITMAP hMemBmp = ::CreateCompatibleBitmap( hDC, 8, 8 );
+ HBITMAP hBmpOld = (HBITMAP) ::SelectObject( hMemDC, hMemBmp );
+ HBRUSH hMemBrush = ::CreateSolidBrush( PALETTERGB( 175, 171, 169 ) );
+ HBRUSH hBrushOld = (HBRUSH) ::SelectObject( hMemDC, hMemBrush );
+ BOOL bDither16 = TRUE;
+
+ ::PatBlt( hMemDC, 0, 0, 8, 8, PATCOPY );
+ const COLORREF aCol( ::GetPixel( hMemDC, 0, 0 ) );
+
+ for( int nY = 0; ( nY < 8 ) && bDither16; nY++ )
+ for( int nX = 0; ( nX < 8 ) && bDither16; nX++ )
+ if( ::GetPixel( hMemDC, nX, nY ) != aCol )
+ bDither16 = FALSE;
+
+ ::SelectObject( hMemDC, hBrushOld ), ::DeleteObject( hMemBrush );
+ ::SelectObject( hMemDC, hBmpOld ), ::DeleteObject( hMemBmp );
+ ::DeleteDC( hMemDC );
+
+ if( bDither16 )
+ {
+ // create DIBPattern for 16Bit dithering
+ long n;
+
+ pSalData->mhDitherDIB = GlobalAlloc( GMEM_FIXED, sizeof( BITMAPINFOHEADER ) + 192 );
+ pSalData->mpDitherDIB = (BYTE*) GlobalLock( pSalData->mhDitherDIB );
+ pSalData->mpDitherDiff = new long[ 256 ];
+ pSalData->mpDitherLow = new BYTE[ 256 ];
+ pSalData->mpDitherHigh = new BYTE[ 256 ];
+ pSalData->mpDitherDIBData = pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER );
+ memset( pSalData->mpDitherDIB, 0, sizeof( BITMAPINFOHEADER ) );
+
+ BITMAPINFOHEADER* pBIH = (BITMAPINFOHEADER*) pSalData->mpDitherDIB;
+
+ pBIH->biSize = sizeof( BITMAPINFOHEADER );
+ pBIH->biWidth = 8;
+ pBIH->biHeight = 8;
+ pBIH->biPlanes = 1;
+ pBIH->biBitCount = 24;
+
+ for( n = 0; n < 256L; n++ )
+ pSalData->mpDitherDiff[ n ] = n - ( n & 248L );
+
+ for( n = 0; n < 256L; n++ )
+ pSalData->mpDitherLow[ n ] = (BYTE) ( n & 248 );
+
+ for( n = 0; n < 256L; n++ )
+ pSalData->mpDitherHigh[ n ] = (BYTE) Min( pSalData->mpDitherLow[ n ] + 8L, 255L );
+ }
+ }
+ else if ( (nRasterCaps & RC_PALETTE) && (nBitCount == 8) )
+ {
+ BYTE nRed, nGreen, nBlue;
+ BYTE nR, nG, nB;
+ PALETTEENTRY* pPalEntry;
+ LOGPALETTE* pLogPal;
+ const USHORT nDitherPalCount = DITHER_PAL_COUNT;
+ ULONG nTotalCount = DITHER_MAX_SYSCOLOR + nDitherPalCount + DITHER_EXTRA_COLORS;
+
+ // create logical palette
+ pLogPal = (LOGPALETTE*) new char[ sizeof( LOGPALETTE ) + ( nTotalCount * sizeof( PALETTEENTRY ) ) ];
+ pLogPal->palVersion = 0x0300;
+ pLogPal->palNumEntries = (USHORT) nTotalCount;
+ pPalEntry = pLogPal->palPalEntry;
+
+ // Standard colors
+ memcpy( pPalEntry, aImplSalSysPalEntryAry, DITHER_MAX_SYSCOLOR * sizeof( PALETTEENTRY ) );
+ pPalEntry += DITHER_MAX_SYSCOLOR;
+
+ // own palette (6/6/6)
+ for( nB=0, nBlue=0; nB < DITHER_PAL_STEPS; nB++, nBlue += DITHER_PAL_DELTA )
+ {
+ for( nG=0, nGreen=0; nG < DITHER_PAL_STEPS; nG++, nGreen += DITHER_PAL_DELTA )
+ {
+ for( nR=0, nRed=0; nR < DITHER_PAL_STEPS; nR++, nRed += DITHER_PAL_DELTA )
+ {
+ pPalEntry->peRed = nRed;
+ pPalEntry->peGreen = nGreen;
+ pPalEntry->peBlue = nBlue;
+ pPalEntry->peFlags = 0;
+ pPalEntry++;
+ }
+ }
+ }
+
+ // insert special 'Blue' as standard drawing color
+ *pPalEntry++ = aImplExtraColor1;
+
+ // create palette
+ pSalData->mhDitherPal = CreatePalette( pLogPal );
+ delete[] (char*) pLogPal;
+
+ if( pSalData->mhDitherPal )
+ {
+ // create DIBPattern for 8Bit dithering
+ long nSize = sizeof( BITMAPINFOHEADER ) + ( 256 * sizeof( short ) ) + 64;
+ long n;
+
+ pSalData->mhDitherDIB = GlobalAlloc( GMEM_FIXED, nSize );
+ pSalData->mpDitherDIB = (BYTE*) GlobalLock( pSalData->mhDitherDIB );
+ pSalData->mpDitherDiff = new long[ 256 ];
+ pSalData->mpDitherLow = new BYTE[ 256 ];
+ pSalData->mpDitherHigh = new BYTE[ 256 ];
+ pSalData->mpDitherDIBData = pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER ) + ( 256 * sizeof( short ) );
+ memset( pSalData->mpDitherDIB, 0, sizeof( BITMAPINFOHEADER ) );
+
+ BITMAPINFOHEADER* pBIH = (BITMAPINFOHEADER*) pSalData->mpDitherDIB;
+ short* pColors = (short*) ( pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER ) );
+
+ pBIH->biSize = sizeof( BITMAPINFOHEADER );
+ pBIH->biWidth = 8;
+ pBIH->biHeight = 8;
+ pBIH->biPlanes = 1;
+ pBIH->biBitCount = 8;
+
+ for( n = 0; n < nDitherPalCount; n++ )
+ pColors[ n ] = (short)( n + DITHER_MAX_SYSCOLOR );
+
+ for( n = 0; n < 256L; n++ )
+ pSalData->mpDitherDiff[ n ] = n % 51L;
+
+ for( n = 0; n < 256L; n++ )
+ pSalData->mpDitherLow[ n ] = (BYTE) ( n / 51L );
+
+ for( n = 0; n < 256L; n++ )
+ pSalData->mpDitherHigh[ n ] = (BYTE)Min( pSalData->mpDitherLow[ n ] + 1, 5 );
+ }
+
+ // get system color entries
+ ImplUpdateSysColorEntries();
+ }
+
+ ReleaseDC( 0, hDC );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplFreeSalGDI()
+{
+ SalData* pSalData = GetSalData();
+
+ // destroy stock objects
+ int i;
+ for ( i = 0; i < pSalData->mnStockPenCount; i++ )
+ DeletePen( pSalData->mhStockPenAry[i] );
+ for ( i = 0; i < pSalData->mnStockBrushCount; i++ )
+ DeleteBrush( pSalData->mhStockBrushAry[i] );
+
+ // 50% Brush loeschen
+ if ( pSalData->mh50Brush )
+ {
+ DeleteBrush( pSalData->mh50Brush );
+ pSalData->mh50Brush = 0;
+ }
+
+ // 50% Bitmap loeschen
+ if ( pSalData->mh50Bmp )
+ {
+ DeleteBitmap( pSalData->mh50Bmp );
+ pSalData->mh50Bmp = 0;
+ }
+
+ ImplClearHDCCache( pSalData );
+ delete[] pSalData->mpHDCCache;
+
+ // Ditherpalette loeschen, wenn vorhanden
+ if ( pSalData->mhDitherPal )
+ {
+ DeleteObject( pSalData->mhDitherPal );
+ pSalData->mhDitherPal = 0;
+ }
+
+ // delete buffers for dithering DIB patterns, if neccessary
+ if ( pSalData->mhDitherDIB )
+ {
+ GlobalUnlock( pSalData->mhDitherDIB );
+ GlobalFree( pSalData->mhDitherDIB );
+ pSalData->mhDitherDIB = 0;
+ delete[] pSalData->mpDitherDiff;
+ delete[] pSalData->mpDitherLow;
+ delete[] pSalData->mpDitherHigh;
+ }
+
+ // delete SysColorList
+ SysColorEntry* pEntry = pFirstSysColor;
+ while( pEntry )
+ {
+ SysColorEntry* pTmp = pEntry->pNext;
+ delete pEntry;
+ pEntry = pTmp;
+ }
+ pFirstSysColor = NULL;
+
+ // delete icon cache
+ SalIcon* pIcon = pSalData->mpFirstIcon;
+ pSalData->mpFirstIcon = NULL;
+ while( pIcon )
+ {
+ SalIcon* pTmp = pIcon->pNext;
+ DestroyIcon( pIcon->hIcon );
+ DestroyIcon( pIcon->hSmallIcon );
+ delete pIcon;
+ pIcon = pTmp;
+ }
+
+ // delete temporary font list
+ ImplReleaseTempFonts( *pSalData );
+}
+
+// -----------------------------------------------------------------------
+
+static int ImplIsPaletteEntry( BYTE nRed, BYTE nGreen, BYTE nBlue )
+{
+ // dither color?
+ if ( !(nRed % DITHER_PAL_DELTA) && !(nGreen % DITHER_PAL_DELTA) && !(nBlue % DITHER_PAL_DELTA) )
+ return TRUE;
+
+ PALETTEENTRY* pPalEntry = aImplSalSysPalEntryAry;
+
+ // standard palette color?
+ for ( USHORT i = 0; i < DITHER_MAX_SYSCOLOR; i++, pPalEntry++ )
+ {
+ if( pPalEntry->peRed == nRed && pPalEntry->peGreen == nGreen && pPalEntry->peBlue == nBlue )
+ return TRUE;
+ }
+
+ // extra color?
+ if ( aImplExtraColor1.peRed == nRed &&
+ aImplExtraColor1.peGreen == nGreen &&
+ aImplExtraColor1.peBlue == nBlue )
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// =======================================================================
+
+int ImplIsSysColorEntry( SalColor nSalColor )
+{
+ SysColorEntry* pEntry = pFirstSysColor;
+ const DWORD nTestRGB = (DWORD)RGB( SALCOLOR_RED( nSalColor ),
+ SALCOLOR_GREEN( nSalColor ),
+ SALCOLOR_BLUE( nSalColor ) );
+
+ while ( pEntry )
+ {
+ if ( pEntry->nRGB == nTestRGB )
+ return TRUE;
+ pEntry = pEntry->pNext;
+ }
+
+ return FALSE;
+}
+
+// =======================================================================
+
+static void ImplInsertSysColorEntry( int nSysIndex )
+{
+ const DWORD nRGB = GetSysColor( nSysIndex );
+
+ if ( !ImplIsPaletteEntry( GetRValue( nRGB ), GetGValue( nRGB ), GetBValue( nRGB ) ) )
+ {
+ if ( !pFirstSysColor )
+ {
+ pActSysColor = pFirstSysColor = new SysColorEntry;
+ pFirstSysColor->nRGB = nRGB;
+ pFirstSysColor->pNext = NULL;
+ }
+ else
+ {
+ pActSysColor = pActSysColor->pNext = new SysColorEntry;
+ pActSysColor->nRGB = nRGB;
+ pActSysColor->pNext = NULL;
+ }
+ }
+}
+
+// =======================================================================
+
+void ImplUpdateSysColorEntries()
+{
+ // delete old SysColorList
+ SysColorEntry* pEntry = pFirstSysColor;
+ while( pEntry )
+ {
+ SysColorEntry* pTmp = pEntry->pNext;
+ delete pEntry;
+ pEntry = pTmp;
+ }
+ pActSysColor = pFirstSysColor = NULL;
+
+ // create new sys color list
+ ImplInsertSysColorEntry( COLOR_ACTIVEBORDER );
+ ImplInsertSysColorEntry( COLOR_INACTIVEBORDER );
+ if( aSalShlData.mnVersion >= 410 )
+ {
+ ImplInsertSysColorEntry( COLOR_GRADIENTACTIVECAPTION );
+ ImplInsertSysColorEntry( COLOR_GRADIENTINACTIVECAPTION );
+ }
+ ImplInsertSysColorEntry( COLOR_3DFACE );
+ ImplInsertSysColorEntry( COLOR_3DHILIGHT );
+ ImplInsertSysColorEntry( COLOR_3DLIGHT );
+ ImplInsertSysColorEntry( COLOR_3DSHADOW );
+ ImplInsertSysColorEntry( COLOR_3DDKSHADOW );
+ ImplInsertSysColorEntry( COLOR_INFOBK );
+ ImplInsertSysColorEntry( COLOR_INFOTEXT );
+ ImplInsertSysColorEntry( COLOR_BTNTEXT );
+ ImplInsertSysColorEntry( COLOR_WINDOW );
+ ImplInsertSysColorEntry( COLOR_WINDOWTEXT );
+ ImplInsertSysColorEntry( COLOR_HIGHLIGHT );
+ ImplInsertSysColorEntry( COLOR_HIGHLIGHTTEXT );
+ ImplInsertSysColorEntry( COLOR_MENU );
+ ImplInsertSysColorEntry( COLOR_MENUTEXT );
+ ImplInsertSysColorEntry( COLOR_ACTIVECAPTION );
+ ImplInsertSysColorEntry( COLOR_CAPTIONTEXT );
+ ImplInsertSysColorEntry( COLOR_INACTIVECAPTION );
+ ImplInsertSysColorEntry( COLOR_INACTIVECAPTIONTEXT );
+}
+
+// -----------------------------------------------------------------------
+
+static SalColor ImplGetROPSalColor( SalROPColor nROPColor )
+{
+ SalColor nSalColor;
+ if ( nROPColor == SAL_ROP_0 )
+ nSalColor = MAKE_SALCOLOR( 0, 0, 0 );
+ else
+ nSalColor = MAKE_SALCOLOR( 255, 255, 255 );
+ return nSalColor;
+}
+
+// =======================================================================
+
+void ImplSalInitGraphics( WinSalGraphics* pData )
+{
+ // Beim Printer berechnen wir die minimale Linienstaerke
+ if ( pData->mbPrinter )
+ {
+ int nDPIX = GetDeviceCaps( pData->mhDC, LOGPIXELSX );
+ if ( nDPIX <= 300 )
+ pData->mnPenWidth = 0;
+ else
+ pData->mnPenWidth = nDPIX/300;
+ }
+
+ ::SetTextAlign( pData->mhDC, TA_BASELINE | TA_LEFT | TA_NOUPDATECP );
+ ::SetBkMode( pData->mhDC, TRANSPARENT );
+ ::SetROP2( pData->mhDC, R2_COPYPEN );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplSalDeInitGraphics( WinSalGraphics* pData )
+{
+ // Default Objekte selektieren
+ if ( pData->mhDefPen )
+ SelectPen( pData->mhDC, pData->mhDefPen );
+ if ( pData->mhDefBrush )
+ SelectBrush( pData->mhDC, pData->mhDefBrush );
+ if ( pData->mhDefFont )
+ SelectFont( pData->mhDC, pData->mhDefFont );
+}
+
+// =======================================================================
+
+HDC ImplGetCachedDC( ULONG nID, HBITMAP hBmp )
+{
+ SalData* pSalData = GetSalData();
+ HDCCache* pC = &pSalData->mpHDCCache[ nID ];
+
+ if( !pC->mhDC )
+ {
+ HDC hDC = GetDC( 0 );
+
+ // neuen DC mit DefaultBitmap anlegen
+ pC->mhDC = CreateCompatibleDC( hDC );
+
+ if( pSalData->mhDitherPal )
+ {
+ pC->mhDefPal = SelectPalette( pC->mhDC, pSalData->mhDitherPal, TRUE );
+ RealizePalette( pC->mhDC );
+ }
+
+ pC->mhSelBmp = CreateCompatibleBitmap( hDC, CACHED_HDC_DEFEXT, CACHED_HDC_DEFEXT );
+ pC->mhDefBmp = (HBITMAP) SelectObject( pC->mhDC, pC->mhSelBmp );
+
+ ReleaseDC( 0, hDC );
+ }
+
+ if ( hBmp )
+ SelectObject( pC->mhDC, pC->mhActBmp = hBmp );
+ else
+ pC->mhActBmp = 0;
+
+ return pC->mhDC;
+}
+
+// =======================================================================
+
+void ImplReleaseCachedDC( ULONG nID )
+{
+ SalData* pSalData = GetSalData();
+ HDCCache* pC = &pSalData->mpHDCCache[ nID ];
+
+ if ( pC->mhActBmp )
+ SelectObject( pC->mhDC, pC->mhSelBmp );
+}
+
+// =======================================================================
+
+void ImplClearHDCCache( SalData* pData )
+{
+ for( ULONG i = 0; i < CACHESIZE_HDC; i++ )
+ {
+ HDCCache* pC = &pData->mpHDCCache[ i ];
+
+ if( pC->mhDC )
+ {
+ SelectObject( pC->mhDC, pC->mhDefBmp );
+
+ if( pC->mhDefPal )
+ SelectPalette( pC->mhDC, pC->mhDefPal, TRUE );
+
+ DeleteDC( pC->mhDC );
+ DeleteObject( pC->mhSelBmp );
+ }
+ }
+}
+
+// =======================================================================
+
+// #100127# Fill point and flag memory from array of points which
+// might also contain bezier control points for the PolyDraw() GDI method
+// Make sure pWinPointAry and pWinFlagAry are big enough
+void ImplPreparePolyDraw( bool bCloseFigures,
+ ULONG nPoly,
+ const ULONG* pPoints,
+ const SalPoint* const* pPtAry,
+ const BYTE* const* pFlgAry,
+ POINT* pWinPointAry,
+ BYTE* pWinFlagAry )
+{
+ ULONG nCurrPoly;
+ for( nCurrPoly=0; nCurrPoly<nPoly; ++nCurrPoly )
+ {
+ const POINT* pCurrPoint = reinterpret_cast<const POINT*>( *pPtAry++ );
+ const BYTE* pCurrFlag = *pFlgAry++;
+ const ULONG nCurrPoints = *pPoints++;
+ const bool bHaveFlagArray( pCurrFlag );
+ ULONG nCurrPoint;
+
+ if( nCurrPoints )
+ {
+ // start figure
+ *pWinPointAry++ = *pCurrPoint++;
+ *pWinFlagAry++ = PT_MOVETO;
+ ++pCurrFlag;
+
+ for( nCurrPoint=1; nCurrPoint<nCurrPoints; )
+ {
+ // #102067# Check existence of flag array
+ if( bHaveFlagArray &&
+ ( nCurrPoint + 2 ) < nCurrPoints )
+ {
+ BYTE P4( pCurrFlag[ 2 ] );
+
+ if( ( POLY_CONTROL == pCurrFlag[ 0 ] ) &&
+ ( POLY_CONTROL == pCurrFlag[ 1 ] ) &&
+ ( POLY_NORMAL == P4 || POLY_SMOOTH == P4 || POLY_SYMMTR == P4 ) )
+ {
+ // control point one
+ *pWinPointAry++ = *pCurrPoint++;
+ *pWinFlagAry++ = PT_BEZIERTO;
+
+ // control point two
+ *pWinPointAry++ = *pCurrPoint++;
+ *pWinFlagAry++ = PT_BEZIERTO;
+
+ // end point
+ *pWinPointAry++ = *pCurrPoint++;
+ *pWinFlagAry++ = PT_BEZIERTO;
+
+ nCurrPoint += 3;
+ pCurrFlag += 3;
+ continue;
+ }
+ }
+
+ // regular line point
+ *pWinPointAry++ = *pCurrPoint++;
+ *pWinFlagAry++ = PT_LINETO;
+ ++pCurrFlag;
+ ++nCurrPoint;
+ }
+
+ // end figure?
+ if( bCloseFigures )
+ pWinFlagAry[-1] |= PT_CLOSEFIGURE;
+ }
+ }
+}
+
+// =======================================================================
+
+// #100127# draw an array of points which might also contain bezier control points
+void ImplRenderPath( HDC hdc, ULONG nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry )
+{
+ if( nPoints )
+ {
+ USHORT i;
+ // TODO: profile whether the following options are faster:
+ // a) look ahead and draw consecutive bezier or line segments by PolyBezierTo/PolyLineTo resp.
+ // b) convert our flag array to window's and use PolyDraw
+
+ MoveToEx( hdc, pPtAry->mnX, pPtAry->mnY, NULL );
+ ++pPtAry; ++pFlgAry;
+
+ for( i=1; i<nPoints; ++i, ++pPtAry, ++pFlgAry )
+ {
+ if( *pFlgAry != POLY_CONTROL )
+ {
+ LineTo( hdc, pPtAry->mnX, pPtAry->mnY );
+ }
+ else if( nPoints - i > 2 )
+ {
+ PolyBezierTo( hdc, reinterpret_cast<const POINT*>(pPtAry), 3 );
+ i += 2; pPtAry += 2; pFlgAry += 2;
+ }
+ }
+ }
+}
+
+// =======================================================================
+
+WinSalGraphics::WinSalGraphics()
+{
+ for( int i = 0; i < MAX_FALLBACK; ++i )
+ {
+ mhFonts[ i ] = 0;
+ mpWinFontData[ i ] = NULL;
+ mpWinFontEntry[ i ] = NULL;
+ }
+
+ mfFontScale = 1.0;
+
+ mhDC = 0;
+ mhPen = 0;
+ mhBrush = 0;
+ mhRegion = 0;
+ mhDefPen = 0;
+ mhDefBrush = 0;
+ mhDefFont = 0;
+ mhDefPal = 0;
+ mpStdClipRgnData = NULL;
+ mpLogFont = NULL;
+ mpFontCharSets = NULL;
+ mpFontAttrCache = NULL;
+ mnFontCharSetCount = 0;
+ mpFontKernPairs = NULL;
+ mnFontKernPairCount = 0;
+ mbFontKernInit = FALSE;
+ mbXORMode = FALSE;
+ mnPenWidth = GSL_PEN_WIDTH;
+}
+
+// -----------------------------------------------------------------------
+
+WinSalGraphics::~WinSalGraphics()
+{
+ // free obsolete GDI objekts
+ ReleaseFonts();
+
+ if ( mhPen )
+ {
+ if ( !mbStockPen )
+ DeletePen( mhPen );
+ }
+ if ( mhBrush )
+ {
+ if ( !mbStockBrush )
+ DeleteBrush( mhBrush );
+ }
+
+ if ( mhRegion )
+ {
+ DeleteRegion( mhRegion );
+ mhRegion = 0;
+ }
+
+ // Cache-Daten zerstoeren
+ if ( mpStdClipRgnData )
+ delete [] mpStdClipRgnData;
+
+ if ( mpLogFont )
+ delete mpLogFont;
+
+ if ( mpFontCharSets )
+ delete mpFontCharSets;
+
+ if ( mpFontKernPairs )
+ delete mpFontKernPairs;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::GetResolution( long& rDPIX, long& rDPIY )
+{
+ rDPIX = GetDeviceCaps( mhDC, LOGPIXELSX );
+ rDPIY = GetDeviceCaps( mhDC, LOGPIXELSY );
+
+ // #111139# this fixes the symptom of div by zero on startup
+ // however, printing will fail most likely as communication with
+ // the printer seems not to work in this case
+ if( !rDPIX || !rDPIY )
+ rDPIX = rDPIY = 600;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT WinSalGraphics::GetBitCount()
+{
+ return (USHORT)GetDeviceCaps( mhDC, BITSPIXEL );
+}
+
+// -----------------------------------------------------------------------
+
+long WinSalGraphics::GetGraphicsWidth() const
+{
+ if( mhWnd && IsWindow( mhWnd ) )
+ {
+ WinSalFrame* pFrame = GetWindowPtr( mhWnd );
+ if( pFrame )
+ {
+ if( pFrame->maGeometry.nWidth )
+ return pFrame->maGeometry.nWidth;
+ else
+ {
+ // TODO: perhaps not needed, maGeometry should always be up-to-date
+ RECT aRect;
+ GetClientRect( mhWnd, &aRect );
+ return aRect.right;
+ }
+ }
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::ResetClipRegion()
+{
+ if ( mhRegion )
+ {
+ DeleteRegion( mhRegion );
+ mhRegion = 0;
+ }
+
+ SelectClipRgn( mhDC, 0 );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::BeginSetClipRegion( ULONG nRectCount )
+{
+ if ( mhRegion )
+ {
+ DeleteRegion( mhRegion );
+ mhRegion = 0;
+ }
+
+ ULONG nRectBufSize = sizeof(RECT)*nRectCount;
+ if ( nRectCount < SAL_CLIPRECT_COUNT )
+ {
+ if ( !mpStdClipRgnData )
+ mpStdClipRgnData = (RGNDATA*)new BYTE[sizeof(RGNDATA)-1+(SAL_CLIPRECT_COUNT*sizeof(RECT))];
+ mpClipRgnData = mpStdClipRgnData;
+ }
+ else
+ mpClipRgnData = (RGNDATA*)new BYTE[sizeof(RGNDATA)-1+nRectBufSize];
+ mpClipRgnData->rdh.dwSize = sizeof( RGNDATAHEADER );
+ mpClipRgnData->rdh.iType = RDH_RECTANGLES;
+ mpClipRgnData->rdh.nCount = nRectCount;
+ mpClipRgnData->rdh.nRgnSize = nRectBufSize;
+ SetRectEmpty( &(mpClipRgnData->rdh.rcBound) );
+ mpNextClipRect = (RECT*)(&(mpClipRgnData->Buffer));
+ mbFirstClipRect = TRUE;
+}
+
+
+// -----------------------------------------------------------------------
+
+BOOL WinSalGraphics::unionClipRegion( long nX, long nY, long nWidth, long nHeight )
+{
+ if ( nWidth && nHeight )
+ {
+ RECT* pRect = mpNextClipRect;
+ RECT* pBoundRect = &(mpClipRgnData->rdh.rcBound);
+ long nRight = nX + nWidth;
+ long nBottom = nY + nHeight;
+
+ if ( mbFirstClipRect )
+ {
+ pBoundRect->left = nX;
+ pBoundRect->top = nY;
+ pBoundRect->right = nRight;
+ pBoundRect->bottom = nBottom;
+ mbFirstClipRect = FALSE;
+ }
+ else
+ {
+ if ( nX < pBoundRect->left )
+ pBoundRect->left = (int)nX;
+
+ if ( nY < pBoundRect->top )
+ pBoundRect->top = (int)nY;
+
+ if ( nRight > pBoundRect->right )
+ pBoundRect->right = (int)nRight;
+
+ if ( nBottom > pBoundRect->bottom )
+ pBoundRect->bottom = (int)nBottom;
+ }
+
+ pRect->left = (int)nX;
+ pRect->top = (int)nY;
+ pRect->right = (int)nRight;
+ pRect->bottom = (int)nBottom;
+ mpNextClipRect++;
+ }
+ else
+ {
+ mpClipRgnData->rdh.nCount--;
+ mpClipRgnData->rdh.nRgnSize -= sizeof( RECT );
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+bool WinSalGraphics::unionClipRegion( const ::basegfx::B2DPolyPolygon& )
+{
+ // TODO: implement and advertise OutDevSupport_B2DClip support
+ return false;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::EndSetClipRegion()
+{
+ // create clip region from ClipRgnData
+ if ( mpClipRgnData->rdh.nCount == 1 )
+ {
+ RECT* pRect = &(mpClipRgnData->rdh.rcBound);
+ mhRegion = CreateRectRgn( pRect->left, pRect->top,
+ pRect->right, pRect->bottom );
+ }
+ else
+ {
+ ULONG nSize = mpClipRgnData->rdh.nRgnSize+sizeof(RGNDATAHEADER);
+ mhRegion = ExtCreateRegion( NULL, nSize, mpClipRgnData );
+
+ // if ExtCreateRegion(...) is not supported
+ if( !mhRegion )
+ {
+ RGNDATAHEADER* pHeader = (RGNDATAHEADER*) mpClipRgnData;
+
+ if( pHeader->nCount )
+ {
+ RECT* pRect = (RECT*) mpClipRgnData->Buffer;
+ mhRegion = CreateRectRgn( pRect->left, pRect->top, pRect->right, pRect->bottom );
+ pRect++;
+
+ for( ULONG n = 1; n < pHeader->nCount; n++, pRect++ )
+ {
+ HRGN hRgn = CreateRectRgn( pRect->left, pRect->top, pRect->right, pRect->bottom );
+ CombineRgn( mhRegion, mhRegion, hRgn, RGN_OR );
+ DeleteRegion( hRgn );
+ }
+ }
+ }
+
+ if ( mpClipRgnData != mpStdClipRgnData )
+ delete [] mpClipRgnData;
+ }
+
+ SelectClipRgn( mhDC, mhRegion );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::SetLineColor()
+{
+ // create and select new pen
+ HPEN hNewPen = GetStockPen( NULL_PEN );
+ HPEN hOldPen = SelectPen( mhDC, hNewPen );
+
+ // destory or save old pen
+ if ( mhPen )
+ {
+ if ( !mbStockPen )
+ DeletePen( mhPen );
+ }
+ else
+ mhDefPen = hOldPen;
+
+ // set new data
+ mhPen = hNewPen;
+ mbPen = FALSE;
+ mbStockPen = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::SetLineColor( SalColor nSalColor )
+{
+ maLineColor = nSalColor;
+ COLORREF nPenColor = PALETTERGB( SALCOLOR_RED( nSalColor ),
+ SALCOLOR_GREEN( nSalColor ),
+ SALCOLOR_BLUE( nSalColor ) );
+ HPEN hNewPen = 0;
+ BOOL bStockPen = FALSE;
+
+ // search for stock pen (only screen, because printer have problems,
+ // when we use stock objects)
+ if ( !mbPrinter )
+ {
+ SalData* pSalData = GetSalData();
+ for ( USHORT i = 0; i < pSalData->mnStockPenCount; i++ )
+ {
+ if ( nPenColor == pSalData->maStockPenColorAry[i] )
+ {
+ hNewPen = pSalData->mhStockPenAry[i];
+ bStockPen = TRUE;
+ break;
+ }
+ }
+ }
+
+ // create new pen
+ if ( !hNewPen )
+ {
+ if ( !mbPrinter )
+ {
+ if ( GetSalData()->mhDitherPal && ImplIsSysColorEntry( nSalColor ) )
+ nPenColor = PALRGB_TO_RGB( nPenColor );
+ }
+
+ hNewPen = CreatePen( PS_SOLID, mnPenWidth, nPenColor );
+ bStockPen = FALSE;
+ }
+
+ // select new pen
+ HPEN hOldPen = SelectPen( mhDC, hNewPen );
+
+ // destory or save old pen
+ if ( mhPen )
+ {
+ if ( !mbStockPen )
+ DeletePen( mhPen );
+ }
+ else
+ mhDefPen = hOldPen;
+
+ // set new data
+ mnPenColor = nPenColor;
+ mhPen = hNewPen;
+ mbPen = TRUE;
+ mbStockPen = bStockPen;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::SetFillColor()
+{
+ // create and select new brush
+ HBRUSH hNewBrush = GetStockBrush( NULL_BRUSH );
+ HBRUSH hOldBrush = SelectBrush( mhDC, hNewBrush );
+
+ // destory or save old brush
+ if ( mhBrush )
+ {
+ if ( !mbStockBrush )
+ DeleteBrush( mhBrush );
+ }
+ else
+ mhDefBrush = hOldBrush;
+
+ // set new data
+ mhBrush = hNewBrush;
+ mbBrush = FALSE;
+ mbStockBrush = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::SetFillColor( SalColor nSalColor )
+{
+ maFillColor = nSalColor;
+ SalData* pSalData = GetSalData();
+ BYTE nRed = SALCOLOR_RED( nSalColor );
+ BYTE nGreen = SALCOLOR_GREEN( nSalColor );
+ BYTE nBlue = SALCOLOR_BLUE( nSalColor );
+ COLORREF nBrushColor = PALETTERGB( nRed, nGreen, nBlue );
+ HBRUSH hNewBrush = 0;
+ BOOL bStockBrush = FALSE;
+
+ // search for stock brush (only screen, because printer have problems,
+ // when we use stock objects)
+ if ( !mbPrinter )
+ {
+ for ( USHORT i = 0; i < pSalData->mnStockBrushCount; i++ )
+ {
+ if ( nBrushColor == pSalData->maStockBrushColorAry[ i ] )
+ {
+ hNewBrush = pSalData->mhStockBrushAry[i];
+ bStockBrush = TRUE;
+ break;
+ }
+ }
+ }
+
+ // create new brush
+ if ( !hNewBrush )
+ {
+ if ( mbPrinter || !pSalData->mhDitherDIB )
+ hNewBrush = CreateSolidBrush( nBrushColor );
+ else
+ {
+ if ( 24 == ((BITMAPINFOHEADER*)pSalData->mpDitherDIB)->biBitCount )
+ {
+ BYTE* pTmp = pSalData->mpDitherDIBData;
+ long* pDitherDiff = pSalData->mpDitherDiff;
+ BYTE* pDitherLow = pSalData->mpDitherLow;
+ BYTE* pDitherHigh = pSalData->mpDitherHigh;
+
+ for( long nY = 0L; nY < 8L; nY++ )
+ {
+ for( long nX = 0L; nX < 8L; nX++ )
+ {
+ const long nThres = aOrdDither16Bit[ nY ][ nX ];
+ *pTmp++ = DMAP( nBlue, nThres );
+ *pTmp++ = DMAP( nGreen, nThres );
+ *pTmp++ = DMAP( nRed, nThres );
+ }
+ }
+
+ hNewBrush = CreateDIBPatternBrush( pSalData->mhDitherDIB, DIB_RGB_COLORS );
+ }
+ else if ( ImplIsSysColorEntry( nSalColor ) )
+ {
+ nBrushColor = PALRGB_TO_RGB( nBrushColor );
+ hNewBrush = CreateSolidBrush( nBrushColor );
+ }
+ else if ( ImplIsPaletteEntry( nRed, nGreen, nBlue ) )
+ hNewBrush = CreateSolidBrush( nBrushColor );
+ else
+ {
+ BYTE* pTmp = pSalData->mpDitherDIBData;
+ long* pDitherDiff = pSalData->mpDitherDiff;
+ BYTE* pDitherLow = pSalData->mpDitherLow;
+ BYTE* pDitherHigh = pSalData->mpDitherHigh;
+
+ for ( long nY = 0L; nY < 8L; nY++ )
+ {
+ for ( long nX = 0L; nX < 8L; nX++ )
+ {
+ const long nThres = aOrdDither8Bit[ nY ][ nX ];
+ *pTmp = DMAP( nRed, nThres ) + DMAP( nGreen, nThres ) * 6 + DMAP( nBlue, nThres ) * 36;
+ pTmp++;
+ }
+ }
+
+ hNewBrush = CreateDIBPatternBrush( pSalData->mhDitherDIB, DIB_PAL_COLORS );
+ }
+ }
+
+ bStockBrush = FALSE;
+ }
+
+ // select new brush
+ HBRUSH hOldBrush = SelectBrush( mhDC, hNewBrush );
+
+ // destory or save old brush
+ if ( mhBrush )
+ {
+ if ( !mbStockBrush )
+ DeleteBrush( mhBrush );
+ }
+ else
+ mhDefBrush = hOldBrush;
+
+ // set new data
+ mnBrushColor = nBrushColor;
+ mhBrush = hNewBrush;
+ mbBrush = TRUE;
+ mbStockBrush = bStockBrush;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::SetXORMode( bool bSet, bool )
+{
+ mbXORMode = bSet;
+ ::SetROP2( mhDC, bSet ? R2_XORPEN : R2_COPYPEN );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::SetROPLineColor( SalROPColor nROPColor )
+{
+ SetLineColor( ImplGetROPSalColor( nROPColor ) );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::SetROPFillColor( SalROPColor nROPColor )
+{
+ SetFillColor( ImplGetROPSalColor( nROPColor ) );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::drawPixel( long nX, long nY )
+{
+ if ( mbXORMode )
+ {
+ HBRUSH hBrush = CreateSolidBrush( mnPenColor );
+ HBRUSH hOldBrush = SelectBrush( mhDC, hBrush );
+ PatBlt( mhDC, (int)nX, (int)nY, (int)1, (int)1, PATINVERT );
+ SelectBrush( mhDC, hOldBrush );
+ DeleteBrush( hBrush );
+ }
+ else
+ SetPixel( mhDC, (int)nX, (int)nY, mnPenColor );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::drawPixel( long nX, long nY, SalColor nSalColor )
+{
+ COLORREF nCol = PALETTERGB( SALCOLOR_RED( nSalColor ),
+ SALCOLOR_GREEN( nSalColor ),
+ SALCOLOR_BLUE( nSalColor ) );
+
+ if ( !mbPrinter &&
+ GetSalData()->mhDitherPal &&
+ ImplIsSysColorEntry( nSalColor ) )
+ nCol = PALRGB_TO_RGB( nCol );
+
+ if ( mbXORMode )
+ {
+ HBRUSH hBrush = CreateSolidBrush( nCol );
+ HBRUSH hOldBrush = SelectBrush( mhDC, hBrush );
+ PatBlt( mhDC, (int)nX, (int)nY, (int)1, (int)1, PATINVERT );
+ SelectBrush( mhDC, hOldBrush );
+ DeleteBrush( hBrush );
+ }
+ else
+ ::SetPixel( mhDC, (int)nX, (int)nY, nCol );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 )
+{
+ MoveToEx( mhDC, (int)nX1, (int)nY1, NULL );
+
+ // we must paint the endpoint
+ int bPaintEnd = TRUE;
+ if ( nX1 == nX2 )
+ {
+ bPaintEnd = FALSE;
+ if ( nY1 <= nY2 )
+ nY2++;
+ else
+ nY2--;
+ }
+ if ( nY1 == nY2 )
+ {
+ bPaintEnd = FALSE;
+ if ( nX1 <= nX2 )
+ nX2++;
+ else
+ nX2--;
+ }
+
+ LineTo( mhDC, (int)nX2, (int)nY2 );
+
+ if ( bPaintEnd && !mbPrinter )
+ {
+ if ( mbXORMode )
+ {
+ HBRUSH hBrush = CreateSolidBrush( mnPenColor );
+ HBRUSH hOldBrush = SelectBrush( mhDC, hBrush );
+ PatBlt( mhDC, (int)nX2, (int)nY2, (int)1, (int)1, PATINVERT );
+ SelectBrush( mhDC, hOldBrush );
+ DeleteBrush( hBrush );
+ }
+ else
+ SetPixel( mhDC, (int)nX2, (int)nY2, mnPenColor );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::drawRect( long nX, long nY, long nWidth, long nHeight )
+{
+ if ( !mbPen )
+ {
+ if ( !mbPrinter )
+ {
+ PatBlt( mhDC, (int)nX, (int)nY, (int)nWidth, (int)nHeight,
+ mbXORMode ? PATINVERT : PATCOPY );
+ }
+ else
+ {
+ RECT aWinRect;
+ aWinRect.left = nX;
+ aWinRect.top = nY;
+ aWinRect.right = nX+nWidth;
+ aWinRect.bottom = nY+nHeight;
+ ::FillRect( mhDC, &aWinRect, mhBrush );
+ }
+ }
+ else
+ WIN_Rectangle( mhDC, (int)nX, (int)nY, (int)(nX+nWidth), (int)(nY+nHeight) );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::drawPolyLine( ULONG nPoints, const SalPoint* pPtAry )
+{
+ // Unter NT koennen wir das Array direkt weiterreichen
+ DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
+ "WinSalGraphics::DrawPolyLine(): POINT != SalPoint" );
+
+ POINT* pWinPtAry = (POINT*)pPtAry;
+ // Wegen Windows 95 und der Beschraenkung auf eine maximale Anzahl
+ // von Punkten
+ if ( !Polyline( mhDC, pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) )
+ Polyline( mhDC, pWinPtAry, MAX_64KSALPOINTS );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::drawPolygon( ULONG nPoints, const SalPoint* pPtAry )
+{
+ // Unter NT koennen wir das Array direkt weiterreichen
+ DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
+ "WinSalGraphics::DrawPolygon(): POINT != SalPoint" );
+
+ POINT* pWinPtAry = (POINT*)pPtAry;
+ // Wegen Windows 95 und der Beschraenkung auf eine maximale Anzahl
+ // von Punkten
+ if ( !WIN_Polygon( mhDC, pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) )
+ WIN_Polygon( mhDC, pWinPtAry, MAX_64KSALPOINTS );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints,
+ PCONSTSALPOINT* pPtAry )
+{
+ UINT aWinPointAry[SAL_POLYPOLYCOUNT_STACKBUF];
+ UINT* pWinPointAry;
+ UINT nPolyPolyPoints = 0;
+ UINT nPoints;
+ UINT i;
+
+ if ( nPoly <= SAL_POLYPOLYCOUNT_STACKBUF )
+ pWinPointAry = aWinPointAry;
+ else
+ pWinPointAry = new UINT[nPoly];
+
+ for ( i = 0; i < (UINT)nPoly; i++ )
+ {
+ nPoints = (UINT)pPoints[i]+1;
+ pWinPointAry[i] = nPoints;
+ nPolyPolyPoints += nPoints;
+ }
+
+ POINT aWinPointAryAry[SAL_POLYPOLYPOINTS_STACKBUF];
+ POINT* pWinPointAryAry;
+ if ( nPolyPolyPoints <= SAL_POLYPOLYPOINTS_STACKBUF )
+ pWinPointAryAry = aWinPointAryAry;
+ else
+ pWinPointAryAry = new POINT[nPolyPolyPoints];
+ // Unter NT koennen wir das Array direkt weiterreichen
+ DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
+ "WinSalGraphics::DrawPolyPolygon(): POINT != SalPoint" );
+ const SalPoint* pPolyAry;
+ UINT n = 0;
+ for ( i = 0; i < (UINT)nPoly; i++ )
+ {
+ nPoints = pWinPointAry[i];
+ pPolyAry = pPtAry[i];
+ memcpy( pWinPointAryAry+n, pPolyAry, (nPoints-1)*sizeof(POINT) );
+ pWinPointAryAry[n+nPoints-1] = pWinPointAryAry[n];
+ n += nPoints;
+ }
+
+ if ( !WIN_PolyPolygon( mhDC, pWinPointAryAry, (int*)pWinPointAry, (UINT)nPoly ) &&
+ (nPolyPolyPoints > MAX_64KSALPOINTS) )
+ {
+ nPolyPolyPoints = 0;
+ nPoly = 0;
+ do
+ {
+ nPolyPolyPoints += pWinPointAry[(UINT)nPoly];
+ nPoly++;
+ }
+ while ( nPolyPolyPoints < MAX_64KSALPOINTS );
+ nPoly--;
+ if ( pWinPointAry[(UINT)nPoly] > MAX_64KSALPOINTS )
+ pWinPointAry[(UINT)nPoly] = MAX_64KSALPOINTS;
+ if ( nPoly == 1 )
+ WIN_Polygon( mhDC, pWinPointAryAry, *pWinPointAry );
+ else
+ WIN_PolyPolygon( mhDC, pWinPointAryAry, (int*)pWinPointAry, nPoly );
+ }
+
+ if ( pWinPointAry != aWinPointAry )
+ delete [] pWinPointAry;
+ if ( pWinPointAryAry != aWinPointAryAry )
+ delete [] pWinPointAryAry;
+}
+
+// -----------------------------------------------------------------------
+
+#define SAL_POLY_STACKBUF 32
+
+// -----------------------------------------------------------------------
+
+sal_Bool WinSalGraphics::drawPolyLineBezier( ULONG nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry )
+{
+#ifdef USE_GDI_BEZIERS
+ // Unter NT koennen wir das Array direkt weiterreichen
+ DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
+ "WinSalGraphics::DrawPolyLineBezier(): POINT != SalPoint" );
+
+ ImplRenderPath( mhDC, nPoints, pPtAry, pFlgAry );
+
+ return sal_True;
+#else
+ return sal_False;
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool WinSalGraphics::drawPolygonBezier( ULONG nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry )
+{
+#ifdef USE_GDI_BEZIERS
+ // Unter NT koennen wir das Array direkt weiterreichen
+ DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
+ "WinSalGraphics::DrawPolygonBezier(): POINT != SalPoint" );
+
+ POINT aStackAry1[SAL_POLY_STACKBUF];
+ BYTE aStackAry2[SAL_POLY_STACKBUF];
+ POINT* pWinPointAry;
+ BYTE* pWinFlagAry;
+ if( nPoints > SAL_POLY_STACKBUF )
+ {
+ pWinPointAry = new POINT[ nPoints ];
+ pWinFlagAry = new BYTE[ nPoints ];
+ }
+ else
+ {
+ pWinPointAry = aStackAry1;
+ pWinFlagAry = aStackAry2;
+ }
+
+ ImplPreparePolyDraw(true, 1, &nPoints, &pPtAry, &pFlgAry, pWinPointAry, pWinFlagAry);
+
+ sal_Bool bRet( sal_False );
+
+ if( BeginPath( mhDC ) )
+ {
+ PolyDraw(mhDC, pWinPointAry, pWinFlagAry, nPoints);
+
+ if( EndPath( mhDC ) )
+ {
+ if( StrokeAndFillPath( mhDC ) )
+ bRet = sal_True;
+ }
+ }
+
+ if( pWinPointAry != aStackAry1 )
+ {
+ delete [] pWinPointAry;
+ delete [] pWinFlagAry;
+ }
+
+ return bRet;
+#else
+ return sal_False;
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool WinSalGraphics::drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* pPoints,
+ const SalPoint* const* pPtAry, const BYTE* const* pFlgAry )
+{
+#ifdef USE_GDI_BEZIERS
+ // Unter NT koennen wir das Array direkt weiterreichen
+ DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
+ "WinSalGraphics::DrawPolyPolygonBezier(): POINT != SalPoint" );
+
+ ULONG nCurrPoly, nTotalPoints;
+ const ULONG* pCurrPoints = pPoints;
+ for( nCurrPoly=0, nTotalPoints=0; nCurrPoly<nPoly; ++nCurrPoly )
+ nTotalPoints += *pCurrPoints++;
+
+ POINT aStackAry1[SAL_POLY_STACKBUF];
+ BYTE aStackAry2[SAL_POLY_STACKBUF];
+ POINT* pWinPointAry;
+ BYTE* pWinFlagAry;
+ if( nTotalPoints > SAL_POLY_STACKBUF )
+ {
+ pWinPointAry = new POINT[ nTotalPoints ];
+ pWinFlagAry = new BYTE[ nTotalPoints ];
+ }
+ else
+ {
+ pWinPointAry = aStackAry1;
+ pWinFlagAry = aStackAry2;
+ }
+
+ ImplPreparePolyDraw(true, nPoly, pPoints, pPtAry, pFlgAry, pWinPointAry, pWinFlagAry);
+
+ sal_Bool bRet( sal_False );
+
+ if( BeginPath( mhDC ) )
+ {
+ PolyDraw(mhDC, pWinPointAry, pWinFlagAry, nTotalPoints);
+
+ if( EndPath( mhDC ) )
+ {
+ if( StrokeAndFillPath( mhDC ) )
+ bRet = sal_True;
+ }
+ }
+
+ if( pWinPointAry != aStackAry1 )
+ {
+ delete [] pWinPointAry;
+ delete [] pWinFlagAry;
+ }
+
+ return bRet;
+#else
+ return sal_False;
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+#define POSTSCRIPT_BUFSIZE 0x4000 // MAXIMUM BUFSIZE EQ 0xFFFF
+#define POSTSCRIPT_BOUNDINGSEARCH 0x1000 // we only try to get the BoundingBox
+ // in the first 4096 bytes
+
+static BYTE* ImplSearchEntry( BYTE* pSource, BYTE* pDest, ULONG nComp, ULONG nSize )
+{
+ while ( nComp-- >= nSize )
+ {
+ ULONG i;
+ for ( i = 0; i < nSize; i++ )
+ {
+ if ( ( pSource[i]&~0x20 ) != ( pDest[i]&~0x20 ) )
+ break;
+ }
+ if ( i == nSize )
+ return pSource;
+ pSource++;
+ }
+ return NULL;
+}
+
+static BOOL ImplGetBoundingBox( double* nNumb, BYTE* pSource, ULONG nSize )
+{
+ BOOL bRetValue = FALSE;
+ BYTE* pDest = ImplSearchEntry( pSource, (BYTE*)"%%BoundingBox:", nSize, 14 );
+ if ( pDest )
+ {
+ nNumb[0] = nNumb[1] = nNumb[2] = nNumb[3] = 0;
+ pDest += 14;
+
+ int nSizeLeft = nSize - ( pDest - pSource );
+ if ( nSizeLeft > 100 )
+ nSizeLeft = 100; // only 100 bytes following the bounding box will be checked
+
+ int i;
+ for ( i = 0; ( i < 4 ) && nSizeLeft; i++ )
+ {
+ int nDivision = 1;
+ BOOL bDivision = FALSE;
+ BOOL bNegative = FALSE;
+ BOOL bValid = TRUE;
+
+ while ( ( --nSizeLeft ) && ( *pDest == ' ' ) || ( *pDest == 0x9 ) ) pDest++;
+ BYTE nByte = *pDest;
+ while ( nSizeLeft && ( nByte != ' ' ) && ( nByte != 0x9 ) && ( nByte != 0xd ) && ( nByte != 0xa ) )
+ {
+ switch ( nByte )
+ {
+ case '.' :
+ if ( bDivision )
+ bValid = FALSE;
+ else
+ bDivision = TRUE;
+ break;
+ case '-' :
+ bNegative = TRUE;
+ break;
+ default :
+ if ( ( nByte < '0' ) || ( nByte > '9' ) )
+ nSizeLeft = 1; // error parsing the bounding box values
+ else if ( bValid )
+ {
+ if ( bDivision )
+ nDivision*=10;
+ nNumb[i] *= 10;
+ nNumb[i] += nByte - '0';
+ }
+ break;
+ }
+ nSizeLeft--;
+ nByte = *(++pDest);
+ }
+ if ( bNegative )
+ nNumb[i] = -nNumb[i];
+ if ( bDivision && ( nDivision != 1 ) )
+ nNumb[i] /= nDivision;
+ }
+ if ( i == 4 )
+ bRetValue = TRUE;
+ }
+ return bRetValue;
+}
+
+BOOL WinSalGraphics::drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, ULONG nSize )
+{
+ BOOL bRetValue = FALSE;
+
+ if ( mbPrinter )
+ {
+ int nEscape = POSTSCRIPT_PASSTHROUGH;
+
+ if ( Escape( mhDC, QUERYESCSUPPORT, sizeof( int ), ( LPSTR )&nEscape, 0 ) )
+ {
+ double nBoundingBox[4];
+
+ if ( ImplGetBoundingBox( nBoundingBox, (BYTE*)pPtr, nSize ) )
+ {
+ OStringBuffer aBuf( POSTSCRIPT_BUFSIZE );
+
+ // reserve place for a USHORT
+ aBuf.append( "aa" );
+
+ // #107797# Write out EPS encapsulation header
+ // ----------------------------------------------------------------------------------
+
+ // directly taken from the PLRM 3.0, p. 726. Note:
+ // this will definitely cause problems when
+ // recursively creating and embedding PostScript files
+ // in OOo, since we use statically-named variables
+ // here (namely, b4_Inc_state_salWin, dict_count_salWin and
+ // op_count_salWin). Currently, I have no idea on how to
+ // work around that, except from scanning and
+ // interpreting the EPS for unused identifiers.
+
+ // append the real text
+ aBuf.append( "\n\n/b4_Inc_state_salWin save def\n"
+ "/dict_count_salWin countdictstack def\n"
+ "/op_count_salWin count 1 sub def\n"
+ "userdict begin\n"
+ "/showpage {} def\n"
+ "0 setgray 0 setlinecap\n"
+ "1 setlinewidth 0 setlinejoin\n"
+ "10 setmiterlimit [] 0 setdash newpath\n"
+ "/languagelevel where\n"
+ "{\n"
+ " pop languagelevel\n"
+ " 1 ne\n"
+ " {\n"
+ " false setstrokeadjust false setoverprint\n"
+ " } if\n"
+ "} if\n\n" );
+
+
+ // #i10737# Apply clipping manually
+ // ----------------------------------------------------------------------------------
+
+ // Windows seems to ignore any clipping at the HDC,
+ // when followed by a POSTSCRIPT_PASSTHROUGH
+
+ // Check whether we've got a clipping, consisting of
+ // exactly one rect (other cases should be, but aren't
+ // handled currently)
+
+ // TODO: Handle more than one rectangle here (take
+ // care, the buffer can handle only POSTSCRIPT_BUFSIZE
+ // characters!)
+ if ( mhRegion != 0 &&
+ mpStdClipRgnData != NULL &&
+ mpClipRgnData == mpStdClipRgnData &&
+ mpClipRgnData->rdh.nCount == 1 )
+ {
+ RECT* pRect = &(mpClipRgnData->rdh.rcBound);
+
+ aBuf.append( "\nnewpath\n" );
+ aBuf.append( pRect->left );
+ aBuf.append( " " );
+ aBuf.append( pRect->top );
+ aBuf.append( " moveto\n" );
+ aBuf.append( pRect->right );
+ aBuf.append( " " );
+ aBuf.append( pRect->top );
+ aBuf.append( " lineto\n" );
+ aBuf.append( pRect->right );
+ aBuf.append( " " );
+ aBuf.append( pRect->bottom );
+ aBuf.append( " lineto\n" );
+ aBuf.append( pRect->left );
+ aBuf.append( " " );
+ aBuf.append( pRect->bottom );
+ aBuf.append( " lineto\n"
+ "closepath\n"
+ "clip\n"
+ "newpath\n" );
+ }
+
+ // #107797# Write out buffer
+ // ----------------------------------------------------------------------------------
+ *((USHORT*)aBuf.getStr()) = (USHORT)( aBuf.getLength() - 2 );
+ Escape ( mhDC, nEscape, aBuf.getLength(), (LPTSTR)aBuf.getStr(), 0 );
+
+
+ // #107797# Write out EPS transformation code
+ // ----------------------------------------------------------------------------------
+ double dM11 = nWidth / ( nBoundingBox[2] - nBoundingBox[0] );
+ double dM22 = nHeight / (nBoundingBox[1] - nBoundingBox[3] );
+ // reserve a USHORT again
+ aBuf.setLength( 2 );
+ aBuf.append( "\n\n[" );
+ aBuf.append( dM11 );
+ aBuf.append( " 0 0 " );
+ aBuf.append( dM22 );
+ aBuf.append( ' ' );
+ aBuf.append( nX - ( dM11 * nBoundingBox[0] ) );
+ aBuf.append( ' ' );
+ aBuf.append( nY - ( dM22 * nBoundingBox[3] ) );
+ aBuf.append( "] concat\n"
+ "%%BeginDocument:\n" );
+ *((USHORT*)aBuf.getStr()) = (USHORT)( aBuf.getLength() - 2 );
+ Escape ( mhDC, nEscape, aBuf.getLength(), (LPTSTR)aBuf.getStr(), 0 );
+
+
+ // #107797# Write out actual EPS content
+ // ----------------------------------------------------------------------------------
+ ULONG nToDo = nSize;
+ ULONG nDoNow;
+ while ( nToDo )
+ {
+ nDoNow = nToDo;
+ if ( nToDo > POSTSCRIPT_BUFSIZE - 2 )
+ nDoNow = POSTSCRIPT_BUFSIZE - 2;
+ // the following is based on the string buffer allocation
+ // of size POSTSCRIPT_BUFSIZE at construction time of aBuf
+ *((USHORT*)aBuf.getStr()) = (USHORT)nDoNow;
+ memcpy( (void*)(aBuf.getStr() + 2), (BYTE*)pPtr + nSize - nToDo, nDoNow );
+ ULONG nResult = Escape ( mhDC, nEscape, nDoNow + 2, (LPTSTR)aBuf.getStr(), 0 );
+ if (!nResult )
+ break;
+ nToDo -= nResult;
+ }
+
+
+ // #107797# Write out EPS encapsulation footer
+ // ----------------------------------------------------------------------------------
+ // reserve a USHORT again
+ aBuf.setLength( 2 );
+ aBuf.append( "%%EndDocument\n"
+ "count op_count_salWin sub {pop} repeat\n"
+ "countdictstack dict_count_salWin sub {end} repeat\n"
+ "b4_Inc_state_salWin restore\n\n" );
+ *((USHORT*)aBuf.getStr()) = (USHORT)( aBuf.getLength() - 2 );
+ Escape ( mhDC, nEscape, aBuf.getLength(), (LPTSTR)aBuf.getStr(), 0 );
+ bRetValue = TRUE;
+ }
+ }
+ }
+
+ return bRetValue;
+}
+
+// -----------------------------------------------------------------------
+
+SystemGraphicsData WinSalGraphics::GetGraphicsData() const
+{
+ SystemGraphicsData aRes;
+ aRes.nSize = sizeof(aRes);
+ aRes.hDC = mhDC;
+ return aRes;
+}
+
+// -----------------------------------------------------------------------
diff --git a/vcl/win/source/gdi/salgdi2.cxx b/vcl/win/source/gdi/salgdi2.cxx
new file mode 100644
index 000000000000..803c0886f429
--- /dev/null
+++ b/vcl/win/source/gdi/salgdi2.cxx
@@ -0,0 +1,821 @@
+/*************************************************************************
+ *
+ * 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 <stdlib.h>
+#include <tools/svwin.h>
+#include <tools/debug.hxx>
+#include <wincomp.hxx>
+#include <salbmp.h>
+#include <saldata.hxx>
+#ifndef _SV_SALIDS_HRC
+#include <salids.hrc>
+#endif
+#include <salgdi.h>
+#include <salframe.h>
+
+bool WinSalGraphics::supportsOperation( OutDevSupportType eType ) const
+{
+ static bool bAllowForTest(true);
+ bool bRet = false;
+
+ switch( eType )
+ {
+ case OutDevSupport_TransparentRect:
+ bRet = mbVirDev || mbWindow;
+ break;
+ case OutDevSupport_B2DDraw:
+ bRet = bAllowForTest;
+ default: break;
+ }
+ return bRet;
+}
+
+// =======================================================================
+
+void WinSalGraphics::copyBits( const SalTwoRect* pPosAry, SalGraphics* pSrcGraphics )
+{
+ HDC hSrcDC;
+ DWORD nRop;
+
+ if ( pSrcGraphics )
+ hSrcDC = static_cast<WinSalGraphics*>(pSrcGraphics)->mhDC;
+ else
+ hSrcDC = mhDC;
+
+ if ( mbXORMode )
+ nRop = SRCINVERT;
+ else
+ nRop = SRCCOPY;
+
+ if ( (pPosAry->mnSrcWidth == pPosAry->mnDestWidth) &&
+ (pPosAry->mnSrcHeight == pPosAry->mnDestHeight) )
+ {
+ BitBlt( mhDC,
+ (int)pPosAry->mnDestX, (int)pPosAry->mnDestY,
+ (int)pPosAry->mnDestWidth, (int)pPosAry->mnDestHeight,
+ hSrcDC,
+ (int)pPosAry->mnSrcX, (int)pPosAry->mnSrcY,
+ nRop );
+ }
+ else
+ {
+ int nOldStretchMode = SetStretchBltMode( mhDC, STRETCH_DELETESCANS );
+ StretchBlt( mhDC,
+ (int)pPosAry->mnDestX, (int)pPosAry->mnDestY,
+ (int)pPosAry->mnDestWidth, (int)pPosAry->mnDestHeight,
+ hSrcDC,
+ (int)pPosAry->mnSrcX, (int)pPosAry->mnSrcY,
+ (int)pPosAry->mnSrcWidth, (int)pPosAry->mnSrcHeight,
+ nRop );
+ SetStretchBltMode( mhDC, nOldStretchMode );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplCalcOutSideRgn( const RECT& rSrcRect,
+ int nLeft, int nTop, int nRight, int nBottom,
+ HRGN& rhInvalidateRgn )
+{
+ HRGN hTempRgn;
+
+ // Bereiche ausserhalb des sichtbaren Bereiches berechnen
+ if ( rSrcRect.left < nLeft )
+ {
+ if ( !rhInvalidateRgn )
+ rhInvalidateRgn = CreateRectRgnIndirect( &rSrcRect );
+ hTempRgn = CreateRectRgn( -31999, 0, nLeft, 31999 );
+ CombineRgn( rhInvalidateRgn, rhInvalidateRgn, hTempRgn, RGN_DIFF );
+ DeleteRegion( hTempRgn );
+ }
+ if ( rSrcRect.top < nTop )
+ {
+ if ( !rhInvalidateRgn )
+ rhInvalidateRgn = CreateRectRgnIndirect( &rSrcRect );
+ hTempRgn = CreateRectRgn( 0, -31999, 31999, nTop );
+ CombineRgn( rhInvalidateRgn, rhInvalidateRgn, hTempRgn, RGN_DIFF );
+ DeleteRegion( hTempRgn );
+ }
+ if ( rSrcRect.right > nRight )
+ {
+ if ( !rhInvalidateRgn )
+ rhInvalidateRgn = CreateRectRgnIndirect( &rSrcRect );
+ hTempRgn = CreateRectRgn( nRight, 0, 31999, 31999 );
+ CombineRgn( rhInvalidateRgn, rhInvalidateRgn, hTempRgn, RGN_DIFF );
+ DeleteRegion( hTempRgn );
+ }
+ if ( rSrcRect.bottom > nBottom )
+ {
+ if ( !rhInvalidateRgn )
+ rhInvalidateRgn = CreateRectRgnIndirect( &rSrcRect );
+ hTempRgn = CreateRectRgn( 0, nBottom, 31999, 31999 );
+ CombineRgn( rhInvalidateRgn, rhInvalidateRgn, hTempRgn, RGN_DIFF );
+ DeleteRegion( hTempRgn );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::copyArea( long nDestX, long nDestY,
+ long nSrcX, long nSrcY,
+ long nSrcWidth, long nSrcHeight,
+ USHORT nFlags )
+{
+ bool bRestoreClipRgn = false;
+ HRGN hOldClipRgn = 0;
+ int nOldClipRgnType = ERROR;
+ HRGN hInvalidateRgn = 0;
+
+ // Muessen die ueberlappenden Bereiche auch invalidiert werden?
+ if ( (nFlags & SAL_COPYAREA_WINDOWINVALIDATE) && mbWindow )
+ {
+ // compute and invalidate those parts that were either off-screen or covered by other windows
+ // while performing the above BitBlt
+ // those regions then have to be invalidated as they contain useless/wrong data
+ RECT aSrcRect;
+ RECT aClipRect;
+ RECT aTempRect;
+ RECT aTempRect2;
+ HRGN hTempRgn;
+ HWND hWnd;
+ int nRgnType;
+
+ // restrict srcRect to this window (calc intersection)
+ aSrcRect.left = (int)nSrcX;
+ aSrcRect.top = (int)nSrcY;
+ aSrcRect.right = aSrcRect.left+(int)nSrcWidth;
+ aSrcRect.bottom = aSrcRect.top+(int)nSrcHeight;
+ GetClientRect( mhWnd, &aClipRect );
+ if ( IntersectRect( &aSrcRect, &aSrcRect, &aClipRect ) )
+ {
+ // transform srcRect to screen coordinates
+ POINT aPt;
+ aPt.x = 0;
+ aPt.y = 0;
+ ClientToScreen( mhWnd, &aPt );
+ aSrcRect.left += aPt.x;
+ aSrcRect.top += aPt.y;
+ aSrcRect.right += aPt.x;
+ aSrcRect.bottom += aPt.y;
+ hInvalidateRgn = 0;
+
+ // compute the parts that are off screen (ie invisible)
+ RECT theScreen;
+ ImplSalGetWorkArea( NULL, &theScreen, NULL ); // find the screen area taking multiple monitors into account
+ ImplCalcOutSideRgn( aSrcRect, theScreen.left, theScreen.top, theScreen.right, theScreen.bottom, hInvalidateRgn );
+
+ // Bereiche die von anderen Fenstern ueberlagert werden berechnen
+ HRGN hTempRgn2 = 0;
+ HWND hWndTopWindow = mhWnd;
+ // Find the TopLevel Window, because only Windows which are in
+ // in the foreground of our TopLevel window must be considered
+ if ( GetWindowStyle( hWndTopWindow ) & WS_CHILD )
+ {
+ RECT aTempRect3 = aSrcRect;
+ do
+ {
+ hWndTopWindow = ::GetParent( hWndTopWindow );
+
+ // Test, if the Parent clips our window
+ GetClientRect( hWndTopWindow, &aTempRect );
+ POINT aPt2;
+ aPt2.x = 0;
+ aPt2.y = 0;
+ ClientToScreen( hWndTopWindow, &aPt2 );
+ aTempRect.left += aPt2.x;
+ aTempRect.top += aPt2.y;
+ aTempRect.right += aPt2.x;
+ aTempRect.bottom += aPt2.y;
+ IntersectRect( &aTempRect3, &aTempRect3, &aTempRect );
+ }
+ while ( GetWindowStyle( hWndTopWindow ) & WS_CHILD );
+
+ // If one or more Parents clip our window, than we must
+ // calculate the outside area
+ if ( !EqualRect( &aSrcRect, &aTempRect3 ) )
+ {
+ ImplCalcOutSideRgn( aSrcRect,
+ aTempRect3.left, aTempRect3.top,
+ aTempRect3.right, aTempRect3.bottom,
+ hInvalidateRgn );
+ }
+ }
+ // retrieve the top-most (z-order) child window
+ hWnd = GetWindow( GetDesktopWindow(), GW_CHILD );
+ while ( hWnd )
+ {
+ if ( hWnd == hWndTopWindow )
+ break;
+ if ( IsWindowVisible( hWnd ) && !IsIconic( hWnd ) )
+ {
+ GetWindowRect( hWnd, &aTempRect );
+ if ( IntersectRect( &aTempRect2, &aSrcRect, &aTempRect ) )
+ {
+ // hWnd covers part or all of aSrcRect
+ if ( !hInvalidateRgn )
+ hInvalidateRgn = CreateRectRgnIndirect( &aSrcRect );
+
+ // get full bounding box of hWnd
+ hTempRgn = CreateRectRgnIndirect( &aTempRect );
+
+ // get region of hWnd (the window may be shaped)
+ if ( !hTempRgn2 )
+ hTempRgn2 = CreateRectRgn( 0, 0, 0, 0 );
+ nRgnType = GetWindowRgn( hWnd, hTempRgn2 );
+ if ( (nRgnType != ERROR) && (nRgnType != NULLREGION) )
+ {
+ // convert window region to screen coordinates
+ OffsetRgn( hTempRgn2, aTempRect.left, aTempRect.top );
+ // and intersect with the window's bounding box
+ CombineRgn( hTempRgn, hTempRgn, hTempRgn2, RGN_AND );
+ }
+ // finally compute that part of aSrcRect which is not covered by any parts of hWnd
+ CombineRgn( hInvalidateRgn, hInvalidateRgn, hTempRgn, RGN_DIFF );
+ DeleteRegion( hTempRgn );
+ }
+ }
+ // retrieve the next window in the z-order, i.e. the window below hwnd
+ hWnd = GetWindow( hWnd, GW_HWNDNEXT );
+ }
+ if ( hTempRgn2 )
+ DeleteRegion( hTempRgn2 );
+ if ( hInvalidateRgn )
+ {
+ // hInvalidateRgn contains the fully visible parts of the original srcRect
+ hTempRgn = CreateRectRgnIndirect( &aSrcRect );
+ // substract it from the original rect to get the occluded parts
+ nRgnType = CombineRgn( hInvalidateRgn, hTempRgn, hInvalidateRgn, RGN_DIFF );
+ DeleteRegion( hTempRgn );
+
+ if ( (nRgnType != ERROR) && (nRgnType != NULLREGION) )
+ {
+ // move the occluded parts to the destination pos
+ int nOffX = (int)(nDestX-nSrcX);
+ int nOffY = (int)(nDestY-nSrcY);
+ OffsetRgn( hInvalidateRgn, nOffX-aPt.x, nOffY-aPt.y );
+
+ // by excluding hInvalidateRgn from the system's clip region
+ // we will prevent bitblt from copying useless data
+ // epsecially now shadows from overlapping windows will appear (#i36344)
+ hOldClipRgn = CreateRectRgn( 0, 0, 0, 0 );
+ nOldClipRgnType = GetClipRgn( mhDC, hOldClipRgn );
+
+ bRestoreClipRgn = TRUE; // indicate changed clipregion and force invalidate
+ ExtSelectClipRgn( mhDC, hInvalidateRgn, RGN_DIFF );
+ }
+ }
+ }
+ }
+
+ BitBlt( mhDC,
+ (int)nDestX, (int)nDestY,
+ (int)nSrcWidth, (int)nSrcHeight,
+ mhDC,
+ (int)nSrcX, (int)nSrcY,
+ SRCCOPY );
+
+ if( bRestoreClipRgn )
+ {
+ // restore old clip region
+ if( nOldClipRgnType != ERROR )
+ SelectClipRgn( mhDC, hOldClipRgn);
+ DeleteRegion( hOldClipRgn );
+
+ // invalidate regions that were not copied
+ bool bInvalidate = true;
+
+ // Combine Invalidate Region with existing ClipRegion
+ HRGN hTempRgn = CreateRectRgn( 0, 0, 0, 0 );
+ if ( GetClipRgn( mhDC, hTempRgn ) == 1 )
+ {
+ int nRgnType = CombineRgn( hInvalidateRgn, hTempRgn, hInvalidateRgn, RGN_AND );
+ if ( (nRgnType == ERROR) || (nRgnType == NULLREGION) )
+ bInvalidate = false;
+ }
+ DeleteRegion( hTempRgn );
+
+ if ( bInvalidate )
+ {
+ InvalidateRgn( mhWnd, hInvalidateRgn, TRUE );
+ // Hier loesen wir nur ein Update aus, wenn es der
+ // MainThread ist, damit es beim Bearbeiten der
+ // Paint-Message keinen Deadlock gibt, da der
+ // SolarMutex durch diesen Thread schon gelockt ist
+ SalData* pSalData = GetSalData();
+ DWORD nCurThreadId = GetCurrentThreadId();
+ if ( pSalData->mnAppThreadId == nCurThreadId )
+ UpdateWindow( mhWnd );
+ }
+
+ DeleteRegion( hInvalidateRgn );
+ }
+
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDrawBitmap( HDC hDC,
+ const SalTwoRect* pPosAry, const WinSalBitmap& rSalBitmap,
+ BOOL bPrinter, int nDrawMode )
+{
+ if( hDC )
+ {
+ HGLOBAL hDrawDIB;
+ HBITMAP hDrawDDB = rSalBitmap.ImplGethDDB();
+ WinSalBitmap* pTmpSalBmp = NULL;
+ BOOL bPrintDDB = ( bPrinter && hDrawDDB );
+
+ if( bPrintDDB )
+ {
+ pTmpSalBmp = new WinSalBitmap;
+ pTmpSalBmp->Create( rSalBitmap, rSalBitmap.GetBitCount() );
+ hDrawDIB = pTmpSalBmp->ImplGethDIB();
+ }
+ else
+ hDrawDIB = rSalBitmap.ImplGethDIB();
+
+ if( hDrawDIB )
+ {
+ PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( hDrawDIB );
+ PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) pBI;
+ PBYTE pBits = (PBYTE) pBI + *(DWORD*) pBI +
+ rSalBitmap.ImplGetDIBColorCount( hDrawDIB ) * sizeof( RGBQUAD );
+ const int nOldStretchMode = SetStretchBltMode( hDC, STRETCH_DELETESCANS );
+
+ StretchDIBits( hDC,
+ (int)pPosAry->mnDestX, (int)pPosAry->mnDestY,
+ (int)pPosAry->mnDestWidth, (int)pPosAry->mnDestHeight,
+ (int)pPosAry->mnSrcX, (int)(pBIH->biHeight - pPosAry->mnSrcHeight - pPosAry->mnSrcY),
+ (int)pPosAry->mnSrcWidth, (int)pPosAry->mnSrcHeight,
+ pBits, pBI, DIB_RGB_COLORS, nDrawMode );
+
+ GlobalUnlock( hDrawDIB );
+ SetStretchBltMode( hDC, nOldStretchMode );
+ }
+ else if( hDrawDDB && !bPrintDDB )
+ {
+ HDC hBmpDC = ImplGetCachedDC( CACHED_HDC_DRAW, hDrawDDB );
+ COLORREF nOldBkColor = RGB(0xFF,0xFF,0xFF);
+ COLORREF nOldTextColor = RGB(0,0,0);
+ BOOL bMono = ( rSalBitmap.GetBitCount() == 1 );
+
+ if( bMono )
+ {
+ nOldBkColor = SetBkColor( hDC, RGB( 0xFF, 0xFF, 0xFF ) );
+ nOldTextColor = ::SetTextColor( hDC, RGB( 0x00, 0x00, 0x00 ) );
+ }
+
+ if ( (pPosAry->mnSrcWidth == pPosAry->mnDestWidth) &&
+ (pPosAry->mnSrcHeight == pPosAry->mnDestHeight) )
+ {
+ BitBlt( hDC,
+ (int)pPosAry->mnDestX, (int)pPosAry->mnDestY,
+ (int)pPosAry->mnDestWidth, (int)pPosAry->mnDestHeight,
+ hBmpDC,
+ (int)pPosAry->mnSrcX, (int)pPosAry->mnSrcY,
+ nDrawMode );
+ }
+ else
+ {
+ const int nOldStretchMode = SetStretchBltMode( hDC, STRETCH_DELETESCANS );
+
+ StretchBlt( hDC,
+ (int)pPosAry->mnDestX, (int)pPosAry->mnDestY,
+ (int)pPosAry->mnDestWidth, (int)pPosAry->mnDestHeight,
+ hBmpDC,
+ (int)pPosAry->mnSrcX, (int)pPosAry->mnSrcY,
+ (int)pPosAry->mnSrcWidth, (int)pPosAry->mnSrcHeight,
+ nDrawMode );
+
+ SetStretchBltMode( hDC, nOldStretchMode );
+ }
+
+ if( bMono )
+ {
+ SetBkColor( hDC, nOldBkColor );
+ ::SetTextColor( hDC, nOldTextColor );
+ }
+
+ ImplReleaseCachedDC( CACHED_HDC_DRAW );
+ }
+
+ if( bPrintDDB )
+ delete pTmpSalBmp;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap )
+{
+ ImplDrawBitmap( mhDC, pPosAry, static_cast<const WinSalBitmap&>(rSalBitmap),
+ mbPrinter,
+ mbXORMode ? SRCINVERT : SRCCOPY );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSSalBitmap,
+ SalColor nTransparentColor )
+{
+ DBG_ASSERT( !mbPrinter, "No transparency print possible!" );
+
+ const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(rSSalBitmap);
+
+ WinSalBitmap* pMask = new WinSalBitmap;
+ const Point aPoint;
+ const Size aSize( rSalBitmap.GetSize() );
+ HBITMAP hMaskBitmap = CreateBitmap( (int) aSize.Width(), (int) aSize.Height(), 1, 1, NULL );
+ HDC hMaskDC = ImplGetCachedDC( CACHED_HDC_1, hMaskBitmap );
+ const BYTE cRed = SALCOLOR_RED( nTransparentColor );
+ const BYTE cGreen = SALCOLOR_GREEN( nTransparentColor );
+ const BYTE cBlue = SALCOLOR_BLUE( nTransparentColor );
+
+ if( rSalBitmap.ImplGethDDB() )
+ {
+ HDC hSrcDC = ImplGetCachedDC( CACHED_HDC_2, rSalBitmap.ImplGethDDB() );
+ COLORREF aOldCol = SetBkColor( hSrcDC, RGB( cRed, cGreen, cBlue ) );
+
+ BitBlt( hMaskDC, 0, 0, (int) aSize.Width(), (int) aSize.Height(), hSrcDC, 0, 0, SRCCOPY );
+
+ SetBkColor( hSrcDC, aOldCol );
+ ImplReleaseCachedDC( CACHED_HDC_2 );
+ }
+ else
+ {
+ WinSalBitmap* pTmpSalBmp = new WinSalBitmap;
+
+ if( pTmpSalBmp->Create( rSalBitmap, this ) )
+ {
+ HDC hSrcDC = ImplGetCachedDC( CACHED_HDC_2, pTmpSalBmp->ImplGethDDB() );
+ COLORREF aOldCol = SetBkColor( hSrcDC, RGB( cRed, cGreen, cBlue ) );
+
+ BitBlt( hMaskDC, 0, 0, (int) aSize.Width(), (int) aSize.Height(), hSrcDC, 0, 0, SRCCOPY );
+
+ SetBkColor( hSrcDC, aOldCol );
+ ImplReleaseCachedDC( CACHED_HDC_2 );
+ }
+
+ delete pTmpSalBmp;
+ }
+
+ ImplReleaseCachedDC( CACHED_HDC_1 );
+
+ // hMaskBitmap is destroyed by new SalBitmap 'pMask' ( bDIB==FALSE, bCopy == FALSE )
+ if( pMask->Create( hMaskBitmap, FALSE, FALSE ) )
+ drawBitmap( pPosAry, rSalBitmap, *pMask );
+
+ delete pMask;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSSalBitmap,
+ const SalBitmap& rSTransparentBitmap )
+{
+ DBG_ASSERT( !mbPrinter, "No transparency print possible!" );
+
+ const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(rSSalBitmap);
+ const WinSalBitmap& rTransparentBitmap = static_cast<const WinSalBitmap&>(rSTransparentBitmap);
+
+ SalTwoRect aPosAry = *pPosAry;
+ int nDstX = (int)aPosAry.mnDestX;
+ int nDstY = (int)aPosAry.mnDestY;
+ int nDstWidth = (int)aPosAry.mnDestWidth;
+ int nDstHeight = (int)aPosAry.mnDestHeight;
+ HDC hDC = mhDC;
+ HBITMAP hMemBitmap = 0;
+ HBITMAP hMaskBitmap = 0;
+
+ if( ( nDstWidth > CACHED_HDC_DEFEXT ) || ( nDstHeight > CACHED_HDC_DEFEXT ) )
+ {
+ hMemBitmap = CreateCompatibleBitmap( hDC, nDstWidth, nDstHeight );
+ hMaskBitmap = CreateCompatibleBitmap( hDC, nDstWidth, nDstHeight );
+ }
+
+ HDC hMemDC = ImplGetCachedDC( CACHED_HDC_1, hMemBitmap );
+ HDC hMaskDC = ImplGetCachedDC( CACHED_HDC_2, hMaskBitmap );
+
+ aPosAry.mnDestX = aPosAry.mnDestY = 0;
+ BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hDC, nDstX, nDstY, SRCCOPY );
+
+ // bei Paletten-Displays hat WIN/WNT offenbar ein kleines Problem,
+ // die Farben der Maske richtig auf die Palette abzubilden,
+ // wenn wir die DIB direkt ausgeben => DDB-Ausgabe
+ if( ( GetBitCount() <= 8 ) && rTransparentBitmap.ImplGethDIB() && rTransparentBitmap.GetBitCount() == 1 )
+ {
+ WinSalBitmap aTmp;
+
+ if( aTmp.Create( rTransparentBitmap, this ) )
+ ImplDrawBitmap( hMaskDC, &aPosAry, aTmp, FALSE, SRCCOPY );
+ }
+ else
+ ImplDrawBitmap( hMaskDC, &aPosAry, rTransparentBitmap, FALSE, SRCCOPY );
+
+ // now MemDC contains background, MaskDC the transparency mask
+
+ // #105055# Respect XOR mode
+ if( mbXORMode )
+ {
+ ImplDrawBitmap( hMaskDC, &aPosAry, rSalBitmap, FALSE, SRCERASE );
+ // now MaskDC contains the bitmap area with black background
+ BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hMaskDC, 0, 0, SRCINVERT );
+ // now MemDC contains background XORed bitmap area ontop
+ }
+ else
+ {
+ BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hMaskDC, 0, 0, SRCAND );
+ // now MemDC contains background with masked-out bitmap area
+ ImplDrawBitmap( hMaskDC, &aPosAry, rSalBitmap, FALSE, SRCERASE );
+ // now MaskDC contains the bitmap area with black background
+ BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hMaskDC, 0, 0, SRCPAINT );
+ // now MemDC contains background and bitmap merged together
+ }
+ // copy to output DC
+ BitBlt( hDC, nDstX, nDstY, nDstWidth, nDstHeight, hMemDC, 0, 0, SRCCOPY );
+
+ ImplReleaseCachedDC( CACHED_HDC_1 );
+ ImplReleaseCachedDC( CACHED_HDC_2 );
+
+ // hMemBitmap != 0 ==> hMaskBitmap != 0
+ if( hMemBitmap )
+ {
+ DeleteObject( hMemBitmap );
+ DeleteObject( hMaskBitmap );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+bool WinSalGraphics::drawAlphaBitmap( const SalTwoRect& rTR,
+ const SalBitmap& rSrcBitmap,
+ const SalBitmap& rAlphaBmp )
+{
+ (void)rTR; (void)rSrcBitmap; (void)rAlphaBmp;
+
+ // TODO(P3): implement alpha bmp blits. Catch: Windows only
+ // handles 32bpp, premultiplied bitmaps
+ return false;
+}
+
+// -----------------------------------------------------------------------
+
+bool WinSalGraphics::drawAlphaRect( long nX, long nY, long nWidth,
+ long nHeight, sal_uInt8 nTransparency )
+{
+ if( mbPen || !mbBrush || mbXORMode )
+ return false; // can only perform solid fills without XOR.
+
+ HDC hMemDC = ImplGetCachedDC( CACHED_HDC_1, 0 );
+ SetPixel( hMemDC, (int)0, (int)0, mnBrushColor );
+
+ BLENDFUNCTION aFunc = {
+ AC_SRC_OVER,
+ 0,
+ 255 - 255L*nTransparency/100,
+ 0
+ };
+
+ // hMemDC contains a 1x1 bitmap of the right color - stretch-blit
+ // that to dest hdc
+ bool bRet = AlphaBlend( mhDC, nX, nY, nWidth, nHeight,
+ hMemDC, 0,0,1,1,
+ aFunc ) == TRUE;
+
+ ImplReleaseCachedDC( CACHED_HDC_1 );
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::drawMask( const SalTwoRect* pPosAry,
+ const SalBitmap& rSSalBitmap,
+ SalColor nMaskColor )
+{
+ DBG_ASSERT( !mbPrinter, "No transparency print possible!" );
+
+ const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(rSSalBitmap);
+
+ SalTwoRect aPosAry = *pPosAry;
+ const BYTE cRed = SALCOLOR_RED( nMaskColor );
+ const BYTE cGreen = SALCOLOR_GREEN( nMaskColor );
+ const BYTE cBlue = SALCOLOR_BLUE( nMaskColor );
+ HDC hDC = mhDC;
+ HBRUSH hMaskBrush = CreateSolidBrush( RGB( cRed, cGreen, cBlue ) );
+ HBRUSH hOldBrush = SelectBrush( hDC, hMaskBrush );
+
+ // bei Paletten-Displays hat WIN/WNT offenbar ein kleines Problem,
+ // die Farben der Maske richtig auf die Palette abzubilden,
+ // wenn wir die DIB direkt ausgeben => DDB-Ausgabe
+ if( ( GetBitCount() <= 8 ) && rSalBitmap.ImplGethDIB() && rSalBitmap.GetBitCount() == 1 )
+ {
+ WinSalBitmap aTmp;
+
+ if( aTmp.Create( rSalBitmap, this ) )
+ ImplDrawBitmap( hDC, &aPosAry, aTmp, FALSE, 0x00B8074AUL );
+ }
+ else
+ ImplDrawBitmap( hDC, &aPosAry, rSalBitmap, FALSE, 0x00B8074AUL );
+
+ SelectBrush( hDC, hOldBrush );
+ DeleteBrush( hMaskBrush );
+}
+
+// -----------------------------------------------------------------------
+
+SalBitmap* WinSalGraphics::getBitmap( long nX, long nY, long nDX, long nDY )
+{
+ DBG_ASSERT( !mbPrinter, "No ::GetBitmap() from printer possible!" );
+
+ WinSalBitmap* pSalBitmap = NULL;
+
+ nDX = labs( nDX );
+ nDY = labs( nDY );
+
+ HDC hDC = mhDC;
+ HBITMAP hBmpBitmap = CreateCompatibleBitmap( hDC, nDX, nDY );
+ HDC hBmpDC = ImplGetCachedDC( CACHED_HDC_1, hBmpBitmap );
+ BOOL bRet;
+ DWORD err = 0;
+
+ bRet = BitBlt( hBmpDC, 0, 0, (int) nDX, (int) nDY, hDC, (int) nX, (int) nY, SRCCOPY ) ? TRUE : FALSE;
+ ImplReleaseCachedDC( CACHED_HDC_1 );
+
+ if( bRet )
+ {
+ pSalBitmap = new WinSalBitmap;
+
+ if( !pSalBitmap->Create( hBmpBitmap, FALSE, FALSE ) )
+ {
+ delete pSalBitmap;
+ pSalBitmap = NULL;
+ }
+ }
+ else
+ {
+ err = GetLastError();
+ // #124826# avoid resource leak ! happens when runing without desktop access (remote desktop, service, may be screensavers)
+ DeleteBitmap( hBmpBitmap );
+ }
+
+ return pSalBitmap;
+}
+
+// -----------------------------------------------------------------------
+
+SalColor WinSalGraphics::getPixel( long nX, long nY )
+{
+ COLORREF aWinCol = ::GetPixel( mhDC, (int) nX, (int) nY );
+
+ if ( CLR_INVALID == aWinCol )
+ return MAKE_SALCOLOR( 0, 0, 0 );
+ else
+ return MAKE_SALCOLOR( GetRValue( aWinCol ),
+ GetGValue( aWinCol ),
+ GetBValue( aWinCol ) );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags )
+{
+ if ( nFlags & SAL_INVERT_TRACKFRAME )
+ {
+ HPEN hDotPen = CreatePen( PS_DOT, 0, 0 );
+ HPEN hOldPen = SelectPen( mhDC, hDotPen );
+ HBRUSH hOldBrush = SelectBrush( mhDC, GetStockBrush( NULL_BRUSH ) );
+ int nOldROP = SetROP2( mhDC, R2_NOT );
+
+ WIN_Rectangle( mhDC, (int)nX, (int)nY, (int)(nX+nWidth), (int)(nY+nHeight) );
+
+ SetROP2( mhDC, nOldROP );
+ SelectPen( mhDC, hOldPen );
+ SelectBrush( mhDC, hOldBrush );
+ DeletePen( hDotPen );
+ }
+ else if ( nFlags & SAL_INVERT_50 )
+ {
+ SalData* pSalData = GetSalData();
+ if ( !pSalData->mh50Brush )
+ {
+ if ( !pSalData->mh50Bmp )
+ pSalData->mh50Bmp = ImplLoadSalBitmap( SAL_RESID_BITMAP_50 );
+ pSalData->mh50Brush = CreatePatternBrush( pSalData->mh50Bmp );
+ }
+
+ COLORREF nOldTextColor = ::SetTextColor( mhDC, 0 );
+ HBRUSH hOldBrush = SelectBrush( mhDC, pSalData->mh50Brush );
+ PatBlt( mhDC, nX, nY, nWidth, nHeight, PATINVERT );
+ ::SetTextColor( mhDC, nOldTextColor );
+ SelectBrush( mhDC, hOldBrush );
+ }
+ else
+ {
+ RECT aRect;
+ aRect.left = (int)nX;
+ aRect.top = (int)nY;
+ aRect.right = (int)nX+nWidth;
+ aRect.bottom = (int)nY+nHeight;
+ ::InvertRect( mhDC, &aRect );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::invert( ULONG nPoints, const SalPoint* pPtAry, SalInvert nSalFlags )
+{
+ HPEN hPen;
+ HPEN hOldPen;
+ HBRUSH hBrush;
+ HBRUSH hOldBrush = 0;
+ COLORREF nOldTextColor RGB(0,0,0);
+ int nOldROP = SetROP2( mhDC, R2_NOT );
+
+ if ( nSalFlags & SAL_INVERT_TRACKFRAME )
+ hPen = CreatePen( PS_DOT, 0, 0 );
+ else
+ {
+
+ if ( nSalFlags & SAL_INVERT_50 )
+ {
+ SalData* pSalData = GetSalData();
+ if ( !pSalData->mh50Brush )
+ {
+ if ( !pSalData->mh50Bmp )
+ pSalData->mh50Bmp = ImplLoadSalBitmap( SAL_RESID_BITMAP_50 );
+ pSalData->mh50Brush = CreatePatternBrush( pSalData->mh50Bmp );
+ }
+
+ hBrush = pSalData->mh50Brush;
+ }
+ else
+ hBrush = GetStockBrush( BLACK_BRUSH );
+
+ hPen = GetStockPen( NULL_PEN );
+ nOldTextColor = ::SetTextColor( mhDC, 0 );
+ hOldBrush = SelectBrush( mhDC, hBrush );
+ }
+ hOldPen = SelectPen( mhDC, hPen );
+
+ POINT* pWinPtAry;
+ // Unter NT koennen wir das Array direkt weiterreichen
+ DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
+ "WinSalGraphics::DrawPolyLine(): POINT != SalPoint" );
+
+ pWinPtAry = (POINT*)pPtAry;
+ // Wegen Windows 95 und der Beschraenkung auf eine maximale Anzahl
+ // von Punkten
+ if ( nSalFlags & SAL_INVERT_TRACKFRAME )
+ {
+ if ( !Polyline( mhDC, pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) )
+ Polyline( mhDC, pWinPtAry, MAX_64KSALPOINTS );
+ }
+ else
+ {
+ if ( !WIN_Polygon( mhDC, pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) )
+ WIN_Polygon( mhDC, pWinPtAry, MAX_64KSALPOINTS );
+ }
+
+ SetROP2( mhDC, nOldROP );
+ SelectPen( mhDC, hOldPen );
+
+ if ( nSalFlags & SAL_INVERT_TRACKFRAME )
+ DeletePen( hPen );
+ else
+ {
+ ::SetTextColor( mhDC, nOldTextColor );
+ SelectBrush( mhDC, hOldBrush );
+ }
+}
diff --git a/vcl/win/source/gdi/salgdi3.cxx b/vcl/win/source/gdi/salgdi3.cxx
new file mode 100644
index 000000000000..d1b5a9cfdeae
--- /dev/null
+++ b/vcl/win/source/gdi/salgdi3.cxx
@@ -0,0 +1,3229 @@
+/*************************************************************************
+ *
+ * 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 <malloc.h>
+
+#include <tools/prewin.h>
+#include <windows.h>
+#include <tools/postwin.h>
+#include <vcl/sysdata.hxx>
+#include "tools/svwin.h"
+
+#include "wincomp.hxx"
+#include "saldata.hxx"
+#include "salgdi.h"
+
+#include "vcl/svapp.hxx"
+#include "vcl/outfont.hxx"
+#include "vcl/font.hxx"
+#include "vcl/fontsubset.hxx"
+#include "vcl/sallayout.hxx"
+
+#include "vcl/outdev.h" // for ImplGlyphFallbackFontSubstitution
+#include "unotools/fontcfg.hxx" // for IMPL_FONT_ATTR_SYMBOL
+
+#include "rtl/logfile.hxx"
+#include "rtl/tencinfo.h"
+#include "rtl/textcvt.h"
+#include "rtl/bootstrap.hxx"
+
+#include "i18npool/mslangid.hxx"
+
+#include "osl/module.h"
+#include "osl/file.hxx"
+#include "osl/thread.hxx"
+#include "osl/process.h"
+
+#include "tools/poly.hxx"
+#include "tools/debug.hxx"
+#include "tools/stream.hxx"
+
+#include "basegfx/polygon/b2dpolygon.hxx"
+#include "basegfx/polygon/b2dpolypolygon.hxx"
+#include "basegfx/matrix/b2dhommatrix.hxx"
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+#include "sft.hxx"
+
+#ifdef GCP_KERN_HACK
+#include <algorithm>
+#endif
+
+#ifdef ENABLE_GRAPHITE
+#include <graphite/GrClient.h>
+#include <graphite/WinFont.h>
+#endif
+
+#include <vector>
+#include <set>
+#include <map>
+
+using namespace vcl;
+
+static const int MAXFONTHEIGHT = 2048;
+
+// -----------
+// - Inlines -
+// -----------
+
+inline FIXED FixedFromDouble( double d )
+{
+ const long l = (long) ( d * 65536. );
+ return *(FIXED*) &l;
+}
+
+// -----------------------------------------------------------------------
+
+inline int IntTimes256FromFixed(FIXED f)
+{
+ int nFixedTimes256 = (f.value << 8) + ((f.fract+0x80) >> 8);
+ return nFixedTimes256;
+}
+
+// =======================================================================
+
+// these variables can be static because they store system wide settings
+static bool bImplSalCourierScalable = false;
+static bool bImplSalCourierNew = false;
+
+
+// =======================================================================
+
+// -----------------------------------------------------------------------
+
+// TODO: also support temporary TTC font files
+typedef std::map< String, ImplDevFontAttributes > FontAttrMap;
+
+class ImplFontAttrCache
+{
+private:
+ FontAttrMap aFontAttributes;
+ rtl::OUString aCacheFileName;
+ String aBaseURL;
+ BOOL bModified;
+
+protected:
+ String OptimizeURL( const String& rURL ) const;
+
+ enum{ MAGIC = 0x12349876 }; // change if fontattrcache format changes
+
+public:
+ ImplFontAttrCache( const String& rCacheFileName, const String& rBaseURL );
+ ~ImplFontAttrCache();
+
+ ImplDevFontAttributes GetFontAttr( const String& rFontFileName ) const;
+ void AddFontAttr( const String& rFontFileName, const ImplDevFontAttributes& );
+};
+
+ImplFontAttrCache::ImplFontAttrCache( const String& rFileNameURL, const String& rBaseURL ) : aBaseURL( rBaseURL )
+{
+ bModified = FALSE;
+ aBaseURL.ToLowerAscii(); // Windows only, no problem...
+
+ // open the cache file
+ osl::FileBase::getSystemPathFromFileURL( rFileNameURL, aCacheFileName );
+ SvFileStream aCacheFile( aCacheFileName, STREAM_READ );
+ if( !aCacheFile.IsOpen() )
+ return;
+
+ // check the cache version
+ sal_uInt32 nCacheMagic;
+ aCacheFile >> nCacheMagic;
+ if( nCacheMagic != ImplFontAttrCache::MAGIC )
+ return; // ignore cache and rewrite if no match
+
+ // read the cache entries from the file
+ String aFontFileURL, aFontName;
+ ImplDevFontAttributes aDFA;
+ for(;;)
+ {
+ aCacheFile.ReadByteString( aFontFileURL, RTL_TEXTENCODING_UTF8 );
+ if( !aFontFileURL.Len() )
+ break;
+ aCacheFile.ReadByteString( aDFA.maName, RTL_TEXTENCODING_UTF8 );
+
+ short n;
+ aCacheFile >> n; aDFA.meWeight = static_cast<FontWeight>(n);
+ aCacheFile >> n; aDFA.meItalic = static_cast<FontItalic>(n);
+ aCacheFile >> n; aDFA.mePitch = static_cast<FontPitch>(n);
+ aCacheFile >> n; aDFA.meWidthType = static_cast<FontWidth>(n);
+ aCacheFile >> n; aDFA.meFamily = static_cast<FontFamily>(n);
+ aCacheFile >> n; aDFA.mbSymbolFlag = (n != 0);
+
+ aCacheFile.ReadByteStringLine( aDFA.maStyleName, RTL_TEXTENCODING_UTF8 );
+
+ aFontAttributes[ aFontFileURL ] = aDFA;
+ }
+}
+
+ImplFontAttrCache::~ImplFontAttrCache()
+{
+ if ( bModified )
+ {
+ SvFileStream aCacheFile( aCacheFileName, STREAM_WRITE|STREAM_TRUNC );
+ if ( aCacheFile.IsWritable() )
+ {
+ sal_uInt32 nCacheMagic = ImplFontAttrCache::MAGIC;
+ aCacheFile << nCacheMagic;
+
+ // write the cache entries to the file
+ FontAttrMap::const_iterator aIter = aFontAttributes.begin();
+ while ( aIter != aFontAttributes.end() )
+ {
+ const String rFontFileURL( (*aIter).first );
+ const ImplDevFontAttributes& rDFA( (*aIter).second );
+ aCacheFile.WriteByteString( rFontFileURL, RTL_TEXTENCODING_UTF8 );
+ aCacheFile.WriteByteString( rDFA.maName, RTL_TEXTENCODING_UTF8 );
+
+ aCacheFile << static_cast<short>(rDFA.meWeight);
+ aCacheFile << static_cast<short>(rDFA.meItalic);
+ aCacheFile << static_cast<short>(rDFA.mePitch);
+ aCacheFile << static_cast<short>(rDFA.meWidthType);
+ aCacheFile << static_cast<short>(rDFA.meFamily);
+ aCacheFile << static_cast<short>(rDFA.mbSymbolFlag != false);
+
+ aCacheFile.WriteByteStringLine( rDFA.maStyleName, RTL_TEXTENCODING_UTF8 );
+
+ aIter++;
+ }
+ // EOF Marker
+ String aEmptyStr;
+ aCacheFile.WriteByteString( aEmptyStr, RTL_TEXTENCODING_UTF8 );
+ }
+ }
+}
+
+String ImplFontAttrCache::OptimizeURL( const String& rURL ) const
+{
+ String aOptimizedFontFileURL( rURL );
+ aOptimizedFontFileURL.ToLowerAscii(); // Windows only, no problem...
+ if ( aOptimizedFontFileURL.CompareTo( aBaseURL, aBaseURL.Len() ) == COMPARE_EQUAL )
+ aOptimizedFontFileURL = aOptimizedFontFileURL.Copy( aBaseURL.Len() );
+ return aOptimizedFontFileURL;
+}
+
+ImplDevFontAttributes ImplFontAttrCache::GetFontAttr( const String& rFontFileName ) const
+{
+ ImplDevFontAttributes aDFA;
+ FontAttrMap::const_iterator it = aFontAttributes.find( OptimizeURL( rFontFileName ) );
+ if( it != aFontAttributes.end() )
+ {
+ aDFA = it->second;
+ }
+ return aDFA;
+}
+
+void ImplFontAttrCache::AddFontAttr( const String& rFontFileName, const ImplDevFontAttributes& rDFA )
+{
+ DBG_ASSERT( rFontFileName.Len() && rDFA.maName.Len(), "ImplFontNameCache::AddFontName - invalid data!" );
+ if ( rFontFileName.Len() && rDFA.maName.Len() )
+ {
+ aFontAttributes.insert( FontAttrMap::value_type( OptimizeURL( rFontFileName ), rDFA ) );
+ bModified = TRUE;
+ }
+}
+
+// =======================================================================
+
+// raw font data with a scoped lifetime
+class RawFontData
+{
+public:
+ explicit RawFontData( HDC, DWORD nTableTag=0 );
+ ~RawFontData() { delete[] mpRawBytes; }
+ const unsigned char* get() const { return mpRawBytes; }
+ const unsigned char* steal() { unsigned char* p = mpRawBytes; mpRawBytes = NULL; return p; }
+ const int size() const { return mnByteCount; }
+
+private:
+ unsigned char* mpRawBytes;
+ int mnByteCount;
+};
+
+RawFontData::RawFontData( HDC hDC, DWORD nTableTag )
+: mpRawBytes( NULL )
+, mnByteCount( 0 )
+{
+ // get required size in bytes
+ mnByteCount = ::GetFontData( hDC, nTableTag, 0, NULL, 0 );
+ if( mnByteCount == GDI_ERROR )
+ return;
+ else if( !mnByteCount )
+ return;
+
+ // allocate the array
+ mpRawBytes = new unsigned char[ mnByteCount ];
+
+ // get raw data in chunks small enough for GetFontData()
+ int nRawDataOfs = 0;
+ DWORD nMaxChunkSize = 0x100000;
+ for(;;)
+ {
+ // calculate remaining raw data to get
+ DWORD nFDGet = mnByteCount - nRawDataOfs;
+ if( nFDGet <= 0 )
+ break;
+ // #i56745# limit GetFontData requests
+ if( nFDGet > nMaxChunkSize )
+ nFDGet = nMaxChunkSize;
+ const DWORD nFDGot = ::GetFontData( hDC, nTableTag, nRawDataOfs,
+ (void*)(mpRawBytes + nRawDataOfs), nFDGet );
+ if( !nFDGot )
+ break;
+ else if( nFDGot != GDI_ERROR )
+ nRawDataOfs += nFDGot;
+ else
+ {
+ // was the chunk too big? reduce it
+ nMaxChunkSize /= 2;
+ if( nMaxChunkSize < 0x10000 )
+ break;
+ }
+ }
+
+ // cleanup if the raw data is incomplete
+ if( nRawDataOfs != mnByteCount )
+ {
+ delete[] mpRawBytes;
+ mpRawBytes = NULL;
+ }
+}
+
+// ===========================================================================
+// platform specific font substitution hooks for glyph fallback enhancement
+// TODO: move into i18n module (maybe merge with svx/ucsubset.*
+// or merge with i18nutil/source/utility/unicode_data.h)
+struct Unicode2LangType
+{
+ sal_UCS4 mnMinCode;
+ sal_UCS4 mnMaxCode;
+ LanguageType mnLangID;
+};
+
+// entries marked with default-CJK get replaced with the default-CJK language
+#define LANGUAGE_DEFAULT_CJK 0xFFF0
+
+// map unicode ranges to languages supported by OOo
+// NOTE: due to the binary search used this list must be sorted by mnMinCode
+static Unicode2LangType aLangFromCodeChart[]= {
+ {0x0000, 0x007F, LANGUAGE_ENGLISH}, // Basic Latin
+ {0x0080, 0x024F, LANGUAGE_ENGLISH}, // Latin Extended-A and Latin Extended-B
+ {0x0250, 0x02AF, LANGUAGE_SYSTEM}, // IPA Extensions
+ {0x0370, 0x03FF, LANGUAGE_GREEK}, // Greek
+ {0x0590, 0x05FF, LANGUAGE_HEBREW}, // Hebrew
+ {0x0600, 0x06FF, LANGUAGE_ARABIC_PRIMARY_ONLY}, // Arabic
+ {0x0900, 0x097F, LANGUAGE_HINDI}, // Devanagari
+ {0x0980, 0x09FF, LANGUAGE_BENGALI}, // Bengali
+ {0x0A80, 0x0AFF, LANGUAGE_GUJARATI}, // Gujarati
+ {0x0B00, 0x0B7F, LANGUAGE_ORIYA}, // Oriya
+ {0x0B80, 0x0BFF, LANGUAGE_TAMIL}, // Tamil
+ {0x0C00, 0x0C7F, LANGUAGE_TELUGU}, // Telugu
+ {0x0C80, 0x0CFF, LANGUAGE_KANNADA}, // Kannada
+ {0x0D00, 0x0D7F, LANGUAGE_MALAYALAM}, // Malayalam
+ {0x0D80, 0x0D7F, LANGUAGE_SINHALESE_SRI_LANKA}, // Sinhala
+ {0x0E00, 0x0E7F, LANGUAGE_THAI}, // Thai
+ {0x0E80, 0x0EFF, LANGUAGE_LAO}, // Lao
+ {0x0F00, 0x0FFF, LANGUAGE_TIBETAN}, // Tibetan
+ {0x1000, 0x109F, LANGUAGE_BURMESE}, // Burmese
+ {0x10A0, 0x10FF, LANGUAGE_GEORGIAN}, // Georgian
+ {0x1100, 0x11FF, LANGUAGE_KOREAN}, // Hangul Jamo, Korean-specific
+// {0x1200, 0x139F, LANGUAGE_AMHARIC_ETHIOPIA}, // Ethiopic
+// {0x1200, 0x139F, LANGUAGE_TIGRIGNA_ETHIOPIA}, // Ethiopic
+ {0x13A0, 0x13FF, LANGUAGE_CHEROKEE_UNITED_STATES}, // Cherokee
+// {0x1400, 0x167F, LANGUAGE_CANADIAN_ABORIGINAL}, // Canadian Aboriginial Syllabics
+// {0x1680, 0x169F, LANGUAGE_OGHAM}, // Ogham
+// {0x16A0, 0x16F0, LANGUAGE_RUNIC}, // Runic
+// {0x1700, 0x171F, LANGUAGE_TAGALOG}, // Tagalog
+// {0x1720, 0x173F, LANGUAGE_HANUNOO}, // Hanunoo
+// {0x1740, 0x175F, LANGUAGE_BUHID}, // Buhid
+// {0x1760, 0x177F, LANGUAGE_TAGBANWA}, // Tagbanwa
+ {0x1780, 0x17FF, LANGUAGE_KHMER}, // Khmer
+ {0x18A0, 0x18AF, LANGUAGE_MONGOLIAN}, // Mongolian
+// {0x1900, 0x194F, LANGUAGE_LIMBU}, // Limbu
+// {0x1950, 0x197F, LANGUAGE_TAILE}, // Tai Le
+// {0x1980, 0x19DF, LANGUAGE_TAILUE}, // Tai Lue
+ {0x19E0, 0x19FF, LANGUAGE_KHMER}, // Khmer Symbols
+// {0x1A00, 0x1A1F, LANGUAGE_BUGINESE}, // Buginese/Lontara
+// {0x1B00, 0x1B7F, LANGUAGE_BALINESE}, // Balinese
+// {0x1D00, 0x1DFF, LANGUAGE_NONE}, // Phonetic Symbols
+ {0x1E00, 0x1EFF, LANGUAGE_ENGLISH}, // Latin Extended Additional
+ {0x1F00, 0x1FFF, LANGUAGE_GREEK}, // Greek Extended
+ {0x2C60, 0x2C7F, LANGUAGE_ENGLISH}, // Latin Extended-C
+ {0x2E80, 0x2FFf, LANGUAGE_CHINESE_SIMPLIFIED}, // CJK Radicals Supplement + Kangxi Radical + Ideographic Description Characters
+ {0x3000, 0x303F, LANGUAGE_DEFAULT_CJK}, // CJK Symbols and punctuation
+ {0x3040, 0x30FF, LANGUAGE_JAPANESE}, // Japanese Hiragana + Katakana
+ {0x3100, 0x312F, LANGUAGE_CHINESE_TRADITIONAL}, // Bopomofo
+ {0x3130, 0x318F, LANGUAGE_KOREAN}, // Hangul Compatibility Jamo, Kocrean-specific
+ {0x3190, 0x319F, LANGUAGE_JAPANESE}, // Kanbun
+ {0x31A0, 0x31BF, LANGUAGE_CHINESE_TRADITIONAL}, // Bopomofo Extended
+ {0x31C0, 0x31EF, LANGUAGE_DEFAULT_CJK}, // CJK Ideographs
+ {0x31F0, 0x31FF, LANGUAGE_JAPANESE}, // Japanese Katakana Phonetic Extensions
+ {0x3200, 0x321F, LANGUAGE_KOREAN}, // Parenthesized Hangul
+ {0x3220, 0x325F, LANGUAGE_DEFAULT_CJK}, // Parenthesized Ideographs
+ {0x3260, 0x327F, LANGUAGE_KOREAN}, // Circled Hangul
+ {0x3280, 0x32CF, LANGUAGE_DEFAULT_CJK}, // Circled Ideographs
+ {0x32d0, 0x32FF, LANGUAGE_JAPANESE}, // Japanese Circled Katakana
+ {0x3400, 0x4DBF, LANGUAGE_DEFAULT_CJK}, // CJK Unified Ideographs Extension A
+ {0x4E00, 0x9FCF, LANGUAGE_DEFAULT_CJK}, // Unified CJK Ideographs
+ {0xA720, 0xA7FF, LANGUAGE_ENGLISH}, // Latin Extended-D
+ {0xAC00, 0xD7AF, LANGUAGE_KOREAN}, // Hangul Syllables, Korean-specific
+ {0xF900, 0xFAFF, LANGUAGE_DEFAULT_CJK}, // CJK Compatibility Ideographs
+ {0xFB00, 0xFB4F, LANGUAGE_HEBREW}, // Hebrew Presentation Forms
+ {0xFB50, 0xFDFF, LANGUAGE_ARABIC_PRIMARY_ONLY}, // Arabic Presentation Forms-A
+ {0xFE70, 0xFEFE, LANGUAGE_ARABIC_PRIMARY_ONLY}, // Arabic Presentation Forms-B
+ {0xFF65, 0xFF9F, LANGUAGE_JAPANESE}, // Japanese Halfwidth Katakana variant
+ {0xFFA0, 0xFFDC, LANGUAGE_KOREAN}, // Kocrean halfwidth hangual variant
+ {0x10140, 0x1018F, LANGUAGE_GREEK}, // Ancient Greak numbers
+ {0x1D200, 0x1D24F, LANGUAGE_GREEK}, // Ancient Greek Musical
+ {0x20000, 0x2A6DF, LANGUAGE_DEFAULT_CJK}, // CJK Unified Ideographs Extension B
+ {0x2F800, 0x2FA1F, LANGUAGE_DEFAULT_CJK} // CJK Compatibility Ideographs Supplement
+};
+
+// get language matching to the missing char
+LanguageType MapCharToLanguage( sal_UCS4 uChar )
+{
+ // entries marked with default-CJK get replaced with the prefered CJK language
+ static bool bFirst = true;
+ if( bFirst )
+ {
+ bFirst = false;
+
+ // use method suggested in #i97086# to determnine the systems default language
+ // TODO: move into i18npool or sal/osl/w32/nlsupport.c
+ LanguageType nDefaultLang = 0;
+ HKEY hKey = NULL;
+ LONG lResult = ::RegOpenKeyExA( HKEY_LOCAL_MACHINE,
+ "SYSTEM\\CurrentControlSet\\Control\\Nls\\Language",
+ 0, KEY_QUERY_VALUE, &hKey );
+ char aKeyValBuf[16];
+ DWORD nKeyValSize = sizeof(aKeyValBuf);
+ if( ERROR_SUCCESS == lResult )
+ lResult = RegQueryValueExA( hKey, "Default", NULL, NULL, (LPBYTE)aKeyValBuf, &nKeyValSize );
+ aKeyValBuf[ sizeof(aKeyValBuf)-1 ] = '\0';
+ if( ERROR_SUCCESS == lResult )
+ nDefaultLang = (LanguageType)rtl_str_toInt32( aKeyValBuf, 16 );
+
+ // TODO: use the default-CJK language selected in
+ // Tools->Options->LangSettings->Languages when it becomes available here
+ if( !nDefaultLang )
+ nDefaultLang = Application::GetSettings().GetUILanguage();
+
+ LanguageType nDefaultCJK = LANGUAGE_CHINESE;
+ switch( nDefaultLang )
+ {
+ case LANGUAGE_JAPANESE:
+ case LANGUAGE_KOREAN:
+ case LANGUAGE_KOREAN_JOHAB:
+ case LANGUAGE_CHINESE_SIMPLIFIED:
+ case LANGUAGE_CHINESE_TRADITIONAL:
+ case LANGUAGE_CHINESE_SINGAPORE:
+ case LANGUAGE_CHINESE_HONGKONG:
+ case LANGUAGE_CHINESE_MACAU:
+ nDefaultCJK = nDefaultLang;
+ break;
+ default:
+ nDefaultCJK = LANGUAGE_CHINESE;
+ break;
+ }
+
+ // change the marked entries to prefered language
+ static const int nCount = (sizeof(aLangFromCodeChart) / sizeof(*aLangFromCodeChart));
+ for( int i = 0; i < nCount; ++i )
+ {
+ if( aLangFromCodeChart[ i].mnLangID == LANGUAGE_DEFAULT_CJK )
+ aLangFromCodeChart[ i].mnLangID = nDefaultCJK;
+ }
+ }
+
+ // binary search
+ int nLow = 0;
+ int nHigh = (sizeof(aLangFromCodeChart) / sizeof(*aLangFromCodeChart)) - 1;
+ while( nLow <= nHigh )
+ {
+ int nMiddle = (nHigh + nLow) / 2;
+ if( uChar < aLangFromCodeChart[ nMiddle].mnMinCode )
+ nHigh = nMiddle - 1;
+ else if( uChar > aLangFromCodeChart[ nMiddle].mnMaxCode )
+ nLow = nMiddle + 1;
+ else
+ return aLangFromCodeChart[ nMiddle].mnLangID;
+ }
+
+ return LANGUAGE_DONTKNOW;
+}
+
+class WinGlyphFallbackSubstititution
+: public ImplGlyphFallbackFontSubstitution
+{
+public:
+ explicit WinGlyphFallbackSubstititution( HDC );
+
+ bool FindFontSubstitute( ImplFontSelectData&, rtl::OUString& rMissingChars ) const;
+private:
+ HDC mhDC;
+ bool HasMissingChars( const ImplFontData*, const rtl::OUString& rMissingChars ) const;
+};
+
+inline WinGlyphFallbackSubstititution::WinGlyphFallbackSubstititution( HDC hDC )
+: mhDC( hDC )
+{}
+
+void ImplGetLogFontFromFontSelect( HDC, const ImplFontSelectData*,
+ LOGFONTW&, bool /*bTestVerticalAvail*/ );
+
+// does a font face hold the given missing characters?
+bool WinGlyphFallbackSubstititution::HasMissingChars( const ImplFontData* pFace, const rtl::OUString& rMissingChars ) const
+{
+ const ImplWinFontData* pWinFont = static_cast<const ImplWinFontData*>(pFace);
+ const ImplFontCharMap* pCharMap = pWinFont->GetImplFontCharMap();
+ if( !pCharMap )
+ {
+ // construct a Size structure as the parameter of constructor of class ImplFontSelectData
+ const Size aSize( pFace->GetWidth(), pFace->GetHeight() );
+ // create a ImplFontSelectData object for getting s LOGFONT
+ const ImplFontSelectData aFSD( *pFace, aSize, (float)aSize.Height(), 0, false );
+ // construct log font
+ LOGFONTW aLogFont;
+ ImplGetLogFontFromFontSelect( mhDC, &aFSD, aLogFont, true );
+
+ // create HFONT from log font
+ HFONT hNewFont = ::CreateFontIndirectW( &aLogFont );
+ // select the new font into device
+ HFONT hOldFont = ::SelectFont( mhDC, hNewFont );
+
+ // read CMAP table to update their pCharMap
+ pWinFont->UpdateFromHDC( mhDC );;
+
+ // cleanup temporary font
+ ::SelectFont( mhDC, hOldFont );
+ ::DeleteFont( hNewFont );
+
+ // get the new charmap
+ pCharMap = pWinFont->GetImplFontCharMap();
+ }
+
+ // avoid fonts with unknown CMAP subtables for glyph fallback
+ if( !pCharMap || pCharMap->IsDefaultMap() )
+ return false;
+
+ int nMatchCount = 0;
+ // static const int nMaxMatchCount = 1; // TODO: check more missing characters?
+ const sal_Int32 nStrLen = rMissingChars.getLength();
+ for( sal_Int32 nStrIdx = 0; nStrIdx < nStrLen; ++nStrIdx )
+ {
+ const sal_UCS4 uChar = rMissingChars.iterateCodePoints( &nStrIdx );
+ nMatchCount += pCharMap->HasChar( uChar );
+ break; // for now
+ }
+
+ const bool bHasMatches = (nMatchCount > 0);
+ return bHasMatches;
+}
+
+// find a fallback font for missing characters
+// TODO: should stylistic matches be searched and prefered?
+bool WinGlyphFallbackSubstititution::FindFontSubstitute( ImplFontSelectData& rFontSelData, rtl::OUString& rMissingChars ) const
+{
+ // guess a locale matching to the missing chars
+ com::sun::star::lang::Locale aLocale;
+
+ sal_Int32 nStrIdx = 0;
+ const sal_Int32 nStrLen = rMissingChars.getLength();
+ while( nStrIdx < nStrLen )
+ {
+ const sal_UCS4 uChar = rMissingChars.iterateCodePoints( &nStrIdx );
+ const LanguageType eLang = MapCharToLanguage( uChar );
+ if( eLang == LANGUAGE_DONTKNOW )
+ continue;
+ MsLangId::convertLanguageToLocale( eLang, aLocale );
+ break;
+ }
+
+ // fall back to default UI locale if the missing characters are inconclusive
+ if( nStrIdx >= nStrLen )
+ aLocale = Application::GetSettings().GetUILocale();
+
+ // first level fallback:
+ // try use the locale specific default fonts defined in VCL.xcu
+ const ImplDevFontList* pDevFontList = ImplGetSVData()->maGDIData.mpScreenFontList;
+ /*const*/ ImplDevFontListData* pDevFont = pDevFontList->ImplFindByLocale( aLocale );
+ if( pDevFont )
+ {
+ const ImplFontData* pFace = pDevFont->FindBestFontFace( rFontSelData );
+ if( HasMissingChars( pFace, rMissingChars ) )
+ {
+ rFontSelData.maSearchName = pDevFont->GetSearchName();
+ return true;
+ }
+ }
+
+ // are the missing characters symbols?
+ pDevFont = pDevFontList->ImplFindByAttributes( IMPL_FONT_ATTR_SYMBOL,
+ rFontSelData.meWeight, rFontSelData.meWidthType,
+ rFontSelData.meFamily, rFontSelData.meItalic, rFontSelData.maSearchName );
+ if( pDevFont )
+ {
+ const ImplFontData* pFace = pDevFont->FindBestFontFace( rFontSelData );
+ if( HasMissingChars( pFace, rMissingChars ) )
+ {
+ rFontSelData.maSearchName = pDevFont->GetSearchName();
+ return true;
+ }
+ }
+
+ // last level fallback, check each font type face one by one
+ const ImplGetDevFontList* pTestFontList = pDevFontList->GetDevFontList();
+ // limit the count of fonts to be checked to prevent hangs
+ static const int MAX_GFBFONT_COUNT = 600;
+ int nTestFontCount = pTestFontList->Count();
+ if( nTestFontCount > MAX_GFBFONT_COUNT )
+ nTestFontCount = MAX_GFBFONT_COUNT;
+
+ for( int i = 0; i < nTestFontCount; ++i )
+ {
+ const ImplFontData* pFace = pTestFontList->Get( i );
+ if( !HasMissingChars( pFace, rMissingChars ) )
+ continue;
+ rFontSelData.maSearchName = pFace->maName;
+ return true;
+ }
+
+ return false;
+}
+
+// =======================================================================
+
+struct ImplEnumInfo
+{
+ HDC mhDC;
+ ImplDevFontList* mpList;
+ String* mpName;
+ LOGFONTA* mpLogFontA;
+ LOGFONTW* mpLogFontW;
+ UINT mnPreferedCharSet;
+ bool mbCourier;
+ bool mbImplSalCourierScalable;
+ bool mbImplSalCourierNew;
+ bool mbPrinter;
+ int mnFontCount;
+};
+
+// =======================================================================
+
+static CharSet ImplCharSetToSal( BYTE nCharSet )
+{
+ rtl_TextEncoding eTextEncoding;
+
+ if ( nCharSet == OEM_CHARSET )
+ {
+ UINT nCP = (USHORT)GetOEMCP();
+ switch ( nCP )
+ {
+ // It is unclear why these two (undefined?) code page numbers are
+ // handled specially here:
+ case 1004: eTextEncoding = RTL_TEXTENCODING_MS_1252; break;
+ case 65400: eTextEncoding = RTL_TEXTENCODING_SYMBOL; break;
+ default:
+ eTextEncoding = rtl_getTextEncodingFromWindowsCodePage(nCP);
+ break;
+ };
+ }
+ else
+ {
+ if( nCharSet )
+ eTextEncoding = rtl_getTextEncodingFromWindowsCharset( nCharSet );
+ else
+ eTextEncoding = RTL_TEXTENCODING_UNICODE;
+ }
+
+ return eTextEncoding;
+}
+
+// -----------------------------------------------------------------------
+
+static FontFamily ImplFamilyToSal( BYTE nFamily )
+{
+ switch ( nFamily & 0xF0 )
+ {
+ case FF_DECORATIVE:
+ return FAMILY_DECORATIVE;
+
+ case FF_MODERN:
+ return FAMILY_MODERN;
+
+ case FF_ROMAN:
+ return FAMILY_ROMAN;
+
+ case FF_SCRIPT:
+ return FAMILY_SCRIPT;
+
+ case FF_SWISS:
+ return FAMILY_SWISS;
+
+ default:
+ break;
+ }
+
+ return FAMILY_DONTKNOW;
+}
+
+// -----------------------------------------------------------------------
+
+static BYTE ImplFamilyToWin( FontFamily eFamily )
+{
+ switch ( eFamily )
+ {
+ case FAMILY_DECORATIVE:
+ return FF_DECORATIVE;
+
+ case FAMILY_MODERN:
+ return FF_MODERN;
+
+ case FAMILY_ROMAN:
+ return FF_ROMAN;
+
+ case FAMILY_SCRIPT:
+ return FF_SCRIPT;
+
+ case FAMILY_SWISS:
+ return FF_SWISS;
+
+ case FAMILY_SYSTEM:
+ return FF_SWISS;
+
+ default:
+ break;
+ }
+
+ return FF_DONTCARE;
+}
+
+// -----------------------------------------------------------------------
+
+static FontWeight ImplWeightToSal( int nWeight )
+{
+ if ( nWeight <= FW_THIN )
+ return WEIGHT_THIN;
+ else if ( nWeight <= FW_ULTRALIGHT )
+ return WEIGHT_ULTRALIGHT;
+ else if ( nWeight <= FW_LIGHT )
+ return WEIGHT_LIGHT;
+ else if ( nWeight < FW_MEDIUM )
+ return WEIGHT_NORMAL;
+ else if ( nWeight == FW_MEDIUM )
+ return WEIGHT_MEDIUM;
+ else if ( nWeight <= FW_SEMIBOLD )
+ return WEIGHT_SEMIBOLD;
+ else if ( nWeight <= FW_BOLD )
+ return WEIGHT_BOLD;
+ else if ( nWeight <= FW_ULTRABOLD )
+ return WEIGHT_ULTRABOLD;
+ else
+ return WEIGHT_BLACK;
+}
+
+// -----------------------------------------------------------------------
+
+static int ImplWeightToWin( FontWeight eWeight )
+{
+ switch ( eWeight )
+ {
+ case WEIGHT_THIN:
+ return FW_THIN;
+
+ case WEIGHT_ULTRALIGHT:
+ return FW_ULTRALIGHT;
+
+ case WEIGHT_LIGHT:
+ return FW_LIGHT;
+
+ case WEIGHT_SEMILIGHT:
+ case WEIGHT_NORMAL:
+ return FW_NORMAL;
+
+ case WEIGHT_MEDIUM:
+ return FW_MEDIUM;
+
+ case WEIGHT_SEMIBOLD:
+ return FW_SEMIBOLD;
+
+ case WEIGHT_BOLD:
+ return FW_BOLD;
+
+ case WEIGHT_ULTRABOLD:
+ return FW_ULTRABOLD;
+
+ case WEIGHT_BLACK:
+ return FW_BLACK;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+inline FontPitch ImplLogPitchToSal( BYTE nPitch )
+{
+ if ( nPitch & FIXED_PITCH )
+ return PITCH_FIXED;
+ else
+ return PITCH_VARIABLE;
+}
+
+// -----------------------------------------------------------------------
+
+inline FontPitch ImplMetricPitchToSal( BYTE nPitch )
+{
+ // Sausaecke bei MS !! siehe NT Hilfe
+ if ( !(nPitch & TMPF_FIXED_PITCH) )
+ return PITCH_FIXED;
+ else
+ return PITCH_VARIABLE;
+}
+
+// -----------------------------------------------------------------------
+
+inline BYTE ImplPitchToWin( FontPitch ePitch )
+{
+ if ( ePitch == PITCH_FIXED )
+ return FIXED_PITCH;
+ else if ( ePitch == PITCH_VARIABLE )
+ return VARIABLE_PITCH;
+ else
+ return DEFAULT_PITCH;
+}
+
+// -----------------------------------------------------------------------
+
+static ImplDevFontAttributes WinFont2DevFontAttributes( const ENUMLOGFONTEXA& rEnumFont,
+ const NEWTEXTMETRICA& rMetric, DWORD nFontType )
+{
+ ImplDevFontAttributes aDFA;
+
+ const LOGFONTA rLogFont = rEnumFont.elfLogFont;
+
+ // get font face attributes
+ aDFA.meFamily = ImplFamilyToSal( rLogFont.lfPitchAndFamily );
+ aDFA.meWidthType = WIDTH_DONTKNOW;
+ aDFA.meWeight = ImplWeightToSal( rLogFont.lfWeight );
+ aDFA.meItalic = (rLogFont.lfItalic) ? ITALIC_NORMAL : ITALIC_NONE;
+ aDFA.mePitch = ImplLogPitchToSal( rLogFont.lfPitchAndFamily );
+ aDFA.mbSymbolFlag = (rLogFont.lfCharSet == SYMBOL_CHARSET);
+
+ // get the font face name
+ aDFA.maName = ImplSalGetUniString( rLogFont.lfFaceName );
+
+ // use the face's style name only if it looks reasonable
+ const char* pStyleName = (const char*)rEnumFont.elfStyle;
+ const char* pEnd = pStyleName + sizeof( rEnumFont.elfStyle );
+ const char* p = pStyleName;
+ for(; *p && (p < pEnd); ++p )
+ if( (0x00 < *p) && (*p < 0x20) )
+ break;
+ if( p < pEnd )
+ aDFA.maStyleName = ImplSalGetUniString( pStyleName );
+
+ // get device specific font attributes
+ aDFA.mbOrientation = (nFontType & RASTER_FONTTYPE) == 0;
+ aDFA.mbDevice = (rMetric.tmPitchAndFamily & TMPF_DEVICE) != 0;
+
+ aDFA.mbEmbeddable = false;
+ aDFA.mbSubsettable = false;
+ if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE))
+ || 0 != (rMetric.tmPitchAndFamily & TMPF_TRUETYPE))
+ aDFA.mbSubsettable = true;
+ else if( 0 != (rMetric.ntmFlags & NTM_TYPE1) ) // TODO: implement subsetting for type1 too
+ aDFA.mbEmbeddable = true;
+
+ // heuristics for font quality
+ // - standard-type1 > opentypeTT > truetype > non-standard-type1 > raster
+ // - subsetting > embedding > none
+ aDFA.mnQuality = 0;
+ if( rMetric.tmPitchAndFamily & TMPF_TRUETYPE )
+ aDFA.mnQuality += 50;
+ if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE)) )
+ aDFA.mnQuality += 10;
+ if( aDFA.mbSubsettable )
+ aDFA.mnQuality += 200;
+ else if( aDFA.mbEmbeddable )
+ aDFA.mnQuality += 100;
+
+ // #i38665# prefer Type1 versions of the standard postscript fonts
+ if( aDFA.mbEmbeddable )
+ {
+ if( aDFA.maName.EqualsAscii( "AvantGarde" )
+ || aDFA.maName.EqualsAscii( "Bookman" )
+ || aDFA.maName.EqualsAscii( "Courier" )
+ || aDFA.maName.EqualsAscii( "Helvetica" )
+ || aDFA.maName.EqualsAscii( "NewCenturySchlbk" )
+ || aDFA.maName.EqualsAscii( "Palatino" )
+ || aDFA.maName.EqualsAscii( "Symbol" )
+ || aDFA.maName.EqualsAscii( "Times" )
+ || aDFA.maName.EqualsAscii( "ZapfChancery" )
+ || aDFA.maName.EqualsAscii( "ZapfDingbats" ) )
+ aDFA.mnQuality += 500;
+ }
+
+ // TODO: add alias names
+ return aDFA;
+}
+
+// -----------------------------------------------------------------------
+
+static ImplDevFontAttributes WinFont2DevFontAttributes( const ENUMLOGFONTEXW& rEnumFont,
+ const NEWTEXTMETRICW& rMetric, DWORD nFontType )
+{
+ ImplDevFontAttributes aDFA;
+
+ const LOGFONTW rLogFont = rEnumFont.elfLogFont;
+
+ // get font face attributes
+ aDFA.meFamily = ImplFamilyToSal( rLogFont.lfPitchAndFamily );
+ aDFA.meWidthType = WIDTH_DONTKNOW;
+ aDFA.meWeight = ImplWeightToSal( rLogFont.lfWeight );
+ aDFA.meItalic = (rLogFont.lfItalic) ? ITALIC_NORMAL : ITALIC_NONE;
+ aDFA.mePitch = ImplLogPitchToSal( rLogFont.lfPitchAndFamily );
+ aDFA.mbSymbolFlag = (rLogFont.lfCharSet == SYMBOL_CHARSET);
+
+ // get the font face name
+ aDFA.maName = reinterpret_cast<const sal_Unicode*>(rLogFont.lfFaceName);
+
+ // use the face's style name only if it looks reasonable
+ const wchar_t* pStyleName = rEnumFont.elfStyle;
+ const wchar_t* pEnd = pStyleName + sizeof(rEnumFont.elfStyle)/sizeof(*rEnumFont.elfStyle);
+ const wchar_t* p = pStyleName;
+ for(; *p && (p < pEnd); ++p )
+ if( *p < 0x0020 )
+ break;
+ if( p < pEnd )
+ aDFA.maStyleName = reinterpret_cast<const sal_Unicode*>(pStyleName);
+
+ // get device specific font attributes
+ aDFA.mbOrientation = (nFontType & RASTER_FONTTYPE) == 0;
+ aDFA.mbDevice = (rMetric.tmPitchAndFamily & TMPF_DEVICE) != 0;
+
+ aDFA.mbEmbeddable = false;
+ aDFA.mbSubsettable = false;
+ if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE))
+ || 0 != (rMetric.tmPitchAndFamily & TMPF_TRUETYPE))
+ aDFA.mbSubsettable = true;
+ else if( 0 != (rMetric.ntmFlags & NTM_TYPE1) ) // TODO: implement subsetting for type1 too
+ aDFA.mbEmbeddable = true;
+
+ // heuristics for font quality
+ // - standard-type1 > opentypeTT > truetype > non-standard-type1 > raster
+ // - subsetting > embedding > none
+ aDFA.mnQuality = 0;
+ if( rMetric.tmPitchAndFamily & TMPF_TRUETYPE )
+ aDFA.mnQuality += 50;
+ if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE)) )
+ aDFA.mnQuality += 10;
+ if( aDFA.mbSubsettable )
+ aDFA.mnQuality += 200;
+ else if( aDFA.mbEmbeddable )
+ aDFA.mnQuality += 100;
+
+ // #i38665# prefer Type1 versions of the standard postscript fonts
+ if( aDFA.mbEmbeddable )
+ {
+ if( aDFA.maName.EqualsAscii( "AvantGarde" )
+ || aDFA.maName.EqualsAscii( "Bookman" )
+ || aDFA.maName.EqualsAscii( "Courier" )
+ || aDFA.maName.EqualsAscii( "Helvetica" )
+ || aDFA.maName.EqualsAscii( "NewCenturySchlbk" )
+ || aDFA.maName.EqualsAscii( "Palatino" )
+ || aDFA.maName.EqualsAscii( "Symbol" )
+ || aDFA.maName.EqualsAscii( "Times" )
+ || aDFA.maName.EqualsAscii( "ZapfChancery" )
+ || aDFA.maName.EqualsAscii( "ZapfDingbats" ) )
+ aDFA.mnQuality += 500;
+ }
+
+ // TODO: add alias names
+ return aDFA;
+}
+
+// -----------------------------------------------------------------------
+
+static ImplWinFontData* ImplLogMetricToDevFontDataA( const ENUMLOGFONTEXA* pLogFont,
+ const NEWTEXTMETRICA* pMetric,
+ DWORD nFontType )
+{
+ int nHeight = 0;
+ if ( nFontType & RASTER_FONTTYPE )
+ nHeight = pMetric->tmHeight - pMetric->tmInternalLeading;
+
+ ImplWinFontData* pData = new ImplWinFontData(
+ WinFont2DevFontAttributes(*pLogFont, *pMetric, nFontType),
+ nHeight,
+ pLogFont->elfLogFont.lfCharSet,
+ pMetric->tmPitchAndFamily );
+
+ return pData;
+}
+
+// -----------------------------------------------------------------------
+
+static ImplWinFontData* ImplLogMetricToDevFontDataW( const ENUMLOGFONTEXW* pLogFont,
+ const NEWTEXTMETRICW* pMetric,
+ DWORD nFontType )
+{
+ int nHeight = 0;
+ if ( nFontType & RASTER_FONTTYPE )
+ nHeight = pMetric->tmHeight - pMetric->tmInternalLeading;
+
+ ImplWinFontData* pData = new ImplWinFontData(
+ WinFont2DevFontAttributes(*pLogFont, *pMetric, nFontType),
+ nHeight,
+ pLogFont->elfLogFont.lfCharSet,
+ pMetric->tmPitchAndFamily );
+
+ return pData;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplSalLogFontToFontA( HDC hDC, const LOGFONTA& rLogFont, Font& rFont )
+{
+ String aFontName( ImplSalGetUniString( rLogFont.lfFaceName ) );
+ if ( aFontName.Len() )
+ {
+ rFont.SetName( aFontName );
+ rFont.SetCharSet( ImplCharSetToSal( rLogFont.lfCharSet ) );
+ rFont.SetFamily( ImplFamilyToSal( rLogFont.lfPitchAndFamily ) );
+ rFont.SetPitch( ImplLogPitchToSal( rLogFont.lfPitchAndFamily ) );
+ rFont.SetWeight( ImplWeightToSal( rLogFont.lfWeight ) );
+
+ long nFontHeight = rLogFont.lfHeight;
+ if ( nFontHeight < 0 )
+ nFontHeight = -nFontHeight;
+ long nDPIY = GetDeviceCaps( hDC, LOGPIXELSY );
+ if( !nDPIY )
+ nDPIY = 600;
+ nFontHeight *= 72;
+ nFontHeight += nDPIY/2;
+ nFontHeight /= nDPIY;
+ rFont.SetSize( Size( 0, nFontHeight ) );
+ rFont.SetOrientation( (short)rLogFont.lfEscapement );
+ if ( rLogFont.lfItalic )
+ rFont.SetItalic( ITALIC_NORMAL );
+ else
+ rFont.SetItalic( ITALIC_NONE );
+ if ( rLogFont.lfUnderline )
+ rFont.SetUnderline( UNDERLINE_SINGLE );
+ else
+ rFont.SetUnderline( UNDERLINE_NONE );
+ if ( rLogFont.lfStrikeOut )
+ rFont.SetStrikeout( STRIKEOUT_SINGLE );
+ else
+ rFont.SetStrikeout( STRIKEOUT_NONE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplSalLogFontToFontW( HDC hDC, const LOGFONTW& rLogFont, Font& rFont )
+{
+ XubString aFontName( reinterpret_cast<const xub_Unicode*>(rLogFont.lfFaceName) );
+ if ( aFontName.Len() )
+ {
+ rFont.SetName( aFontName );
+ rFont.SetCharSet( ImplCharSetToSal( rLogFont.lfCharSet ) );
+ rFont.SetFamily( ImplFamilyToSal( rLogFont.lfPitchAndFamily ) );
+ rFont.SetPitch( ImplLogPitchToSal( rLogFont.lfPitchAndFamily ) );
+ rFont.SetWeight( ImplWeightToSal( rLogFont.lfWeight ) );
+
+ long nFontHeight = rLogFont.lfHeight;
+ if ( nFontHeight < 0 )
+ nFontHeight = -nFontHeight;
+ long nDPIY = GetDeviceCaps( hDC, LOGPIXELSY );
+ if( !nDPIY )
+ nDPIY = 600;
+ nFontHeight *= 72;
+ nFontHeight += nDPIY/2;
+ nFontHeight /= nDPIY;
+ rFont.SetSize( Size( 0, nFontHeight ) );
+ rFont.SetOrientation( (short)rLogFont.lfEscapement );
+ if ( rLogFont.lfItalic )
+ rFont.SetItalic( ITALIC_NORMAL );
+ else
+ rFont.SetItalic( ITALIC_NONE );
+ if ( rLogFont.lfUnderline )
+ rFont.SetUnderline( UNDERLINE_SINGLE );
+ else
+ rFont.SetUnderline( UNDERLINE_NONE );
+ if ( rLogFont.lfStrikeOut )
+ rFont.SetStrikeout( STRIKEOUT_SINGLE );
+ else
+ rFont.SetStrikeout( STRIKEOUT_NONE );
+ }
+}
+
+// =======================================================================
+
+ImplWinFontData::ImplWinFontData( const ImplDevFontAttributes& rDFS,
+ int nHeight, WIN_BYTE eWinCharSet, WIN_BYTE nPitchAndFamily )
+: ImplFontData( rDFS, 0 ),
+ meWinCharSet( eWinCharSet ),
+ mnPitchAndFamily( nPitchAndFamily ),
+ mpFontCharSets( NULL ),
+ mpUnicodeMap( NULL ),
+ mbGsubRead( false ),
+ mbDisableGlyphApi( false ),
+ mbHasKoreanRange( false ),
+ mbHasCJKSupport( false ),
+#ifdef ENABLE_GRAPHITE
+ mbHasGraphiteSupport( false ),
+#endif
+ mbHasArabicSupport ( false ),
+ mbAliasSymbolsLow( false ),
+ mbAliasSymbolsHigh( false ),
+ mnId( 0 ),
+ mpEncodingVector( NULL )
+{
+ SetBitmapSize( 0, nHeight );
+
+ if( eWinCharSet == SYMBOL_CHARSET )
+ {
+ if( (nPitchAndFamily & TMPF_TRUETYPE) != 0 )
+ {
+ // truetype fonts need their symbols as U+F0xx
+ mbAliasSymbolsHigh = true;
+ }
+ else if( (nPitchAndFamily & (TMPF_VECTOR|TMPF_DEVICE))
+ == (TMPF_VECTOR|TMPF_DEVICE) )
+ {
+ // scalable device fonts (e.g. builtin printer fonts)
+ // need their symbols as U+00xx
+ mbAliasSymbolsLow = true;
+ }
+ else if( (nPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE)) == 0 )
+ {
+ // bitmap fonts need their symbols as U+F0xx
+ mbAliasSymbolsHigh = true;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ImplWinFontData::~ImplWinFontData()
+{
+ delete[] mpFontCharSets;
+
+ if( mpUnicodeMap )
+ mpUnicodeMap->DeReference();
+ delete mpEncodingVector;
+}
+
+// -----------------------------------------------------------------------
+
+sal_IntPtr ImplWinFontData::GetFontId() const
+{
+ return mnId;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplWinFontData::UpdateFromHDC( HDC hDC ) const
+{
+ // short circuit if already initialized
+ if( mpUnicodeMap != NULL )
+ return;
+
+ ReadCmapTable( hDC );
+ ReadOs2Table( hDC );
+#ifdef ENABLE_GRAPHITE
+ static const char* pDisableGraphiteText = getenv( "SAL_DISABLE_GRAPHITE" );
+ if( !pDisableGraphiteText || (pDisableGraphiteText[0] == '0') )
+ {
+ mbHasGraphiteSupport = gr::WinFont::FontHasGraphiteTables(hDC);
+ }
+#endif
+
+ // even if the font works some fonts have problems with the glyph API
+ // => the heuristic below tries to figure out which fonts have the problem
+ TEXTMETRICA aTextMetric;
+ if( ::GetTextMetricsA( hDC, &aTextMetric ) )
+ if( !(aTextMetric.tmPitchAndFamily & TMPF_TRUETYPE)
+ || (aTextMetric.tmPitchAndFamily & TMPF_DEVICE) )
+ mbDisableGlyphApi = true;
+
+#if 0
+ // #110548# more important than #107885# => TODO: better solution
+ DWORD nFLI = GetFontLanguageInfo( hDC );
+ if( 0 == (nFLI & GCP_GLYPHSHAPE) )
+ mbDisableGlyphApi = true;
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+bool ImplWinFontData::HasGSUBstitutions( HDC hDC ) const
+{
+ if( !mbGsubRead )
+ ReadGsubTable( hDC );
+ return !maGsubTable.empty();
+}
+
+// -----------------------------------------------------------------------
+
+bool ImplWinFontData::IsGSUBstituted( sal_UCS4 cChar ) const
+{
+ return( maGsubTable.find( cChar ) != maGsubTable.end() );
+}
+
+// -----------------------------------------------------------------------
+
+ImplFontCharMap* ImplWinFontData::GetImplFontCharMap() const
+{
+ if( !mpUnicodeMap )
+ return NULL;
+ mpUnicodeMap->AddReference();
+ return mpUnicodeMap;
+}
+
+// -----------------------------------------------------------------------
+
+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]));}
+static inline DWORD CalcTag( const char p[4]) { return (p[0]+(p[1]<<8)+(p[2]<<16)+(p[3]<<24)); }
+
+void ImplWinFontData::ReadOs2Table( HDC hDC ) const
+{
+ const DWORD Os2Tag = CalcTag( "OS/2" );
+ DWORD nLength = ::GetFontData( hDC, Os2Tag, 0, NULL, 0 );
+ if( (nLength == GDI_ERROR) || !nLength )
+ return;
+ std::vector<unsigned char> aOS2map( nLength );
+ unsigned char* pOS2map = &aOS2map[0];
+ ::GetFontData( hDC, Os2Tag, 0, pOS2map, nLength );
+ sal_uInt32 nVersion = GetUShort( pOS2map );
+ if ( nVersion >= 0x0001 && nLength >= 58 )
+ {
+ // We need at least version 0x0001 (TrueType rev 1.66)
+ // to have access to the needed struct members.
+ sal_uInt32 ulUnicodeRange1 = GetUInt( pOS2map + 42 );
+ sal_uInt32 ulUnicodeRange2 = GetUInt( pOS2map + 46 );
+#if 0
+ sal_uInt32 ulUnicodeRange3 = GetUInt( pOS2map + 50 );
+ sal_uInt32 ulUnicodeRange4 = GetUInt( pOS2map + 54 );
+#endif
+
+ // Check for CJK capabilities of the current font
+ mbHasCJKSupport = (ulUnicodeRange2 & 0x2DF00000);
+ mbHasKoreanRange= (ulUnicodeRange1 & 0x10000000)
+ | (ulUnicodeRange2 & 0x01100000);
+ mbHasArabicSupport = (ulUnicodeRange1 & 0x00002000);
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplWinFontData::ReadGsubTable( HDC hDC ) const
+{
+ mbGsubRead = true;
+
+ // check the existence of a GSUB table
+ const DWORD GsubTag = CalcTag( "GSUB" );
+ DWORD nRC = ::GetFontData( hDC, GsubTag, 0, NULL, 0 );
+ if( (nRC == GDI_ERROR) || !nRC )
+ return;
+
+ // parse the GSUB table through sft
+ // TODO: parse it directly
+
+ // sft needs the full font file data => get it
+ const RawFontData aRawFontData( hDC );
+ if( !aRawFontData.get() )
+ return;
+
+ // open font file
+ sal_uInt32 nFaceNum = 0;
+ if( !*aRawFontData.get() ) // TTC candidate
+ nFaceNum = ~0U; // indicate "TTC font extracts only"
+
+ TrueTypeFont* pTTFont = NULL;
+ ::OpenTTFontBuffer( (void*)aRawFontData.get(), aRawFontData.size(), nFaceNum, &pTTFont );
+ if( !pTTFont )
+ return;
+
+ // add vertically substituted characters to list
+ static const sal_Unicode aGSUBCandidates[] = {
+ 0x0020, 0x0080, // ASCII
+ 0x2000, 0x2600, // misc
+ 0x3000, 0x3100, // CJK punctutation
+ 0x3300, 0x3400, // squared words
+ 0xFF00, 0xFFF0, // halfwidth|fullwidth forms
+ 0 };
+
+ for( const sal_Unicode* pPair = aGSUBCandidates; *pPair; pPair += 2 )
+ for( sal_Unicode cChar = pPair[0]; cChar < pPair[1]; ++cChar )
+ if( ::MapChar( pTTFont, cChar, 0 ) != ::MapChar( pTTFont, cChar, 1 ) )
+ maGsubTable.insert( cChar ); // insert GSUBbed unicodes
+
+ CloseTTFont( pTTFont );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplWinFontData::ReadCmapTable( HDC hDC ) const
+{
+ if( mpUnicodeMap != NULL )
+ return;
+
+ bool bIsSymbolFont = (meWinCharSet == SYMBOL_CHARSET);
+ // get the CMAP table from the font which is selected into the DC
+ const DWORD nCmapTag = CalcTag( "cmap" );
+ const RawFontData aRawFontData( hDC, nCmapTag );
+ // parse the CMAP table if available
+ if( aRawFontData.get() ) {
+ CmapResult aResult;
+ ParseCMAP( aRawFontData.get(), aRawFontData.size(), aResult );
+ mbDisableGlyphApi |= aResult.mbRecoded;
+ aResult.mbSymbolic = bIsSymbolFont;
+ if( aResult.mnRangeCount > 0 )
+ mpUnicodeMap = new ImplFontCharMap( aResult );
+ }
+
+ if( !mpUnicodeMap )
+ mpUnicodeMap = ImplFontCharMap::GetDefaultMap( bIsSymbolFont );
+}
+
+// =======================================================================
+
+void WinSalGraphics::SetTextColor( SalColor nSalColor )
+{
+ COLORREF aCol = PALETTERGB( SALCOLOR_RED( nSalColor ),
+ SALCOLOR_GREEN( nSalColor ),
+ SALCOLOR_BLUE( nSalColor ) );
+
+ if( !mbPrinter &&
+ GetSalData()->mhDitherPal &&
+ ImplIsSysColorEntry( nSalColor ) )
+ {
+ aCol = PALRGB_TO_RGB( aCol );
+ }
+
+ ::SetTextColor( mhDC, aCol );
+}
+
+// -----------------------------------------------------------------------
+
+int CALLBACK SalEnumQueryFontProcExW( const ENUMLOGFONTEXW*,
+ const NEWTEXTMETRICEXW*,
+ DWORD, LPARAM lParam )
+{
+ *((bool*)(void*)lParam) = true;
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+int CALLBACK SalEnumQueryFontProcExA( const ENUMLOGFONTEXA*,
+ const NEWTEXTMETRICEXA*,
+ DWORD, LPARAM lParam )
+{
+ *((bool*)(void*)lParam) = true;
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+bool ImplIsFontAvailable( HDC hDC, const UniString& rName )
+{
+ bool bAvailable = false;
+
+ if ( aSalShlData.mbWNT )
+ {
+ // Test, if Font available
+ LOGFONTW aLogFont;
+ memset( &aLogFont, 0, sizeof( aLogFont ) );
+ aLogFont.lfCharSet = DEFAULT_CHARSET;
+
+ UINT nNameLen = rName.Len();
+ if ( nNameLen > (sizeof( aLogFont.lfFaceName )/sizeof( wchar_t ))-1 )
+ nNameLen = (sizeof( aLogFont.lfFaceName )/sizeof( wchar_t ))-1;
+ memcpy( aLogFont.lfFaceName, rName.GetBuffer(), nNameLen*sizeof( wchar_t ) );
+ aLogFont.lfFaceName[nNameLen] = 0;
+
+ EnumFontFamiliesExW( hDC, &aLogFont, (FONTENUMPROCW)SalEnumQueryFontProcExW,
+ (LPARAM)(void*)&bAvailable, 0 );
+ }
+ else
+ {
+ ByteString aTemp = ImplSalGetWinAnsiString( rName );
+
+ // Test, if Font available
+ LOGFONTA aLogFont;
+ memset( &aLogFont, 0, sizeof( aLogFont ) );
+ aLogFont.lfCharSet = DEFAULT_CHARSET;
+
+ UINT nNameLen = aTemp.Len();
+ if ( nNameLen > sizeof( aLogFont.lfFaceName )-1 )
+ nNameLen = sizeof( aLogFont.lfFaceName )-1;
+ memcpy( aLogFont.lfFaceName, aTemp.GetBuffer(), nNameLen );
+ aLogFont.lfFaceName[nNameLen] = 0;
+
+ EnumFontFamiliesExA( hDC, &aLogFont, (FONTENUMPROCA)SalEnumQueryFontProcExA,
+ (LPARAM)(void*)&bAvailable, 0 );
+ }
+
+ return bAvailable;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplGetLogFontFromFontSelect( HDC hDC,
+ const ImplFontSelectData* pFont,
+ LOGFONTW& rLogFont,
+ bool /*bTestVerticalAvail*/ )
+{
+ UniString aName;
+ if ( pFont->mpFontData )
+ aName = pFont->mpFontData->maName;
+ else
+ aName = pFont->maName.GetToken( 0 );
+
+ UINT nNameLen = aName.Len();
+ if ( nNameLen > (sizeof( rLogFont.lfFaceName )/sizeof( wchar_t ))-1 )
+ nNameLen = (sizeof( rLogFont.lfFaceName )/sizeof( wchar_t ))-1;
+ memcpy( rLogFont.lfFaceName, aName.GetBuffer(), nNameLen*sizeof( wchar_t ) );
+ rLogFont.lfFaceName[nNameLen] = 0;
+
+ if( !pFont->mpFontData )
+ {
+ rLogFont.lfCharSet = pFont->IsSymbolFont() ? SYMBOL_CHARSET : DEFAULT_CHARSET;
+ rLogFont.lfPitchAndFamily = ImplPitchToWin( pFont->mePitch )
+ | ImplFamilyToWin( pFont->meFamily );
+ }
+ else
+ {
+ const ImplWinFontData* pWinFontData = static_cast<const ImplWinFontData*>( pFont->mpFontData );
+ rLogFont.lfCharSet = pWinFontData->GetCharSet();
+ rLogFont.lfPitchAndFamily = pWinFontData->GetPitchAndFamily();
+ }
+
+ rLogFont.lfWeight = ImplWeightToWin( pFont->meWeight );
+ rLogFont.lfHeight = (LONG)-pFont->mnHeight;
+ rLogFont.lfWidth = (LONG)pFont->mnWidth;
+ rLogFont.lfUnderline = 0;
+ rLogFont.lfStrikeOut = 0;
+ rLogFont.lfItalic = (pFont->meItalic) != ITALIC_NONE;
+ rLogFont.lfEscapement = pFont->mnOrientation;
+ rLogFont.lfOrientation = rLogFont.lfEscapement;
+ rLogFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ rLogFont.lfQuality = DEFAULT_QUALITY;
+ rLogFont.lfOutPrecision = OUT_TT_PRECIS;
+ if ( pFont->mnOrientation )
+ rLogFont.lfClipPrecision |= CLIP_LH_ANGLES;
+
+ // disable antialiasing if requested
+ if ( pFont->mbNonAntialiased )
+ rLogFont.lfQuality = NONANTIALIASED_QUALITY;
+
+ // select vertical mode if requested and available
+ if( pFont->mbVertical && nNameLen )
+ {
+ // vertical fonts start with an '@'
+ memmove( &rLogFont.lfFaceName[1], &rLogFont.lfFaceName[0],
+ sizeof(rLogFont.lfFaceName)-sizeof(rLogFont.lfFaceName[0]) );
+ rLogFont.lfFaceName[0] = '@';
+
+ // check availability of vertical mode for this font
+ bool bAvailable = false;
+ EnumFontFamiliesExW( hDC, &rLogFont, (FONTENUMPROCW)SalEnumQueryFontProcExW,
+ (LPARAM)&bAvailable, 0 );
+
+ if( !bAvailable )
+ {
+ // restore non-vertical name if not vertical mode isn't available
+ memcpy( &rLogFont.lfFaceName[0], aName.GetBuffer(), nNameLen*sizeof(wchar_t) );
+ if( nNameLen < LF_FACESIZE )
+ rLogFont.lfFaceName[nNameLen] = '\0';
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplGetLogFontFromFontSelect( HDC hDC,
+ const ImplFontSelectData* pFont,
+ LOGFONTA& rLogFont,
+ bool /*bTestVerticalAvail*/ )
+{
+ ByteString aName;
+ if( pFont->mpFontData )
+ aName = ImplSalGetWinAnsiString( pFont->mpFontData->maName );
+ else
+ aName = ImplSalGetWinAnsiString( pFont->maName.GetToken( 0 ) );
+
+ int nNameLen = aName.Len();
+ if( nNameLen > LF_FACESIZE )
+ nNameLen = LF_FACESIZE;
+ memcpy( rLogFont.lfFaceName, aName.GetBuffer(), nNameLen );
+ if( nNameLen < LF_FACESIZE )
+ rLogFont.lfFaceName[nNameLen] = '\0';
+
+ if( !pFont->mpFontData )
+ {
+ rLogFont.lfCharSet = pFont->IsSymbolFont() ? SYMBOL_CHARSET : DEFAULT_CHARSET;
+ rLogFont.lfPitchAndFamily = ImplPitchToWin( pFont->mePitch )
+ | ImplFamilyToWin( pFont->meFamily );
+ }
+ else
+ {
+ const ImplWinFontData* pWinFontData = static_cast<const ImplWinFontData*>( pFont->mpFontData );
+ rLogFont.lfCharSet = pWinFontData->GetCharSet();
+ rLogFont.lfPitchAndFamily = pWinFontData->GetPitchAndFamily();
+ }
+
+ rLogFont.lfWeight = ImplWeightToWin( pFont->meWeight );
+ rLogFont.lfHeight = (LONG)-pFont->mnHeight;
+ rLogFont.lfWidth = (LONG)pFont->mnWidth;
+ rLogFont.lfUnderline = 0;
+ rLogFont.lfStrikeOut = 0;
+ rLogFont.lfItalic = (pFont->meItalic) != ITALIC_NONE;
+ rLogFont.lfEscapement = pFont->mnOrientation;
+ rLogFont.lfOrientation = rLogFont.lfEscapement; // ignored by W98
+ rLogFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ rLogFont.lfQuality = DEFAULT_QUALITY;
+ rLogFont.lfOutPrecision = OUT_TT_PRECIS;
+ if( pFont->mnOrientation )
+ rLogFont.lfClipPrecision |= CLIP_LH_ANGLES;
+
+ // disable antialiasing if requested
+ if( pFont->mbNonAntialiased )
+ rLogFont.lfQuality = NONANTIALIASED_QUALITY;
+
+ // select vertical mode if requested and available
+ if( pFont->mbVertical && nNameLen )
+ {
+ // vertical fonts start with an '@'
+ memmove( &rLogFont.lfFaceName[1], &rLogFont.lfFaceName[0],
+ sizeof(rLogFont.lfFaceName)-sizeof(rLogFont.lfFaceName[0]) );
+ rLogFont.lfFaceName[0] = '@';
+
+ // check availability of vertical mode for this font
+ bool bAvailable = false;
+ EnumFontFamiliesExA( hDC, &rLogFont, (FONTENUMPROCA)SalEnumQueryFontProcExA,
+ (LPARAM)&bAvailable, 0 );
+
+ if( !bAvailable )
+ {
+ // restore non-vertical name if vertical mode is not supported
+ memcpy( rLogFont.lfFaceName, aName.GetBuffer(), nNameLen );
+ if( nNameLen < LF_FACESIZE )
+ rLogFont.lfFaceName[nNameLen] = '\0';
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+HFONT WinSalGraphics::ImplDoSetFont( ImplFontSelectData* i_pFont, float& o_rFontScale, HFONT& o_rOldFont )
+{
+ HFONT hNewFont = 0;
+
+ HDC hdcScreen = 0;
+ if( mbVirDev )
+ // only required for virtual devices, see below for details
+ hdcScreen = GetDC(0);
+
+ if( aSalShlData.mbWNT )
+ {
+ LOGFONTW aLogFont;
+ ImplGetLogFontFromFontSelect( mhDC, i_pFont, aLogFont, true );
+
+ // on the display we prefer Courier New when Courier is a
+ // bitmap only font and we need to stretch or rotate it
+ if( mbScreen
+ && (i_pFont->mnWidth != 0
+ || i_pFont->mnOrientation != 0
+ || i_pFont->mpFontData == NULL
+ || (i_pFont->mpFontData->GetHeight() != i_pFont->mnHeight))
+ && !bImplSalCourierScalable
+ && bImplSalCourierNew
+ && (ImplSalWICompareAscii( aLogFont.lfFaceName, "Courier" ) == 0) )
+ lstrcpynW( aLogFont.lfFaceName, L"Courier New", 11 );
+
+ // #i47675# limit font requests to MAXFONTHEIGHT
+ // TODO: share MAXFONTHEIGHT font instance
+ if( (-aLogFont.lfHeight <= MAXFONTHEIGHT)
+ && (+aLogFont.lfWidth <= MAXFONTHEIGHT) )
+ {
+ o_rFontScale = 1.0;
+ }
+ else if( -aLogFont.lfHeight >= +aLogFont.lfWidth )
+ {
+ o_rFontScale = -aLogFont.lfHeight / (float)MAXFONTHEIGHT;
+ aLogFont.lfHeight = -MAXFONTHEIGHT;
+ aLogFont.lfWidth = FRound( aLogFont.lfWidth / o_rFontScale );
+ }
+ else // #i95867# also limit font widths
+ {
+ o_rFontScale = +aLogFont.lfWidth / (float)MAXFONTHEIGHT;
+ aLogFont.lfWidth = +MAXFONTHEIGHT;
+ aLogFont.lfHeight = FRound( aLogFont.lfHeight / o_rFontScale );
+ }
+
+ hNewFont = ::CreateFontIndirectW( &aLogFont );
+ if( hdcScreen )
+ {
+ // select font into screen hdc first to get an antialiased font
+ // see knowledge base article 305290:
+ // "PRB: Fonts Not Drawn Antialiased on Device Context for DirectDraw Surface"
+ SelectFont( hdcScreen, SelectFont( hdcScreen , hNewFont ) );
+ }
+ o_rOldFont = ::SelectFont( mhDC, hNewFont );
+
+ TEXTMETRICW aTextMetricW;
+ if( !::GetTextMetricsW( mhDC, &aTextMetricW ) )
+ {
+ // the selected font doesn't work => try a replacement
+ // TODO: use its font fallback instead
+ lstrcpynW( aLogFont.lfFaceName, L"Courier New", 11 );
+ aLogFont.lfPitchAndFamily = FIXED_PITCH;
+ HFONT hNewFont2 = CreateFontIndirectW( &aLogFont );
+ SelectFont( mhDC, hNewFont2 );
+ DeleteFont( hNewFont );
+ hNewFont = hNewFont2;
+ }
+ }
+ else
+ {
+ if( !mpLogFont )
+ // mpLogFont is needed for getting the kerning pairs
+ // TODO: get them from somewhere else
+ mpLogFont = new LOGFONTA;
+ LOGFONTA& aLogFont = *mpLogFont;
+ ImplGetLogFontFromFontSelect( mhDC, i_pFont, aLogFont, true );
+
+ // on the display we prefer Courier New when Courier is a
+ // bitmap only font and we need to stretch or rotate it
+ if( mbScreen
+ && (i_pFont->mnWidth != 0
+ || i_pFont->mnOrientation != 0
+ || i_pFont->mpFontData == NULL
+ || (i_pFont->mpFontData->GetHeight() != i_pFont->mnHeight))
+ && !bImplSalCourierScalable
+ && bImplSalCourierNew
+ && (stricmp( aLogFont.lfFaceName, "Courier" ) == 0) )
+ strncpy( aLogFont.lfFaceName, "Courier New", 11 );
+
+ // limit font requests to MAXFONTHEIGHT to work around driver problems
+ // TODO: share MAXFONTHEIGHT font instance
+ if( -aLogFont.lfHeight <= MAXFONTHEIGHT )
+ o_rFontScale = 1.0;
+ else
+ {
+ o_rFontScale = -aLogFont.lfHeight / (float)MAXFONTHEIGHT;
+ aLogFont.lfHeight = -MAXFONTHEIGHT;
+ aLogFont.lfWidth = static_cast<LONG>( aLogFont.lfWidth / o_rFontScale );
+ }
+
+ hNewFont = ::CreateFontIndirectA( &aLogFont );
+ if( hdcScreen )
+ {
+ // select font into screen hdc first to get an antialiased font
+ // see knowledge base article 305290:
+ // "PRB: Fonts Not Drawn Antialiased on Device Context for DirectDraw Surface"
+ ::SelectFont( hdcScreen, ::SelectFont( hdcScreen , hNewFont ) );
+ }
+ o_rOldFont = ::SelectFont( mhDC, hNewFont );
+
+ TEXTMETRICA aTextMetricA;
+ // when the font doesn't work try a replacement
+ if ( !::GetTextMetricsA( mhDC, &aTextMetricA ) )
+ {
+ // the selected font doesn't work => try a replacement
+ // TODO: use its font fallback instead
+ LOGFONTA aTempLogFont = aLogFont;
+ strncpy( aTempLogFont.lfFaceName, "Courier New", 11 );
+ aTempLogFont.lfPitchAndFamily = FIXED_PITCH;
+ HFONT hNewFont2 = CreateFontIndirectA( &aTempLogFont );
+ ::SelectFont( mhDC, hNewFont2 );
+ ::DeleteFont( hNewFont );
+ hNewFont = hNewFont2;
+ }
+ }
+
+ if( hdcScreen )
+ ::ReleaseDC( NULL, hdcScreen );
+
+ return hNewFont;
+}
+
+USHORT WinSalGraphics::SetFont( ImplFontSelectData* pFont, int nFallbackLevel )
+{
+ // return early if there is no new font
+ if( !pFont )
+ {
+ // deselect still active font
+ if( mhDefFont )
+ ::SelectFont( mhDC, mhDefFont );
+ // release no longer referenced font handles
+ for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
+ {
+ if( mhFonts[i] )
+ ::DeleteFont( mhFonts[i] );
+ mhFonts[ i ] = 0;
+ }
+ mhDefFont = 0;
+ return 0;
+ }
+
+ DBG_ASSERT( pFont->mpFontData, "WinSalGraphics mpFontData==NULL");
+ mpWinFontEntry[ nFallbackLevel ] = reinterpret_cast<ImplWinFontEntry*>( pFont->mpFontEntry );
+ mpWinFontData[ nFallbackLevel ] = static_cast<const ImplWinFontData*>( pFont->mpFontData );
+
+ HFONT hOldFont = 0;
+ HFONT hNewFont = ImplDoSetFont( pFont, mfFontScale, hOldFont );
+
+ if( !mhDefFont )
+ {
+ // keep default font
+ mhDefFont = hOldFont;
+ }
+ else
+ {
+ // release no longer referenced font handles
+ for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
+ {
+ if( mhFonts[i] )
+ {
+ ::DeleteFont( mhFonts[i] );
+ mhFonts[i] = 0;
+ }
+ }
+ }
+
+ // store new font in correct layer
+ mhFonts[ nFallbackLevel ] = hNewFont;
+ // now the font is live => update font face
+ if( mpWinFontData[ nFallbackLevel ] )
+ mpWinFontData[ nFallbackLevel ]->UpdateFromHDC( mhDC );
+
+ if( !nFallbackLevel )
+ {
+ mbFontKernInit = TRUE;
+ if ( mpFontKernPairs )
+ {
+ delete[] mpFontKernPairs;
+ mpFontKernPairs = NULL;
+ }
+ mnFontKernPairCount = 0;
+ }
+
+ mnFontCharSetCount = 0;
+
+ // some printers have higher internal resolution, so their
+ // text output would be different from what we calculated
+ // => suggest DrawTextArray to workaround this problem
+ if ( mbPrinter )
+ return SAL_SETFONT_USEDRAWTEXTARRAY;
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::GetFontMetric( ImplFontMetricData* pMetric )
+{
+ if ( aSalShlData.mbWNT )
+ {
+ wchar_t aFaceName[LF_FACESIZE+60];
+ if( ::GetTextFaceW( mhDC, sizeof(aFaceName)/sizeof(wchar_t), aFaceName ) )
+ pMetric->maName = reinterpret_cast<const sal_Unicode*>(aFaceName);
+ }
+ else
+ {
+ char aFaceName[LF_FACESIZE+60];
+ if( ::GetTextFaceA( mhDC, sizeof(aFaceName), aFaceName ) )
+ pMetric->maName = ImplSalGetUniString( aFaceName );
+ }
+
+ TEXTMETRICA aWinMetric;
+ if( !GetTextMetricsA( mhDC, &aWinMetric ) )
+ return;
+
+ // device independent font attributes
+ pMetric->meFamily = ImplFamilyToSal( aWinMetric.tmPitchAndFamily );;
+ pMetric->mbSymbolFlag = (aWinMetric.tmCharSet == SYMBOL_CHARSET);
+ pMetric->meWeight = ImplWeightToSal( aWinMetric.tmWeight );
+ pMetric->mePitch = ImplMetricPitchToSal( aWinMetric.tmPitchAndFamily );
+ pMetric->meItalic = aWinMetric.tmItalic ? ITALIC_NORMAL : ITALIC_NONE;
+ pMetric->mnSlant = 0;
+
+ // device dependend font attributes
+ pMetric->mbDevice = (aWinMetric.tmPitchAndFamily & TMPF_DEVICE) != 0;
+ pMetric->mbScalableFont = (aWinMetric.tmPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE)) != 0;
+ if( pMetric->mbScalableFont )
+ {
+ // check if there are kern pairs
+ // TODO: does this work with GPOS kerning?
+ DWORD nKernPairs = ::GetKerningPairsA( mhDC, 0, NULL );
+ pMetric->mbKernableFont = (nKernPairs > 0);
+ }
+ else
+ {
+ // bitmap fonts cannot be rotated directly
+ pMetric->mnOrientation = 0;
+ // bitmap fonts have no kerning
+ pMetric->mbKernableFont = false;
+ }
+
+ // transformation dependend font metrics
+ pMetric->mnWidth = static_cast<int>( mfFontScale * aWinMetric.tmAveCharWidth );
+ pMetric->mnIntLeading = static_cast<int>( mfFontScale * aWinMetric.tmInternalLeading );
+ pMetric->mnExtLeading = static_cast<int>( mfFontScale * aWinMetric.tmExternalLeading );
+ pMetric->mnAscent = static_cast<int>( mfFontScale * aWinMetric.tmAscent );
+ pMetric->mnDescent = static_cast<int>( mfFontScale * aWinMetric.tmDescent );
+
+ // #107888# improved metric compatibility for Asian fonts...
+ // TODO: assess workaround below for CWS >= extleading
+ // TODO: evaluate use of aWinMetric.sTypo* members for CJK
+ if( mpWinFontData[0] && mpWinFontData[0]->SupportsCJK() )
+ {
+ pMetric->mnIntLeading += pMetric->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 = pMetric->mnExtLeading / 2;
+ const long nOtherHalfTmpExtLeading = pMetric->mnExtLeading - nHalfTmpExtLeading;
+
+ // #110641# external leading for Asian fonts.
+ // The factor 0.3 has been confirmed with experiments.
+ long nCJKExtLeading = static_cast<long>(0.30 * (pMetric->mnAscent + pMetric->mnDescent));
+ nCJKExtLeading -= pMetric->mnExtLeading;
+ pMetric->mnExtLeading = (nCJKExtLeading > 0) ? nCJKExtLeading : 0;
+
+ pMetric->mnAscent += nHalfTmpExtLeading;
+ pMetric->mnDescent += nOtherHalfTmpExtLeading;
+
+ // #109280# HACK korean only: increase descent for wavelines and impr
+ if( !aSalShlData.mbWNT )
+ if( mpWinFontData[0]->SupportsKorean() )
+ pMetric->mnDescent += pMetric->mnExtLeading;
+ }
+
+ pMetric->mnMinKashida = GetMinKashidaWidth();
+}
+
+// -----------------------------------------------------------------------
+
+int CALLBACK SalEnumCharSetsProcExA( const ENUMLOGFONTEXA* pLogFont,
+ const NEWTEXTMETRICEXA* /*pMetric*/,
+ DWORD /*nFontType*/, LPARAM lParam )
+{
+ WinSalGraphics* pData = (WinSalGraphics*)lParam;
+ // Charset already in the list?
+ for ( BYTE i = 0; i < pData->mnFontCharSetCount; i++ )
+ {
+ if ( pData->mpFontCharSets[i] == pLogFont->elfLogFont.lfCharSet )
+ return 1;
+ }
+ pData->mpFontCharSets[pData->mnFontCharSetCount] = pLogFont->elfLogFont.lfCharSet;
+ pData->mnFontCharSetCount++;
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplGetAllFontCharSets( WinSalGraphics* pData )
+{
+ if ( !pData->mpFontCharSets )
+ pData->mpFontCharSets = new BYTE[256];
+
+ LOGFONTA aLogFont;
+ memset( &aLogFont, 0, sizeof( aLogFont ) );
+ aLogFont.lfCharSet = DEFAULT_CHARSET;
+ GetTextFaceA( pData->mhDC, sizeof( aLogFont.lfFaceName ), aLogFont.lfFaceName );
+ EnumFontFamiliesExA( pData->mhDC, &aLogFont, (FONTENUMPROCA)SalEnumCharSetsProcExA,
+ (LPARAM)(void*)pData, 0 );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplAddKerningPairs( WinSalGraphics* pData )
+{
+ ULONG nPairs = ::GetKerningPairsA( pData->mhDC, 0, NULL );
+ if ( !nPairs )
+ return;
+
+ CHARSETINFO aInfo;
+ if ( !TranslateCharsetInfo( (DWORD*)(ULONG)GetTextCharset( pData->mhDC ), &aInfo, TCI_SRCCHARSET ) )
+ return;
+
+ if ( !pData->mpFontKernPairs )
+ pData->mpFontKernPairs = new KERNINGPAIR[nPairs];
+ else
+ {
+ KERNINGPAIR* pOldPairs = pData->mpFontKernPairs;
+ pData->mpFontKernPairs = new KERNINGPAIR[nPairs+pData->mnFontKernPairCount];
+ memcpy( pData->mpFontKernPairs, pOldPairs,
+ pData->mnFontKernPairCount*sizeof( KERNINGPAIR ) );
+ delete[] pOldPairs;
+ }
+
+ UINT nCP = aInfo.ciACP;
+ ULONG nOldPairs = pData->mnFontKernPairCount;
+ KERNINGPAIR* pTempPair = pData->mpFontKernPairs+pData->mnFontKernPairCount;
+ nPairs = ::GetKerningPairsA( pData->mhDC, nPairs, pTempPair );
+ for ( ULONG i = 0; i < nPairs; i++ )
+ {
+ unsigned char aBuf[2];
+ wchar_t nChar;
+ int nLen;
+ BOOL bAdd = TRUE;
+
+ // None-ASCII?, then we must convert the char
+ if ( (pTempPair->wFirst > 125) || (pTempPair->wFirst == 92) )
+ {
+ if ( pTempPair->wFirst < 256 )
+ {
+ aBuf[0] = (unsigned char)pTempPair->wFirst;
+ nLen = 1;
+ }
+ else
+ {
+ aBuf[0] = (unsigned char)(pTempPair->wFirst >> 8);
+ aBuf[1] = (unsigned char)(pTempPair->wFirst & 0xFF);
+ nLen = 2;
+ }
+ if ( MultiByteToWideChar( nCP, MB_PRECOMPOSED | MB_USEGLYPHCHARS,
+ (const char*)aBuf, nLen, &nChar, 1 ) )
+ pTempPair->wFirst = nChar;
+ else
+ bAdd = FALSE;
+ }
+ if ( (pTempPair->wSecond > 125) || (pTempPair->wSecond == 92) )
+ {
+ if ( pTempPair->wSecond < 256 )
+ {
+ aBuf[0] = (unsigned char)pTempPair->wSecond;
+ nLen = 1;
+ }
+ else
+ {
+ aBuf[0] = (unsigned char)(pTempPair->wSecond >> 8);
+ aBuf[1] = (unsigned char)(pTempPair->wSecond & 0xFF);
+ nLen = 2;
+ }
+ if ( MultiByteToWideChar( nCP, MB_PRECOMPOSED | MB_USEGLYPHCHARS,
+ (const char*)aBuf, nLen, &nChar, 1 ) )
+ pTempPair->wSecond = nChar;
+ else
+ bAdd = FALSE;
+ }
+
+ // TODO: get rid of linear search!
+ KERNINGPAIR* pTempPair2 = pData->mpFontKernPairs;
+ for ( ULONG j = 0; j < nOldPairs; j++ )
+ {
+ if ( (pTempPair2->wFirst == pTempPair->wFirst) &&
+ (pTempPair2->wSecond == pTempPair->wSecond) )
+ {
+ bAdd = FALSE;
+ break;
+ }
+ pTempPair2++;
+ }
+
+ if ( bAdd )
+ {
+ KERNINGPAIR* pDestPair = pData->mpFontKernPairs+pData->mnFontKernPairCount;
+ if ( pDestPair != pTempPair )
+ memcpy( pDestPair, pTempPair, sizeof( KERNINGPAIR ) );
+ pData->mnFontKernPairCount++;
+ }
+
+ pTempPair++;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ULONG WinSalGraphics::GetKernPairs( ULONG nPairs, ImplKernPairData* pKernPairs )
+{
+ DBG_ASSERT( sizeof( KERNINGPAIR ) == sizeof( ImplKernPairData ),
+ "WinSalGraphics::GetKernPairs(): KERNINGPAIR != ImplKernPairData" );
+
+ if ( mbFontKernInit )
+ {
+ if( mpFontKernPairs )
+ {
+ delete[] mpFontKernPairs;
+ mpFontKernPairs = NULL;
+ }
+ mnFontKernPairCount = 0;
+
+ if ( aSalShlData.mbWNT )
+ {
+ KERNINGPAIR* pPairs = NULL;
+ int nCount = ::GetKerningPairsW( mhDC, 0, NULL );
+ if( nCount )
+ {
+#ifdef GCP_KERN_HACK
+ pPairs = new KERNINGPAIR[ nCount+1 ];
+ mpFontKernPairs = pPairs;
+ mnFontKernPairCount = nCount;
+ ::GetKerningPairsW( mhDC, nCount, pPairs );
+#else // GCP_KERN_HACK
+ pPairs = pKernPairs;
+ nCount = (nCount < nPairs) : nCount : nPairs;
+ ::GetKerningPairsW( mhDC, nCount, pPairs );
+ return nCount;
+#endif // GCP_KERN_HACK
+ }
+ }
+ else
+ {
+ if ( !mnFontCharSetCount )
+ ImplGetAllFontCharSets( this );
+
+ if ( mnFontCharSetCount <= 1 )
+ ImplAddKerningPairs( this );
+ else
+ {
+ // Query All Kerning Pairs from all possible CharSets
+ for ( BYTE i = 0; i < mnFontCharSetCount; i++ )
+ {
+ mpLogFont->lfCharSet = mpFontCharSets[i];
+ HFONT hNewFont = CreateFontIndirectA( mpLogFont );
+ HFONT hOldFont = SelectFont( mhDC, hNewFont );
+ ImplAddKerningPairs( this );
+ SelectFont( mhDC, hOldFont );
+ DeleteFont( hNewFont );
+ }
+ }
+ }
+
+ mbFontKernInit = FALSE;
+
+ std::sort( mpFontKernPairs, mpFontKernPairs + mnFontKernPairCount, ImplCmpKernData );
+ }
+
+ if( !pKernPairs )
+ return mnFontKernPairCount;
+ else if( mpFontKernPairs )
+ {
+ if ( nPairs < mnFontKernPairCount )
+ nPairs = mnFontKernPairCount;
+ memcpy( pKernPairs, mpFontKernPairs,
+ nPairs*sizeof( ImplKernPairData ) );
+ return nPairs;
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+ImplFontCharMap* WinSalGraphics::GetImplFontCharMap() const
+{
+ if( !mpWinFontData[0] )
+ return ImplFontCharMap::GetDefaultMap();
+ return mpWinFontData[0]->GetImplFontCharMap();
+}
+
+// -----------------------------------------------------------------------
+
+int CALLBACK SalEnumFontsProcExA( const ENUMLOGFONTEXA* pLogFont,
+ const NEWTEXTMETRICEXA* pMetric,
+ DWORD nFontType, LPARAM lParam )
+{
+ ImplEnumInfo* pInfo = (ImplEnumInfo*)(void*)lParam;
+ if ( !pInfo->mpName )
+ {
+ // Ignore vertical fonts
+ if ( pLogFont->elfLogFont.lfFaceName[0] != '@' )
+ {
+ if ( !pInfo->mbImplSalCourierNew )
+ pInfo->mbImplSalCourierNew = stricmp( pLogFont->elfLogFont.lfFaceName, "Courier New" ) == 0;
+ if ( !pInfo->mbImplSalCourierScalable )
+ pInfo->mbCourier = stricmp( pLogFont->elfLogFont.lfFaceName, "Courier" ) == 0;
+ else
+ pInfo->mbCourier = FALSE;
+ String aName( ImplSalGetUniString( pLogFont->elfLogFont.lfFaceName ) );
+ pInfo->mpName = &aName;
+ strncpy( pInfo->mpLogFontA->lfFaceName, pLogFont->elfLogFont.lfFaceName, LF_FACESIZE );
+ pInfo->mpLogFontA->lfCharSet = pLogFont->elfLogFont.lfCharSet;
+ EnumFontFamiliesExA( pInfo->mhDC, pInfo->mpLogFontA, (FONTENUMPROCA)SalEnumFontsProcExA,
+ (LPARAM)(void*)pInfo, 0 );
+ pInfo->mpLogFontA->lfFaceName[0] = '\0';
+ pInfo->mpLogFontA->lfCharSet = DEFAULT_CHARSET;
+ pInfo->mpName = NULL;
+ pInfo->mbCourier = FALSE;
+ }
+ }
+ else
+ {
+ // ignore non-scalable non-device font on printer
+ if( pInfo->mbPrinter )
+ if( (nFontType & RASTER_FONTTYPE) && !(nFontType & DEVICE_FONTTYPE) )
+ return 1;
+
+ ImplWinFontData* pData = ImplLogMetricToDevFontDataA( pLogFont, &(pMetric->ntmTm), nFontType );
+ pData->SetFontId( sal_IntPtr( pInfo->mnFontCount++ ) );
+
+ // prefer the system character set, so that we get as much as
+ // possible important characters. In the other case we could only
+ // display a limited set of characters (#87309#)
+ if ( pInfo->mnPreferedCharSet == pLogFont->elfLogFont.lfCharSet )
+ pData->mnQuality += 100;
+
+ // knowing Courier to be scalable is nice
+ if( pInfo->mbCourier )
+ pInfo->mbImplSalCourierScalable |= pData->IsScalable();
+
+ pInfo->mpList->Add( pData );
+ }
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+
+int CALLBACK SalEnumFontsProcExW( const ENUMLOGFONTEXW* pLogFont,
+ const NEWTEXTMETRICEXW* pMetric,
+ DWORD nFontType, LPARAM lParam )
+{
+ ImplEnumInfo* pInfo = (ImplEnumInfo*)(void*)lParam;
+ if ( !pInfo->mpName )
+ {
+ // Ignore vertical fonts
+ if ( pLogFont->elfLogFont.lfFaceName[0] != '@' )
+ {
+ if ( !pInfo->mbImplSalCourierNew )
+ pInfo->mbImplSalCourierNew = ImplSalWICompareAscii( pLogFont->elfLogFont.lfFaceName, "Courier New" ) == 0;
+ if ( !pInfo->mbImplSalCourierScalable )
+ pInfo->mbCourier = ImplSalWICompareAscii( pLogFont->elfLogFont.lfFaceName, "Courier" ) == 0;
+ else
+ pInfo->mbCourier = FALSE;
+ String aName( reinterpret_cast<const sal_Unicode*>(pLogFont->elfLogFont.lfFaceName) );
+ pInfo->mpName = &aName;
+ memcpy( pInfo->mpLogFontW->lfFaceName, pLogFont->elfLogFont.lfFaceName, (aName.Len()+1)*sizeof( wchar_t ) );
+ pInfo->mpLogFontW->lfCharSet = pLogFont->elfLogFont.lfCharSet;
+ EnumFontFamiliesExW( pInfo->mhDC, pInfo->mpLogFontW, (FONTENUMPROCW)SalEnumFontsProcExW,
+ (LPARAM)(void*)pInfo, 0 );
+ pInfo->mpLogFontW->lfFaceName[0] = '\0';
+ pInfo->mpLogFontW->lfCharSet = DEFAULT_CHARSET;
+ pInfo->mpName = NULL;
+ pInfo->mbCourier = FALSE;
+ }
+ }
+ else
+ {
+ // ignore non-scalable non-device font on printer
+ if( pInfo->mbPrinter )
+ if( (nFontType & RASTER_FONTTYPE) && !(nFontType & DEVICE_FONTTYPE) )
+ return 1;
+
+ ImplWinFontData* pData = ImplLogMetricToDevFontDataW( pLogFont, &(pMetric->ntmTm), nFontType );
+ pData->SetFontId( sal_IntPtr( pInfo->mnFontCount++ ) );
+
+ // knowing Courier to be scalable is nice
+ if( pInfo->mbCourier )
+ pInfo->mbImplSalCourierScalable |= pData->IsScalable();
+
+ pInfo->mpList->Add( pData );
+ }
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+
+struct TempFontItem
+{
+ ::rtl::OUString maFontFilePath;
+ ::rtl::OString maResourcePath;
+ TempFontItem* mpNextItem;
+};
+
+#ifdef FR_PRIVATE
+static int WINAPI __AddFontResourceExW( LPCWSTR lpszfileName, DWORD fl, PVOID pdv )
+{
+ typedef int (WINAPI *AddFontResourceExW_FUNC)(LPCWSTR, DWORD, PVOID );
+
+ static AddFontResourceExW_FUNC pFunc = NULL;
+ static HMODULE hmGDI = NULL;
+
+ if ( !pFunc && !hmGDI )
+ {
+ hmGDI = GetModuleHandleA( "GDI32" );
+ if ( hmGDI )
+ pFunc = reinterpret_cast<AddFontResourceExW_FUNC>( GetProcAddress( hmGDI, "AddFontResourceExW" ) );
+ }
+
+ if ( pFunc )
+ return pFunc( lpszfileName, fl, pdv );
+ else
+ {
+ SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
+ return 0;
+ }
+}
+#endif
+
+bool ImplAddTempFont( SalData& rSalData, const String& rFontFileURL )
+{
+ int nRet = 0;
+ ::rtl::OUString aUSytemPath;
+ OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL, aUSytemPath ) );
+
+#ifdef FR_PRIVATE
+ nRet = __AddFontResourceExW( reinterpret_cast<LPCWSTR>(aUSytemPath.getStr()), FR_PRIVATE, NULL );
+#endif
+
+ if ( !nRet )
+ {
+ static int nCounter = 0;
+ char aFileName[] = "soAA.fot";
+ aFileName[2] = sal::static_int_cast<char>('A' + (15 & (nCounter>>4)));
+ aFileName[3] = sal::static_int_cast<char>('A' + (15 & nCounter));
+ char aResourceName[512];
+ int nMaxLen = sizeof(aResourceName)/sizeof(*aResourceName) - 16;
+ int nLen = ::GetTempPathA( nMaxLen, aResourceName );
+ ::strncpy( aResourceName + nLen, aFileName, sizeof( aResourceName )- nLen );
+ // security: end buffer in any case
+ aResourceName[ (sizeof(aResourceName)/sizeof(*aResourceName))-1 ] = 0;
+ ::DeleteFileA( aResourceName );
+
+ rtl_TextEncoding theEncoding = osl_getThreadTextEncoding();
+ ::rtl::OString aCFileName = rtl::OUStringToOString( aUSytemPath, theEncoding );
+ // TODO: font should be private => need to investigate why it doesn't work then
+ if( !::CreateScalableFontResourceA( 0, aResourceName, aCFileName.getStr(), NULL ) )
+ return false;
+ ++nCounter;
+
+ nRet = ::AddFontResourceA( aResourceName );
+ if( nRet > 0 )
+ {
+ TempFontItem* pNewItem = new TempFontItem;
+ pNewItem->maResourcePath = rtl::OString( aResourceName );
+ pNewItem->maFontFilePath = aUSytemPath.getStr();
+ pNewItem->mpNextItem = rSalData.mpTempFontItem;
+ rSalData.mpTempFontItem = pNewItem;
+ }
+ }
+
+ return (nRet > 0);
+}
+
+// -----------------------------------------------------------------------
+
+void ImplReleaseTempFonts( SalData& rSalData )
+{
+ int nCount = 0;
+ while( TempFontItem* p = rSalData.mpTempFontItem )
+ {
+ ++nCount;
+ if( p->maResourcePath.getLength() )
+ {
+ const char* pResourcePath = p->maResourcePath.getStr();
+ ::RemoveFontResourceA( pResourcePath );
+ ::DeleteFileA( pResourcePath );
+ }
+ else
+ {
+ if( aSalShlData.mbWNT )
+ ::RemoveFontResourceW( reinterpret_cast<LPCWSTR>(p->maFontFilePath.getStr()) );
+ else
+ {
+ // poor man's string conversion because converter is gone
+ int nLen = p->maFontFilePath.getLength();
+ char* pNameA = new char[ nLen + 1 ];
+ for( int i = 0; i < nLen; ++i )
+ pNameA[i] = (char)(p->maFontFilePath.getStr())[i];
+ pNameA[ nLen ] = 0;
+ ::RemoveFontResourceA( pNameA );
+ delete[] pNameA;
+ }
+ }
+
+ rSalData.mpTempFontItem = p->mpNextItem;
+ delete p;
+ }
+
+#ifndef FR_PRIVATE
+ // notify every other application
+ // unless the temp fonts were installed as private fonts
+ if( nCount > 0 )
+ ::PostMessage( HWND_BROADCAST, WM_FONTCHANGE, 0, NULL );
+#endif // FR_PRIVATE
+}
+
+// -----------------------------------------------------------------------
+
+static bool ImplGetFontAttrFromFile( const String& rFontFileURL,
+ ImplDevFontAttributes& rDFA )
+{
+ ::rtl::OUString aUSytemPath;
+ OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL, aUSytemPath ) );
+
+ // get FontAttributes from a *fot file
+ // TODO: use GetTTGlobalFontInfo() to access the font directly
+ rDFA.mnQuality = 1000;
+ rDFA.mbDevice = true;
+ rDFA.meFamily = FAMILY_DONTKNOW;
+ rDFA.meWidthType = WIDTH_DONTKNOW;
+ rDFA.meWeight = WEIGHT_DONTKNOW;
+ rDFA.meItalic = ITALIC_DONTKNOW;
+ rDFA.mePitch = PITCH_DONTKNOW;;
+ rDFA.mbSubsettable= true;
+ rDFA.mbEmbeddable = false;
+
+ // Create temporary file name
+ char aFileName[] = "soAAT.fot";
+ char aResourceName[512];
+ int nMaxLen = sizeof(aResourceName)/sizeof(*aResourceName) - 16;
+ int nLen = ::GetTempPathA( nMaxLen, aResourceName );
+ ::strncpy( aResourceName + nLen, aFileName, Max( 0, nMaxLen - nLen ));
+ ::DeleteFileA( aResourceName );
+
+ // Create font resource file (typically with a .fot file name extension).
+ rtl_TextEncoding theEncoding = osl_getThreadTextEncoding();
+ ::rtl::OString aCFileName = rtl::OUStringToOString( aUSytemPath, theEncoding );
+ ::CreateScalableFontResourceA( 0, aResourceName, aCFileName.getStr(), NULL );
+
+ // Open and read the font resource file
+ rtl::OUString aFotFileName = rtl::OStringToOUString( aResourceName, osl_getThreadTextEncoding() );
+ osl::FileBase::getFileURLFromSystemPath( aFotFileName, aFotFileName );
+ osl::File aFotFile( aFotFileName );
+ osl::FileBase::RC aError = aFotFile.open( osl_File_OpenFlag_Read );
+ if( aError != osl::FileBase::E_None )
+ return false;
+
+ sal_uInt64 nBytesRead = 0;
+ char aBuffer[4096];
+ aFotFile.read( aBuffer, sizeof( aBuffer ), nBytesRead );
+ // clean up temporary resource file
+ aFotFile.close();
+ ::DeleteFileA( aResourceName );
+
+ // retrieve font family name from byte offset 0x4F6
+ int i = 0x4F6;
+ int nNameOfs = i;
+ while( (i < nBytesRead) && (aBuffer[i++] != 0) );
+ // skip full name
+ while( (i < nBytesRead) && (aBuffer[i++] != 0) );
+ // retrieve font style name
+ int nStyleOfs = i;
+ while( (i < nBytesRead) && (aBuffer[i++] != 0) );
+ if( i >= nBytesRead )
+ return false;
+
+ // convert byte strings to unicode
+ rDFA.maName = String( aBuffer + nNameOfs, osl_getThreadTextEncoding() );
+ rDFA.maStyleName = String( aBuffer + nStyleOfs, osl_getThreadTextEncoding() );
+
+ // byte offset 0x4C7: OS2_fsSelection
+ const char nFSS = aBuffer[ 0x4C7 ];
+ if( nFSS & 0x01 ) // italic
+ rDFA.meItalic = ITALIC_NORMAL;
+ //if( nFSS & 0x20 ) // bold
+ // rDFA.meWeight = WEIGHT_BOLD;
+ if( nFSS & 0x40 ) // regular
+ {
+ rDFA.meWeight = WEIGHT_NORMAL;
+ rDFA.meItalic = ITALIC_NONE;
+ }
+
+ // byte offsets 0x4D7/0x4D8: wingdi's FW_WEIGHT
+ int nWinWeight = (aBuffer[0x4D7] & 0xFF) + ((aBuffer[0x4D8] & 0xFF) << 8);
+ rDFA.meWeight = ImplWeightToSal( nWinWeight );
+
+ rDFA.mbSymbolFlag = false; // TODO
+ rDFA.mePitch = PITCH_DONTKNOW; // TODO
+
+ // byte offset 0x4DE: pitch&family
+ rDFA.meFamily = ImplFamilyToSal( aBuffer[0x4DE] );
+
+ // byte offsets 0x4C8/0x4C9: emunits
+ // byte offsets 0x4CE/0x4CF: winascent
+ // byte offsets 0x4D0/0x4D1: winascent+windescent-emunits
+ // byte offsets 0x4DF/0x4E0: avgwidth
+ //...
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+bool WinSalGraphics::AddTempDevFont( ImplDevFontList* pFontList,
+ const String& rFontFileURL, const String& rFontName )
+{
+ RTL_LOGFILE_TRACE1( "WinSalGraphics::AddTempDevFont(): %s", rtl::OUStringToOString( rFontFileURL, RTL_TEXTENCODING_UTF8 ).getStr() );
+
+ ImplDevFontAttributes aDFA;
+ aDFA.maName = rFontName;
+ aDFA.mnQuality = 1000;
+ aDFA.mbDevice = true;
+
+ // Search Font Name in Cache
+ if( !rFontName.Len() && mpFontAttrCache )
+ aDFA = mpFontAttrCache->GetFontAttr( rFontFileURL );
+
+ // Retrieve font name from font resource
+ if( !aDFA.maName.Len() )
+ {
+ ImplGetFontAttrFromFile( rFontFileURL, aDFA );
+ if( mpFontAttrCache && aDFA.maName.Len() )
+ mpFontAttrCache->AddFontAttr( rFontFileURL, aDFA );
+ }
+
+ if ( !aDFA.maName.Len() )
+ return false;
+
+ // remember temp font for cleanup later
+ if( !ImplAddTempFont( *GetSalData(), rFontFileURL ) )
+ return false;
+
+ UINT nPreferedCharSet = DEFAULT_CHARSET;
+ if ( !aSalShlData.mbWNT )
+ {
+ // for W98 guess charset preference from active codepage
+ CHARSETINFO aCharSetInfo;
+ DWORD nCP = GetACP();
+ if ( TranslateCharsetInfo( (DWORD*)nCP, &aCharSetInfo, TCI_SRCCODEPAGE ) )
+ nPreferedCharSet = aCharSetInfo.ciCharset;
+ }
+
+ // create matching FontData struct
+ aDFA.mbSymbolFlag = false; // TODO: how to know it without accessing the font?
+ aDFA.meFamily = FAMILY_DONTKNOW;
+ aDFA.meWidthType = WIDTH_DONTKNOW;
+ aDFA.meWeight = WEIGHT_DONTKNOW;
+ aDFA.meItalic = ITALIC_DONTKNOW;
+ aDFA.mePitch = PITCH_DONTKNOW;;
+ aDFA.mbSubsettable= true;
+ aDFA.mbEmbeddable = false;
+
+ /*
+ // TODO: improve ImplDevFontAttributes using the "font resource file"
+ aDFS.maName = // using "FONTRES:" from file
+ if( rFontName != aDFS.maName )
+ aDFS.maMapName = aFontName;
+ */
+
+ ImplWinFontData* pFontData = new ImplWinFontData( aDFA, 0,
+ sal::static_int_cast<WIN_BYTE>(nPreferedCharSet),
+ sal::static_int_cast<WIN_BYTE>(TMPF_VECTOR|TMPF_TRUETYPE) );
+ pFontData->SetFontId( reinterpret_cast<sal_IntPtr>(pFontData) );
+ pFontList->Add( pFontData );
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::GetDevFontList( ImplDevFontList* pFontList )
+{
+ // make sure all fonts are registered at least temporarily
+ static bool bOnce = true;
+ if( bOnce )
+ {
+ bOnce = false;
+
+ // determine font path
+ // since we are only interested in fonts that could not be
+ // registered before because of missing administration rights
+ // only the font path of the user installation is needed
+ ::rtl::OUString aPath;
+ osl_getExecutableFile( &aPath.pData );
+ ::rtl::OUString aExecutableFile( aPath );
+ aPath = aPath.copy( 0, aPath.lastIndexOf('/') );
+ String aFontDirUrl = aPath.copy( 0, aPath.lastIndexOf('/') );
+ aFontDirUrl += String( RTL_CONSTASCII_USTRINGPARAM("/Basis/share/fonts/truetype") );
+
+ // collect fonts in font path that could not be registered
+ osl::Directory aFontDir( aFontDirUrl );
+ osl::FileBase::RC rcOSL = aFontDir.open();
+ if( rcOSL == osl::FileBase::E_None )
+ {
+ osl::DirectoryItem aDirItem;
+ String aEmptyString;
+
+ ::rtl::OUString aBootStrap;
+ rtl::Bootstrap::get( String( RTL_CONSTASCII_USTRINGPARAM( "BRAND_BASE_DIR" ) ), aBootStrap );
+ aBootStrap += String( RTL_CONSTASCII_USTRINGPARAM( "/program/" SAL_CONFIGFILE( "bootstrap" ) ) );
+ rtl::Bootstrap aBootstrap( aBootStrap );
+ ::rtl::OUString aUserPath;
+ aBootstrap.getFrom( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UserInstallation" ) ), aUserPath );
+ aUserPath += String( RTL_CONSTASCII_USTRINGPARAM("/user/config/fontnames.dat") );
+ String aBaseURL = aPath.copy( 0, aPath.lastIndexOf('/')+1 );
+ mpFontAttrCache = new ImplFontAttrCache( aUserPath, aBaseURL );
+
+ while( aFontDir.getNextItem( aDirItem, 10 ) == osl::FileBase::E_None )
+ {
+ osl::FileStatus aFileStatus( FileStatusMask_FileURL );
+ rcOSL = aDirItem.getFileStatus( aFileStatus );
+ if ( rcOSL == osl::FileBase::E_None )
+ AddTempDevFont( pFontList, aFileStatus.getFileURL(), aEmptyString );
+ }
+
+ delete mpFontAttrCache; // destructor rewrites the cache file if needed
+ mpFontAttrCache = NULL;
+ }
+ }
+
+ ImplEnumInfo aInfo;
+ aInfo.mhDC = mhDC;
+ aInfo.mpList = pFontList;
+ aInfo.mpName = NULL;
+ aInfo.mpLogFontA = NULL;
+ aInfo.mpLogFontW = NULL;
+ aInfo.mbCourier = false;
+ aInfo.mbPrinter = mbPrinter;
+ aInfo.mnFontCount = 0;
+ if ( !mbPrinter )
+ {
+ aInfo.mbImplSalCourierScalable = false;
+ aInfo.mbImplSalCourierNew = false;
+ }
+ else
+ {
+ aInfo.mbImplSalCourierScalable = true;
+ aInfo.mbImplSalCourierNew = true;
+ }
+
+ aInfo.mnPreferedCharSet = DEFAULT_CHARSET;
+ DWORD nCP = GetACP();
+ CHARSETINFO aCharSetInfo;
+ if ( TranslateCharsetInfo( (DWORD*)nCP, &aCharSetInfo, TCI_SRCCODEPAGE ) )
+ aInfo.mnPreferedCharSet = aCharSetInfo.ciCharset;
+
+ if ( aSalShlData.mbWNT )
+ {
+ LOGFONTW aLogFont;
+ memset( &aLogFont, 0, sizeof( aLogFont ) );
+ aLogFont.lfCharSet = DEFAULT_CHARSET;
+ aInfo.mpLogFontW = &aLogFont;
+ EnumFontFamiliesExW( mhDC, &aLogFont,
+ (FONTENUMPROCW)SalEnumFontsProcExW, (LPARAM)(void*)&aInfo, 0 );
+ }
+ else
+ {
+ LOGFONTA aLogFont;
+ memset( &aLogFont, 0, sizeof( aLogFont ) );
+ aLogFont.lfCharSet = DEFAULT_CHARSET;
+ aInfo.mpLogFontA = &aLogFont;
+ EnumFontFamiliesExA( mhDC, &aLogFont,
+ (FONTENUMPROCA)SalEnumFontsProcExA, (LPARAM)(void*)&aInfo, 0 );
+ }
+
+ // Feststellen, was es fuer Courier-Schriften auf dem Bildschirm gibt,
+ // um in SetFont() evt. Courier auf Courier New zu mappen
+ if ( !mbPrinter )
+ {
+ bImplSalCourierScalable = aInfo.mbImplSalCourierScalable;
+ bImplSalCourierNew = aInfo.mbImplSalCourierNew;
+ }
+
+ // set glyph fallback hook
+ static WinGlyphFallbackSubstititution aSubstFallback( mhDC );
+ pFontList->SetFallbackHook( &aSubstFallback );
+}
+
+// ----------------------------------------------------------------------------
+
+void WinSalGraphics::GetDevFontSubstList( OutputDevice* )
+{}
+
+// -----------------------------------------------------------------------
+
+BOOL WinSalGraphics::GetGlyphBoundRect( long nIndex, Rectangle& rRect )
+{
+ HDC hDC = mhDC;
+
+ // use unity matrix
+ MAT2 aMat;
+ aMat.eM11 = aMat.eM22 = FixedFromDouble( 1.0 );
+ aMat.eM12 = aMat.eM21 = FixedFromDouble( 0.0 );
+
+ UINT nGGOFlags = GGO_METRICS;
+ if( !(nIndex & GF_ISCHAR) )
+ nGGOFlags |= GGO_GLYPH_INDEX;
+ nIndex &= GF_IDXMASK;
+
+ GLYPHMETRICS aGM;
+ aGM.gmptGlyphOrigin.x = aGM.gmptGlyphOrigin.y = 0;
+ aGM.gmBlackBoxX = aGM.gmBlackBoxY = 0;
+ DWORD nSize = GDI_ERROR;
+ if ( aSalShlData.mbWNT )
+ nSize = ::GetGlyphOutlineW( hDC, nIndex, nGGOFlags, &aGM, 0, NULL, &aMat );
+ else if( (nGGOFlags & GGO_GLYPH_INDEX) || (nIndex <= 255) )
+ nSize = ::GetGlyphOutlineA( hDC, nIndex, nGGOFlags, &aGM, 0, NULL, &aMat );
+
+ if( nSize == GDI_ERROR )
+ return false;
+
+ rRect = Rectangle( Point( +aGM.gmptGlyphOrigin.x, -aGM.gmptGlyphOrigin.y ),
+ Size( aGM.gmBlackBoxX, aGM.gmBlackBoxY ) );
+ rRect.Left() = static_cast<int>( mfFontScale * rRect.Left() );
+ rRect.Right() = static_cast<int>( mfFontScale * rRect.Right() );
+ rRect.Top() = static_cast<int>( mfFontScale * rRect.Top() );
+ rRect.Bottom() = static_cast<int>( mfFontScale * rRect.Bottom() );
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL WinSalGraphics::GetGlyphOutline( long nIndex,
+ ::basegfx::B2DPolyPolygon& rB2DPolyPoly )
+{
+ rB2DPolyPoly.clear();
+
+ BOOL bRet = FALSE;
+ HDC hDC = mhDC;
+
+ // use unity matrix
+ MAT2 aMat;
+ aMat.eM11 = aMat.eM22 = FixedFromDouble( 1.0 );
+ aMat.eM12 = aMat.eM21 = FixedFromDouble( 0.0 );
+
+ UINT nGGOFlags = GGO_NATIVE;
+ if( !(nIndex & GF_ISCHAR) )
+ nGGOFlags |= GGO_GLYPH_INDEX;
+ nIndex &= GF_IDXMASK;
+
+ GLYPHMETRICS aGlyphMetrics;
+ DWORD nSize1 = GDI_ERROR;
+ if ( aSalShlData.mbWNT )
+ nSize1 = ::GetGlyphOutlineW( hDC, nIndex, nGGOFlags, &aGlyphMetrics, 0, NULL, &aMat );
+ else if( (nGGOFlags & GGO_GLYPH_INDEX) || (nIndex <= 255) )
+ nSize1 = ::GetGlyphOutlineA( hDC, nIndex, nGGOFlags, &aGlyphMetrics, 0, NULL, &aMat );
+
+ if( !nSize1 ) // blank glyphs are ok
+ bRet = TRUE;
+ else if( nSize1 != GDI_ERROR )
+ {
+ BYTE* pData = new BYTE[ nSize1 ];
+ DWORD nSize2;
+ if ( aSalShlData.mbWNT )
+ nSize2 = ::GetGlyphOutlineW( hDC, nIndex, nGGOFlags,
+ &aGlyphMetrics, nSize1, pData, &aMat );
+ else
+ nSize2 = ::GetGlyphOutlineA( hDC, nIndex, nGGOFlags,
+ &aGlyphMetrics, nSize1, pData, &aMat );
+
+ if( nSize1 == nSize2 )
+ {
+ bRet = TRUE;
+
+ int nPtSize = 512;
+ Point* pPoints = new Point[ nPtSize ];
+ BYTE* pFlags = new BYTE[ nPtSize ];
+
+ TTPOLYGONHEADER* pHeader = (TTPOLYGONHEADER*)pData;
+ while( (BYTE*)pHeader < pData+nSize2 )
+ {
+ // only outline data is interesting
+ if( pHeader->dwType != TT_POLYGON_TYPE )
+ break;
+
+ // get start point; next start points are end points
+ // of previous segment
+ USHORT nPnt = 0;
+
+ long nX = IntTimes256FromFixed( pHeader->pfxStart.x );
+ long nY = IntTimes256FromFixed( pHeader->pfxStart.y );
+ pPoints[ nPnt ] = Point( nX, nY );
+ pFlags[ nPnt++ ] = POLY_NORMAL;
+
+ bool bHasOfflinePoints = false;
+ TTPOLYCURVE* pCurve = (TTPOLYCURVE*)( pHeader + 1 );
+ pHeader = (TTPOLYGONHEADER*)( (BYTE*)pHeader + pHeader->cb );
+ while( (BYTE*)pCurve < (BYTE*)pHeader )
+ {
+ int nNeededSize = nPnt + 16 + 3 * pCurve->cpfx;
+ if( nPtSize < nNeededSize )
+ {
+ Point* pOldPoints = pPoints;
+ BYTE* pOldFlags = pFlags;
+ nPtSize = 2 * nNeededSize;
+ pPoints = new Point[ nPtSize ];
+ pFlags = new BYTE[ nPtSize ];
+ for( USHORT i = 0; i < nPnt; ++i )
+ {
+ pPoints[ i ] = pOldPoints[ i ];
+ pFlags[ i ] = pOldFlags[ i ];
+ }
+ delete[] pOldPoints;
+ delete[] pOldFlags;
+ }
+
+ int i = 0;
+ if( TT_PRIM_LINE == pCurve->wType )
+ {
+ while( i < pCurve->cpfx )
+ {
+ nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
+ nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
+ ++i;
+ pPoints[ nPnt ] = Point( nX, nY );
+ pFlags[ nPnt ] = POLY_NORMAL;
+ ++nPnt;
+ }
+ }
+ else if( TT_PRIM_QSPLINE == pCurve->wType )
+ {
+ bHasOfflinePoints = true;
+ while( i < pCurve->cpfx )
+ {
+ // get control point of quadratic bezier spline
+ nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
+ nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
+ ++i;
+ Point aControlP( nX, nY );
+
+ // calculate first cubic control point
+ // P0 = 1/3 * (PBeg + 2 * PQControl)
+ nX = pPoints[ nPnt-1 ].X() + 2 * aControlP.X();
+ nY = pPoints[ nPnt-1 ].Y() + 2 * aControlP.Y();
+ pPoints[ nPnt+0 ] = Point( (2*nX+3)/6, (2*nY+3)/6 );
+ pFlags[ nPnt+0 ] = POLY_CONTROL;
+
+ // calculate endpoint of segment
+ nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
+ nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
+
+ if ( i+1 >= pCurve->cpfx )
+ {
+ // endpoint is either last point in segment => advance
+ ++i;
+ }
+ else
+ {
+ // or endpoint is the middle of two control points
+ nX += IntTimes256FromFixed( pCurve->apfx[ i-1 ].x );
+ nY += IntTimes256FromFixed( pCurve->apfx[ i-1 ].y );
+ nX = (nX + 1) / 2;
+ nY = (nY + 1) / 2;
+ // no need to advance, because the current point
+ // is the control point in next bezier spline
+ }
+
+ pPoints[ nPnt+2 ] = Point( nX, nY );
+ pFlags[ nPnt+2 ] = POLY_NORMAL;
+
+ // calculate second cubic control point
+ // P1 = 1/3 * (PEnd + 2 * PQControl)
+ nX = pPoints[ nPnt+2 ].X() + 2 * aControlP.X();
+ nY = pPoints[ nPnt+2 ].Y() + 2 * aControlP.Y();
+ pPoints[ nPnt+1 ] = Point( (2*nX+3)/6, (2*nY+3)/6 );
+ pFlags[ nPnt+1 ] = POLY_CONTROL;
+
+ nPnt += 3;
+ }
+ }
+
+ // next curve segment
+ pCurve = (TTPOLYCURVE*)&pCurve->apfx[ i ];
+ }
+
+ // end point is start point for closed contour
+ // disabled, because Polygon class closes the contour itself
+ // pPoints[nPnt++] = pPoints[0];
+ // #i35928#
+ // Added again, but add only when not yet closed
+ if(pPoints[nPnt - 1] != pPoints[0])
+ {
+ if( bHasOfflinePoints )
+ pFlags[nPnt] = pFlags[0];
+
+ pPoints[nPnt++] = pPoints[0];
+ }
+
+ // convert y-coordinates W32 -> VCL
+ for( int i = 0; i < nPnt; ++i )
+ pPoints[i].Y() = -pPoints[i].Y();
+
+ // insert into polypolygon
+ Polygon aPoly( nPnt, pPoints, (bHasOfflinePoints ? pFlags : NULL) );
+ // convert to B2DPolyPolygon
+ // TODO: get rid of the intermediate PolyPolygon
+ rB2DPolyPoly.append( aPoly.getB2DPolygon() );
+ }
+
+ delete[] pPoints;
+ delete[] pFlags;
+ }
+
+ delete[] pData;
+ }
+
+ // rescaling needed for the PolyPolygon conversion
+ if( rB2DPolyPoly.count() )
+ {
+ const double fFactor(mfFontScale/256);
+ rB2DPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix(fFactor, fFactor));
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+class ScopedFont
+{
+public:
+ explicit ScopedFont(WinSalGraphics & rData);
+
+ ~ScopedFont();
+
+private:
+ WinSalGraphics & m_rData;
+ HFONT m_hOrigFont;
+};
+
+ScopedFont::ScopedFont(WinSalGraphics & rData): m_rData(rData)
+{
+ m_hOrigFont = m_rData.mhFonts[0];
+ m_rData.mhFonts[0] = 0; // avoid deletion of current font
+}
+
+ScopedFont::~ScopedFont()
+{
+ if( m_hOrigFont )
+ {
+ // restore original font, destroy temporary font
+ HFONT hTempFont = m_rData.mhFonts[0];
+ m_rData.mhFonts[0] = m_hOrigFont;
+ SelectObject( m_rData.mhDC, m_hOrigFont );
+ DeleteObject( hTempFont );
+ }
+}
+
+class ScopedTrueTypeFont
+{
+public:
+ inline ScopedTrueTypeFont(): m_pFont(0) {}
+
+ ~ScopedTrueTypeFont();
+
+ int open(void * pBuffer, sal_uInt32 nLen, sal_uInt32 nFaceNum);
+
+ inline TrueTypeFont * get() const { return m_pFont; }
+
+private:
+ TrueTypeFont * m_pFont;
+};
+
+ScopedTrueTypeFont::~ScopedTrueTypeFont()
+{
+ if (m_pFont != 0)
+ CloseTTFont(m_pFont);
+}
+
+int ScopedTrueTypeFont::open(void * pBuffer, sal_uInt32 nLen,
+ sal_uInt32 nFaceNum)
+{
+ OSL_ENSURE(m_pFont == 0, "already open");
+ return OpenTTFontBuffer(pBuffer, nLen, nFaceNum, &m_pFont);
+}
+
+BOOL WinSalGraphics::CreateFontSubset( const rtl::OUString& rToFile,
+ const ImplFontData* pFont, long* pGlyphIDs, sal_uInt8* pEncoding,
+ sal_Int32* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rInfo )
+{
+ // TODO: use more of the central font-subsetting code, move stuff there if needed
+
+ // create matching ImplFontSelectData
+ // we need just enough to get to the font file data
+ // use height=1000 for easier debugging (to match psprint's font units)
+ ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
+
+ // TODO: much better solution: move SetFont and restoration of old font to caller
+ ScopedFont aOldFont(*this);
+ float fScale = 1.0;
+ HFONT hOldFont = 0;
+ ImplDoSetFont( &aIFSD, fScale, hOldFont );
+
+ ImplWinFontData* pWinFontData = (ImplWinFontData*)aIFSD.mpFontData;
+ pWinFontData->UpdateFromHDC( mhDC );
+/*const*/ ImplFontCharMap* pImplFontCharMap = pWinFontData->GetImplFontCharMap();
+
+#if OSL_DEBUG_LEVEL > 1
+ // get font metrics
+ TEXTMETRICA aWinMetric;
+ if( !::GetTextMetricsA( mhDC, &aWinMetric ) )
+ return FALSE;
+
+ DBG_ASSERT( !(aWinMetric.tmPitchAndFamily & TMPF_DEVICE), "cannot subset device font" );
+ DBG_ASSERT( aWinMetric.tmPitchAndFamily & TMPF_TRUETYPE, "can only subset TT font" );
+#endif
+
+ rtl::OUString aSysPath;
+ if( osl_File_E_None != osl_getSystemPathFromFileURL( rToFile.pData, &aSysPath.pData ) )
+ return FALSE;
+ const rtl_TextEncoding aThreadEncoding = osl_getThreadTextEncoding();
+ const ByteString aToFile( aSysPath.getStr(), (xub_StrLen)aSysPath.getLength(), aThreadEncoding );
+
+ // check if the font has a CFF-table
+ const DWORD nCffTag = CalcTag( "CFF " );
+ const RawFontData aRawCffData( mhDC, nCffTag );
+ if( aRawCffData.get() )
+ {
+ long nRealGlyphIds[ 256 ];
+ for( int i = 0; i < nGlyphCount; ++i )
+ {
+ // TODO: remap notdef glyph if needed
+ // TODO: use GDI's GetGlyphIndices instead? Does it handle GSUB properly?
+ sal_uInt32 nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK;
+ if( pGlyphIDs[i] & GF_ISCHAR ) // remaining pseudo-glyphs need to be translated
+ nGlyphIdx = pImplFontCharMap->GetGlyphIndex( nGlyphIdx );
+ if( (pGlyphIDs[i] & (GF_ROTMASK|GF_GSUB)) != 0) // TODO: vertical substitution
+ {/*####*/}
+
+ nRealGlyphIds[i] = nGlyphIdx;
+ }
+
+ // provide a font subset from the CFF-table
+ FILE* pOutFile = fopen( aToFile.GetBuffer(), "wb" );
+ rInfo.LoadFont( FontSubsetInfo::CFF_FONT, aRawCffData.get(), aRawCffData.size() );
+ bool bRC = rInfo.CreateFontSubset( FontSubsetInfo::TYPE1_PFB, pOutFile, NULL,
+ nRealGlyphIds, pEncoding, nGlyphCount, pGlyphWidths );
+ fclose( pOutFile );
+ return bRC;
+ }
+
+ // get raw font file data
+ const RawFontData xRawFontData( mhDC, NULL );
+ if( !xRawFontData.get() )
+ return FALSE;
+
+ // open font file
+ sal_uInt32 nFaceNum = 0;
+ if( !*xRawFontData.get() ) // TTC candidate
+ nFaceNum = ~0U; // indicate "TTC font extracts only"
+
+ ScopedTrueTypeFont aSftTTF;
+ int nRC = aSftTTF.open( (void*)xRawFontData.get(), xRawFontData.size(), nFaceNum );
+ if( nRC != SF_OK )
+ return FALSE;
+
+ TTGlobalFontInfo aTTInfo;
+ ::GetTTGlobalFontInfo( aSftTTF.get(), &aTTInfo );
+ rInfo.m_nFontType = FontSubsetInfo::SFNT_TTF;
+ rInfo.m_aPSName = ImplSalGetUniString( aTTInfo.psname );
+ rInfo.m_nAscent = +aTTInfo.winAscent;
+ rInfo.m_nDescent = -aTTInfo.winDescent;
+ rInfo.m_aFontBBox = Rectangle( Point( aTTInfo.xMin, aTTInfo.yMin ),
+ Point( aTTInfo.xMax, aTTInfo.yMax ) );
+ rInfo.m_nCapHeight = aTTInfo.yMax; // Well ...
+
+ // subset TTF-glyphs and get their properties
+ // take care that subset fonts require the NotDef glyph in pos 0
+ int nOrigCount = nGlyphCount;
+ USHORT aShortIDs[ 256 ];
+ sal_uInt8 aTempEncs[ 256 ];
+
+ int nNotDef=-1, i;
+ for( i = 0; i < nGlyphCount; ++i )
+ {
+ aTempEncs[i] = pEncoding[i];
+ sal_uInt32 nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK;
+ if( pGlyphIDs[i] & GF_ISCHAR )
+ {
+ sal_Unicode cChar = static_cast<sal_Unicode>(nGlyphIdx); // TODO: sal_UCS4
+ const bool bVertical = ((pGlyphIDs[i] & (GF_ROTMASK|GF_GSUB)) != 0);
+ nGlyphIdx = ::MapChar( aSftTTF.get(), cChar, bVertical );
+ if( (nGlyphIdx == 0) && pFont->IsSymbolFont() )
+ {
+ // #i12824# emulate symbol aliasing U+FXXX <-> U+0XXX
+ cChar = (cChar & 0xF000) ? (cChar & 0x00FF) : (cChar | 0xF000);
+ nGlyphIdx = ::MapChar( aSftTTF.get(), cChar, bVertical );
+ }
+ }
+ aShortIDs[i] = static_cast<USHORT>( nGlyphIdx );
+ if( !nGlyphIdx )
+ if( nNotDef < 0 )
+ nNotDef = i; // first NotDef glyph found
+ }
+
+ if( nNotDef != 0 )
+ {
+ // add fake NotDef glyph if needed
+ if( nNotDef < 0 )
+ nNotDef = nGlyphCount++;
+
+ // NotDef glyph must be in pos 0 => swap glyphids
+ aShortIDs[ nNotDef ] = aShortIDs[0];
+ aTempEncs[ nNotDef ] = aTempEncs[0];
+ aShortIDs[0] = 0;
+ aTempEncs[0] = 0;
+ }
+ DBG_ASSERT( nGlyphCount < 257, "too many glyphs for subsetting" );
+
+ // fill pWidth array
+ TTSimpleGlyphMetrics* pMetrics =
+ ::GetTTSimpleGlyphMetrics( aSftTTF.get(), aShortIDs, nGlyphCount, aIFSD.mbVertical );
+ if( !pMetrics )
+ return FALSE;
+ sal_uInt16 nNotDefAdv = pMetrics[0].adv;
+ pMetrics[0].adv = pMetrics[nNotDef].adv;
+ pMetrics[nNotDef].adv = nNotDefAdv;
+ for( i = 0; i < nOrigCount; ++i )
+ pGlyphWidths[i] = pMetrics[i].adv;
+ free( pMetrics );
+
+ // write subset into destination file
+ nRC = ::CreateTTFromTTGlyphs( aSftTTF.get(), aToFile.GetBuffer(), aShortIDs,
+ aTempEncs, nGlyphCount, 0, NULL, 0 );
+ return (nRC == SF_OK);
+}
+
+//--------------------------------------------------------------------------
+
+const void* WinSalGraphics::GetEmbedFontData( const ImplFontData* pFont,
+ const sal_Unicode* pUnicodes, sal_Int32* pCharWidths,
+ FontSubsetInfo& rInfo, long* pDataLen )
+{
+ // create matching ImplFontSelectData
+ // we need just enough to get to the font file data
+ ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
+
+ // TODO: much better solution: move SetFont and restoration of old font to caller
+ ScopedFont aOldFont(*this);
+ SetFont( &aIFSD, 0 );
+
+ // get the raw font file data
+ RawFontData aRawFontData( mhDC );
+ *pDataLen = aRawFontData.size();
+ if( !aRawFontData.get() )
+ return NULL;
+
+ // get important font properties
+ TEXTMETRICA aTm;
+ if( !::GetTextMetricsA( mhDC, &aTm ) )
+ *pDataLen = 0;
+ const bool bPFA = (*aRawFontData.get() < 0x80);
+ rInfo.m_nFontType = bPFA ? FontSubsetInfo::TYPE1_PFA : FontSubsetInfo::TYPE1_PFB;
+ WCHAR aFaceName[64];
+ int nFNLen = ::GetTextFaceW( mhDC, 64, aFaceName );
+ // #i59854# strip eventual null byte
+ while( nFNLen > 0 && aFaceName[nFNLen-1] == 0 )
+ nFNLen--;
+ if( nFNLen == 0 )
+ *pDataLen = 0;
+ rInfo.m_aPSName = String( reinterpret_cast<const sal_Unicode*>(aFaceName), sal::static_int_cast<USHORT>(nFNLen) );
+ rInfo.m_nAscent = +aTm.tmAscent;
+ rInfo.m_nDescent = -aTm.tmDescent;
+ rInfo.m_aFontBBox = Rectangle( Point( -aTm.tmOverhang, -aTm.tmDescent ),
+ Point( aTm.tmMaxCharWidth, aTm.tmAscent+aTm.tmExternalLeading ) );
+ rInfo.m_nCapHeight = aTm.tmAscent; // Well ...
+
+ // get individual character widths
+ for( int i = 0; i < 256; ++i )
+ {
+ int nCharWidth = 0;
+ const sal_Unicode cChar = pUnicodes[i];
+ if( !::GetCharWidth32W( mhDC, cChar, cChar, &nCharWidth ) )
+ *pDataLen = 0;
+ pCharWidths[i] = nCharWidth;
+ }
+
+ if( !*pDataLen )
+ return NULL;
+
+ const unsigned char* pData = aRawFontData.steal();
+ return (void*)pData;
+}
+
+//--------------------------------------------------------------------------
+
+void WinSalGraphics::FreeEmbedFontData( const void* pData, long /*nLen*/ )
+{
+ delete[] reinterpret_cast<char*>(const_cast<void*>(pData));
+}
+
+//--------------------------------------------------------------------------
+
+const Ucs2SIntMap* WinSalGraphics::GetFontEncodingVector( const ImplFontData* pFont, const Ucs2OStrMap** pNonEncoded )
+{
+ // TODO: even for builtin fonts we get here... why?
+ if( !pFont->IsEmbeddable() )
+ return NULL;
+
+ // fill the encoding vector
+ // currently no nonencoded vector
+ if( pNonEncoded )
+ *pNonEncoded = NULL;
+
+ const ImplWinFontData* pWinFontData = static_cast<const ImplWinFontData*>(pFont);
+ const Ucs2SIntMap* pEncoding = pWinFontData->GetEncodingVector();
+ if( pEncoding == NULL )
+ {
+ Ucs2SIntMap* pNewEncoding = new Ucs2SIntMap;
+ #if 0
+ // TODO: get correct encoding vector
+ GLYPHSET aGlyphSet;
+ aGlyphSet.cbThis = sizeof(aGlyphSet);
+ DWORD aW = ::GetFontUnicodeRanges( mhDC, &aGlyphSet);
+ #else
+ for( sal_Unicode i = 32; i < 256; ++i )
+ (*pNewEncoding)[i] = i;
+ #endif
+ pWinFontData->SetEncodingVector( pNewEncoding );
+ pEncoding = pNewEncoding;
+ }
+
+ return pEncoding;
+}
+
+//--------------------------------------------------------------------------
+
+void WinSalGraphics::GetGlyphWidths( const ImplFontData* pFont,
+ bool bVertical,
+ Int32Vector& rWidths,
+ Ucs2UIntMap& rUnicodeEnc )
+{
+ // create matching ImplFontSelectData
+ // we need just enough to get to the font file data
+ ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
+
+ // TODO: much better solution: move SetFont and restoration of old font to caller
+ ScopedFont aOldFont(*this);
+
+ float fScale = 0.0;
+ HFONT hOldFont = 0;
+ ImplDoSetFont( &aIFSD, fScale, hOldFont );
+
+ if( pFont->IsSubsettable() )
+ {
+ // get raw font file data
+ const RawFontData xRawFontData( mhDC );
+ if( !xRawFontData.get() )
+ return;
+
+ // open font file
+ sal_uInt32 nFaceNum = 0;
+ if( !*xRawFontData.get() ) // TTC candidate
+ nFaceNum = ~0U; // indicate "TTC font extracts only"
+
+ ScopedTrueTypeFont aSftTTF;
+ int nRC = aSftTTF.open( (void*)xRawFontData.get(), xRawFontData.size(), nFaceNum );
+ if( nRC != SF_OK )
+ return;
+
+ int nGlyphs = GetTTGlyphCount( aSftTTF.get() );
+ if( nGlyphs > 0 )
+ {
+ rWidths.resize(nGlyphs);
+ std::vector<sal_uInt16> aGlyphIds(nGlyphs);
+ for( int i = 0; i < nGlyphs; i++ )
+ aGlyphIds[i] = sal_uInt16(i);
+ TTSimpleGlyphMetrics* pMetrics = ::GetTTSimpleGlyphMetrics( aSftTTF.get(),
+ &aGlyphIds[0],
+ nGlyphs,
+ bVertical ? 1 : 0 );
+ if( pMetrics )
+ {
+ for( int i = 0; i< nGlyphs; i++ )
+ rWidths[i] = pMetrics[i].adv;
+ free( pMetrics );
+ rUnicodeEnc.clear();
+ }
+ const ImplWinFontData* pWinFont = static_cast<const ImplWinFontData*>(pFont);
+ ImplFontCharMap* pMap = pWinFont->GetImplFontCharMap();
+ DBG_ASSERT( pMap && pMap->GetCharCount(), "no map" );
+
+ int nCharCount = pMap->GetCharCount();
+ sal_uInt32 nChar = pMap->GetFirstChar();
+ for( int i = 0; i < nCharCount; i++ )
+ {
+ if( nChar < 0x00010000 )
+ {
+ sal_uInt16 nGlyph = ::MapChar( aSftTTF.get(),
+ static_cast<sal_Ucs>(nChar),
+ bVertical ? 1 : 0 );
+ if( nGlyph )
+ rUnicodeEnc[ static_cast<sal_Unicode>(nChar) ] = nGlyph;
+ }
+ nChar = pMap->GetNextChar( nChar );
+ }
+ }
+ }
+ else if( pFont->IsEmbeddable() )
+ {
+ // get individual character widths
+ rWidths.clear();
+ rUnicodeEnc.clear();
+ rWidths.reserve( 224 );
+ for( sal_Unicode i = 32; i < 256; ++i )
+ {
+ int nCharWidth = 0;
+ if( ::GetCharWidth32W( mhDC, i, i, &nCharWidth ) )
+ {
+ rUnicodeEnc[ i ] = rWidths.size();
+ rWidths.push_back( nCharWidth );
+ }
+ }
+ }
+}
+
+//--------------------------------------------------------------------------
+
+void WinSalGraphics::DrawServerFontLayout( const ServerFontLayout& )
+{}
+
+//--------------------------------------------------------------------------
+
+SystemFontData WinSalGraphics::GetSysFontData( int nFallbacklevel ) const
+{
+ SystemFontData aSysFontData;
+
+ if (nFallbacklevel >= MAX_FALLBACK) nFallbacklevel = MAX_FALLBACK - 1;
+ if (nFallbacklevel < 0 ) nFallbacklevel = 0;
+
+ aSysFontData.nSize = sizeof( SystemFontData );
+ aSysFontData.hFont = mhFonts[nFallbacklevel];
+ aSysFontData.bFakeBold = false;
+ aSysFontData.bFakeItalic = false;
+ aSysFontData.bAntialias = true;
+ aSysFontData.bVerticalCharacterType = false;
+
+ OSL_TRACE("\r\n:WinSalGraphics::GetSysFontData(): FontID: %p, Fallback level: %d",
+ aSysFontData.hFont,
+ nFallbacklevel);
+
+ return aSysFontData;
+}
+
+//--------------------------------------------------------------------------
+
diff --git a/vcl/win/source/gdi/salgdi_gdiplus.cxx b/vcl/win/source/gdi/salgdi_gdiplus.cxx
new file mode 100644
index 000000000000..88efbb29d30a
--- /dev/null
+++ b/vcl/win/source/gdi/salgdi_gdiplus.cxx
@@ -0,0 +1,265 @@
+/*************************************************************************
+ *
+ * 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 <string.h>
+#include <tools/svwin.h>
+#include <wincomp.hxx>
+#include <saldata.hxx>
+#include <salgdi.h>
+#include <tools/debug.hxx>
+
+#ifndef min
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+#ifndef max
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#if defined _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <GdiPlus.h>
+#include <GdiPlusEnums.h>
+#include <GdiPlusColor.h>
+
+#if defined _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include <basegfx/polygon/b2dpolygon.hxx>
+
+// -----------------------------------------------------------------------
+
+void impAddB2DPolygonToGDIPlusGraphicsPathReal(Gdiplus::GraphicsPath& rPath, const basegfx::B2DPolygon& rPolygon, bool bNoLineJoin)
+{
+ sal_uInt32 nCount(rPolygon.count());
+
+ if(nCount)
+ {
+ const sal_uInt32 nEdgeCount(rPolygon.isClosed() ? nCount : nCount - 1);
+ const bool bControls(rPolygon.areControlPointsUsed());
+ basegfx::B2DPoint aCurr(rPolygon.getB2DPoint(0));
+ Gdiplus::PointF aFCurr(Gdiplus::REAL(aCurr.getX()), Gdiplus::REAL(aCurr.getY()));
+
+ for(sal_uInt32 a(0); a < nEdgeCount; a++)
+ {
+ const sal_uInt32 nNextIndex((a + 1) % nCount);
+ const basegfx::B2DPoint aNext(rPolygon.getB2DPoint(nNextIndex));
+ const Gdiplus::PointF aFNext(Gdiplus::REAL(aNext.getX()), Gdiplus::REAL(aNext.getY()));
+
+ if(bControls && (rPolygon.isNextControlPointUsed(a) || rPolygon.isPrevControlPointUsed(nNextIndex)))
+ {
+ const basegfx::B2DPoint aCa(rPolygon.getNextControlPoint(a));
+ const basegfx::B2DPoint aCb(rPolygon.getPrevControlPoint(nNextIndex));
+
+ rPath.AddBezier(
+ aFCurr,
+ Gdiplus::PointF(Gdiplus::REAL(aCa.getX()), Gdiplus::REAL(aCa.getY())),
+ Gdiplus::PointF(Gdiplus::REAL(aCb.getX()), Gdiplus::REAL(aCb.getY())),
+ aFNext);
+ }
+ else
+ {
+ rPath.AddLine(aFCurr, aFNext);
+ }
+
+ if(a + 1 < nEdgeCount)
+ {
+ aFCurr = aFNext;
+
+ if(bNoLineJoin)
+ {
+ rPath.StartFigure();
+ }
+ }
+ }
+ }
+}
+
+void impAddB2DPolygonToGDIPlusGraphicsPathInteger(Gdiplus::GraphicsPath& rPath, const basegfx::B2DPolygon& rPolygon, bool bNoLineJoin)
+{
+ sal_uInt32 nCount(rPolygon.count());
+
+ if(nCount)
+ {
+ const sal_uInt32 nEdgeCount(rPolygon.isClosed() ? nCount : nCount - 1);
+ const bool bControls(rPolygon.areControlPointsUsed());
+ basegfx::B2DPoint aCurr(rPolygon.getB2DPoint(0));
+ Gdiplus::Point aICurr(INT(aCurr.getX()), INT(aCurr.getY()));
+
+ for(sal_uInt32 a(0); a < nEdgeCount; a++)
+ {
+ const sal_uInt32 nNextIndex((a + 1) % nCount);
+ const basegfx::B2DPoint aNext(rPolygon.getB2DPoint(nNextIndex));
+ const Gdiplus::Point aINext(INT(aNext.getX()), INT(aNext.getY()));
+
+ if(bControls && (rPolygon.isNextControlPointUsed(a) || rPolygon.isPrevControlPointUsed(nNextIndex)))
+ {
+ const basegfx::B2DPoint aCa(rPolygon.getNextControlPoint(a));
+ const basegfx::B2DPoint aCb(rPolygon.getPrevControlPoint(nNextIndex));
+
+ rPath.AddBezier(
+ aICurr,
+ Gdiplus::Point(INT(aCa.getX()), INT(aCa.getY())),
+ Gdiplus::Point(INT(aCb.getX()), INT(aCb.getY())),
+ aINext);
+ }
+ else
+ {
+ rPath.AddLine(aICurr, aINext);
+ }
+
+ if(a + 1 < nEdgeCount)
+ {
+ aICurr = aINext;
+
+ if(bNoLineJoin)
+ {
+ rPath.StartFigure();
+ }
+ }
+ }
+ }
+}
+
+bool WinSalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPolygon, double fTransparency)
+{
+ const sal_uInt32 nCount(rPolyPolygon.count());
+
+ if(mbBrush && nCount && (fTransparency >= 0.0 && fTransparency < 1.0))
+ {
+ Gdiplus::Graphics aGraphics(mhDC);
+ const sal_uInt8 aTrans((sal_uInt8)255 - (sal_uInt8)basegfx::fround(fTransparency * 255.0));
+ Gdiplus::Color aTestColor(aTrans, SALCOLOR_RED(maFillColor), SALCOLOR_GREEN(maFillColor), SALCOLOR_BLUE(maFillColor));
+ Gdiplus::SolidBrush aTestBrush(aTestColor);
+ Gdiplus::GraphicsPath aPath;
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ if(0 != a)
+ {
+ aPath.StartFigure(); // #i101491# not needed for first run
+ }
+
+ impAddB2DPolygonToGDIPlusGraphicsPathReal(aPath, rPolyPolygon.getB2DPolygon(a), false);
+ aPath.CloseFigure();
+ }
+
+ if(getAntiAliasB2DDraw())
+ {
+ aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
+ }
+ else
+ {
+ aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeNone);
+ }
+
+ aGraphics.FillPath(&aTestBrush, &aPath);
+ }
+
+ return true;
+}
+
+bool WinSalGraphics::drawPolyLine( const basegfx::B2DPolygon& rPolygon, double fTransparency, const basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin eLineJoin )
+{
+ const sal_uInt32 nCount(rPolygon.count());
+
+ if(mbPen && nCount)
+ {
+ Gdiplus::Graphics aGraphics(mhDC);
+ const sal_uInt8 aTrans = (sal_uInt8)basegfx::fround( 255 * (1.0 - fTransparency) );
+ Gdiplus::Color aTestColor(aTrans, SALCOLOR_RED(maLineColor), SALCOLOR_GREEN(maLineColor), SALCOLOR_BLUE(maLineColor));
+ Gdiplus::Pen aTestPen(aTestColor, Gdiplus::REAL(rLineWidths.getX()));
+ Gdiplus::GraphicsPath aPath;
+ bool bNoLineJoin(false);
+
+ switch(eLineJoin)
+ {
+ default : // basegfx::B2DLINEJOIN_NONE :
+ {
+ if(basegfx::fTools::more(rLineWidths.getX(), 0.0))
+ {
+ bNoLineJoin = true;
+ }
+ break;
+ }
+ case basegfx::B2DLINEJOIN_BEVEL :
+ {
+ aTestPen.SetLineJoin(Gdiplus::LineJoinBevel);
+ break;
+ }
+ case basegfx::B2DLINEJOIN_MIDDLE :
+ case basegfx::B2DLINEJOIN_MITER :
+ {
+ const Gdiplus::REAL aMiterLimit(15.0);
+ aTestPen.SetMiterLimit(aMiterLimit);
+ aTestPen.SetLineJoin(Gdiplus::LineJoinMiter);
+ break;
+ }
+ case basegfx::B2DLINEJOIN_ROUND :
+ {
+ aTestPen.SetLineJoin(Gdiplus::LineJoinRound);
+ break;
+ }
+ }
+
+ if(nCount > 250 && basegfx::fTools::more(rLineWidths.getX(), 1.5))
+ {
+ impAddB2DPolygonToGDIPlusGraphicsPathInteger(aPath, rPolygon, bNoLineJoin);
+ }
+ else
+ {
+ impAddB2DPolygonToGDIPlusGraphicsPathReal(aPath, rPolygon, bNoLineJoin);
+ }
+
+ if(rPolygon.isClosed() && !bNoLineJoin)
+ {
+ // #i101491# needed to create the correct line joins
+ aPath.CloseFigure();
+ }
+
+ if(getAntiAliasB2DDraw())
+ {
+ aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
+ }
+ else
+ {
+ aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeNone);
+ }
+
+ aGraphics.DrawPath(&aTestPen, &aPath);
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
diff --git a/vcl/win/source/gdi/salnativewidgets-luna.cxx b/vcl/win/source/gdi/salnativewidgets-luna.cxx
new file mode 100644
index 000000000000..be5d7f8360bc
--- /dev/null
+++ b/vcl/win/source/gdi/salnativewidgets-luna.cxx
@@ -0,0 +1,1288 @@
+/*************************************************************************
+ *
+ * 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 _SV_SALNATIVEWIDGETS_CXX
+
+#include "svsys.h"
+#include "salgdi.h"
+#include "saldata.hxx"
+#include "vcl/svapp.hxx"
+
+#include "rtl/ustring.h"
+#include "osl/module.h"
+
+#include "uxtheme.h"
+#include "vssym32.h"
+
+#include <map>
+#include <string>
+
+using namespace rtl;
+using namespace std;
+
+typedef map< wstring, HTHEME > ThemeMap;
+static ThemeMap aThemeMap;
+
+
+/****************************************************
+ wrap visual styles API to avoid linking against it
+ it is not available on all Windows platforms
+*****************************************************/
+
+class VisualStylesAPI
+{
+private:
+ typedef HTHEME (WINAPI * OpenThemeData_Proc_T) ( HWND hwnd, LPCWSTR pszClassList );
+ typedef HRESULT (WINAPI * CloseThemeData_Proc_T) ( HTHEME hTheme );
+ typedef HRESULT (WINAPI * GetThemeBackgroundContentRect_Proc_T) ( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pBoundingRect, RECT *pContentRect );
+ typedef HRESULT (WINAPI * DrawThemeBackground_Proc_T) ( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, const RECT *pClipRect );
+ typedef HRESULT (WINAPI * DrawThemeText_Proc_T) ( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, const RECT *pRect );
+ typedef HRESULT (WINAPI * GetThemePartSize_Proc_T) ( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, RECT *prc, THEMESIZE eSize, SIZE *psz );
+
+ OpenThemeData_Proc_T lpfnOpenThemeData;
+ CloseThemeData_Proc_T lpfnCloseThemeData;
+ GetThemeBackgroundContentRect_Proc_T lpfnGetThemeBackgroundContentRect;
+ DrawThemeBackground_Proc_T lpfnDrawThemeBackground;
+ DrawThemeText_Proc_T lpfnDrawThemeText;
+ GetThemePartSize_Proc_T lpfnGetThemePartSize;
+
+ oslModule mhModule;
+
+public:
+ VisualStylesAPI();
+ ~VisualStylesAPI();
+ BOOL IsAvailable() { return (mhModule != NULL); }
+
+ HTHEME OpenThemeData( HWND hwnd, LPCWSTR pszClassList );
+ HRESULT CloseThemeData( HTHEME hTheme );
+ HRESULT GetThemeBackgroundContentRect( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pBoundingRect, RECT *pContentRect );
+ HRESULT DrawThemeBackground( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, const RECT *pClipRect );
+ HRESULT DrawThemeText( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, const RECT *pRect );
+ HRESULT GetThemePartSize( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, RECT *prc, THEMESIZE eSize, SIZE *psz );
+};
+
+static VisualStylesAPI vsAPI;
+
+VisualStylesAPI::VisualStylesAPI()
+{
+ OUString aLibraryName( RTL_CONSTASCII_USTRINGPARAM( "uxtheme.dll" ) );
+ mhModule = osl_loadModule( aLibraryName.pData, SAL_LOADMODULE_DEFAULT );
+
+ if ( mhModule )
+ {
+ lpfnOpenThemeData = (OpenThemeData_Proc_T)osl_getAsciiFunctionSymbol( mhModule, "OpenThemeData" );
+ lpfnCloseThemeData = (CloseThemeData_Proc_T)osl_getAsciiFunctionSymbol( mhModule, "CloseThemeData" );
+ lpfnGetThemeBackgroundContentRect = (GetThemeBackgroundContentRect_Proc_T)osl_getAsciiFunctionSymbol( mhModule, "GetThemeBackgroundContentRect" );
+ lpfnDrawThemeBackground = (DrawThemeBackground_Proc_T)osl_getAsciiFunctionSymbol( mhModule, "DrawThemeBackground" );
+ lpfnDrawThemeText = (DrawThemeText_Proc_T)osl_getAsciiFunctionSymbol( mhModule, "DrawThemeText" );
+ lpfnGetThemePartSize = (GetThemePartSize_Proc_T)osl_getAsciiFunctionSymbol( mhModule, "GetThemePartSize" );
+ }
+ else
+ {
+ lpfnOpenThemeData = NULL;
+ lpfnCloseThemeData = NULL;
+ lpfnGetThemeBackgroundContentRect = NULL;
+ lpfnDrawThemeBackground = NULL;
+ lpfnDrawThemeText = NULL;
+ lpfnGetThemePartSize = NULL;
+ }
+}
+VisualStylesAPI::~VisualStylesAPI()
+{
+ if( mhModule )
+ osl_unloadModule( mhModule );
+}
+HTHEME VisualStylesAPI::OpenThemeData( HWND hwnd, LPCWSTR pszClassList )
+{
+ if(lpfnOpenThemeData)
+ return (*lpfnOpenThemeData) (hwnd, pszClassList);
+ else
+ return NULL;
+}
+
+HRESULT VisualStylesAPI::CloseThemeData( HTHEME hTheme )
+{
+ if(lpfnCloseThemeData)
+ return (*lpfnCloseThemeData) (hTheme);
+ else
+ return S_FALSE;
+}
+HRESULT VisualStylesAPI::GetThemeBackgroundContentRect( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pBoundingRect, RECT *pContentRect )
+{
+ if(lpfnGetThemeBackgroundContentRect)
+ return (*lpfnGetThemeBackgroundContentRect) ( hTheme, hdc, iPartId, iStateId, pBoundingRect, pContentRect );
+ else
+ return S_FALSE;
+}
+HRESULT VisualStylesAPI::DrawThemeBackground( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, const RECT *pClipRect )
+{
+ if(lpfnDrawThemeBackground)
+ return (*lpfnDrawThemeBackground) (hTheme, hdc, iPartId, iStateId, pRect, pClipRect);
+ else
+ return S_FALSE;
+}
+HRESULT VisualStylesAPI::DrawThemeText( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, const RECT *pRect )
+{
+ if(lpfnDrawThemeText)
+ return (*lpfnDrawThemeText) (hTheme, hdc, iPartId, iStateId, pszText, iCharCount, dwTextFlags, dwTextFlags2, pRect);
+ else
+ return S_FALSE;
+}
+HRESULT VisualStylesAPI::GetThemePartSize( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, RECT *prc, THEMESIZE eSize, SIZE *psz )
+{
+ if(lpfnGetThemePartSize)
+ return (*lpfnGetThemePartSize) (hTheme, hdc, iPartId, iStateId, prc, eSize, psz);
+ else
+ return S_FALSE;
+}
+
+
+/*********************************************************
+ * Initialize XP theming and local stuff
+ *********************************************************/
+void SalData::initNWF( void )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ // the menu bar and the top docking area should have a common background (gradient)
+ pSVData->maNWFData.mbMenuBarDockingAreaCommonBG = true;
+}
+
+
+// *********************************************************
+// * Release theming handles
+// ********************************************************
+void SalData::deInitNWF( void )
+{
+ ThemeMap::iterator iter = aThemeMap.begin();
+ while( iter != aThemeMap.end() )
+ {
+ vsAPI.CloseThemeData(iter->second);
+ iter++;
+ }
+ aThemeMap.clear();
+}
+
+static HTHEME getThemeHandle( HWND hWnd, LPCWSTR name )
+{
+ if( GetSalData()->mbThemeChanged )
+ {
+ // throw away invalid theme handles
+ GetSalData()->deInitNWF();
+ GetSalData()->mbThemeChanged = FALSE;
+ }
+
+ ThemeMap::iterator iter;
+ if( (iter = aThemeMap.find( name )) != aThemeMap.end() )
+ return iter->second;
+ // theme not found -> add it to map
+ HTHEME hTheme = vsAPI.OpenThemeData( hWnd, name );
+ if( hTheme != NULL )
+ aThemeMap[name] = hTheme;
+ return hTheme;
+}
+
+/*
+ * IsNativeControlSupported()
+ *
+ * Returns TRUE if the platform supports native
+ * drawing of the control defined by nPart
+ */
+BOOL WinSalGraphics::IsNativeControlSupported( ControlType nType, ControlPart nPart )
+{
+ HTHEME hTheme = NULL;
+
+ switch( nType )
+ {
+ case CTRL_PUSHBUTTON:
+ case CTRL_RADIOBUTTON:
+ case CTRL_CHECKBOX:
+ if( nPart == PART_ENTIRE_CONTROL )
+ hTheme = getThemeHandle( mhWnd, L"Button");
+ break;
+ case CTRL_SCROLLBAR:
+ if( nPart == PART_DRAW_BACKGROUND_HORZ || nPart == PART_DRAW_BACKGROUND_VERT )
+ return FALSE; // no background painting needed
+ if( nPart == PART_ENTIRE_CONTROL )
+ hTheme = getThemeHandle( mhWnd, L"Scrollbar");
+ break;
+ case CTRL_COMBOBOX:
+ if( nPart == HAS_BACKGROUND_TEXTURE )
+ return FALSE; // we do not paint the inner part (ie the selection background/focus indication)
+ if( nPart == PART_ENTIRE_CONTROL )
+ hTheme = getThemeHandle( mhWnd, L"Edit");
+ else if( nPart == PART_BUTTON_DOWN )
+ hTheme = getThemeHandle( mhWnd, L"Combobox");
+ break;
+ case CTRL_SPINBOX:
+ if( nPart == PART_ENTIRE_CONTROL )
+ hTheme = getThemeHandle( mhWnd, L"Edit");
+ else if( nPart == PART_ALL_BUTTONS ||
+ nPart == PART_BUTTON_UP || nPart == PART_BUTTON_DOWN ||
+ nPart == PART_BUTTON_LEFT|| nPart == PART_BUTTON_RIGHT )
+ hTheme = getThemeHandle( mhWnd, L"Spin");
+ break;
+ case CTRL_SPINBUTTONS:
+ if( nPart == PART_ENTIRE_CONTROL || nPart == PART_ALL_BUTTONS )
+ hTheme = getThemeHandle( mhWnd, L"Spin");
+ break;
+ case CTRL_EDITBOX:
+ case CTRL_MULTILINE_EDITBOX:
+ if( nPart == HAS_BACKGROUND_TEXTURE )
+ return FALSE; // we do not paint the inner part (ie the selection background/focus indication)
+ //return TRUE;
+ if( nPart == PART_ENTIRE_CONTROL )
+ hTheme = getThemeHandle( mhWnd, L"Edit");
+ break;
+ case CTRL_LISTBOX:
+ if( nPart == HAS_BACKGROUND_TEXTURE )
+ return FALSE; // we do not paint the inner part (ie the selection background/focus indication)
+ if( nPart == PART_ENTIRE_CONTROL || nPart == PART_WINDOW )
+ hTheme = getThemeHandle( mhWnd, L"Listview");
+ else if( nPart == PART_BUTTON_DOWN )
+ hTheme = getThemeHandle( mhWnd, L"Combobox");
+ break;
+ case CTRL_TAB_PANE:
+ case CTRL_TAB_BODY:
+ case CTRL_TAB_ITEM:
+ case CTRL_FIXEDBORDER:
+ if( nPart == PART_ENTIRE_CONTROL )
+ hTheme = getThemeHandle( mhWnd, L"Tab");
+ break;
+ case CTRL_TOOLBAR:
+ if( nPart == PART_ENTIRE_CONTROL || nPart == PART_BUTTON )
+ hTheme = getThemeHandle( mhWnd, L"Toolbar");
+ else
+ // use rebar theme for grip and background
+ hTheme = getThemeHandle( mhWnd, L"Rebar");
+ break;
+ case CTRL_MENUBAR:
+ if( nPart == PART_ENTIRE_CONTROL )
+ hTheme = getThemeHandle( mhWnd, L"Rebar");
+ break;
+ case CTRL_PROGRESS:
+ if( nPart == PART_ENTIRE_CONTROL )
+ hTheme = getThemeHandle( mhWnd, L"Progress");
+ break;
+ case CTRL_SLIDER:
+ if( nPart == PART_TRACK_HORZ_AREA || nPart == PART_TRACK_VERT_AREA )
+ hTheme = getThemeHandle( mhWnd, L"Trackbar" );
+ break;
+ case CTRL_LISTNODE:
+ if( nPart == PART_ENTIRE_CONTROL )
+ hTheme = getThemeHandle( mhWnd, L"TreeView" );
+ break;
+ default:
+ hTheme = NULL;
+ break;
+ }
+
+ return (hTheme != NULL);
+}
+
+
+/*
+ * 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 WinSalGraphics::hitTestNativeControl( ControlType,
+ ControlPart,
+ const Region&,
+ const Point&,
+ BOOL& )
+{
+ return FALSE;
+}
+
+BOOL ImplDrawTheme( HTHEME hTheme, HDC hDC, int iPart, int iState, RECT rc, const OUString& aStr)
+{
+ HRESULT hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, 0);
+
+ if( aStr.getLength() )
+ {
+ RECT rcContent;
+ hr = vsAPI.GetThemeBackgroundContentRect( hTheme, hDC, iPart, iState, &rc, &rcContent);
+ hr = vsAPI.DrawThemeText( hTheme, hDC, iPart, iState,
+ reinterpret_cast<LPCWSTR>(aStr.getStr()), -1,
+ DT_CENTER | DT_VCENTER | DT_SINGLELINE,
+ 0, &rcContent);
+ }
+ return (hr == S_OK);
+}
+
+
+Rectangle ImplGetThemeRect( HTHEME hTheme, HDC hDC, int iPart, int iState, const Rectangle& aRect, THEMESIZE eTS = TS_TRUE )
+{
+ SIZE aSz;
+ RECT rc;
+ rc.left = aRect.nLeft;
+ rc.right = aRect.nRight;
+ rc.top = aRect.nTop;
+ rc.bottom = aRect.nBottom;
+ HRESULT hr = vsAPI.GetThemePartSize( hTheme, hDC, iPart, iState, NULL, eTS, &aSz ); // TS_TRUE returns optimal size
+ if( hr == S_OK )
+ return Rectangle( 0, 0, aSz.cx, aSz.cy );
+ else
+ return Rectangle();
+}
+
+// Helper functions
+// ----
+
+void ImplConvertSpinbuttonValues( int nControlPart, const ControlState& rState, const Rectangle& rRect,
+ int* pLunaPart, int *pLunaState, RECT *pRect )
+{
+ if( nControlPart == PART_BUTTON_DOWN )
+ {
+ *pLunaPart = SPNP_DOWN;
+ if( rState & CTRL_STATE_PRESSED )
+ *pLunaState = DNS_PRESSED;
+ else if( !(rState & CTRL_STATE_ENABLED) )
+ *pLunaState = DNS_DISABLED;
+ else if( rState & CTRL_STATE_ROLLOVER )
+ *pLunaState = DNS_HOT;
+ else
+ *pLunaState = DNS_NORMAL;
+ }
+ if( nControlPart == PART_BUTTON_UP )
+ {
+ *pLunaPart = SPNP_UP;
+ if( rState & CTRL_STATE_PRESSED )
+ *pLunaState = UPS_PRESSED;
+ else if( !(rState & CTRL_STATE_ENABLED) )
+ *pLunaState = UPS_DISABLED;
+ else if( rState & CTRL_STATE_ROLLOVER )
+ *pLunaState = UPS_HOT;
+ else
+ *pLunaState = UPS_NORMAL;
+ }
+ if( nControlPart == PART_BUTTON_RIGHT )
+ {
+ *pLunaPart = SPNP_UPHORZ;
+ if( rState & CTRL_STATE_PRESSED )
+ *pLunaState = DNHZS_PRESSED;
+ else if( !(rState & CTRL_STATE_ENABLED) )
+ *pLunaState = DNHZS_DISABLED;
+ else if( rState & CTRL_STATE_ROLLOVER )
+ *pLunaState = DNHZS_HOT;
+ else
+ *pLunaState = DNHZS_NORMAL;
+ }
+ if( nControlPart == PART_BUTTON_LEFT )
+ {
+ *pLunaPart = SPNP_DOWNHORZ;
+ if( rState & CTRL_STATE_PRESSED )
+ *pLunaState = UPHZS_PRESSED;
+ else if( !(rState & CTRL_STATE_ENABLED) )
+ *pLunaState = UPHZS_DISABLED;
+ else if( rState & CTRL_STATE_ROLLOVER )
+ *pLunaState = UPHZS_HOT;
+ else
+ *pLunaState = UPHZS_NORMAL;
+ }
+
+ pRect->left = rRect.Left();
+ pRect->right = rRect.Right()+1;
+ pRect->top = rRect.Top();
+ pRect->bottom = rRect.Bottom()+1;
+}
+
+// ----
+
+BOOL ImplDrawNativeControl( HDC hDC, HTHEME hTheme, RECT rc,
+ ControlType nType,
+ ControlPart nPart,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ OUString aCaption )
+{
+ // a listbox dropdown is actually a combobox dropdown
+ if( nType == CTRL_LISTBOX )
+ if( nPart == PART_BUTTON_DOWN )
+ nType = CTRL_COMBOBOX;
+
+ // draw entire combobox as a large edit box
+ if( nType == CTRL_COMBOBOX )
+ if( nPart == PART_ENTIRE_CONTROL )
+ nType = CTRL_EDITBOX;
+
+ // draw entire spinbox as a large edit box
+ if( nType == CTRL_SPINBOX )
+ if( nPart == PART_ENTIRE_CONTROL )
+ nType = CTRL_EDITBOX;
+
+ int iPart(0), iState(0);
+ if( nType == CTRL_SCROLLBAR )
+ {
+ HRESULT hr;
+ if( nPart == PART_BUTTON_UP )
+ {
+ iPart = SBP_ARROWBTN;
+ if( nState & CTRL_STATE_PRESSED )
+ iState = ABS_UPPRESSED;
+ else if( !(nState & CTRL_STATE_ENABLED) )
+ iState = ABS_UPDISABLED;
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = ABS_UPHOT;
+ else
+ iState = ABS_UPNORMAL;
+ hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, 0);
+ return (hr == S_OK);
+ }
+ if( nPart == PART_BUTTON_DOWN )
+ {
+ iPart = SBP_ARROWBTN;
+ if( nState & CTRL_STATE_PRESSED )
+ iState = ABS_DOWNPRESSED;
+ else if( !(nState & CTRL_STATE_ENABLED) )
+ iState = ABS_DOWNDISABLED;
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = ABS_DOWNHOT;
+ else
+ iState = ABS_DOWNNORMAL;
+ hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, 0);
+ return (hr == S_OK);
+ }
+ if( nPart == PART_BUTTON_LEFT )
+ {
+ iPart = SBP_ARROWBTN;
+ if( nState & CTRL_STATE_PRESSED )
+ iState = ABS_LEFTPRESSED;
+ else if( !(nState & CTRL_STATE_ENABLED) )
+ iState = ABS_LEFTDISABLED;
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = ABS_LEFTHOT;
+ else
+ iState = ABS_LEFTNORMAL;
+ hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, 0);
+ return (hr == S_OK);
+ }
+ if( nPart == PART_BUTTON_RIGHT )
+ {
+ iPart = SBP_ARROWBTN;
+ if( nState & CTRL_STATE_PRESSED )
+ iState = ABS_RIGHTPRESSED;
+ else if( !(nState & CTRL_STATE_ENABLED) )
+ iState = ABS_RIGHTDISABLED;
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = ABS_RIGHTHOT;
+ else
+ iState = ABS_RIGHTNORMAL;
+ hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, 0);
+ return (hr == S_OK);
+ }
+ if( nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT )
+ {
+ iPart = (nPart == PART_THUMB_HORZ) ? SBP_THUMBBTNHORZ : SBP_THUMBBTNVERT;
+ if( nState & CTRL_STATE_PRESSED )
+ iState = SCRBS_PRESSED;
+ else if( !(nState & CTRL_STATE_ENABLED) )
+ iState = SCRBS_DISABLED;
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = SCRBS_HOT;
+ else
+ iState = SCRBS_NORMAL;
+
+ SIZE sz;
+ vsAPI.GetThemePartSize(hTheme, hDC, iPart, iState, NULL, TS_MIN, &sz);
+ vsAPI.GetThemePartSize(hTheme, hDC, iPart, iState, NULL, TS_TRUE, &sz);
+ vsAPI.GetThemePartSize(hTheme, hDC, iPart, iState, NULL, TS_DRAW, &sz);
+
+ hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, 0);
+ // paint gripper on thumb if enough space
+ if( ( (nPart == PART_THUMB_VERT) && (rc.bottom-rc.top > 12) ) ||
+ ( (nPart == PART_THUMB_HORZ) && (rc.right-rc.left > 12) ) )
+ {
+ iPart = (nPart == PART_THUMB_HORZ) ? SBP_GRIPPERHORZ : SBP_GRIPPERVERT;
+ iState = 0;
+ vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, 0);
+ }
+ return (hr == S_OK);
+ }
+ if( nPart == PART_TRACK_HORZ_LEFT || nPart == PART_TRACK_HORZ_RIGHT || nPart == PART_TRACK_VERT_UPPER || nPart == PART_TRACK_VERT_LOWER )
+ {
+ switch( nPart )
+ {
+ case PART_TRACK_HORZ_LEFT: iPart = SBP_UPPERTRACKHORZ; break;
+ case PART_TRACK_HORZ_RIGHT: iPart = SBP_LOWERTRACKHORZ; break;
+ case PART_TRACK_VERT_UPPER: iPart = SBP_UPPERTRACKVERT; break;
+ case PART_TRACK_VERT_LOWER: iPart = SBP_LOWERTRACKVERT; break;
+ }
+
+ if( nState & CTRL_STATE_PRESSED )
+ iState = SCRBS_PRESSED;
+ else if( !(nState & CTRL_STATE_ENABLED) )
+ iState = SCRBS_DISABLED;
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = SCRBS_HOT;
+ else
+ iState = SCRBS_NORMAL;
+ hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, 0);
+ return (hr == S_OK);
+ }
+ }
+ if( nType == CTRL_SPINBUTTONS && nPart == PART_ALL_BUTTONS )
+ {
+ SpinbuttonValue *pValue = (SpinbuttonValue*) aValue.getOptionalVal();
+ if( pValue )
+ {
+ BOOL bOk = FALSE;
+
+ RECT rect;
+ ImplConvertSpinbuttonValues( pValue->mnUpperPart, pValue->mnUpperState, pValue->maUpperRect, &iPart, &iState, &rect );
+ bOk = ImplDrawTheme( hTheme, hDC, iPart, iState, rect, aCaption);
+
+ if( bOk )
+ {
+ ImplConvertSpinbuttonValues( pValue->mnLowerPart, pValue->mnLowerState, pValue->maLowerRect, &iPart, &iState, &rect );
+ bOk = ImplDrawTheme( hTheme, hDC, iPart, iState, rect, aCaption);
+ }
+
+ return bOk;
+ }
+ }
+ if( nType == CTRL_SPINBOX )
+ {
+ // decrease spinbutton rects a little
+ //rc.right--;
+ //rc.bottom--;
+ if( nPart == PART_ALL_BUTTONS )
+ {
+ SpinbuttonValue *pValue = (SpinbuttonValue*) aValue.getOptionalVal();
+ if( pValue )
+ {
+ BOOL bOk = FALSE;
+
+ RECT rect;
+ ImplConvertSpinbuttonValues( pValue->mnUpperPart, pValue->mnUpperState, pValue->maUpperRect, &iPart, &iState, &rect );
+ bOk = ImplDrawTheme( hTheme, hDC, iPart, iState, rect, aCaption);
+
+ if( bOk )
+ {
+ ImplConvertSpinbuttonValues( pValue->mnLowerPart, pValue->mnLowerState, pValue->maLowerRect, &iPart, &iState, &rect );
+ bOk = ImplDrawTheme( hTheme, hDC, iPart, iState, rect, aCaption);
+ }
+
+ return bOk;
+ }
+ }
+
+ if( nPart == PART_BUTTON_DOWN )
+ {
+ iPart = SPNP_DOWN;
+ if( nState & CTRL_STATE_PRESSED )
+ iState = DNS_PRESSED;
+ else if( !(nState & CTRL_STATE_ENABLED) )
+ iState = DNS_DISABLED;
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = DNS_HOT;
+ else
+ iState = DNS_NORMAL;
+ }
+ if( nPart == PART_BUTTON_UP )
+ {
+ iPart = SPNP_UP;
+ if( nState & CTRL_STATE_PRESSED )
+ iState = UPS_PRESSED;
+ else if( !(nState & CTRL_STATE_ENABLED) )
+ iState = UPS_DISABLED;
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = UPS_HOT;
+ else
+ iState = UPS_NORMAL;
+ }
+ if( nPart == PART_BUTTON_RIGHT )
+ {
+ iPart = SPNP_DOWNHORZ;
+ if( nState & CTRL_STATE_PRESSED )
+ iState = DNHZS_PRESSED;
+ else if( !(nState & CTRL_STATE_ENABLED) )
+ iState = DNHZS_DISABLED;
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = DNHZS_HOT;
+ else
+ iState = DNHZS_NORMAL;
+ }
+ if( nPart == PART_BUTTON_LEFT )
+ {
+ iPart = SPNP_UPHORZ;
+ if( nState & CTRL_STATE_PRESSED )
+ iState = UPHZS_PRESSED;
+ else if( !(nState & CTRL_STATE_ENABLED) )
+ iState = UPHZS_DISABLED;
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = UPHZS_HOT;
+ else
+ iState = UPHZS_NORMAL;
+ }
+ if( nPart == PART_BUTTON_LEFT || nPart == PART_BUTTON_RIGHT || nPart == PART_BUTTON_UP || nPart == PART_BUTTON_DOWN )
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
+ }
+ if( nType == CTRL_COMBOBOX )
+ {
+ if( nPart == PART_BUTTON_DOWN )
+ {
+ iPart = CP_DROPDOWNBUTTON;
+ if( nState & CTRL_STATE_PRESSED )
+ iState = CBXS_PRESSED;
+ else if( !(nState & CTRL_STATE_ENABLED) )
+ iState = CBXS_DISABLED;
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = CBXS_HOT;
+ else
+ iState = CBXS_NORMAL;
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
+ }
+ }
+ if( nType == CTRL_PUSHBUTTON )
+ {
+ iPart = BP_PUSHBUTTON;
+ if( nState & CTRL_STATE_PRESSED )
+ iState = PBS_PRESSED;
+ else if( !(nState & CTRL_STATE_ENABLED) )
+ iState = PBS_DISABLED;
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = PBS_HOT;
+ else if( nState & CTRL_STATE_DEFAULT )
+ iState = PBS_DEFAULTED;
+ //else if( nState & CTRL_STATE_FOCUSED )
+ // iState = PBS_DEFAULTED; // may need to draw focus rect
+ else
+ iState = PBS_NORMAL;
+
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
+ }
+
+ if( nType == CTRL_RADIOBUTTON )
+ {
+ iPart = BP_RADIOBUTTON;
+ BOOL bChecked = ( aValue.getTristateVal() == BUTTONVALUE_ON );
+
+ if( nState & CTRL_STATE_PRESSED )
+ iState = bChecked ? RBS_CHECKEDPRESSED : RBS_UNCHECKEDPRESSED;
+ else if( !(nState & CTRL_STATE_ENABLED) )
+ iState = bChecked ? RBS_CHECKEDDISABLED : RBS_UNCHECKEDDISABLED;
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = bChecked ? RBS_CHECKEDHOT : RBS_UNCHECKEDHOT;
+ else
+ iState = bChecked ? RBS_CHECKEDNORMAL : RBS_UNCHECKEDNORMAL;
+
+ //if( nState & CTRL_STATE_FOCUSED )
+ // iState |= PBS_DEFAULTED; // may need to draw focus rect
+
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
+ }
+
+ if( nType == CTRL_CHECKBOX )
+ {
+ iPart = BP_CHECKBOX;
+ ButtonValue v = aValue.getTristateVal();
+
+ if( nState & CTRL_STATE_PRESSED )
+ iState = (v == BUTTONVALUE_ON) ? CBS_CHECKEDPRESSED :
+ ( (v == BUTTONVALUE_OFF) ? CBS_UNCHECKEDPRESSED : CBS_MIXEDPRESSED );
+ else if( !(nState & CTRL_STATE_ENABLED) )
+ iState = (v == BUTTONVALUE_ON) ? CBS_CHECKEDDISABLED :
+ ( (v == BUTTONVALUE_OFF) ? CBS_UNCHECKEDDISABLED : CBS_MIXEDDISABLED );
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = (v == BUTTONVALUE_ON) ? CBS_CHECKEDHOT :
+ ( (v == BUTTONVALUE_OFF) ? CBS_UNCHECKEDHOT : CBS_MIXEDHOT );
+ else
+ iState = (v == BUTTONVALUE_ON) ? CBS_CHECKEDNORMAL :
+ ( (v == BUTTONVALUE_OFF) ? CBS_UNCHECKEDNORMAL : CBS_MIXEDNORMAL );
+
+ //if( nState & CTRL_STATE_FOCUSED )
+ // iState |= PBS_DEFAULTED; // may need to draw focus rect
+
+ //SIZE sz;
+ //THEMESIZE eSize = TS_DRAW; // TS_MIN, TS_TRUE, TS_DRAW
+ //vsAPI.GetThemePartSize( hTheme, hDC, iPart, iState, &rc, eSize, &sz);
+
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
+ }
+
+ if( ( nType == CTRL_EDITBOX ) || ( nType == CTRL_MULTILINE_EDITBOX ) )
+ {
+ iPart = EP_EDITTEXT;
+ if( !(nState & CTRL_STATE_ENABLED) )
+ iState = ETS_DISABLED;
+ else if( nState & CTRL_STATE_FOCUSED )
+ iState = ETS_FOCUSED;
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = ETS_HOT;
+ else
+ iState = ETS_NORMAL;
+
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
+ }
+
+ if( nType == CTRL_LISTBOX )
+ {
+ if( nPart == PART_ENTIRE_CONTROL || nPart == PART_WINDOW )
+ {
+ iPart = LVP_EMPTYTEXT; // ??? no idea which part to choose here
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
+ }
+ }
+
+ if( nType == CTRL_TAB_PANE )
+ {
+ iPart = TABP_PANE;
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
+ }
+
+ if( nType == CTRL_FIXEDBORDER )
+ {
+ /*
+ iPart = BP_GROUPBOX;
+ if( !(nState & CTRL_STATE_ENABLED) )
+ iState = GBS_DISABLED;
+ else
+ iState = GBS_NORMAL;
+ */
+ // The fixed border is only used around the tools->options tabpage where
+ // TABP_PANE fits best
+ iPart = TABP_PANE;
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
+ }
+
+ if( nType == CTRL_TAB_BODY )
+ {
+ iPart = TABP_BODY;
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
+ }
+
+ if( nType == CTRL_TAB_ITEM )
+ {
+ iPart = TABP_TABITEMLEFTEDGE;
+ rc.bottom--;
+
+ TabitemValue *pValue = (TabitemValue*) aValue.getOptionalVal();
+ if( pValue )
+ {
+ if( pValue->isBothAligned() )
+ {
+ iPart = TABP_TABITEMLEFTEDGE;
+ rc.right--;
+ }
+ else if( pValue->isLeftAligned() )
+ iPart = TABP_TABITEMLEFTEDGE;
+ else if( pValue->isRightAligned() )
+ iPart = TABP_TABITEMRIGHTEDGE;
+ else iPart = TABP_TABITEM;
+ }
+
+ if( !(nState & CTRL_STATE_ENABLED) )
+ iState = TILES_DISABLED;
+ else if( nState & CTRL_STATE_SELECTED )
+ {
+ iState = TILES_SELECTED;
+ // increase the selected tab
+ rc.left-=2;
+ if( pValue && !pValue->isBothAligned() )
+ {
+ if( pValue->isLeftAligned() || pValue->isNotAligned() )
+ rc.right+=2;
+ if( pValue->isRightAligned() )
+ rc.right+=1;
+ }
+ rc.top-=2;
+ rc.bottom+=2;
+ }
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = TILES_HOT;
+ else if( nState & CTRL_STATE_FOCUSED )
+ iState = TILES_FOCUSED; // may need to draw focus rect
+ else
+ iState = TILES_NORMAL;
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
+ }
+
+ if( nType == CTRL_TOOLBAR )
+ {
+ if( nPart == PART_BUTTON )
+ {
+ iPart = TP_BUTTON;
+ BOOL bChecked = ( aValue.getTristateVal() == BUTTONVALUE_ON );
+ if( !(nState & CTRL_STATE_ENABLED) )
+ //iState = TS_DISABLED;
+ // disabled buttons are typically not painted at all but we need visual
+ // feedback when travelling by keyboard over disabled entries
+ iState = TS_HOT;
+ else if( nState & CTRL_STATE_PRESSED )
+ iState = TS_PRESSED;
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = bChecked ? TS_HOTCHECKED : TS_HOT;
+ else
+ iState = bChecked ? TS_CHECKED : TS_NORMAL;
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
+ }
+ else if( nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT )
+ {
+ // the vertical gripper is not supported in most themes and it makes no
+ // sense to only support horizontal gripper
+ //iPart = (nPart == PART_THUMB_HORZ) ? RP_GRIPPERVERT : RP_GRIPPER;
+ //return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
+ }
+ else if( nPart == PART_DRAW_BACKGROUND_HORZ || nPart == PART_DRAW_BACKGROUND_VERT )
+ {
+ ToolbarValue *pValue = (ToolbarValue*) aValue.getOptionalVal();
+ if( pValue && pValue->mbIsTopDockingArea )
+ rc.top = 0; // extend potential gradient to cover menu bar as well
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
+ }
+ }
+
+ if( nType == CTRL_MENUBAR )
+ {
+ if( nPart != PART_ENTIRE_CONTROL )
+ return FALSE;
+
+ MenubarValue *pValue = (MenubarValue*) aValue.getOptionalVal();
+ if( pValue )
+ rc.bottom += pValue->maTopDockingAreaHeight; // extend potential gradient to cover docking area as well
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
+ }
+
+ if( nType == CTRL_PROGRESS )
+ {
+ if( nPart != PART_ENTIRE_CONTROL )
+ return FALSE;
+
+ if( ! ImplDrawTheme( hTheme, hDC, PP_BAR, iState, rc, aCaption) )
+ return false;
+ RECT aProgressRect = rc;
+ if( vsAPI.GetThemeBackgroundContentRect( hTheme, hDC, PP_BAR, iState, &rc, &aProgressRect) != S_OK )
+ return false;
+
+ long nProgressWidth = aValue.getNumericVal();
+ nProgressWidth *= (aProgressRect.right - aProgressRect.left);
+ nProgressWidth /= (rc.right - rc.left);
+ if( Application::GetSettings().GetLayoutRTL() )
+ aProgressRect.left = aProgressRect.right - nProgressWidth;
+ else
+ aProgressRect.right = aProgressRect.left + nProgressWidth;
+
+ return ImplDrawTheme( hTheme, hDC, PP_CHUNK, iState, aProgressRect, aCaption );
+ }
+
+ if( nType == CTRL_SLIDER )
+ {
+ iPart = (nPart == PART_TRACK_HORZ_AREA) ? TKP_TRACK : TKP_TRACKVERT;
+ iState = (nPart == PART_TRACK_HORZ_AREA) ? TRS_NORMAL : TRVS_NORMAL;
+
+ Rectangle aTrackRect = ImplGetThemeRect( hTheme, hDC, iPart, iState, Rectangle() );
+ RECT aTRect = rc;
+ if( nPart == PART_TRACK_HORZ_AREA )
+ {
+ long nH = aTrackRect.GetHeight();
+ aTRect.top += (rc.bottom - rc.top - nH)/2;
+ aTRect.bottom = aTRect.top + nH;
+ }
+ else
+ {
+ long nW = aTrackRect.GetWidth();
+ aTRect.left += (rc.right - rc.left - nW)/2;
+ aTRect.right = aTRect.left + nW;
+ }
+ ImplDrawTheme( hTheme, hDC, iPart, iState, aTRect, aCaption );
+
+ RECT aThumbRect;
+ SliderValue* pVal = (SliderValue*)aValue.getOptionalVal();
+ aThumbRect.left = pVal->maThumbRect.Left();
+ aThumbRect.top = pVal->maThumbRect.Top();
+ aThumbRect.right = pVal->maThumbRect.Right();
+ aThumbRect.bottom = pVal->maThumbRect.Bottom();
+ iPart = (nPart == PART_TRACK_HORZ_AREA) ? TKP_THUMB : TKP_THUMBVERT;
+ iState = (nState & CTRL_STATE_ENABLED) ? TUS_NORMAL : TUS_DISABLED;
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, aThumbRect, aCaption );
+ }
+
+ if( nType == CTRL_LISTNODE )
+ {
+ if( nPart != PART_ENTIRE_CONTROL )
+ return FALSE;
+
+ ButtonValue aButtonValue = aValue.getTristateVal();
+ iPart = TVP_GLYPH;
+ switch( aButtonValue )
+ {
+ case BUTTONVALUE_ON:
+ iState = GLPS_OPENED;
+ break;
+ case BUTTONVALUE_OFF:
+ iState = GLPS_CLOSED;
+ break;
+ default:
+ return FALSE;
+ }
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption );
+ }
+
+ 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 WinSalGraphics::drawNativeControl( ControlType nType,
+ ControlPart nPart,
+ const Region& rControlRegion,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const OUString& aCaption )
+{
+ BOOL bOk = false;
+ HTHEME hTheme = NULL;
+
+ switch( nType )
+ {
+ case CTRL_PUSHBUTTON:
+ case CTRL_RADIOBUTTON:
+ case CTRL_CHECKBOX:
+ hTheme = getThemeHandle( mhWnd, L"Button");
+ break;
+ case CTRL_SCROLLBAR:
+ hTheme = getThemeHandle( mhWnd, L"Scrollbar");
+ break;
+ case CTRL_COMBOBOX:
+ if( nPart == PART_ENTIRE_CONTROL )
+ hTheme = getThemeHandle( mhWnd, L"Edit");
+ else if( nPart == PART_BUTTON_DOWN )
+ hTheme = getThemeHandle( mhWnd, L"Combobox");
+ break;
+ case CTRL_SPINBOX:
+ if( nPart == PART_ENTIRE_CONTROL )
+ hTheme = getThemeHandle( mhWnd, L"Edit");
+ else
+ hTheme = getThemeHandle( mhWnd, L"Spin");
+ break;
+ case CTRL_SPINBUTTONS:
+ hTheme = getThemeHandle( mhWnd, L"Spin");
+ break;
+ case CTRL_EDITBOX:
+ case CTRL_MULTILINE_EDITBOX:
+ hTheme = getThemeHandle( mhWnd, L"Edit");
+ break;
+ case CTRL_LISTBOX:
+ if( nPart == PART_ENTIRE_CONTROL || nPart == PART_WINDOW )
+ hTheme = getThemeHandle( mhWnd, L"Listview");
+ else if( nPart == PART_BUTTON_DOWN )
+ hTheme = getThemeHandle( mhWnd, L"Combobox");
+ break;
+ case CTRL_TAB_PANE:
+ case CTRL_TAB_BODY:
+ case CTRL_TAB_ITEM:
+ case CTRL_FIXEDBORDER:
+ hTheme = getThemeHandle( mhWnd, L"Tab");
+ break;
+ case CTRL_TOOLBAR:
+ if( nPart == PART_ENTIRE_CONTROL || nPart == PART_BUTTON )
+ hTheme = getThemeHandle( mhWnd, L"Toolbar");
+ else
+ // use rebar for grip and background
+ hTheme = getThemeHandle( mhWnd, L"Rebar");
+ break;
+ case CTRL_MENUBAR:
+ if( nPart == PART_ENTIRE_CONTROL )
+ hTheme = getThemeHandle( mhWnd, L"Rebar");
+ break;
+ case CTRL_PROGRESS:
+ if( nPart == PART_ENTIRE_CONTROL )
+ hTheme = getThemeHandle( mhWnd, L"Progress");
+ break;
+ case CTRL_LISTNODE:
+ if( nPart == PART_ENTIRE_CONTROL )
+ hTheme = getThemeHandle( mhWnd, L"TreeView");
+ break;
+ case CTRL_SLIDER:
+ if( nPart == PART_TRACK_HORZ_AREA || nPart == PART_TRACK_VERT_AREA )
+ hTheme = getThemeHandle( mhWnd, L"Trackbar" );
+ break;
+ default:
+ hTheme = NULL;
+ break;
+ }
+
+ if( !hTheme )
+ return false;
+
+ Rectangle buttonRect = rControlRegion.GetBoundRect();
+ RECT rc;
+ rc.left = buttonRect.Left();
+ rc.right = buttonRect.Right()+1;
+ rc.top = buttonRect.Top();
+ rc.bottom = buttonRect.Bottom()+1;
+
+ // set default text alignment
+ int ta = SetTextAlign( mhDC, TA_LEFT|TA_TOP|TA_NOUPDATECP );
+
+ OUString aCaptionStr( aCaption.replace('~', '&') ); // translate mnemonics
+ bOk = ImplDrawNativeControl(mhDC, hTheme, rc,
+ nType, nPart, nState, aValue,
+ aCaptionStr );
+
+ // restore alignment
+ SetTextAlign( mhDC, ta );
+
+
+ //GdiFlush();
+
+ return bOk;
+}
+
+
+/*
+ * 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 WinSalGraphics::drawNativeControlText( ControlType,
+ ControlPart,
+ const Region&,
+ 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 WinSalGraphics::getNativeControlRegion( ControlType nType,
+ ControlPart nPart,
+ const Region& rControlRegion,
+ ControlState nState,
+ const ImplControlValue& rControlValue,
+ const OUString&,
+ Region &rNativeBoundingRegion,
+ Region &rNativeContentRegion )
+{
+ BOOL bRet = FALSE;
+
+ HDC hDC = GetDC( mhWnd );
+ if( nType == CTRL_TOOLBAR )
+ {
+ if( nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT )
+ {
+ /*
+ // the vertical gripper is not supported in most themes and it makes no
+ // sense to only support horizontal gripper
+
+ HTHEME hTheme = getThemeHandle( mhWnd, L"Rebar");
+ if( hTheme )
+ {
+ Rectangle aRect( ImplGetThemeRect( hTheme, hDC, nPart == PART_THUMB_HORZ ? RP_GRIPPERVERT : RP_GRIPPER,
+ 0, rControlRegion.GetBoundRect() ) );
+ if( nPart == PART_THUMB_HORZ && !aRect.IsEmpty() )
+ {
+ Rectangle aVertRect( 0, 0, aRect.getHeight(), aRect.getWidth() );
+ rNativeContentRegion = aVertRect;
+ }
+ else
+ rNativeContentRegion = aRect;
+ rNativeBoundingRegion = rNativeContentRegion;
+ if( !rNativeContentRegion.IsEmpty() )
+ bRet = TRUE;
+ }
+ */
+ }
+ if( nPart == PART_BUTTON )
+ {
+ HTHEME hTheme = getThemeHandle( mhWnd, L"Toolbar");
+ if( hTheme )
+ {
+ Rectangle aRect( ImplGetThemeRect( hTheme, hDC, TP_SPLITBUTTONDROPDOWN,
+ TS_HOT, rControlRegion.GetBoundRect() ) );
+ rNativeContentRegion = aRect;
+ rNativeBoundingRegion = rNativeContentRegion;
+ if( !rNativeContentRegion.IsEmpty() )
+ bRet = TRUE;
+ }
+ }
+ }
+ if( nType == CTRL_PROGRESS && nPart == PART_ENTIRE_CONTROL )
+ {
+ HTHEME hTheme = getThemeHandle( mhWnd, L"Progress");
+ if( hTheme )
+ {
+ Rectangle aRect( ImplGetThemeRect( hTheme, hDC, PP_BAR,
+ 0, rControlRegion.GetBoundRect() ) );
+ rNativeContentRegion = aRect;
+ rNativeBoundingRegion = rNativeContentRegion;
+ if( !rNativeContentRegion.IsEmpty() )
+ bRet = TRUE;
+ }
+ }
+ if( (nType == CTRL_LISTBOX || nType == CTRL_COMBOBOX ) && nPart == PART_ENTIRE_CONTROL )
+ {
+ HTHEME hTheme = getThemeHandle( mhWnd, L"Combobox");
+ if( hTheme )
+ {
+ Rectangle aBoxRect( rControlRegion.GetBoundRect() );
+ Rectangle aRect( ImplGetThemeRect( hTheme, hDC, CP_DROPDOWNBUTTON,
+ CBXS_NORMAL, aBoxRect ) );
+ Rectangle aBrdRect( ImplGetThemeRect( hTheme, hDC, CP_BORDER,
+ CBB_HOT, aBoxRect ) );
+ aRect.Top() -= aBrdRect.GetHeight();
+ if( aRect.GetHeight() > aBoxRect.GetHeight() )
+ aBoxRect.Bottom() = aBoxRect.Top() + aRect.GetHeight();
+ if( aRect.GetWidth() > aBoxRect.GetWidth() )
+ aBoxRect.Right() = aBoxRect.Left() + aRect.GetWidth();
+ rNativeContentRegion = aBoxRect;
+ rNativeBoundingRegion = rNativeContentRegion;
+ if( !aRect.IsEmpty() )
+ bRet = TRUE;
+ }
+ }
+
+ if( (nType == CTRL_EDITBOX || nType == CTRL_SPINBOX) && nPart == PART_ENTIRE_CONTROL )
+ {
+ HTHEME hTheme = getThemeHandle( mhWnd, L"Edit");
+ if( hTheme )
+ {
+ // get borderr size
+ Rectangle aBoxRect( rControlRegion.GetBoundRect() );
+ Rectangle aRect( ImplGetThemeRect( hTheme, hDC, EP_BACKGROUNDWITHBORDER,
+ EBWBS_HOT, aBoxRect ) );
+ // ad app font height
+ NONCLIENTMETRICSW aNonClientMetrics;
+ aNonClientMetrics.cbSize = sizeof( aNonClientMetrics );
+ if ( SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, sizeof( aNonClientMetrics ), &aNonClientMetrics, 0 ) )
+ {
+ long nFontHeight = aNonClientMetrics.lfMessageFont.lfHeight;
+ if( nFontHeight < 0 )
+ nFontHeight = -nFontHeight;
+
+ if( aRect.GetHeight() && nFontHeight )
+ {
+ aRect.Bottom() += aRect.GetHeight();
+ aRect.Bottom() += nFontHeight;
+ if( aRect.GetHeight() > aBoxRect.GetHeight() )
+ aBoxRect.Bottom() = aBoxRect.Top() + aRect.GetHeight();
+ if( aRect.GetWidth() > aBoxRect.GetWidth() )
+ aBoxRect.Right() = aBoxRect.Left() + aRect.GetWidth();
+ rNativeContentRegion = aBoxRect;
+ rNativeBoundingRegion = rNativeContentRegion;
+ bRet = TRUE;
+ }
+ }
+ }
+ }
+
+ if( nType == CTRL_SLIDER && ( (nPart == PART_THUMB_HORZ) || (nPart == PART_THUMB_VERT) ) )
+ {
+ HTHEME hTheme = getThemeHandle( mhWnd, L"Trackbar");
+ if( hTheme )
+ {
+ int iPart = (nPart == PART_THUMB_HORZ) ? TKP_THUMB : TKP_THUMBVERT;
+ int iState = (nPart == PART_THUMB_HORZ) ? TUS_NORMAL : TUVS_NORMAL;
+ Rectangle aThumbRect = ImplGetThemeRect( hTheme, hDC, iPart, iState, Rectangle() );
+ if( nPart == PART_THUMB_HORZ )
+ {
+ long nW = aThumbRect.GetWidth();
+ Rectangle aRect( rControlRegion.GetBoundRect() );
+ aRect.Right() = aRect.Left() + nW - 1;
+ rNativeContentRegion = aRect;
+ rNativeBoundingRegion = rNativeContentRegion;
+ }
+ else
+ {
+ long nH = aThumbRect.GetHeight();
+ Rectangle aRect( rControlRegion.GetBoundRect() );
+ aRect.Bottom() = aRect.Top() + nH - 1;
+ rNativeContentRegion = aRect;
+ rNativeBoundingRegion = rNativeContentRegion;
+ }
+ bRet = TRUE;
+ }
+ }
+
+ if ( ( nType == CTRL_TAB_ITEM ) && ( nPart == PART_ENTIRE_CONTROL ) )
+ {
+ Rectangle aControlRect( rControlRegion.GetBoundRect() );
+ rNativeContentRegion = aControlRect;
+
+ --aControlRect.Bottom();
+
+ TabitemValue *pValue = static_cast< TabitemValue* >( rControlValue.getOptionalVal() );
+ if ( pValue )
+ {
+ if ( pValue->isBothAligned() )
+ --aControlRect.Right();
+ }
+
+ if ( nState & CTRL_STATE_SELECTED )
+ {
+ aControlRect.Left() -= 2;
+ if ( pValue && !pValue->isBothAligned() )
+ {
+ if ( pValue->isLeftAligned() || pValue->isNotAligned() )
+ aControlRect.Right() += 2;
+ if ( pValue->isRightAligned() )
+ aControlRect.Right() += 1;
+ }
+ aControlRect.Top() -= 2;
+ aControlRect.Bottom() += 2;
+ }
+ rNativeBoundingRegion = aControlRect;
+ bRet = TRUE;
+ }
+
+ ReleaseDC( mhWnd, hDC );
+ return( bRet );
+}
+
diff --git a/vcl/win/source/gdi/salprn.cxx b/vcl/win/source/gdi/salprn.cxx
new file mode 100644
index 000000000000..9d8d41723f64
--- /dev/null
+++ b/vcl/win/source/gdi/salprn.cxx
@@ -0,0 +1,2364 @@
+/*************************************************************************
+ *
+ * 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/svwin.h>
+
+#ifdef __MINGW32__
+#include <excpt.h>
+#endif
+
+#ifndef _OSL_MODULE_H
+#include <osl/module.h>
+#endif
+#include <wincomp.hxx>
+#include <saldata.hxx>
+#include <salinst.h>
+#include <salgdi.h>
+#include <salframe.h>
+#include <vcl/salptype.hxx>
+#include <salprn.h>
+#include <vcl/print.h>
+#include <vcl/jobset.h>
+
+#include <tools/urlobj.hxx>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
+#include <com/sun/star/ui/dialogs/XFilePicker.hpp>
+#include <com/sun/star/ui/dialogs/XFilterManager.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <comphelper/processfactory.hxx>
+
+#include <malloc.h>
+
+#ifdef __MINGW32__
+#define CATCH_DRIVER_EX_BEGIN \
+ jmp_buf jmpbuf; \
+ __SEHandler han; \
+ if (__builtin_setjmp(jmpbuf) == 0) \
+ { \
+ han.Set(jmpbuf, NULL, (__SEHandler::PF)EXCEPTION_EXECUTE_HANDLER)
+
+#define CATCH_DRIVER_EX_END(mes, p) \
+ } \
+ han.Reset()
+#define CATCH_DRIVER_EX_END_2(mes) \
+ } \
+ han.Reset()
+#else
+#define CATCH_DRIVER_EX_BEGIN \
+ __try \
+ {
+#define CATCH_DRIVER_EX_END(mes, p) \
+ } \
+ __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))\
+ { \
+ DBG_ERROR( mes ); \
+ p->markInvalid(); \
+ }
+#define CATCH_DRIVER_EX_END_2(mes) \
+ } \
+ __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))\
+ { \
+ DBG_ERROR( mes ); \
+ }
+#endif
+
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::ui::dialogs;
+using namespace rtl;
+
+// =======================================================================
+
+static char aImplWindows[] = "windows";
+static char aImplDevices[] = "devices";
+static char aImplDevice[] = "device";
+
+static LPDEVMODEA SAL_DEVMODE_A( const ImplJobSetup* pSetupData )
+{
+ LPDEVMODEA pRet = NULL;
+ SalDriverData* pDrv = (SalDriverData*)pSetupData->mpDriverData;
+ if( pDrv->mnVersion == SAL_DRIVERDATA_VERSION_A &&
+ pSetupData->mnDriverDataLen >= sizeof(DEVMODEA)+sizeof(SalDriverData)-1
+ )
+ pRet = ((LPDEVMODEA)((pSetupData->mpDriverData) + (pDrv->mnDriverOffset)));
+ return pRet;
+}
+
+static LPDEVMODEW SAL_DEVMODE_W( const ImplJobSetup* pSetupData )
+{
+ LPDEVMODEW pRet = NULL;
+ SalDriverData* pDrv = (SalDriverData*)pSetupData->mpDriverData;
+ if( pDrv->mnVersion == SAL_DRIVERDATA_VERSION_W &&
+ pSetupData->mnDriverDataLen >= sizeof(DEVMODEW)+sizeof(SalDriverData)-1
+ )
+ pRet = ((LPDEVMODEW)((pSetupData->mpDriverData) + (pDrv->mnDriverOffset)));
+ return pRet;
+}
+
+// =======================================================================
+
+static ULONG ImplWinQueueStatusToSal( DWORD nWinStatus )
+{
+ ULONG nStatus = 0;
+ if ( nWinStatus & PRINTER_STATUS_PAUSED )
+ nStatus |= QUEUE_STATUS_PAUSED;
+ if ( nWinStatus & PRINTER_STATUS_ERROR )
+ nStatus |= QUEUE_STATUS_ERROR;
+ if ( nWinStatus & PRINTER_STATUS_PENDING_DELETION )
+ nStatus |= QUEUE_STATUS_PENDING_DELETION;
+ if ( nWinStatus & PRINTER_STATUS_PAPER_JAM )
+ nStatus |= QUEUE_STATUS_PAPER_JAM;
+ if ( nWinStatus & PRINTER_STATUS_PAPER_OUT )
+ nStatus |= QUEUE_STATUS_PAPER_OUT;
+ if ( nWinStatus & PRINTER_STATUS_MANUAL_FEED )
+ nStatus |= QUEUE_STATUS_MANUAL_FEED;
+ if ( nWinStatus & PRINTER_STATUS_PAPER_PROBLEM )
+ nStatus |= QUEUE_STATUS_PAPER_PROBLEM;
+ if ( nWinStatus & PRINTER_STATUS_OFFLINE )
+ nStatus |= QUEUE_STATUS_OFFLINE;
+ if ( nWinStatus & PRINTER_STATUS_IO_ACTIVE )
+ nStatus |= QUEUE_STATUS_IO_ACTIVE;
+ if ( nWinStatus & PRINTER_STATUS_BUSY )
+ nStatus |= QUEUE_STATUS_BUSY;
+ if ( nWinStatus & PRINTER_STATUS_PRINTING )
+ nStatus |= QUEUE_STATUS_PRINTING;
+ if ( nWinStatus & PRINTER_STATUS_OUTPUT_BIN_FULL )
+ nStatus |= QUEUE_STATUS_OUTPUT_BIN_FULL;
+ if ( nWinStatus & PRINTER_STATUS_WAITING )
+ nStatus |= QUEUE_STATUS_WAITING;
+ if ( nWinStatus & PRINTER_STATUS_PROCESSING )
+ nStatus |= QUEUE_STATUS_PROCESSING;
+ if ( nWinStatus & PRINTER_STATUS_INITIALIZING )
+ nStatus |= QUEUE_STATUS_INITIALIZING;
+ if ( nWinStatus & PRINTER_STATUS_WARMING_UP )
+ nStatus |= QUEUE_STATUS_WARMING_UP;
+ if ( nWinStatus & PRINTER_STATUS_TONER_LOW )
+ nStatus |= QUEUE_STATUS_TONER_LOW;
+ if ( nWinStatus & PRINTER_STATUS_NO_TONER )
+ nStatus |= QUEUE_STATUS_NO_TONER;
+ if ( nWinStatus & PRINTER_STATUS_PAGE_PUNT )
+ nStatus |= QUEUE_STATUS_PAGE_PUNT;
+ if ( nWinStatus & PRINTER_STATUS_USER_INTERVENTION )
+ nStatus |= QUEUE_STATUS_USER_INTERVENTION;
+ if ( nWinStatus & PRINTER_STATUS_OUT_OF_MEMORY )
+ nStatus |= QUEUE_STATUS_OUT_OF_MEMORY;
+ if ( nWinStatus & PRINTER_STATUS_DOOR_OPEN )
+ nStatus |= QUEUE_STATUS_DOOR_OPEN;
+ if ( nWinStatus & PRINTER_STATUS_SERVER_UNKNOWN )
+ nStatus |= QUEUE_STATUS_SERVER_UNKNOWN;
+ if ( nWinStatus & PRINTER_STATUS_POWER_SAVE )
+ nStatus |= QUEUE_STATUS_POWER_SAVE;
+ if ( !nStatus && !(nWinStatus & PRINTER_STATUS_NOT_AVAILABLE) )
+ nStatus |= QUEUE_STATUS_READY;
+ return nStatus;
+}
+
+// -----------------------------------------------------------------------
+
+static void getPrinterQueueInfoOldStyle( ImplPrnQueueList* pList )
+{
+ DWORD i;
+ DWORD n;
+ DWORD nBytes = 0;
+ DWORD nInfoPrn2;
+ BOOL bFound = FALSE;
+ PRINTER_INFO_2* pWinInfo2 = NULL;
+ PRINTER_INFO_2* pGetInfo2;
+ EnumPrintersA( PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &nBytes, &nInfoPrn2 );
+ if ( nBytes )
+ {
+ pWinInfo2 = (PRINTER_INFO_2*) rtl_allocateMemory( nBytes );
+ if ( EnumPrintersA( PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)pWinInfo2, nBytes, &nBytes, &nInfoPrn2 ) )
+ {
+ pGetInfo2 = pWinInfo2;
+ for ( i = 0; i < nInfoPrn2; i++ )
+ {
+ SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo;
+ pInfo->maPrinterName = ImplSalGetUniString( pGetInfo2->pPrinterName );
+ pInfo->maDriver = ImplSalGetUniString( pGetInfo2->pDriverName );
+ XubString aPortName;
+ if ( pGetInfo2->pPortName )
+ aPortName = ImplSalGetUniString( pGetInfo2->pPortName );
+ // pLocation can be 0 (the Windows docu doesn't describe this)
+ if ( pGetInfo2->pLocation && strlen( pGetInfo2->pLocation ) )
+ pInfo->maLocation = ImplSalGetUniString( pGetInfo2->pLocation );
+ else
+ pInfo->maLocation = aPortName;
+ // pComment can be 0 (the Windows docu doesn't describe this)
+ if ( pGetInfo2->pComment )
+ pInfo->maComment = ImplSalGetUniString( pGetInfo2->pComment );
+ pInfo->mnStatus = ImplWinQueueStatusToSal( pGetInfo2->Status );
+ pInfo->mnJobs = pGetInfo2->cJobs;
+ pInfo->mpSysData = new XubString( aPortName );
+ pList->Add( pInfo );
+ pGetInfo2++;
+ }
+
+ bFound = TRUE;
+ }
+ }
+
+ // read printers from win.ini
+ // TODO: MSDN: GetProfileString() should not be called from server
+ // code because it is just there for WIN16 compatibility
+ UINT nSize = 4096;
+ char* pBuf = new char[nSize];
+ UINT nRead = GetProfileStringA( aImplDevices, NULL, "", pBuf, nSize );
+ while ( nRead >= nSize-2 )
+ {
+ nSize += 2048;
+ delete []pBuf;
+ pBuf = new char[nSize];
+ nRead = GetProfileStringA( aImplDevices, NULL, "", pBuf, nSize );
+ }
+
+ // extract printer names from buffer and fill list
+ char* pName = pBuf;
+ while ( *pName )
+ {
+ char* pPortName;
+ char* pTmp;
+ char aPortBuf[256];
+ GetProfileStringA( aImplDevices, pName, "", aPortBuf, sizeof( aPortBuf ) );
+
+ pPortName = aPortBuf;
+
+ // create name
+ xub_StrLen nNameLen = sal::static_int_cast<xub_StrLen>(strlen( pName ));
+ XubString aName( ImplSalGetUniString( pName, nNameLen ) );
+
+ // get driver name
+ pTmp = pPortName;
+ while ( *pTmp != ',' )
+ pTmp++;
+ XubString aDriver( ImplSalGetUniString( pPortName, (USHORT)(pTmp-pPortName) ) );
+ pPortName = pTmp;
+
+ // get port names
+ do
+ {
+ pPortName++;
+ pTmp = pPortName;
+ while ( *pTmp && (*pTmp != ',') )
+ pTmp++;
+
+ String aPortName( ImplSalGetUniString( pPortName, (USHORT)(pTmp-pPortName) ) );
+
+ // create new entry
+ // look up if printer was already found in first loop
+ BOOL bAdd = TRUE;
+ if ( pWinInfo2 )
+ {
+ pGetInfo2 = pWinInfo2;
+ for ( n = 0; n < nInfoPrn2; n++ )
+ {
+ if ( aName.EqualsIgnoreCaseAscii( pGetInfo2->pPrinterName ) )
+ {
+ bAdd = FALSE;
+ break;
+ }
+ pGetInfo2++;
+ }
+ }
+ // if it's a new printer, add it
+ if ( bAdd )
+ {
+ SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo;
+ pInfo->maPrinterName = aName;
+ pInfo->maDriver = aDriver;
+ pInfo->maLocation = aPortName;
+ pInfo->mnStatus = 0;
+ pInfo->mnJobs = QUEUE_JOBS_DONTKNOW;
+ pInfo->mpSysData = new XubString( aPortName );
+ pList->Add( pInfo );
+ }
+ }
+ while ( *pTmp == ',' );
+
+ pName += nNameLen + 1;
+ }
+
+ delete []pBuf;
+ rtl_freeMemory( pWinInfo2 );
+}
+
+void WinSalInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList )
+{
+ if( ! aSalShlData.mbWPrinter )
+ {
+ getPrinterQueueInfoOldStyle( pList );
+ return;
+ }
+ DWORD i;
+ DWORD nBytes = 0;
+ DWORD nInfoPrn4 = 0;
+ PRINTER_INFO_4W* pWinInfo4 = NULL;
+ EnumPrintersW( PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 4, NULL, 0, &nBytes, &nInfoPrn4 );
+ if ( nBytes )
+ {
+ pWinInfo4 = (PRINTER_INFO_4W*) rtl_allocateMemory( nBytes );
+ if ( EnumPrintersW( PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 4, (LPBYTE)pWinInfo4, nBytes, &nBytes, &nInfoPrn4 ) )
+ {
+ for ( i = 0; i < nInfoPrn4; i++ )
+ {
+ SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo;
+ pInfo->maPrinterName = UniString( reinterpret_cast< const sal_Unicode* >(pWinInfo4[i].pPrinterName) );
+ pInfo->mnStatus = 0;
+ pInfo->mnJobs = 0;
+ pInfo->mpSysData = NULL;
+ pList->Add( pInfo );
+ }
+ }
+ rtl_freeMemory( pWinInfo4 );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void getPrinterQueueStateOldStyle( SalPrinterQueueInfo* pInfo )
+{
+ DWORD nBytes = 0;
+ DWORD nInfoRet;
+ PRINTER_INFO_2* pWinInfo2;
+ EnumPrintersA( PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &nBytes, &nInfoRet );
+ if ( nBytes )
+ {
+ pWinInfo2 = (PRINTER_INFO_2*) rtl_allocateMemory( nBytes );
+ if ( EnumPrintersA( PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)pWinInfo2, nBytes, &nBytes, &nInfoRet ) )
+ {
+ PRINTER_INFO_2* pGetInfo2 = pWinInfo2;
+ for ( DWORD i = 0; i < nInfoRet; i++ )
+ {
+ if ( pInfo->maPrinterName.EqualsAscii( pGetInfo2->pPrinterName ) &&
+ ( pInfo->maDriver.Len() == 0 ||
+ pInfo->maDriver.EqualsAscii( pGetInfo2->pDriverName ) )
+ )
+ {
+ XubString aPortName;
+ if ( pGetInfo2->pPortName )
+ aPortName = ImplSalGetUniString( pGetInfo2->pPortName );
+ // pLocation can be 0 (the Windows docu doesn't describe this)
+ if ( pGetInfo2->pLocation && strlen( pGetInfo2->pLocation ) )
+ pInfo->maLocation = ImplSalGetUniString( pGetInfo2->pLocation );
+ else
+ pInfo->maLocation = aPortName;
+ // pComment can be 0 (the Windows docu doesn't describe this)
+ if ( pGetInfo2->pComment )
+ pInfo->maComment = ImplSalGetUniString( pGetInfo2->pComment );
+ pInfo->mnStatus = ImplWinQueueStatusToSal( pGetInfo2->Status );
+ pInfo->mnJobs = pGetInfo2->cJobs;
+ if( ! pInfo->mpSysData )
+ pInfo->mpSysData = new XubString( aPortName );
+ break;
+ }
+
+ pGetInfo2++;
+ }
+ }
+
+ rtl_freeMemory( pWinInfo2 );
+ }
+}
+
+void WinSalInstance::GetPrinterQueueState( SalPrinterQueueInfo* pInfo )
+{
+ if( ! aSalShlData.mbWPrinter )
+ {
+ getPrinterQueueStateOldStyle( pInfo );
+ return;
+ }
+
+ HANDLE hPrinter = 0;
+ LPWSTR pPrnName = reinterpret_cast<LPWSTR>(const_cast<sal_Unicode*>(pInfo->maPrinterName.GetBuffer()));
+ if( OpenPrinterW( pPrnName, &hPrinter, NULL ) )
+ {
+ DWORD nBytes = 0;
+ GetPrinterW( hPrinter, 2, NULL, 0, &nBytes );
+ if( nBytes )
+ {
+ PRINTER_INFO_2W* pWinInfo2 = (PRINTER_INFO_2W*)rtl_allocateMemory(nBytes);
+ if( GetPrinterW( hPrinter, 2, (LPBYTE)pWinInfo2, nBytes, &nBytes ) )
+ {
+ if( pWinInfo2->pDriverName )
+ pInfo->maDriver = String( reinterpret_cast< const sal_Unicode* >(pWinInfo2->pDriverName) );
+ XubString aPortName;
+ if ( pWinInfo2->pPortName )
+ aPortName = String( reinterpret_cast< const sal_Unicode* >(pWinInfo2->pPortName) );
+ // pLocation can be 0 (the Windows docu doesn't describe this)
+ if ( pWinInfo2->pLocation && *pWinInfo2->pLocation )
+ pInfo->maLocation = String( reinterpret_cast< const sal_Unicode* >(pWinInfo2->pLocation) );
+ else
+ pInfo->maLocation = aPortName;
+ // pComment can be 0 (the Windows docu doesn't describe this)
+ if ( pWinInfo2->pComment )
+ pInfo->maComment = String( reinterpret_cast< const sal_Unicode* >(pWinInfo2->pComment) );
+ pInfo->mnStatus = ImplWinQueueStatusToSal( pWinInfo2->Status );
+ pInfo->mnJobs = pWinInfo2->cJobs;
+ if( ! pInfo->mpSysData )
+ pInfo->mpSysData = new XubString( aPortName );
+ }
+ rtl_freeMemory(pWinInfo2);
+ }
+ ClosePrinter( hPrinter );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo )
+{
+ delete (String*)(pInfo->mpSysData);
+ delete pInfo;
+}
+
+// -----------------------------------------------------------------------
+XubString WinSalInstance::GetDefaultPrinter()
+{
+ static bool bGetDefPrtAPI = true;
+ static BOOL(WINAPI*pGetDefaultPrinter)(LPWSTR,LPDWORD) = NULL;
+ // try to use GetDefaultPrinter API (not available prior to W2000)
+ if( bGetDefPrtAPI )
+ {
+ bGetDefPrtAPI = false;
+ // check for W2k and XP
+ if( aSalShlData.maVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT && aSalShlData.maVersionInfo.dwMajorVersion >= 5 )
+ {
+ OUString aLibraryName( RTL_CONSTASCII_USTRINGPARAM( "winspool.drv" ) );
+ oslModule pLib = osl_loadModule( aLibraryName.pData, SAL_LOADMODULE_DEFAULT );
+ oslGenericFunction pFunc = NULL;
+ if( pLib )
+ {
+ OUString queryFuncName( RTL_CONSTASCII_USTRINGPARAM( "GetDefaultPrinterW" ) );
+ pFunc = osl_getFunctionSymbol( pLib, queryFuncName.pData );
+ }
+
+ pGetDefaultPrinter = (BOOL(WINAPI*)(LPWSTR,LPDWORD)) pFunc;
+ }
+ }
+ if( pGetDefaultPrinter )
+ {
+ DWORD nChars = 0;
+ pGetDefaultPrinter( NULL, &nChars );
+ if( nChars )
+ {
+ LPWSTR pStr = (LPWSTR)rtl_allocateMemory(nChars*sizeof(WCHAR));
+ XubString aDefPrt;
+ if( pGetDefaultPrinter( pStr, &nChars ) )
+ {
+ aDefPrt = reinterpret_cast<sal_Unicode* >(pStr);
+ }
+ rtl_freeMemory( pStr );
+ if( aDefPrt.Len() )
+ return aDefPrt;
+ }
+ }
+
+ // get default printer from win.ini
+ char szBuffer[256];
+ GetProfileStringA( aImplWindows, aImplDevice, "", szBuffer, sizeof( szBuffer ) );
+ if ( szBuffer[0] )
+ {
+ // Printername suchen
+ char* pBuf = szBuffer;
+ char* pTmp = pBuf;
+ while ( *pTmp && (*pTmp != ',') )
+ pTmp++;
+ return ImplSalGetUniString( pBuf, (xub_StrLen)(pTmp-pBuf) );
+ }
+ else
+ return XubString();
+}
+
+// =======================================================================
+
+static DWORD ImplDeviceCaps( WinSalInfoPrinter* pPrinter, WORD nCaps,
+ BYTE* pOutput, const ImplJobSetup* pSetupData )
+{
+ if( aSalShlData.mbWPrinter )
+ {
+ DEVMODEW* pDevMode;
+ if ( !pSetupData || !pSetupData->mpDriverData )
+ pDevMode = NULL;
+ else
+ pDevMode = SAL_DEVMODE_W( pSetupData );
+
+ return DeviceCapabilitiesW( reinterpret_cast<LPCWSTR>(pPrinter->maDeviceName.GetBuffer()),
+ reinterpret_cast<LPCWSTR>(pPrinter->maPortName.GetBuffer()),
+ nCaps, (LPWSTR)pOutput, pDevMode );
+ }
+ else
+ {
+ DEVMODEA* pDevMode;
+ if ( !pSetupData || !pSetupData->mpDriverData )
+ pDevMode = NULL;
+ else
+ pDevMode = SAL_DEVMODE_A( pSetupData );
+
+ return DeviceCapabilitiesA( ImplSalGetWinAnsiString( pPrinter->maDeviceName, TRUE ).GetBuffer(),
+ ImplSalGetWinAnsiString( pPrinter->maPortName, TRUE ).GetBuffer(),
+ nCaps, (LPSTR)pOutput, pDevMode );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplTestSalJobSetup( WinSalInfoPrinter* pPrinter,
+ ImplJobSetup* pSetupData, BOOL bDelete )
+{
+ if ( pSetupData && pSetupData->mpDriverData )
+ {
+ // signature and size must fit to avoid using
+ // JobSetups from a wrong system
+
+ // initialize versions from jobsetup
+ // those will be overwritten with driver's version
+ DEVMODEA* pDevModeA = NULL;
+ DEVMODEW* pDevModeW = NULL;
+ LONG dmSpecVersion = -1;
+ LONG dmDriverVersion = -1;
+ SalDriverData* pSalDriverData = (SalDriverData*)pSetupData->mpDriverData;
+ BYTE* pDriverData = ((BYTE*)pSalDriverData) + pSalDriverData->mnDriverOffset;
+ if( pSalDriverData->mnVersion == SAL_DRIVERDATA_VERSION_W )
+ {
+ if( aSalShlData.mbWPrinter )
+ pDevModeW = (DEVMODEW*)pDriverData;
+ }
+ else if( pSalDriverData->mnVersion == SAL_DRIVERDATA_VERSION_A )
+ {
+ if( ! aSalShlData.mbWPrinter )
+ pDevModeA = (DEVMODEA*)pDriverData;
+ }
+
+ long nSysJobSize = -1;
+ if( pPrinter && ( pDevModeA || pDevModeW ) )
+ {
+ // just too many driver crashes in that area -> check the dmSpecVersion and dmDriverVersion fields always !!!
+ // this prevents using the jobsetup between different Windows versions (eg from XP to 9x) but we
+ // can avoid potential driver crashes as their jobsetups are often not compatible
+ // #110800#, #111151#, #112381#, #i16580#, #i14173# and perhaps #112375#
+ ByteString aPrinterNameA= ImplSalGetWinAnsiString( pPrinter->maDeviceName, TRUE );
+ HANDLE hPrn;
+ LPWSTR pPrinterNameW = reinterpret_cast<LPWSTR>(const_cast<sal_Unicode*>(pPrinter->maDeviceName.GetBuffer()));
+ if ( ! aSalShlData.mbWPrinter )
+ {
+ if ( !OpenPrinterA( (LPSTR)aPrinterNameA.GetBuffer(), &hPrn, NULL ) )
+ return FALSE;
+ }
+ else
+ if ( !OpenPrinterW( pPrinterNameW, &hPrn, NULL ) )
+ return FALSE;
+
+ // #131642# hPrn==HGDI_ERROR even though OpenPrinter() succeeded!
+ if( hPrn == HGDI_ERROR )
+ return FALSE;
+
+ if( aSalShlData.mbWPrinter )
+ {
+ nSysJobSize = DocumentPropertiesW( 0, hPrn,
+ pPrinterNameW,
+ NULL, NULL, 0 );
+ }
+ else
+ {
+ nSysJobSize = DocumentPropertiesA( 0, hPrn,
+ (LPSTR)aPrinterNameA.GetBuffer(),
+ NULL, NULL, 0 );
+ }
+
+ if( nSysJobSize < 0 )
+ {
+ ClosePrinter( hPrn );
+ return FALSE;
+ }
+ BYTE *pBuffer = (BYTE*)_alloca( nSysJobSize );
+ LONG nRet = -1;
+ if( aSalShlData.mbWPrinter )
+ {
+ nRet = DocumentPropertiesW( 0, hPrn,
+ pPrinterNameW,
+ (LPDEVMODEW)pBuffer, NULL, DM_OUT_BUFFER );
+ }
+ else
+ {
+ nRet = DocumentPropertiesA( 0, hPrn,
+ (LPSTR)aPrinterNameA.GetBuffer(),
+ (LPDEVMODEA)pBuffer, NULL, DM_OUT_BUFFER );
+ }
+ if( nRet < 0 )
+ {
+ ClosePrinter( hPrn );
+ return FALSE;
+ }
+
+ // the spec version differs between the windows platforms, ie 98,NT,2000/XP
+ // this allows us to throw away printer settings from other platforms that might crash a buggy driver
+ // we check the driver version as well
+ dmSpecVersion = aSalShlData.mbWPrinter ? ((DEVMODEW*)pBuffer)->dmSpecVersion : ((DEVMODEA*)pBuffer)->dmSpecVersion;
+ dmDriverVersion = aSalShlData.mbWPrinter ? ((DEVMODEW*)pBuffer)->dmDriverVersion : ((DEVMODEA*)pBuffer)->dmDriverVersion;
+
+ ClosePrinter( hPrn );
+ }
+ SalDriverData* pSetupDriverData = (SalDriverData*)(pSetupData->mpDriverData);
+ if ( (pSetupData->mnSystem == JOBSETUP_SYSTEM_WINDOWS) &&
+ (pPrinter->maDriverName == pSetupData->maDriver) &&
+ (pSetupData->mnDriverDataLen > sizeof( SalDriverData )) &&
+ (long)(pSetupData->mnDriverDataLen - pSetupDriverData->mnDriverOffset) == nSysJobSize &&
+ pSetupDriverData->mnSysSignature == SAL_DRIVERDATA_SYSSIGN )
+ {
+ if( pDevModeA &&
+ (dmSpecVersion == pDevModeA->dmSpecVersion) &&
+ (dmDriverVersion == pDevModeA->dmDriverVersion) )
+ return TRUE;
+ if( pDevModeW &&
+ (dmSpecVersion == pDevModeW->dmSpecVersion) &&
+ (dmDriverVersion == pDevModeW->dmDriverVersion) )
+ return TRUE;
+ }
+ if ( bDelete )
+ {
+ rtl_freeMemory( pSetupData->mpDriverData );
+ pSetupData->mpDriverData = NULL;
+ pSetupData->mnDriverDataLen = 0;
+ }
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplUpdateSalJobSetup( WinSalInfoPrinter* pPrinter, ImplJobSetup* pSetupData,
+ BOOL bIn, WinSalFrame* pVisibleDlgParent )
+{
+ ByteString aPrinterNameA = ImplSalGetWinAnsiString( pPrinter->maDeviceName, TRUE );
+ HANDLE hPrn;
+ LPWSTR pPrinterNameW = reinterpret_cast<LPWSTR>(const_cast<sal_Unicode*>(pPrinter->maDeviceName.GetBuffer()));
+ if( aSalShlData.mbWPrinter )
+ {
+ if ( !OpenPrinterW( pPrinterNameW, &hPrn, NULL ) )
+ return FALSE;
+ }
+ else
+ {
+ if ( !OpenPrinterA( (LPSTR)aPrinterNameA.GetBuffer(), &hPrn, NULL ) )
+ return FALSE;
+ }
+ // #131642# hPrn==HGDI_ERROR even though OpenPrinter() succeeded!
+ if( hPrn == HGDI_ERROR )
+ return FALSE;
+
+ LONG nRet;
+ LONG nSysJobSize = -1;
+ HWND hWnd = 0;
+ DWORD nMode = DM_OUT_BUFFER;
+ ULONG nDriverDataLen = 0;
+ SalDriverData* pOutBuffer = NULL;
+ BYTE* pInBuffer = NULL;
+
+ if( aSalShlData.mbWPrinter )
+ {
+ nSysJobSize = DocumentPropertiesW( hWnd, hPrn,
+ pPrinterNameW,
+ NULL, NULL, 0 );
+ }
+ else
+ nSysJobSize = DocumentPropertiesA( hWnd, hPrn,
+ (LPSTR)ImplSalGetWinAnsiString( pPrinter->maDeviceName, TRUE ).GetBuffer(),
+ NULL, NULL, 0 );
+ if ( nSysJobSize < 0 )
+ {
+ ClosePrinter( hPrn );
+ return FALSE;
+ }
+
+ // Outputbuffer anlegen
+ nDriverDataLen = sizeof(SalDriverData) + nSysJobSize-1;
+ pOutBuffer = (SalDriverData*)rtl_allocateZeroMemory( nDriverDataLen );
+ pOutBuffer->mnSysSignature = SAL_DRIVERDATA_SYSSIGN;
+ pOutBuffer->mnVersion = aSalShlData.mbWPrinter ? SAL_DRIVERDATA_VERSION_W : SAL_DRIVERDATA_VERSION_A;
+ // calculate driver data offset including structure padding
+ pOutBuffer->mnDriverOffset = sal::static_int_cast<USHORT>(
+ (char*)pOutBuffer->maDriverData -
+ (char*)pOutBuffer );
+
+ // Testen, ob wir einen geeigneten Inputbuffer haben
+ if ( bIn && ImplTestSalJobSetup( pPrinter, pSetupData, FALSE ) )
+ {
+ pInBuffer = (BYTE*)pSetupData->mpDriverData + ((SalDriverData*)pSetupData->mpDriverData)->mnDriverOffset;
+ nMode |= DM_IN_BUFFER;
+ }
+
+ // Testen, ob Dialog angezeigt werden soll
+ if ( pVisibleDlgParent )
+ {
+ hWnd = pVisibleDlgParent->mhWnd;
+ nMode |= DM_IN_PROMPT;
+ }
+
+ // Release mutex, in the other case we don't get paints and so on
+ ULONG nMutexCount=0;
+ if ( pVisibleDlgParent )
+ nMutexCount = ImplSalReleaseYieldMutex();
+
+ BYTE* pOutDevMode = (((BYTE*)pOutBuffer) + pOutBuffer->mnDriverOffset);
+ if( aSalShlData.mbWPrinter )
+ {
+ nRet = DocumentPropertiesW( hWnd, hPrn,
+ pPrinterNameW,
+ (LPDEVMODEW)pOutDevMode, (LPDEVMODEW)pInBuffer, nMode );
+ }
+ else
+ {
+ nRet = DocumentPropertiesA( hWnd, hPrn,
+ (LPSTR)ImplSalGetWinAnsiString( pPrinter->maDeviceName, TRUE ).GetBuffer(),
+ (LPDEVMODEA)pOutDevMode, (LPDEVMODEA)pInBuffer, nMode );
+ }
+ if ( pVisibleDlgParent )
+ ImplSalAcquireYieldMutex( nMutexCount );
+ ClosePrinter( hPrn );
+
+ if( (nRet < 0) || (pVisibleDlgParent && (nRet == IDCANCEL)) )
+ {
+ rtl_freeMemory( pOutBuffer );
+ return FALSE;
+ }
+
+ // fill up string buffers with 0 so they do not influence a JobSetup's memcmp
+ if( aSalShlData.mbWPrinter )
+ {
+ if( ((LPDEVMODEW)pOutDevMode)->dmSize >= 64 )
+ {
+ sal_Int32 nLen = rtl_ustr_getLength( (const sal_Unicode*)((LPDEVMODEW)pOutDevMode)->dmDeviceName );
+ if ( nLen < sizeof( ((LPDEVMODEW)pOutDevMode)->dmDeviceName )/sizeof(sal_Unicode) )
+ memset( ((LPDEVMODEW)pOutDevMode)->dmDeviceName+nLen, 0, sizeof( ((LPDEVMODEW)pOutDevMode)->dmDeviceName )-(nLen*sizeof(sal_Unicode)) );
+ }
+ if( ((LPDEVMODEW)pOutDevMode)->dmSize >= 166 )
+ {
+ sal_Int32 nLen = rtl_ustr_getLength( (const sal_Unicode*)((LPDEVMODEW)pOutDevMode)->dmFormName );
+ if ( nLen < sizeof( ((LPDEVMODEW)pOutDevMode)->dmFormName )/sizeof(sal_Unicode) )
+ memset( ((LPDEVMODEW)pOutDevMode)->dmFormName+nLen, 0, sizeof( ((LPDEVMODEW)pOutDevMode)->dmFormName )-(nLen*sizeof(sal_Unicode)) );
+ }
+ }
+ else
+ {
+ if( ((LPDEVMODEA)pOutDevMode)->dmSize >= 32 )
+ {
+ sal_Int32 nLen = strlen( (const char*)((LPDEVMODEA)pOutDevMode)->dmDeviceName );
+ if ( nLen < sizeof( ((LPDEVMODEA)pOutDevMode)->dmDeviceName ) )
+ memset( ((LPDEVMODEA)pOutDevMode)->dmDeviceName+nLen, 0, sizeof( ((LPDEVMODEA)pOutDevMode)->dmDeviceName )-nLen );
+ }
+ if( ((LPDEVMODEA)pOutDevMode)->dmSize >= 102 )
+ {
+ sal_Int32 nLen = strlen( (const char*)((LPDEVMODEA)pOutDevMode)->dmFormName );
+ if ( nLen < sizeof( ((LPDEVMODEA)pOutDevMode)->dmFormName ) )
+ memset( ((LPDEVMODEA)pOutDevMode)->dmFormName+nLen, 0, sizeof( ((LPDEVMODEA)pOutDevMode)->dmFormName )-nLen );
+ }
+ }
+
+ // update data
+ if ( pSetupData->mpDriverData )
+ rtl_freeMemory( pSetupData->mpDriverData );
+ pSetupData->mnDriverDataLen = nDriverDataLen;
+ pSetupData->mpDriverData = (BYTE*)pOutBuffer;
+ pSetupData->mnSystem = JOBSETUP_SYSTEM_WINDOWS;
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+#define DECLARE_DEVMODE( i )\
+ DEVMODEA* pDevModeA = SAL_DEVMODE_A(i);\
+ DEVMODEW* pDevModeW = SAL_DEVMODE_W(i);\
+ if( pDevModeA == NULL && pDevModeW == NULL )\
+ return
+
+#define CHOOSE_DEVMODE(i)\
+ (pDevModeW ? pDevModeW->i : pDevModeA->i)
+
+static void ImplDevModeToJobSetup( WinSalInfoPrinter* pPrinter, ImplJobSetup* pSetupData, ULONG nFlags )
+{
+ if ( !pSetupData || !pSetupData->mpDriverData )
+ return;
+
+ DECLARE_DEVMODE( pSetupData );
+
+ // Orientation
+ if ( nFlags & SAL_JOBSET_ORIENTATION )
+ {
+ if ( CHOOSE_DEVMODE(dmOrientation) == DMORIENT_PORTRAIT )
+ pSetupData->meOrientation = ORIENTATION_PORTRAIT;
+ else if ( CHOOSE_DEVMODE(dmOrientation) == DMORIENT_LANDSCAPE )
+ pSetupData->meOrientation = ORIENTATION_LANDSCAPE;
+ }
+
+ // PaperBin
+ if ( nFlags & SAL_JOBSET_PAPERBIN )
+ {
+ ULONG nCount = ImplDeviceCaps( pPrinter, DC_BINS, NULL, pSetupData );
+
+ if ( nCount && (nCount != GDI_ERROR) )
+ {
+ WORD* pBins = (WORD*)rtl_allocateZeroMemory( nCount*sizeof(WORD) );
+ ImplDeviceCaps( pPrinter, DC_BINS, (BYTE*)pBins, pSetupData );
+ pSetupData->mnPaperBin = 0;
+
+ // search the right bin and assign index to mnPaperBin
+ for( ULONG i = 0; i < nCount; i++ )
+ {
+ if( CHOOSE_DEVMODE(dmDefaultSource) == pBins[ i ] )
+ {
+ pSetupData->mnPaperBin = (USHORT)i;
+ break;
+ }
+ }
+
+ rtl_freeMemory( pBins );
+ }
+ }
+
+ // PaperSize
+ if ( nFlags & SAL_JOBSET_PAPERSIZE )
+ {
+ if( (CHOOSE_DEVMODE(dmFields) & (DM_PAPERWIDTH|DM_PAPERLENGTH)) == (DM_PAPERWIDTH|DM_PAPERLENGTH) )
+ {
+ pSetupData->mnPaperWidth = CHOOSE_DEVMODE(dmPaperWidth)*10;
+ pSetupData->mnPaperHeight = CHOOSE_DEVMODE(dmPaperLength)*10;
+ }
+ else
+ {
+ ULONG nPaperCount = ImplDeviceCaps( pPrinter, DC_PAPERS, NULL, pSetupData );
+ WORD* pPapers = NULL;
+ ULONG nPaperSizeCount = ImplDeviceCaps( pPrinter, DC_PAPERSIZE, NULL, pSetupData );
+ POINT* pPaperSizes = NULL;
+ if ( nPaperCount && (nPaperCount != GDI_ERROR) )
+ {
+ pPapers = (WORD*)rtl_allocateZeroMemory(nPaperCount*sizeof(WORD));
+ ImplDeviceCaps( pPrinter, DC_PAPERS, (BYTE*)pPapers, pSetupData );
+ }
+ if ( nPaperSizeCount && (nPaperSizeCount != GDI_ERROR) )
+ {
+ pPaperSizes = (POINT*)rtl_allocateZeroMemory(nPaperSizeCount*sizeof(POINT));
+ ImplDeviceCaps( pPrinter, DC_PAPERSIZE, (BYTE*)pPaperSizes, pSetupData );
+ }
+ if( nPaperSizeCount == nPaperCount && pPaperSizes && pPapers )
+ {
+ for( ULONG i = 0; i < nPaperCount; i++ )
+ {
+ if( pPapers[ i ] == CHOOSE_DEVMODE(dmPaperSize) )
+ {
+ pSetupData->mnPaperWidth = pPaperSizes[ i ].x*10;
+ pSetupData->mnPaperHeight = pPaperSizes[ i ].y*10;
+ break;
+ }
+ }
+ }
+ if( pPapers )
+ rtl_freeMemory( pPapers );
+ if( pPaperSizes )
+ rtl_freeMemory( pPaperSizes );
+ }
+ switch( CHOOSE_DEVMODE(dmPaperSize) )
+ {
+ case( DMPAPER_LETTER ):
+ pSetupData->mePaperFormat = PAPER_LETTER;
+ break;
+ case( DMPAPER_TABLOID ):
+ pSetupData->mePaperFormat = PAPER_TABLOID;
+ break;
+ case( DMPAPER_LEDGER ):
+ pSetupData->mePaperFormat = PAPER_LEDGER;
+ break;
+ case( DMPAPER_LEGAL ):
+ pSetupData->mePaperFormat = PAPER_LEGAL;
+ break;
+ case( DMPAPER_STATEMENT ):
+ pSetupData->mePaperFormat = PAPER_STATEMENT;
+ break;
+ case( DMPAPER_EXECUTIVE ):
+ pSetupData->mePaperFormat = PAPER_EXECUTIVE;
+ break;
+ case( DMPAPER_A3 ):
+ pSetupData->mePaperFormat = PAPER_A3;
+ break;
+ case( DMPAPER_A4 ):
+ pSetupData->mePaperFormat = PAPER_A4;
+ break;
+ case( DMPAPER_A5 ):
+ pSetupData->mePaperFormat = PAPER_A5;
+ break;
+ //See http://wiki.services.openoffice.org/wiki/DefaultPaperSize
+ //i.e.
+ //http://msdn.microsoft.com/en-us/library/dd319099(VS.85).aspx
+ //DMPAPER_B4 12 B4 (JIS) 257 x 364 mm
+ //http://partners.adobe.com/public/developer/en/ps/5003.PPD_Spec_v4.3.pdf
+ //also says that the MS DMPAPER_B4 is JIS, which makes most sense. And
+ //matches our Excel filter's belief about the matching XlPaperSize
+ //enumeration.
+ //
+ //http://msdn.microsoft.com/en-us/library/ms776398(VS.85).aspx said
+ ////"DMPAPER_B4 12 B4 (JIS) 250 x 354"
+ //which is bogus as it's either JIS 257 × 364 or ISO 250 × 353
+ //(cmc)
+ case( DMPAPER_B4 ):
+ pSetupData->mePaperFormat = PAPER_B4_JIS;
+ break;
+ case( DMPAPER_B5 ):
+ pSetupData->mePaperFormat = PAPER_B5_JIS;
+ break;
+ case( DMPAPER_QUARTO ):
+ pSetupData->mePaperFormat = PAPER_QUARTO;
+ break;
+ case( DMPAPER_10X14 ):
+ pSetupData->mePaperFormat = PAPER_10x14;
+ break;
+ case( DMPAPER_NOTE ):
+ pSetupData->mePaperFormat = PAPER_LETTER;
+ break;
+ case( DMPAPER_ENV_9 ):
+ pSetupData->mePaperFormat = PAPER_ENV_9;
+ break;
+ case( DMPAPER_ENV_10 ):
+ pSetupData->mePaperFormat = PAPER_ENV_10;
+ break;
+ case( DMPAPER_ENV_11 ):
+ pSetupData->mePaperFormat = PAPER_ENV_11;
+ break;
+ case( DMPAPER_ENV_12 ):
+ pSetupData->mePaperFormat = PAPER_ENV_12;
+ break;
+ case( DMPAPER_ENV_14 ):
+ pSetupData->mePaperFormat = PAPER_ENV_14;
+ break;
+ case( DMPAPER_CSHEET ):
+ pSetupData->mePaperFormat = PAPER_C;
+ break;
+ case( DMPAPER_DSHEET ):
+ pSetupData->mePaperFormat = PAPER_D;
+ break;
+ case( DMPAPER_ESHEET ):
+ pSetupData->mePaperFormat = PAPER_E;
+ break;
+ case( DMPAPER_ENV_DL):
+ pSetupData->mePaperFormat = PAPER_ENV_DL;
+ break;
+ case( DMPAPER_ENV_C5):
+ pSetupData->mePaperFormat = PAPER_ENV_C5;
+ break;
+ case( DMPAPER_ENV_C3):
+ pSetupData->mePaperFormat = PAPER_ENV_C3;
+ break;
+ case( DMPAPER_ENV_C4):
+ pSetupData->mePaperFormat = PAPER_ENV_C4;
+ break;
+ case( DMPAPER_ENV_C6):
+ pSetupData->mePaperFormat = PAPER_ENV_C6;
+ break;
+ case( DMPAPER_ENV_C65):
+ pSetupData->mePaperFormat = PAPER_ENV_C65;
+ break;
+ case( DMPAPER_ENV_ITALY ):
+ pSetupData->mePaperFormat = PAPER_ENV_ITALY;
+ break;
+ case( DMPAPER_ENV_MONARCH ):
+ pSetupData->mePaperFormat = PAPER_ENV_MONARCH;
+ break;
+ case( DMPAPER_ENV_PERSONAL ):
+ pSetupData->mePaperFormat = PAPER_ENV_PERSONAL;
+ break;
+ case( DMPAPER_FANFOLD_US ):
+ pSetupData->mePaperFormat = PAPER_FANFOLD_US;
+ break;
+ case( DMPAPER_FANFOLD_STD_GERMAN ):
+ pSetupData->mePaperFormat = PAPER_FANFOLD_DE;
+ break;
+ case( DMPAPER_FANFOLD_LGL_GERMAN ):
+ pSetupData->mePaperFormat = PAPER_FANFOLD_LEGAL_DE;
+ break;
+ case( DMPAPER_ISO_B4 ):
+ pSetupData->mePaperFormat = PAPER_B4_ISO;
+ break;
+ case( DMPAPER_JAPANESE_POSTCARD ):
+ pSetupData->mePaperFormat = PAPER_POSTCARD_JP;
+ break;
+ case( DMPAPER_9X11 ):
+ pSetupData->mePaperFormat = PAPER_9x11;
+ break;
+ case( DMPAPER_10X11 ):
+ pSetupData->mePaperFormat = PAPER_10x11;
+ break;
+ case( DMPAPER_15X11 ):
+ pSetupData->mePaperFormat = PAPER_15x11;
+ break;
+ case( DMPAPER_ENV_INVITE ):
+ pSetupData->mePaperFormat = PAPER_ENV_INVITE;
+ break;
+ case( DMPAPER_A_PLUS ):
+ pSetupData->mePaperFormat = PAPER_A_PLUS;
+ break;
+ case( DMPAPER_B_PLUS ):
+ pSetupData->mePaperFormat = PAPER_B_PLUS;
+ break;
+ case( DMPAPER_LETTER_PLUS ):
+ pSetupData->mePaperFormat = PAPER_LETTER_PLUS;
+ break;
+ case( DMPAPER_A4_PLUS ):
+ pSetupData->mePaperFormat = PAPER_A4_PLUS;
+ break;
+ case( DMPAPER_A2 ):
+ pSetupData->mePaperFormat = PAPER_A2;
+ break;
+ case( DMPAPER_DBL_JAPANESE_POSTCARD ):
+ pSetupData->mePaperFormat = PAPER_DOUBLEPOSTCARD_JP;
+ break;
+ case( DMPAPER_A6 ):
+ pSetupData->mePaperFormat = PAPER_A6;
+ break;
+ case( DMPAPER_B6_JIS ):
+ pSetupData->mePaperFormat = PAPER_B6_JIS;
+ break;
+ case( DMPAPER_12X11 ):
+ pSetupData->mePaperFormat = PAPER_12x11;
+ break;
+ default:
+ pSetupData->mePaperFormat = PAPER_USER;
+ break;
+ }
+ }
+
+ if( nFlags & SAL_JOBSET_DUPLEXMODE )
+ {
+ DuplexMode eDuplex = DUPLEX_UNKNOWN;
+ if( (CHOOSE_DEVMODE(dmFields) & DM_DUPLEX) )
+ {
+ if( CHOOSE_DEVMODE(dmDuplex) == DMDUP_SIMPLEX )
+ eDuplex = DUPLEX_OFF;
+ else if( CHOOSE_DEVMODE(dmDuplex) == DMDUP_VERTICAL )
+ eDuplex = DUPLEX_LONGEDGE;
+ else if( CHOOSE_DEVMODE(dmDuplex) == DMDUP_HORIZONTAL )
+ eDuplex = DUPLEX_SHORTEDGE;
+ }
+ pSetupData->meDuplexMode = eDuplex;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplJobSetupToDevMode( WinSalInfoPrinter* pPrinter, ImplJobSetup* pSetupData, ULONG nFlags )
+{
+ if ( !pSetupData || !pSetupData->mpDriverData )
+ return;
+
+ DECLARE_DEVMODE( pSetupData );
+
+ // Orientation
+ if ( nFlags & SAL_JOBSET_ORIENTATION )
+ {
+ CHOOSE_DEVMODE(dmFields) |= DM_ORIENTATION;
+ if ( pSetupData->meOrientation == ORIENTATION_PORTRAIT )
+ CHOOSE_DEVMODE(dmOrientation) = DMORIENT_PORTRAIT;
+ else
+ CHOOSE_DEVMODE(dmOrientation) = DMORIENT_LANDSCAPE;
+ }
+
+ // PaperBin
+ if ( nFlags & SAL_JOBSET_PAPERBIN )
+ {
+ ULONG nCount = ImplDeviceCaps( pPrinter, DC_BINS, NULL, pSetupData );
+
+ if ( nCount && (nCount != GDI_ERROR) )
+ {
+ WORD* pBins = (WORD*)rtl_allocateZeroMemory(nCount*sizeof(WORD));
+ ImplDeviceCaps( pPrinter, DC_BINS, (BYTE*)pBins, pSetupData );
+ CHOOSE_DEVMODE(dmFields) |= DM_DEFAULTSOURCE;
+ CHOOSE_DEVMODE(dmDefaultSource) = pBins[ pSetupData->mnPaperBin ];
+ rtl_freeMemory( pBins );
+ }
+ }
+
+ // PaperSize
+ if ( nFlags & SAL_JOBSET_PAPERSIZE )
+ {
+ CHOOSE_DEVMODE(dmFields) |= DM_PAPERSIZE;
+ CHOOSE_DEVMODE(dmPaperWidth) = 0;
+ CHOOSE_DEVMODE(dmPaperLength) = 0;
+
+ switch( pSetupData->mePaperFormat )
+ {
+ case( PAPER_A2 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A2;
+ break;
+ case( PAPER_A3 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A3;
+ break;
+ case( PAPER_A4 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A4;
+ break;
+ case( PAPER_A5 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A5;
+ break;
+ case( PAPER_B4_ISO):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ISO_B4;
+ break;
+ case( PAPER_LETTER ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_LETTER;
+ break;
+ case( PAPER_LEGAL ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_LEGAL;
+ break;
+ case( PAPER_TABLOID ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_TABLOID;
+ break;
+#if 0
+ //http://msdn.microsoft.com/en-us/library/ms776398(VS.85).aspx
+ //DMPAPER_ENV_B6 is documented as:
+ //"DMPAPER_ENV_B6 35 Envelope B6 176 x 125 mm"
+ //which is the wrong way around, it is surely 125 x 176, i.e.
+ //compare DMPAPER_ENV_B4 and DMPAPER_ENV_B4 as
+ //DMPAPER_ENV_B4 33 Envelope B4 250 x 353 mm
+ //DMPAPER_ENV_B5 34 Envelope B5 176 x 250 mm
+ case( PAPER_B6_ISO ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_B6;
+ break;
+#endif
+ case( PAPER_ENV_C4 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_C4;
+ break;
+ case( PAPER_ENV_C5 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_C5;
+ break;
+ case( PAPER_ENV_C6 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_C6;
+ break;
+ case( PAPER_ENV_C65 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_C65;
+ break;
+ case( PAPER_ENV_DL ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_DL;
+ break;
+ case( PAPER_C ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_CSHEET;
+ break;
+ case( PAPER_D ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_DSHEET;
+ break;
+ case( PAPER_E ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ESHEET;
+ break;
+ case( PAPER_EXECUTIVE ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_EXECUTIVE;
+ break;
+ case( PAPER_FANFOLD_LEGAL_DE ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_FANFOLD_LGL_GERMAN;
+ break;
+ case( PAPER_ENV_MONARCH ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_MONARCH;
+ break;
+ case( PAPER_ENV_PERSONAL ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_PERSONAL;
+ break;
+ case( PAPER_ENV_9 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_9;
+ break;
+ case( PAPER_ENV_10 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_10;
+ break;
+ case( PAPER_ENV_11 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_11;
+ break;
+ case( PAPER_ENV_12 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_12;
+ break;
+ //See the comments on DMPAPER_B4 above
+ case( PAPER_B4_JIS ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_B4;
+ break;
+ case( PAPER_B5_JIS ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_B5;
+ break;
+ case( PAPER_B6_JIS ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_B6_JIS;
+ break;
+ case( PAPER_LEDGER ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_LEDGER;
+ break;
+ case( PAPER_STATEMENT ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_STATEMENT;
+ break;
+ case( PAPER_10x14 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_10X14;
+ break;
+ case( PAPER_ENV_14 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_14;
+ break;
+ case( PAPER_ENV_C3 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_C3;
+ break;
+ case( PAPER_ENV_ITALY ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_ITALY;
+ break;
+ case( PAPER_FANFOLD_US ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_FANFOLD_US;
+ break;
+ case( PAPER_FANFOLD_DE ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_FANFOLD_STD_GERMAN;
+ break;
+ case( PAPER_POSTCARD_JP ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_JAPANESE_POSTCARD;
+ break;
+ case( PAPER_9x11 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_9X11;
+ break;
+ case( PAPER_10x11 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_10X11;
+ break;
+ case( PAPER_15x11 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_15X11;
+ break;
+ case( PAPER_ENV_INVITE ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_INVITE;
+ break;
+ case( PAPER_A_PLUS ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A_PLUS;
+ break;
+ case( PAPER_B_PLUS ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_B_PLUS;
+ break;
+ case( PAPER_LETTER_PLUS ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_LETTER_PLUS;
+ break;
+ case( PAPER_A4_PLUS ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A4_PLUS;
+ break;
+ case( PAPER_DOUBLEPOSTCARD_JP ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_DBL_JAPANESE_POSTCARD;
+ break;
+ case( PAPER_A6 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A6;
+ break;
+ case( PAPER_12x11 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_12X11;
+ break;
+ default:
+ {
+ short nPaper = 0;
+ ULONG nPaperCount = ImplDeviceCaps( pPrinter, DC_PAPERS, NULL, pSetupData );
+ WORD* pPapers = NULL;
+ ULONG nPaperSizeCount = ImplDeviceCaps( pPrinter, DC_PAPERSIZE, NULL, pSetupData );
+ POINT* pPaperSizes = NULL;
+ DWORD nLandscapeAngle = ImplDeviceCaps( pPrinter, DC_ORIENTATION, NULL, pSetupData );
+ if ( nPaperCount && (nPaperCount != GDI_ERROR) )
+ {
+ pPapers = (WORD*)rtl_allocateZeroMemory(nPaperCount*sizeof(WORD));
+ ImplDeviceCaps( pPrinter, DC_PAPERS, (BYTE*)pPapers, pSetupData );
+ }
+ if ( nPaperSizeCount && (nPaperSizeCount != GDI_ERROR) )
+ {
+ pPaperSizes = (POINT*)rtl_allocateZeroMemory(nPaperSizeCount*sizeof(POINT));
+ ImplDeviceCaps( pPrinter, DC_PAPERSIZE, (BYTE*)pPaperSizes, pSetupData );
+ }
+ if ( (nPaperSizeCount == nPaperCount) && pPapers && pPaperSizes )
+ {
+ PaperInfo aInfo(pSetupData->mnPaperWidth, pSetupData->mnPaperHeight);
+ // compare paper formats and select a good match
+ for ( ULONG i = 0; i < nPaperCount; i++ )
+ {
+ if ( aInfo.sloppyEqual(PaperInfo(pPaperSizes[i].x*10, pPaperSizes[i].y*10)))
+ {
+ nPaper = pPapers[i];
+ 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 ( !nPaper && nLandscapeAngle != 0 )
+ {
+ PaperInfo aRotatedInfo(pSetupData->mnPaperHeight, pSetupData->mnPaperWidth);
+ for ( ULONG i = 0; i < nPaperCount; i++ )
+ {
+ if ( aRotatedInfo.sloppyEqual(PaperInfo(pPaperSizes[i].x*10, pPaperSizes[i].y*10)) )
+ {
+ nPaper = pPapers[i];
+ break;
+ }
+ }
+ }
+
+ if ( nPaper )
+ CHOOSE_DEVMODE(dmPaperSize) = nPaper;
+ }
+
+ if ( !nPaper )
+ {
+ CHOOSE_DEVMODE(dmFields) |= DM_PAPERLENGTH | DM_PAPERWIDTH;
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_USER;
+ CHOOSE_DEVMODE(dmPaperWidth) = (short)(pSetupData->mnPaperWidth/10);
+ CHOOSE_DEVMODE(dmPaperLength) = (short)(pSetupData->mnPaperHeight/10);
+ }
+
+ if ( pPapers )
+ rtl_freeMemory(pPapers);
+ if ( pPaperSizes )
+ rtl_freeMemory(pPaperSizes);
+
+ break;
+ }
+ }
+ }
+ if( (nFlags & SAL_JOBSET_DUPLEXMODE) )
+ {
+ switch( pSetupData->meDuplexMode )
+ {
+ case DUPLEX_OFF:
+ CHOOSE_DEVMODE(dmFields) |= DM_DUPLEX;
+ CHOOSE_DEVMODE(dmDuplex) = DMDUP_SIMPLEX;
+ break;
+ case DUPLEX_SHORTEDGE:
+ CHOOSE_DEVMODE(dmFields) |= DM_DUPLEX;
+ CHOOSE_DEVMODE(dmDuplex) = DMDUP_HORIZONTAL;
+ break;
+ case DUPLEX_LONGEDGE:
+ CHOOSE_DEVMODE(dmFields) |= DM_DUPLEX;
+ CHOOSE_DEVMODE(dmDuplex) = DMDUP_VERTICAL;
+ break;
+ case DUPLEX_UNKNOWN:
+ break;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static HDC ImplCreateICW_WithCatch( LPWSTR pDriver,
+ LPCWSTR pDevice,
+ LPDEVMODEW pDevMode )
+{
+ HDC hDC = 0;
+ CATCH_DRIVER_EX_BEGIN;
+ hDC = CreateICW( pDriver, pDevice, 0, pDevMode );
+ CATCH_DRIVER_EX_END_2( "exception in CreateICW" );
+ return hDC;
+}
+
+static HDC ImplCreateICA_WithCatch( char* pDriver,
+ char* pDevice,
+ LPDEVMODEA pDevMode )
+{
+ HDC hDC = 0;
+ CATCH_DRIVER_EX_BEGIN;
+ hDC = CreateICA( pDriver, pDevice, 0, pDevMode );
+ CATCH_DRIVER_EX_END_2( "exception in CreateICW" );
+ return hDC;
+}
+
+
+static HDC ImplCreateSalPrnIC( WinSalInfoPrinter* pPrinter, ImplJobSetup* pSetupData )
+{
+ HDC hDC = 0;
+ if( aSalShlData.mbWPrinter )
+ {
+ LPDEVMODEW pDevMode;
+ if ( pSetupData && pSetupData->mpDriverData )
+ pDevMode = SAL_DEVMODE_W( pSetupData );
+ else
+ pDevMode = NULL;
+ // #95347 some buggy drivers (eg, OKI) write to those buffers in CreateIC, although declared const - so provide some space
+ // pl: does this hold true for Unicode functions ?
+ if( pPrinter->maDriverName.Len() > 2048 || pPrinter->maDeviceName.Len() > 2048 )
+ return 0;
+ sal_Unicode pDriverName[ 4096 ];
+ sal_Unicode pDeviceName[ 4096 ];
+ rtl_copyMemory( pDriverName, pPrinter->maDriverName.GetBuffer(), pPrinter->maDriverName.Len()*sizeof(sal_Unicode));
+ memset( pDriverName+pPrinter->maDriverName.Len(), 0, 32 );
+ rtl_copyMemory( pDeviceName, pPrinter->maDeviceName.GetBuffer(), pPrinter->maDeviceName.Len()*sizeof(sal_Unicode));
+ memset( pDeviceName+pPrinter->maDeviceName.Len(), 0, 32 );
+ hDC = ImplCreateICW_WithCatch( reinterpret_cast< LPWSTR >(pDriverName),
+ reinterpret_cast< LPCWSTR >(pDeviceName),
+ pDevMode );
+ }
+ else
+ {
+ LPDEVMODEA pDevMode;
+ if ( pSetupData && pSetupData->mpDriverData )
+ pDevMode = SAL_DEVMODE_A( pSetupData );
+ else
+ pDevMode = NULL;
+ // #95347 some buggy drivers (eg, OKI) write to those buffers in CreateIC, although declared const - so provide some space
+ ByteString aDriver ( ImplSalGetWinAnsiString( pPrinter->maDriverName, TRUE ) );
+ ByteString aDevice ( ImplSalGetWinAnsiString( pPrinter->maDeviceName, TRUE ) );
+ int n = aDriver.Len() > aDevice.Len() ? aDriver.Len() : aDevice.Len();
+ // #125813# under some circumstances many printer drivers really
+ // seem to have a problem with the names and their conversions.
+ // We need to get on to of this, but haven't been able to reproduce
+ // the problem yet. Put the names on the stack so we get them
+ // with an eventual crash report.
+ if( n >= 2048 )
+ return 0;
+ n += 2048;
+ char lpszDriverName[ 4096 ];
+ char lpszDeviceName[ 4096 ];
+ strncpy( lpszDriverName, aDriver.GetBuffer(), n );
+ strncpy( lpszDeviceName, aDevice.GetBuffer(), n );
+ // HDU: the crashes usually happen in a MBCS to unicode conversion,
+ // so I suspect the MBCS string's end is not properly recognized.
+ // The longest MBCS encoding I'm aware of has six bytes per code
+ // => add a couple of zeroes...
+ memset( lpszDriverName+aDriver.Len(), 0, 16 );
+ memset( lpszDeviceName+aDevice.Len(), 0, 16 );
+ hDC = ImplCreateICA_WithCatch( lpszDriverName,
+ lpszDeviceName,
+ pDevMode );
+ }
+ return hDC;
+}
+
+// -----------------------------------------------------------------------
+
+static WinSalGraphics* ImplCreateSalPrnGraphics( HDC hDC )
+{
+ WinSalGraphics* pGraphics = new WinSalGraphics;
+ pGraphics->SetLayout( 0 );
+ pGraphics->mhDC = hDC;
+ pGraphics->mhWnd = 0;
+ pGraphics->mbPrinter = TRUE;
+ pGraphics->mbVirDev = FALSE;
+ pGraphics->mbWindow = FALSE;
+ pGraphics->mbScreen = FALSE;
+ ImplSalInitGraphics( pGraphics );
+ return pGraphics;
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplUpdateSalPrnIC( WinSalInfoPrinter* pPrinter, ImplJobSetup* pSetupData )
+{
+ HDC hNewDC = ImplCreateSalPrnIC( pPrinter, pSetupData );
+ if ( !hNewDC )
+ return FALSE;
+
+ if ( pPrinter->mpGraphics )
+ {
+ ImplSalDeInitGraphics( pPrinter->mpGraphics );
+ DeleteDC( pPrinter->mpGraphics->mhDC );
+ delete pPrinter->mpGraphics;
+ }
+
+ pPrinter->mpGraphics = ImplCreateSalPrnGraphics( hNewDC );
+ pPrinter->mhDC = hNewDC;
+
+ return TRUE;
+}
+
+// =======================================================================
+
+SalInfoPrinter* WinSalInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
+ ImplJobSetup* pSetupData )
+{
+ WinSalInfoPrinter* pPrinter = new WinSalInfoPrinter;
+ if( ! pQueueInfo->mpSysData )
+ GetPrinterQueueState( pQueueInfo );
+ pPrinter->maDriverName = pQueueInfo->maDriver;
+ pPrinter->maDeviceName = pQueueInfo->maPrinterName;
+ pPrinter->maPortName = pQueueInfo->mpSysData ?
+ *(String*)(pQueueInfo->mpSysData)
+ : String();
+
+ // check if the provided setup data match the actual printer
+ ImplTestSalJobSetup( pPrinter, pSetupData, TRUE );
+
+ HDC hDC = ImplCreateSalPrnIC( pPrinter, pSetupData );
+ if ( !hDC )
+ {
+ delete pPrinter;
+ return NULL;
+ }
+
+ pPrinter->mpGraphics = ImplCreateSalPrnGraphics( hDC );
+ pPrinter->mhDC = hDC;
+ if ( !pSetupData->mpDriverData )
+ ImplUpdateSalJobSetup( pPrinter, pSetupData, FALSE, NULL );
+ ImplDevModeToJobSetup( pPrinter, pSetupData, SAL_JOBSET_ALL );
+ pSetupData->mnSystem = JOBSETUP_SYSTEM_WINDOWS;
+
+ return pPrinter;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter )
+{
+ delete pPrinter;
+}
+
+// =======================================================================
+
+WinSalInfoPrinter::WinSalInfoPrinter() :
+ mpGraphics( NULL ),
+ mhDC( 0 ),
+ mbGraphics( FALSE )
+{
+ m_bPapersInit = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+WinSalInfoPrinter::~WinSalInfoPrinter()
+{
+ if ( mpGraphics )
+ {
+ ImplSalDeInitGraphics( mpGraphics );
+ DeleteDC( mpGraphics->mhDC );
+ delete mpGraphics;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalInfoPrinter::InitPaperFormats( const ImplJobSetup* pSetupData )
+{
+ m_aPaperFormats.clear();
+
+ DWORD nCount = ImplDeviceCaps( this, DC_PAPERSIZE, NULL, pSetupData );
+ if( nCount == GDI_ERROR )
+ nCount = 0;
+
+ POINT* pPaperSizes = NULL;
+ if( nCount )
+ {
+ pPaperSizes = (POINT*)rtl_allocateZeroMemory(nCount*sizeof(POINT));
+ ImplDeviceCaps( this, DC_PAPERSIZE, (BYTE*)pPaperSizes, pSetupData );
+
+ if( aSalShlData.mbWPrinter )
+ {
+ sal_Unicode* pNamesBuffer = (sal_Unicode*)rtl_allocateMemory(nCount*64*sizeof(sal_Unicode));
+ ImplDeviceCaps( this, DC_PAPERNAMES, (BYTE*)pNamesBuffer, pSetupData );
+ for( DWORD i = 0; i < nCount; ++i )
+ {
+ PaperInfo aInfo(pPaperSizes[i].x * 10, pPaperSizes[i].y * 10);
+ m_aPaperFormats.push_back( aInfo );
+ }
+ rtl_freeMemory( pNamesBuffer );
+ }
+ else
+ {
+ char* pNamesBuffer = (char*)rtl_allocateMemory(nCount*64);
+ ImplDeviceCaps( this, DC_PAPERNAMES, (BYTE*)pNamesBuffer, pSetupData );
+ for( DWORD i = 0; i < nCount; ++i )
+ {
+ PaperInfo aInfo(pPaperSizes[i].x * 10, pPaperSizes[i].y * 10);
+ m_aPaperFormats.push_back( aInfo );
+ }
+ rtl_freeMemory( pNamesBuffer );
+ }
+ rtl_freeMemory( pPaperSizes );
+ }
+
+ m_bPapersInit = true;
+}
+
+// -----------------------------------------------------------------------
+
+int WinSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* pSetupData )
+{
+ int nRet = ImplDeviceCaps( this, DC_ORIENTATION, NULL, pSetupData );
+
+ if( nRet != GDI_ERROR )
+ return nRet * 10;
+ else
+ return 900; // guess
+}
+
+// -----------------------------------------------------------------------
+
+SalGraphics* WinSalInfoPrinter::GetGraphics()
+{
+ if ( mbGraphics )
+ return NULL;
+
+ if ( mpGraphics )
+ mbGraphics = TRUE;
+
+ return mpGraphics;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalInfoPrinter::ReleaseGraphics( SalGraphics* )
+{
+ mbGraphics = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL WinSalInfoPrinter::Setup( SalFrame* pFrame, ImplJobSetup* pSetupData )
+{
+ if ( ImplUpdateSalJobSetup( this, pSetupData, TRUE, static_cast<WinSalFrame*>(pFrame) ) )
+ {
+ ImplDevModeToJobSetup( this, pSetupData, SAL_JOBSET_ALL );
+ return ImplUpdateSalPrnIC( this, pSetupData );
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL WinSalInfoPrinter::SetPrinterData( ImplJobSetup* pSetupData )
+{
+ if ( !ImplTestSalJobSetup( this, pSetupData, FALSE ) )
+ return FALSE;
+ return ImplUpdateSalPrnIC( this, pSetupData );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL WinSalInfoPrinter::SetData( ULONG nFlags, ImplJobSetup* pSetupData )
+{
+ ImplJobSetupToDevMode( this, pSetupData, nFlags );
+ if ( ImplUpdateSalJobSetup( this, pSetupData, TRUE, NULL ) )
+ {
+ ImplDevModeToJobSetup( this, pSetupData, nFlags );
+ return ImplUpdateSalPrnIC( this, pSetupData );
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG WinSalInfoPrinter::GetPaperBinCount( const ImplJobSetup* pSetupData )
+{
+ DWORD nRet = ImplDeviceCaps( this, DC_BINS, NULL, pSetupData );
+ if ( nRet && (nRet != GDI_ERROR) )
+ return nRet;
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+XubString WinSalInfoPrinter::GetPaperBinName( const ImplJobSetup* pSetupData, ULONG nPaperBin )
+{
+ XubString aPaperBinName;
+
+ DWORD nBins = ImplDeviceCaps( this, DC_BINNAMES, NULL, pSetupData );
+ if ( (nPaperBin < nBins) && (nBins != GDI_ERROR) )
+ {
+ if( aSalShlData.mbWPrinter )
+ {
+ sal_Unicode* pBuffer = new sal_Unicode[nBins*24];
+ DWORD nRet = ImplDeviceCaps( this, DC_BINNAMES, (BYTE*)pBuffer, pSetupData );
+ if ( nRet && (nRet != GDI_ERROR) )
+ aPaperBinName = pBuffer + (nPaperBin*24);
+ delete [] pBuffer;
+ }
+ else
+ {
+ char* pBuffer = new char[nBins*24];
+ DWORD nRet = ImplDeviceCaps( this, DC_BINNAMES, (BYTE*)pBuffer, pSetupData );
+ if ( nRet && (nRet != GDI_ERROR) )
+ aPaperBinName = ImplSalGetUniString( (const char*)(pBuffer + (nPaperBin*24)) );
+ delete [] pBuffer;
+ }
+ }
+
+ return aPaperBinName;
+}
+
+// -----------------------------------------------------------------------
+
+ULONG WinSalInfoPrinter::GetCapabilities( const ImplJobSetup* pSetupData, USHORT nType )
+{
+ DWORD nRet;
+
+ switch ( nType )
+ {
+ case PRINTER_CAPABILITIES_SUPPORTDIALOG:
+ return TRUE;
+ case PRINTER_CAPABILITIES_COPIES:
+ nRet = ImplDeviceCaps( this, DC_COPIES, NULL, pSetupData );
+ if ( nRet && (nRet != GDI_ERROR) )
+ return nRet;
+ return 0;
+ case PRINTER_CAPABILITIES_COLLATECOPIES:
+ if ( aSalShlData.mbW40 )
+ {
+ nRet = ImplDeviceCaps( this, DC_COLLATE, NULL, pSetupData );
+ if ( nRet && (nRet != GDI_ERROR) )
+ {
+ nRet = ImplDeviceCaps( this, DC_COPIES, NULL, pSetupData );
+ if ( nRet && (nRet != GDI_ERROR) )
+ return nRet;
+ }
+ }
+ return 0;
+
+ case PRINTER_CAPABILITIES_SETORIENTATION:
+ nRet = ImplDeviceCaps( this, DC_ORIENTATION, NULL, pSetupData );
+ if ( nRet && (nRet != GDI_ERROR) )
+ return TRUE;
+ return FALSE;
+
+ case PRINTER_CAPABILITIES_SETPAPERBIN:
+ nRet = ImplDeviceCaps( this, DC_BINS, NULL, pSetupData );
+ if ( nRet && (nRet != GDI_ERROR) )
+ return TRUE;
+ return FALSE;
+
+ case PRINTER_CAPABILITIES_SETPAPERSIZE:
+ case PRINTER_CAPABILITIES_SETPAPER:
+ nRet = ImplDeviceCaps( this, DC_PAPERS, NULL, pSetupData );
+ if ( nRet && (nRet != GDI_ERROR) )
+ return TRUE;
+ return FALSE;
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalInfoPrinter::GetPageInfo( const ImplJobSetup*,
+ long& rOutWidth, long& rOutHeight,
+ long& rPageOffX, long& rPageOffY,
+ long& rPageWidth, long& rPageHeight )
+{
+ HDC hDC = mhDC;
+
+ rOutWidth = GetDeviceCaps( hDC, HORZRES );
+ rOutHeight = GetDeviceCaps( hDC, VERTRES );
+
+ rPageOffX = GetDeviceCaps( hDC, PHYSICALOFFSETX );
+ rPageOffY = GetDeviceCaps( hDC, PHYSICALOFFSETY );
+ rPageWidth = GetDeviceCaps( hDC, PHYSICALWIDTH );
+ rPageHeight = GetDeviceCaps( hDC, PHYSICALHEIGHT );
+}
+
+// =======================================================================
+
+SalPrinter* WinSalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter )
+{
+ WinSalPrinter* pPrinter = new WinSalPrinter;
+ pPrinter->mpInfoPrinter = static_cast<WinSalInfoPrinter*>(pInfoPrinter);
+ return pPrinter;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalInstance::DestroyPrinter( SalPrinter* pPrinter )
+{
+ delete pPrinter;
+}
+
+// =======================================================================
+
+WIN_BOOL CALLBACK SalPrintAbortProc( HDC hPrnDC, int /* nError */ )
+{
+ SalData* pSalData = GetSalData();
+ WinSalPrinter* pPrinter;
+ BOOL bWhile = TRUE;
+ int i = 0;
+
+ do
+ {
+ // Messages verarbeiten
+ MSG aMsg;
+ if ( ImplPeekMessage( &aMsg, 0, 0, 0, PM_REMOVE ) )
+ {
+ TranslateMessage( &aMsg );
+ ImplDispatchMessage( &aMsg );
+ i++;
+ if ( i > 15 )
+ bWhile = FALSE;
+ }
+ else
+ bWhile = FALSE;
+
+ pPrinter = pSalData->mpFirstPrinter;
+ while ( pPrinter )
+ {
+ if( pPrinter->mhDC == hPrnDC )
+ break;
+
+ pPrinter = pPrinter->mpNextPrinter;
+ }
+
+ if ( !pPrinter || pPrinter->mbAbort )
+ return FALSE;
+ }
+ while ( bWhile );
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+static LPDEVMODEA ImplSalSetCopies( LPDEVMODEA pDevMode, ULONG nCopies, BOOL bCollate )
+{
+ LPDEVMODEA pNewDevMode = pDevMode;
+ if ( pDevMode && (nCopies > 1) )
+ {
+ if ( nCopies > 32765 )
+ nCopies = 32765;
+ ULONG nDevSize = pDevMode->dmSize+pDevMode->dmDriverExtra;
+ pNewDevMode = (LPDEVMODEA)rtl_allocateMemory( nDevSize );
+ memcpy( pNewDevMode, pDevMode, nDevSize );
+ pDevMode = pNewDevMode;
+ pDevMode->dmFields |= DM_COPIES;
+ pDevMode->dmCopies = (short)(USHORT)nCopies;
+ if ( aSalShlData.mbW40 )
+ {
+ pDevMode->dmFields |= DM_COLLATE;
+ if ( bCollate )
+ pDevMode->dmCollate = DMCOLLATE_TRUE;
+ else
+ pDevMode->dmCollate = DMCOLLATE_FALSE;
+ }
+ }
+
+ return pNewDevMode;
+}
+
+static LPDEVMODEW ImplSalSetCopies( LPDEVMODEW pDevMode, ULONG nCopies, BOOL bCollate )
+{
+ LPDEVMODEW pNewDevMode = pDevMode;
+ if ( pDevMode && (nCopies > 1) )
+ {
+ if ( nCopies > 32765 )
+ nCopies = 32765;
+ ULONG nDevSize = pDevMode->dmSize+pDevMode->dmDriverExtra;
+ pNewDevMode = (LPDEVMODEW)rtl_allocateMemory( nDevSize );
+ memcpy( pNewDevMode, pDevMode, nDevSize );
+ pDevMode = pNewDevMode;
+ pDevMode->dmFields |= DM_COPIES;
+ pDevMode->dmCopies = (short)(USHORT)nCopies;
+ if ( aSalShlData.mbW40 )
+ {
+ pDevMode->dmFields |= DM_COLLATE;
+ if ( bCollate )
+ pDevMode->dmCollate = DMCOLLATE_TRUE;
+ else
+ pDevMode->dmCollate = DMCOLLATE_FALSE;
+ }
+ }
+
+ return pNewDevMode;
+}
+
+// -----------------------------------------------------------------------
+
+WinSalPrinter::WinSalPrinter() :
+ mpGraphics( NULL ),
+ mpInfoPrinter( NULL ),
+ mpNextPrinter( NULL ),
+ mhDC( 0 ),
+ mnError( 0 ),
+ mnCopies( 0 ),
+ mbCollate( FALSE ),
+ mbAbort( FALSE ),
+ mbValid( true )
+{
+ SalData* pSalData = GetSalData();
+ // insert printer in printerlist
+ mpNextPrinter = pSalData->mpFirstPrinter;
+ pSalData->mpFirstPrinter = this;
+}
+
+// -----------------------------------------------------------------------
+
+WinSalPrinter::~WinSalPrinter()
+{
+ SalData* pSalData = GetSalData();
+
+ // release DC if there is one still around because of AbortJob
+ HDC hDC = mhDC;
+ if ( hDC )
+ {
+ if ( mpGraphics )
+ {
+ ImplSalDeInitGraphics( mpGraphics );
+ delete mpGraphics;
+ }
+
+ DeleteDC( hDC );
+ }
+
+ // remove printer from printerlist
+ if ( this == pSalData->mpFirstPrinter )
+ pSalData->mpFirstPrinter = mpNextPrinter;
+ else
+ {
+ WinSalPrinter* pTempPrinter = pSalData->mpFirstPrinter;
+
+ while( pTempPrinter->mpNextPrinter != this )
+ pTempPrinter = pTempPrinter->mpNextPrinter;
+
+ pTempPrinter->mpNextPrinter = mpNextPrinter;
+ }
+ mbValid = false;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalPrinter::markInvalid()
+{
+ mbValid = false;
+}
+
+// -----------------------------------------------------------------------
+
+// need wrappers for StarTocW/A to use structured exception handling
+// since SEH does not mix with standard exception handling's cleanup
+static int lcl_StartDocW( HDC hDC, DOCINFOW* pInfo, WinSalPrinter* pPrt )
+{
+ int nRet = 0;
+ CATCH_DRIVER_EX_BEGIN;
+ nRet = ::StartDocW( hDC, pInfo );
+ CATCH_DRIVER_EX_END( "exception in StartDocW", pPrt );
+ return nRet;
+}
+
+static int lcl_StartDocA( HDC hDC, DOCINFOA* pInfo, WinSalPrinter* pPrt )
+{
+ int nRet = 0;
+ CATCH_DRIVER_EX_BEGIN;
+ nRet = ::StartDocA( hDC, pInfo );
+ CATCH_DRIVER_EX_END( "exception in StartDocW", pPrt );
+ return nRet;
+}
+
+BOOL WinSalPrinter::StartJob( const XubString* pFileName,
+ const XubString& rJobName,
+ const XubString&,
+ ULONG nCopies,
+ bool bCollate,
+ bool /*bDirect*/,
+ ImplJobSetup* pSetupData )
+{
+ mnError = 0;
+ mbAbort = FALSE;
+ mnCopies = nCopies;
+ mbCollate = bCollate;
+
+ LPDEVMODEA pOrgDevModeA = NULL;
+ LPDEVMODEA pDevModeA = NULL;
+ LPDEVMODEW pOrgDevModeW = NULL;
+ LPDEVMODEW pDevModeW = NULL;
+ HDC hDC = 0;
+ if( aSalShlData.mbWPrinter )
+ {
+ if ( pSetupData && pSetupData->mpDriverData )
+ {
+ pOrgDevModeW = SAL_DEVMODE_W( pSetupData );
+ pDevModeW = ImplSalSetCopies( pOrgDevModeW, nCopies, bCollate );
+ }
+ else
+ pDevModeW = NULL;
+
+ // #95347 some buggy drivers (eg, OKI) write to those buffers in CreateDC, although declared const - so provide some space
+ sal_Unicode aDrvBuf[4096];
+ sal_Unicode aDevBuf[4096];
+ rtl_copyMemory( aDrvBuf, mpInfoPrinter->maDriverName.GetBuffer(), (mpInfoPrinter->maDriverName.Len()+1)*sizeof(sal_Unicode));
+ rtl_copyMemory( aDevBuf, mpInfoPrinter->maDeviceName.GetBuffer(), (mpInfoPrinter->maDeviceName.Len()+1)*sizeof(sal_Unicode));
+ hDC = CreateDCW( reinterpret_cast<LPCWSTR>(aDrvBuf),
+ reinterpret_cast<LPCWSTR>(aDevBuf),
+ NULL,
+ pDevModeW );
+
+ if ( pDevModeW != pOrgDevModeW )
+ rtl_freeMemory( pDevModeW );
+ }
+ else
+ {
+ if ( pSetupData && pSetupData->mpDriverData )
+ {
+ pOrgDevModeA = SAL_DEVMODE_A( pSetupData );
+ pDevModeA = ImplSalSetCopies( pOrgDevModeA, nCopies, bCollate );
+ }
+ else
+ pDevModeA = NULL;
+
+ // #95347 some buggy drivers (eg, OKI) write to those buffers in CreateDC, although declared const - so provide some space
+ ByteString aDriver ( ImplSalGetWinAnsiString( mpInfoPrinter->maDriverName, TRUE ) );
+ ByteString aDevice ( ImplSalGetWinAnsiString( mpInfoPrinter->maDeviceName, TRUE ) );
+ int n = aDriver.Len() > aDevice.Len() ? aDriver.Len() : aDevice.Len();
+ n += 2048;
+ char *lpszDriverName = new char[n];
+ char *lpszDeviceName = new char[n];
+ strncpy( lpszDriverName, aDriver.GetBuffer(), n );
+ strncpy( lpszDeviceName, aDevice.GetBuffer(), n );
+ hDC = CreateDCA( lpszDriverName,
+ lpszDeviceName,
+ NULL,
+ pDevModeA );
+
+ delete [] lpszDriverName;
+ delete [] lpszDeviceName;
+
+ if ( pDevModeA != pOrgDevModeA )
+ rtl_freeMemory( pDevModeA );
+ }
+
+ if ( !hDC )
+ {
+ mnError = SAL_PRINTER_ERROR_GENERALERROR;
+ return FALSE;
+ }
+
+ // make sure mhDC is set before the printer driver may call our abortproc
+ mhDC = hDC;
+ if ( SetAbortProc( hDC, SalPrintAbortProc ) <= 0 )
+ {
+ mnError = SAL_PRINTER_ERROR_GENERALERROR;
+ return FALSE;
+ }
+
+ mnError = 0;
+ mbAbort = FALSE;
+
+ // Wegen Telocom Balloon Fax-Treiber, der uns unsere Messages
+ // ansonsten oefters schickt, versuchen wir vorher alle
+ // zu verarbeiten und dann eine Dummy-Message reinstellen
+ BOOL bWhile = TRUE;
+ int i = 0;
+ do
+ {
+ // Messages verarbeiten
+ MSG aMsg;
+ if ( ImplPeekMessage( &aMsg, 0, 0, 0, PM_REMOVE ) )
+ {
+ TranslateMessage( &aMsg );
+ ImplDispatchMessage( &aMsg );
+ i++;
+ if ( i > 15 )
+ bWhile = FALSE;
+ }
+ else
+ bWhile = FALSE;
+ }
+ while ( bWhile );
+ ImplPostMessage( GetSalData()->mpFirstInstance->mhComWnd, SAL_MSG_DUMMY, 0, 0 );
+
+ // bring up a file choser if printing to file port but no file name given
+ OUString aOutFileName;
+ if( mpInfoPrinter->maPortName.EqualsIgnoreCaseAscii( "FILE:" ) && !(pFileName && pFileName->Len()) )
+ {
+
+ Reference< XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory() );
+ if( xFactory.is() )
+ {
+ Reference< XFilePicker > xFilePicker( xFactory->createInstance(
+ OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.ui.dialogs.FilePicker" ) ) ),
+ UNO_QUERY );
+ DBG_ASSERT( xFilePicker.is(), "could not get FilePicker service" );
+
+ Reference< XInitialization > xInit( xFilePicker, UNO_QUERY );
+ Reference< XFilterManager > xFilterMgr( xFilePicker, UNO_QUERY );
+ if( xInit.is() && xFilePicker.is() && xFilterMgr.is() )
+ {
+ Sequence< Any > aServiceType( 1 );
+ aServiceType[0] <<= TemplateDescription::FILESAVE_SIMPLE;
+ xInit->initialize( aServiceType );
+ if( xFilePicker->execute() == ExecutableDialogResults::OK )
+ {
+ Sequence< OUString > aPathSeq( xFilePicker->getFiles() );
+ INetURLObject aObj( aPathSeq[0] );
+ // we're using ansi calls (StartDocA) so convert the string
+ aOutFileName = aObj.PathToFileName();
+ }
+ else
+ {
+ mnError = SAL_PRINTER_ERROR_ABORT;
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ if( aSalShlData.mbWPrinter )
+ {
+ DOCINFOW aInfo;
+ memset( &aInfo, 0, sizeof( DOCINFOW ) );
+ aInfo.cbSize = sizeof( aInfo );
+ aInfo.lpszDocName = (LPWSTR)rJobName.GetBuffer();
+ if ( pFileName || aOutFileName.getLength() )
+ {
+ if ( (pFileName && pFileName->Len()) || aOutFileName.getLength() )
+ {
+ aInfo.lpszOutput = (LPWSTR)( (pFileName && pFileName->Len()) ? pFileName->GetBuffer() : aOutFileName.getStr());
+ }
+ else
+ aInfo.lpszOutput = L"FILE:";
+ }
+ else
+ aInfo.lpszOutput = NULL;
+
+ // start Job
+ int nRet = lcl_StartDocW( hDC, &aInfo, this );
+
+ if ( nRet <= 0 )
+ {
+ long nError = GetLastError();
+ if ( (nRet == SP_USERABORT) || (nRet == SP_APPABORT) || (nError == ERROR_PRINT_CANCELLED) || (nError == ERROR_CANCELLED) )
+ mnError = SAL_PRINTER_ERROR_ABORT;
+ else
+ mnError = SAL_PRINTER_ERROR_GENERALERROR;
+ return FALSE;
+ }
+ }
+ else
+ {
+ // Both strings must exist, if StartJob() is called
+ ByteString aJobName( ImplSalGetWinAnsiString( rJobName, TRUE ) );
+ ByteString aFileName;
+
+ DOCINFOA aInfo;
+ memset( &aInfo, 0, sizeof( DOCINFOA ) );
+ aInfo.cbSize = sizeof( aInfo );
+ aInfo.lpszDocName = (LPCSTR)aJobName.GetBuffer();
+ if ( pFileName || aOutFileName.getLength() )
+ {
+ if ( pFileName->Len() || aOutFileName.getLength() )
+ {
+ aFileName = ImplSalGetWinAnsiString( pFileName ? *pFileName : static_cast<const XubString>(aOutFileName), TRUE );
+ aInfo.lpszOutput = (LPCSTR)aFileName.GetBuffer();
+ }
+ else
+ aInfo.lpszOutput = "FILE:";
+ }
+ else
+ aInfo.lpszOutput = NULL;
+
+ // start Job
+ int nRet = lcl_StartDocA( hDC, &aInfo, this );
+ if ( nRet <= 0 )
+ {
+ long nError = GetLastError();
+ if ( (nRet == SP_USERABORT) || (nRet == SP_APPABORT) || (nError == ERROR_PRINT_CANCELLED) || (nError == ERROR_CANCELLED) )
+ mnError = SAL_PRINTER_ERROR_ABORT;
+ else
+ mnError = SAL_PRINTER_ERROR_GENERALERROR;
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL WinSalPrinter::EndJob()
+{
+ DWORD err = 0;
+ HDC hDC = mhDC;
+ if ( isValid() && hDC )
+ {
+ if ( mpGraphics )
+ {
+ ImplSalDeInitGraphics( mpGraphics );
+ delete mpGraphics;
+ mpGraphics = NULL;
+ }
+
+ // #i54419# Windows fax printer brings up a dialog in EndDoc
+ // which text previously copied in soffice process can be
+ // pasted to -> deadlock due to mutex not released.
+ // it should be safe to release the yield mutex over the EndDoc
+ // call, however the real solution is supposed to be the threading
+ // framework yet to come.
+ SalData* pSalData = GetSalData();
+ ULONG nAcquire = pSalData->mpFirstInstance->ReleaseYieldMutex();
+ CATCH_DRIVER_EX_BEGIN;
+ if( ::EndDoc( hDC ) <= 0 )
+ err = GetLastError();
+ CATCH_DRIVER_EX_END( "exception in EndDoc", this );
+
+ pSalData->mpFirstInstance->AcquireYieldMutex( nAcquire );
+ DeleteDC( hDC );
+ mhDC = 0;
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL WinSalPrinter::AbortJob()
+{
+ mbAbort = TRUE;
+
+ // Abort asyncron ausloesen
+ HDC hDC = mhDC;
+ if ( hDC )
+ {
+ SalData* pSalData = GetSalData();
+ ImplPostMessage( pSalData->mpFirstInstance->mhComWnd,
+ SAL_MSG_PRINTABORTJOB, (WPARAM)hDC, 0 );
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplSalPrinterAbortJobAsync( HDC hPrnDC )
+{
+ SalData* pSalData = GetSalData();
+ WinSalPrinter* pPrinter = pSalData->mpFirstPrinter;
+
+ // Feststellen, ob Printer noch existiert
+ while ( pPrinter )
+ {
+ if ( pPrinter->mhDC == hPrnDC )
+ break;
+
+ pPrinter = pPrinter->mpNextPrinter;
+ }
+
+ // Wenn Printer noch existiert, dann den Job abbrechen
+ if ( pPrinter )
+ {
+ HDC hDC = pPrinter->mhDC;
+ if ( hDC )
+ {
+ if ( pPrinter->mpGraphics )
+ {
+ ImplSalDeInitGraphics( pPrinter->mpGraphics );
+ delete pPrinter->mpGraphics;
+ pPrinter->mpGraphics = NULL;
+ }
+
+ CATCH_DRIVER_EX_BEGIN;
+ ::AbortDoc( hDC );
+ CATCH_DRIVER_EX_END( "exception in AbortDoc", pPrinter );
+
+ DeleteDC( hDC );
+ pPrinter->mhDC = 0;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+SalGraphics* WinSalPrinter::StartPage( ImplJobSetup* pSetupData, BOOL bNewJobData )
+{
+ if( ! isValid() || mhDC == 0 )
+ return NULL;
+
+ HDC hDC = mhDC;
+ if ( pSetupData && pSetupData->mpDriverData && bNewJobData )
+ {
+ if( aSalShlData.mbWPrinter )
+ {
+ LPDEVMODEW pOrgDevModeW;
+ LPDEVMODEW pDevModeW;
+ pOrgDevModeW = SAL_DEVMODE_W( pSetupData );
+ pDevModeW = ImplSalSetCopies( pOrgDevModeW, mnCopies, mbCollate );
+ ResetDCW( hDC, pDevModeW );
+ if ( pDevModeW != pOrgDevModeW )
+ rtl_freeMemory( pDevModeW );
+ }
+ else
+ {
+ LPDEVMODEA pOrgDevModeA;
+ LPDEVMODEA pDevModeA;
+ pOrgDevModeA = SAL_DEVMODE_A( pSetupData );
+ pDevModeA = ImplSalSetCopies( pOrgDevModeA, mnCopies, mbCollate );
+ ResetDCA( hDC, pDevModeA );
+ if ( pDevModeA != pOrgDevModeA )
+ rtl_freeMemory( pDevModeA );
+ }
+ }
+ int nRet = 0;
+ CATCH_DRIVER_EX_BEGIN;
+ nRet = ::StartPage( hDC );
+ CATCH_DRIVER_EX_END( "exception in StartPage", this );
+
+ if ( nRet <= 0 )
+ {
+ GetLastError();
+ mnError = SAL_PRINTER_ERROR_GENERALERROR;
+ return NULL;
+ }
+
+ // Hack to work around old PostScript printer drivers optimizing away empty pages
+ // TODO: move into ImplCreateSalPrnGraphics()?
+ HPEN hTempPen = SelectPen( hDC, GetStockPen( NULL_PEN ) );
+ HBRUSH hTempBrush = SelectBrush( hDC, GetStockBrush( NULL_BRUSH ) );
+ WIN_Rectangle( hDC, -8000, -8000, -7999, -7999 );
+ SelectPen( hDC, hTempPen );
+ SelectBrush( hDC, hTempBrush );
+
+ mpGraphics = ImplCreateSalPrnGraphics( hDC );
+ return mpGraphics;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL WinSalPrinter::EndPage()
+{
+ HDC hDC = mhDC;
+ if ( hDC && mpGraphics )
+ {
+ ImplSalDeInitGraphics( mpGraphics );
+ delete mpGraphics;
+ mpGraphics = NULL;
+ }
+
+ if( ! isValid() )
+ return FALSE;
+
+ int nRet = 0;
+ CATCH_DRIVER_EX_BEGIN;
+ nRet = ::EndPage( hDC );
+ CATCH_DRIVER_EX_END( "exception in EndPage", this );
+
+ if ( nRet > 0 )
+ return TRUE;
+ else
+ {
+ GetLastError();
+ mnError = SAL_PRINTER_ERROR_GENERALERROR;
+ return FALSE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ULONG WinSalPrinter::GetErrorCode()
+{
+ return mnError;
+}
diff --git a/vcl/win/source/gdi/salvd.cxx b/vcl/win/source/gdi/salvd.cxx
new file mode 100644
index 000000000000..816a8fef1141
--- /dev/null
+++ b/vcl/win/source/gdi/salvd.cxx
@@ -0,0 +1,256 @@
+/*************************************************************************
+ *
+ * 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/svwin.h>
+#include <wincomp.hxx>
+#include <saldata.hxx>
+#include <salinst.h>
+#include <salgdi.h>
+#include <salvd.h>
+#include <vcl/sysdata.hxx>
+
+// =======================================================================
+
+static HBITMAP ImplCreateVirDevBitmap( HDC hDC, long nDX, long nDY,
+ USHORT nBitCount )
+{
+ HBITMAP hBitmap;
+
+ if ( nBitCount == 1 )
+ {
+ hBitmap = CreateBitmap( (int)nDX, (int)nDY, 1, 1, NULL );
+ }
+ else
+ {
+ // #146839# Don't use CreateCompatibleBitmap() - there seem to
+ // be build-in limits for those HBITMAPs, at least this fails
+ // rather often on large displays/multi-monitor setups.
+ BITMAPINFO aBitmapInfo;
+ aBitmapInfo.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
+ aBitmapInfo.bmiHeader.biWidth = nDX;
+ aBitmapInfo.bmiHeader.biHeight = nDY;
+ aBitmapInfo.bmiHeader.biPlanes = 1;
+ aBitmapInfo.bmiHeader.biBitCount = (WORD)GetDeviceCaps( hDC,
+ BITSPIXEL );
+ aBitmapInfo.bmiHeader.biCompression = BI_RGB;
+ aBitmapInfo.bmiHeader.biSizeImage = 0;
+ aBitmapInfo.bmiHeader.biXPelsPerMeter = 0;
+ aBitmapInfo.bmiHeader.biYPelsPerMeter = 0;
+ aBitmapInfo.bmiHeader.biClrUsed = 0;
+ aBitmapInfo.bmiHeader.biClrImportant = 0;
+
+ void* pDummy;
+ hBitmap = CreateDIBSection( hDC, &aBitmapInfo,
+ DIB_RGB_COLORS, &pDummy, NULL,
+ 0 );
+ }
+
+ return hBitmap;
+}
+
+// =======================================================================
+
+SalVirtualDevice* WinSalInstance::CreateVirtualDevice( SalGraphics* pSGraphics,
+ long nDX, long nDY,
+ USHORT nBitCount,
+ const SystemGraphicsData* pData )
+{
+ WinSalGraphics* pGraphics = static_cast<WinSalGraphics*>(pSGraphics);
+
+ HDC hDC = NULL;
+ HBITMAP hBmp = NULL;
+ BOOL bOk = FALSE;
+
+ if( pData )
+ {
+ hDC = pData->hDC;
+ hBmp = NULL;
+ bOk = (hDC != NULL);
+ }
+ else
+ {
+ hDC = CreateCompatibleDC( pGraphics->mhDC );
+ if( !hDC )
+ ImplWriteLastError( GetLastError(), "CreateCompatibleDC in CreateVirtualDevice" );
+
+ hBmp = ImplCreateVirDevBitmap( pGraphics->mhDC,
+ nDX, nDY, nBitCount );
+ if( !hBmp )
+ ImplWriteLastError( GetLastError(), "ImplCreateVirDevBitmap in CreateVirtualDevice" );
+ // #124826# continue even if hBmp could not be created
+ // if we would return a failure in this case, the process
+ // would terminate which is not required
+
+ DBG_ASSERT( hBmp, "WinSalInstance::CreateVirtualDevice(), could not create Bitmap!" );
+
+ bOk = (hDC != NULL);
+ }
+
+ if ( bOk )
+ {
+ WinSalVirtualDevice* pVDev = new WinSalVirtualDevice;
+ SalData* pSalData = GetSalData();
+ WinSalGraphics* pVirGraphics = new WinSalGraphics;
+ pVirGraphics->SetLayout( 0 ); // by default no! mirroring for VirtualDevices, can be enabled with EnableRTL()
+ pVirGraphics->mhDC = hDC;
+ pVirGraphics->mhWnd = 0;
+ pVirGraphics->mbPrinter = FALSE;
+ pVirGraphics->mbVirDev = TRUE;
+ pVirGraphics->mbWindow = FALSE;
+ pVirGraphics->mbScreen = pGraphics->mbScreen;
+ if ( pSalData->mhDitherPal && pVirGraphics->mbScreen )
+ {
+ pVirGraphics->mhDefPal = SelectPalette( hDC, pSalData->mhDitherPal, TRUE );
+ RealizePalette( hDC );
+ }
+ ImplSalInitGraphics( pVirGraphics );
+
+ pVDev->mhDC = hDC;
+ pVDev->mhBmp = hBmp;
+ if( hBmp )
+ pVDev->mhDefBmp = SelectBitmap( hDC, hBmp );
+ else
+ pVDev->mhDefBmp = NULL;
+ pVDev->mpGraphics = pVirGraphics;
+ pVDev->mnBitCount = nBitCount;
+ pVDev->mbGraphics = FALSE;
+ pVDev->mbForeignDC = (pData != NULL);
+
+ // insert VirDev in VirDevList
+ pVDev->mpNext = pSalData->mpFirstVD;
+ pSalData->mpFirstVD = pVDev;
+
+ return pVDev;
+ }
+ else
+ {
+ if ( hDC && !pData )
+ DeleteDC( hDC );
+ if ( hBmp )
+ DeleteBitmap( hBmp );
+ return NULL;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalInstance::DestroyVirtualDevice( SalVirtualDevice* pDevice )
+{
+ delete pDevice;
+}
+
+// =======================================================================
+
+WinSalVirtualDevice::WinSalVirtualDevice()
+{
+ mhDC = (HDC) NULL; // HDC or 0 for Cache Device
+ mhBmp = (HBITMAP) NULL; // Memory Bitmap
+ mhDefBmp = (HBITMAP) NULL; // Default Bitmap
+ mpGraphics = NULL; // current VirDev graphics
+ mpNext = NULL; // next VirDev
+ mnBitCount = 0; // BitCount (0 or 1)
+ mbGraphics = FALSE; // is Graphics used
+ mbForeignDC = FALSE; // uses a foreign DC instead of a bitmap
+}
+
+// -----------------------------------------------------------------------
+
+WinSalVirtualDevice::~WinSalVirtualDevice()
+{
+ // remove VirDev from list of virtual devices
+ SalData* pSalData = GetSalData();
+ WinSalVirtualDevice** ppVirDev = &pSalData->mpFirstVD;
+ for(; (*ppVirDev != this) && *ppVirDev; ppVirDev = &(*ppVirDev)->mpNext );
+ if( *ppVirDev )
+ *ppVirDev = mpNext;
+
+ // destroy saved DC
+ if( mpGraphics->mhDefPal )
+ SelectPalette( mpGraphics->mhDC, mpGraphics->mhDefPal, TRUE );
+ ImplSalDeInitGraphics( mpGraphics );
+ if( mhDefBmp )
+ SelectBitmap( mpGraphics->mhDC, mhDefBmp );
+ if( !mbForeignDC )
+ DeleteDC( mpGraphics->mhDC );
+ if( mhBmp )
+ DeleteBitmap( mhBmp );
+ delete mpGraphics;
+ mpGraphics = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+SalGraphics* WinSalVirtualDevice::GetGraphics()
+{
+ if ( mbGraphics )
+ return NULL;
+
+ if ( mpGraphics )
+ mbGraphics = TRUE;
+
+ return mpGraphics;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalVirtualDevice::ReleaseGraphics( SalGraphics* )
+{
+ mbGraphics = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL WinSalVirtualDevice::SetSize( long nDX, long nDY )
+{
+ if( mbForeignDC || !mhBmp )
+ return TRUE; // ???
+ else
+ {
+ HBITMAP hNewBmp = ImplCreateVirDevBitmap( mhDC, nDX, nDY,
+ mnBitCount );
+ if ( hNewBmp )
+ {
+ SelectBitmap( mhDC, hNewBmp );
+ DeleteBitmap( mhBmp );
+ mhBmp = hNewBmp;
+ return TRUE;
+ }
+ else
+ {
+ ImplWriteLastError( GetLastError(), "ImplCreateVirDevBitmap in SetSize" );
+ return FALSE;
+ }
+ }
+}
+
+void WinSalVirtualDevice::GetSize( long& rWidth, long& rHeight )
+{
+ rWidth = GetDeviceCaps( mhDC, HORZRES );
+ rHeight= GetDeviceCaps( mhDC, VERTRES );
+}
diff --git a/vcl/win/source/gdi/winlayout.cxx b/vcl/win/source/gdi/winlayout.cxx
new file mode 100644
index 000000000000..ba19f2255646
--- /dev/null
+++ b/vcl/win/source/gdi/winlayout.cxx
@@ -0,0 +1,3203 @@
+/*************************************************************************
+ *
+ * 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/svwin.h"
+
+#include "salgdi.h"
+#include "saldata.hxx"
+// for GetMirroredChar
+#include "sft.hxx"
+
+#include "vcl/sallayout.hxx"
+#include "vcl/svapp.hxx"
+
+#include "rtl/ustring.hxx"
+
+#include "osl/module.h"
+#include "osl/file.h"
+
+
+#include <cstdio>
+#include <malloc.h>
+#ifndef __MINGW32__
+#define alloca _alloca
+#endif
+
+#ifdef GCP_KERN_HACK
+ #include <algorithm>
+#endif // GCP_KERN_HACK
+
+
+#define USE_UNISCRIBE
+#ifdef USE_UNISCRIBE
+#include <Usp10.h>
+#include <ShLwApi.h>
+#include <winver.h>
+#endif // USE_UNISCRIBE
+
+#include <hash_map>
+#include <set>
+
+typedef std::hash_map<int,int> IntMap;
+typedef std::set<int> IntSet;
+
+// Graphite headers
+#ifdef ENABLE_GRAPHITE
+#include <i18npool/mslangid.hxx>
+#include <graphite/GrClient.h>
+#include <graphite/WinFont.h>
+#include <graphite/Segment.h>
+#include <vcl/graphite_layout.hxx>
+#include <vcl/graphite_cache.hxx>
+#include <vcl/graphite_features.hxx>
+#endif
+
+#define DROPPED_OUTGLYPH 0xFFFF
+
+using namespace rtl;
+
+// =======================================================================
+
+// win32 specific physical font instance
+class ImplWinFontEntry : public ImplFontEntry
+{
+public:
+ ImplWinFontEntry( ImplFontSelectData& );
+ ~ImplWinFontEntry();
+
+private:
+ // TODO: also add HFONT??? Watch out for issues with too many active fonts...
+
+#ifdef GCP_KERN_HACK
+public:
+ bool HasKernData() const;
+ void SetKernData( int, const KERNINGPAIR* );
+ int GetKerning( sal_Unicode, sal_Unicode ) const;
+private:
+ KERNINGPAIR* mpKerningPairs;
+ int mnKerningPairs;
+#endif // GCP_KERN_HACK
+
+#ifdef USE_UNISCRIBE
+public:
+ SCRIPT_CACHE& GetScriptCache() const
+ { return maScriptCache; }
+private:
+ mutable SCRIPT_CACHE maScriptCache;
+#endif // USE_UNISCRIBE
+
+public:
+ int GetCachedGlyphWidth( int nCharCode ) const;
+ void CacheGlyphWidth( int nCharCode, int nCharWidth );
+
+ bool InitKashidaHandling( HDC );
+ int GetMinKashidaWidth() const { return mnMinKashidaWidth; }
+ int GetMinKashidaGlyph() const { return mnMinKashidaGlyph; }
+
+private:
+ IntMap maWidthMap;
+ mutable int mnMinKashidaWidth;
+ mutable int mnMinKashidaGlyph;
+};
+
+// -----------------------------------------------------------------------
+
+inline void ImplWinFontEntry::CacheGlyphWidth( int nCharCode, int nCharWidth )
+{
+ maWidthMap[ nCharCode ] = nCharWidth;
+}
+
+inline int ImplWinFontEntry::GetCachedGlyphWidth( int nCharCode ) const
+{
+ IntMap::const_iterator it = maWidthMap.find( nCharCode );
+ if( it == maWidthMap.end() )
+ return -1;
+ return it->second;
+}
+
+// =======================================================================
+
+class WinLayout : public SalLayout
+{
+public:
+ WinLayout( HDC, const ImplWinFontData&, ImplWinFontEntry& );
+ virtual void InitFont() const;
+ void SetFontScale( float f ) { mfFontScale = f; }
+ float GetFontScale() const { return mfFontScale; }
+ HFONT DisableFontScaling( void) const;
+
+#ifdef USE_UNISCRIBE
+ SCRIPT_CACHE& GetScriptCache() const
+ { return mrWinFontEntry.GetScriptCache(); }
+#endif // USE_UNISCRIBE
+
+protected:
+ HDC mhDC; // WIN32 device handle
+ HFONT mhFont; // WIN32 font handle
+ int mnBaseAdv; // x-offset relative to Layout origin
+ float mfFontScale; // allows metrics emulation of huge font sizes
+
+ const ImplWinFontData& mrWinFontData;
+ ImplWinFontEntry& mrWinFontEntry;
+};
+
+// =======================================================================
+
+class SimpleWinLayout : public WinLayout
+{
+public:
+ SimpleWinLayout( HDC, BYTE nCharSet, const ImplWinFontData&, ImplWinFontEntry& );
+ virtual ~SimpleWinLayout();
+
+ virtual bool LayoutText( ImplLayoutArgs& );
+ virtual void AdjustLayout( ImplLayoutArgs& );
+ virtual void DrawText( SalGraphics& ) const;
+
+ virtual int GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, int&,
+ sal_Int32* pGlyphAdvances, int* pCharIndexes ) const;
+
+ virtual long FillDXArray( long* pDXArray ) const;
+ virtual int GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const;
+ virtual void GetCaretPositions( int nArraySize, long* pCaretXArray ) const;
+
+ // for glyph+font+script fallback
+ virtual void MoveGlyph( int nStart, long nNewXPos );
+ virtual void DropGlyph( int nStart );
+ virtual void Simplify( bool bIsBase );
+
+protected:
+ void Justify( long nNewWidth );
+ void ApplyDXArray( const ImplLayoutArgs& );
+
+private:
+ int mnGlyphCount;
+ int mnCharCount;
+ WCHAR* mpOutGlyphs;
+ int* mpGlyphAdvances; // if possible this is shared with mpGlyphAdvances[]
+ int* mpGlyphOrigAdvs;
+ int* mpCharWidths; // map rel char pos to char width
+ int* mpChars2Glyphs; // map rel char pos to abs glyph pos
+ int* mpGlyphs2Chars; // map abs glyph pos to abs char pos
+ bool* mpGlyphRTLFlags; // BiDi status for glyphs: true=>RTL
+ mutable long mnWidth;
+ bool mbDisableGlyphs;
+
+ int mnNotdefWidth;
+ BYTE mnCharSet;
+};
+
+// =======================================================================
+
+WinLayout::WinLayout( HDC hDC, const ImplWinFontData& rWFD, ImplWinFontEntry& rWFE )
+: mhDC( hDC ),
+ mhFont( (HFONT)::GetCurrentObject(hDC,OBJ_FONT) ),
+ mnBaseAdv( 0 ),
+ mfFontScale( 1.0 ),
+ mrWinFontData( rWFD ),
+ mrWinFontEntry( rWFE )
+{}
+
+// -----------------------------------------------------------------------
+
+void WinLayout::InitFont() const
+{
+ ::SelectObject( mhDC, mhFont );
+}
+
+// -----------------------------------------------------------------------
+
+// Using reasonably sized fonts to emulate huge fonts works around
+// a lot of problems in printer and display drivers. Huge fonts are
+// mostly used by high resolution reference devices which are never
+// painted to anyway. In the rare case that a huge font needs to be
+// displayed somewhere then the workaround doesn't help anymore.
+// If the drivers fail silently for huge fonts, so be it...
+HFONT WinLayout::DisableFontScaling() const
+{
+ if( mfFontScale == 1.0 )
+ return 0;
+
+ HFONT hHugeFont = 0;
+ if( aSalShlData.mbWNT )
+ {
+ LOGFONTW aLogFont;
+ ::GetObjectW( mhFont, sizeof(LOGFONTW), &aLogFont);
+ aLogFont.lfHeight = (LONG)(mfFontScale * aLogFont.lfHeight);
+ aLogFont.lfWidth = (LONG)(mfFontScale * aLogFont.lfWidth);
+ hHugeFont = ::CreateFontIndirectW( &aLogFont);
+ }
+ else
+ {
+ LOGFONTA aLogFont;
+ ::GetObjectA( mhFont, sizeof(LOGFONTA), &aLogFont);
+ aLogFont.lfHeight = (LONG)(mfFontScale * aLogFont.lfHeight);
+ aLogFont.lfWidth = (LONG)(mfFontScale * aLogFont.lfWidth);
+ hHugeFont = ::CreateFontIndirectA( &aLogFont);
+ }
+
+ if( !hHugeFont )
+ return 0;
+
+ return SelectFont( mhDC, hHugeFont );
+}
+
+// =======================================================================
+
+SimpleWinLayout::SimpleWinLayout( HDC hDC, BYTE nCharSet,
+ const ImplWinFontData& rWinFontData, ImplWinFontEntry& rWinFontEntry )
+: WinLayout( hDC, rWinFontData, rWinFontEntry ),
+ mnGlyphCount( 0 ),
+ mnCharCount( 0 ),
+ mpOutGlyphs( NULL ),
+ mpGlyphAdvances( NULL ),
+ mpGlyphOrigAdvs( NULL ),
+ mpCharWidths( NULL ),
+ mpChars2Glyphs( NULL ),
+ mpGlyphs2Chars( NULL ),
+ mpGlyphRTLFlags( NULL ),
+ mnWidth( 0 ),
+ mnNotdefWidth( -1 ),
+ mnCharSet( nCharSet ),
+ mbDisableGlyphs( false )
+{
+ mbDisableGlyphs = true;
+}
+
+// -----------------------------------------------------------------------
+
+SimpleWinLayout::~SimpleWinLayout()
+{
+ delete[] mpGlyphRTLFlags;
+ delete[] mpGlyphs2Chars;
+ delete[] mpChars2Glyphs;
+ if( mpCharWidths != mpGlyphAdvances )
+ delete[] mpCharWidths;
+ delete[] mpGlyphOrigAdvs;
+ delete[] mpGlyphAdvances;
+ delete[] mpOutGlyphs;
+}
+
+// -----------------------------------------------------------------------
+
+bool SimpleWinLayout::LayoutText( ImplLayoutArgs& rArgs )
+{
+ // prepare layout
+ // TODO: fix case when recyclying old SimpleWinLayout object
+ mbDisableGlyphs |= ((rArgs.mnFlags & SAL_LAYOUT_DISABLE_GLYPH_PROCESSING) != 0);
+ mnCharCount = rArgs.mnEndCharPos - rArgs.mnMinCharPos;
+
+ if( !mbDisableGlyphs )
+ {
+ // Win32 glyph APIs have serious problems with vertical layout
+ // => workaround is to use the unicode methods then
+ if( rArgs.mnFlags & SAL_LAYOUT_VERTICAL )
+ mbDisableGlyphs = true;
+ else
+ // use cached value from font face
+ mbDisableGlyphs = mrWinFontData.IsGlyphApiDisabled();
+ }
+
+ // TODO: use a cached value for bDisableAsianKern from upper layers
+ if( rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN )
+ {
+ TEXTMETRICA aTextMetricA;
+ if( ::GetTextMetricsA( mhDC, &aTextMetricA )
+ && !(aTextMetricA.tmPitchAndFamily & TMPF_FIXED_PITCH) && !(aTextMetricA.tmCharSet == 0x86) )
+ rArgs.mnFlags &= ~SAL_LAYOUT_KERNING_ASIAN;
+ }
+
+ // layout text
+ int i, j;
+
+ mnGlyphCount = 0;
+ bool bVertical = (rArgs.mnFlags & SAL_LAYOUT_VERTICAL) != 0;
+
+ // count the number of chars to process if no RTL run
+ rArgs.ResetPos();
+ bool bHasRTL = false;
+ while( rArgs.GetNextRun( &i, &j, &bHasRTL ) && !bHasRTL )
+ mnGlyphCount += j - i;
+
+ // if there are RTL runs we need room to remember individual BiDi flags
+ if( bHasRTL )
+ {
+ mpGlyphRTLFlags = new bool[ mnCharCount ];
+ for( i = 0; i < mnCharCount; ++i )
+ mpGlyphRTLFlags[i] = false;
+ }
+
+ // rewrite the logical string if needed to prepare for the API calls
+ const sal_Unicode* pBidiStr = rArgs.mpStr + rArgs.mnMinCharPos;
+ if( (mnGlyphCount != mnCharCount) || bVertical )
+ {
+ // we need to rewrite the pBidiStr when any of
+ // - BiDirectional layout
+ // - vertical layout
+ // - partial runs (e.g. with control chars or for glyph fallback)
+ // are involved
+ sal_Unicode* pRewrittenStr = (sal_Unicode*)alloca( mnCharCount * sizeof(sal_Unicode) );
+ pBidiStr = pRewrittenStr;
+
+ // note: glyph to char mapping is relative to first character
+ mpChars2Glyphs = new int[ mnCharCount ];
+ mpGlyphs2Chars = new int[ mnCharCount ];
+ for( i = 0; i < mnCharCount; ++i )
+ mpChars2Glyphs[i] = mpGlyphs2Chars[i] = -1;
+
+ mnGlyphCount = 0;
+ rArgs.ResetPos();
+ bool bIsRTL = false;
+ while( rArgs.GetNextRun( &i, &j, &bIsRTL ) )
+ {
+ do
+ {
+ // get the next leftmost character in this run
+ int nCharPos = bIsRTL ? --j : i++;
+ sal_UCS4 cChar = rArgs.mpStr[ nCharPos ];
+
+ // in the RTL case mirror the character and remember its RTL status
+ if( bIsRTL )
+ {
+ cChar = ::GetMirroredChar( cChar );
+ mpGlyphRTLFlags[ mnGlyphCount ] = true;
+ }
+
+ // for vertical writing use vertical alternatives
+ if( bVertical )
+ {
+ sal_UCS4 cVert = ::GetVerticalChar( cChar );
+ if( cVert )
+ cChar = cVert;
+ }
+
+ // rewrite the original string
+ // update the mappings between original and rewritten string
+ // TODO: support surrogates in rewritten strings
+ pRewrittenStr[ mnGlyphCount ] = static_cast<sal_Unicode>(cChar);
+ mpGlyphs2Chars[ mnGlyphCount ] = nCharPos;
+ mpChars2Glyphs[ nCharPos - rArgs.mnMinCharPos ] = mnGlyphCount;
+ ++mnGlyphCount;
+ } while( i < j );
+ }
+ }
+
+ mpOutGlyphs = new WCHAR[ mnGlyphCount ];
+ mpGlyphAdvances = new int[ mnGlyphCount ];
+
+ if( rArgs.mnFlags & (SAL_LAYOUT_KERNING_PAIRS | SAL_LAYOUT_KERNING_ASIAN) )
+ mpGlyphOrigAdvs = new int[ mnGlyphCount ];
+
+#ifndef GCP_KERN_HACK
+ DWORD nGcpOption = 0;
+ // enable kerning if requested
+ if( rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS )
+ nGcpOption |= GCP_USEKERNING;
+#endif // GCP_KERN_HACK
+
+ for( i = 0; i < mnGlyphCount; ++i )
+ mpOutGlyphs[i] = pBidiStr[ i ];
+ mnWidth = 0;
+ for( i = 0; i < mnGlyphCount; ++i )
+ {
+ // get the current UCS-4 code point, check for surrogate pairs
+ const WCHAR* pCodes = reinterpret_cast<LPCWSTR>(&pBidiStr[i]);
+ unsigned nCharCode = pCodes[0];
+ bool bSurrogate = ((nCharCode >= 0xD800) && (nCharCode <= 0xDFFF));
+ if( bSurrogate )
+ {
+ if( nCharCode >= 0xDC00 ) // this part of a surrogate pair was already processed
+ continue;
+ nCharCode = 0x10000 + ((pCodes[0] - 0xD800) << 10) + (pCodes[1] - 0xDC00);
+ }
+
+ // get the advance width for the current UCS-4 code point
+ int nGlyphWidth = mrWinFontEntry.GetCachedGlyphWidth( nCharCode );
+ if( nGlyphWidth == -1 )
+ {
+ ABC aABC;
+ SIZE aExtent;
+ if( ::GetTextExtentPoint32W( mhDC, &pCodes[0], bSurrogate ? 2 : 1, &aExtent) )
+ nGlyphWidth = aExtent.cx;
+ else if( ::GetCharABCWidthsW( mhDC, nCharCode, nCharCode, &aABC ) )
+ nGlyphWidth = aABC.abcA + aABC.abcB + aABC.abcC;
+ else if( !::GetCharWidth32W( mhDC, nCharCode, nCharCode, &nGlyphWidth )
+ && !::GetCharWidthW( mhDC, nCharCode, nCharCode, &nGlyphWidth ) )
+ nGlyphWidth = 0;
+ mrWinFontEntry.CacheGlyphWidth( nCharCode, nGlyphWidth );
+ }
+ mpGlyphAdvances[ i ] = nGlyphWidth;
+ mnWidth += nGlyphWidth;
+
+ // remaining codes of surrogate pair get a zero width
+ if( bSurrogate && ((i+1) < mnGlyphCount) )
+ mpGlyphAdvances[ i+1 ] = 0;
+
+ // check with the font face if glyph fallback is needed
+ if( mrWinFontData.HasChar( nCharCode ) )
+ continue;
+
+ // request glyph fallback at this position in the string
+ bool bRTL = mpGlyphRTLFlags ? mpGlyphRTLFlags[i] : false;
+ int nCharPos = mpGlyphs2Chars ? mpGlyphs2Chars[i]: i + rArgs.mnMinCharPos;
+ rArgs.NeedFallback( nCharPos, bRTL );
+ if( bSurrogate && ((nCharPos+1) < rArgs.mnLength) )
+ rArgs.NeedFallback( nCharPos+1, bRTL );
+
+ // replace the current glyph shape with the NotDef glyph shape
+ if( rArgs.mnFlags & SAL_LAYOUT_FOR_FALLBACK )
+ {
+ // when we already are layouting for glyph fallback
+ // then a new unresolved glyph is not interesting
+ mnNotdefWidth = 0;
+ mpOutGlyphs[i] = DROPPED_OUTGLYPH;
+ }
+ else
+ {
+ if( mnNotdefWidth < 0 )
+ {
+ // get the width of the NotDef glyph
+ SIZE aExtent;
+ WCHAR cNotDef = rArgs.mpStr[ nCharPos ];
+ mnNotdefWidth = 0;
+ if( ::GetTextExtentPoint32W( mhDC, &cNotDef, 1, &aExtent) )
+ mnNotdefWidth = aExtent.cx;
+ }
+ // use a better NotDef glyph
+ if( !mbDisableGlyphs && !bSurrogate )
+ mpOutGlyphs[i] = 0;
+ }
+ if( bSurrogate && ((i+1) < mnGlyphCount) )
+ mpOutGlyphs[i+1] = DROPPED_OUTGLYPH;
+
+ // adjust the current glyph width to the NotDef glyph width
+ mnWidth += mnNotdefWidth - mpGlyphAdvances[i];
+ mpGlyphAdvances[i] = mnNotdefWidth;
+ if( mpGlyphOrigAdvs )
+ mpGlyphOrigAdvs[i] = mnNotdefWidth;
+ }
+
+#ifdef GCP_KERN_HACK
+ // apply kerning if the layout engine has not yet done it
+ if( rArgs.mnFlags & (SAL_LAYOUT_KERNING_ASIAN|SAL_LAYOUT_KERNING_PAIRS) )
+ {
+#else // GCP_KERN_HACK
+ // apply just asian kerning
+ if( rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN )
+ {
+ if( !(rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS) )
+#endif // GCP_KERN_HACK
+ for( i = 0; i < mnGlyphCount; ++i )
+ mpGlyphOrigAdvs[i] = mpGlyphAdvances[i];
+
+ // #99658# also apply asian kerning on the substring border
+ int nLen = mnGlyphCount;
+ if( rArgs.mnMinCharPos + nLen < rArgs.mnLength )
+ ++nLen;
+ for( i = 1; i < nLen; ++i )
+ {
+#ifdef GCP_KERN_HACK
+ if( rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS )
+ {
+ int nKernAmount = mrWinFontEntry.GetKerning( pBidiStr[i-1], pBidiStr[i] );
+ mpGlyphAdvances[ i-1 ] += nKernAmount;
+ mnWidth += nKernAmount;
+ }
+ else if( rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN )
+#endif // GCP_KERN_HACK
+
+ if( ( (0x3000 == (0xFF00 & pBidiStr[i-1])) || (0x2010 == (0xFFF0 & pBidiStr[i-1])) || (0xFF00 == (0xFF00 & pBidiStr[i-1])))
+ && ( (0x3000 == (0xFF00 & pBidiStr[i])) || (0x2010 == (0xFFF0 & pBidiStr[i])) || (0xFF00 == (0xFF00 & pBidiStr[i])) ) )
+ {
+ long nKernFirst = +CalcAsianKerning( pBidiStr[i-1], true, bVertical );
+ long nKernNext = -CalcAsianKerning( pBidiStr[i], false, bVertical );
+
+ long nDelta = (nKernFirst < nKernNext) ? nKernFirst : nKernNext;
+ if( nDelta<0 && nKernFirst!=0 && nKernNext!=0 )
+ {
+ nDelta = (nDelta * mpGlyphAdvances[i-1] + 2) / 4;
+ mpGlyphAdvances[i-1] += nDelta;
+ mnWidth += nDelta;
+ }
+ }
+ }
+ }
+
+ // calculate virtual char widths
+ if( !mpGlyphs2Chars )
+ mpCharWidths = mpGlyphAdvances;
+ else
+ {
+ mpCharWidths = new int[ mnCharCount ];
+ for( i = 0; i < mnCharCount; ++i )
+ mpCharWidths[ i ] = 0;
+ for( i = 0; i < mnGlyphCount; ++i )
+ {
+ int j = mpGlyphs2Chars[ i ] - rArgs.mnMinCharPos;
+ if( j >= 0 )
+ mpCharWidths[ j ] += mpGlyphAdvances[ i ];
+ }
+ }
+
+ // scale layout metrics if needed
+ // TODO: does it make the code more simple if the metric scaling
+ // is moved to the methods that need metric scaling (e.g. FillDXArray())?
+ if( mfFontScale != 1.0 )
+ {
+ mnWidth = (long)(mnWidth * mfFontScale);
+ mnBaseAdv = (int)(mnBaseAdv * mfFontScale);
+ for( i = 0; i < mnCharCount; ++i )
+ mpCharWidths[i] = (int)(mpCharWidths[i] * mfFontScale);
+ if( mpGlyphAdvances != mpCharWidths )
+ for( i = 0; i < mnGlyphCount; ++i )
+ mpGlyphAdvances[i] = (int)(mpGlyphAdvances[i] * mfFontScale);
+ if( mpGlyphOrigAdvs && (mpGlyphOrigAdvs != mpGlyphAdvances) )
+ for( i = 0; i < mnGlyphCount; ++i )
+ mpGlyphOrigAdvs[i] = (int)(mpGlyphOrigAdvs[i] * mfFontScale);
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+int SimpleWinLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, int& nStart,
+ long* pGlyphAdvances, int* pCharIndexes ) const
+{
+ // return zero if no more glyph found
+ if( nStart >= mnGlyphCount )
+ return 0;
+
+ // calculate glyph position relative to layout base
+ // TODO: avoid for nStart!=0 case by reusing rPos
+ long nXOffset = mnBaseAdv;
+ for( int i = 0; i < nStart; ++i )
+ nXOffset += mpGlyphAdvances[ i ];
+
+ // calculate absolute position in pixel units
+ Point aRelativePos( nXOffset, 0 );
+ rPos = GetDrawPosition( aRelativePos );
+
+ int nCount = 0;
+ while( nCount < nLen )
+ {
+ // update return values {nGlyphIndex,nCharPos,nGlyphAdvance}
+ sal_GlyphId nGlyphIndex = mpOutGlyphs[ nStart ];
+ if( mbDisableGlyphs )
+ {
+ if( mnLayoutFlags & SAL_LAYOUT_VERTICAL )
+ {
+ const sal_UCS4 cChar = static_cast<sal_UCS4>(nGlyphIndex & GF_IDXMASK);
+ if( mrWinFontData.HasGSUBstitutions( mhDC )
+ && mrWinFontData.IsGSUBstituted( cChar ) )
+ nGlyphIndex |= GF_GSUB | GF_ROTL;
+ else
+ {
+ nGlyphIndex |= GetVerticalFlags( cChar );
+ if( (nGlyphIndex & GF_ROTMASK) == 0 )
+ nGlyphIndex |= GF_VERT;
+ }
+ }
+ nGlyphIndex |= GF_ISCHAR;
+ }
+ ++nCount;
+ *(pGlyphs++) = nGlyphIndex;
+ if( pGlyphAdvances )
+ *(pGlyphAdvances++) = mpGlyphAdvances[ nStart ];
+ if( pCharIndexes )
+ {
+ int nCharPos;
+ if( !mpGlyphs2Chars )
+ nCharPos = nStart + mnMinCharPos;
+ else
+ nCharPos = mpGlyphs2Chars[nStart];
+ *(pCharIndexes++) = nCharPos;
+ }
+
+ // stop at last glyph
+ if( ++nStart >= mnGlyphCount )
+ break;
+
+ // stop when next x-position is unexpected
+ if( !pGlyphAdvances && mpGlyphOrigAdvs )
+ if( mpGlyphAdvances[nStart-1] != mpGlyphOrigAdvs[nStart-1] )
+ break;
+ }
+
+ return nCount;
+}
+
+// -----------------------------------------------------------------------
+
+void SimpleWinLayout::DrawText( SalGraphics& rGraphics ) const
+{
+ if( mnGlyphCount <= 0 )
+ return;
+
+ WinSalGraphics& rWinGraphics = static_cast<WinSalGraphics&>(rGraphics);
+ HDC aHDC = rWinGraphics.mhDC;
+
+ HFONT hOrigFont = DisableFontScaling();
+
+ UINT mnDrawOptions = ETO_GLYPH_INDEX;
+ if( mbDisableGlyphs )
+ mnDrawOptions = 0;
+
+ Point aPos = GetDrawPosition( Point( mnBaseAdv, 0 ) );
+
+ // #108267#, limit the number of glyphs to avoid paint errors
+ UINT limitedGlyphCount = Min( 8192, mnGlyphCount );
+ if( mnDrawOptions || aSalShlData.mbWNT )
+ {
+ // #108267#, break up into glyph portions of a limited size required by Win32 API
+ const unsigned int maxGlyphCount = 8192;
+ UINT numGlyphPortions = mnGlyphCount / maxGlyphCount;
+ UINT remainingGlyphs = mnGlyphCount % maxGlyphCount;
+
+ if( numGlyphPortions )
+ {
+ // #108267#,#109387# break up string into smaller chunks
+ // the output positions will be updated by windows (SetTextAlign)
+ unsigned int i,n;
+ POINT oldPos;
+ UINT oldTa = ::GetTextAlign( aHDC );
+ ::SetTextAlign( aHDC, (oldTa & ~TA_NOUPDATECP) | TA_UPDATECP );
+ ::MoveToEx( aHDC, aPos.X(), aPos.Y(), &oldPos );
+ for( i=n=0; n<numGlyphPortions; n++, i+=maxGlyphCount )
+ ::ExtTextOutW( aHDC, 0, 0, mnDrawOptions, NULL,
+ mpOutGlyphs+i, maxGlyphCount, mpGlyphAdvances+i );
+ ::ExtTextOutW( aHDC, 0, 0, mnDrawOptions, NULL,
+ mpOutGlyphs+i, remainingGlyphs, mpGlyphAdvances+i );
+ ::MoveToEx( aHDC, oldPos.x, oldPos.y, (LPPOINT) NULL);
+ ::SetTextAlign( aHDC, oldTa );
+ }
+ else
+ ::ExtTextOutW( aHDC, aPos.X(), aPos.Y(), mnDrawOptions, NULL,
+ mpOutGlyphs, mnGlyphCount, mpGlyphAdvances );
+ }
+ else
+ {
+ // #108267#, On Win9x, we get paint errors when drawing huge strings, even when
+ // split into pieces (see above), seems to be a problem in the internal text clipping
+ // so we just cut off the string
+ if( !mpGlyphOrigAdvs )
+ ::ExtTextOutW( aHDC, aPos.X(), aPos.Y(), 0, NULL,
+ mpOutGlyphs, limitedGlyphCount, NULL );
+ else
+ {
+ // workaround for problem in #106259#
+ long nXPos = mnBaseAdv;
+ for( unsigned int i = 0; i < limitedGlyphCount; ++i )
+ {
+ ::ExtTextOutW( aHDC, aPos.X(), aPos.Y(), 0, NULL,
+ mpOutGlyphs+i, 1, NULL );
+ nXPos += mpGlyphAdvances[ i ];
+ aPos = GetDrawPosition( Point( nXPos, 0 ) );
+ }
+ }
+ }
+
+ if( hOrigFont )
+ DeleteFont( SelectFont( aHDC, hOrigFont ) );
+}
+
+// -----------------------------------------------------------------------
+
+long SimpleWinLayout::FillDXArray( long* pDXArray ) const
+{
+ if( !mnWidth )
+ {
+ long mnWidth = mnBaseAdv;
+ for( int i = 0; i < mnGlyphCount; ++i )
+ mnWidth += mpGlyphAdvances[ i ];
+ }
+
+ if( pDXArray != NULL )
+ {
+ for( int i = 0; i < mnCharCount; ++i )
+ pDXArray[ i ] = mpCharWidths[ i ];
+ }
+
+ return mnWidth;
+}
+
+// -----------------------------------------------------------------------
+
+int SimpleWinLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const
+// NOTE: the nFactor is used to prevent rounding errors for small nCharExtra values
+{
+ if( mnWidth )
+ if( (mnWidth * nFactor + mnCharCount * nCharExtra) <= nMaxWidth )
+ return STRING_LEN;
+
+ long nExtraWidth = mnBaseAdv * nFactor;
+ for( int n = 0; n < mnCharCount; ++n )
+ {
+ // skip unused characters
+ if( mpChars2Glyphs && (mpChars2Glyphs[n] < 0) )
+ continue;
+ // add char widths until max
+ nExtraWidth += mpCharWidths[ n ] * nFactor;
+ if( nExtraWidth >= nMaxWidth )
+ return (mnMinCharPos + n);
+ nExtraWidth += nCharExtra;
+ }
+
+ return STRING_LEN;
+}
+
+// -----------------------------------------------------------------------
+
+void SimpleWinLayout::GetCaretPositions( int nMaxIdx, long* pCaretXArray ) const
+{
+ long nXPos = mnBaseAdv;
+
+ if( !mpGlyphs2Chars )
+ {
+ for( int i = 0; i < nMaxIdx; i += 2 )
+ {
+ pCaretXArray[ i ] = nXPos;
+ nXPos += mpGlyphAdvances[ i>>1 ];
+ pCaretXArray[ i+1 ] = nXPos;
+ }
+ }
+ else
+ {
+ int i;
+ for( i = 0; i < nMaxIdx; ++i )
+ pCaretXArray[ i ] = -1;
+
+ // assign glyph positions to character positions
+ for( i = 0; i < mnGlyphCount; ++i )
+ {
+ int nCurrIdx = mpGlyphs2Chars[ i ] - mnMinCharPos;
+ long nXRight = nXPos + mpCharWidths[ nCurrIdx ];
+ nCurrIdx *= 2;
+ if( !(mpGlyphRTLFlags && mpGlyphRTLFlags[i]) )
+ {
+ // 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;
+ }
+ nXPos += mpGlyphAdvances[ i ];
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SimpleWinLayout::Justify( long nNewWidth )
+{
+ long nOldWidth = mnWidth;
+ mnWidth = nNewWidth;
+
+ if( mnGlyphCount <= 0 )
+ return;
+
+ if( nNewWidth == nOldWidth )
+ return;
+
+ // the rightmost glyph cannot be stretched
+ const int nRight = mnGlyphCount - 1;
+ nOldWidth -= mpGlyphAdvances[ nRight ];
+ nNewWidth -= mpGlyphAdvances[ nRight ];
+
+ // count stretchable glyphs
+ int nStretchable = 0, i;
+ for( i = 0; i < nRight; ++i )
+ if( mpGlyphAdvances[i] >= 0 )
+ ++nStretchable;
+
+ // stretch these glyphs
+ int nDiffWidth = nNewWidth - nOldWidth;
+ for( i = 0; (i < nRight) && (nStretchable > 0); ++i )
+ {
+ if( mpGlyphAdvances[i] <= 0 )
+ continue;
+ int nDeltaWidth = nDiffWidth / nStretchable;
+ mpGlyphAdvances[i] += nDeltaWidth;
+ --nStretchable;
+ nDiffWidth -= nDeltaWidth;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SimpleWinLayout::AdjustLayout( ImplLayoutArgs& rArgs )
+{
+ SalLayout::AdjustLayout( rArgs );
+
+ // adjust positions if requested
+ if( rArgs.mpDXArray )
+ ApplyDXArray( rArgs );
+ else if( rArgs.mnLayoutWidth )
+ Justify( rArgs.mnLayoutWidth );
+ else
+ return;
+
+ // recalculate virtual char widths if they were changed
+ if( mpCharWidths != mpGlyphAdvances )
+ {
+ int i;
+ if( !mpGlyphs2Chars )
+ {
+ // standard LTR case
+ for( i = 0; i < mnGlyphCount; ++i )
+ mpCharWidths[ i ] = mpGlyphAdvances[ i ];
+ }
+ else
+ {
+ // BiDi or complex case
+ for( i = 0; i < mnCharCount; ++i )
+ mpCharWidths[ i ] = 0;
+ for( i = 0; i < mnGlyphCount; ++i )
+ {
+ int j = mpGlyphs2Chars[ i ] - rArgs.mnMinCharPos;
+ if( j >= 0 )
+ mpCharWidths[ j ] += mpGlyphAdvances[ i ];
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SimpleWinLayout::ApplyDXArray( const ImplLayoutArgs& rArgs )
+{
+ // try to avoid disturbance of text flow for LSB rounding case;
+ const long* pDXArray = rArgs.mpDXArray;
+
+ int i = 0;
+ long nOldWidth = mnBaseAdv;
+ for(; i < mnCharCount; ++i )
+ {
+ int j = !mpChars2Glyphs ? i : mpChars2Glyphs[i];
+ if( j >= 0 )
+ {
+ nOldWidth += mpGlyphAdvances[ j ];
+ int nDiff = nOldWidth - pDXArray[ i ];
+
+ // disabled because of #104768#
+ // works great for static text, but problems when typing
+ // if( nDiff>+1 || nDiff<-1 )
+ // only bother with changing anything when something moved
+ if( nDiff != 0 )
+ break;
+ }
+ }
+ if( i >= mnCharCount )
+ return;
+
+ if( !mpGlyphOrigAdvs )
+ {
+ mpGlyphOrigAdvs = new int[ mnGlyphCount ];
+ for( i = 0; i < mnGlyphCount; ++i )
+ mpGlyphOrigAdvs[ i ] = mpGlyphAdvances[ i ];
+ }
+
+ mnWidth = mnBaseAdv;
+ for( i = 0; i < mnCharCount; ++i )
+ {
+ int j = !mpChars2Glyphs ? i : mpChars2Glyphs[i];
+ if( j >= 0 )
+ mpGlyphAdvances[j] = pDXArray[i] - mnWidth;
+ mnWidth = pDXArray[i];
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SimpleWinLayout::MoveGlyph( int nStart, long nNewXPos )
+{
+ if( nStart > mnGlyphCount )
+ return;
+
+ // calculate the current x-position of the requested glyph
+ // TODO: cache absolute positions
+ int nXPos = mnBaseAdv;
+ for( int i = 0; i < nStart; ++i )
+ nXPos += mpGlyphAdvances[i];
+
+ // calculate the difference to the current glyph position
+ int nDelta = nNewXPos - nXPos;
+
+ // adjust the width of the layout if it was already cached
+ if( mnWidth )
+ mnWidth += nDelta;
+
+ // depending on whether the requested glyph is leftmost in the layout
+ // adjust either the layout's or the requested glyph's relative position
+ if( nStart > 0 )
+ mpGlyphAdvances[ nStart-1 ] += nDelta;
+ else
+ mnBaseAdv += nDelta;
+}
+
+// -----------------------------------------------------------------------
+
+void SimpleWinLayout::DropGlyph( int nStart )
+{
+ mpOutGlyphs[ nStart ] = DROPPED_OUTGLYPH;
+}
+
+// -----------------------------------------------------------------------
+
+void SimpleWinLayout::Simplify( bool /*bIsBase*/ )
+{
+ // return early if no glyph has been dropped
+ int i = mnGlyphCount;
+ while( (--i >= 0) && (mpOutGlyphs[ i ] != DROPPED_OUTGLYPH) );
+ if( i < 0 )
+ return;
+
+ // convert the layout to a sparse layout if it is not already
+ if( !mpGlyphs2Chars )
+ {
+ mpGlyphs2Chars = new int[ mnGlyphCount ];
+ mpCharWidths = new int[ mnCharCount ];
+ // assertion: mnGlyphCount == mnCharCount
+ for( int k = 0; k < mnGlyphCount; ++k )
+ {
+ mpGlyphs2Chars[ k ] = mnMinCharPos + k;
+ mpCharWidths[ k ] = mpGlyphAdvances[ k ];
+ }
+ }
+
+ // remove dropped glyphs that are rightmost in the layout
+ for( i = mnGlyphCount; --i >= 0; )
+ {
+ if( mpOutGlyphs[ i ] != DROPPED_OUTGLYPH )
+ break;
+ if( mnWidth )
+ mnWidth -= mpGlyphAdvances[ i ];
+ int nRelCharPos = mpGlyphs2Chars[ i ] - mnMinCharPos;
+ if( nRelCharPos >= 0 )
+ mpCharWidths[ nRelCharPos ] = 0;
+ }
+ mnGlyphCount = i + 1;
+
+ // keep original glyph widths around
+ if( !mpGlyphOrigAdvs )
+ {
+ mpGlyphOrigAdvs = new int[ mnGlyphCount ];
+ for( int k = 0; k < mnGlyphCount; ++k )
+ mpGlyphOrigAdvs[ k ] = mpGlyphAdvances[ k ];
+ }
+
+ // remove dropped glyphs inside the layout
+ int nNewGC = 0;
+ for( i = 0; i < mnGlyphCount; ++i )
+ {
+ if( mpOutGlyphs[ i ] == DROPPED_OUTGLYPH )
+ {
+ // adjust relative position to last valid glyph
+ int nDroppedWidth = mpGlyphAdvances[ i ];
+ mpGlyphAdvances[ i ] = 0;
+ if( nNewGC > 0 )
+ mpGlyphAdvances[ nNewGC-1 ] += nDroppedWidth;
+ else
+ mnBaseAdv += nDroppedWidth;
+
+ // zero the virtual char width for the char that has a fallback
+ int nRelCharPos = mpGlyphs2Chars[ i ] - mnMinCharPos;
+ if( nRelCharPos >= 0 )
+ mpCharWidths[ nRelCharPos ] = 0;
+ }
+ else
+ {
+ if( nNewGC != i )
+ {
+ // rearrange the glyph array to get rid of the dropped glyph
+ mpOutGlyphs[ nNewGC ] = mpOutGlyphs[ i ];
+ mpGlyphAdvances[ nNewGC ] = mpGlyphAdvances[ i ];
+ mpGlyphOrigAdvs[ nNewGC ] = mpGlyphOrigAdvs[ i ];
+ mpGlyphs2Chars[ nNewGC ] = mpGlyphs2Chars[ i ];
+ }
+ ++nNewGC;
+ }
+ }
+
+ mnGlyphCount = nNewGC;
+ if( mnGlyphCount <= 0 )
+ mnWidth = mnBaseAdv = 0;
+}
+
+// =======================================================================
+
+#ifdef USE_UNISCRIBE
+
+struct VisualItem
+{
+public:
+ SCRIPT_ITEM* mpScriptItem;
+ int mnMinGlyphPos;
+ int mnEndGlyphPos;
+ int mnMinCharPos;
+ int mnEndCharPos;
+ //long mnPixelWidth;
+ int mnXOffset;
+ ABC maABCWidths;
+ bool mbHasKashidas;
+
+public:
+ bool IsEmpty() const { return (mnEndGlyphPos <= 0); }
+ bool IsRTL() const { return mpScriptItem->a.fRTL; }
+ bool HasKashidas() const { return mbHasKashidas; }
+};
+
+// -----------------------------------------------------------------------
+
+class UniscribeLayout : public WinLayout
+{
+public:
+ UniscribeLayout( HDC, const ImplWinFontData&, ImplWinFontEntry& );
+
+ virtual bool LayoutText( ImplLayoutArgs& );
+ virtual void AdjustLayout( ImplLayoutArgs& );
+ virtual void DrawText( SalGraphics& ) const;
+ virtual int GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, int&,
+ sal_Int32* pGlyphAdvances, int* pCharPosAry ) const;
+
+ virtual long FillDXArray( long* pDXArray ) const;
+ virtual int GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const;
+ virtual void GetCaretPositions( int nArraySize, long* pCaretXArray ) const;
+ virtual bool IsKashidaPosValid ( int nCharPos ) const;
+
+ // for glyph+font+script fallback
+ virtual void MoveGlyph( int nStart, long nNewXPos );
+ virtual void DropGlyph( int nStart );
+ virtual void Simplify( bool bIsBase );
+ virtual void DisableGlyphInjection( bool bDisable ) { mbDisableGlyphInjection = bDisable; }
+
+protected:
+ virtual ~UniscribeLayout();
+
+ void Justify( long nNewWidth );
+ void ApplyDXArray( const ImplLayoutArgs& );
+
+ bool GetItemSubrange( const VisualItem&,
+ int& rMinIndex, int& rEndIndex ) const;
+
+private:
+ // item specific info
+ SCRIPT_ITEM* mpScriptItems; // in logical order
+ VisualItem* mpVisualItems; // in visual order
+ int mnItemCount; // number of visual items
+
+ // string specific info
+ // everything is in logical order
+ int mnCharCapacity;
+ WORD* mpLogClusters; // map from absolute_char_pos to relative_glyph_pos
+ int* mpCharWidths; // map from absolute_char_pos to char_width
+ int mnSubStringMin; // char_pos of first char in context
+
+ // glyph specific info
+ // everything is in visual order
+ int mnGlyphCount;
+ int mnGlyphCapacity;
+ int* mpGlyphAdvances; // glyph advance width before justification
+ int* mpJustifications; // glyph advance width after justification
+ WORD* mpOutGlyphs; // glyphids in visual order
+ GOFFSET* mpGlyphOffsets; // glyph offsets to the "naive" layout
+ SCRIPT_VISATTR* mpVisualAttrs; // glyph visual attributes
+ mutable int* mpGlyphs2Chars; // map from absolute_glyph_pos to absolute_char_pos
+
+ // kashida stuff
+ void InitKashidaHandling();
+ void KashidaItemFix( int nMinGlyphPos, int nEndGlyphPos );
+ bool KashidaWordFix( int nMinGlyphPos, int nEndGlyphPos, int* pnCurrentPos );
+
+ int mnMinKashidaWidth;
+ int mnMinKashidaGlyph;
+ bool mbDisableGlyphInjection;
+};
+
+// -----------------------------------------------------------------------
+// dynamic loading of usp library
+
+static oslModule aUspModule = NULL;
+static bool bUspEnabled = true;
+
+static HRESULT ((WINAPI *pScriptIsComplex)( const WCHAR*, int, DWORD ));
+static HRESULT ((WINAPI *pScriptItemize)( const WCHAR*, int, int,
+ const SCRIPT_CONTROL*, const SCRIPT_STATE*, SCRIPT_ITEM*, int* ));
+static HRESULT ((WINAPI *pScriptShape)( HDC, SCRIPT_CACHE*, const WCHAR*,
+ int, int, SCRIPT_ANALYSIS*, WORD*, WORD*, SCRIPT_VISATTR*, int* ));
+static HRESULT ((WINAPI *pScriptPlace)( HDC, SCRIPT_CACHE*, const WORD*, int,
+ const SCRIPT_VISATTR*, SCRIPT_ANALYSIS*, int*, GOFFSET*, ABC* ));
+static HRESULT ((WINAPI *pScriptGetLogicalWidths)( const SCRIPT_ANALYSIS*,
+ int, int, const int*, const WORD*, const SCRIPT_VISATTR*, int* ));
+static HRESULT ((WINAPI *pScriptApplyLogicalWidth)( const int*, int, int, const WORD*,
+ const SCRIPT_VISATTR*, const int*, const SCRIPT_ANALYSIS*, ABC*, int* ));
+static HRESULT ((WINAPI *pScriptJustify)( const SCRIPT_VISATTR*,
+ const int*, int, int, int, int* ));
+static HRESULT ((WINAPI *pScriptTextOut)( const HDC, SCRIPT_CACHE*,
+ int, int, UINT, const RECT*, const SCRIPT_ANALYSIS*, const WCHAR*,
+ int, const WORD*, int, const int*, const int*, const GOFFSET* ));
+static HRESULT ((WINAPI *pScriptGetFontProperties)( HDC, SCRIPT_CACHE*, SCRIPT_FONTPROPERTIES* ));
+static HRESULT ((WINAPI *pScriptFreeCache)( SCRIPT_CACHE* ));
+
+static bool bManualCellAlign = true;
+
+// -----------------------------------------------------------------------
+
+static bool InitUSP()
+{
+ OUString aLibraryName( RTL_CONSTASCII_USTRINGPARAM( "usp10" ) );
+ aUspModule = osl_loadModule( aLibraryName.pData, SAL_LOADMODULE_DEFAULT );
+ if( !aUspModule )
+ return (bUspEnabled = false);
+
+ pScriptIsComplex = (HRESULT (WINAPI*)(const WCHAR*,int,DWORD))
+ osl_getAsciiFunctionSymbol( aUspModule, "ScriptIsComplex" );
+ bUspEnabled &= (NULL != pScriptIsComplex);
+
+ pScriptItemize = (HRESULT (WINAPI*)(const WCHAR*,int,int,
+ const SCRIPT_CONTROL*,const SCRIPT_STATE*,SCRIPT_ITEM*,int*))
+ osl_getAsciiFunctionSymbol( aUspModule, "ScriptItemize" );
+ bUspEnabled &= (NULL != pScriptItemize);
+
+ pScriptShape = (HRESULT (WINAPI*)(HDC,SCRIPT_CACHE*,const WCHAR*,
+ int,int,SCRIPT_ANALYSIS*,WORD*,WORD*,SCRIPT_VISATTR*,int*))
+ osl_getAsciiFunctionSymbol( aUspModule, "ScriptShape" );
+ bUspEnabled &= (NULL != pScriptShape);
+
+ pScriptPlace = (HRESULT (WINAPI*)(HDC, SCRIPT_CACHE*, const WORD*, int,
+ const SCRIPT_VISATTR*,SCRIPT_ANALYSIS*,int*,GOFFSET*,ABC*))
+ osl_getAsciiFunctionSymbol( aUspModule, "ScriptPlace" );
+ bUspEnabled &= (NULL != pScriptPlace);
+
+ pScriptGetLogicalWidths = (HRESULT (WINAPI*)(const SCRIPT_ANALYSIS*,
+ int,int,const int*,const WORD*,const SCRIPT_VISATTR*,int*))
+ osl_getAsciiFunctionSymbol( aUspModule, "ScriptGetLogicalWidths" );
+ bUspEnabled &= (NULL != pScriptGetLogicalWidths);
+
+ pScriptApplyLogicalWidth = (HRESULT (WINAPI*)(const int*,int,int,const WORD*,
+ const SCRIPT_VISATTR*,const int*,const SCRIPT_ANALYSIS*,ABC*,int*))
+ osl_getAsciiFunctionSymbol( aUspModule, "ScriptApplyLogicalWidth" );
+ bUspEnabled &= (NULL != pScriptApplyLogicalWidth);
+
+ pScriptJustify = (HRESULT (WINAPI*)(const SCRIPT_VISATTR*,const int*,
+ int,int,int,int*))
+ osl_getAsciiFunctionSymbol( aUspModule, "ScriptJustify" );
+ bUspEnabled &= (NULL != pScriptJustify);
+
+ pScriptGetFontProperties = (HRESULT (WINAPI*)( HDC,SCRIPT_CACHE*,SCRIPT_FONTPROPERTIES*))
+ osl_getAsciiFunctionSymbol( aUspModule, "ScriptGetFontProperties" );
+ bUspEnabled &= (NULL != pScriptGetFontProperties);
+
+ pScriptTextOut = (HRESULT (WINAPI*)(const HDC,SCRIPT_CACHE*,
+ int,int,UINT,const RECT*,const SCRIPT_ANALYSIS*,const WCHAR*,
+ int,const WORD*,int,const int*,const int*,const GOFFSET*))
+ osl_getAsciiFunctionSymbol( aUspModule, "ScriptTextOut" );
+ bUspEnabled &= (NULL != pScriptTextOut);
+
+ pScriptFreeCache = (HRESULT (WINAPI*)(SCRIPT_CACHE*))
+ osl_getAsciiFunctionSymbol( aUspModule, "ScriptFreeCache" );
+ bUspEnabled &= (NULL != pScriptFreeCache);
+
+ if( !bUspEnabled )
+ {
+ osl_unloadModule( aUspModule );
+ aUspModule = NULL;
+ }
+
+ // get the DLL version info
+ int nUspVersion = 0;
+ // TODO: there must be a simpler way to get the friggin version info from OSL?
+ rtl_uString* pModuleURL = NULL;
+ osl_getModuleURLFromAddress( (void*)pScriptIsComplex, &pModuleURL );
+ rtl_uString* pModuleFileName = NULL;
+ if( pModuleURL )
+ osl_getSystemPathFromFileURL( pModuleURL, &pModuleFileName );
+ const sal_Unicode* pModuleFileCStr = NULL;
+ if( pModuleFileName )
+ pModuleFileCStr = rtl_uString_getStr( pModuleFileName );
+ if( pModuleFileCStr )
+ {
+ DWORD nHandle;
+ DWORD nBufSize = ::GetFileVersionInfoSizeW( const_cast<LPWSTR>(reinterpret_cast<LPCWSTR>(pModuleFileCStr)), &nHandle );
+ char* pBuffer = (char*)alloca( nBufSize );
+ WIN_BOOL bRC = ::GetFileVersionInfoW( const_cast<LPWSTR>(reinterpret_cast<LPCWSTR>(pModuleFileCStr)), nHandle, nBufSize, pBuffer );
+ VS_FIXEDFILEINFO* pFixedFileInfo = NULL;
+ UINT nFixedFileSize = 0;
+ if( bRC )
+ ::VerQueryValueW( pBuffer, const_cast<LPWSTR>(L"\\"), (void**)&pFixedFileInfo, &nFixedFileSize );
+ if( pFixedFileInfo && pFixedFileInfo->dwSignature == 0xFEEF04BD )
+ nUspVersion = HIWORD(pFixedFileInfo->dwProductVersionMS) * 10000
+ + LOWORD(pFixedFileInfo->dwProductVersionMS);
+ }
+
+ // #i77976# USP>=1.0600 changed the need to manually align glyphs in their cells
+ if( nUspVersion >= 10600 )
+ bManualCellAlign = false;
+
+ return bUspEnabled;
+}
+
+// -----------------------------------------------------------------------
+
+UniscribeLayout::UniscribeLayout( HDC hDC,
+ const ImplWinFontData& rWinFontData, ImplWinFontEntry& rWinFontEntry )
+: WinLayout( hDC, rWinFontData, rWinFontEntry ),
+ mnItemCount( 0 ),
+ mpScriptItems( NULL ),
+ mpVisualItems( NULL ),
+ mpLogClusters( NULL ),
+ mpCharWidths( NULL ),
+ mnCharCapacity( 0 ),
+ mnSubStringMin( 0 ),
+ mnGlyphCapacity( 0 ),
+ mnGlyphCount( 0 ),
+ mpOutGlyphs( NULL ),
+ mpGlyphAdvances( NULL ),
+ mpJustifications( NULL ),
+ mpGlyphOffsets( NULL ),
+ mpVisualAttrs( NULL ),
+ mpGlyphs2Chars( NULL ),
+ mnMinKashidaGlyph( 0 ),
+ mbDisableGlyphInjection( false )
+{}
+
+// -----------------------------------------------------------------------
+
+UniscribeLayout::~UniscribeLayout()
+{
+ delete[] mpScriptItems;
+ delete[] mpVisualItems;
+ delete[] mpLogClusters;
+ delete[] mpCharWidths;
+ delete[] mpOutGlyphs;
+ delete[] mpGlyphAdvances;
+ delete[] mpJustifications;
+ delete[] mpGlyphOffsets;
+ delete[] mpVisualAttrs;
+ delete[] mpGlyphs2Chars;
+}
+
+// -----------------------------------------------------------------------
+
+bool UniscribeLayout::LayoutText( ImplLayoutArgs& rArgs )
+{
+ // for a base layout only the context glyphs have to be dropped
+ // => when the whole string is involved there is no extra context
+ typedef std::vector<int> TIntVector;
+ TIntVector aDropChars;
+ if( rArgs.mnFlags & SAL_LAYOUT_FOR_FALLBACK )
+ {
+ // calculate superfluous context char positions
+ aDropChars.push_back( 0 );
+ aDropChars.push_back( rArgs.mnLength );
+ int nMin, nEnd;
+ bool bRTL;
+ for( rArgs.ResetPos(); rArgs.GetNextRun( &nMin, &nEnd, &bRTL ); )
+ {
+ aDropChars.push_back( nMin );
+ aDropChars.push_back( nEnd );
+ }
+ // prepare aDropChars for binary search which will allow to
+ // not bother with visual items that will be dropped anyway
+ std::sort( aDropChars.begin(), aDropChars.end() );
+ }
+
+ // prepare layout
+ // TODO: fix case when recyclying old UniscribeLayout object
+ mnMinCharPos = rArgs.mnMinCharPos;
+ mnEndCharPos = rArgs.mnEndCharPos;
+
+ // determine script items from string
+
+ // prepare itemization
+ // TODO: try to avoid itemization since it costs a lot of performance
+ SCRIPT_STATE aScriptState = {0,false,false,false,false,false,false,false,false,0,0};
+ aScriptState.uBidiLevel = (0 != (rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL));
+ aScriptState.fOverrideDirection = (0 != (rArgs.mnFlags & SAL_LAYOUT_BIDI_STRONG));
+ aScriptState.fDigitSubstitute = (0 != (rArgs.mnFlags & SAL_LAYOUT_SUBSTITUTE_DIGITS));
+ aScriptState.fArabicNumContext = aScriptState.fDigitSubstitute & aScriptState.uBidiLevel;
+ DWORD nLangId = 0; // TODO: get language from font
+ SCRIPT_CONTROL aScriptControl = {nLangId,false,false,false,false,false,false,false,false,0};
+ aScriptControl.fNeutralOverride = aScriptState.fOverrideDirection;
+ aScriptControl.fContextDigits = (0 != (rArgs.mnFlags & SAL_LAYOUT_SUBSTITUTE_DIGITS));
+ // determine relevant substring and work only on it
+ // when Bidi status is unknown we need to look at the whole string though
+ mnSubStringMin = 0;
+ int nSubStringEnd = rArgs.mnLength;
+ if( aScriptState.fOverrideDirection )
+ {
+ // TODO: limit substring to portion limits
+ mnSubStringMin = rArgs.mnMinCharPos - 8;
+ if( mnSubStringMin < 0 )
+ mnSubStringMin = 0;
+ nSubStringEnd = rArgs.mnEndCharPos + 8;
+ if( nSubStringEnd > rArgs.mnLength )
+ nSubStringEnd = rArgs.mnLength;
+
+ }
+
+ // now itemize the substring with its context
+ for( int nItemCapacity = 16;; nItemCapacity *= 8 )
+ {
+ mpScriptItems = new SCRIPT_ITEM[ nItemCapacity ];
+ HRESULT nRC = (*pScriptItemize)(
+ reinterpret_cast<LPCWSTR>(rArgs.mpStr + mnSubStringMin), nSubStringEnd - mnSubStringMin,
+ nItemCapacity - 1, &aScriptControl, &aScriptState,
+ mpScriptItems, &mnItemCount );
+ if( !nRC ) // break loop when everything is correctly itemized
+ break;
+
+ // prepare bigger buffers for another itemization round
+ delete[] mpScriptItems;
+ mpScriptItems = NULL;
+ if( nRC != E_OUTOFMEMORY )
+ return false;
+ if( nItemCapacity > (nSubStringEnd - mnSubStringMin) + 16 )
+ return false;
+ }
+
+ // calculate the order of visual items
+ int nItem, i;
+
+ // adjust char positions by substring offset
+ for( nItem = 0; nItem <= mnItemCount; ++nItem )
+ mpScriptItems[ nItem ].iCharPos += mnSubStringMin;
+ // default visual item ordering
+ mpVisualItems = new VisualItem[ mnItemCount ];
+ for( nItem = 0; nItem < mnItemCount; ++nItem )
+ {
+ // initialize char specific item info
+ VisualItem& rVisualItem = mpVisualItems[ nItem ];
+ SCRIPT_ITEM* pScriptItem = &mpScriptItems[ nItem ];
+ rVisualItem.mpScriptItem = pScriptItem;
+ rVisualItem.mnMinCharPos = pScriptItem[0].iCharPos;
+ rVisualItem.mnEndCharPos = pScriptItem[1].iCharPos;
+ }
+
+ // reorder visual item order if needed
+ if( rArgs.mnFlags & SAL_LAYOUT_BIDI_STRONG )
+ {
+ // force RTL item ordering if requested
+ if( rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL )
+ {
+ VisualItem* pVI0 = &mpVisualItems[ 0 ];
+ VisualItem* pVI1 = &mpVisualItems[ mnItemCount ];
+ while( pVI0 < --pVI1 )
+ {
+ VisualItem aVtmp = *pVI0;
+ *(pVI0++) = *pVI1;
+ *pVI1 = aVtmp;
+ }
+ }
+ }
+ else if( mnItemCount > 1 )
+ {
+ // apply bidi algorithm's rule L2 on item level
+ // TODO: use faster L2 algorithm
+ int nMaxBidiLevel = 0;
+ VisualItem* pVI = &mpVisualItems[0];
+ VisualItem* const pVIend = pVI + mnItemCount;
+ for(; pVI < pVIend; ++pVI )
+ if( nMaxBidiLevel < pVI->mpScriptItem->a.s.uBidiLevel )
+ nMaxBidiLevel = pVI->mpScriptItem->a.s.uBidiLevel;
+
+ while( --nMaxBidiLevel >= 0 )
+ {
+ for( pVI = &mpVisualItems[0]; pVI < pVIend; )
+ {
+ // find item range that needs reordering
+ for(; pVI < pVIend; ++pVI )
+ if( nMaxBidiLevel < pVI->mpScriptItem->a.s.uBidiLevel )
+ break;
+ VisualItem* pVImin = pVI++;
+ for(; pVI < pVIend; ++pVI )
+ if( nMaxBidiLevel >= pVI->mpScriptItem->a.s.uBidiLevel )
+ break;
+ VisualItem* pVImax = pVI++;
+
+ // reverse order of items in this range
+ while( pVImin < --pVImax )
+ {
+ VisualItem aVtmp = *pVImin;
+ *(pVImin++) = *pVImax;
+ *pVImax = aVtmp;
+ }
+ }
+ }
+ }
+
+ // allocate arrays
+ // TODO: when reusing object reuse old allocations or delete them
+ // TODO: use only [nSubStringMin..nSubStringEnd) instead of [0..nSubStringEnd)
+ mnCharCapacity = nSubStringEnd;
+ mpLogClusters = new WORD[ mnCharCapacity ];
+ mpCharWidths = new int[ mnCharCapacity ];
+
+ mnGlyphCount = 0;
+ mnGlyphCapacity = 16 + 4 * (nSubStringEnd - mnSubStringMin); // worst case assumption
+ mpGlyphAdvances = new int[ mnGlyphCapacity ];
+ mpOutGlyphs = new WORD[ mnGlyphCapacity ];
+ mpGlyphOffsets = new GOFFSET[ mnGlyphCapacity ];
+ mpVisualAttrs = new SCRIPT_VISATTR[ mnGlyphCapacity ];
+
+ long nXOffset = 0;
+ for( int j = mnSubStringMin; j < nSubStringEnd; ++j )
+ mpCharWidths[j] = 0;
+
+ // layout script items
+ SCRIPT_CACHE& rScriptCache = GetScriptCache();
+ for( nItem = 0; nItem < mnItemCount; ++nItem )
+ {
+ VisualItem& rVisualItem = mpVisualItems[ nItem ];
+
+ // initialize glyph specific item info
+ rVisualItem.mnMinGlyphPos = mnGlyphCount;
+ rVisualItem.mnEndGlyphPos = 0;
+ rVisualItem.mnXOffset = nXOffset;
+ //rVisualItem.mnPixelWidth = 0;
+
+ // shortcut ignorable items
+ if( (rArgs.mnEndCharPos <= rVisualItem.mnMinCharPos)
+ || (rArgs.mnMinCharPos >= rVisualItem.mnEndCharPos) )
+ {
+ for( int i = rVisualItem.mnMinCharPos; i < rVisualItem.mnEndCharPos; ++i )
+ mpLogClusters[i] = sal::static_int_cast<WORD>(~0U);
+ continue;
+ }
+
+ // override bidi analysis if requested
+ if( rArgs.mnFlags & SAL_LAYOUT_BIDI_STRONG )
+ {
+ // FIXME: is this intended ?
+ rVisualItem.mpScriptItem->a.fRTL = (aScriptState.uBidiLevel & 1);
+ rVisualItem.mpScriptItem->a.s.uBidiLevel = aScriptState.uBidiLevel;
+ rVisualItem.mpScriptItem->a.s.fOverrideDirection = aScriptState.fOverrideDirection;
+ }
+
+ // convert the unicodes to glyphs
+ int nGlyphCount = 0;
+ int nCharCount = rVisualItem.mnEndCharPos - rVisualItem.mnMinCharPos;
+ HRESULT nRC = (*pScriptShape)( mhDC, &rScriptCache,
+ reinterpret_cast<LPCWSTR>(rArgs.mpStr + rVisualItem.mnMinCharPos),
+ nCharCount,
+ mnGlyphCapacity - rVisualItem.mnMinGlyphPos, // problem when >0xFFFF
+ &rVisualItem.mpScriptItem->a,
+ mpOutGlyphs + rVisualItem.mnMinGlyphPos,
+ mpLogClusters + rVisualItem.mnMinCharPos,
+ mpVisualAttrs + rVisualItem.mnMinGlyphPos,
+ &nGlyphCount );
+
+ // find and handle problems in the unicode to glyph conversion
+ if( nRC == USP_E_SCRIPT_NOT_IN_FONT )
+ {
+ // the whole visual item needs a fallback, but make sure that the next
+ // fallback request is limited to the characters in the original request
+ // => this is handled in ImplLayoutArgs::PrepareFallback()
+ rArgs.NeedFallback( rVisualItem.mnMinCharPos, rVisualItem.mnEndCharPos,
+ rVisualItem.IsRTL() );
+
+ // don't bother to do a default layout in a fallback level
+ if( 0 != (rArgs.mnFlags & SAL_LAYOUT_FOR_FALLBACK) )
+ continue;
+
+ // the primitive layout engine is good enough for the default layout
+ rVisualItem.mpScriptItem->a.eScript = SCRIPT_UNDEFINED;
+ nRC = (*pScriptShape)( mhDC, &rScriptCache,
+ reinterpret_cast<LPCWSTR>(rArgs.mpStr + rVisualItem.mnMinCharPos),
+ nCharCount,
+ mnGlyphCapacity - rVisualItem.mnMinGlyphPos,
+ &rVisualItem.mpScriptItem->a,
+ mpOutGlyphs + rVisualItem.mnMinGlyphPos,
+ mpLogClusters + rVisualItem.mnMinCharPos,
+ mpVisualAttrs + rVisualItem.mnMinGlyphPos,
+ &nGlyphCount );
+
+ if( nRC != 0 )
+ continue;
+
+#if 0 // keep the glyphs for now because they are better than nothing
+ // mark as NotDef glyphs
+ for( i = 0; i < nGlyphCount; ++i )
+ mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] = 0;
+#endif
+ }
+ else if( nRC != 0 )
+ // something undefined happened => give up for this visual item
+ continue;
+ else // if( nRC == 0 )
+ {
+ // check if there are any NotDef glyphs
+ for( i = 0; i < nGlyphCount; ++i )
+ if( 0 == mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] )
+ break;
+ if( i < nGlyphCount )
+ {
+ // clip charpos limits to the layout string without context
+ int nMinCharPos = rVisualItem.mnMinCharPos;
+ if( nMinCharPos < rArgs.mnMinCharPos )
+ nMinCharPos = rArgs.mnMinCharPos;
+ int nEndCharPos = rVisualItem.mnEndCharPos;
+ if( nEndCharPos > rArgs.mnEndCharPos )
+ nEndCharPos = rArgs.mnEndCharPos;
+ // request fallback for individual NotDef glyphs
+ do
+ {
+ // ignore non-NotDef glyphs
+ if( 0 != mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] )
+ continue;
+ mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] = DROPPED_OUTGLYPH;
+ // request fallback for the whole cell that resulted in a NotDef glyph
+ // TODO: optimize algorithm
+ const bool bRTL = rVisualItem.IsRTL();
+ if( !bRTL )
+ {
+ // request fallback for the left-to-right cell
+ for( int c = nMinCharPos; c < nEndCharPos; ++c )
+ {
+ if( mpLogClusters[ c ] == i )
+ {
+ // --> HDU/FME 2005-10-25 #i55716# skip WORDJOINER
+ if( rArgs.mpStr[ c ] == 0x2060 )
+ mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] = 1;
+ else
+ // <--
+ rArgs.NeedFallback( c, false );
+ }
+ }
+ }
+ else
+ {
+ // request fallback for the right to left cell
+ for( int c = nEndCharPos; --c >= nMinCharPos; )
+ {
+ if( mpLogClusters[ c ] == i )
+ {
+ // --> HDU/FME 2005-10-25 #i55716# skip WORDJOINER
+ if( rArgs.mpStr[ c ] == 0x2060 )
+ mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] = 1;
+ else
+ // <--
+ rArgs.NeedFallback( c, true );
+ }
+ }
+ }
+ } while( ++i < nGlyphCount );
+ }
+ }
+
+ // now place the glyphs
+ nRC = (*pScriptPlace)( mhDC, &rScriptCache,
+ mpOutGlyphs + rVisualItem.mnMinGlyphPos,
+ nGlyphCount,
+ mpVisualAttrs + rVisualItem.mnMinGlyphPos,
+ &rVisualItem.mpScriptItem->a,
+ mpGlyphAdvances + rVisualItem.mnMinGlyphPos,
+ mpGlyphOffsets + rVisualItem.mnMinGlyphPos,
+ &rVisualItem.maABCWidths );
+
+ if( nRC != 0 )
+ continue;
+
+ // calculate the logical char widths from the glyph layout
+ nRC = (*pScriptGetLogicalWidths)(
+ &rVisualItem.mpScriptItem->a,
+ nCharCount, nGlyphCount,
+ mpGlyphAdvances + rVisualItem.mnMinGlyphPos,
+ mpLogClusters + rVisualItem.mnMinCharPos,
+ mpVisualAttrs + rVisualItem.mnMinGlyphPos,
+ mpCharWidths + rVisualItem.mnMinCharPos );
+
+ // update the glyph counters
+ mnGlyphCount += nGlyphCount;
+ rVisualItem.mnEndGlyphPos = mnGlyphCount;
+
+ // update nXOffset
+ int nEndGlyphPos;
+ if( GetItemSubrange( rVisualItem, i, nEndGlyphPos ) )
+ for(; i < nEndGlyphPos; ++i )
+ nXOffset += mpGlyphAdvances[ i ];
+
+ // TODO: shrink glyphpos limits to match charpos/fallback limits
+ //pVI->mnMinGlyphPos = nMinGlyphPos;
+ //pVI->mnEndGlyphPos = nEndGlyphPos;
+
+ // drop the superfluous context glyphs
+ TIntVector::const_iterator it = aDropChars.begin();
+ while( it != aDropChars.end() )
+ {
+ // find matching "drop range"
+ int nMinDropPos = *(it++); // begin of drop range
+ if( nMinDropPos >= rVisualItem.mnEndCharPos )
+ break;
+ int nEndDropPos = *(it++); // end of drop range
+ if( nEndDropPos <= rVisualItem.mnMinCharPos )
+ continue;
+ // clip "drop range" to visual item's char range
+ if( nMinDropPos <= rVisualItem.mnMinCharPos )
+ {
+ nMinDropPos = rVisualItem.mnMinCharPos;
+ // drop the whole visual item if possible
+ if( nEndDropPos >= rVisualItem.mnEndCharPos )
+ {
+ rVisualItem.mnEndGlyphPos = 0;
+ break;
+ }
+ }
+ if( nEndDropPos > rVisualItem.mnEndCharPos )
+ nEndDropPos = rVisualItem.mnEndCharPos;
+
+ // drop the glyphs which correspond to the charpos range
+ // drop the corresponding glyphs in the cluster
+ for( int c = nMinDropPos; c < nEndDropPos; ++c )
+ {
+ int nGlyphPos = mpLogClusters[c] + rVisualItem.mnMinGlyphPos;
+ // no need to bother when the cluster was already dropped
+ if( mpOutGlyphs[ nGlyphPos ] != DROPPED_OUTGLYPH )
+ {
+ for(;;)
+ {
+ mpOutGlyphs[ nGlyphPos ] = DROPPED_OUTGLYPH;
+ // until the end of visual item
+ if( ++nGlyphPos >= rVisualItem.mnEndGlyphPos )
+ break;
+ // until the next cluster start
+ if( mpVisualAttrs[ nGlyphPos ].fClusterStart )
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // scale layout metrics if needed
+ // TODO: does it make the code more simple if the metric scaling
+ // is moved to the methods that need metric scaling (e.g. FillDXArray())?
+ if( mfFontScale != 1.0 )
+ {
+ mnBaseAdv = (int)((double)mnBaseAdv*mfFontScale);
+
+ for( i = 0; i < mnItemCount; ++i )
+ mpVisualItems[i].mnXOffset = (int)((double)mpVisualItems[i].mnXOffset*mfFontScale);
+
+ mnBaseAdv = (int)((double)mnBaseAdv*mfFontScale);
+ for( i = 0; i < mnGlyphCount; ++i )
+ {
+ mpGlyphAdvances[i] = (int)(mpGlyphAdvances[i] * mfFontScale);
+ mpGlyphOffsets[i].du = (LONG)(mpGlyphOffsets[i].du * mfFontScale);
+ mpGlyphOffsets[i].dv = (LONG)(mpGlyphOffsets[i].dv * mfFontScale);
+ // mpJustifications are still NULL
+ }
+
+ for( i = mnSubStringMin; i < nSubStringEnd; ++i )
+ mpCharWidths[i] = (int)(mpCharWidths[i] * mfFontScale);
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+// calculate the range of relevant glyphs for this visual item
+bool UniscribeLayout::GetItemSubrange( const VisualItem& rVisualItem,
+ int& rMinGlyphPos, int& rEndGlyphPos ) const
+{
+ // return early when nothing of interest in this item
+ if( rVisualItem.IsEmpty()
+ || (rVisualItem.mnEndCharPos <= mnMinCharPos)
+ || (mnEndCharPos <= rVisualItem.mnMinCharPos) )
+ return false;
+
+ // default: subrange is complete range
+ rMinGlyphPos = rVisualItem.mnMinGlyphPos;
+ rEndGlyphPos = rVisualItem.mnEndGlyphPos;
+
+ // return early when the whole item is of interest
+ if( (mnMinCharPos <= rVisualItem.mnMinCharPos)
+ && (rVisualItem.mnEndCharPos <= mnEndCharPos ) )
+ return true;
+
+ // get glyph range from char range by looking at cluster boundries
+ // TODO: optimize for case that LTR/RTL correspond to monotonous glyph indexes
+ rMinGlyphPos = rVisualItem.mnEndGlyphPos;
+ int nMaxGlyphPos = 0;
+
+ int i = mnMinCharPos;
+ if( i < rVisualItem.mnMinCharPos )
+ i = rVisualItem.mnMinCharPos;
+ int nCharPosLimit = rVisualItem.mnEndCharPos;
+ if( nCharPosLimit > mnEndCharPos )
+ nCharPosLimit = mnEndCharPos;
+ for(; i < nCharPosLimit; ++i )
+ {
+ int n = mpLogClusters[ i ] + rVisualItem.mnMinGlyphPos;
+ if( rMinGlyphPos > n )
+ rMinGlyphPos = n;
+ if( nMaxGlyphPos < n )
+ nMaxGlyphPos = n;
+ }
+ if (nMaxGlyphPos > rVisualItem.mnEndGlyphPos)
+ nMaxGlyphPos = rVisualItem.mnEndGlyphPos - 1;
+
+ // extend the glyph range to account for all glyphs in referenced clusters
+ if( !rVisualItem.IsRTL() ) // LTR-item
+ {
+ // extend to rightmost glyph of rightmost referenced cluster
+ for( i = nMaxGlyphPos; ++i < rVisualItem.mnEndGlyphPos; nMaxGlyphPos = i )
+ if( mpVisualAttrs[i].fClusterStart )
+ break;
+ }
+ else // RTL-item
+ {
+ // extend to leftmost glyph of leftmost referenced cluster
+ for( i = rMinGlyphPos; --i >= rVisualItem.mnMinGlyphPos; rMinGlyphPos = i )
+ if( mpVisualAttrs[i].fClusterStart )
+ break;
+ }
+ rEndGlyphPos = nMaxGlyphPos + 1;
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+int UniscribeLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos,
+ int& nStartx8, sal_Int32* pGlyphAdvances, int* pCharPosAry ) const
+{
+ // HACK to allow fake-glyph insertion (e.g. for kashidas)
+ // TODO: use iterator idiom instead of GetNextGlyphs(...)
+ // TODO: else make sure that the limit for glyph injection is sufficient (currently 256)
+ int nSubIter = nStartx8 & 0xff;
+ int nStart = nStartx8 >> 8;
+
+ // check the glyph iterator
+ if( nStart > mnGlyphCount ) // nStart>MAX means no more glyphs
+ return 0;
+
+ // find the visual item for the nStart glyph position
+ int nItem = 0;
+ const VisualItem* pVI = mpVisualItems;
+ if( nStart <= 0 ) // nStart<=0 requests the first visible glyph
+ {
+ // find first visible item
+ for(; nItem < mnItemCount; ++nItem, ++pVI )
+ if( !pVI->IsEmpty() )
+ break;
+ // it is possible that there are glyphs but no valid visual item
+ // TODO: get rid of these visual items more early
+ if( nItem < mnItemCount )
+ nStart = pVI->mnMinGlyphPos;
+ }
+ else //if( nStart > 0 ) // nStart>0 means absolute glyph pos +1
+ {
+ --nStart;
+
+ // find matching item
+ for(; nItem < mnItemCount; ++nItem, ++pVI )
+ if( (nStart >= pVI->mnMinGlyphPos)
+ && (nStart < pVI->mnEndGlyphPos) )
+ break;
+ }
+
+ // after the last visual item there are no more glyphs
+ if( (nItem >= mnItemCount) || (nStart < 0) )
+ {
+ nStartx8 = (mnGlyphCount + 1) << 8;
+ return 0;
+ }
+
+ // calculate the first glyph in the next visual item
+ int nNextItemStart = mnGlyphCount;
+ while( ++nItem < mnItemCount )
+ {
+ if( mpVisualItems[nItem].IsEmpty() )
+ continue;
+ nNextItemStart = mpVisualItems[nItem].mnMinGlyphPos;
+ break;
+ }
+
+ // get the range of relevant glyphs in this visual item
+ int nMinGlyphPos, nEndGlyphPos;
+ bool bRC = GetItemSubrange( *pVI, nMinGlyphPos, nEndGlyphPos );
+ DBG_ASSERT( bRC, "USPLayout::GNG GISR() returned false" );
+ if( !bRC )
+ {
+ nStartx8 = (mnGlyphCount + 1) << 8;
+ return 0;
+ }
+
+ // make sure nStart is inside the range of relevant glyphs
+ if( nStart < nMinGlyphPos )
+ nStart = nMinGlyphPos;
+
+ // calculate the start glyph xoffset relative to layout's base position,
+ // advance to next visual glyph position by using adjusted glyph widths
+ // TODO: speed up the calculation for nStart!=0 case by using rPos as a cache
+ long nXOffset = pVI->mnXOffset;
+ const int* pGlyphWidths = mpJustifications ? mpJustifications : mpGlyphAdvances;
+ for( int i = nMinGlyphPos; i < nStart; ++i )
+ nXOffset += pGlyphWidths[ i ];
+
+ // adjust the nXOffset relative to glyph cluster start
+ int c = mnMinCharPos;
+ if( !pVI->IsRTL() ) // LTR-case
+ {
+ // LTR case: subtract the remainder of the cell from xoffset
+ int nTmpIndex = mpLogClusters[c];
+ while( (--c >= pVI->mnMinCharPos)
+ && (nTmpIndex == mpLogClusters[c]) )
+ nXOffset -= mpCharWidths[c];
+ }
+ else // RTL-case
+ {
+ // RTL case: add the remainder of the cell from xoffset
+ int nTmpIndex = mpLogClusters[ pVI->mnEndCharPos - 1 ];
+ while( (--c >= pVI->mnMinCharPos)
+ && (nTmpIndex == mpLogClusters[c]) )
+ nXOffset += mpCharWidths[c];
+
+ // adjust the xoffset if justified glyphs are not positioned at their justified positions yet
+ if( mpJustifications && !bManualCellAlign )
+ nXOffset += mpJustifications[ nStart ] - mpGlyphAdvances[ nStart ];
+ }
+
+ // create mpGlyphs2Chars[] if it is needed later
+ if( pCharPosAry && !mpGlyphs2Chars )
+ {
+ // create and reset the new array
+ mpGlyphs2Chars = new int[ mnGlyphCapacity ];
+ for( int i = 0; i < mnGlyphCount; ++i )
+ mpGlyphs2Chars[i] = -1;
+ // calculate the char->glyph mapping
+ for( nItem = 0; nItem < mnItemCount; ++nItem )
+ {
+ // ignore invisible visual items
+ const VisualItem& rVI = mpVisualItems[ nItem ];
+ if( rVI.IsEmpty() )
+ continue;
+ // calculate the mapping by using mpLogClusters[]
+ // mpGlyphs2Chars[] should obey the logical order
+ // => reversing the loop does this by overwriting higher logicals
+ for( c = rVI.mnEndCharPos; --c >= rVI.mnMinCharPos; )
+ {
+ int i = mpLogClusters[c] + rVI.mnMinGlyphPos;
+ mpGlyphs2Chars[i] = c;
+ }
+ }
+ }
+
+ // calculate the absolute position of the first result glyph in pixel units
+ const GOFFSET aGOffset = mpGlyphOffsets[ nStart ];
+ Point aRelativePos( nXOffset + aGOffset.du, -aGOffset.dv );
+ rPos = GetDrawPosition( aRelativePos );
+
+ // fill the result arrays
+ int nCount = 0;
+ while( nCount < nLen )
+ {
+ // prepare return values
+ sal_GlyphId aGlyphId = mpOutGlyphs[ nStart ];
+ int nGlyphWidth = pGlyphWidths[ nStart ];
+ int nCharPos = -1; // no need to determine charpos
+ if( mpGlyphs2Chars ) // unless explicitly requested+provided
+ nCharPos = mpGlyphs2Chars[ nStart ];
+
+ // inject kashida glyphs if needed
+ if( !mbDisableGlyphInjection
+ && mpJustifications
+ && mnMinKashidaWidth
+ && mpVisualAttrs[nStart].uJustification >= SCRIPT_JUSTIFY_ARABIC_NORMAL )
+ {
+ // prepare draw position adjustment
+ int nExtraOfs = (nSubIter++) * mnMinKashidaWidth;
+ // calculate space available for the injected glyphs
+ nGlyphWidth = mpGlyphAdvances[ nStart ];
+ const int nExtraWidth = mpJustifications[ nStart ] - nGlyphWidth;
+ const int nToFillWidth = nExtraWidth - nExtraOfs;
+ if( (4*nToFillWidth >= mnMinKashidaWidth) // prevent glyph-injection if there is no room
+ || ((nSubIter > 1) && (nToFillWidth > 0)) ) // unless they can overlap with others
+ {
+ // handle if there is not sufficient room for a full glyph
+ if( nToFillWidth < mnMinKashidaWidth )
+ {
+ // overlap it with the previously injected glyph if possible
+ int nOverlap = mnMinKashidaWidth - nToFillWidth;
+ // else overlap it with both neighboring glyphs
+ if( nSubIter <= 1 )
+ nOverlap /= 2;
+ nExtraOfs -= nOverlap;
+ }
+ nGlyphWidth = mnMinKashidaWidth;
+ aGlyphId = mnMinKashidaGlyph;
+ nCharPos = -1;
+ }
+ else
+ {
+ nExtraOfs += nToFillWidth; // at right of cell
+ nSubIter = 0; // done with glyph injection
+ }
+ if( !bManualCellAlign )
+ nExtraOfs -= nExtraWidth; // adjust for right-aligned cells
+
+ // adjust the draw position for the injected-glyphs case
+ if( nExtraOfs )
+ {
+ aRelativePos.X() += nExtraOfs;
+ rPos = GetDrawPosition( aRelativePos );
+ }
+ }
+
+ // update return values
+ *(pGlyphs++) = aGlyphId;
+ if( pGlyphAdvances )
+ *(pGlyphAdvances++) = nGlyphWidth;
+ if( pCharPosAry )
+ *(pCharPosAry++) = nCharPos;
+
+ // increment counter of returned glyphs
+ ++nCount;
+
+ // reduce code complexity by returning early in glyph-injection case
+ if( nSubIter != 0 )
+ break;
+
+ // stop after the last visible glyph in this visual item
+ if( ++nStart >= nEndGlyphPos )
+ {
+ nStart = nNextItemStart;
+ break;
+ }
+
+ // RTL-justified glyph positioning is not easy
+ // simplify the code by just returning only one glyph at a time
+ if( mpJustifications && pVI->IsRTL() )
+ break;
+
+ // stop when the x-position of the next glyph is unexpected
+ if( !pGlyphAdvances )
+ if( (mpGlyphOffsets && (mpGlyphOffsets[nStart].du != aGOffset.du) )
+ || (mpJustifications && (mpJustifications[nStart] != mpGlyphAdvances[nStart]) ) )
+ break;
+
+ // stop when the y-position of the next glyph is unexpected
+ if( mpGlyphOffsets && (mpGlyphOffsets[nStart].dv != aGOffset.dv) )
+ break;
+ }
+
+ ++nStart;
+ nStartx8 = (nStart << 8) + nSubIter;
+ return nCount;
+}
+
+// -----------------------------------------------------------------------
+
+void UniscribeLayout::MoveGlyph( int nStartx8, long nNewXPos )
+{
+ DBG_ASSERT( !(nStartx8 & 0xff), "USP::MoveGlyph(): glyph injection not disabled!" );
+ int nStart = nStartx8 >> 8;
+ if( nStart > mnGlyphCount )
+ return;
+
+ VisualItem* pVI = mpVisualItems;
+ int nMinGlyphPos = 0, nEndGlyphPos;
+ if( nStart == 0 ) // nStart==0 for first visible glyph
+ {
+ for( int i = mnItemCount; --i >= 0; ++pVI )
+ if( GetItemSubrange( *pVI, nMinGlyphPos, nEndGlyphPos ) )
+ break;
+ nStart = nMinGlyphPos;
+ DBG_ASSERT( nStart <= mnGlyphCount, "USPLayout::MoveG overflow" );
+ }
+ else //if( nStart > 0 ) // nStart>0 means absolute_glyphpos+1
+ {
+ --nStart;
+ for( int i = mnItemCount; --i >= 0; ++pVI )
+ if( (nStart >= pVI->mnMinGlyphPos) && (nStart < pVI->mnEndGlyphPos) )
+ break;
+ bool bRC = GetItemSubrange( *pVI, nMinGlyphPos, nEndGlyphPos );
+ (void)bRC; // avoid var-not-used warning
+ DBG_ASSERT( bRC, "USPLayout::MoveG GISR() returned false" );
+ }
+
+ long nDelta = nNewXPos - pVI->mnXOffset;
+ if( nStart > nMinGlyphPos )
+ {
+ // move the glyph by expanding its left glyph but ignore dropped glyphs
+ int i, nLastUndropped = nMinGlyphPos - 1;
+ for( i = nMinGlyphPos; i < nStart; ++i )
+ {
+ if (mpOutGlyphs[i] != DROPPED_OUTGLYPH)
+ {
+ nDelta -= (mpJustifications)? mpJustifications[ i ] : mpGlyphAdvances[ i ];
+ nLastUndropped = i;
+ }
+ }
+ if (nLastUndropped >= nMinGlyphPos)
+ {
+ mpGlyphAdvances[ nLastUndropped ] += nDelta;
+ if (mpJustifications) mpJustifications[ nLastUndropped ] += nDelta;
+ }
+ else
+ {
+ pVI->mnXOffset += nDelta;
+ }
+ }
+ else
+ {
+ // move the visual item by having an offset
+ pVI->mnXOffset += nDelta;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void UniscribeLayout::DropGlyph( int nStartx8 )
+{
+ DBG_ASSERT( !(nStartx8 & 0xff), "USP::DropGlyph(): glyph injection not disabled!" );
+ int nStart = nStartx8 >> 8;
+ DBG_ASSERT( nStart<=mnGlyphCount, "USPLayout::MoveG nStart overflow" );
+
+ if( nStart > 0 ) // nStart>0 means absolute glyph pos + 1
+ --nStart;
+ else // nStart<=0 for first visible glyph
+ {
+ VisualItem* pVI = mpVisualItems;
+ for( int i = mnItemCount, nDummy; --i >= 0; ++pVI )
+ if( GetItemSubrange( *pVI, nStart, nDummy ) )
+ break;
+ DBG_ASSERT( nStart <= mnGlyphCount, "USPLayout::DropG overflow" );
+ int nOffset = 0;
+ int j = pVI->mnMinGlyphPos;
+ while (mpOutGlyphs[j] == DROPPED_OUTGLYPH) j++;
+ if (j == nStart)
+ {
+ pVI->mnXOffset += ((mpJustifications)? mpJustifications[nStart] : mpGlyphAdvances[nStart]);
+ }
+ }
+
+ mpOutGlyphs[ nStart ] = DROPPED_OUTGLYPH;
+}
+
+// -----------------------------------------------------------------------
+
+void UniscribeLayout::Simplify( bool /*bIsBase*/ )
+{
+ static const WCHAR cDroppedGlyph = DROPPED_OUTGLYPH;
+ int i;
+ // if there are no dropped glyphs don't bother
+ for( i = 0; i < mnGlyphCount; ++i )
+ if( mpOutGlyphs[ i ] == cDroppedGlyph )
+ break;
+ if( i >= mnGlyphCount )
+ return;
+
+ // prepare for sparse layout
+ // => make sure mpGlyphs2Chars[] exists
+ if( !mpGlyphs2Chars )
+ {
+ mpGlyphs2Chars = new int[ mnGlyphCapacity ];
+ for( i = 0; i < mnGlyphCount; ++i )
+ mpGlyphs2Chars[ i ] = -1;
+ for( int nItem = 0; nItem < mnItemCount; ++nItem )
+ {
+ // skip invisible items
+ VisualItem& rVI = mpVisualItems[ nItem ];
+ if( rVI.IsEmpty() )
+ continue;
+ for( i = rVI.mnEndCharPos; --i >= rVI.mnMinCharPos; )
+ {
+ int j = mpLogClusters[ i ] + rVI.mnMinGlyphPos;
+ mpGlyphs2Chars[ j ] = i;
+ }
+ }
+ }
+
+ // remove the dropped glyphs
+ const int* pGlyphWidths = mpJustifications ? mpJustifications : mpGlyphAdvances;
+ for( int nItem = 0; nItem < mnItemCount; ++nItem )
+ {
+ VisualItem& rVI = mpVisualItems[ nItem ];
+ if( rVI.IsEmpty() )
+ continue;
+
+ // mark replaced character widths
+ for( i = rVI.mnMinCharPos; i < rVI.mnEndCharPos; ++i )
+ {
+ int j = mpLogClusters[ i ] + rVI.mnMinGlyphPos;
+ if( mpOutGlyphs[ j ] == cDroppedGlyph )
+ mpCharWidths[ i ] = 0;
+ }
+
+ // handle dropped glyphs at start of visual item
+ int nMinGlyphPos, nEndGlyphPos, nOrigMinGlyphPos = rVI.mnMinGlyphPos;
+ GetItemSubrange( rVI, nMinGlyphPos, nEndGlyphPos );
+ i = nMinGlyphPos;
+ while( (mpOutGlyphs[i] == cDroppedGlyph) && (i < nEndGlyphPos) )
+ {
+ //rVI.mnXOffset += pGlyphWidths[ i ];
+ rVI.mnMinGlyphPos = ++i;
+ }
+
+ // when all glyphs in item got dropped mark it as empty
+ if( i >= nEndGlyphPos )
+ {
+ rVI.mnEndGlyphPos = 0;
+ continue;
+ }
+ // If there are still glyphs in the cluster and mnMinGlyphPos
+ // has changed then we need to remove the dropped glyphs at start
+ // to correct logClusters, which is unsigned and relative to the
+ // item start.
+ if (rVI.mnMinGlyphPos != nOrigMinGlyphPos)
+ {
+ // drop any glyphs in the visual item outside the range
+ for (i = nOrigMinGlyphPos; i < nMinGlyphPos; i++)
+ mpOutGlyphs[ i ] = cDroppedGlyph;
+ rVI.mnMinGlyphPos = i = nOrigMinGlyphPos;
+ }
+
+ // handle dropped glyphs in the middle of visual item
+ for(; i < nEndGlyphPos; ++i )
+ if( mpOutGlyphs[ i ] == cDroppedGlyph )
+ break;
+ int j = i;
+ while( ++i < nEndGlyphPos )
+ {
+ if( mpOutGlyphs[ i ] == cDroppedGlyph )
+ continue;
+ mpOutGlyphs[ j ] = mpOutGlyphs[ i ];
+ mpGlyphOffsets[ j ] = mpGlyphOffsets[ i ];
+ mpVisualAttrs[ j ] = mpVisualAttrs[ i ];
+ mpGlyphAdvances[ j ] = mpGlyphAdvances[ i ];
+ if( mpJustifications )
+ mpJustifications[ j ] = mpJustifications[ i ];
+ const int k = mpGlyphs2Chars[ i ];
+ mpGlyphs2Chars[ j ] = k;
+ const int nRelGlyphPos = (j++) - rVI.mnMinGlyphPos;
+ mpLogClusters[ k ] = static_cast<WORD>(nRelGlyphPos);
+ }
+
+ rVI.mnEndGlyphPos = j;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void UniscribeLayout::DrawText( SalGraphics& ) const
+{
+ HFONT hOrigFont = DisableFontScaling();
+
+ int nBaseClusterOffset = 0;
+ int nBaseGlyphPos = -1;
+ for( int nItem = 0; nItem < mnItemCount; ++nItem )
+ {
+ const VisualItem& rVisualItem = mpVisualItems[ nItem ];
+
+ // skip if there is nothing to display
+ int nMinGlyphPos, nEndGlyphPos;
+ if( !GetItemSubrange( rVisualItem, nMinGlyphPos, nEndGlyphPos ) )
+ continue;
+
+ if( nBaseGlyphPos < 0 )
+ {
+ // adjust draw position relative to cluster start
+ if( rVisualItem.IsRTL() )
+ nBaseGlyphPos = nEndGlyphPos - 1;
+ else
+ nBaseGlyphPos = nMinGlyphPos;
+
+ const int* pGlyphWidths;
+ if( mpJustifications )
+ pGlyphWidths = mpJustifications;
+ else
+ pGlyphWidths = mpGlyphAdvances;
+
+ int i = mnMinCharPos;
+ while( (--i >= rVisualItem.mnMinCharPos)
+ && (nBaseGlyphPos == mpLogClusters[i]) )
+ nBaseClusterOffset += mpCharWidths[i];
+
+ if( !rVisualItem.IsRTL() )
+ nBaseClusterOffset = -nBaseClusterOffset;
+ }
+
+ // now draw the matching glyphs in this item
+ Point aRelPos( rVisualItem.mnXOffset + nBaseClusterOffset, 0 );
+ Point aPos = GetDrawPosition( aRelPos );
+ SCRIPT_CACHE& rScriptCache = GetScriptCache();
+ (*pScriptTextOut)( mhDC, &rScriptCache,
+ aPos.X(), aPos.Y(), 0, NULL,
+ &rVisualItem.mpScriptItem->a, NULL, 0,
+ mpOutGlyphs + nMinGlyphPos,
+ nEndGlyphPos - nMinGlyphPos,
+ mpGlyphAdvances + nMinGlyphPos,
+ mpJustifications ? mpJustifications + nMinGlyphPos : NULL,
+ mpGlyphOffsets + nMinGlyphPos );
+ }
+
+ if( hOrigFont )
+ DeleteFont( SelectFont( mhDC, hOrigFont ) );
+}
+
+// -----------------------------------------------------------------------
+
+long UniscribeLayout::FillDXArray( long* pDXArray ) const
+{
+ // calculate width of the complete layout
+ long nWidth = mnBaseAdv;
+ for( int nItem = mnItemCount; --nItem >= 0; )
+ {
+ const VisualItem& rVI = mpVisualItems[ nItem ];
+
+ // skip if there is nothing to display
+ int nMinGlyphPos, nEndGlyphPos;
+ if( !GetItemSubrange( rVI, nMinGlyphPos, nEndGlyphPos ) )
+ continue;
+
+ // width = xoffset + width of last item
+ nWidth = rVI.mnXOffset;
+ const int* pGlyphWidths = mpJustifications ? mpJustifications : mpGlyphAdvances;
+ for( int i = nMinGlyphPos; i < nEndGlyphPos; ++i )
+ nWidth += pGlyphWidths[i];
+ break;
+ }
+
+ // copy the virtual char widths into pDXArray[]
+ if( pDXArray )
+ for( int i = mnMinCharPos; i < mnEndCharPos; ++i )
+ pDXArray[ i - mnMinCharPos ] = mpCharWidths[ i ];
+
+ return nWidth;
+}
+
+// -----------------------------------------------------------------------
+
+int UniscribeLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const
+{
+ long nWidth = 0;
+ for( int i = mnMinCharPos; i < mnEndCharPos; ++i )
+ {
+ nWidth += mpCharWidths[ i ] * nFactor;
+
+ // check if the nMaxWidth still fits the current sub-layout
+ if( nWidth >= nMaxWidth )
+ {
+ // go back to cluster start
+ // we have to find the visual item first since the mpLogClusters[]
+ // needed to find the cluster start is relative to to the visual item
+ int nMinGlyphIndex = 0;
+ for( int nItem = 0; nItem < mnItemCount; ++nItem )
+ {
+ const VisualItem& rVisualItem = mpVisualItems[ nItem ];
+ nMinGlyphIndex = rVisualItem.mnMinGlyphPos;
+ if( (i >= rVisualItem.mnMinCharPos)
+ && (i < rVisualItem.mnEndCharPos) )
+ break;
+ }
+ // now go back to the matching cluster start
+ do
+ {
+ int nGlyphPos = mpLogClusters[i] + nMinGlyphIndex;
+ if( 0 != mpVisualAttrs[ nGlyphPos ].fClusterStart )
+ return i;
+ } while( --i >= mnMinCharPos );
+
+ // if the cluster starts before the start of the visual item
+ // then set the visual breakpoint before this item
+ return mnMinCharPos;
+ }
+
+ // the visual break also depends on the nCharExtra between the characters
+ nWidth += nCharExtra;
+ }
+
+ // the whole layout did fit inside the nMaxWidth
+ return STRING_LEN;
+}
+
+// -----------------------------------------------------------------------
+
+void UniscribeLayout::GetCaretPositions( int nMaxIdx, long* pCaretXArray ) const
+{
+ int i;
+ for( i = 0; i < nMaxIdx; ++i )
+ pCaretXArray[ i ] = -1;
+ long* const pGlyphPos = (long*)alloca( (mnGlyphCount+1) * sizeof(long) );
+ for( i = 0; i <= mnGlyphCount; ++i )
+ pGlyphPos[ i ] = -1;
+
+ long nXPos = 0;
+ for( int nItem = 0; nItem < mnItemCount; ++nItem )
+ {
+ const VisualItem& rVisualItem = mpVisualItems[ nItem ];
+ if( rVisualItem.IsEmpty() )
+ continue;
+
+ // get glyph positions
+ // TODO: handle when rVisualItem's glyph range is only partially used
+ for( i = rVisualItem.mnMinGlyphPos; i < rVisualItem.mnEndGlyphPos; ++i )
+ {
+ pGlyphPos[ i ] = nXPos;
+ nXPos += mpGlyphAdvances[ i ];
+ }
+ // rightmost position of this visualitem
+ pGlyphPos[ i ] = nXPos;
+
+ // convert glyph positions to character positions
+ i = rVisualItem.mnMinCharPos;
+ if( i < mnMinCharPos )
+ i = mnMinCharPos;
+ for(; (i < rVisualItem.mnEndCharPos) && (i < mnEndCharPos); ++i )
+ {
+ int j = mpLogClusters[ i ] + rVisualItem.mnMinGlyphPos;
+ int nCurrIdx = i * 2;
+ if( !rVisualItem.IsRTL() )
+ {
+ // normal positions for LTR case
+ pCaretXArray[ nCurrIdx ] = pGlyphPos[ j ];
+ pCaretXArray[ nCurrIdx+1 ] = pGlyphPos[ j+1 ];
+ }
+ else
+ {
+ // reverse positions for RTL case
+ pCaretXArray[ nCurrIdx ] = pGlyphPos[ j+1 ];
+ pCaretXArray[ nCurrIdx+1 ] = pGlyphPos[ j ];
+ }
+ }
+ }
+
+ // fixup unknown character positions to neighbor
+ for( i = 0; i < nMaxIdx; ++i )
+ {
+ if( pCaretXArray[ i ] >= 0 )
+ nXPos = pCaretXArray[ i ];
+ else
+ pCaretXArray[ i ] = nXPos;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void UniscribeLayout::AdjustLayout( ImplLayoutArgs& rArgs )
+{
+ SalLayout::AdjustLayout( rArgs );
+
+ // adjust positions if requested
+ if( rArgs.mpDXArray )
+ ApplyDXArray( rArgs );
+ else if( rArgs.mnLayoutWidth )
+ Justify( rArgs.mnLayoutWidth );
+}
+
+// -----------------------------------------------------------------------
+
+void UniscribeLayout::ApplyDXArray( const ImplLayoutArgs& rArgs )
+{
+ const long* pDXArray = rArgs.mpDXArray;
+
+ // increase char widths in string range to desired values
+ bool bModified = false;
+ int nOldWidth = 0;
+ DBG_ASSERT( mnUnitsPerPixel==1, "UniscribeLayout.mnUnitsPerPixel != 1" );
+ int i,j;
+ for( i = mnMinCharPos, j = 0; i < mnEndCharPos; ++i, ++j )
+ {
+ int nNewCharWidth = (pDXArray[j] - nOldWidth);
+ // TODO: nNewCharWidth *= mnUnitsPerPixel;
+ if( mpCharWidths[i] != nNewCharWidth )
+ {
+ mpCharWidths[i] = nNewCharWidth;
+ bModified = true;
+ }
+ nOldWidth = pDXArray[j];
+ }
+
+ if( !bModified )
+ return;
+
+ // initialize justifications array
+ mpJustifications = new int[ mnGlyphCapacity ];
+ for( i = 0; i < mnGlyphCount; ++i )
+ mpJustifications[ i ] = mpGlyphAdvances[ i ];
+
+ // apply new widths to script items
+ long nXOffset = 0;
+ for( int nItem = 0; nItem < mnItemCount; ++nItem )
+ {
+ VisualItem& rVisualItem = mpVisualItems[ nItem ];
+
+ // set the position of this visual item
+ rVisualItem.mnXOffset = nXOffset;
+
+ // ignore empty visual items
+ if( rVisualItem.IsEmpty() )
+ {
+ for (i = rVisualItem.mnMinCharPos; i < rVisualItem.mnEndCharPos; i++)
+ nXOffset += mpCharWidths[i];
+ continue;
+ }
+ // ignore irrelevant visual items
+ if( (rVisualItem.mnMinCharPos >= mnEndCharPos)
+ || (rVisualItem.mnEndCharPos <= mnMinCharPos) )
+ continue;
+
+ // if needed prepare special handling for arabic justification
+ rVisualItem.mbHasKashidas = false;
+ if( rVisualItem.IsRTL() )
+ {
+ for( i = rVisualItem.mnMinGlyphPos; i < rVisualItem.mnEndGlyphPos; ++i )
+ if ( (1U << mpVisualAttrs[i].uJustification) & 0xFF82 ) // any Arabic justification
+ { // excluding SCRIPT_JUSTIFY_NONE
+ // yes
+ rVisualItem.mbHasKashidas = true;
+ // so prepare for kashida handling
+ InitKashidaHandling();
+ break;
+ }
+
+ if( rVisualItem.HasKashidas() )
+ for( i = rVisualItem.mnMinGlyphPos; i < rVisualItem.mnEndGlyphPos; ++i )
+ {
+ // TODO: check if we still need this hack after correction of kashida placing?
+ // (i87688): apparently yes, we still need it!
+ if ( mpVisualAttrs[i].uJustification == SCRIPT_JUSTIFY_NONE )
+ // usp decided that justification can't be applied here
+ // but maybe our Kashida algorithm thinks differently.
+ // To avoid trouble (gaps within words, last character of
+ // a word gets a Kashida appended) override this.
+
+ // I chose SCRIPT_JUSTIFY_ARABIC_KASHIDA to replace SCRIPT_JUSTIFY_NONE
+ // just because this previous hack (which I haven't understand, sorry) used
+ // the same value to replace. Don't know if this is really the best
+ // thing to do, but it seems to fix things
+ mpVisualAttrs[i].uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
+ }
+ }
+
+ // convert virtual charwidths to glyph justification values
+ HRESULT nRC = (*pScriptApplyLogicalWidth)(
+ mpCharWidths + rVisualItem.mnMinCharPos,
+ rVisualItem.mnEndCharPos - rVisualItem.mnMinCharPos,
+ rVisualItem.mnEndGlyphPos - rVisualItem.mnMinGlyphPos,
+ mpLogClusters + rVisualItem.mnMinCharPos,
+ mpVisualAttrs + rVisualItem.mnMinGlyphPos,
+ mpGlyphAdvances + rVisualItem.mnMinGlyphPos,
+ &rVisualItem.mpScriptItem->a,
+ &rVisualItem.maABCWidths,
+ mpJustifications + rVisualItem.mnMinGlyphPos );
+
+ if( nRC != 0 )
+ {
+ delete[] mpJustifications;
+ mpJustifications = NULL;
+ break;
+ }
+
+ // to prepare for the next visual item
+ // update nXOffset to the next items position
+ // before the mpJustifications[] array gets modified
+ int nMinGlyphPos, nEndGlyphPos;
+ if( GetItemSubrange( rVisualItem, nMinGlyphPos, nEndGlyphPos ) )
+ {
+ for( i = nMinGlyphPos; i < nEndGlyphPos; ++i )
+ nXOffset += mpJustifications[ i ];
+
+ if( rVisualItem.mbHasKashidas )
+ KashidaItemFix( nMinGlyphPos, nEndGlyphPos );
+ }
+
+ // workaround needed for older USP versions:
+ // right align the justification-adjusted glyphs in their cells for RTL-items
+ // unless the right alignment is done by inserting kashidas
+ if( bManualCellAlign && rVisualItem.IsRTL() && !rVisualItem.HasKashidas() )
+ {
+ for( i = nMinGlyphPos; i < nEndGlyphPos; ++i )
+ {
+ const int nXOffsetAdjust = mpJustifications[i] - mpGlyphAdvances[i];
+ // #i99862# skip diacritics, we mustn't add extra justification to diacritics
+ int nIdxAdd = i - 1;
+ while( (nIdxAdd >= nMinGlyphPos) && !mpGlyphAdvances[nIdxAdd] )
+ --nIdxAdd;
+ if( nIdxAdd < nMinGlyphPos )
+ rVisualItem.mnXOffset += nXOffsetAdjust;
+ else
+ mpJustifications[nIdxAdd] += nXOffsetAdjust;
+ mpJustifications[i] -= nXOffsetAdjust;
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void UniscribeLayout::InitKashidaHandling()
+{
+ if( mnMinKashidaGlyph != 0 ) // already initialized
+ return;
+
+ mrWinFontEntry.InitKashidaHandling( mhDC );
+ mnMinKashidaWidth = static_cast<int>(mfFontScale * mrWinFontEntry.GetMinKashidaWidth());
+ mnMinKashidaGlyph = mrWinFontEntry.GetMinKashidaGlyph();
+}
+
+// adjust the kashida placement matching to the WriterEngine
+void UniscribeLayout::KashidaItemFix( int nMinGlyphPos, int nEndGlyphPos )
+{
+ // workaround needed for all known USP versions:
+ // ApplyLogicalWidth does not match ScriptJustify behaviour
+ for( int i = nMinGlyphPos; i < nEndGlyphPos; ++i )
+ {
+ // check for vowels
+ if( (i > nMinGlyphPos && !mpGlyphAdvances[ i-1 ])
+ && (1U << mpVisualAttrs[i].uJustification) & 0xFF83 ) // all Arabic justifiction types
+ { // including SCRIPT_JUSTIFY_NONE
+ // vowel, we do it like ScriptJustify does
+ // the vowel gets the extra width
+ long nSpaceAdded = mpJustifications[ i ] - mpGlyphAdvances[ i ];
+ mpJustifications [ i ] = mpGlyphAdvances [ i ];
+ mpJustifications [ i - 1 ] += nSpaceAdded;
+ }
+ }
+
+ // redistribute the widths for kashidas
+ for( int i = nMinGlyphPos; i < nEndGlyphPos; )
+ KashidaWordFix ( nMinGlyphPos, nEndGlyphPos, &i );
+}
+
+bool UniscribeLayout::KashidaWordFix ( int nMinGlyphPos, int nEndGlyphPos, int* pnCurrentPos )
+{
+ // doing pixel work within a word.
+ // sometimes we have extra pixels and sometimes we miss some pixels to get to mnMinKashidaWidth
+
+ // find the next kashida
+ int nMinPos = *pnCurrentPos;
+ int nMaxPos = *pnCurrentPos;
+ for( int i = nMaxPos; i < nEndGlyphPos; ++i )
+ {
+ if( (mpVisualAttrs[ i ].uJustification >= SCRIPT_JUSTIFY_ARABIC_BLANK)
+ && (mpVisualAttrs[ i ].uJustification < SCRIPT_JUSTIFY_ARABIC_NORMAL) )
+ break;
+ nMaxPos = i;
+ }
+ *pnCurrentPos = nMaxPos + 1;
+ if( nMinPos == nMaxPos )
+ return false;
+
+ // calculate the available space for an extra kashida
+ long nMaxAdded = 0;
+ int nKashPos = -1;
+ for( int i = nMaxPos; i >= nMinPos; --i )
+ {
+ long nSpaceAdded = mpJustifications[ i ] - mpGlyphAdvances[ i ];
+ if( nSpaceAdded > nMaxAdded )
+ {
+ nKashPos = i;
+ nMaxAdded = nSpaceAdded;
+ }
+ }
+
+ // return early if there is no need for an extra kashida
+ if ( nMaxAdded <= 0 )
+ return false;
+ // return early if there is not enough space for an extra kashida
+ if( 2*nMaxAdded < mnMinKashidaWidth )
+ return false;
+
+ // redistribute the extra spacing to the kashida position
+ for( int i = nMinPos; i <= nMaxPos; ++i )
+ {
+ if( i == nKashPos )
+ continue;
+ // everything else should not have extra spacing
+ long nSpaceAdded = mpJustifications[ i ] - mpGlyphAdvances[ i ];
+ if( nSpaceAdded > 0 )
+ {
+ mpJustifications[ i ] -= nSpaceAdded;
+ mpJustifications[ nKashPos ] += nSpaceAdded;
+ }
+ }
+
+ // check if we fulfill minimal kashida width
+ long nSpaceAdded = mpJustifications[ nKashPos ] - mpGlyphAdvances[ nKashPos ];
+ if( nSpaceAdded < mnMinKashidaWidth )
+ {
+ // ugly: steal some pixels
+ long nSteal = 1;
+ if ( nMaxPos - nMinPos > 0 && ((mnMinKashidaWidth - nSpaceAdded) > (nMaxPos - nMinPos)))
+ nSteal = (mnMinKashidaWidth - nSpaceAdded) / (nMaxPos - nMinPos);
+ for( int i = nMinPos; i <= nMaxPos; ++i )
+ {
+ if( i == nKashPos )
+ continue;
+ nSteal = Min( mnMinKashidaWidth - nSpaceAdded, nSteal );
+ if ( nSteal > 0 )
+ {
+ mpJustifications [ i ] -= nSteal;
+ mpJustifications [ nKashPos ] += nSteal;
+ nSpaceAdded += nSteal;
+ }
+ if( nSpaceAdded >= mnMinKashidaWidth )
+ return true;
+ }
+ }
+
+ // blank padding
+ long nSpaceMissing = mnMinKashidaWidth - nSpaceAdded;
+ if( nSpaceMissing > 0 )
+ {
+ // inner glyph: distribute extra space evenly
+ if( (nMinPos > nMinGlyphPos) && (nMaxPos < nEndGlyphPos - 1) )
+ {
+ mpJustifications [ nKashPos ] += nSpaceMissing;
+ long nHalfSpace = nSpaceMissing / 2;
+ mpJustifications [ nMinPos - 1 ] -= nHalfSpace;
+ mpJustifications [ nMaxPos + 1 ] -= nSpaceMissing - nHalfSpace;
+ }
+ // rightmost: left glyph gets extra space
+ else if( nMinPos > nMinGlyphPos )
+ {
+ mpJustifications [ nMinPos - 1 ] -= nSpaceMissing;
+ mpJustifications [ nKashPos ] += nSpaceMissing;
+ }
+ // leftmost: right glyph gets extra space
+ else if( nMaxPos < nEndGlyphPos - 1 )
+ {
+ mpJustifications [ nKashPos ] += nSpaceMissing;
+ mpJustifications [ nMaxPos + 1 ] -= nSpaceMissing;
+ }
+ else
+ return false;
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+void UniscribeLayout::Justify( long nNewWidth )
+{
+ long nOldWidth = 0;
+ int i;
+ for( i = mnMinCharPos; i < mnEndCharPos; ++i )
+ nOldWidth += mpCharWidths[ i ];
+ if( nOldWidth <= 0 )
+ return;
+
+ nNewWidth *= mnUnitsPerPixel; // convert into font units
+ if( nNewWidth == nOldWidth )
+ return;
+ // prepare to distribute the extra width evenly among the visual items
+ const double fStretch = (double)nNewWidth / nOldWidth;
+
+ // initialize justifications array
+ mpJustifications = new int[ mnGlyphCapacity ];
+ for( i = 0; i < mnGlyphCapacity; ++i )
+ mpJustifications[ i ] = mpGlyphAdvances[ i ];
+
+ // justify stretched script items
+ long nXOffset = 0;
+ SCRIPT_CACHE& rScriptCache = GetScriptCache();
+ for( int nItem = 0; nItem < mnItemCount; ++nItem )
+ {
+ VisualItem& rVisualItem = mpVisualItems[ nItem ];
+ if( rVisualItem.IsEmpty() )
+ continue;
+
+ if( (rVisualItem.mnMinCharPos < mnEndCharPos)
+ && (rVisualItem.mnEndCharPos > mnMinCharPos) )
+ {
+ long nItemWidth = 0;
+ for( i = rVisualItem.mnMinCharPos; i < rVisualItem.mnEndCharPos; ++i )
+ nItemWidth += mpCharWidths[ i ];
+ nItemWidth = (int)((fStretch - 1.0) * nItemWidth + 0.5);
+
+ HRESULT nRC = (*pScriptJustify) (
+ mpVisualAttrs + rVisualItem.mnMinGlyphPos,
+ mpGlyphAdvances + rVisualItem.mnMinGlyphPos,
+ rVisualItem.mnEndGlyphPos - rVisualItem.mnMinGlyphPos,
+ nItemWidth,
+ mnMinKashidaWidth,
+ mpJustifications + rVisualItem.mnMinGlyphPos );
+
+ rVisualItem.mnXOffset = nXOffset;
+ nXOffset += nItemWidth;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+bool UniscribeLayout::IsKashidaPosValid ( int nCharPos ) const
+{
+ // we have to find the visual item first since the mpLogClusters[]
+ // needed to find the cluster start is relative to to the visual item
+ int nMinGlyphIndex = -1;
+ for( int nItem = 0; nItem < mnItemCount; ++nItem )
+ {
+ const VisualItem& rVisualItem = mpVisualItems[ nItem ];
+ if( (nCharPos >= rVisualItem.mnMinCharPos)
+ && (nCharPos < rVisualItem.mnEndCharPos) )
+ {
+ nMinGlyphIndex = rVisualItem.mnMinGlyphPos;
+ break;
+ }
+ }
+ // Invalid char pos or leftmost glyph in visual item
+ if ( nMinGlyphIndex == -1 || !mpLogClusters[ nCharPos ] )
+ return false;
+
+// This test didn't give the expected results
+/* if( mpLogClusters[ nCharPos+1 ] == mpLogClusters[ nCharPos ])
+ // two chars, one glyph
+ return false;*/
+
+ const int nGlyphPos = mpLogClusters[ nCharPos ] + nMinGlyphIndex;
+ if( nGlyphPos <= 0 )
+ return true;
+ // justification is only allowed if the glyph to the left has not SCRIPT_JUSTIFY_NONE
+ // and not SCRIPT_JUSTIFY_ARABIC_BLANK
+ // special case: glyph to the left is vowel (no advance width)
+ if ( mpVisualAttrs[ nGlyphPos-1 ].uJustification == SCRIPT_JUSTIFY_ARABIC_BLANK
+ || ( mpVisualAttrs[ nGlyphPos-1 ].uJustification == SCRIPT_JUSTIFY_NONE
+ && mpGlyphAdvances [ nGlyphPos-1 ] ))
+ return false;
+ return true;
+}
+
+#endif // USE_UNISCRIBE
+
+#ifdef ENABLE_GRAPHITE
+
+class GraphiteLayoutWinImpl : public GraphiteLayout
+{
+public:
+ GraphiteLayoutWinImpl(const gr::Font & font, ImplWinFontEntry & rFont)
+ throw()
+ : GraphiteLayout(font), mrFont(rFont) {};
+ virtual ~GraphiteLayoutWinImpl() throw() {};
+ virtual sal_GlyphId getKashidaGlyph(int & rWidth);
+private:
+ ImplWinFontEntry & mrFont;
+};
+
+sal_GlyphId GraphiteLayoutWinImpl::getKashidaGlyph(int & rWidth)
+{
+ rWidth = mrFont.GetMinKashidaWidth();
+ return mrFont.GetMinKashidaGlyph();
+}
+
+// This class uses the SIL Graphite engine to provide complex text layout services to the VCL
+// @author tse
+//
+class GraphiteWinLayout : public WinLayout
+{
+private:
+ mutable gr::WinFont mpFont;
+ grutils::GrFeatureParser * mpFeatures;
+ mutable GraphiteLayoutWinImpl maImpl;
+public:
+ GraphiteWinLayout(HDC hDC, const ImplWinFontData& rWFD, ImplWinFontEntry& rWFE);
+
+ static bool IsGraphiteEnabledFont(HDC hDC) throw();
+
+ // used by upper layers
+ virtual bool LayoutText( ImplLayoutArgs& ); // first step of layout
+ virtual void AdjustLayout( ImplLayoutArgs& ); // adjusting after fallback etc.
+ // virtual void InitFont() const;
+ virtual void DrawText( SalGraphics& ) const;
+
+ // methods using string indexing
+ virtual int GetTextBreak( long nMaxWidth, long nCharExtra=0, int nFactor=1 ) const;
+ virtual long FillDXArray( long* pDXArray ) const;
+
+ virtual void GetCaretPositions( int nArraySize, long* pCaretXArray ) const;
+
+ // methods using glyph indexing
+ virtual int GetNextGlyphs(int nLen, sal_GlyphId* pGlyphIdxAry, ::Point & rPos, int&,
+ long* pGlyphAdvAry = 0, int* pCharPosAry = 0 ) const;
+
+ // used by glyph+font+script fallback
+ virtual void MoveGlyph( int nStart, long nNewXPos );
+ virtual void DropGlyph( int nStart );
+ virtual void Simplify( bool bIsBase );
+ ~GraphiteWinLayout() { delete mpFeatures; mpFeatures = NULL; };
+protected:
+ virtual void ReplaceDC(gr::Segment & segment) const;
+ virtual void RestoreDC(gr::Segment & segment) const;
+};
+
+bool GraphiteWinLayout::IsGraphiteEnabledFont(HDC hDC) throw()
+{
+ return gr::WinFont::FontHasGraphiteTables(hDC);
+}
+
+GraphiteWinLayout::GraphiteWinLayout(HDC hDC, const ImplWinFontData& rWFD, ImplWinFontEntry& rWFE) throw()
+ : WinLayout(hDC, rWFD, rWFE), mpFont(hDC),
+ maImpl(mpFont, rWFE)
+{
+ const rtl::OString aLang = MsLangId::convertLanguageToIsoByteString( rWFE.maFontSelData.meLanguage );
+ rtl::OString name = rtl::OUStringToOString(
+ rWFE.maFontSelData.maTargetName, RTL_TEXTENCODING_UTF8 );
+ 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(mpFont, aFeat.getStr(), aLang.getStr());
+ }
+ else
+ {
+ mpFeatures = new grutils::GrFeatureParser(mpFont, aLang.getStr());
+ }
+ maImpl.SetFeatures(mpFeatures);
+}
+
+void GraphiteWinLayout::ReplaceDC(gr::Segment & segment) const
+{
+ COLORREF color = GetTextColor(mhDC);
+ dynamic_cast<gr::WinFont&>(segment.getFont()).replaceDC(mhDC);
+ SetTextColor(mhDC, color);
+}
+
+void GraphiteWinLayout::RestoreDC(gr::Segment & segment) const
+{
+ dynamic_cast<gr::WinFont&>(segment.getFont()).restoreDC();
+}
+
+bool GraphiteWinLayout::LayoutText( ImplLayoutArgs & args)
+{
+ HFONT hUnRotatedFont;
+ if (args.mnOrientation)
+ {
+ // Graphite gets very confused if the font is rotated
+ LOGFONTW aLogFont;
+ ::GetObjectW( mhFont, sizeof(LOGFONTW), &aLogFont);
+ aLogFont.lfEscapement = 0;
+ aLogFont.lfOrientation = 0;
+ hUnRotatedFont = ::CreateFontIndirectW( &aLogFont);
+ ::SelectFont(mhDC, hUnRotatedFont);
+ }
+ WinLayout::AdjustLayout(args);
+ mpFont.replaceDC(mhDC);
+ maImpl.SetFontScale(WinLayout::mfFontScale);
+ //bool succeeded = maImpl.LayoutText(args);
+#ifdef GRCACHE
+ GrSegRecord * pSegRecord = NULL;
+ gr::Segment * pSegment = maImpl.CreateSegment(args, &pSegRecord);
+#else
+ gr::Segment * pSegment = maImpl.CreateSegment(args);
+#endif
+ bool bSucceeded = false;
+ if (pSegment)
+ {
+ // replace the DC on the font within the segment
+ ReplaceDC(*pSegment);
+ // create glyph vectors
+#ifdef GRCACHE
+ bSucceeded = maImpl.LayoutGlyphs(args, pSegment, pSegRecord);
+#else
+ bSucceeded = maImpl.LayoutGlyphs(args, pSegment);
+#endif
+ // restore original DC
+ RestoreDC(*pSegment);
+#ifdef GRCACHE
+ if (pSegRecord) pSegRecord->unlock();
+ else delete pSegment;
+#else
+ delete pSegment;
+#endif
+ }
+ mpFont.restoreDC();
+ if (args.mnOrientation)
+ {
+ // restore the rotated font
+ ::SelectFont(mhDC, mhFont);
+ ::DeleteObject(hUnRotatedFont);
+ }
+ return bSucceeded;
+}
+
+void GraphiteWinLayout::AdjustLayout(ImplLayoutArgs& rArgs)
+{
+ WinLayout::AdjustLayout(rArgs);
+ maImpl.DrawBase() = WinLayout::maDrawBase;
+ maImpl.DrawOffset() = WinLayout::maDrawOffset;
+ if ( (rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL) && rArgs.mpDXArray)
+ {
+ mrWinFontEntry.InitKashidaHandling(mhDC);
+ }
+ maImpl.AdjustLayout(rArgs);
+}
+
+void GraphiteWinLayout::DrawText(SalGraphics &sal_graphics) const
+{
+ HFONT hOrigFont = DisableFontScaling();
+ HDC aHDC = static_cast<WinSalGraphics&>(sal_graphics).mhDC;
+ maImpl.DrawBase() = WinLayout::maDrawBase;
+ maImpl.DrawOffset() = WinLayout::maDrawOffset;
+ const int MAX_GLYPHS = 2;
+ sal_GlyphId glyphIntStr[MAX_GLYPHS];
+ WORD glyphWStr[MAX_GLYPHS];
+ int glyphIndex = 0;
+ Point aPos(0,0);
+ int nGlyphs = 0;
+ do
+ {
+ nGlyphs = maImpl.GetNextGlyphs(1, glyphIntStr, aPos, glyphIndex);
+ if (nGlyphs < 1)
+ break;
+ std::copy(glyphIntStr, glyphIntStr + nGlyphs, glyphWStr);
+ ::ExtTextOutW(aHDC, aPos.X(), aPos.Y(), ETO_GLYPH_INDEX,
+ NULL, (LPCWSTR)&(glyphWStr), nGlyphs, NULL);
+ } while (nGlyphs);
+ if( hOrigFont )
+ DeleteFont( SelectFont( mhDC, hOrigFont ) );
+}
+
+int GraphiteWinLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const
+{
+ mpFont.replaceDC(mhDC);
+ int nBreak = maImpl.GetTextBreak(nMaxWidth, nCharExtra, nFactor);
+ mpFont.restoreDC();
+ return nBreak;
+}
+
+long GraphiteWinLayout::FillDXArray( long* pDXArray ) const
+{
+ return maImpl.FillDXArray(pDXArray);
+}
+
+void GraphiteWinLayout::GetCaretPositions( int nArraySize, long* pCaretXArray ) const
+{
+ maImpl.GetCaretPositions(nArraySize, pCaretXArray);
+}
+
+int GraphiteWinLayout::GetNextGlyphs( int length, sal_GlyphId* glyph_out,
+ ::Point & pos_out, int &glyph_slot, long * glyph_adv, int *char_index) const
+{
+ maImpl.DrawBase() = WinLayout::maDrawBase;
+ maImpl.DrawOffset() = WinLayout::maDrawOffset;
+ return maImpl.GetNextGlyphs(length, glyph_out, pos_out, glyph_slot, glyph_adv, char_index);
+}
+
+void GraphiteWinLayout::MoveGlyph( int glyph_idx, long new_x_pos )
+{
+ maImpl.MoveGlyph(glyph_idx, new_x_pos);
+}
+
+void GraphiteWinLayout::DropGlyph( int glyph_idx )
+{
+ maImpl.DropGlyph(glyph_idx);
+}
+
+void GraphiteWinLayout::Simplify( bool is_base )
+{
+ maImpl.Simplify(is_base);
+}
+#endif // ENABLE_GRAPHITE
+// =======================================================================
+
+SalLayout* WinSalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLevel )
+{
+ DBG_ASSERT( mpWinFontEntry[nFallbackLevel], "WinSalGraphics mpWinFontEntry==NULL");
+
+ WinLayout* pWinLayout = NULL;
+
+ const ImplWinFontData& rFontFace = *mpWinFontData[ nFallbackLevel ];
+ ImplWinFontEntry& rFontInstance = *mpWinFontEntry[ nFallbackLevel ];
+
+#if defined( USE_UNISCRIBE )
+ if( !(rArgs.mnFlags & SAL_LAYOUT_COMPLEX_DISABLED)
+ && (aUspModule || (bUspEnabled && InitUSP())) ) // CTL layout engine
+ {
+#ifdef ENABLE_GRAPHITE
+ if (rFontFace.SupportsGraphite())
+ pWinLayout = new GraphiteWinLayout(mhDC, rFontFace, rFontInstance);
+ else
+#endif // ENABLE_GRAPHITE
+ // script complexity is determined in upper layers
+ pWinLayout = new UniscribeLayout( mhDC, rFontFace, rFontInstance );
+ // NOTE: it must be guaranteed that the WinSalGraphics lives longer than
+ // the created UniscribeLayout, otherwise the data passed into the
+ // constructor might become invalid too early
+ }
+ else
+#endif // USE_UNISCRIBE
+ {
+#ifdef GCP_KERN_HACK
+ if( (rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS) && !rFontInstance.HasKernData() )
+ {
+ // TODO: directly cache kerning info in the rFontInstance
+ // TODO: get rid of kerning methods+data in WinSalGraphics object
+ GetKernPairs( 0, NULL );
+ rFontInstance.SetKernData( mnFontKernPairCount, mpFontKernPairs );
+ }
+#endif // GCP_KERN_HACK
+
+ BYTE eCharSet = ANSI_CHARSET;
+ if( mpLogFont )
+ eCharSet = mpLogFont->lfCharSet;
+#ifdef ENABLE_GRAPHITE
+ if (rFontFace.SupportsGraphite())
+ pWinLayout = new GraphiteWinLayout(mhDC, rFontFace, rFontInstance);
+ else
+#endif // ENABLE_GRAPHITE
+ pWinLayout = new SimpleWinLayout( mhDC, eCharSet, rFontFace, rFontInstance );
+ }
+
+ if( mfFontScale != 1.0 )
+ pWinLayout->SetFontScale( mfFontScale );
+
+ return pWinLayout;
+}
+
+// -----------------------------------------------------------------------
+
+int WinSalGraphics::GetMinKashidaWidth()
+{
+ if( !mpWinFontEntry[0] )
+ return 0;
+ mpWinFontEntry[0]->InitKashidaHandling( mhDC );
+ int nMinKashida = static_cast<int>(mfFontScale * mpWinFontEntry[0]->GetMinKashidaWidth());
+ return nMinKashida;
+}
+
+// =======================================================================
+
+ImplWinFontEntry::ImplWinFontEntry( ImplFontSelectData& rFSD )
+: ImplFontEntry( rFSD )
+, maWidthMap( 512 )
+, mpKerningPairs( NULL )
+, mnKerningPairs( -1 )
+, mnMinKashidaWidth( -1 )
+, mnMinKashidaGlyph( -1 )
+{
+#ifdef USE_UNISCRIBE
+ maScriptCache = NULL;
+#endif // USE_UNISCRIBE
+}
+
+// -----------------------------------------------------------------------
+
+ImplWinFontEntry::~ImplWinFontEntry()
+{
+#ifdef USE_UNISCRIBE
+ if( maScriptCache != NULL )
+ (*pScriptFreeCache)( &maScriptCache );
+#endif // USE_UNISCRIBE
+#ifdef GCP_KERN_HACK
+ delete[] mpKerningPairs;
+#endif // GCP_KERN_HACK
+}
+
+// -----------------------------------------------------------------------
+
+bool ImplWinFontEntry::HasKernData() const
+{
+ return (mnKerningPairs >= 0);
+}
+
+// -----------------------------------------------------------------------
+
+void ImplWinFontEntry::SetKernData( int nPairCount, const KERNINGPAIR* pPairData )
+{
+ mnKerningPairs = nPairCount;
+ mpKerningPairs = new KERNINGPAIR[ mnKerningPairs ];
+ ::memcpy( mpKerningPairs, (const void*)pPairData, nPairCount*sizeof(KERNINGPAIR) );
+}
+
+// -----------------------------------------------------------------------
+
+int ImplWinFontEntry::GetKerning( sal_Unicode cLeft, sal_Unicode cRight ) const
+{
+ int nKernAmount = 0;
+ if( mpKerningPairs )
+ {
+ const KERNINGPAIR aRefPair = { cLeft, cRight, 0 };
+ const KERNINGPAIR* pFirstPair = mpKerningPairs;
+ const KERNINGPAIR* pEndPair = mpKerningPairs + mnKerningPairs;
+ const KERNINGPAIR* pPair = std::lower_bound( pFirstPair,
+ pEndPair, aRefPair, ImplCmpKernData );
+ if( (pPair != pEndPair)
+ && (pPair->wFirst == aRefPair.wFirst)
+ && (pPair->wSecond == aRefPair.wSecond) )
+ nKernAmount = pPair->iKernAmount;
+ }
+
+ return nKernAmount;
+}
+
+// -----------------------------------------------------------------------
+
+bool ImplWinFontEntry::InitKashidaHandling( HDC hDC )
+{
+ if( mnMinKashidaWidth >= 0 ) // already cached?
+ return mnMinKashidaWidth;
+
+ // initialize the kashida width
+ mnMinKashidaWidth = 0;
+ mnMinKashidaGlyph = 0;
+#ifdef USE_UNISCRIBE
+ if (aUspModule || (bUspEnabled && InitUSP()))
+ {
+ SCRIPT_FONTPROPERTIES aFontProperties;
+ aFontProperties.cBytes = sizeof (aFontProperties);
+ SCRIPT_CACHE& rScriptCache = GetScriptCache();
+ HRESULT nRC = (*pScriptGetFontProperties)( hDC, &rScriptCache, &aFontProperties );
+ if( nRC != 0 )
+ return false;
+ mnMinKashidaWidth = aFontProperties.iKashidaWidth;
+ mnMinKashidaGlyph = aFontProperties.wgKashida;
+ }
+#endif // USE_UNISCRIBE
+
+ return true;
+}
+
+// =======================================================================
+
+ImplFontData* ImplWinFontData::Clone() const
+{
+ if( mpUnicodeMap )
+ mpUnicodeMap->AddReference();
+ ImplFontData* pClone = new ImplWinFontData( *this );
+ return pClone;
+}
+
+// -----------------------------------------------------------------------
+
+ImplFontEntry* ImplWinFontData::CreateFontInstance( ImplFontSelectData& rFSD ) const
+{
+ ImplFontEntry* pEntry = new ImplWinFontEntry( rFSD );
+ return pEntry;
+}
+
+// =======================================================================
diff --git a/vcl/win/source/gdi/wntgdi.cxx b/vcl/win/source/gdi/wntgdi.cxx
new file mode 100644
index 000000000000..eb53fb4d8699
--- /dev/null
+++ b/vcl/win/source/gdi/wntgdi.cxx
@@ -0,0 +1,67 @@
+/*************************************************************************
+ *
+ * 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"
+
+#if defined _MSC_VER
+#pragma warning(push, 1)
+#endif
+#include <windows.h>
+#if defined _MSC_VER
+#pragma warning(pop)
+#endif
+
+// -----------------------------------------------------------------------
+
+extern "C"
+{
+BOOL WINAPI WIN_Rectangle( HDC hDC, int X1, int Y1, int X2, int Y2 )
+{
+ return Rectangle( hDC, X1, Y1, X2, Y2 );
+}
+}
+
+// -----------------------------------------------------------------------
+
+extern "C"
+{
+BOOL WINAPI WIN_Polygon( HDC hDC, CONST POINT * ppt, int ncnt )
+{
+ return Polygon( hDC, ppt, ncnt );
+}
+}
+
+// -----------------------------------------------------------------------
+
+extern "C"
+{
+BOOL WINAPI WIN_PolyPolygon( HDC hDC, CONST POINT * ppt, LPINT npcnt, int ncnt )
+{
+ return PolyPolygon( hDC, ppt, npcnt, ncnt );
+}
+}
diff --git a/vcl/win/source/src/50.bmp b/vcl/win/source/src/50.bmp
new file mode 100644
index 000000000000..b9d56fcd14c1
--- /dev/null
+++ b/vcl/win/source/src/50.bmp
Binary files differ
diff --git a/vcl/win/source/src/50.png b/vcl/win/source/src/50.png
new file mode 100644
index 000000000000..8517d965f0b9
--- /dev/null
+++ b/vcl/win/source/src/50.png
Binary files differ
diff --git a/vcl/win/source/src/MAKEFILE.MK b/vcl/win/source/src/MAKEFILE.MK
new file mode 100644
index 000000000000..7addba363481
--- /dev/null
+++ b/vcl/win/source/src/MAKEFILE.MK
@@ -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.
+#
+#*************************************************************************
+
+
+PRJ=..$/..$/..
+
+PRJNAME=vcl
+TARGET=salsrc
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+# --- #105371#
+CFLAGS += -DWINVER=0x0400
+
+# --- Files --------------------------------------------------------
+
+RCDEPN= nullptr.cur \
+ help.cur \
+ hsize.cur \
+ vsize.cur \
+ neswsize.cur \
+ nwsesize.cur \
+ cross.cur \
+ move.cur \
+ hsplit.cur \
+ vsplit.cur \
+ hsizebar.cur \
+ vsizebar.cur \
+ hand.cur \
+ refhand.cur \
+ pen.cur \
+ magnify.cur \
+ fill.cur \
+ rotate.cur \
+ hshear.cur \
+ vshear.cur \
+ mirror.cur \
+ crook.cur \
+ crop.cur \
+ movept.cur \
+ movebw.cur \
+ movedata.cur \
+ copydata.cur \
+ linkdata.cur \
+ movedlnk.cur \
+ copydlnk.cur \
+ movef.cur \
+ copyf.cur \
+ linkf.cur \
+ moveflnk.cur \
+ copyflnk.cur \
+ movef2.cur \
+ copyf2.cur \
+ notallow.cur \
+ dline.cur \
+ drect.cur \
+ dpolygon.cur \
+ dbezier.cur \
+ darc.cur \
+ dpie.cur \
+ dcirccut.cur \
+ dellipse.cur \
+ dfree.cur \
+ dconnect.cur \
+ dtext.cur \
+ dcapt.cur \
+ chart.cur \
+ detectiv.cur \
+ pivotcol.cur \
+ pivotrow.cur \
+ pivotfld.cur \
+ pivotdel.cur \
+ chain.cur \
+ chainnot.cur \
+ timemove.cur \
+ timesize.cur \
+ asn.cur \
+ ass.cur \
+ asw.cur \
+ ase.cur \
+ asnw.cur \
+ asne.cur \
+ assw.cur \
+ asse.cur \
+ asns.cur \
+ aswe.cur \
+ asnswe.cur \
+ airbrush.cur \
+ vtext.cur \
+ tblsels.cur \
+ tblsele.cur \
+ tblselse.cur \
+ tblselw.cur \
+ tblselsw.cur \
+ pntbrsh.cur \
+ 50.bmp \
+ sd.ico
+
+RCFILES= salsrc.rc
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
diff --git a/vcl/win/source/src/airbrush.cur b/vcl/win/source/src/airbrush.cur
new file mode 100644
index 000000000000..f6a684e6fcbd
--- /dev/null
+++ b/vcl/win/source/src/airbrush.cur
Binary files differ
diff --git a/vcl/win/source/src/ase.cur b/vcl/win/source/src/ase.cur
new file mode 100755
index 000000000000..7634a7d34a7b
--- /dev/null
+++ b/vcl/win/source/src/ase.cur
Binary files differ
diff --git a/vcl/win/source/src/asn.cur b/vcl/win/source/src/asn.cur
new file mode 100755
index 000000000000..e444e42bf37e
--- /dev/null
+++ b/vcl/win/source/src/asn.cur
Binary files differ
diff --git a/vcl/win/source/src/asne.cur b/vcl/win/source/src/asne.cur
new file mode 100755
index 000000000000..e92cc65e7eb1
--- /dev/null
+++ b/vcl/win/source/src/asne.cur
Binary files differ
diff --git a/vcl/win/source/src/asns.cur b/vcl/win/source/src/asns.cur
new file mode 100755
index 000000000000..04d0b09c353e
--- /dev/null
+++ b/vcl/win/source/src/asns.cur
Binary files differ
diff --git a/vcl/win/source/src/asnswe.cur b/vcl/win/source/src/asnswe.cur
new file mode 100755
index 000000000000..a0e25b16de1f
--- /dev/null
+++ b/vcl/win/source/src/asnswe.cur
Binary files differ
diff --git a/vcl/win/source/src/asnw.cur b/vcl/win/source/src/asnw.cur
new file mode 100755
index 000000000000..20322bc97b16
--- /dev/null
+++ b/vcl/win/source/src/asnw.cur
Binary files differ
diff --git a/vcl/win/source/src/ass.cur b/vcl/win/source/src/ass.cur
new file mode 100755
index 000000000000..7166636a1a77
--- /dev/null
+++ b/vcl/win/source/src/ass.cur
Binary files differ
diff --git a/vcl/win/source/src/asse.cur b/vcl/win/source/src/asse.cur
new file mode 100755
index 000000000000..8cb71234b0a9
--- /dev/null
+++ b/vcl/win/source/src/asse.cur
Binary files differ
diff --git a/vcl/win/source/src/assw.cur b/vcl/win/source/src/assw.cur
new file mode 100755
index 000000000000..fddaf3f57cbf
--- /dev/null
+++ b/vcl/win/source/src/assw.cur
Binary files differ
diff --git a/vcl/win/source/src/asw.cur b/vcl/win/source/src/asw.cur
new file mode 100755
index 000000000000..0ccac50f4596
--- /dev/null
+++ b/vcl/win/source/src/asw.cur
Binary files differ
diff --git a/vcl/win/source/src/aswe.cur b/vcl/win/source/src/aswe.cur
new file mode 100755
index 000000000000..c238b7e10aef
--- /dev/null
+++ b/vcl/win/source/src/aswe.cur
Binary files differ
diff --git a/vcl/win/source/src/chain.cur b/vcl/win/source/src/chain.cur
new file mode 100755
index 000000000000..02abb7ab714f
--- /dev/null
+++ b/vcl/win/source/src/chain.cur
Binary files differ
diff --git a/vcl/win/source/src/chainnot.cur b/vcl/win/source/src/chainnot.cur
new file mode 100755
index 000000000000..938ece03f329
--- /dev/null
+++ b/vcl/win/source/src/chainnot.cur
Binary files differ
diff --git a/vcl/win/source/src/chart.cur b/vcl/win/source/src/chart.cur
new file mode 100644
index 000000000000..25fe85b76039
--- /dev/null
+++ b/vcl/win/source/src/chart.cur
Binary files differ
diff --git a/vcl/win/source/src/copydata.cur b/vcl/win/source/src/copydata.cur
new file mode 100644
index 000000000000..d3c4bc93afd5
--- /dev/null
+++ b/vcl/win/source/src/copydata.cur
Binary files differ
diff --git a/vcl/win/source/src/copydlnk.cur b/vcl/win/source/src/copydlnk.cur
new file mode 100644
index 000000000000..495fd5e17776
--- /dev/null
+++ b/vcl/win/source/src/copydlnk.cur
Binary files differ
diff --git a/vcl/win/source/src/copyf.cur b/vcl/win/source/src/copyf.cur
new file mode 100644
index 000000000000..450c09443a84
--- /dev/null
+++ b/vcl/win/source/src/copyf.cur
Binary files differ
diff --git a/vcl/win/source/src/copyf2.cur b/vcl/win/source/src/copyf2.cur
new file mode 100644
index 000000000000..ac8de5da6ba5
--- /dev/null
+++ b/vcl/win/source/src/copyf2.cur
Binary files differ
diff --git a/vcl/win/source/src/copyflnk.cur b/vcl/win/source/src/copyflnk.cur
new file mode 100644
index 000000000000..e67f0539fa43
--- /dev/null
+++ b/vcl/win/source/src/copyflnk.cur
Binary files differ
diff --git a/vcl/win/source/src/crook.cur b/vcl/win/source/src/crook.cur
new file mode 100644
index 000000000000..c40cf591e261
--- /dev/null
+++ b/vcl/win/source/src/crook.cur
Binary files differ
diff --git a/vcl/win/source/src/crop.cur b/vcl/win/source/src/crop.cur
new file mode 100644
index 000000000000..327fb06976c2
--- /dev/null
+++ b/vcl/win/source/src/crop.cur
Binary files differ
diff --git a/vcl/win/source/src/cross.cur b/vcl/win/source/src/cross.cur
new file mode 100644
index 000000000000..8fd9762386b1
--- /dev/null
+++ b/vcl/win/source/src/cross.cur
Binary files differ
diff --git a/vcl/win/source/src/darc.cur b/vcl/win/source/src/darc.cur
new file mode 100644
index 000000000000..38504fa23c4a
--- /dev/null
+++ b/vcl/win/source/src/darc.cur
Binary files differ
diff --git a/vcl/win/source/src/dbezier.cur b/vcl/win/source/src/dbezier.cur
new file mode 100644
index 000000000000..f630b837ddf8
--- /dev/null
+++ b/vcl/win/source/src/dbezier.cur
Binary files differ
diff --git a/vcl/win/source/src/dcapt.cur b/vcl/win/source/src/dcapt.cur
new file mode 100644
index 000000000000..10dd5ba0d676
--- /dev/null
+++ b/vcl/win/source/src/dcapt.cur
Binary files differ
diff --git a/vcl/win/source/src/dcirccut.cur b/vcl/win/source/src/dcirccut.cur
new file mode 100644
index 000000000000..b19d3f8257f4
--- /dev/null
+++ b/vcl/win/source/src/dcirccut.cur
Binary files differ
diff --git a/vcl/win/source/src/dconnect.cur b/vcl/win/source/src/dconnect.cur
new file mode 100644
index 000000000000..5318d8f22d8b
--- /dev/null
+++ b/vcl/win/source/src/dconnect.cur
Binary files differ
diff --git a/vcl/win/source/src/dellipse.cur b/vcl/win/source/src/dellipse.cur
new file mode 100644
index 000000000000..c489a640335e
--- /dev/null
+++ b/vcl/win/source/src/dellipse.cur
Binary files differ
diff --git a/vcl/win/source/src/detectiv.cur b/vcl/win/source/src/detectiv.cur
new file mode 100644
index 000000000000..30e5685b64b2
--- /dev/null
+++ b/vcl/win/source/src/detectiv.cur
Binary files differ
diff --git a/vcl/win/source/src/dfree.cur b/vcl/win/source/src/dfree.cur
new file mode 100644
index 000000000000..3ff56d007648
--- /dev/null
+++ b/vcl/win/source/src/dfree.cur
Binary files differ
diff --git a/vcl/win/source/src/dline.cur b/vcl/win/source/src/dline.cur
new file mode 100644
index 000000000000..623c33ac2351
--- /dev/null
+++ b/vcl/win/source/src/dline.cur
Binary files differ
diff --git a/vcl/win/source/src/dpie.cur b/vcl/win/source/src/dpie.cur
new file mode 100644
index 000000000000..3b911cd01e43
--- /dev/null
+++ b/vcl/win/source/src/dpie.cur
Binary files differ
diff --git a/vcl/win/source/src/dpolygon.cur b/vcl/win/source/src/dpolygon.cur
new file mode 100644
index 000000000000..9467f1e286aa
--- /dev/null
+++ b/vcl/win/source/src/dpolygon.cur
Binary files differ
diff --git a/vcl/win/source/src/drect.cur b/vcl/win/source/src/drect.cur
new file mode 100644
index 000000000000..60a5242c203c
--- /dev/null
+++ b/vcl/win/source/src/drect.cur
Binary files differ
diff --git a/vcl/win/source/src/dtext.cur b/vcl/win/source/src/dtext.cur
new file mode 100644
index 000000000000..01e7d31eae7e
--- /dev/null
+++ b/vcl/win/source/src/dtext.cur
Binary files differ
diff --git a/vcl/win/source/src/fill.cur b/vcl/win/source/src/fill.cur
new file mode 100644
index 000000000000..78f5fad87ad0
--- /dev/null
+++ b/vcl/win/source/src/fill.cur
Binary files differ
diff --git a/vcl/win/source/src/hand.cur b/vcl/win/source/src/hand.cur
new file mode 100644
index 000000000000..fc0e53b474e2
--- /dev/null
+++ b/vcl/win/source/src/hand.cur
Binary files differ
diff --git a/vcl/win/source/src/help.cur b/vcl/win/source/src/help.cur
new file mode 100644
index 000000000000..e59ee97992b3
--- /dev/null
+++ b/vcl/win/source/src/help.cur
Binary files differ
diff --git a/vcl/win/source/src/hshear.cur b/vcl/win/source/src/hshear.cur
new file mode 100644
index 000000000000..5cf2211458c3
--- /dev/null
+++ b/vcl/win/source/src/hshear.cur
Binary files differ
diff --git a/vcl/win/source/src/hsize.cur b/vcl/win/source/src/hsize.cur
new file mode 100644
index 000000000000..571dd0ef703c
--- /dev/null
+++ b/vcl/win/source/src/hsize.cur
Binary files differ
diff --git a/vcl/win/source/src/hsizebar.cur b/vcl/win/source/src/hsizebar.cur
new file mode 100644
index 000000000000..dda3483bb5d4
--- /dev/null
+++ b/vcl/win/source/src/hsizebar.cur
Binary files differ
diff --git a/vcl/win/source/src/hsplit.cur b/vcl/win/source/src/hsplit.cur
new file mode 100644
index 000000000000..f2f0be363d3a
--- /dev/null
+++ b/vcl/win/source/src/hsplit.cur
Binary files differ
diff --git a/vcl/win/source/src/linkdata.cur b/vcl/win/source/src/linkdata.cur
new file mode 100644
index 000000000000..e47c1dea2cec
--- /dev/null
+++ b/vcl/win/source/src/linkdata.cur
Binary files differ
diff --git a/vcl/win/source/src/linkf.cur b/vcl/win/source/src/linkf.cur
new file mode 100644
index 000000000000..6cc498a02610
--- /dev/null
+++ b/vcl/win/source/src/linkf.cur
Binary files differ
diff --git a/vcl/win/source/src/magnify.cur b/vcl/win/source/src/magnify.cur
new file mode 100644
index 000000000000..1e32b92351af
--- /dev/null
+++ b/vcl/win/source/src/magnify.cur
Binary files differ
diff --git a/vcl/win/source/src/mirror.cur b/vcl/win/source/src/mirror.cur
new file mode 100644
index 000000000000..e05eb836eb5d
--- /dev/null
+++ b/vcl/win/source/src/mirror.cur
Binary files differ
diff --git a/vcl/win/source/src/move.cur b/vcl/win/source/src/move.cur
new file mode 100644
index 000000000000..a407a1298ad5
--- /dev/null
+++ b/vcl/win/source/src/move.cur
Binary files differ
diff --git a/vcl/win/source/src/movebw.cur b/vcl/win/source/src/movebw.cur
new file mode 100644
index 000000000000..d079eb9fe20d
--- /dev/null
+++ b/vcl/win/source/src/movebw.cur
Binary files differ
diff --git a/vcl/win/source/src/movedata.cur b/vcl/win/source/src/movedata.cur
new file mode 100644
index 000000000000..4d67cbe47149
--- /dev/null
+++ b/vcl/win/source/src/movedata.cur
Binary files differ
diff --git a/vcl/win/source/src/movedlnk.cur b/vcl/win/source/src/movedlnk.cur
new file mode 100644
index 000000000000..1bb7b0306406
--- /dev/null
+++ b/vcl/win/source/src/movedlnk.cur
Binary files differ
diff --git a/vcl/win/source/src/movef.cur b/vcl/win/source/src/movef.cur
new file mode 100644
index 000000000000..6abee2381dcf
--- /dev/null
+++ b/vcl/win/source/src/movef.cur
Binary files differ
diff --git a/vcl/win/source/src/movef2.cur b/vcl/win/source/src/movef2.cur
new file mode 100644
index 000000000000..d044981a3ffd
--- /dev/null
+++ b/vcl/win/source/src/movef2.cur
Binary files differ
diff --git a/vcl/win/source/src/moveflnk.cur b/vcl/win/source/src/moveflnk.cur
new file mode 100644
index 000000000000..630fa1bc3e4e
--- /dev/null
+++ b/vcl/win/source/src/moveflnk.cur
Binary files differ
diff --git a/vcl/win/source/src/movept.cur b/vcl/win/source/src/movept.cur
new file mode 100644
index 000000000000..81d3af5a05c4
--- /dev/null
+++ b/vcl/win/source/src/movept.cur
Binary files differ
diff --git a/vcl/win/source/src/neswsize.cur b/vcl/win/source/src/neswsize.cur
new file mode 100644
index 000000000000..c38501ee15a8
--- /dev/null
+++ b/vcl/win/source/src/neswsize.cur
Binary files differ
diff --git a/vcl/win/source/src/notallow.cur b/vcl/win/source/src/notallow.cur
new file mode 100644
index 000000000000..90c1dfbb3a97
--- /dev/null
+++ b/vcl/win/source/src/notallow.cur
Binary files differ
diff --git a/vcl/win/source/src/nullptr.cur b/vcl/win/source/src/nullptr.cur
new file mode 100644
index 000000000000..28dbb2a903f2
--- /dev/null
+++ b/vcl/win/source/src/nullptr.cur
Binary files differ
diff --git a/vcl/win/source/src/nwsesize.cur b/vcl/win/source/src/nwsesize.cur
new file mode 100644
index 000000000000..570cbbb571cc
--- /dev/null
+++ b/vcl/win/source/src/nwsesize.cur
Binary files differ
diff --git a/vcl/win/source/src/pen.cur b/vcl/win/source/src/pen.cur
new file mode 100644
index 000000000000..040c5dc703e9
--- /dev/null
+++ b/vcl/win/source/src/pen.cur
Binary files differ
diff --git a/vcl/win/source/src/pivotcol.cur b/vcl/win/source/src/pivotcol.cur
new file mode 100644
index 000000000000..061b3ba92644
--- /dev/null
+++ b/vcl/win/source/src/pivotcol.cur
Binary files differ
diff --git a/vcl/win/source/src/pivotdel.cur b/vcl/win/source/src/pivotdel.cur
new file mode 100644
index 000000000000..4497dacd9983
--- /dev/null
+++ b/vcl/win/source/src/pivotdel.cur
Binary files differ
diff --git a/vcl/win/source/src/pivotfld.cur b/vcl/win/source/src/pivotfld.cur
new file mode 100644
index 000000000000..efbbead8930c
--- /dev/null
+++ b/vcl/win/source/src/pivotfld.cur
Binary files differ
diff --git a/vcl/win/source/src/pivotrow.cur b/vcl/win/source/src/pivotrow.cur
new file mode 100644
index 000000000000..649444e9e132
--- /dev/null
+++ b/vcl/win/source/src/pivotrow.cur
Binary files differ
diff --git a/vcl/win/source/src/pntbrsh.cur b/vcl/win/source/src/pntbrsh.cur
new file mode 100644
index 000000000000..517d114237c1
--- /dev/null
+++ b/vcl/win/source/src/pntbrsh.cur
Binary files differ
diff --git a/vcl/win/source/src/refhand.cur b/vcl/win/source/src/refhand.cur
new file mode 100644
index 000000000000..a654974c6f8b
--- /dev/null
+++ b/vcl/win/source/src/refhand.cur
Binary files differ
diff --git a/vcl/win/source/src/rotate.cur b/vcl/win/source/src/rotate.cur
new file mode 100644
index 000000000000..43c2a54a10ac
--- /dev/null
+++ b/vcl/win/source/src/rotate.cur
Binary files differ
diff --git a/vcl/win/source/src/salsrc.rc b/vcl/win/source/src/salsrc.rc
new file mode 100644
index 000000000000..1db1bfc910cf
--- /dev/null
+++ b/vcl/win/source/src/salsrc.rc
@@ -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.
+ *
+**************************************************************************/
+
+// for WINVER
+#include <windows.h>
+
+#ifndef _SV_SALIDS_HRC
+#include <salids.hrc>
+#endif
+
+SAL_RESID_POINTER_NULL CURSOR NULLPTR.CUR
+#if ( WINVER < 0x0400 )
+SAL_RESID_POINTER_HELP CURSOR HELP.CUR
+#endif
+#ifndef WNT
+SAL_RESID_POINTER_HSIZE CURSOR HSIZE.CUR
+SAL_RESID_POINTER_VSIZE CURSOR VSIZE.CUR
+SAL_RESID_POINTER_NESWSIZE CURSOR NESWSIZE.CUR
+SAL_RESID_POINTER_NWSESIZE CURSOR NWSESIZE.CUR
+#endif
+SAL_RESID_POINTER_CROSS CURSOR CROSS.CUR
+SAL_RESID_POINTER_MOVE CURSOR MOVE.CUR
+SAL_RESID_POINTER_HSPLIT CURSOR HSPLIT.CUR
+SAL_RESID_POINTER_VSPLIT CURSOR VSPLIT.CUR
+SAL_RESID_POINTER_HSIZEBAR CURSOR HSIZEBAR.CUR
+SAL_RESID_POINTER_VSIZEBAR CURSOR VSIZEBAR.CUR
+SAL_RESID_POINTER_HAND CURSOR HAND.CUR
+SAL_RESID_POINTER_REFHAND CURSOR REFHAND.CUR
+SAL_RESID_POINTER_PEN CURSOR PEN.CUR
+SAL_RESID_POINTER_MAGNIFY CURSOR MAGNIFY.CUR
+SAL_RESID_POINTER_FILL CURSOR FILL.CUR
+SAL_RESID_POINTER_ROTATE CURSOR ROTATE.CUR
+SAL_RESID_POINTER_HSHEAR CURSOR HSHEAR.CUR
+SAL_RESID_POINTER_VSHEAR CURSOR VSHEAR.CUR
+SAL_RESID_POINTER_MIRROR CURSOR MIRROR.CUR
+SAL_RESID_POINTER_CROOK CURSOR CROOK.CUR
+SAL_RESID_POINTER_CROP CURSOR CROP.CUR
+SAL_RESID_POINTER_MOVEPOINT CURSOR MOVEPT.CUR
+SAL_RESID_POINTER_MOVEBEZIERWEIGHT CURSOR MOVEBW.CUR
+SAL_RESID_POINTER_MOVEDATA CURSOR MOVEDATA.CUR
+SAL_RESID_POINTER_COPYDATA CURSOR COPYDATA.CUR
+SAL_RESID_POINTER_LINKDATA CURSOR LINKDATA.CUR
+SAL_RESID_POINTER_MOVEDATALINK CURSOR MOVEDLNK.CUR
+SAL_RESID_POINTER_COPYDATALINK CURSOR COPYDLNK.CUR
+SAL_RESID_POINTER_MOVEFILE CURSOR MOVEF.CUR
+SAL_RESID_POINTER_COPYFILE CURSOR COPYF.CUR
+SAL_RESID_POINTER_LINKFILE CURSOR LINKF.CUR
+SAL_RESID_POINTER_MOVEFILELINK CURSOR MOVEFLNK.CUR
+SAL_RESID_POINTER_COPYFILELINK CURSOR COPYFLNK.CUR
+SAL_RESID_POINTER_MOVEFILES CURSOR MOVEF2.CUR
+SAL_RESID_POINTER_COPYFILES CURSOR COPYF2.CUR
+SAL_RESID_POINTER_NOTALLOWED CURSOR NOTALLOW.CUR
+SAL_RESID_POINTER_DRAW_LINE CURSOR DLINE.CUR
+SAL_RESID_POINTER_DRAW_RECT CURSOR DRECT.CUR
+SAL_RESID_POINTER_DRAW_POLYGON CURSOR DPOLYGON.CUR
+SAL_RESID_POINTER_DRAW_BEZIER CURSOR DBEZIER.CUR
+SAL_RESID_POINTER_DRAW_ARC CURSOR DARC.CUR
+SAL_RESID_POINTER_DRAW_PIE CURSOR DPIE.CUR
+SAL_RESID_POINTER_DRAW_CIRCLECUT CURSOR DCIRCCUT.CUR
+SAL_RESID_POINTER_DRAW_ELLIPSE CURSOR DELLIPSE.CUR
+SAL_RESID_POINTER_DRAW_FREEHAND CURSOR DFREE.CUR
+SAL_RESID_POINTER_DRAW_CONNECT CURSOR DCONNECT.CUR
+SAL_RESID_POINTER_DRAW_TEXT CURSOR DTEXT.CUR
+SAL_RESID_POINTER_DRAW_CAPTION CURSOR DCAPT.CUR
+SAL_RESID_POINTER_CHART CURSOR CHART.CUR
+SAL_RESID_POINTER_DETECTIVE CURSOR DETECTIV.CUR
+SAL_RESID_POINTER_PIVOT_COL CURSOR PIVOTCOL.CUR
+SAL_RESID_POINTER_PIVOT_ROW CURSOR PIVOTROW.CUR
+SAL_RESID_POINTER_PIVOT_FIELD CURSOR PIVOTFLD.CUR
+SAL_RESID_POINTER_PIVOT_DELETE CURSOR PIVOTDEL.CUR
+SAL_RESID_POINTER_CHAIN CURSOR CHAIN.CUR
+SAL_RESID_POINTER_CHAIN_NOTALLOWED CURSOR CHAINNOT.CUR
+SAL_RESID_POINTER_TIMEEVENT_MOVE CURSOR TIMEMOVE.CUR
+SAL_RESID_POINTER_TIMEEVENT_SIZE CURSOR TIMESIZE.CUR
+SAL_RESID_POINTER_AUTOSCROLL_N CURSOR ASN.CUR
+SAL_RESID_POINTER_AUTOSCROLL_S CURSOR ASS.CUR
+SAL_RESID_POINTER_AUTOSCROLL_W CURSOR ASW.CUR
+SAL_RESID_POINTER_AUTOSCROLL_E CURSOR ASE.CUR
+SAL_RESID_POINTER_AUTOSCROLL_NW CURSOR ASNW.CUR
+SAL_RESID_POINTER_AUTOSCROLL_NE CURSOR ASNE.CUR
+SAL_RESID_POINTER_AUTOSCROLL_SW CURSOR ASSW.CUR
+SAL_RESID_POINTER_AUTOSCROLL_SE CURSOR ASSE.CUR
+SAL_RESID_POINTER_AUTOSCROLL_NS CURSOR ASNS.CUR
+SAL_RESID_POINTER_AUTOSCROLL_WE CURSOR ASWE.CUR
+SAL_RESID_POINTER_AUTOSCROLL_NSWE CURSOR ASNSWE.CUR
+SAL_RESID_POINTER_AIRBRUSH CURSOR AIRBRUSH.CUR
+SAL_RESID_POINTER_TEXT_VERTICAL CURSOR VTEXT.CUR
+SAL_RESID_POINTER_TAB_SELECT_S CURSOR TBLSELS.CUR
+SAL_RESID_POINTER_TAB_SELECT_E CURSOR TBLSELE.CUR
+SAL_RESID_POINTER_TAB_SELECT_SE CURSOR TBLSELSE.CUR
+SAL_RESID_POINTER_TAB_SELECT_W CURSOR TBLSELW.CUR
+SAL_RESID_POINTER_TAB_SELECT_SW CURSOR TBLSELSW.CUR
+SAL_RESID_POINTER_PAINTBRUSH CURSOR PNTBRSH.CUR
+
+SAL_RESID_BITMAP_50 BITMAP 50.BMP
+
+SAL_RESID_ICON_DEFAULT ICON SD.ICO
diff --git a/vcl/win/source/src/sd.ico b/vcl/win/source/src/sd.ico
new file mode 100644
index 000000000000..b2a0a07a67c3
--- /dev/null
+++ b/vcl/win/source/src/sd.ico
Binary files differ
diff --git a/vcl/win/source/src/tblsele.cur b/vcl/win/source/src/tblsele.cur
new file mode 100644
index 000000000000..3683e20df112
--- /dev/null
+++ b/vcl/win/source/src/tblsele.cur
Binary files differ
diff --git a/vcl/win/source/src/tblsels.cur b/vcl/win/source/src/tblsels.cur
new file mode 100644
index 000000000000..007182d734de
--- /dev/null
+++ b/vcl/win/source/src/tblsels.cur
Binary files differ
diff --git a/vcl/win/source/src/tblselse.cur b/vcl/win/source/src/tblselse.cur
new file mode 100644
index 000000000000..986f0139501a
--- /dev/null
+++ b/vcl/win/source/src/tblselse.cur
Binary files differ
diff --git a/vcl/win/source/src/tblselsw.cur b/vcl/win/source/src/tblselsw.cur
new file mode 100644
index 000000000000..adabba1a2adc
--- /dev/null
+++ b/vcl/win/source/src/tblselsw.cur
Binary files differ
diff --git a/vcl/win/source/src/tblselw.cur b/vcl/win/source/src/tblselw.cur
new file mode 100644
index 000000000000..a95eb85af49a
--- /dev/null
+++ b/vcl/win/source/src/tblselw.cur
Binary files differ
diff --git a/vcl/win/source/src/timemove.cur b/vcl/win/source/src/timemove.cur
new file mode 100755
index 000000000000..319b6edc5774
--- /dev/null
+++ b/vcl/win/source/src/timemove.cur
Binary files differ
diff --git a/vcl/win/source/src/timesize.cur b/vcl/win/source/src/timesize.cur
new file mode 100755
index 000000000000..1ec23de05b71
--- /dev/null
+++ b/vcl/win/source/src/timesize.cur
Binary files differ
diff --git a/vcl/win/source/src/vshear.cur b/vcl/win/source/src/vshear.cur
new file mode 100644
index 000000000000..a4bbf7e8eb00
--- /dev/null
+++ b/vcl/win/source/src/vshear.cur
Binary files differ
diff --git a/vcl/win/source/src/vsize.cur b/vcl/win/source/src/vsize.cur
new file mode 100644
index 000000000000..76449be89d0a
--- /dev/null
+++ b/vcl/win/source/src/vsize.cur
Binary files differ
diff --git a/vcl/win/source/src/vsizebar.cur b/vcl/win/source/src/vsizebar.cur
new file mode 100644
index 000000000000..a87811cb474d
--- /dev/null
+++ b/vcl/win/source/src/vsizebar.cur
Binary files differ
diff --git a/vcl/win/source/src/vsplit.cur b/vcl/win/source/src/vsplit.cur
new file mode 100644
index 000000000000..a4260808fadc
--- /dev/null
+++ b/vcl/win/source/src/vsplit.cur
Binary files differ
diff --git a/vcl/win/source/src/vtext.cur b/vcl/win/source/src/vtext.cur
new file mode 100644
index 000000000000..776177901e11
--- /dev/null
+++ b/vcl/win/source/src/vtext.cur
Binary files differ
diff --git a/vcl/win/source/window/MAKEFILE.MK b/vcl/win/source/window/MAKEFILE.MK
new file mode 100644
index 000000000000..cecfbcf5b2e5
--- /dev/null
+++ b/vcl/win/source/window/MAKEFILE.MK
@@ -0,0 +1,60 @@
+#*************************************************************************
+#
+# 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=salwin
+ENABLE_EXCEPTIONS=TRUE
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/makefile2.pmk
+
+# --- #105371#
+CDEFS +=-U_WIN32_WINNT -D_WIN32_WINNT=0x0501
+
+# --- Files --------------------------------------------------------
+
+SLOFILES= \
+ $(SLO)$/salframe.obj \
+ $(SLO)$/salmenu.obj \
+ $(SLO)$/salobj.obj
+
+.IF "$(COM)"=="GCC"
+EXCEPTIONSFILES= $(SLO)$/salframe.obj
+.ENDIF
+
+.IF "$(ENABLE_GRAPHITE)" == "TRUE"
+CFLAGS+=-DENABLE_GRAPHITE
+.ENDIF
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
diff --git a/vcl/win/source/window/salframe.cxx b/vcl/win/source/window/salframe.cxx
new file mode 100644
index 000000000000..7314fd2b6164
--- /dev/null
+++ b/vcl/win/source/window/salframe.cxx
@@ -0,0 +1,6440 @@
+/*************************************************************************
+ *
+ * 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"
+
+// i72022: ad-hoc to forcibly enable reconversion
+#if WINVER < 0x0500
+#undef WINVER
+#define WINVER 0x0500
+#endif
+
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <comphelper/processfactory.hxx>
+#include <unotools/misccfg.hxx>
+
+#include <string.h>
+#include <limits.h>
+
+#include <stdio.h>
+
+#ifndef _SVWIN_HXX
+#include <tools/svwin.h>
+#endif
+#ifdef __MINGW32__
+#include <excpt.h>
+#endif
+#include <rtl/string.h>
+#include <rtl/ustring.h>
+
+#include <osl/module.h>
+#include <tools/debug.hxx>
+
+// Warning in SDK header
+#if defined(_MSC_VER) && (_MSC_VER > 1400)
+#pragma warning( disable: 4242 4244 )
+#endif
+#include <wincomp.hxx>
+#ifndef _SV_SALIDS_HRC
+#include <salids.hrc>
+#endif
+#include <vcl/sysdata.hxx>
+#include <saldata.hxx>
+#include <salinst.h>
+#include <salbmp.h>
+#include <salgdi.h>
+#include <salsys.h>
+#include <salframe.h>
+#include <salvd.h>
+#include <salmenu.h>
+#include <salobj.h>
+#include <vcl/impbmp.hxx>
+#include <vcl/timer.hxx>
+#include <saltimer.h>
+#include <vcl/settings.hxx>
+#ifndef _SV_KEYCOES_HXX
+#include <vcl/keycodes.hxx>
+#endif
+#include <vcl/window.h>
+#include <vcl/window.hxx>
+#include <vcl/wrkwin.hxx>
+#include <vcl/sallayout.hxx>
+#include <vcl/svapp.hxx>
+#ifndef _VCL_IMPDEL_HXX
+#include <impdel.hxx>
+#endif
+#define COMPILE_MULTIMON_STUBS
+#include <multimon.h>
+#include <vector>
+#ifdef __MINGW32__
+#include <algorithm>
+using ::std::max;
+#endif
+
+#include <com/sun/star/uno/Exception.hdl>
+
+#include <time.h>
+
+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;
+
+// The following defines are newly added in Longhorn
+#ifndef WM_MOUSEHWHEEL
+# define WM_MOUSEHWHEEL 0x020E
+#endif
+#ifndef SPI_GETWHEELSCROLLCHARS
+# define SPI_GETWHEELSCROLLCHARS 0x006C
+#endif
+#ifndef SPI_SETWHEELSCROLLCHARS
+# define SPI_SETWHEELSCROLLCHARS 0x006D
+#endif
+
+
+
+#if OSL_DEBUG_LEVEL > 1
+void MyOutputDebugString( char *s) { OutputDebugString( s ); }
+#endif
+
+// misssing prototypes and constants for LayeredWindows
+extern "C" {
+ //WINUSERAPI BOOL WINAPI SetLayeredWindowAttributes(HWND,COLORREF,BYTE,DWORD);
+ typedef BOOL ( WINAPI * SetLayeredWindowAttributes_Proc_T ) (HWND,COLORREF,BYTE,DWORD);
+ static SetLayeredWindowAttributes_Proc_T lpfnSetLayeredWindowAttributes;
+};
+
+// =======================================================================
+
+const unsigned int WM_USER_SYSTEM_WINDOW_ACTIVATED = RegisterWindowMessageA("SYSTEM_WINDOW_ACTIVATED");
+
+BOOL WinSalFrame::mbInReparent = FALSE;
+
+// =======================================================================
+
+// Wegen Fehler in Windows-Headerfiles
+#ifndef IMN_OPENCANDIDATE
+#define IMN_OPENCANDIDATE 0x0005
+#endif
+#ifndef IMN_CLOSECANDIDATE
+#define IMN_CLOSECANDIDATE 0x0004
+#endif
+
+#ifndef WM_THEMECHANGED
+#define WM_THEMECHANGED 0x031A
+#endif
+
+// Macros for support of WM_UNICHAR & Keyman 6.0
+#define Uni_UTF32ToSurrogate1(ch) (((unsigned long) (ch) - 0x10000) / 0x400 + 0xD800)
+#define Uni_UTF32ToSurrogate2(ch) (((unsigned long) (ch) - 0x10000) % 0x400 + 0xDC00)
+#define Uni_SupplementaryPlanesStart 0x10000
+
+// =======================================================================
+
+static void UpdateFrameGeometry( HWND hWnd, WinSalFrame* pFrame );
+static void SetMaximizedFrameGeometry( HWND hWnd, WinSalFrame* pFrame );
+
+static void ImplSaveFrameState( WinSalFrame* pFrame )
+{
+ // Position, Groesse und Status fuer GetWindowState() merken
+ if ( !pFrame->mbFullScreen )
+ {
+ BOOL bVisible = (GetWindowStyle( pFrame->mhWnd ) & WS_VISIBLE) != 0;
+ if ( IsIconic( pFrame->mhWnd ) )
+ {
+ pFrame->maState.mnState |= SAL_FRAMESTATE_MINIMIZED;
+ if ( bVisible )
+ pFrame->mnShowState = SW_SHOWMAXIMIZED;
+ }
+ else if ( IsZoomed( pFrame->mhWnd ) )
+ {
+ pFrame->maState.mnState &= ~SAL_FRAMESTATE_MINIMIZED;
+ pFrame->maState.mnState |= SAL_FRAMESTATE_MAXIMIZED;
+ if ( bVisible )
+ pFrame->mnShowState = SW_SHOWMAXIMIZED;
+ pFrame->mbRestoreMaximize = TRUE;
+ }
+ else
+ {
+ RECT aRect;
+ GetWindowRect( pFrame->mhWnd, &aRect );
+
+ // to be consistent with Unix, the frame state is without(!) decoration
+ RECT aRect2 = aRect;
+ AdjustWindowRectEx( &aRect2, GetWindowStyle( pFrame->mhWnd ),
+ FALSE, GetWindowExStyle( pFrame->mhWnd ) );
+ long nTopDeco = abs( aRect.top - aRect2.top );
+ long nLeftDeco = abs( aRect.left - aRect2.left );
+ long nBottomDeco = abs( aRect.bottom - aRect2.bottom );
+ long nRightDeco = abs( aRect.right - aRect2.right );
+
+ pFrame->maState.mnState &= ~(SAL_FRAMESTATE_MINIMIZED | SAL_FRAMESTATE_MAXIMIZED);
+ // subtract decoration
+ pFrame->maState.mnX = aRect.left+nLeftDeco;
+ pFrame->maState.mnY = aRect.top+nTopDeco;
+ pFrame->maState.mnWidth = aRect.right-aRect.left-nLeftDeco-nRightDeco;
+ pFrame->maState.mnHeight = aRect.bottom-aRect.top-nTopDeco-nBottomDeco;
+ if ( bVisible )
+ pFrame->mnShowState = SW_SHOWNORMAL;
+ pFrame->mbRestoreMaximize = FALSE;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+// if pParentRect is set, the workarea of the monitor that contains pParentRect is returned
+void ImplSalGetWorkArea( HWND hWnd, RECT *pRect, const RECT *pParentRect )
+{
+ static int winVerChecked = 0;
+ static int winVerOk = 0;
+
+ // check if we or our parent is fullscreen, then the taskbar should be ignored
+ bool bIgnoreTaskbar = false;
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if( pFrame )
+ {
+ Window *pWin = pFrame->GetWindow();
+ while( pWin )
+ {
+ WorkWindow *pWorkWin = (pWin->GetType() == WINDOW_WORKWINDOW) ? (WorkWindow *) pWin : NULL;
+ if( pWorkWin && pWorkWin->ImplGetWindowImpl()->mbReallyVisible && pWorkWin->IsFullScreenMode() )
+ {
+ bIgnoreTaskbar = true;
+ break;
+ }
+ else
+ pWin = pWin->ImplGetWindowImpl()->mpParent;
+ }
+ }
+
+ if( !winVerChecked )
+ {
+ winVerChecked = 1;
+ winVerOk = 1;
+
+ // multi monitor calls not available on Win95/NT
+ if ( aSalShlData.maVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
+ {
+ if ( aSalShlData.maVersionInfo.dwMajorVersion <= 4 )
+ winVerOk = 0; // NT
+ }
+ else if( aSalShlData.maVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
+ {
+ if ( aSalShlData.maVersionInfo.dwMajorVersion == 4 && aSalShlData.maVersionInfo.dwMinorVersion == 0 )
+ winVerOk = 0; // Win95
+ }
+ }
+
+ // calculates the work area taking multiple monitors into account
+ if( winVerOk )
+ {
+ static int nMonitors = GetSystemMetrics( SM_CMONITORS );
+ if( nMonitors == 1 )
+ {
+ if( bIgnoreTaskbar )
+ {
+ pRect->left = pRect->top = 0;
+ pRect->right = GetSystemMetrics( SM_CXSCREEN );
+ pRect->bottom = GetSystemMetrics( SM_CYSCREEN );
+ }
+ else
+ SystemParametersInfo( SPI_GETWORKAREA, 0, pRect, 0 );
+ }
+ else
+ {
+ if( pParentRect != NULL )
+ {
+ // return the size of the monitor where pParentRect lives
+ HMONITOR hMonitor;
+ MONITORINFO mi;
+
+ // get the nearest monitor to the passed rect.
+ hMonitor = MonitorFromRect(pParentRect, MONITOR_DEFAULTTONEAREST);
+
+ // get the work area or entire monitor rect.
+ mi.cbSize = sizeof(mi);
+ GetMonitorInfo(hMonitor, &mi);
+ if( !bIgnoreTaskbar )
+ *pRect = mi.rcWork;
+ else
+ *pRect = mi.rcMonitor;
+ }
+ else
+ {
+ // return the union of all monitors
+ pRect->left = GetSystemMetrics( SM_XVIRTUALSCREEN );
+ pRect->top = GetSystemMetrics( SM_YVIRTUALSCREEN );
+ pRect->right = pRect->left + GetSystemMetrics( SM_CXVIRTUALSCREEN );
+ pRect->bottom = pRect->top + GetSystemMetrics( SM_CYVIRTUALSCREEN );
+
+ // virtualscreen does not take taskbar into account, so use the corresponding
+ // diffs between screen and workarea from the default screen
+ // however, this is still not perfect: the taskbar might not be on the primary screen
+ if( !bIgnoreTaskbar )
+ {
+ RECT wRect, scrRect;
+ SystemParametersInfo( SPI_GETWORKAREA, 0, &wRect, 0 );
+ scrRect.left = 0;
+ scrRect.top = 0;
+ scrRect.right = GetSystemMetrics( SM_CXSCREEN );
+ scrRect.bottom = GetSystemMetrics( SM_CYSCREEN );
+
+ pRect->left += wRect.left;
+ pRect->top += wRect.top;
+ pRect->right -= scrRect.right - wRect.right;
+ pRect->bottom -= scrRect.bottom - wRect.bottom;
+ }
+ }
+ }
+ }
+ else
+ {
+ if( bIgnoreTaskbar )
+ {
+ pRect->left = pRect->top = 0;
+ pRect->right = GetSystemMetrics( SM_CXSCREEN );
+ pRect->bottom = GetSystemMetrics( SM_CYSCREEN );
+ }
+ else
+ SystemParametersInfo( SPI_GETWORKAREA, 0, pRect, 0 );
+ }
+}
+
+// =======================================================================
+
+SalFrame* ImplSalCreateFrame( WinSalInstance* pInst,
+ HWND hWndParent, ULONG nSalFrameStyle )
+{
+ WinSalFrame* pFrame = new WinSalFrame;
+ HWND hWnd;
+ DWORD nSysStyle = 0;
+ DWORD nExSysStyle = 0;
+ BOOL bSubFrame = FALSE;
+
+ if( getenv( "SAL_SYNCHRONIZE" ) ) // no buffering of drawing commands
+ GdiSetBatchLimit( 1 );
+
+ static int bLayeredAPI = -1;
+ if( bLayeredAPI == -1 )
+ {
+ bLayeredAPI = 0;
+ // check for W2k and XP
+ if ( aSalShlData.maVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT && aSalShlData.maVersionInfo.dwMajorVersion >= 5 )
+ {
+ OUString aLibraryName( RTL_CONSTASCII_USTRINGPARAM( "user32" ) );
+ oslModule pLib = osl_loadModule( aLibraryName.pData, SAL_LOADMODULE_DEFAULT );
+ oslGenericFunction pFunc = NULL;
+ if( pLib )
+ pFunc = osl_getAsciiFunctionSymbol( pLib, "SetLayeredWindowAttributes" );
+
+ lpfnSetLayeredWindowAttributes = ( SetLayeredWindowAttributes_Proc_T ) pFunc;
+
+ bLayeredAPI = pFunc ? 1 : 0;
+ }
+ }
+ static const char* pEnvTransparentFloats = getenv("SAL_TRANSPARENT_FLOATS" );
+
+ // determine creation data
+ if ( nSalFrameStyle & (SAL_FRAME_STYLE_PLUG | SAL_FRAME_STYLE_SYSTEMCHILD) )
+ {
+ nSysStyle |= WS_CHILD;
+ if( nSalFrameStyle & SAL_FRAME_STYLE_SYSTEMCHILD )
+ nSysStyle |= WS_CLIPSIBLINGS;
+ }
+ else
+ {
+ // #i87402# commenting out WS_CLIPCHILDREN
+ // this breaks SAL_FRAME_STYLE_SYSTEMCHILD handling, which is not
+ // used currently. Probably SAL_FRAME_STYLE_SYSTEMCHILD should be
+ // removed again.
+
+ // nSysStyle |= WS_CLIPCHILDREN;
+ if ( hWndParent )
+ {
+ nSysStyle |= WS_POPUP;
+ bSubFrame = TRUE;
+ pFrame->mbNoIcon = TRUE;
+ }
+ else
+ {
+ // Only with WS_OVRLAPPED we get a useful default position/size
+ if ( (nSalFrameStyle & (SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_MOVEABLE)) ==
+ (SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_MOVEABLE) )
+ nSysStyle |= WS_OVERLAPPED;
+ else
+ {
+ nSysStyle |= WS_POPUP;
+ if ( !(nSalFrameStyle & SAL_FRAME_STYLE_MOVEABLE) )
+ nExSysStyle |= WS_EX_TOOLWINDOW; // avoid taskbar appearance, for eg splash screen
+ }
+ }
+
+ if ( nSalFrameStyle & SAL_FRAME_STYLE_MOVEABLE )
+ {
+ pFrame->mbCaption = TRUE;
+ nSysStyle |= WS_SYSMENU | WS_CAPTION;
+ if ( !hWndParent )
+ nSysStyle |= WS_SYSMENU | WS_MINIMIZEBOX;
+ else
+ nExSysStyle |= WS_EX_DLGMODALFRAME;
+
+ if ( nSalFrameStyle & SAL_FRAME_STYLE_SIZEABLE )
+ {
+ pFrame->mbSizeBorder = TRUE;
+ nSysStyle |= WS_THICKFRAME;
+ if ( !hWndParent )
+ nSysStyle |= WS_MAXIMIZEBOX;
+ }
+ else
+ pFrame->mbFixBorder = TRUE;
+
+ if ( nSalFrameStyle & SAL_FRAME_STYLE_DEFAULT )
+ nExSysStyle |= WS_EX_APPWINDOW;
+ }
+ if( nSalFrameStyle & SAL_FRAME_STYLE_TOOLWINDOW
+ // #100656# toolwindows lead to bad alt-tab behaviour, if they have the focus
+ // you must press it twice to leave the application
+ // so toolwindows are only used for non sizeable windows
+ // which are typically small, so a small caption makes sense
+
+ // #103578# looked too bad - above changes reverted
+ /* && !(nSalFrameStyle & SAL_FRAME_STYLE_SIZEABLE) */ )
+ {
+ pFrame->mbNoIcon = TRUE;
+ nExSysStyle |= WS_EX_TOOLWINDOW;
+ if ( pEnvTransparentFloats && bLayeredAPI == 1 /*&& !(nSalFrameStyle & SAL_FRAME_STYLE_MOVEABLE) */)
+ nExSysStyle |= WS_EX_LAYERED;
+ }
+ }
+ if ( nSalFrameStyle & SAL_FRAME_STYLE_FLOAT )
+ {
+ nExSysStyle |= WS_EX_TOOLWINDOW;
+ pFrame->mbFloatWin = TRUE;
+
+ if ( (bLayeredAPI == 1) && (pEnvTransparentFloats /* does not work remote! || (nSalFrameStyle & SAL_FRAME_STYLE_FLOAT_FOCUSABLE) */ ) )
+ nExSysStyle |= WS_EX_LAYERED;
+
+ }
+ if( (nSalFrameStyle & SAL_FRAME_STYLE_TOOLTIP) || (nSalFrameStyle & SAL_FRAME_STYLE_FLOAT_FOCUSABLE) )
+ nExSysStyle |= WS_EX_TOPMOST;
+
+ // init frame data
+ pFrame->mnStyle = nSalFrameStyle;
+
+ // determine show style
+ pFrame->mnShowState = SW_SHOWNORMAL;
+ if ( (nSysStyle & (WS_POPUP | WS_MAXIMIZEBOX | WS_THICKFRAME)) == (WS_MAXIMIZEBOX | WS_THICKFRAME) )
+ {
+ if ( GetSystemMetrics( SM_CXSCREEN ) <= 1024 )
+ pFrame->mnShowState = SW_SHOWMAXIMIZED;
+ else
+ {
+ if ( nSalFrameStyle & SAL_FRAME_STYLE_DEFAULT )
+ {
+ SalData* pSalData = GetSalData();
+ pFrame->mnShowState = pSalData->mnCmdShow;
+ if ( (pFrame->mnShowState != SW_SHOWMINIMIZED) &&
+ (pFrame->mnShowState != SW_MINIMIZE) &&
+ (pFrame->mnShowState != SW_SHOWMINNOACTIVE) )
+ {
+ if ( (pFrame->mnShowState == SW_SHOWMAXIMIZED) ||
+ (pFrame->mnShowState == SW_MAXIMIZE) )
+ pFrame->mbOverwriteState = FALSE;
+ pFrame->mnShowState = SW_SHOWMAXIMIZED;
+ }
+ else
+ pFrame->mbOverwriteState = FALSE;
+ }
+ else
+ {
+ // Document Windows are also maximized, if the current Document Window
+ // is also maximized
+ HWND hWnd = GetForegroundWindow();
+ if ( hWnd && IsMaximized( hWnd ) &&
+ (GetWindowInstance( hWnd ) == pInst->mhInst) &&
+ ((GetWindowStyle( hWnd ) & (WS_POPUP | WS_MAXIMIZEBOX | WS_THICKFRAME)) == (WS_MAXIMIZEBOX | WS_THICKFRAME)) )
+ pFrame->mnShowState = SW_SHOWMAXIMIZED;
+ }
+ }
+ }
+
+ // create frame
+ if ( aSalShlData.mbWNT )
+ {
+ LPCWSTR pClassName;
+ if ( bSubFrame )
+ {
+ if ( nSalFrameStyle & (SAL_FRAME_STYLE_MOVEABLE|SAL_FRAME_STYLE_NOSHADOW) ) // check if shadow not wanted
+ pClassName = SAL_SUBFRAME_CLASSNAMEW;
+ else
+ pClassName = SAL_TMPSUBFRAME_CLASSNAMEW; // undecorated floaters will get shadow on XP
+ }
+ else
+ {
+ if ( nSalFrameStyle & SAL_FRAME_STYLE_MOVEABLE )
+ pClassName = SAL_FRAME_CLASSNAMEW;
+ else
+ pClassName = SAL_TMPSUBFRAME_CLASSNAMEW;
+ }
+ hWnd = CreateWindowExW( nExSysStyle, pClassName, L"", nSysStyle,
+ CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
+ hWndParent, 0, pInst->mhInst, (void*)pFrame );
+ if( !hWnd )
+ ImplWriteLastError( GetLastError(), "CreateWindowEx" );
+#if OSL_DEBUG_LEVEL > 1
+ // set transparency value
+ if( bLayeredAPI == 1 && GetWindowExStyle( hWnd ) & WS_EX_LAYERED )
+ lpfnSetLayeredWindowAttributes( hWnd, 0, 230, 0x00000002 /*LWA_ALPHA*/ );
+#endif
+ }
+ else
+ {
+ LPCSTR pClassName;
+ if ( bSubFrame )
+ pClassName = SAL_SUBFRAME_CLASSNAMEA;
+ else
+ pClassName = SAL_FRAME_CLASSNAMEA;
+ hWnd = CreateWindowExA( nExSysStyle, pClassName, "", nSysStyle,
+ CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
+ hWndParent, 0, pInst->mhInst, (void*)pFrame );
+ }
+ if ( !hWnd )
+ {
+ delete pFrame;
+ return NULL;
+ }
+
+ // If we have an Window with an Caption Bar and without
+ // an MaximizeBox, we change the SystemMenu
+ if ( (nSysStyle & (WS_CAPTION | WS_MAXIMIZEBOX)) == (WS_CAPTION) )
+ {
+ HMENU hSysMenu = GetSystemMenu( hWnd, FALSE );
+ if ( hSysMenu )
+ {
+ if ( !(nSysStyle & (WS_MINIMIZEBOX | WS_MAXIMIZEBOX)) )
+ DeleteMenu( hSysMenu, SC_RESTORE, MF_BYCOMMAND );
+ else
+ EnableMenuItem( hSysMenu, SC_RESTORE, MF_BYCOMMAND | MF_GRAYED | MF_DISABLED );
+ if ( !(nSysStyle & WS_MINIMIZEBOX) )
+ DeleteMenu( hSysMenu, SC_MINIMIZE, MF_BYCOMMAND );
+ if ( !(nSysStyle & WS_MAXIMIZEBOX) )
+ DeleteMenu( hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND );
+ if ( !(nSysStyle & WS_THICKFRAME) )
+ DeleteMenu( hSysMenu, SC_SIZE, MF_BYCOMMAND );
+ }
+ }
+ if ( (nSysStyle & WS_SYSMENU) && !(nSalFrameStyle & SAL_FRAME_STYLE_CLOSEABLE) )
+ {
+ HMENU hSysMenu = GetSystemMenu( hWnd, FALSE );
+ if ( hSysMenu )
+ EnableMenuItem( hSysMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED | MF_DISABLED );
+ }
+
+ // reset input context
+ pFrame->mhDefIMEContext = ImmAssociateContext( hWnd, 0 );
+
+ // determine output size and state
+ RECT aRect;
+ GetClientRect( hWnd, &aRect );
+ pFrame->mnWidth = aRect.right;
+ pFrame->mnHeight = aRect.bottom;
+ ImplSaveFrameState( pFrame );
+ pFrame->mbDefPos = TRUE;
+
+ UpdateFrameGeometry( hWnd, pFrame );
+
+ if( pFrame->mnShowState == SW_SHOWMAXIMIZED )
+ {
+ // #96084 set a useful internal window size because
+ // the window will not be maximized (and the size updated) before show()
+
+ SetMaximizedFrameGeometry( hWnd, pFrame );
+ }
+
+ return pFrame;
+}
+
+// helper that only creates the HWND
+// to allow for easy reparenting of system windows, (i.e. destroy and create new)
+HWND ImplSalReCreateHWND( HWND hWndParent, HWND oldhWnd, BOOL bAsChild )
+{
+ HINSTANCE hInstance = GetSalData()->mhInst;
+ ULONG nSysStyle = GetWindowLong( oldhWnd, GWL_STYLE );
+ ULONG nExSysStyle = GetWindowLong( oldhWnd, GWL_EXSTYLE );
+
+ if( bAsChild )
+ {
+ nSysStyle = WS_CHILD;
+ nExSysStyle = 0;
+ }
+
+ HWND hWnd = NULL;
+ if ( aSalShlData.mbWNT )
+ {
+ LPCWSTR pClassName = SAL_SUBFRAME_CLASSNAMEW;
+ hWnd = CreateWindowExW( nExSysStyle, pClassName, L"", nSysStyle,
+ CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
+ hWndParent, 0, hInstance, (void*)GetWindowPtr( oldhWnd ) );
+ }
+ else
+ {
+ LPCSTR pClassName = SAL_SUBFRAME_CLASSNAMEA;
+ hWnd = CreateWindowExA( nExSysStyle, pClassName, "", nSysStyle,
+ CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
+ hWndParent, 0, hInstance, (void*)GetWindowPtr( oldhWnd ) );
+ }
+ return hWnd;
+}
+
+// =======================================================================
+
+// Uebersetzungstabelle von System-Keycodes in StarView-Keycodes
+#define KEY_TAB_SIZE 146
+
+static USHORT aImplTranslateKeyTab[KEY_TAB_SIZE] =
+{
+ // StarView-Code System-Code Index
+ 0, // 0
+ 0, // VK_LBUTTON 1
+ 0, // VK_RBUTTON 2
+ 0, // VK_CANCEL 3
+ 0, // VK_MBUTTON 4
+ 0, // 5
+ 0, // 6
+ 0, // 7
+ KEY_BACKSPACE, // VK_BACK 8
+ KEY_TAB, // VK_TAB 9
+ 0, // 10
+ 0, // 11
+ 0, // VK_CLEAR 12
+ KEY_RETURN, // VK_RETURN 13
+ 0, // 14
+ 0, // 15
+ 0, // VK_SHIFT 16
+ 0, // VK_CONTROL 17
+ 0, // VK_MENU 18
+ 0, // VK_PAUSE 19
+ 0, // VK_CAPITAL 20
+ 0, // VK_HANGUL 21
+ 0, // 22
+ 0, // 23
+ 0, // 24
+ KEY_HANGUL_HANJA, // VK_HANJA 25
+ 0, // 26
+ KEY_ESCAPE, // VK_ESCAPE 27
+ 0, // 28
+ 0, // 29
+ 0, // 30
+ 0, // 31
+ KEY_SPACE, // VK_SPACE 32
+ KEY_PAGEUP, // VK_PRIOR 33
+ KEY_PAGEDOWN, // VK_NEXT 34
+ KEY_END, // VK_END 35
+ KEY_HOME, // VK_HOME 36
+ KEY_LEFT, // VK_LEFT 37
+ KEY_UP, // VK_UP 38
+ KEY_RIGHT, // VK_RIGHT 39
+ KEY_DOWN, // VK_DOWN 40
+ 0, // VK_SELECT 41
+ 0, // VK_PRINT 42
+ 0, // VK_EXECUTE 43
+ 0, // VK_SNAPSHOT 44
+ KEY_INSERT, // VK_INSERT 45
+ KEY_DELETE, // VK_DELETE 46
+ KEY_HELP, // VK_HELP 47
+ KEY_0, // 48
+ KEY_1, // 49
+ KEY_2, // 50
+ KEY_3, // 51
+ KEY_4, // 52
+ KEY_5, // 53
+ KEY_6, // 54
+ KEY_7, // 55
+ KEY_8, // 56
+ KEY_9, // 57
+ 0, // 58
+ 0, // 59
+ 0, // 60
+ 0, // 61
+ 0, // 62
+ 0, // 63
+ 0, // 64
+ KEY_A, // 65
+ KEY_B, // 66
+ KEY_C, // 67
+ KEY_D, // 68
+ KEY_E, // 69
+ KEY_F, // 70
+ KEY_G, // 71
+ KEY_H, // 72
+ KEY_I, // 73
+ KEY_J, // 74
+ KEY_K, // 75
+ KEY_L, // 76
+ KEY_M, // 77
+ KEY_N, // 78
+ KEY_O, // 79
+ KEY_P, // 80
+ KEY_Q, // 81
+ KEY_R, // 82
+ KEY_S, // 83
+ KEY_T, // 84
+ KEY_U, // 85
+ KEY_V, // 86
+ KEY_W, // 87
+ KEY_X, // 88
+ KEY_Y, // 89
+ KEY_Z, // 90
+ 0, // VK_LWIN 91
+ 0, // VK_RWIN 92
+ KEY_CONTEXTMENU, // VK_APPS 93
+ 0, // 94
+ 0, // 95
+ KEY_0, // VK_NUMPAD0 96
+ KEY_1, // VK_NUMPAD1 97
+ KEY_2, // VK_NUMPAD2 98
+ KEY_3, // VK_NUMPAD3 99
+ KEY_4, // VK_NUMPAD4 100
+ KEY_5, // VK_NUMPAD5 101
+ KEY_6, // VK_NUMPAD6 102
+ KEY_7, // VK_NUMPAD7 103
+ KEY_8, // VK_NUMPAD8 104
+ KEY_9, // VK_NUMPAD9 105
+ KEY_MULTIPLY, // VK_MULTIPLY 106
+ KEY_ADD, // VK_ADD 107
+ KEY_DECIMAL, // VK_SEPARATOR 108
+ KEY_SUBTRACT, // VK_SUBTRACT 109
+ KEY_DECIMAL, // VK_DECIMAL 110
+ KEY_DIVIDE, // VK_DIVIDE 111
+ KEY_F1, // VK_F1 112
+ KEY_F2, // VK_F2 113
+ KEY_F3, // VK_F3 114
+ KEY_F4, // VK_F4 115
+ KEY_F5, // VK_F5 116
+ KEY_F6, // VK_F6 117
+ KEY_F7, // VK_F7 118
+ KEY_F8, // VK_F8 119
+ KEY_F9, // VK_F9 120
+ KEY_F10, // VK_F10 121
+ KEY_F11, // VK_F11 122
+ KEY_F12, // VK_F12 123
+ KEY_F13, // VK_F13 124
+ KEY_F14, // VK_F14 125
+ KEY_F15, // VK_F15 126
+ KEY_F16, // VK_F16 127
+ KEY_F17, // VK_F17 128
+ KEY_F18, // VK_F18 129
+ KEY_F19, // VK_F19 130
+ KEY_F20, // VK_F20 131
+ KEY_F21, // VK_F21 132
+ KEY_F22, // VK_F22 133
+ KEY_F23, // VK_F23 134
+ KEY_F24, // VK_F24 135
+ 0, // 136
+ 0, // 137
+ 0, // 138
+ 0, // 139
+ 0, // 140
+ 0, // 141
+ 0, // 142
+ 0, // 143
+ 0, // NUMLOCK 144
+ 0 // SCROLLLOCK 145
+};
+
+// =======================================================================
+
+static UINT ImplSalGetWheelScrollLines()
+{
+ UINT nScrLines = 0;
+ HWND hWndMsWheel = WIN_FindWindow( MSH_WHEELMODULE_CLASS, MSH_WHEELMODULE_TITLE );
+ if ( hWndMsWheel )
+ {
+ UINT nGetScrollLinesMsgId = RegisterWindowMessage( MSH_SCROLL_LINES );
+ nScrLines = (UINT)ImplSendMessage( hWndMsWheel, nGetScrollLinesMsgId, 0, 0 );
+ }
+
+ if ( !nScrLines )
+ if( !SystemParametersInfo( SPI_GETWHEELSCROLLLINES, 0, &nScrLines, 0 ) )
+ nScrLines = 0 ;
+
+ if ( !nScrLines )
+ nScrLines = 3;
+
+ return nScrLines;
+}
+
+// -----------------------------------------------------------------------
+
+static UINT ImplSalGetWheelScrollChars()
+{
+ UINT nScrChars = 0;
+ if( !SystemParametersInfo( SPI_GETWHEELSCROLLCHARS, 0, &nScrChars, 0 ) )
+ {
+ // Depending on Windows version, use proper default or 1 (when
+ // driver emulates hscroll)
+ if( VER_PLATFORM_WIN32_NT == aSalShlData.maVersionInfo.dwPlatformId &&
+ aSalShlData.maVersionInfo.dwMajorVersion < 6 )
+ {
+ // Windows 2000 & WinXP : emulating driver, use step size
+ // of 1
+ return 1;
+ }
+ else
+ {
+ // Longhorn or above: use proper default value of 3
+ return 3;
+ }
+ }
+
+ // system settings successfully read
+ return nScrChars;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplSalAddBorder( const WinSalFrame* pFrame, int& width, int& height )
+{
+ // transform client size into window size
+ RECT aWinRect;
+ aWinRect.left = 0;
+ aWinRect.right = width-1;
+ aWinRect.top = 0;
+ aWinRect.bottom = height-1;
+ AdjustWindowRectEx( &aWinRect, GetWindowStyle( pFrame->mhWnd ),
+ FALSE, GetWindowExStyle( pFrame->mhWnd ) );
+ width = aWinRect.right - aWinRect.left + 1;
+ height = aWinRect.bottom - aWinRect.top + 1;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplSalCalcFullScreenSize( const WinSalFrame* pFrame,
+ int& rX, int& rY, int& rDX, int& rDY )
+{
+ // set window to screen size
+ int nFrameX;
+ int nFrameY;
+ int nCaptionY;
+ int nScreenX = 0;
+ int nScreenY = 0;
+ int nScreenDX = 0;
+ int nScreenDY = 0;
+
+ if ( pFrame->mbSizeBorder )
+ {
+ nFrameX = GetSystemMetrics( SM_CXSIZEFRAME );
+ nFrameY = GetSystemMetrics( SM_CYSIZEFRAME );
+ }
+ else if ( pFrame->mbFixBorder )
+ {
+ nFrameX = GetSystemMetrics( SM_CXFIXEDFRAME );
+ nFrameY = GetSystemMetrics( SM_CYFIXEDFRAME );
+ }
+ else if ( pFrame->mbBorder )
+ {
+ nFrameX = GetSystemMetrics( SM_CXBORDER );
+ nFrameY = GetSystemMetrics( SM_CYBORDER );
+ }
+ else
+ {
+ nFrameX = 0;
+ nFrameY = 0;
+ }
+ if ( pFrame->mbCaption )
+ nCaptionY = GetSystemMetrics( SM_CYCAPTION );
+ else
+ nCaptionY = 0;
+
+ try
+ {
+ Reference< XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory(), UNO_QUERY_THROW );
+ Reference< XIndexAccess > xMultiMon( xFactory->createInstance(OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.awt.DisplayAccess" ) ) ), UNO_QUERY_THROW );
+ if( (pFrame->mnDisplay >= 0) && (pFrame->mnDisplay < xMultiMon->getCount()) )
+ {
+ Reference< XPropertySet > xMonitor( xMultiMon->getByIndex( pFrame->mnDisplay ), UNO_QUERY_THROW );
+ com::sun::star::awt::Rectangle aRect;
+ if( xMonitor->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "ScreenArea" ) ) ) >>= aRect )
+ {
+ nScreenX = aRect.X;
+ nScreenY = aRect.Y;
+ nScreenDX = aRect.Width+1; // difference between java/awt convention and vcl
+ nScreenDY = aRect.Height+1; // difference between java/awt convention and vcl
+ }
+ }
+ else
+ {
+ nScreenX = GetSystemMetrics( SM_XVIRTUALSCREEN );
+ nScreenY = GetSystemMetrics( SM_YVIRTUALSCREEN );
+ nScreenDX = GetSystemMetrics( SM_CXVIRTUALSCREEN );
+ nScreenDY = GetSystemMetrics( SM_CYVIRTUALSCREEN );
+ }
+ }
+ catch( Exception& )
+ {
+ }
+
+ if( !nScreenDX || !nScreenDY )
+ {
+ nScreenDX = GetSystemMetrics( SM_CXSCREEN );
+ nScreenDY = GetSystemMetrics( SM_CYSCREEN );
+ }
+
+ rX = nScreenX -nFrameX;
+ rY = nScreenY -(nFrameY+nCaptionY);
+ rDX = nScreenDX+(nFrameX*2);
+ rDY = nScreenDY+(nFrameY*2)+nCaptionY;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplSalFrameFullScreenPos( WinSalFrame* pFrame, BOOL bAlways = FALSE )
+{
+ if ( bAlways || !IsIconic( pFrame->mhWnd ) )
+ {
+ // set window to screen size
+ int nX;
+ int nY;
+ int nWidth;
+ int nHeight;
+ ImplSalCalcFullScreenSize( pFrame, nX, nY, nWidth, nHeight );
+ SetWindowPos( pFrame->mhWnd, 0,
+ nX, nY, nWidth, nHeight,
+ SWP_NOZORDER | SWP_NOACTIVATE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+WinSalFrame::WinSalFrame()
+{
+ SalData* pSalData = GetSalData();
+
+ mhWnd = 0;
+ mhCursor = LoadCursor( 0, IDC_ARROW );
+ mhDefIMEContext = 0;
+ mpGraphics = NULL;
+ mpGraphics2 = NULL;
+ mnShowState = SW_SHOWNORMAL;
+ mnWidth = 0;
+ mnHeight = 0;
+ mnMinWidth = 0;
+ mnMinHeight = 0;
+ mnMaxWidth = SHRT_MAX;
+ mnMaxHeight = SHRT_MAX;
+ mnInputLang = 0;
+ mnInputCodePage = 0;
+ mbGraphics = FALSE;
+ mbCaption = FALSE;
+ mbBorder = FALSE;
+ mbFixBorder = FALSE;
+ mbSizeBorder = FALSE;
+ mbFullScreen = FALSE;
+ mbPresentation = FALSE;
+ mbInShow = FALSE;
+ mbRestoreMaximize = FALSE;
+ mbInMoveMsg = FALSE;
+ mbInSizeMsg = FALSE;
+ mbFullScreenToolWin = FALSE;
+ mbDefPos = TRUE;
+ mbOverwriteState = TRUE;
+ mbIME = FALSE;
+ mbHandleIME = FALSE;
+ mbSpezIME = FALSE;
+ mbAtCursorIME = FALSE;
+ mbCandidateMode = FALSE;
+ mbFloatWin = FALSE;
+ mbNoIcon = FALSE;
+ mSelectedhMenu = 0;
+ mLastActivatedhMenu = 0;
+ mpClipRgnData = NULL;
+ mbFirstClipRect = TRUE;
+ mpNextClipRect = NULL;
+ mnDisplay = 0;
+
+ memset( &maState, 0, sizeof( SalFrameState ) );
+ maSysData.nSize = sizeof( SystemEnvData );
+
+ memset( &maGeometry, 0, sizeof( maGeometry ) );
+
+ // Daten ermitteln, wenn erster Frame angelegt wird
+ if ( !pSalData->mpFirstFrame )
+ {
+ if ( !aSalShlData.mnWheelMsgId )
+ aSalShlData.mnWheelMsgId = RegisterWindowMessage( MSH_MOUSEWHEEL );
+ if ( !aSalShlData.mnWheelScrollLines )
+ aSalShlData.mnWheelScrollLines = ImplSalGetWheelScrollLines();
+ if ( !aSalShlData.mnWheelScrollChars )
+ aSalShlData.mnWheelScrollChars = ImplSalGetWheelScrollChars();
+ }
+
+ // insert frame in framelist
+ mpNextFrame = pSalData->mpFirstFrame;
+ pSalData->mpFirstFrame = this;
+}
+
+// -----------------------------------------------------------------------
+void WinSalFrame::updateScreenNumber()
+{
+ WinSalSystem* pSys = static_cast<WinSalSystem*>(ImplGetSalSystem());
+ if( pSys )
+ {
+ const std::vector<WinSalSystem::DisplayMonitor>& rMonitors =
+ pSys->getMonitors();
+ Point aPoint( maGeometry.nX, maGeometry.nY );
+ size_t nMon = rMonitors.size();
+ for( size_t i = 0; i < nMon; i++ )
+ {
+ if( rMonitors[i].m_aArea.IsInside( aPoint ) )
+ {
+ mnDisplay = static_cast<sal_Int32>(i);
+ maGeometry.nScreenNumber = static_cast<unsigned int>(i);
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+WinSalFrame::~WinSalFrame()
+{
+ SalData* pSalData = GetSalData();
+
+ if( mpClipRgnData )
+ delete [] (BYTE*)mpClipRgnData;
+
+ // remove frame from framelist
+ WinSalFrame** ppFrame = &pSalData->mpFirstFrame;
+ for(; (*ppFrame != this) && *ppFrame; ppFrame = &(*ppFrame)->mpNextFrame );
+ if( *ppFrame )
+ *ppFrame = mpNextFrame;
+ mpNextFrame = NULL;
+
+ // Release Cache DC
+ if ( mpGraphics2 &&
+ mpGraphics2->mhDC )
+ ReleaseGraphics( mpGraphics2 );
+
+ // destroy saved DC
+ if ( mpGraphics )
+ {
+ if ( mpGraphics->mhDefPal )
+ SelectPalette( mpGraphics->mhDC, mpGraphics->mhDefPal, TRUE );
+ ImplSalDeInitGraphics( mpGraphics );
+ ReleaseDC( mhWnd, mpGraphics->mhDC );
+ delete mpGraphics;
+ mpGraphics = NULL;
+ }
+
+ if ( mhWnd )
+ {
+ // reset mouse leave data
+ if ( pSalData->mhWantLeaveMsg == mhWnd )
+ {
+ pSalData->mhWantLeaveMsg = 0;
+ if ( pSalData->mpMouseLeaveTimer )
+ {
+ delete pSalData->mpMouseLeaveTimer;
+ pSalData->mpMouseLeaveTimer = NULL;
+ }
+ }
+
+ // destroy system frame
+ if ( !DestroyWindow( mhWnd ) )
+ SetWindowPtr( mhWnd, 0 );
+
+ mhWnd = 0;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+SalGraphics* WinSalFrame::GetGraphics()
+{
+ if ( mbGraphics )
+ return NULL;
+
+ // Other threads get an own DC, because Windows modify in the
+ // other case our DC (changing clip region), when they send a
+ // WM_ERASEBACKGROUND message
+ SalData* pSalData = GetSalData();
+ if ( pSalData->mnAppThreadId != GetCurrentThreadId() )
+ {
+ // We use only three CacheDC's for all threads, because W9x is limited
+ // to max. 5 Cache DC's per thread
+ if ( pSalData->mnCacheDCInUse >= 3 )
+ return NULL;
+
+ if ( !mpGraphics2 )
+ {
+ mpGraphics2 = new WinSalGraphics;
+ mpGraphics2->mhDC = 0;
+ mpGraphics2->mhWnd = mhWnd;
+ mpGraphics2->mbPrinter = FALSE;
+ mpGraphics2->mbVirDev = FALSE;
+ mpGraphics2->mbWindow = TRUE;
+ mpGraphics2->mbScreen = TRUE;
+ }
+
+ HDC hDC = (HDC)ImplSendMessage( pSalData->mpFirstInstance->mhComWnd,
+ SAL_MSG_GETDC,
+ (WPARAM)mhWnd, 0 );
+ if ( hDC )
+ {
+ mpGraphics2->mhDC = hDC;
+ if ( pSalData->mhDitherPal )
+ {
+ mpGraphics2->mhDefPal = SelectPalette( hDC, pSalData->mhDitherPal, TRUE );
+ RealizePalette( hDC );
+ }
+ ImplSalInitGraphics( mpGraphics2 );
+ mbGraphics = TRUE;
+
+ pSalData->mnCacheDCInUse++;
+ return mpGraphics2;
+ }
+ else
+ return NULL;
+ }
+ else
+ {
+ if ( !mpGraphics )
+ {
+ HDC hDC = GetDC( mhWnd );
+ if ( hDC )
+ {
+ mpGraphics = new WinSalGraphics;
+ mpGraphics->mhDC = hDC;
+ mpGraphics->mhWnd = mhWnd;
+ mpGraphics->mbPrinter = FALSE;
+ mpGraphics->mbVirDev = FALSE;
+ mpGraphics->mbWindow = TRUE;
+ mpGraphics->mbScreen = TRUE;
+ if ( pSalData->mhDitherPal )
+ {
+ mpGraphics->mhDefPal = SelectPalette( hDC, pSalData->mhDitherPal, TRUE );
+ RealizePalette( hDC );
+ }
+ ImplSalInitGraphics( mpGraphics );
+ mbGraphics = TRUE;
+ }
+ }
+ else
+ mbGraphics = TRUE;
+
+ return mpGraphics;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::ReleaseGraphics( SalGraphics* pGraphics )
+{
+ if ( mpGraphics2 == pGraphics )
+ {
+ if ( mpGraphics2->mhDC )
+ {
+ SalData* pSalData = GetSalData();
+ if ( mpGraphics2->mhDefPal )
+ SelectPalette( mpGraphics2->mhDC, mpGraphics2->mhDefPal, TRUE );
+ ImplSalDeInitGraphics( mpGraphics2 );
+ ImplSendMessage( pSalData->mpFirstInstance->mhComWnd,
+ SAL_MSG_RELEASEDC,
+ (WPARAM)mhWnd,
+ (LPARAM)mpGraphics2->mhDC );
+ mpGraphics2->mhDC = 0;
+ pSalData->mnCacheDCInUse--;
+ }
+ }
+
+ mbGraphics = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL WinSalFrame::PostEvent( void* pData )
+{
+ return (BOOL)ImplPostMessage( mhWnd, SAL_MSG_USEREVENT, 0, (LPARAM)pData );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::SetTitle( const XubString& rTitle )
+{
+ DBG_ASSERT( sizeof( WCHAR ) == sizeof( xub_Unicode ), "WinSalFrame::SetTitle(): WCHAR != sal_Unicode" );
+
+ if ( !SetWindowTextW( mhWnd, reinterpret_cast<LPCWSTR>(rTitle.GetBuffer()) ) )
+ {
+ ByteString aAnsiTitle = ImplSalGetWinAnsiString( rTitle );
+ SetWindowTextA( mhWnd, aAnsiTitle.GetBuffer() );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::SetIcon( USHORT nIcon )
+{
+ // If we have a window without an Icon (for example a dialog), ignore this call
+ if ( mbNoIcon )
+ return;
+
+ // 0 means default (class) icon
+ HICON hIcon = NULL, hSmIcon = NULL;
+ if ( !nIcon )
+ nIcon = 1;
+
+ ImplLoadSalIcon( nIcon, hIcon, hSmIcon );
+
+ DBG_ASSERT( hIcon , "WinSalFrame::SetIcon(): Could not load large icon !" );
+ DBG_ASSERT( hSmIcon , "WinSalFrame::SetIcon(): Could not load small icon !" );
+
+ ImplSendMessage( mhWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon );
+ ImplSendMessage( mhWnd, WM_SETICON, ICON_SMALL, (LPARAM)hSmIcon );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::SetMenu( SalMenu* pSalMenu )
+{
+ WinSalMenu* pWMenu = static_cast<WinSalMenu*>(pSalMenu);
+ if( pSalMenu && pWMenu->mbMenuBar )
+ ::SetMenu( mhWnd, pWMenu->mhMenu );
+}
+
+void WinSalFrame::DrawMenuBar()
+{
+ ::DrawMenuBar( mhWnd );
+}
+
+// -----------------------------------------------------------------------
+HWND ImplGetParentHwnd( HWND hWnd )
+{
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if( !pFrame || !pFrame->GetWindow())
+ return ::GetParent( hWnd );
+ Window *pRealParent = pFrame->GetWindow()->ImplGetWindowImpl()->mpRealParent;
+ if( pRealParent )
+ return static_cast<WinSalFrame*>(pRealParent->ImplGetWindowImpl()->mpFrame)->mhWnd;
+ else
+ return ::GetParent( hWnd );
+
+}
+
+// -----------------------------------------------------------------------
+
+SalFrame* WinSalFrame::GetParent() const
+{
+ return GetWindowPtr( ImplGetParentHwnd( mhWnd ) );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplSalShow( HWND hWnd, BOOL bVisible, BOOL bNoActivate )
+{
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( !pFrame )
+ return;
+
+ if ( bVisible )
+ {
+ pFrame->mbDefPos = FALSE;
+ pFrame->mbOverwriteState = TRUE;
+ pFrame->mbInShow = TRUE;
+
+ // #i4715, save position
+ RECT aRectPreMatrox, aRectPostMatrox;
+ GetWindowRect( hWnd, &aRectPreMatrox );
+
+ vcl::DeletionListener aDogTag( pFrame );
+ if( bNoActivate )
+ ShowWindow( hWnd, SW_SHOWNOACTIVATE );
+ else
+ ShowWindow( hWnd, pFrame->mnShowState );
+ if( aDogTag.isDeleted() )
+ return;
+
+ if ( aSalShlData.mbWXP && pFrame->mbFloatWin && !(pFrame->mnStyle & SAL_FRAME_STYLE_NOSHADOW))
+ {
+ // erase the window immediately to improve XP shadow effect
+ // otherwise the shadow may appears long time before the rest of the window
+ // especially when accessibility is on
+ HDC dc = GetDC( hWnd );
+ RECT aRect;
+ GetClientRect( hWnd, &aRect );
+ FillRect( dc, &aRect, (HBRUSH) (COLOR_MENU+1) ); // choose the menucolor, because its mostly noticeable for menues
+ ReleaseDC( hWnd, dc );
+ }
+
+ // #i4715, matrox centerpopup might have changed our position
+ // reposition popups without caption (menues, dropdowns, tooltips)
+ GetWindowRect( hWnd, &aRectPostMatrox );
+ if( (GetWindowStyle( hWnd ) & WS_POPUP) &&
+ !pFrame->mbCaption &&
+ (aRectPreMatrox.left != aRectPostMatrox.left || aRectPreMatrox.top != aRectPostMatrox.top) )
+ SetWindowPos( hWnd, 0, aRectPreMatrox.left, aRectPreMatrox.top, 0, 0, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE );
+
+ if( aDogTag.isDeleted() )
+ return;
+ Window *pClientWin = pFrame->GetWindow()->ImplGetClientWindow();
+ if ( pFrame->mbFloatWin || ( pClientWin && (pClientWin->GetStyle() & WB_SYSTEMFLOATWIN) ) )
+ pFrame->mnShowState = SW_SHOWNOACTIVATE;
+ else
+ pFrame->mnShowState = SW_SHOW;
+ // Damit Taskleiste unter W98 auch gleich ausgeblendet wird
+ if ( pFrame->mbPresentation )
+ {
+ HWND hWndParent = ::GetParent( hWnd );
+ if ( hWndParent )
+ SetForegroundWindow( hWndParent );
+ SetForegroundWindow( hWnd );
+ }
+
+ pFrame->mbInShow = FALSE;
+ pFrame->updateScreenNumber();
+
+ // Direct Paint only, if we get the SolarMutx
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ UpdateWindow( hWnd );
+ ImplSalYieldMutexRelease();
+ }
+ }
+ else
+ {
+ // See also Bug #91813# and #68467#
+ if ( pFrame->mbFullScreen &&
+ pFrame->mbPresentation &&
+ (aSalShlData.mnVersion < 500) &&
+ !::GetParent( hWnd ) )
+ {
+ // Damit im Impress-Player in der Taskleiste nicht durch
+ // einen Windows-Fehler hin- und wieder mal ein leerer
+ // Button stehen bleibt, muessen wir hier die Taskleiste
+ // etwas austricksen. Denn wenn wir im FullScreenMode sind
+ // und das Fenster hiden kommt Windows anscheinend etwas aus
+ // dem tritt und somit minimieren wir das Fenster damit es
+ // nicht flackert
+ ANIMATIONINFO aInfo;
+ aInfo.cbSize = sizeof( aInfo );
+ SystemParametersInfo( SPI_GETANIMATION, 0, &aInfo, 0 );
+ if ( aInfo.iMinAnimate )
+ {
+ int nOldAni = aInfo.iMinAnimate;
+ aInfo.iMinAnimate = 0;
+ SystemParametersInfo( SPI_SETANIMATION, 0, &aInfo, 0 );
+ ShowWindow( pFrame->mhWnd, SW_SHOWMINNOACTIVE );
+ aInfo.iMinAnimate = nOldAni;
+ SystemParametersInfo( SPI_SETANIMATION, 0, &aInfo, 0 );
+ }
+ else
+ ShowWindow( hWnd, SW_SHOWMINNOACTIVE );
+ ShowWindow( hWnd, SW_HIDE );
+ }
+ else
+ ShowWindow( hWnd, SW_HIDE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+
+void WinSalFrame::SetExtendedFrameStyle( SalExtStyle )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::Show( BOOL bVisible, BOOL bNoActivate )
+{
+ // Post this Message to the window, because this only works
+ // in the thread of the window, which has create this window.
+ // We post this message to avoid deadlocks
+ if ( GetSalData()->mnAppThreadId != GetCurrentThreadId() )
+ ImplPostMessage( mhWnd, SAL_MSG_SHOW, bVisible, bNoActivate );
+ else
+ ImplSalShow( mhWnd, bVisible, bNoActivate );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::Enable( BOOL bEnable )
+{
+ EnableWindow( mhWnd, bEnable );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::SetMinClientSize( long nWidth, long nHeight )
+{
+ mnMinWidth = nWidth;
+ mnMinHeight = nHeight;
+}
+
+void WinSalFrame::SetMaxClientSize( long nWidth, long nHeight )
+{
+ mnMaxWidth = nWidth;
+ mnMaxHeight = nHeight;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::SetPosSize( long nX, long nY, long nWidth, long nHeight,
+ USHORT nFlags )
+{
+ BOOL bVisible = (GetWindowStyle( mhWnd ) & WS_VISIBLE) != 0;
+ if ( !bVisible )
+ {
+ Window *pClientWin = GetWindow()->ImplGetClientWindow();
+ if ( mbFloatWin || ( pClientWin && (pClientWin->GetStyle() & WB_SYSTEMFLOATWIN) ) )
+ mnShowState = SW_SHOWNOACTIVATE;
+ else
+ mnShowState = SW_SHOWNORMAL;
+ }
+ else
+ {
+ if ( IsIconic( mhWnd ) || IsZoomed( mhWnd ) )
+ ShowWindow( mhWnd, SW_RESTORE );
+ }
+
+ USHORT nEvent = 0;
+ UINT nPosSize = 0;
+ RECT aClientRect, aWindowRect;
+ GetClientRect( mhWnd, &aClientRect ); // x,y always 0,0, but width and height without border
+ GetWindowRect( mhWnd, &aWindowRect ); // x,y in screen coordinates, width and height with border
+
+ if ( !(nFlags & (SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y)) )
+ nPosSize |= SWP_NOMOVE;
+ else
+ {
+ //DBG_ASSERT( nX && nY, " Windowposition of (0,0) requested!" );
+ nEvent = SALEVENT_MOVE;
+ }
+ if ( !(nFlags & (SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT)) )
+ nPosSize |= SWP_NOSIZE;
+ else
+ nEvent = (nEvent == SALEVENT_MOVE) ? SALEVENT_MOVERESIZE : SALEVENT_RESIZE;
+
+ if ( !(nFlags & SAL_FRAME_POSSIZE_X) )
+ nX = aWindowRect.left;
+ if ( !(nFlags & SAL_FRAME_POSSIZE_Y) )
+ nY = aWindowRect.top;
+ if ( !(nFlags & SAL_FRAME_POSSIZE_WIDTH) )
+ nWidth = aClientRect.right-aClientRect.left;
+ if ( !(nFlags & SAL_FRAME_POSSIZE_HEIGHT) )
+ nHeight = aClientRect.bottom-aClientRect.top;
+
+ // Calculate window size including the border
+ RECT aWinRect;
+ aWinRect.left = 0;
+ aWinRect.right = (int)nWidth-1;
+ aWinRect.top = 0;
+ aWinRect.bottom = (int)nHeight-1;
+ AdjustWindowRectEx( &aWinRect, GetWindowStyle( mhWnd ),
+ FALSE, GetWindowExStyle( mhWnd ) );
+ nWidth = aWinRect.right - aWinRect.left + 1;
+ nHeight = aWinRect.bottom - aWinRect.top + 1;
+
+ if ( !(nPosSize & SWP_NOMOVE) && ::GetParent( mhWnd ) )
+ {
+ // --- RTL --- (mirror window pos)
+ RECT aParentRect;
+ GetClientRect( ImplGetParentHwnd( mhWnd ), &aParentRect );
+ if( Application::GetSettings().GetLayoutRTL() )
+ nX = (aParentRect.right - aParentRect.left) - nWidth-1 - nX;
+
+ //#110386#, do not transform coordinates for system child windows
+ if( !(GetWindowStyle( mhWnd ) & WS_CHILD) )
+ {
+ POINT aPt;
+ aPt.x = nX;
+ aPt.y = nY;
+
+ HWND parentHwnd = ImplGetParentHwnd( mhWnd );
+ WinSalFrame* pParentFrame = GetWindowPtr( parentHwnd );
+ if ( pParentFrame && pParentFrame->mnShowState == SW_SHOWMAXIMIZED )
+ {
+ // #i42485#: parent will be shown maximized in which case
+ // a ClientToScreen uses the wrong coordinates (i.e. those from the restore pos)
+ // so use the (already updated) frame geometry for the transformation
+ aPt.x += pParentFrame->maGeometry.nX;
+ aPt.y += pParentFrame->maGeometry.nY;
+ }
+ else
+ ClientToScreen( parentHwnd, &aPt );
+
+ nX = aPt.x;
+ nY = aPt.y;
+ }
+ }
+
+ // #i3338# to be conformant to UNIX we must position the client window, ie without the decoration
+ // #i43250# if the position was read from the system (GetWindowRect(), see above), it must not be modified
+ if ( nFlags & SAL_FRAME_POSSIZE_X )
+ nX += aWinRect.left;
+ if ( nFlags & SAL_FRAME_POSSIZE_Y )
+ nY += aWinRect.top;
+
+ int nScreenX;
+ int nScreenY;
+ int nScreenWidth;
+ int nScreenHeight;
+
+
+ RECT aRect;
+ ImplSalGetWorkArea( mhWnd, &aRect, NULL );
+ nScreenX = aRect.left;
+ nScreenY = aRect.top;
+ nScreenWidth = aRect.right-aRect.left;
+ nScreenHeight = aRect.bottom-aRect.top;
+
+ if ( mbDefPos && (nPosSize & SWP_NOMOVE)) // we got no positioning request, so choose default position
+ {
+ // center window
+
+ HWND hWndParent = ::GetParent( mhWnd );
+ // Search for TopLevel Frame
+ while ( hWndParent && (GetWindowStyle( hWndParent ) & WS_CHILD) )
+ hWndParent = ::GetParent( hWndParent );
+ // if the Window has a Parent, than center the window to
+ // the parent, in the other case to the screen
+ if ( hWndParent && !IsIconic( hWndParent ) &&
+ (GetWindowStyle( hWndParent ) & WS_VISIBLE) )
+ {
+ RECT aParentRect;
+ GetWindowRect( hWndParent, &aParentRect );
+ int nParentWidth = aParentRect.right-aParentRect.left;
+ int nParentHeight = aParentRect.bottom-aParentRect.top;
+
+ // We don't center, when Parent is smaller than our window
+ if ( (nParentWidth-GetSystemMetrics( SM_CXFIXEDFRAME ) <= nWidth) &&
+ (nParentHeight-GetSystemMetrics( SM_CYFIXEDFRAME ) <= nHeight) )
+ {
+ int nOff = GetSystemMetrics( SM_CYSIZEFRAME ) + GetSystemMetrics( SM_CYCAPTION );
+ nX = aParentRect.left+nOff;
+ nY = aParentRect.top+nOff;
+ }
+ else
+ {
+ nX = (nParentWidth-nWidth)/2 + aParentRect.left;
+ nY = (nParentHeight-nHeight)/2 + aParentRect.top;
+ }
+ }
+ else
+ {
+ POINT pt;
+ GetCursorPos( &pt );
+ RECT aRect;
+ aRect.left = pt.x;
+ aRect.top = pt.y;
+ aRect.right = pt.x+2;
+ aRect.bottom = pt.y+2;
+
+ // dualmonitor support:
+ // Get screensize of the monitor whith the mouse pointer
+ ImplSalGetWorkArea( mhWnd, &aRect, &aRect );
+
+ nX = ((aRect.right-aRect.left)-nWidth)/2 + aRect.left;
+ nY = ((aRect.bottom-aRect.top)-nHeight)/2 + aRect.top;
+ }
+
+
+ //if ( bVisible )
+ // mbDefPos = FALSE;
+
+ mbDefPos = FALSE; // center only once
+ nPosSize &= ~SWP_NOMOVE; // activate positioning
+ nEvent = SALEVENT_MOVERESIZE;
+ }
+
+
+ // Adjust Window in the screen
+ BOOL bCheckOffScreen = TRUE;
+
+ // but don't do this for floaters or ownerdraw windows that are currently moved interactively
+ if( (mnStyle & SAL_FRAME_STYLE_FLOAT) && !(mnStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) )
+ bCheckOffScreen = FALSE;
+
+ if( mnStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION )
+ {
+ // may be the window is currently being moved (mouse is captured), then no check is required
+ if( mhWnd == ::GetCapture() )
+ bCheckOffScreen = FALSE;
+ else
+ bCheckOffScreen = TRUE;
+ }
+
+ if( bCheckOffScreen )
+ {
+ if ( nX+nWidth > nScreenX+nScreenWidth )
+ nX = (nScreenX+nScreenWidth) - nWidth;
+ if ( nY+nHeight > nScreenY+nScreenHeight )
+ nY = (nScreenY+nScreenHeight) - nHeight;
+ if ( nX < nScreenX )
+ nX = nScreenX;
+ if ( nY < nScreenY )
+ nY = nScreenY;
+ }
+
+ UINT nPosFlags = SWP_NOACTIVATE | SWP_NOOWNERZORDER | nPosSize;
+ // bring floating windows always to top
+ if( !(mnStyle & SAL_FRAME_STYLE_FLOAT) )
+ nPosFlags |= SWP_NOZORDER; // do not change z-order
+
+ SetWindowPos( mhWnd, HWND_TOP, nX, nY, (int)nWidth, (int)nHeight, nPosFlags );
+
+ UpdateFrameGeometry( mhWnd, this );
+
+ // Notification -- really ???
+ if( nEvent )
+ CallCallback( nEvent, NULL );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplSetParentFrame( WinSalFrame* pThis, HWND hNewParentWnd, BOOL bAsChild )
+{
+ // save hwnd, will be overwritten in WM_CREATE during createwindow
+ HWND hWndOld = pThis->mhWnd;
+ HWND hWndOldParent = ::GetParent( hWndOld );
+ SalData* pSalData = GetSalData();
+
+ if( hNewParentWnd == hWndOldParent )
+ return;
+
+ ::std::vector< WinSalFrame* > children;
+ ::std::vector< WinSalObject* > systemChildren;
+
+ // search child windows
+ WinSalFrame *pFrame = pSalData->mpFirstFrame;
+ while( pFrame )
+ {
+ HWND hWndParent = ::GetParent( pFrame->mhWnd );
+ if( pThis->mhWnd == hWndParent )
+ children.push_back( pFrame );
+ pFrame = pFrame->mpNextFrame;
+ }
+
+ // search system child windows (plugins etc.)
+ WinSalObject *pObject = pSalData->mpFirstObject;
+ while( pObject )
+ {
+ HWND hWndParent = ::GetParent( pObject->mhWnd );
+ if( pThis->mhWnd == hWndParent )
+ systemChildren.push_back( pObject );
+ pObject = pObject->mpNextObject;
+ }
+
+ BOOL bNeedGraphics = pThis->mbGraphics;
+ BOOL bNeedCacheDC = FALSE;
+
+ HFONT hFont = NULL;
+ HPEN hPen = NULL;
+ HBRUSH hBrush = NULL;
+
+ #if OSL_DEBUG_LEVEL > 0
+ int oldCount = pSalData->mnCacheDCInUse;
+ (void)oldCount;
+ #endif
+
+ // Release Cache DC
+ if ( pThis->mpGraphics2 &&
+ pThis->mpGraphics2->mhDC )
+ {
+ // save current gdi objects before hdc is gone
+ hFont = (HFONT) GetCurrentObject( pThis->mpGraphics2->mhDC, OBJ_FONT);
+ hPen = (HPEN) GetCurrentObject( pThis->mpGraphics2->mhDC, OBJ_PEN);
+ hBrush = (HBRUSH) GetCurrentObject( pThis->mpGraphics2->mhDC, OBJ_BRUSH);
+ pThis->ReleaseGraphics( pThis->mpGraphics2 );
+
+ // recreate cache dc only if it was destroyed
+ bNeedCacheDC = TRUE;
+ }
+
+ // destroy saved DC
+ if ( pThis->mpGraphics )
+ {
+ if ( pThis->mpGraphics->mhDefPal )
+ SelectPalette( pThis->mpGraphics->mhDC, pThis->mpGraphics->mhDefPal, TRUE );
+ ImplSalDeInitGraphics( pThis->mpGraphics );
+ ReleaseDC( pThis->mhWnd, pThis->mpGraphics->mhDC );
+ }
+
+ // create a new hwnd with the same styles
+ HWND hWndParent = hNewParentWnd;
+ // forward to main thread
+ HWND hWnd = (HWND) ImplSendMessage( pSalData->mpFirstInstance->mhComWnd,
+ bAsChild ? SAL_MSG_RECREATECHILDHWND : SAL_MSG_RECREATEHWND,
+ (WPARAM) hWndParent, (LPARAM)pThis->mhWnd );
+
+ // succeeded ?
+ DBG_ASSERT( IsWindow( hWnd ), "WinSalFrame::SetParent not successful");
+
+ // recreate DCs
+ if( bNeedGraphics )
+ {
+ if( pThis->mpGraphics2 )
+ {
+ pThis->mpGraphics2->mhWnd = hWnd;
+
+ if( bNeedCacheDC )
+ {
+ // re-create cached DC
+ HDC hDC = (HDC)ImplSendMessage( pSalData->mpFirstInstance->mhComWnd,
+ SAL_MSG_GETDC,
+ (WPARAM) hWnd, 0 );
+ if ( hDC )
+ {
+ pThis->mpGraphics2->mhDC = hDC;
+ if ( pSalData->mhDitherPal )
+ {
+ pThis->mpGraphics2->mhDefPal = SelectPalette( hDC, pSalData->mhDitherPal, TRUE );
+ RealizePalette( hDC );
+ }
+ ImplSalInitGraphics( pThis->mpGraphics2 );
+
+ // re-select saved gdi objects
+ if( hFont )
+ SelectObject( hDC, hFont );
+ if( hPen )
+ SelectObject( hDC, hPen );
+ if( hBrush )
+ SelectObject( hDC, hBrush );
+
+ pThis->mbGraphics = TRUE;
+
+ pSalData->mnCacheDCInUse++;
+
+ DBG_ASSERT( oldCount == pSalData->mnCacheDCInUse, "WinSalFrame::SetParent() hDC count corrupted");
+ }
+ }
+ }
+
+ if( pThis->mpGraphics )
+ {
+ // re-create DC
+ pThis->mpGraphics->mhWnd = hWnd;
+ pThis->mpGraphics->mhDC = GetDC( hWnd );
+ if ( GetSalData()->mhDitherPal )
+ {
+ pThis->mpGraphics->mhDefPal = SelectPalette( pThis->mpGraphics->mhDC, GetSalData()->mhDitherPal, TRUE );
+ RealizePalette( pThis->mpGraphics->mhDC );
+ }
+ ImplSalInitGraphics( pThis->mpGraphics );
+ pThis->mbGraphics = TRUE;
+ }
+ }
+
+
+ // TODO: add SetParent() call for SalObjects
+ DBG_ASSERT( systemChildren.empty(), "WinSalFrame::SetParent() parent of living system child window will be destroyed!");
+
+ // reparent children before old parent is destroyed
+ for( ::std::vector< WinSalFrame* >::iterator iChild = children.begin(); iChild != children.end(); iChild++ )
+ ImplSetParentFrame( *iChild, hWnd, FALSE );
+
+ children.clear();
+ systemChildren.clear();
+
+ // Now destroy original HWND in the thread where it was created.
+ ImplSendMessage( GetSalData()->mpFirstInstance->mhComWnd,
+ SAL_MSG_DESTROYHWND, (WPARAM) 0, (LPARAM)hWndOld);
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::SetParent( SalFrame* pNewParent )
+{
+ WinSalFrame::mbInReparent = TRUE;
+ ImplSetParentFrame( this, static_cast<WinSalFrame*>(pNewParent)->mhWnd, FALSE );
+ WinSalFrame::mbInReparent = FALSE;
+}
+
+bool WinSalFrame::SetPluginParent( SystemParentData* pNewParent )
+{
+ if ( pNewParent->hWnd == 0 )
+ {
+ pNewParent->hWnd = GetDesktopWindow();
+ }
+
+ WinSalFrame::mbInReparent = TRUE;
+ ImplSetParentFrame( this, pNewParent->hWnd, TRUE );
+ WinSalFrame::mbInReparent = FALSE;
+ return true;
+}
+
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::GetWorkArea( Rectangle &rRect )
+{
+ RECT aRect;
+ ImplSalGetWorkArea( mhWnd, &aRect, NULL );
+ rRect.nLeft = aRect.left;
+ rRect.nRight = aRect.right-1;
+ rRect.nTop = aRect.top;
+ rRect.nBottom = aRect.bottom-1;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::GetClientSize( long& rWidth, long& rHeight )
+{
+ rWidth = maGeometry.nWidth;
+ rHeight = maGeometry.nHeight;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::SetWindowState( const SalFrameState* pState )
+{
+ // Wir testen, ob das Fenster ueberhaupt auf den Bildschirm passt, damit
+ // nicht wenn die Bildschirm-Aufloesung geaendert wurde, das Fenster aus
+ // diesem herausragt
+ int nX;
+ int nY;
+ int nWidth;
+ int nHeight;
+ int nScreenX;
+ int nScreenY;
+ int nScreenWidth;
+ int nScreenHeight;
+
+ RECT aRect;
+ ImplSalGetWorkArea( mhWnd, &aRect, NULL );
+ // #102500# allow some overlap, the window could have been made a little larger than the physical screen
+ nScreenX = aRect.left-10;
+ nScreenY = aRect.top-10;
+ nScreenWidth = aRect.right-aRect.left+20;
+ nScreenHeight = aRect.bottom-aRect.top+20;
+
+ UINT nPosSize = 0;
+ RECT aWinRect;
+ GetWindowRect( mhWnd, &aWinRect );
+
+ // to be consistent with Unix, the frame state is without(!) decoration
+ // ->add the decoration
+ RECT aRect2 = aWinRect;
+ AdjustWindowRectEx( &aRect2, GetWindowStyle( mhWnd ),
+ FALSE, GetWindowExStyle( mhWnd ) );
+ long nTopDeco = abs( aWinRect.top - aRect2.top );
+ long nLeftDeco = abs( aWinRect.left - aRect2.left );
+ long nBottomDeco = abs( aWinRect.bottom - aRect2.bottom );
+ long nRightDeco = abs( aWinRect.right - aRect2.right );
+
+ // Fenster-Position/Groesse in den Bildschirm einpassen
+ if ( !(pState->mnMask & (SAL_FRAMESTATE_MASK_X | SAL_FRAMESTATE_MASK_Y)) )
+ nPosSize |= SWP_NOMOVE;
+ if ( !(pState->mnMask & (SAL_FRAMESTATE_MASK_WIDTH | SAL_FRAMESTATE_MASK_HEIGHT)) )
+ nPosSize |= SWP_NOSIZE;
+ if ( pState->mnMask & SAL_FRAMESTATE_MASK_X )
+ nX = (int)pState->mnX - nLeftDeco;
+ else
+ nX = aWinRect.left;
+ if ( pState->mnMask & SAL_FRAMESTATE_MASK_Y )
+ nY = (int)pState->mnY - nTopDeco;
+ else
+ nY = aWinRect.top;
+ if ( pState->mnMask & SAL_FRAMESTATE_MASK_WIDTH )
+ nWidth = (int)pState->mnWidth + nLeftDeco + nRightDeco;
+ else
+ nWidth = aWinRect.right-aWinRect.left;
+ if ( pState->mnMask & SAL_FRAMESTATE_MASK_HEIGHT )
+ nHeight = (int)pState->mnHeight + nTopDeco + nBottomDeco;
+ else
+ nHeight = aWinRect.bottom-aWinRect.top;
+
+ // Adjust Window in the screen:
+ // if it does not fit into the screen do nothing, ie default pos/size will be used
+ // if there is an overlap with the screen border move the window while keeping its size
+
+ if( nWidth > nScreenWidth || nHeight > nScreenHeight )
+ nPosSize |= (SWP_NOMOVE | SWP_NOSIZE);
+
+ if ( nX+nWidth > nScreenX+nScreenWidth )
+ nX = (nScreenX+nScreenWidth) - nWidth;
+ if ( nY+nHeight > nScreenY+nScreenHeight )
+ nY = (nScreenY+nScreenHeight) - nHeight;
+ if ( nX < nScreenX )
+ nX = nScreenX;
+ if ( nY < nScreenY )
+ nY = nScreenY;
+
+ // Restore-Position setzen
+ WINDOWPLACEMENT aPlacement;
+ aPlacement.length = sizeof( aPlacement );
+ GetWindowPlacement( mhWnd, &aPlacement );
+
+ // Status setzen
+ BOOL bVisible = (GetWindowStyle( mhWnd ) & WS_VISIBLE) != 0;
+ BOOL bUpdateHiddenFramePos = FALSE;
+ if ( !bVisible )
+ {
+ aPlacement.showCmd = SW_HIDE;
+
+ if ( mbOverwriteState )
+ {
+ if ( pState->mnMask & SAL_FRAMESTATE_MASK_STATE )
+ {
+ if ( pState->mnState & SAL_FRAMESTATE_MINIMIZED )
+ mnShowState = SW_SHOWMINIMIZED;
+ else if ( pState->mnState & SAL_FRAMESTATE_MAXIMIZED )
+ {
+ mnShowState = SW_SHOWMAXIMIZED;
+ bUpdateHiddenFramePos = TRUE;
+ }
+ else if ( pState->mnState & SAL_FRAMESTATE_NORMAL )
+ mnShowState = SW_SHOWNORMAL;
+ }
+ }
+ }
+ else
+ {
+ if ( pState->mnMask & SAL_FRAMESTATE_MASK_STATE )
+ {
+ if ( pState->mnState & SAL_FRAMESTATE_MINIMIZED )
+ {
+ if ( pState->mnState & SAL_FRAMESTATE_MAXIMIZED )
+ aPlacement.flags |= WPF_RESTORETOMAXIMIZED;
+ aPlacement.showCmd = SW_SHOWMINIMIZED;
+ }
+ else if ( pState->mnState & SAL_FRAMESTATE_MAXIMIZED )
+ aPlacement.showCmd = SW_SHOWMAXIMIZED;
+ else if ( pState->mnState & SAL_FRAMESTATE_NORMAL )
+ aPlacement.showCmd = SW_RESTORE;
+ }
+ }
+
+ // Wenn Fenster nicht minimiert/maximiert ist oder nicht optisch
+ // umgesetzt werden muss, dann SetWindowPos() benutzen, da
+ // SetWindowPlacement() die TaskBar mit einrechnet
+ if ( !IsIconic( mhWnd ) && !IsZoomed( mhWnd ) &&
+ (!bVisible || (aPlacement.showCmd == SW_RESTORE)) )
+ {
+ if( bUpdateHiddenFramePos )
+ {
+ // #96084 set a useful internal window size because
+ // the window will not be maximized (and the size updated) before show()
+ SetMaximizedFrameGeometry( mhWnd, this );
+ }
+ else
+ SetWindowPos( mhWnd, 0,
+ nX, nY, nWidth, nHeight,
+ SWP_NOZORDER | SWP_NOACTIVATE | nPosSize );
+ }
+ else
+ {
+ if( !(nPosSize & (SWP_NOMOVE|SWP_NOSIZE)) )
+ {
+ aPlacement.rcNormalPosition.left = nX-nScreenX;
+ aPlacement.rcNormalPosition.top = nY-nScreenY;
+ aPlacement.rcNormalPosition.right = nX+nWidth-nScreenX;
+ aPlacement.rcNormalPosition.bottom = nY+nHeight-nScreenY;
+ }
+ SetWindowPlacement( mhWnd, &aPlacement );
+ }
+
+ if( !(nPosSize & SWP_NOMOVE) )
+ mbDefPos = FALSE; // window was positioned
+}
+
+// -----------------------------------------------------------------------
+
+BOOL WinSalFrame::GetWindowState( SalFrameState* pState )
+{
+ if ( maState.mnWidth && maState.mnHeight )
+ {
+ *pState = maState;
+ // #94144# allow Minimize again, should be masked out when read from configuration
+ // 91625 - Don't save minimize
+ //if ( !(pState->mnState & SAL_FRAMESTATE_MAXIMIZED) )
+ if ( !(pState->mnState & (SAL_FRAMESTATE_MINIMIZED | SAL_FRAMESTATE_MAXIMIZED)) )
+ pState->mnState |= SAL_FRAMESTATE_NORMAL;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::SetScreenNumber( unsigned int nNewScreen )
+{
+ WinSalSystem* pSys = static_cast<WinSalSystem*>(ImplGetSalSystem());
+ if( pSys )
+ {
+ const std::vector<WinSalSystem::DisplayMonitor>& rMonitors =
+ pSys->getMonitors();
+ size_t nMon = rMonitors.size();
+ if( nNewScreen < nMon )
+ {
+ Point aOldMonPos, aNewMonPos( rMonitors[nNewScreen].m_aArea.TopLeft() );
+ Point aCurPos( maGeometry.nX, maGeometry.nY );
+ for( size_t i = 0; i < nMon; i++ )
+ {
+ if( rMonitors[i].m_aArea.IsInside( aCurPos ) )
+ {
+ aOldMonPos = rMonitors[i].m_aArea.TopLeft();
+ break;
+ }
+ }
+ mnDisplay = nNewScreen;
+ maGeometry.nScreenNumber = nNewScreen;
+ SetPosSize( aNewMonPos.X() + (maGeometry.nX - aOldMonPos.X()),
+ aNewMonPos.Y() + (maGeometry.nY - aOldMonPos.Y()),
+ 0, 0,
+ SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::ShowFullScreen( BOOL bFullScreen, sal_Int32 nDisplay )
+{
+ if ( (mbFullScreen == bFullScreen) && (!bFullScreen || (mnDisplay == nDisplay)) )
+ return;
+
+ mbFullScreen = bFullScreen;
+ mnDisplay = nDisplay;
+
+ if ( bFullScreen )
+ {
+ // Damit Taskleiste von Windows ausgeblendet wird
+ DWORD nExStyle = GetWindowExStyle( mhWnd );
+ if ( nExStyle & WS_EX_TOOLWINDOW )
+ {
+ mbFullScreenToolWin = TRUE;
+ nExStyle &= ~WS_EX_TOOLWINDOW;
+ SetWindowExStyle( mhWnd, nExStyle );
+ }
+ // save old position
+ GetWindowRect( mhWnd, &maFullScreenRect );
+
+ // save show state
+ mnFullScreenShowState = mnShowState;
+ if ( !(GetWindowStyle( mhWnd ) & WS_VISIBLE) )
+ mnShowState = SW_SHOW;
+
+ // set window to screen size
+ ImplSalFrameFullScreenPos( this, TRUE );
+ }
+ else
+ {
+ // wenn ShowState wieder hergestellt werden muss, hiden wir zuerst
+ // das Fenster, damit es nicht so sehr flackert
+ BOOL bVisible = (GetWindowStyle( mhWnd ) & WS_VISIBLE) != 0;
+ if ( bVisible && (mnShowState != mnFullScreenShowState) )
+ ShowWindow( mhWnd, SW_HIDE );
+
+ if ( mbFullScreenToolWin )
+ SetWindowExStyle( mhWnd, GetWindowExStyle( mhWnd ) | WS_EX_TOOLWINDOW );
+ mbFullScreenToolWin = FALSE;
+
+ SetWindowPos( mhWnd, 0,
+ maFullScreenRect.left,
+ maFullScreenRect.top,
+ maFullScreenRect.right-maFullScreenRect.left,
+ maFullScreenRect.bottom-maFullScreenRect.top,
+ SWP_NOZORDER | SWP_NOACTIVATE );
+
+ // restore show state
+ if ( mnShowState != mnFullScreenShowState )
+ {
+ mnShowState = mnFullScreenShowState;
+ if ( bVisible )
+ {
+ mbInShow = TRUE;
+ ShowWindow( mhWnd, mnShowState );
+ mbInShow = FALSE;
+ UpdateWindow( mhWnd );
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::StartPresentation( BOOL bStart )
+{
+ if ( mbPresentation == bStart )
+ return;
+
+ mbPresentation = bStart;
+
+ SalData* pSalData = GetSalData();
+ if ( bStart )
+ {
+ if ( !pSalData->mpSageEnableProc )
+ {
+ if ( pSalData->mnSageStatus != DISABLE_AGENT )
+ {
+ OFSTRUCT aOS;
+ OpenFile( "SAGE.DLL", &aOS, OF_EXIST );
+
+ if ( !aOS.nErrCode )
+ {
+ OUString aLibraryName( OUString::createFromAscii( aOS.szPathName ) );
+ oslModule mhSageInst = osl_loadModule( aLibraryName.pData, SAL_LOADMODULE_DEFAULT );
+ pSalData->mpSageEnableProc = (SysAgt_Enable_PROC)osl_getAsciiFunctionSymbol( mhSageInst, "System_Agent_Enable" );
+ }
+ else
+ pSalData->mnSageStatus = DISABLE_AGENT;
+ }
+ }
+
+ if ( pSalData->mpSageEnableProc )
+ {
+ pSalData->mnSageStatus = pSalData->mpSageEnableProc( GET_AGENT_STATUS );
+ if ( pSalData->mnSageStatus == ENABLE_AGENT )
+ pSalData->mpSageEnableProc( DISABLE_AGENT );
+ }
+
+ // Bildschirmschoner ausschalten, wenn Praesentation laueft
+ SystemParametersInfo( SPI_GETSCREENSAVEACTIVE, 0,
+ &(pSalData->mbScrSvrEnabled), 0 );
+ if ( pSalData->mbScrSvrEnabled )
+ SystemParametersInfo( SPI_SETSCREENSAVEACTIVE, FALSE, 0, 0 );
+ }
+ else
+ {
+ // Bildschirmschoner wieder einschalten
+ if ( pSalData->mbScrSvrEnabled )
+ SystemParametersInfo( SPI_SETSCREENSAVEACTIVE, pSalData->mbScrSvrEnabled, 0, 0 );
+
+ // Systemagenten wieder aktivieren
+ if ( pSalData->mnSageStatus == ENABLE_AGENT )
+ pSalData->mpSageEnableProc( pSalData->mnSageStatus );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::SetAlwaysOnTop( BOOL bOnTop )
+{
+ HWND hWnd;
+ if ( bOnTop )
+ hWnd = HWND_TOPMOST;
+ else
+ hWnd = HWND_NOTOPMOST;
+ SetWindowPos( mhWnd, hWnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplSalToTop( HWND hWnd, USHORT nFlags )
+{
+ WinSalFrame* pToTopFrame = GetWindowPtr( hWnd );
+ if( pToTopFrame && (pToTopFrame->mnStyle & SAL_FRAME_STYLE_SYSTEMCHILD) != 0 )
+ BringWindowToTop( hWnd );
+
+ if ( nFlags & SAL_FRAME_TOTOP_FOREGROUNDTASK )
+ {
+ // This magic code is necessary to connect the input focus of the
+ // current window thread and the thread which owns the window that
+ // should be the new foreground window.
+ HWND hCurrWnd = GetForegroundWindow();
+ DWORD myThreadID = GetCurrentThreadId();
+ DWORD currThreadID = GetWindowThreadProcessId(hCurrWnd,NULL);
+ AttachThreadInput(myThreadID, currThreadID,TRUE);
+ SetForegroundWindow(hWnd);
+ AttachThreadInput(myThreadID,currThreadID,FALSE);
+ }
+
+ if ( nFlags & SAL_FRAME_TOTOP_RESTOREWHENMIN )
+ {
+ HWND hIconicWnd = hWnd;
+ while ( hIconicWnd )
+ {
+ if ( IsIconic( hIconicWnd ) )
+ {
+ WinSalFrame* pFrame = GetWindowPtr( hIconicWnd );
+ if ( pFrame )
+ {
+ if ( GetWindowPtr( hWnd )->mbRestoreMaximize )
+ ShowWindow( hIconicWnd, SW_MAXIMIZE );
+ else
+ ShowWindow( hIconicWnd, SW_RESTORE );
+ }
+ else
+ ShowWindow( hIconicWnd, SW_RESTORE );
+ }
+
+ hIconicWnd = ::GetParent( hIconicWnd );
+ }
+ }
+
+ if ( !IsIconic( hWnd ) && IsWindowVisible( hWnd ) )
+ {
+ SetFocus( hWnd );
+
+ // Windows behauptet oefters mal, das man den Focus hat, obwohl
+ // man diesen nicht hat. Wenn dies der Fall ist, dann versuchen
+ // wir diesen auch ganz richtig zu bekommen.
+ if ( ::GetFocus() == hWnd )
+ SetForegroundWindow( hWnd );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::ToTop( USHORT nFlags )
+{
+ nFlags &= ~SAL_FRAME_TOTOP_GRABFOCUS; // this flag is not needed on win32
+ // Post this Message to the window, because this only works
+ // in the thread of the window, which has create this window.
+ // We post this message to avoid deadlocks
+ if ( GetSalData()->mnAppThreadId != GetCurrentThreadId() )
+ ImplPostMessage( mhWnd, SAL_MSG_TOTOP, nFlags, 0 );
+ else
+ ImplSalToTop( mhWnd, nFlags );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::SetPointer( PointerStyle ePointerStyle )
+{
+ struct ImplPtrData
+ {
+ HCURSOR mhCursor;
+ LPCSTR mnSysId;
+ UINT mnOwnId;
+ };
+
+ static ImplPtrData aImplPtrTab[POINTER_COUNT] =
+ {
+ { 0, IDC_ARROW, 0 }, // POINTER_ARROW
+ { 0, 0, SAL_RESID_POINTER_NULL }, // POINTER_NULL
+ { 0, IDC_WAIT, 0 }, // POINTER_WAIT
+ { 0, IDC_IBEAM, 0 }, // POINTER_TEXT
+ { 0, IDC_HELP, 0 }, // POINTER_HELP
+ { 0, 0, SAL_RESID_POINTER_CROSS }, // POINTER_CROSS
+ { 0, 0, SAL_RESID_POINTER_MOVE }, // POINTER_MOVE
+ { 0, IDC_SIZENS, 0 }, // POINTER_NSIZE
+ { 0, IDC_SIZENS, 0 }, // POINTER_SSIZE
+ { 0, IDC_SIZEWE, 0 }, // POINTER_WSIZE
+ { 0, IDC_SIZEWE, 0 }, // POINTER_ESIZE
+ { 0, IDC_SIZENWSE, 0 }, // POINTER_NWSIZE
+ { 0, IDC_SIZENESW, 0 }, // POINTER_NESIZE
+ { 0, IDC_SIZENESW, 0 }, // POINTER_SWSIZE
+ { 0, IDC_SIZENWSE, 0 }, // POINTER_SESIZE
+ { 0, IDC_SIZENS, 0 }, // POINTER_WINDOW_NSIZE
+ { 0, IDC_SIZENS, 0 }, // POINTER_WINDOW_SSIZE
+ { 0, IDC_SIZEWE, 0 }, // POINTER_WINDOW_WSIZE
+ { 0, IDC_SIZEWE, 0 }, // POINTER_WINDOW_ESIZE
+ { 0, IDC_SIZENWSE, 0 }, // POINTER_WINDOW_NWSIZE
+ { 0, IDC_SIZENESW, 0 }, // POINTER_WINDOW_NESIZE
+ { 0, IDC_SIZENESW, 0 }, // POINTER_WINDOW_SWSIZE
+ { 0, IDC_SIZENWSE, 0 }, // POINTER_WINDOW_SESIZE
+ { 0, 0, SAL_RESID_POINTER_HSPLIT }, // POINTER_HSPLIT
+ { 0, 0, SAL_RESID_POINTER_VSPLIT }, // POINTER_VSPLIT
+ { 0, 0, SAL_RESID_POINTER_HSIZEBAR }, // POINTER_HSIZEBAR
+ { 0, 0, SAL_RESID_POINTER_VSIZEBAR }, // POINTER_VSIZEBAR
+ { 0, 0, SAL_RESID_POINTER_HAND }, // POINTER_HAND
+ { 0, 0, SAL_RESID_POINTER_REFHAND }, // POINTER_REFHAND
+ { 0, 0, SAL_RESID_POINTER_PEN }, // POINTER_PEN
+ { 0, 0, SAL_RESID_POINTER_MAGNIFY }, // POINTER_MAGNIFY
+ { 0, 0, SAL_RESID_POINTER_FILL }, // POINTER_FILL
+ { 0, 0, SAL_RESID_POINTER_ROTATE }, // POINTER_ROTATE
+ { 0, 0, SAL_RESID_POINTER_HSHEAR }, // POINTER_HSHEAR
+ { 0, 0, SAL_RESID_POINTER_VSHEAR }, // POINTER_VSHEAR
+ { 0, 0, SAL_RESID_POINTER_MIRROR }, // POINTER_MIRROR
+ { 0, 0, SAL_RESID_POINTER_CROOK }, // POINTER_CROOK
+ { 0, 0, SAL_RESID_POINTER_CROP }, // POINTER_CROP
+ { 0, 0, SAL_RESID_POINTER_MOVEPOINT }, // POINTER_MOVEPOINT
+ { 0, 0, SAL_RESID_POINTER_MOVEBEZIERWEIGHT }, // POINTER_MOVEBEZIERWEIGHT
+ { 0, 0, SAL_RESID_POINTER_MOVEDATA }, // POINTER_MOVEDATA
+ { 0, 0, SAL_RESID_POINTER_COPYDATA }, // POINTER_COPYDATA
+ { 0, 0, SAL_RESID_POINTER_LINKDATA }, // POINTER_LINKDATA
+ { 0, 0, SAL_RESID_POINTER_MOVEDATALINK }, // POINTER_MOVEDATALINK
+ { 0, 0, SAL_RESID_POINTER_COPYDATALINK }, // POINTER_COPYDATALINK
+ { 0, 0, SAL_RESID_POINTER_MOVEFILE }, // POINTER_MOVEFILE
+ { 0, 0, SAL_RESID_POINTER_COPYFILE }, // POINTER_COPYFILE
+ { 0, 0, SAL_RESID_POINTER_LINKFILE }, // POINTER_LINKFILE
+ { 0, 0, SAL_RESID_POINTER_MOVEFILELINK }, // POINTER_MOVEFILELINK
+ { 0, 0, SAL_RESID_POINTER_COPYFILELINK }, // POINTER_COPYFILELINK
+ { 0, 0, SAL_RESID_POINTER_MOVEFILES }, // POINTER_MOVEFILES
+ { 0, 0, SAL_RESID_POINTER_COPYFILES }, // POINTER_COPYFILES
+ { 0, 0, SAL_RESID_POINTER_NOTALLOWED }, // POINTER_NOTALLOWED
+ { 0, 0, SAL_RESID_POINTER_DRAW_LINE }, // POINTER_DRAW_LINE
+ { 0, 0, SAL_RESID_POINTER_DRAW_RECT }, // POINTER_DRAW_RECT
+ { 0, 0, SAL_RESID_POINTER_DRAW_POLYGON }, // POINTER_DRAW_POLYGON
+ { 0, 0, SAL_RESID_POINTER_DRAW_BEZIER }, // POINTER_DRAW_BEZIER
+ { 0, 0, SAL_RESID_POINTER_DRAW_ARC }, // POINTER_DRAW_ARC
+ { 0, 0, SAL_RESID_POINTER_DRAW_PIE }, // POINTER_DRAW_PIE
+ { 0, 0, SAL_RESID_POINTER_DRAW_CIRCLECUT }, // POINTER_DRAW_CIRCLECUT
+ { 0, 0, SAL_RESID_POINTER_DRAW_ELLIPSE }, // POINTER_DRAW_ELLIPSE
+ { 0, 0, SAL_RESID_POINTER_DRAW_FREEHAND }, // POINTER_DRAW_FREEHAND
+ { 0, 0, SAL_RESID_POINTER_DRAW_CONNECT }, // POINTER_DRAW_CONNECT
+ { 0, 0, SAL_RESID_POINTER_DRAW_TEXT }, // POINTER_DRAW_TEXT
+ { 0, 0, SAL_RESID_POINTER_DRAW_CAPTION }, // POINTER_DRAW_CAPTION
+ { 0, 0, SAL_RESID_POINTER_CHART }, // POINTER_CHART
+ { 0, 0, SAL_RESID_POINTER_DETECTIVE }, // POINTER_DETECTIVE
+ { 0, 0, SAL_RESID_POINTER_PIVOT_COL }, // POINTER_PIVOT_COL
+ { 0, 0, SAL_RESID_POINTER_PIVOT_ROW }, // POINTER_PIVOT_ROW
+ { 0, 0, SAL_RESID_POINTER_PIVOT_FIELD }, // POINTER_PIVOT_FIELD
+ { 0, 0, SAL_RESID_POINTER_CHAIN }, // POINTER_CHAIN
+ { 0, 0, SAL_RESID_POINTER_CHAIN_NOTALLOWED }, // POINTER_CHAIN_NOTALLOWED
+ { 0, 0, SAL_RESID_POINTER_TIMEEVENT_MOVE }, // POINTER_TIMEEVENT_MOVE
+ { 0, 0, SAL_RESID_POINTER_TIMEEVENT_SIZE }, // POINTER_TIMEEVENT_SIZE
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_N }, // POINTER_AUTOSCROLL_N
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_S }, // POINTER_AUTOSCROLL_S
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_W }, // POINTER_AUTOSCROLL_W
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_E }, // POINTER_AUTOSCROLL_E
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_NW }, // POINTER_AUTOSCROLL_NW
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_NE }, // POINTER_AUTOSCROLL_NE
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_SW }, // POINTER_AUTOSCROLL_SW
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_SE }, // POINTER_AUTOSCROLL_SE
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_NS }, // POINTER_AUTOSCROLL_NS
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_WE }, // POINTER_AUTOSCROLL_WE
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_NSWE }, // POINTER_AUTOSCROLL_NSWE
+ { 0, 0, SAL_RESID_POINTER_AIRBRUSH }, // POINTER_AIRBRUSH
+ { 0, 0, SAL_RESID_POINTER_TEXT_VERTICAL }, // POINTER_TEXT_VERTICAL
+ { 0, 0, SAL_RESID_POINTER_PIVOT_DELETE }, // POINTER_PIVOT_DELETE
+
+ // --> FME 2004-07-30 #i32329# Enhanced table selection
+ { 0, 0, SAL_RESID_POINTER_TAB_SELECT_S }, // POINTER_TAB_SELECT_S
+ { 0, 0, SAL_RESID_POINTER_TAB_SELECT_E }, // POINTER_TAB_SELECT_E
+ { 0, 0, SAL_RESID_POINTER_TAB_SELECT_SE }, // POINTER_TAB_SELECT_SE
+ { 0, 0, SAL_RESID_POINTER_TAB_SELECT_W }, // POINTER_TAB_SELECT_W
+ { 0, 0, SAL_RESID_POINTER_TAB_SELECT_SW }, // POINTER_TAB_SELECT_SW
+ // <--
+
+ // --> FME 2004-08-16 #i20119# Paintbrush tool
+ { 0, 0, SAL_RESID_POINTER_PAINTBRUSH } // POINTER_PAINTBRUSH
+ // <--
+
+ };
+
+#if POINTER_COUNT != 94
+#error New Pointer must be defined!
+#endif
+
+ // Mousepointer loaded ?
+ if ( !aImplPtrTab[ePointerStyle].mhCursor )
+ {
+ if ( aImplPtrTab[ePointerStyle].mnOwnId )
+ aImplPtrTab[ePointerStyle].mhCursor = ImplLoadSalCursor( aImplPtrTab[ePointerStyle].mnOwnId );
+ else
+ aImplPtrTab[ePointerStyle].mhCursor = LoadCursor( 0, aImplPtrTab[ePointerStyle].mnSysId );
+ }
+
+ // Unterscheidet sich der Mauspointer, dann den neuen setzen
+ if ( mhCursor != aImplPtrTab[ePointerStyle].mhCursor )
+ {
+ mhCursor = aImplPtrTab[ePointerStyle].mhCursor;
+ SetCursor( mhCursor );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::CaptureMouse( BOOL bCapture )
+{
+ // Send this Message to the window, because CaptureMouse() only work
+ // in the thread of the window, which has create this window
+ int nMsg;
+ if ( bCapture )
+ nMsg = SAL_MSG_CAPTUREMOUSE;
+ else
+ nMsg = SAL_MSG_RELEASEMOUSE;
+ ImplSendMessage( mhWnd, nMsg, 0, 0 );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::SetPointerPos( long nX, long nY )
+{
+ POINT aPt;
+ aPt.x = (int)nX;
+ aPt.y = (int)nY;
+ ClientToScreen( mhWnd, &aPt );
+ SetCursorPos( aPt.x, aPt.y );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::Flush()
+{
+ GdiFlush();
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::Sync()
+{
+ GdiFlush();
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplSalFrameSetInputContext( HWND hWnd, const SalInputContext* pContext )
+{
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ BOOL bIME = (pContext->mnOptions & SAL_INPUTCONTEXT_TEXT) != 0;
+ if ( bIME )
+ {
+ if ( !pFrame->mbIME )
+ {
+ pFrame->mbIME = TRUE;
+
+ if ( pFrame->mhDefIMEContext )
+ {
+ ImmAssociateContext( pFrame->mhWnd, pFrame->mhDefIMEContext );
+ UINT nImeProps = ImmGetProperty( GetKeyboardLayout( 0 ), IGP_PROPERTY );
+ pFrame->mbSpezIME = (nImeProps & IME_PROP_SPECIAL_UI) != 0;
+ pFrame->mbAtCursorIME = (nImeProps & IME_PROP_AT_CARET) != 0;
+ pFrame->mbHandleIME = !pFrame->mbSpezIME;
+ }
+ }
+
+ // When the application can't handle IME messages, then the
+ // System should handle the IME handling
+ if ( !(pContext->mnOptions & SAL_INPUTCONTEXT_EXTTEXTINPUT) )
+ pFrame->mbHandleIME = FALSE;
+
+ // Set the Font for IME Handling
+ if ( pContext->mpFont )
+ {
+ HIMC hIMC = ImmGetContext( pFrame->mhWnd );
+ if ( hIMC )
+ {
+ LOGFONTW aLogFont;
+ HDC hDC = GetDC( pFrame->mhWnd );
+ // In case of vertical writing, always append a '@' to the
+ // Windows font name, not only if such a Windows font really is
+ // available (bTestVerticalAvail == false in the below call):
+ // The Windows IME's candidates window seems to always use a
+ // font that has all necessary glyphs, not necessarily the one
+ // specified by this font name; but it seems to decide whether
+ // to use that font's horizontal or vertical variant based on a
+ // '@' in front of this font name.
+ ImplGetLogFontFromFontSelect( hDC, pContext->mpFont, aLogFont,
+ false );
+ ReleaseDC( pFrame->mhWnd, hDC );
+ ImmSetCompositionFontW( hIMC, &aLogFont );
+ ImmReleaseContext( pFrame->mhWnd, hIMC );
+ }
+ }
+ }
+ else
+ {
+ if ( pFrame->mbIME )
+ {
+ pFrame->mbIME = FALSE;
+ pFrame->mbHandleIME = FALSE;
+ ImmAssociateContext( pFrame->mhWnd, 0 );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::SetInputContext( SalInputContext* pContext )
+{
+ // Must be called in the main thread!
+ ImplSendMessage( mhWnd, SAL_MSG_SETINPUTCONTEXT, 0, (LPARAM)(void*)pContext );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplSalFrameEndExtTextInput( HWND hWnd, USHORT nFlags )
+{
+ HIMC hIMC = ImmGetContext( hWnd );
+ if ( hIMC )
+ {
+ DWORD nIndex;
+ if ( nFlags & SAL_FRAME_ENDEXTTEXTINPUT_COMPLETE )
+ nIndex = CPS_COMPLETE;
+ else
+ nIndex = CPS_CANCEL;
+
+ ImmNotifyIME( hIMC, NI_COMPOSITIONSTR, nIndex, 0 );
+ ImmReleaseContext( hWnd, hIMC );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::EndExtTextInput( USHORT nFlags )
+{
+ // Must be called in the main thread!
+ ImplSendMessage( mhWnd, SAL_MSG_ENDEXTTEXTINPUT, (WPARAM)nFlags, 0 );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplGetKeyNameText( LONG lParam, sal_Unicode* pBuf,
+ UINT& rCount, UINT nMaxSize,
+ const sal_Char* pReplace )
+{
+ DBG_ASSERT( sizeof( WCHAR ) == sizeof( xub_Unicode ), "WinSalFrame::ImplGetKeyNameTextW(): WCHAR != sal_Unicode" );
+
+ static const int nMaxKeyLen = 350;
+ WCHAR aKeyBuf[ nMaxKeyLen ];
+ int nKeyLen = 0;
+ if ( lParam )
+ {
+ if ( aSalShlData.mbWNT )
+ {
+ nKeyLen = GetKeyNameTextW( lParam, aKeyBuf, nMaxKeyLen );
+ // #i12401# the current unicows.dll has a bug in CharUpperBuffW, which corrupts the stack
+ // fall back to the ANSI version instead
+ DBG_ASSERT( nKeyLen <= nMaxKeyLen, "Invalid key name length!" );
+ if( nKeyLen > nMaxKeyLen )
+ nKeyLen = 0;
+ else if( nKeyLen > 0 )
+ {
+ // Capitalize just the first letter of key names
+ CharLowerBuffW( aKeyBuf, nKeyLen );
+
+ bool bUpper = true;
+ for( WCHAR *pW=aKeyBuf, *pE=pW+nKeyLen; pW < pE; ++pW )
+ {
+ if( bUpper )
+ CharUpperBuffW( pW, 1 );
+ bUpper = (*pW=='+') || (*pW=='-') || (*pW==' ') || (*pW=='.');
+ }
+ }
+ }
+ else // !mbWnt
+ {
+ sal_Char aAnsiKeyBuf[ nMaxKeyLen ];
+ int nAnsiKeyLen = GetKeyNameTextA( lParam, aAnsiKeyBuf, nMaxKeyLen );
+ DBG_ASSERT( nAnsiKeyLen <= nMaxKeyLen, "Invalid key name length!" );
+ if( nAnsiKeyLen > nMaxKeyLen )
+ nAnsiKeyLen = 0;
+ else if( nAnsiKeyLen > 0 )
+ {
+ // Capitalize just the first letter of key names
+ // TODO: check MCBS key names
+ CharLowerBuffA( aAnsiKeyBuf, nAnsiKeyLen );
+
+ bool bUpper = true;
+ for( sal_Char *pA=aAnsiKeyBuf, *pE=pA+nAnsiKeyLen; pA < pE; ++pA )
+ {
+ if( bUpper )
+ CharUpperBuffA( pA, 1 );
+ bUpper = (*pA=='+') || (*pA=='-') || (*pA==' ') || (*pA=='.');
+ }
+
+ // Convert to Unicode and copy the data in the Unicode Buffer
+ nKeyLen = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED,
+ aAnsiKeyBuf, nAnsiKeyLen, aKeyBuf, nMaxKeyLen );
+ }
+ }
+ }
+
+ if ( (nKeyLen > 0) || pReplace )
+ {
+ if( (rCount > 0) && (rCount < nMaxSize) )
+ {
+ pBuf[rCount] = '+';
+ rCount++;
+ }
+
+ if( nKeyLen > 0 )
+ {
+ if( nKeyLen + rCount > nMaxSize )
+ nKeyLen = nMaxSize - rCount;
+ memcpy( pBuf+rCount, aKeyBuf, nKeyLen*sizeof( sal_Unicode ) );
+ rCount += nKeyLen;
+ }
+ else // fall back to provided default name
+ {
+ while( *pReplace && (rCount < nMaxSize) )
+ {
+ pBuf[rCount] = *pReplace;
+ rCount++;
+ pReplace++;
+ }
+ }
+ }
+ else
+ rCount = 0;
+}
+
+// -----------------------------------------------------------------------
+
+XubString WinSalFrame::GetKeyName( USHORT nKeyCode )
+{
+ static const int nMaxKeyLen = 350;
+ sal_Unicode aKeyBuf[ nMaxKeyLen ];
+ UINT nKeyBufLen = 0;
+ UINT nSysCode = 0;
+
+ if ( nKeyCode & KEY_MOD1 )
+ {
+ nSysCode = MapVirtualKey( VK_CONTROL, 0 );
+ nSysCode = (nSysCode << 16) | (((ULONG)1) << 25);
+ ImplGetKeyNameText( nSysCode, aKeyBuf, nKeyBufLen, nMaxKeyLen, "Ctrl" );
+ }
+
+ if ( nKeyCode & KEY_MOD2 )
+ {
+ nSysCode = MapVirtualKey( VK_MENU, 0 );
+ nSysCode = (nSysCode << 16) | (((ULONG)1) << 25);
+ ImplGetKeyNameText( nSysCode, aKeyBuf, nKeyBufLen, nMaxKeyLen, "Alt" );
+ }
+
+ if ( nKeyCode & KEY_SHIFT )
+ {
+ nSysCode = MapVirtualKey( VK_SHIFT, 0 );
+ nSysCode = (nSysCode << 16) | (((ULONG)1) << 25);
+ ImplGetKeyNameText( nSysCode, aKeyBuf, nKeyBufLen, nMaxKeyLen, "Shift" );
+ }
+
+ USHORT nCode = nKeyCode & 0x0FFF;
+ ULONG nSysCode2 = 0;
+ sal_Char* pReplace = NULL;
+ sal_Unicode cSVCode = 0;
+ sal_Char aFBuf[4];
+ nSysCode = 0;
+
+ if ( (nCode >= KEY_0) && (nCode <= KEY_9) )
+ cSVCode = '0' + (nCode - KEY_0);
+ else if ( (nCode >= KEY_A) && (nCode <= KEY_Z) )
+ cSVCode = 'A' + (nCode - KEY_A);
+ else if ( (nCode >= KEY_F1) && (nCode <= KEY_F26) )
+ {
+ nSysCode = VK_F1 + (nCode - KEY_F1);
+ aFBuf[0] = 'F';
+ if ( (nCode >= KEY_F1) && (nCode <= KEY_F9) )
+ {
+ aFBuf[1] = sal::static_int_cast<sal_Char>('1' + (nCode - KEY_F1));
+ aFBuf[2] = 0;
+ }
+ else if ( (nCode >= KEY_F10) && (nCode <= KEY_F19) )
+ {
+ aFBuf[1] = '1';
+ aFBuf[2] = sal::static_int_cast<sal_Char>('0' + (nCode - KEY_F10));
+ aFBuf[3] = 0;
+ }
+ else
+ {
+ aFBuf[1] = '2';
+ aFBuf[2] = sal::static_int_cast<sal_Char>('0' + (nCode - KEY_F20));
+ aFBuf[3] = 0;
+ }
+ pReplace = aFBuf;
+ }
+ else
+ {
+ switch ( nCode )
+ {
+ case KEY_DOWN:
+ nSysCode = VK_DOWN;
+ nSysCode2 = (((ULONG)1) << 24);
+ pReplace = "Down";
+ break;
+ case KEY_UP:
+ nSysCode = VK_UP;
+ nSysCode2 = (((ULONG)1) << 24);
+ pReplace = "Up";
+ break;
+ case KEY_LEFT:
+ nSysCode = VK_LEFT;
+ nSysCode2 = (((ULONG)1) << 24);
+ pReplace = "Left";
+ break;
+ case KEY_RIGHT:
+ nSysCode = VK_RIGHT;
+ nSysCode2 = (((ULONG)1) << 24);
+ pReplace = "Right";
+ break;
+ case KEY_HOME:
+ nSysCode = VK_HOME;
+ nSysCode2 = (((ULONG)1) << 24);
+ pReplace = "Home";
+ break;
+ case KEY_END:
+ nSysCode = VK_END;
+ nSysCode2 = (((ULONG)1) << 24);
+ pReplace = "End";
+ break;
+ case KEY_PAGEUP:
+ nSysCode = VK_PRIOR;
+ nSysCode2 = (((ULONG)1) << 24);
+ pReplace = "Page Up";
+ break;
+ case KEY_PAGEDOWN:
+ nSysCode = VK_NEXT;
+ nSysCode2 = (((ULONG)1) << 24);
+ pReplace = "Page Down";
+ break;
+ case KEY_RETURN:
+ nSysCode = VK_RETURN;
+ pReplace = "Enter";
+ break;
+ case KEY_ESCAPE:
+ nSysCode = VK_ESCAPE;
+ pReplace = "Escape";
+ break;
+ case KEY_TAB:
+ nSysCode = VK_TAB;
+ pReplace = "Tab";
+ break;
+ case KEY_BACKSPACE:
+ nSysCode = VK_BACK;
+ pReplace = "Backspace";
+ break;
+ case KEY_SPACE:
+ nSysCode = VK_SPACE;
+ pReplace = "Space";
+ break;
+ case KEY_INSERT:
+ nSysCode = VK_INSERT;
+ nSysCode2 = (((ULONG)1) << 24);
+ pReplace = "Insert";
+ break;
+ case KEY_DELETE:
+ nSysCode = VK_DELETE;
+ nSysCode2 = (((ULONG)1) << 24);
+ pReplace = "Delete";
+ break;
+
+ case KEY_ADD:
+ cSVCode = '+';
+ break;
+ case KEY_SUBTRACT:
+ cSVCode = '-';
+ break;
+ case KEY_MULTIPLY:
+ cSVCode = '*';
+ break;
+ case KEY_DIVIDE:
+ cSVCode = '/';
+ break;
+ case KEY_POINT:
+ cSVCode = '.';
+ break;
+ case KEY_COMMA:
+ cSVCode = ',';
+ break;
+ case KEY_LESS:
+ cSVCode = '<';
+ break;
+ case KEY_GREATER:
+ cSVCode = '>';
+ break;
+ case KEY_EQUAL:
+ cSVCode = '=';
+ break;
+ }
+ }
+
+ if ( nSysCode )
+ {
+ nSysCode = MapVirtualKey( (UINT)nSysCode, 0 );
+ if ( nSysCode )
+ nSysCode = (nSysCode << 16) | nSysCode2;
+ ImplGetKeyNameText( nSysCode, aKeyBuf, nKeyBufLen, nMaxKeyLen, pReplace );
+ }
+ else
+ {
+ if ( cSVCode )
+ {
+ if ( nKeyBufLen > 0 )
+ aKeyBuf[ nKeyBufLen++ ] = '+';
+ if( nKeyBufLen < nMaxKeyLen )
+ aKeyBuf[ nKeyBufLen++ ] = cSVCode;
+ }
+ }
+
+ if( !nKeyBufLen )
+ return XubString();
+
+ return XubString( aKeyBuf, sal::static_int_cast< USHORT >(nKeyBufLen) );
+}
+
+// -----------------------------------------------------------------------
+
+XubString WinSalFrame::GetSymbolKeyName( const XubString&, USHORT nKeyCode )
+{
+ return GetKeyName( nKeyCode );
+}
+
+// -----------------------------------------------------------------------
+
+inline Color ImplWinColorToSal( COLORREF nColor )
+{
+ return Color( GetRValue( nColor ), GetGValue( nColor ), GetBValue( nColor ) );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplSalUpdateStyleFontA( HDC hDC, const LOGFONTA& rLogFont, Font& rFont )
+{
+ ImplSalLogFontToFontA( hDC, rLogFont, rFont );
+
+ // On Windows 9x, Windows NT we get sometimes very small sizes
+ // (for example for the small Caption height).
+ // So if it is MS Sans Serif, a none scalable font we use
+ // 8 Point as the minimum control height, in all other cases
+ // 6 Point is the smallest one
+ if ( rFont.GetHeight() < 8 )
+ {
+ if ( rtl_str_compareIgnoreAsciiCase( rLogFont.lfFaceName, "MS Sans Serif" ) == 0 )
+ rFont.SetHeight( 8 );
+ else if ( rFont.GetHeight() < 6 )
+ rFont.SetHeight( 6 );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplSalUpdateStyleFontW( HDC hDC, const LOGFONTW& rLogFont, Font& rFont )
+{
+ ImplSalLogFontToFontW( hDC, rLogFont, rFont );
+
+ // On Windows 9x, Windows NT we get sometimes very small sizes
+ // (for example for the small Caption height).
+ // So if it is MS Sans Serif, a none scalable font we use
+ // 8 Point as the minimum control height, in all other cases
+ // 6 Point is the smallest one
+ if ( rFont.GetHeight() < 8 )
+ {
+ if ( rtl_ustr_compareIgnoreAsciiCase( reinterpret_cast<const sal_Unicode*>(rLogFont.lfFaceName), reinterpret_cast<const sal_Unicode*>(L"MS Sans Serif") ) == 0 )
+ rFont.SetHeight( 8 );
+ else if ( rFont.GetHeight() < 6 )
+ rFont.SetHeight( 6 );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static long ImplA2I( const BYTE* pStr )
+{
+ long n = 0;
+ int nSign = 1;
+
+ if ( *pStr == '-' )
+ {
+ nSign = -1;
+ pStr++;
+ }
+
+ while( (*pStr >= 48) && (*pStr <= 57) )
+ {
+ n *= 10;
+ n += ((*pStr) - 48);
+ pStr++;
+ }
+
+ n *= nSign;
+
+ return n;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::UpdateSettings( AllSettings& rSettings )
+{
+ MouseSettings aMouseSettings = rSettings.GetMouseSettings();
+ aMouseSettings.SetDoubleClickTime( GetDoubleClickTime() );
+ aMouseSettings.SetDoubleClickWidth( GetSystemMetrics( SM_CXDOUBLECLK ) );
+ aMouseSettings.SetDoubleClickHeight( GetSystemMetrics( SM_CYDOUBLECLK ) );
+ long nDragWidth = GetSystemMetrics( SM_CXDRAG );
+ long nDragHeight = GetSystemMetrics( SM_CYDRAG );
+ if ( nDragWidth )
+ aMouseSettings.SetStartDragWidth( nDragWidth );
+ if ( nDragHeight )
+ aMouseSettings.SetStartDragHeight( nDragHeight );
+ HKEY hRegKey;
+ if ( RegOpenKey( HKEY_CURRENT_USER,
+ "Control Panel\\Desktop",
+ &hRegKey ) == ERROR_SUCCESS )
+ {
+ BYTE aValueBuf[10];
+ DWORD nValueSize = sizeof( aValueBuf );
+ DWORD nType;
+ if ( RegQueryValueEx( hRegKey, "MenuShowDelay", 0,
+ &nType, aValueBuf, &nValueSize ) == ERROR_SUCCESS )
+ {
+ if ( nType == REG_SZ )
+ aMouseSettings.SetMenuDelay( (ULONG)ImplA2I( aValueBuf ) );
+ }
+
+ RegCloseKey( hRegKey );
+ }
+
+ StyleSettings aStyleSettings = rSettings.GetStyleSettings();
+ BOOL bCompBorder = (aStyleSettings.GetOptions() & (STYLE_OPTION_MACSTYLE | STYLE_OPTION_UNIXSTYLE)) == 0;
+ // TODO: once those options vanish: just set bCompBorder to TRUE
+ // to have the system colors read
+ aStyleSettings.SetScrollBarSize( GetSystemMetrics( SM_CXVSCROLL ) );
+ aStyleSettings.SetSpinSize( GetSystemMetrics( SM_CXVSCROLL ) );
+ aStyleSettings.SetCursorBlinkTime( GetCaretBlinkTime() );
+ if ( bCompBorder )
+ {
+ aStyleSettings.SetFloatTitleHeight( GetSystemMetrics( SM_CYSMCAPTION ) );
+ aStyleSettings.SetTitleHeight( GetSystemMetrics( SM_CYCAPTION ) );
+ aStyleSettings.SetActiveBorderColor( ImplWinColorToSal( GetSysColor( COLOR_ACTIVEBORDER ) ) );
+ aStyleSettings.SetDeactiveBorderColor( ImplWinColorToSal( GetSysColor( COLOR_INACTIVEBORDER ) ) );
+ if ( aSalShlData.mnVersion >= 410 )
+ {
+ aStyleSettings.SetActiveColor2( ImplWinColorToSal( GetSysColor( COLOR_GRADIENTACTIVECAPTION ) ) );
+ aStyleSettings.SetDeactiveColor( ImplWinColorToSal( GetSysColor( COLOR_GRADIENTINACTIVECAPTION ) ) );
+ }
+ aStyleSettings.SetFaceColor( ImplWinColorToSal( GetSysColor( COLOR_3DFACE ) ) );
+ aStyleSettings.SetInactiveTabColor( aStyleSettings.GetFaceColor() );
+ aStyleSettings.SetLightColor( ImplWinColorToSal( GetSysColor( COLOR_3DHILIGHT ) ) );
+ aStyleSettings.SetLightBorderColor( ImplWinColorToSal( GetSysColor( COLOR_3DLIGHT ) ) );
+ aStyleSettings.SetShadowColor( ImplWinColorToSal( GetSysColor( COLOR_3DSHADOW ) ) );
+ aStyleSettings.SetDarkShadowColor( ImplWinColorToSal( GetSysColor( COLOR_3DDKSHADOW ) ) );
+ }
+ aStyleSettings.SetWorkspaceColor( ImplWinColorToSal( GetSysColor( COLOR_APPWORKSPACE ) ) );
+ aStyleSettings.SetHelpColor( ImplWinColorToSal( GetSysColor( COLOR_INFOBK ) ) );
+ aStyleSettings.SetHelpTextColor( ImplWinColorToSal( GetSysColor( COLOR_INFOTEXT ) ) );
+ aStyleSettings.SetDialogColor( aStyleSettings.GetFaceColor() );
+ aStyleSettings.SetDialogTextColor( aStyleSettings.GetButtonTextColor() );
+ aStyleSettings.SetButtonTextColor( ImplWinColorToSal( GetSysColor( COLOR_BTNTEXT ) ) );
+ aStyleSettings.SetButtonRolloverTextColor( aStyleSettings.GetButtonTextColor() );
+ aStyleSettings.SetRadioCheckTextColor( ImplWinColorToSal( GetSysColor( COLOR_WINDOWTEXT ) ) );
+ aStyleSettings.SetGroupTextColor( aStyleSettings.GetRadioCheckTextColor() );
+ aStyleSettings.SetLabelTextColor( aStyleSettings.GetRadioCheckTextColor() );
+ aStyleSettings.SetInfoTextColor( aStyleSettings.GetRadioCheckTextColor() );
+ aStyleSettings.SetWindowColor( ImplWinColorToSal( GetSysColor( COLOR_WINDOW ) ) );
+ aStyleSettings.SetActiveTabColor( aStyleSettings.GetWindowColor() );
+ aStyleSettings.SetWindowTextColor( ImplWinColorToSal( GetSysColor( COLOR_WINDOWTEXT ) ) );
+ aStyleSettings.SetFieldColor( aStyleSettings.GetWindowColor() );
+ aStyleSettings.SetFieldTextColor( aStyleSettings.GetWindowTextColor() );
+ aStyleSettings.SetFieldRolloverTextColor( aStyleSettings.GetFieldTextColor() );
+ aStyleSettings.SetHighlightColor( ImplWinColorToSal( GetSysColor( COLOR_HIGHLIGHT ) ) );
+ aStyleSettings.SetHighlightTextColor( ImplWinColorToSal( GetSysColor( COLOR_HIGHLIGHTTEXT ) ) );
+ aStyleSettings.SetMenuHighlightColor( aStyleSettings.GetHighlightColor() );
+ aStyleSettings.SetMenuHighlightTextColor( aStyleSettings.GetHighlightTextColor() );
+ if ( bCompBorder )
+ {
+ aStyleSettings.SetMenuColor( ImplWinColorToSal( GetSysColor( COLOR_MENU ) ) );
+ aStyleSettings.SetMenuBarColor( aStyleSettings.GetMenuColor() );
+ aStyleSettings.SetMenuBorderColor( aStyleSettings.GetLightBorderColor() ); // overriden below for flat menus
+ aStyleSettings.SetUseFlatBorders( FALSE );
+ aStyleSettings.SetUseFlatMenues( FALSE );
+ aStyleSettings.SetMenuTextColor( ImplWinColorToSal( GetSysColor( COLOR_MENUTEXT ) ) );
+ aStyleSettings.SetMenuBarTextColor( ImplWinColorToSal( GetSysColor( COLOR_MENUTEXT ) ) );
+ aStyleSettings.SetActiveColor( ImplWinColorToSal( GetSysColor( COLOR_ACTIVECAPTION ) ) );
+ aStyleSettings.SetActiveTextColor( ImplWinColorToSal( GetSysColor( COLOR_CAPTIONTEXT ) ) );
+ aStyleSettings.SetDeactiveColor( ImplWinColorToSal( GetSysColor( COLOR_INACTIVECAPTION ) ) );
+ aStyleSettings.SetDeactiveTextColor( ImplWinColorToSal( GetSysColor( COLOR_INACTIVECAPTIONTEXT ) ) );
+ if ( aSalShlData.mbWXP )
+ {
+ // only xp supports a different menu bar color
+ long bFlatMenues = 0;
+ SystemParametersInfo( SPI_GETFLATMENU, 0, &bFlatMenues, 0);
+ if( bFlatMenues )
+ {
+ aStyleSettings.SetUseFlatMenues( TRUE );
+ aStyleSettings.SetMenuBarColor( ImplWinColorToSal( GetSysColor( COLOR_MENUBAR ) ) );
+ aStyleSettings.SetMenuHighlightColor( ImplWinColorToSal( GetSysColor( COLOR_MENUHILIGHT ) ) );
+ aStyleSettings.SetMenuBorderColor( ImplWinColorToSal( GetSysColor( COLOR_3DSHADOW ) ) );
+
+ // flat borders for our controls etc. as well in this mode (ie, no 3d borders)
+ // this is not active in the classic style appearance
+ aStyleSettings.SetUseFlatBorders( TRUE );
+ }
+ }
+ }
+ // Bei hellgrau geben wir die Farbe vor, damit es besser aussieht
+ if ( aStyleSettings.GetFaceColor() == COL_LIGHTGRAY )
+ aStyleSettings.SetCheckedColor( Color( 0xCC, 0xCC, 0xCC ) );
+ else
+ {
+ // Checked-Color berechnen
+ Color aColor1 = aStyleSettings.GetFaceColor();
+ Color aColor2 = aStyleSettings.GetLightColor();
+ BYTE nRed = (BYTE)(((USHORT)aColor1.GetRed() + (USHORT)aColor2.GetRed())/2);
+ BYTE nGreen = (BYTE)(((USHORT)aColor1.GetGreen() + (USHORT)aColor2.GetGreen())/2);
+ BYTE nBlue = (BYTE)(((USHORT)aColor1.GetBlue() + (USHORT)aColor2.GetBlue())/2);
+ aStyleSettings.SetCheckedColor( Color( nRed, nGreen, nBlue ) );
+ }
+
+ // caret width
+ DWORD nCaretWidth = 2;
+ if( SystemParametersInfo( SPI_GETCARETWIDTH, 0, &nCaretWidth, 0 ) )
+ aStyleSettings.SetCursorSize( nCaretWidth );
+
+ // High contrast
+ HIGHCONTRAST hc;
+ hc.cbSize = sizeof( HIGHCONTRAST );
+ if( SystemParametersInfo( SPI_GETHIGHCONTRAST, hc.cbSize, &hc, 0) && (hc.dwFlags & HCF_HIGHCONTRASTON) )
+ aStyleSettings.SetHighContrastMode( 1 );
+ else
+ aStyleSettings.SetHighContrastMode( 0 );
+
+
+ // Query Fonts
+ Font aMenuFont = aStyleSettings.GetMenuFont();
+ Font aTitleFont = aStyleSettings.GetTitleFont();
+ Font aFloatTitleFont = aStyleSettings.GetFloatTitleFont();
+ Font aHelpFont = aStyleSettings.GetHelpFont();
+ Font aAppFont = aStyleSettings.GetAppFont();
+ Font aIconFont = aStyleSettings.GetIconFont();
+ HDC hDC = GetDC( 0 );
+ if ( aSalShlData.mbWNT )
+ {
+ NONCLIENTMETRICSW aNonClientMetrics;
+ aNonClientMetrics.cbSize = sizeof( aNonClientMetrics );
+ if ( SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, sizeof( aNonClientMetrics ), &aNonClientMetrics, 0 ) )
+ {
+ ImplSalUpdateStyleFontW( hDC, aNonClientMetrics.lfMenuFont, aMenuFont );
+ ImplSalUpdateStyleFontW( hDC, aNonClientMetrics.lfCaptionFont, aTitleFont );
+ ImplSalUpdateStyleFontW( hDC, aNonClientMetrics.lfSmCaptionFont, aFloatTitleFont );
+ ImplSalUpdateStyleFontW( hDC, aNonClientMetrics.lfStatusFont, aHelpFont );
+ ImplSalUpdateStyleFontW( hDC, aNonClientMetrics.lfMessageFont, aAppFont );
+
+ LOGFONTW aLogFont;
+ if ( SystemParametersInfoW( SPI_GETICONTITLELOGFONT, 0, &aLogFont, 0 ) )
+ ImplSalUpdateStyleFontW( hDC, aLogFont, aIconFont );
+ }
+ }
+ else
+ {
+ NONCLIENTMETRICSA aNonClientMetrics;
+ aNonClientMetrics.cbSize = sizeof( aNonClientMetrics );
+ if ( SystemParametersInfoA( SPI_GETNONCLIENTMETRICS, sizeof( aNonClientMetrics ), &aNonClientMetrics, 0 ) )
+ {
+ ImplSalUpdateStyleFontA( hDC, aNonClientMetrics.lfMenuFont, aMenuFont );
+ ImplSalUpdateStyleFontA( hDC, aNonClientMetrics.lfCaptionFont, aTitleFont );
+ ImplSalUpdateStyleFontA( hDC, aNonClientMetrics.lfSmCaptionFont, aFloatTitleFont );
+ ImplSalUpdateStyleFontA( hDC, aNonClientMetrics.lfStatusFont, aHelpFont );
+ ImplSalUpdateStyleFontA( hDC, aNonClientMetrics.lfMessageFont, aAppFont );
+
+ LOGFONTA aLogFont;
+ if ( SystemParametersInfoA( SPI_GETICONTITLELOGFONT, 0, &aLogFont, 0 ) )
+ ImplSalUpdateStyleFontA( hDC, aLogFont, aIconFont );
+ }
+ }
+
+ // get screen font resolution to calculate toolbox item size
+ long nDPIY = GetDeviceCaps( hDC, LOGPIXELSY );
+
+ ReleaseDC( 0, hDC );
+
+ long nHeightPx = aMenuFont.GetHeight() * nDPIY / 72;
+ aStyleSettings.SetToolbarIconSize( (((nHeightPx-1)*2) >= 28) ? STYLE_TOOLBAR_ICONSIZE_LARGE : STYLE_TOOLBAR_ICONSIZE_SMALL );
+
+ aStyleSettings.SetMenuFont( aMenuFont );
+ aStyleSettings.SetTitleFont( aTitleFont );
+ aStyleSettings.SetFloatTitleFont( aFloatTitleFont );
+ aStyleSettings.SetHelpFont( aHelpFont );
+ aStyleSettings.SetIconFont( aIconFont );
+ // We prefer Arial in the russian version, because MS Sans Serif
+ // is to wide for the dialogs
+ if ( rSettings.GetLanguage() == LANGUAGE_RUSSIAN )
+ {
+ XubString aFontName = aAppFont.GetName();
+ XubString aFirstName = aFontName.GetToken( 0, ';' );
+ if ( aFirstName.EqualsIgnoreCaseAscii( "MS Sans Serif" ) )
+ {
+ aFontName.InsertAscii( "Arial;", 0 );
+ aAppFont.SetName( aFontName );
+ }
+ }
+ aStyleSettings.SetAppFont( aAppFont );
+ aStyleSettings.SetGroupFont( aAppFont );
+ aStyleSettings.SetLabelFont( aAppFont );
+ aStyleSettings.SetRadioCheckFont( aAppFont );
+ aStyleSettings.SetPushButtonFont( aAppFont );
+ aStyleSettings.SetFieldFont( aAppFont );
+ if ( aAppFont.GetWeight() > WEIGHT_NORMAL )
+ aAppFont.SetWeight( WEIGHT_NORMAL );
+ aStyleSettings.SetInfoFont( aAppFont );
+ aStyleSettings.SetToolFont( aAppFont );
+
+ WIN_BOOL bDragFull;
+ if ( SystemParametersInfo( SPI_GETDRAGFULLWINDOWS, 0, &bDragFull, 0 ) )
+ {
+ ULONG nDragFullOptions = aStyleSettings.GetDragFullOptions();
+ if ( bDragFull )
+ nDragFullOptions |= DRAGFULL_OPTION_WINDOWMOVE | DRAGFULL_OPTION_WINDOWSIZE | DRAGFULL_OPTION_DOCKING | DRAGFULL_OPTION_SPLIT;
+ else
+ nDragFullOptions &= ~(DRAGFULL_OPTION_WINDOWMOVE | DRAGFULL_OPTION_WINDOWSIZE | DRAGFULL_OPTION_DOCKING | DRAGFULL_OPTION_SPLIT);
+ aStyleSettings.SetDragFullOptions( nDragFullOptions );
+ }
+
+ aStyleSettings.SetIconHorzSpace( GetSystemMetrics( SM_CXICONSPACING ) );
+ aStyleSettings.SetIconVertSpace( GetSystemMetrics( SM_CYICONSPACING ) );
+ if ( RegOpenKey( HKEY_CURRENT_USER,
+ "Control Panel\\International\\Calendars\\TwoDigitYearMax",
+ &hRegKey ) == ERROR_SUCCESS )
+ {
+ BYTE aValueBuf[10];
+ DWORD nValue;
+ DWORD nValueSize = sizeof( aValueBuf );
+ DWORD nType;
+ if ( RegQueryValueEx( hRegKey, "1", 0,
+ &nType, aValueBuf, &nValueSize ) == ERROR_SUCCESS )
+ {
+ if ( nType == REG_SZ )
+ {
+ nValue = (ULONG)ImplA2I( aValueBuf );
+ if ( (nValue > 1000) && (nValue < 10000) )
+ {
+ MiscSettings aMiscSettings = rSettings.GetMiscSettings();
+ utl::MiscCfg().SetYear2000( (sal_Int32)(nValue-99) );
+ rSettings.SetMiscSettings( aMiscSettings );
+ }
+ }
+ }
+
+ RegCloseKey( hRegKey );
+ }
+
+ rSettings.SetMouseSettings( aMouseSettings );
+ rSettings.SetStyleSettings( aStyleSettings );
+}
+
+// -----------------------------------------------------------------------
+
+SalBitmap* WinSalFrame::SnapShot()
+{
+ WinSalBitmap* pSalBitmap = NULL;
+
+ RECT aRect;
+ GetWindowRect( mhWnd, &aRect );
+
+ int nDX = aRect.right-aRect.left;
+ int nDY = aRect.bottom-aRect.top;
+ HDC hDC = GetWindowDC( mhWnd );
+ HBITMAP hBmpBitmap = CreateCompatibleBitmap( hDC, nDX, nDY );
+ HDC hBmpDC = ImplGetCachedDC( CACHED_HDC_1, hBmpBitmap );
+ BOOL bRet;
+
+ bRet = BitBlt( hBmpDC, 0, 0, nDX, nDY, hDC, 0, 0, SRCCOPY ) ? TRUE : FALSE;
+ ImplReleaseCachedDC( CACHED_HDC_1 );
+
+ if ( bRet )
+ {
+ pSalBitmap = new WinSalBitmap;
+
+ if ( !pSalBitmap->Create( hBmpBitmap, FALSE, FALSE ) )
+ {
+ delete pSalBitmap;
+ pSalBitmap = NULL;
+ }
+ }
+
+ return pSalBitmap;
+}
+
+// -----------------------------------------------------------------------
+
+const SystemEnvData* WinSalFrame::GetSystemData() const
+{
+ return &maSysData;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::Beep( SoundType eSoundType )
+{
+ static UINT aImplSoundTab[5] =
+ {
+ 0, // SOUND_DEFAULT
+ MB_ICONASTERISK, // SOUND_INFO
+ MB_ICONEXCLAMATION, // SOUND_WARNING
+ MB_ICONHAND, // SOUND_ERROR
+ MB_ICONQUESTION // SOUND_QUERY
+ };
+
+ if( eSoundType != SOUND_DISABLE ) // don't beep on disable
+ MessageBeep( aImplSoundTab[eSoundType] );
+}
+
+// -----------------------------------------------------------------------
+
+SalFrame::SalPointerState WinSalFrame::GetPointerState()
+{
+ SalPointerState aState;
+ aState.mnState = 0;
+
+ if ( GetKeyState( VK_LBUTTON ) & 0x8000 )
+ aState.mnState |= MOUSE_LEFT;
+ if ( GetKeyState( VK_MBUTTON ) & 0x8000 )
+ aState.mnState |= MOUSE_MIDDLE;
+ if ( GetKeyState( VK_RBUTTON ) & 0x8000 )
+ aState.mnState |= MOUSE_RIGHT;
+ if ( GetKeyState( VK_SHIFT ) & 0x8000 )
+ aState.mnState |= KEY_SHIFT;
+ if ( GetKeyState( VK_CONTROL ) & 0x8000 )
+ aState.mnState |= KEY_MOD1;
+ if ( GetKeyState( VK_MENU ) & 0x8000 )
+ aState.mnState |= KEY_MOD2;
+
+ POINT pt;
+ GetCursorPos( &pt );
+
+ aState.maPos = Point( pt.x - maGeometry.nX, pt.y - maGeometry.nY );
+ return aState;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::SetBackgroundBitmap( SalBitmap* )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::ResetClipRegion()
+{
+ SetWindowRgn( mhWnd, 0, TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::BeginSetClipRegion( ULONG nRects )
+{
+ if( mpClipRgnData )
+ delete [] (BYTE*)mpClipRgnData;
+ ULONG nRectBufSize = sizeof(RECT)*nRects;
+ mpClipRgnData = (RGNDATA*)new BYTE[sizeof(RGNDATA)-1+nRectBufSize];
+ mpClipRgnData->rdh.dwSize = sizeof( RGNDATAHEADER );
+ mpClipRgnData->rdh.iType = RDH_RECTANGLES;
+ mpClipRgnData->rdh.nCount = nRects;
+ mpClipRgnData->rdh.nRgnSize = nRectBufSize;
+ SetRectEmpty( &(mpClipRgnData->rdh.rcBound) );
+ mpNextClipRect = (RECT*)(&(mpClipRgnData->Buffer));
+ mbFirstClipRect = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
+{
+ if( ! mpClipRgnData )
+ return;
+
+ RECT* pRect = mpNextClipRect;
+ RECT* pBoundRect = &(mpClipRgnData->rdh.rcBound);
+ long nRight = nX + nWidth;
+ long nBottom = nY + nHeight;
+
+ if ( mbFirstClipRect )
+ {
+ pBoundRect->left = nX;
+ pBoundRect->top = nY;
+ pBoundRect->right = nRight;
+ pBoundRect->bottom = nBottom;
+ mbFirstClipRect = FALSE;
+ }
+ else
+ {
+ if ( nX < pBoundRect->left )
+ pBoundRect->left = (int)nX;
+
+ if ( nY < pBoundRect->top )
+ pBoundRect->top = (int)nY;
+
+ if ( nRight > pBoundRect->right )
+ pBoundRect->right = (int)nRight;
+
+ if ( nBottom > pBoundRect->bottom )
+ pBoundRect->bottom = (int)nBottom;
+ }
+
+ pRect->left = (int)nX;
+ pRect->top = (int)nY;
+ pRect->right = (int)nRight;
+ pRect->bottom = (int)nBottom;
+ if( (mpNextClipRect - (RECT*)(&mpClipRgnData->Buffer)) < (int)mpClipRgnData->rdh.nCount )
+ mpNextClipRect++;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::EndSetClipRegion()
+{
+ if( ! mpClipRgnData )
+ return;
+
+ HRGN hRegion;
+
+ // create region from accumulated rectangles
+ if ( mpClipRgnData->rdh.nCount == 1 )
+ {
+ RECT* pRect = &(mpClipRgnData->rdh.rcBound);
+ hRegion = CreateRectRgn( pRect->left, pRect->top,
+ pRect->right, pRect->bottom );
+ }
+ else
+ {
+ ULONG nSize = mpClipRgnData->rdh.nRgnSize+sizeof(RGNDATAHEADER);
+ hRegion = ExtCreateRegion( NULL, nSize, mpClipRgnData );
+ }
+ delete [] (BYTE*)mpClipRgnData;
+ mpClipRgnData = NULL;
+
+ DBG_ASSERT( hRegion, "WinSalFrame::EndSetClipRegion() - Can't create ClipRegion" );
+ if( hRegion )
+ {
+ RECT aWindowRect;
+ GetWindowRect( mhWnd, &aWindowRect );
+ POINT aPt;
+ aPt.x=0;
+ aPt.y=0;
+ ClientToScreen( mhWnd, &aPt );
+ OffsetRgn( hRegion, aPt.x - aWindowRect.left, aPt.y - aWindowRect.top );
+
+ if( SetWindowRgn( mhWnd, hRegion, TRUE ) == 0 )
+ DeleteObject( hRegion );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static long ImplHandleMouseMsg( HWND hWnd, UINT nMsg,
+ WPARAM wParam, LPARAM lParam )
+{
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( !pFrame )
+ return 0;
+
+ if( nMsg == WM_LBUTTONDOWN || nMsg == WM_MBUTTONDOWN || nMsg == WM_RBUTTONDOWN )
+ {
+ // #103168# post again if async focus has not arrived yet
+ // hopefully we will not receive the corresponding button up before this
+ // button down arrives again
+ Window *pWin = pFrame->GetWindow();
+ if( pWin && pWin->ImplGetWindowImpl()->mpFrameData->mnFocusId )
+ {
+ ImplPostMessage( hWnd, nMsg, wParam, lParam );
+ return 1;
+ }
+ }
+ SalMouseEvent aMouseEvt;
+ long nRet;
+ USHORT nEvent = 0;
+ BOOL bCall = TRUE;
+
+ aMouseEvt.mnX = (short)LOWORD( lParam );
+ aMouseEvt.mnY = (short)HIWORD( lParam );
+ aMouseEvt.mnCode = 0;
+ aMouseEvt.mnTime = GetMessageTime();
+
+ // Wegen (Logitech-)MouseTreiber ueber GetKeyState() gehen, die auf
+ // mittlerer Maustaste Doppelklick simulieren und den KeyStatus nicht
+ // beruecksichtigen
+
+ if ( GetKeyState( VK_LBUTTON ) & 0x8000 )
+ aMouseEvt.mnCode |= MOUSE_LEFT;
+ if ( GetKeyState( VK_MBUTTON ) & 0x8000 )
+ aMouseEvt.mnCode |= MOUSE_MIDDLE;
+ if ( GetKeyState( VK_RBUTTON ) & 0x8000 )
+ aMouseEvt.mnCode |= MOUSE_RIGHT;
+ if ( GetKeyState( VK_SHIFT ) & 0x8000 )
+ aMouseEvt.mnCode |= KEY_SHIFT;
+ if ( GetKeyState( VK_CONTROL ) & 0x8000 )
+ aMouseEvt.mnCode |= KEY_MOD1;
+ if ( GetKeyState( VK_MENU ) & 0x8000 )
+ aMouseEvt.mnCode |= KEY_MOD2;
+
+ switch ( nMsg )
+ {
+ case WM_MOUSEMOVE:
+ {
+ // Da bei Druecken von Modifier-Tasten die MouseEvents
+ // nicht zusammengefast werden (da diese durch KeyEvents
+ // unterbrochen werden), machen wir dieses hier selber
+ if ( aMouseEvt.mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2) )
+ {
+ MSG aTempMsg;
+ if ( ImplPeekMessage( &aTempMsg, hWnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE | PM_NOYIELD ) )
+ {
+ if ( (aTempMsg.message == WM_MOUSEMOVE) &&
+ (aTempMsg.wParam == wParam) )
+ return 1;
+ }
+ }
+
+ SalData* pSalData = GetSalData();
+ // Test for MouseLeave
+ if ( pSalData->mhWantLeaveMsg && (pSalData->mhWantLeaveMsg != hWnd) )
+ ImplSendMessage( pSalData->mhWantLeaveMsg, SAL_MSG_MOUSELEAVE, 0, GetMessagePos() );
+
+ pSalData->mhWantLeaveMsg = hWnd;
+ // Start MouseLeave-Timer
+ if ( !pSalData->mpMouseLeaveTimer )
+ {
+ pSalData->mpMouseLeaveTimer = new AutoTimer;
+ pSalData->mpMouseLeaveTimer->SetTimeout( SAL_MOUSELEAVE_TIMEOUT );
+ pSalData->mpMouseLeaveTimer->Start();
+ // We dont need to set a timeout handler, because we test
+ // for mouseleave in the timeout callback
+ }
+ aMouseEvt.mnButton = 0;
+ nEvent = SALEVENT_MOUSEMOVE;
+ }
+ break;
+
+ case WM_NCMOUSEMOVE:
+ case SAL_MSG_MOUSELEAVE:
+ {
+ SalData* pSalData = GetSalData();
+ if ( pSalData->mhWantLeaveMsg == hWnd )
+ {
+ pSalData->mhWantLeaveMsg = 0;
+ if ( pSalData->mpMouseLeaveTimer )
+ {
+ delete pSalData->mpMouseLeaveTimer;
+ pSalData->mpMouseLeaveTimer = NULL;
+ }
+ // Mouse-Coordinaates are relativ to the screen
+ POINT aPt;
+ aPt.x = (short)LOWORD( lParam );
+ aPt.y = (short)HIWORD( lParam );
+ ScreenToClient( hWnd, &aPt );
+ aMouseEvt.mnX = aPt.x;
+ aMouseEvt.mnY = aPt.y;
+ aMouseEvt.mnButton = 0;
+ nEvent = SALEVENT_MOUSELEAVE;
+ }
+ else
+ bCall = FALSE;
+ }
+ break;
+
+ case WM_LBUTTONDOWN:
+ aMouseEvt.mnButton = MOUSE_LEFT;
+ nEvent = SALEVENT_MOUSEBUTTONDOWN;
+ break;
+
+ case WM_MBUTTONDOWN:
+ aMouseEvt.mnButton = MOUSE_MIDDLE;
+ nEvent = SALEVENT_MOUSEBUTTONDOWN;
+ break;
+
+ case WM_RBUTTONDOWN:
+ aMouseEvt.mnButton = MOUSE_RIGHT;
+ nEvent = SALEVENT_MOUSEBUTTONDOWN;
+ break;
+
+ case WM_LBUTTONUP:
+ aMouseEvt.mnButton = MOUSE_LEFT;
+ nEvent = SALEVENT_MOUSEBUTTONUP;
+ break;
+
+ case WM_MBUTTONUP:
+ aMouseEvt.mnButton = MOUSE_MIDDLE;
+ nEvent = SALEVENT_MOUSEBUTTONUP;
+ break;
+
+ case WM_RBUTTONUP:
+ aMouseEvt.mnButton = MOUSE_RIGHT;
+ nEvent = SALEVENT_MOUSEBUTTONUP;
+ break;
+ }
+
+ // check if this window was destroyed - this might happen if we are the help window
+ // and sent a mouse leave message to the application which killed the help window, ie ourself
+ if( !IsWindow( hWnd ) )
+ return 0;
+
+ if ( bCall )
+ {
+ if ( nEvent == SALEVENT_MOUSEBUTTONDOWN )
+ UpdateWindow( hWnd );
+
+ // --- RTL --- (mirror mouse pos)
+ if( Application::GetSettings().GetLayoutRTL() )
+ aMouseEvt.mnX = pFrame->maGeometry.nWidth-1-aMouseEvt.mnX;
+
+ nRet = pFrame->CallCallback( nEvent, &aMouseEvt );
+ if ( nMsg == WM_MOUSEMOVE )
+ SetCursor( pFrame->mhCursor );
+ }
+ else
+ nRet = 0;
+
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+static long ImplHandleMouseActivateMsg( HWND hWnd )
+{
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( !pFrame )
+ return 0;
+
+ if ( pFrame->mbFloatWin )
+ return TRUE;
+
+ SalMouseActivateEvent aMouseActivateEvt;
+ POINT aPt;
+ GetCursorPos( &aPt );
+ ScreenToClient( hWnd, &aPt );
+ aMouseActivateEvt.mnX = aPt.x;
+ aMouseActivateEvt.mnY = aPt.y;
+ return pFrame->CallCallback( SALEVENT_MOUSEACTIVATE, &aMouseActivateEvt );
+}
+
+// -----------------------------------------------------------------------
+
+static long ImplHandleWheelMsg( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
+{
+ DBG_ASSERT( nMsg == WM_MOUSEWHEEL ||
+ nMsg == WM_MOUSEHWHEEL,
+ "ImplHandleWheelMsg() called with no wheel mouse event" );
+
+ ImplSalYieldMutexAcquireWithWait();
+
+ long nRet = 0;
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ WORD nWinModCode = LOWORD( wParam );
+ POINT aWinPt;
+ aWinPt.x = (short)LOWORD( lParam );
+ aWinPt.y = (short)HIWORD( lParam );
+ ScreenToClient( hWnd, &aWinPt );
+
+ SalWheelMouseEvent aWheelEvt;
+ aWheelEvt.mnTime = GetMessageTime();
+ aWheelEvt.mnX = aWinPt.x;
+ aWheelEvt.mnY = aWinPt.y;
+ aWheelEvt.mnCode = 0;
+ aWheelEvt.mnDelta = (short)HIWORD( wParam );
+ aWheelEvt.mnNotchDelta = aWheelEvt.mnDelta/WHEEL_DELTA;
+ if( aWheelEvt.mnNotchDelta == 0 )
+ {
+ if( aWheelEvt.mnDelta > 0 )
+ aWheelEvt.mnNotchDelta = 1;
+ else if( aWheelEvt.mnDelta < 0 )
+ aWheelEvt.mnNotchDelta = -1;
+ }
+
+ if( nMsg == WM_MOUSEWHEEL )
+ {
+ if ( aSalShlData.mnWheelScrollLines == WHEEL_PAGESCROLL )
+ aWheelEvt.mnScrollLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
+ else
+ aWheelEvt.mnScrollLines = aSalShlData.mnWheelScrollLines;
+ aWheelEvt.mbHorz = FALSE;
+ }
+ else
+ {
+ aWheelEvt.mnScrollLines = aSalShlData.mnWheelScrollChars;
+ aWheelEvt.mbHorz = TRUE;
+ }
+
+ if ( nWinModCode & MK_SHIFT )
+ aWheelEvt.mnCode |= KEY_SHIFT;
+ if ( nWinModCode & MK_CONTROL )
+ aWheelEvt.mnCode |= KEY_MOD1;
+ if ( GetKeyState( VK_MENU ) & 0x8000 )
+ aWheelEvt.mnCode |= KEY_MOD2;
+
+ // --- RTL --- (mirror mouse pos)
+ if( Application::GetSettings().GetLayoutRTL() )
+ aWheelEvt.mnX = pFrame->maGeometry.nWidth-1-aWheelEvt.mnX;
+
+ nRet = pFrame->CallCallback( SALEVENT_WHEELMOUSE, &aWheelEvt );
+ }
+
+ ImplSalYieldMutexRelease();
+
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+static USHORT ImplSalGetKeyCode( WPARAM wParam )
+{
+ USHORT nKeyCode;
+
+ // convert KeyCode
+ if ( wParam < KEY_TAB_SIZE )
+ nKeyCode = aImplTranslateKeyTab[wParam];
+ else
+ {
+ SalData* pSalData = GetSalData();
+ std::map< UINT, USHORT >::const_iterator it = pSalData->maVKMap.find( (UINT)wParam );
+ if( it != pSalData->maVKMap.end() )
+ nKeyCode = it->second;
+ else
+ nKeyCode = 0;
+ }
+
+ return nKeyCode;
+}
+
+// -----------------------------------------------------------------------
+
+static UINT ImplStrToNum( const sal_Char* pStr )
+{
+ USHORT n = 0;
+
+ // Solange es sich um eine Ziffer handelt, String umwandeln
+ while( (*pStr >= 48) && (*pStr <= 57) )
+ {
+ n *= 10;
+ n += ((*pStr) - 48);
+ pStr++;
+ }
+
+ return n;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplUpdateInputLang( WinSalFrame* pFrame )
+{
+ BOOL bLanguageChange = FALSE;
+ UINT nLang = LOWORD( GetKeyboardLayout( 0 ) );
+ if ( nLang && nLang != pFrame->mnInputLang )
+ {
+ // keep input lang up-to-date
+ pFrame->mnInputLang = nLang;
+ bLanguageChange = TRUE;
+ }
+
+ // If we are on Windows NT we use Unicode FrameProcs and so we
+ // get Unicode charcodes directly from Windows
+ // no need to set up a code page
+ if ( aSalShlData.mbWNT )
+ return;
+
+ if ( !nLang )
+ {
+ pFrame->mnInputLang = 0;
+ pFrame->mnInputCodePage = GetACP();
+ }
+ else if ( bLanguageChange )
+ {
+ sal_Char aBuf[10];
+ if ( GetLocaleInfoA( MAKELCID( nLang, SORT_DEFAULT ), LOCALE_IDEFAULTANSICODEPAGE,
+ aBuf, sizeof(aBuf) ) > 0 )
+ {
+ pFrame->mnInputCodePage = ImplStrToNum( aBuf );
+ if ( !pFrame->mnInputCodePage )
+ pFrame->mnInputCodePage = GetACP();
+ }
+ else
+ pFrame->mnInputCodePage = GetACP();
+ }
+}
+
+
+static sal_Unicode ImplGetCharCode( WinSalFrame* pFrame, WPARAM nCharCode )
+{
+ ImplUpdateInputLang( pFrame );
+
+ // If we are on Windows NT we use Unicode FrameProcs and so we
+ // get Unicode charcodes directly from Windows
+ if ( aSalShlData.mbWNT )
+ return (sal_Unicode)nCharCode;
+
+ sal_Char aCharBuf[2];
+ int nCharLen;
+ WCHAR c;
+ if ( nCharCode > 0xFF )
+ {
+ aCharBuf[0] = (sal_Char)(nCharCode>>8);
+ aCharBuf[1] = (sal_Char)nCharCode;
+ nCharLen = 2;
+ }
+ else
+ {
+ aCharBuf[0] = (sal_Char)nCharCode;
+ nCharLen = 1;
+ }
+ if ( ::MultiByteToWideChar( pFrame->mnInputCodePage,
+ MB_PRECOMPOSED,
+ aCharBuf, nCharLen, &c, 1 ) )
+ return (sal_Unicode)c;
+ else
+ return (sal_Unicode)nCharCode;
+}
+
+// -----------------------------------------------------------------------
+
+LanguageType WinSalFrame::GetInputLanguage()
+{
+ if( !mnInputLang )
+ ImplUpdateInputLang( this );
+
+ if( !mnInputLang )
+ return LANGUAGE_DONTKNOW;
+ else
+ return (LanguageType) mnInputLang;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL WinSalFrame::MapUnicodeToKeyCode( sal_Unicode aUnicode, LanguageType aLangType, KeyCode& rKeyCode )
+{
+ BOOL bRet = FALSE;
+ HKL hkl = 0;
+
+ // just use the passed language identifier, do not try to load additional keyboard support
+ hkl = (HKL) aLangType;
+
+ if( hkl )
+ {
+ SHORT scan = VkKeyScanExW( aUnicode, hkl );
+ if( LOWORD(scan) == 0xFFFF )
+ // keyboard not loaded or key cannot be mapped
+ bRet = FALSE;
+ else
+ {
+ BYTE vkeycode = LOBYTE(scan);
+ BYTE shiftstate = HIBYTE(scan);
+
+ // Last argument is set to FALSE, because there's no decission made
+ // yet which key should be assigned to MOD3 modifier on Windows.
+ // Windows key - user's can be confused, because it should display
+ // Windows menu (applies to both left/right key)
+ // Menu key - this key is used to display context menu
+ // AltGr key - probably it has no sense
+ rKeyCode = KeyCode( ImplSalGetKeyCode( vkeycode ),
+ (shiftstate & 0x01) ? TRUE : FALSE, // shift
+ (shiftstate & 0x02) ? TRUE : FALSE, // ctrl
+ (shiftstate & 0x04) ? TRUE : FALSE, // alt
+ FALSE );
+ bRet = TRUE;
+ }
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+static long ImplHandleKeyMsg( HWND hWnd, UINT nMsg,
+ WPARAM wParam, LPARAM lParam, LRESULT& rResult )
+{
+ static BOOL bIgnoreCharMsg = FALSE;
+ static WPARAM nDeadChar = 0;
+ static WPARAM nLastVKChar = 0;
+ static USHORT nLastChar = 0;
+ static USHORT nLastModKeyCode = 0;
+ static bool bWaitForModKeyRelease = false;
+ USHORT nRepeat = LOWORD( lParam )-1;
+ USHORT nModCode = 0;
+
+ // Key wurde evtl. durch SysChild an uns weitergeleitet und
+ // darf somit dann nicht doppelt verarbeitet werden
+ GetSalData()->mnSalObjWantKeyEvt = 0;
+
+ if ( nMsg == WM_DEADCHAR )
+ {
+ nDeadChar = wParam;
+ return 0;
+ }
+
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( !pFrame )
+ return 0;
+
+ // Wir restaurieren den Background-Modus bei jeder Texteingabe,
+ // da einige Tools wie RichWin uns diesen hin- und wieder umsetzen
+ if ( pFrame->mpGraphics &&
+ pFrame->mpGraphics->mhDC )
+ SetBkMode( pFrame->mpGraphics->mhDC, TRANSPARENT );
+
+ // determine modifiers
+ if ( GetKeyState( VK_SHIFT ) & 0x8000 )
+ nModCode |= KEY_SHIFT;
+ if ( GetKeyState( VK_CONTROL ) & 0x8000 )
+ nModCode |= KEY_MOD1;
+ if ( GetKeyState( VK_MENU ) & 0x8000 )
+ nModCode |= KEY_MOD2;
+
+ if ( (nMsg == WM_CHAR) || (nMsg == WM_SYSCHAR) )
+ {
+ nDeadChar = 0;
+
+ if ( bIgnoreCharMsg )
+ {
+ bIgnoreCharMsg = FALSE;
+ // #101635# if zero is returned here for WM_SYSCHAR (ALT+<key>) Windows will beep
+ // becaus this 'hotkey' was not processed -> better return 1
+ // except for Alt-SPACE which should always open the sysmenu (#104616#)
+
+ // also return zero if a system menubar is available that might process this hotkey
+ // this also applies to the OLE inplace embedding where we are a child window
+ if( (GetWindowStyle( hWnd ) & WS_CHILD) || GetMenu( hWnd ) || (wParam == 0x20) )
+ return 0;
+ else
+ return 1;
+ }
+
+ // Backspace ignorieren wir als eigenstaendige Taste,
+ // damit wir keine Probleme in Kombination mit einem
+ // DeadKey bekommen
+ if ( wParam == 0x08 ) // BACKSPACE
+ return 0;
+
+ // Hier kommen nur "freifliegende" WM_CHAR Message an, die durch
+ // eintippen einer ALT-NUMPAD Kombination erzeugt wurden
+ SalKeyEvent aKeyEvt;
+
+ if ( (wParam >= '0') && (wParam <= '9') )
+ aKeyEvt.mnCode = sal::static_int_cast<USHORT>(KEYGROUP_NUM + wParam - '0');
+ else if ( (wParam >= 'A') && (wParam <= 'Z') )
+ aKeyEvt.mnCode = sal::static_int_cast<USHORT>(KEYGROUP_ALPHA + wParam - 'A');
+ else if ( (wParam >= 'a') && (wParam <= 'z') )
+ aKeyEvt.mnCode = sal::static_int_cast<USHORT>(KEYGROUP_ALPHA + wParam - 'a');
+ else if ( wParam == 0x0D ) // RETURN
+ aKeyEvt.mnCode = KEY_RETURN;
+ else if ( wParam == 0x1B ) // ESCAPE
+ aKeyEvt.mnCode = KEY_ESCAPE;
+ else if ( wParam == 0x09 ) // TAB
+ aKeyEvt.mnCode = KEY_TAB;
+ else if ( wParam == 0x20 ) // SPACE
+ aKeyEvt.mnCode = KEY_SPACE;
+ else
+ aKeyEvt.mnCode = 0;
+
+ aKeyEvt.mnTime = GetMessageTime();
+ aKeyEvt.mnCode |= nModCode;
+ aKeyEvt.mnCharCode = ImplGetCharCode( pFrame, wParam );
+ aKeyEvt.mnRepeat = nRepeat;
+ nLastChar = 0;
+ nLastVKChar = 0;
+ long nRet = pFrame->CallCallback( SALEVENT_KEYINPUT, &aKeyEvt );
+ pFrame->CallCallback( SALEVENT_KEYUP, &aKeyEvt );
+ return nRet;
+ }
+ // #i11583#, MCD, 2003-01-13, Support for WM_UNICHAR & Keyman 6.0; addition begins
+ else if( nMsg == WM_UNICHAR )
+ {
+ // If Windows is asking if we accept WM_UNICHAR, return TRUE
+ if(wParam == UNICODE_NOCHAR)
+ {
+ rResult = TRUE; // ssa: this will actually return TRUE to windows
+ return 1; // ...but this will only avoid calling the defwindowproc
+ }
+
+ SalKeyEvent aKeyEvt;
+ aKeyEvt.mnCode = nModCode; // Or should it be 0? - as this is always a character returned
+ aKeyEvt.mnTime = GetMessageTime();
+ aKeyEvt.mnRepeat = 0;
+
+ if( wParam >= Uni_SupplementaryPlanesStart )
+ {
+ // character is supplementary char in UTF-32 format - must be converted to UTF-16 supplementary pair
+ // sal_Unicode ch = (sal_Unicode) Uni_UTF32ToSurrogate1(wParam);
+ nLastChar = 0;
+ nLastVKChar = 0;
+ pFrame->CallCallback( SALEVENT_KEYINPUT, &aKeyEvt );
+ pFrame->CallCallback( SALEVENT_KEYUP, &aKeyEvt );
+ wParam = (sal_Unicode) Uni_UTF32ToSurrogate2( wParam );
+ }
+
+ aKeyEvt.mnCharCode = (sal_Unicode) wParam;
+
+ nLastChar = 0;
+ nLastVKChar = 0;
+ long nRet = pFrame->CallCallback( SALEVENT_KEYINPUT, &aKeyEvt );
+ pFrame->CallCallback( SALEVENT_KEYUP, &aKeyEvt );
+
+ return nRet;
+ }
+ // MCD, 2003-01-13, Support for WM_UNICHAR & Keyman 6.0; addition ends
+ else
+ {
+ // Bei Shift, Control und Menu schicken wir einen KeyModChange-Event
+ if ( (wParam == VK_SHIFT) || (wParam == VK_CONTROL) || (wParam == VK_MENU) )
+ {
+ SalKeyModEvent aModEvt;
+ aModEvt.mnTime = GetMessageTime();
+ aModEvt.mnCode = nModCode;
+ aModEvt.mnModKeyCode = 0; // no command events will be sent if this member is 0
+
+ USHORT tmpCode = 0;
+ if( GetKeyState( VK_LSHIFT ) & 0x8000 )
+ tmpCode |= MODKEY_LSHIFT;
+ if( GetKeyState( VK_RSHIFT ) & 0x8000 )
+ tmpCode |= MODKEY_RSHIFT;
+ if( GetKeyState( VK_LCONTROL ) & 0x8000 )
+ tmpCode |= MODKEY_LMOD1;
+ if( GetKeyState( VK_RCONTROL ) & 0x8000 )
+ tmpCode |= MODKEY_RMOD1;
+ if( GetKeyState( VK_LMENU ) & 0x8000 )
+ tmpCode |= MODKEY_LMOD2;
+ if( GetKeyState( VK_RMENU ) & 0x8000 )
+ tmpCode |= MODKEY_RMOD2;
+
+ if( tmpCode < nLastModKeyCode )
+ {
+ aModEvt.mnModKeyCode = nLastModKeyCode;
+ nLastModKeyCode = 0;
+ bWaitForModKeyRelease = true;
+ }
+ else
+ {
+ if( !bWaitForModKeyRelease )
+ nLastModKeyCode = tmpCode;
+ }
+
+ if( !tmpCode )
+ bWaitForModKeyRelease = false;
+
+ return pFrame->CallCallback( SALEVENT_KEYMODCHANGE, &aModEvt );
+ }
+ else
+ {
+ SalKeyEvent aKeyEvt;
+ USHORT nEvent;
+ MSG aCharMsg;
+ WIN_BOOL bCharPeek = FALSE;
+ UINT nCharMsg = WM_CHAR;
+ BOOL bKeyUp = (nMsg == WM_KEYUP) || (nMsg == WM_SYSKEYUP);
+
+ nLastModKeyCode = 0; // make sure no modkey messages are sent if they belong to a hotkey (see above)
+ aKeyEvt.mnCharCode = 0;
+ aKeyEvt.mnCode = 0;
+
+ aKeyEvt.mnCode = ImplSalGetKeyCode( wParam );
+ if ( !bKeyUp )
+ {
+ // check for charcode
+ // Mit Hilfe von PeekMessage holen wir uns jetzt die
+ // zugehoerige WM_CHAR Message, wenn vorhanden.
+ // Diese WM_CHAR Message steht immer am Anfang der
+ // Messagequeue. Ausserdem ist sichergestellt, dass immer
+ // nur eine WM_CHAR Message in der Queue steht.
+ bCharPeek = ImplPeekMessage( &aCharMsg, hWnd,
+ WM_CHAR, WM_CHAR, PM_NOREMOVE | PM_NOYIELD );
+ if ( bCharPeek && (nDeadChar == aCharMsg.wParam) )
+ {
+ bCharPeek = FALSE;
+ nDeadChar = 0;
+
+ if ( wParam == VK_BACK )
+ {
+ ImplPeekMessage( &aCharMsg, hWnd,
+ nCharMsg, nCharMsg, PM_REMOVE | PM_NOYIELD );
+ return 0;
+ }
+ }
+ else
+ {
+ if ( !bCharPeek )
+ {
+ bCharPeek = ImplPeekMessage( &aCharMsg, hWnd,
+ WM_SYSCHAR, WM_SYSCHAR, PM_NOREMOVE | PM_NOYIELD );
+ nCharMsg = WM_SYSCHAR;
+ }
+ }
+ if ( bCharPeek )
+ aKeyEvt.mnCharCode = ImplGetCharCode( pFrame, aCharMsg.wParam );
+ else
+ aKeyEvt.mnCharCode = 0;
+
+ nLastChar = aKeyEvt.mnCharCode;
+ nLastVKChar = wParam;
+ }
+ else
+ {
+ if ( wParam == nLastVKChar )
+ {
+ aKeyEvt.mnCharCode = nLastChar;
+ nLastChar = 0;
+ nLastVKChar = 0;
+ }
+ }
+
+ if ( aKeyEvt.mnCode || aKeyEvt.mnCharCode )
+ {
+ if ( bKeyUp )
+ nEvent = SALEVENT_KEYUP;
+ else
+ nEvent = SALEVENT_KEYINPUT;
+
+ aKeyEvt.mnTime = GetMessageTime();
+ aKeyEvt.mnCode |= nModCode;
+ aKeyEvt.mnRepeat = nRepeat;
+
+ if( (nModCode & (KEY_MOD1|KEY_MOD2)) == (KEY_MOD1|KEY_MOD2) &&
+ aKeyEvt.mnCharCode )
+ {
+ // this is actually AltGr and should not be handled as Alt
+ aKeyEvt.mnCode &= ~(KEY_MOD1|KEY_MOD2);
+ }
+
+ bIgnoreCharMsg = bCharPeek ? TRUE : FALSE;
+ long nRet = pFrame->CallCallback( nEvent, &aKeyEvt );
+ // independent part only reacts on keyup but Windows does not send
+ // keyup for VK_HANJA
+ if( aKeyEvt.mnCode == KEY_HANGUL_HANJA )
+ nRet = pFrame->CallCallback( SALEVENT_KEYUP, &aKeyEvt );
+
+ bIgnoreCharMsg = FALSE;
+
+ // char-message, than remove or ignore
+ if ( bCharPeek )
+ {
+ nDeadChar = 0;
+ if ( nRet )
+ {
+ ImplPeekMessage( &aCharMsg, hWnd,
+ nCharMsg, nCharMsg, PM_REMOVE | PM_NOYIELD );
+ }
+ else
+ bIgnoreCharMsg = TRUE;
+ }
+
+ return nRet;
+ }
+ else
+ return 0;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+long ImplHandleSalObjKeyMsg( HWND hWnd, UINT nMsg,
+ WPARAM wParam, LPARAM lParam )
+{
+ if ( (nMsg == WM_KEYDOWN) || (nMsg == WM_KEYUP) )
+ {
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( !pFrame )
+ return 0;
+
+ USHORT nRepeat = LOWORD( lParam )-1;
+ USHORT nModCode = 0;
+
+ // determine modifiers
+ if ( GetKeyState( VK_SHIFT ) & 0x8000 )
+ nModCode |= KEY_SHIFT;
+ if ( GetKeyState( VK_CONTROL ) & 0x8000 )
+ nModCode |= KEY_MOD1;
+ if ( GetKeyState( VK_MENU ) & 0x8000 )
+ nModCode |= KEY_MOD2;
+
+ if ( (wParam != VK_SHIFT) && (wParam != VK_CONTROL) && (wParam != VK_MENU) )
+ {
+ SalKeyEvent aKeyEvt;
+ USHORT nEvent;
+ BOOL bKeyUp = (nMsg == WM_KEYUP) || (nMsg == WM_SYSKEYUP);
+
+ // convert KeyCode
+ aKeyEvt.mnCode = ImplSalGetKeyCode( wParam );
+ aKeyEvt.mnCharCode = 0;
+
+ if ( aKeyEvt.mnCode )
+ {
+ if ( bKeyUp )
+ nEvent = SALEVENT_KEYUP;
+ else
+ nEvent = SALEVENT_KEYINPUT;
+
+ aKeyEvt.mnTime = GetMessageTime();
+ aKeyEvt.mnCode |= nModCode;
+ aKeyEvt.mnRepeat = nRepeat;
+ long nRet = pFrame->CallCallback( nEvent, &aKeyEvt );
+ return nRet;
+ }
+ else
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+long ImplHandleSalObjSysCharMsg( HWND hWnd, WPARAM wParam, LPARAM lParam )
+{
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( !pFrame )
+ return 0;
+
+ USHORT nRepeat = LOWORD( lParam )-1;
+ USHORT nModCode = 0;
+ USHORT cKeyCode = (USHORT)wParam;
+
+ // determine modifiers
+ if ( GetKeyState( VK_SHIFT ) & 0x8000 )
+ nModCode |= KEY_SHIFT;
+ if ( GetKeyState( VK_CONTROL ) & 0x8000 )
+ nModCode |= KEY_MOD1;
+ nModCode |= KEY_MOD2;
+
+ // KeyEvent zusammenbauen
+ SalKeyEvent aKeyEvt;
+ aKeyEvt.mnTime = GetMessageTime();
+ if ( (cKeyCode >= 48) && (cKeyCode <= 57) )
+ aKeyEvt.mnCode = KEY_0+(cKeyCode-48);
+ else if ( (cKeyCode >= 65) && (cKeyCode <= 90) )
+ aKeyEvt.mnCode = KEY_A+(cKeyCode-65);
+ else if ( (cKeyCode >= 97) && (cKeyCode <= 122) )
+ aKeyEvt.mnCode = KEY_A+(cKeyCode-97);
+ else
+ aKeyEvt.mnCode = 0;
+ aKeyEvt.mnCode |= nModCode;
+ aKeyEvt.mnCharCode = ImplGetCharCode( pFrame, cKeyCode );
+ aKeyEvt.mnRepeat = nRepeat;
+ long nRet = pFrame->CallCallback( SALEVENT_KEYINPUT, &aKeyEvt );
+ pFrame->CallCallback( SALEVENT_KEYUP, &aKeyEvt );
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+static bool ImplHandlePaintMsg( HWND hWnd )
+{
+ BOOL bMutex = FALSE;
+ if ( ImplSalYieldMutexTryToAcquire() )
+ bMutex = TRUE;
+
+ // if we don't get the mutex, we can also change the clip region,
+ // because other threads doesn't use the mutex from the main
+ // thread --> see GetGraphics()
+
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ // Clip-Region muss zurueckgesetzt werden, da wir sonst kein
+ // ordentliches Bounding-Rectangle bekommen
+ if ( pFrame->mpGraphics && pFrame->mpGraphics->mhRegion )
+ SelectClipRgn( pFrame->mpGraphics->mhDC, 0 );
+
+ // Laut Window-Doku soll man erst abfragen, ob ueberhaupt eine
+ // Paint-Region anliegt
+ if ( GetUpdateRect( hWnd, NULL, FALSE ) )
+ {
+ // Call BeginPaint/EndPaint to query the rect and send
+ // this Notofication to rect
+ RECT aUpdateRect;
+ PAINTSTRUCT aPs;
+ BeginPaint( hWnd, &aPs );
+ CopyRect( &aUpdateRect, &aPs.rcPaint );
+
+ // Paint
+ // ClipRegion wieder herstellen
+ if ( pFrame->mpGraphics && pFrame->mpGraphics->mhRegion )
+ {
+ SelectClipRgn( pFrame->mpGraphics->mhDC,
+ pFrame->mpGraphics->mhRegion );
+ }
+
+ if ( bMutex )
+ {
+ SalPaintEvent aPEvt( aUpdateRect.left, aUpdateRect.top, aUpdateRect.right-aUpdateRect.left, aUpdateRect.bottom-aUpdateRect.top, pFrame->mbPresentation );
+ pFrame->CallCallback( SALEVENT_PAINT, &aPEvt );
+ }
+ else
+ {
+ RECT* pRect = new RECT;
+ CopyRect( pRect, &aUpdateRect );
+ ImplPostMessage( hWnd, SAL_MSG_POSTPAINT, (WPARAM)pRect, 0 );
+ }
+ EndPaint( hWnd, &aPs );
+ }
+ else
+ {
+ // ClipRegion wieder herstellen
+ if ( pFrame->mpGraphics && pFrame->mpGraphics->mhRegion )
+ {
+ SelectClipRgn( pFrame->mpGraphics->mhDC,
+ pFrame->mpGraphics->mhRegion );
+ }
+ }
+ }
+
+ if ( bMutex )
+ ImplSalYieldMutexRelease();
+
+ return bMutex ? true : false;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandlePaintMsg2( HWND hWnd, RECT* pRect )
+{
+ // Paint
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ SalPaintEvent aPEvt( pRect->left, pRect->top, pRect->right-pRect->left, pRect->bottom-pRect->top );
+ pFrame->CallCallback( SALEVENT_PAINT, &aPEvt );
+ }
+ ImplSalYieldMutexRelease();
+ delete pRect;
+ }
+ else
+ ImplPostMessage( hWnd, SAL_MSG_POSTPAINT, (WPARAM)pRect, 0 );
+}
+
+// -----------------------------------------------------------------------
+
+static void SetMaximizedFrameGeometry( HWND hWnd, WinSalFrame* pFrame )
+{
+ // calculate and set frame geometry of a maximized window - useful if the window is still hidden
+
+ // dualmonitor support:
+ // Get screensize of the monitor whith the mouse pointer
+
+ POINT pt;
+ GetCursorPos( &pt );
+ RECT aRectMouse;
+ aRectMouse.left = pt.x;
+ aRectMouse.top = pt.y;
+ aRectMouse.right = pt.x+2;
+ aRectMouse.bottom = pt.y+2;
+
+ RECT aRect;
+ ImplSalGetWorkArea( hWnd, &aRect, &aRectMouse );
+
+ // a maximized window has no other borders than the caption
+ pFrame->maGeometry.nLeftDecoration = pFrame->maGeometry.nRightDecoration = pFrame->maGeometry.nBottomDecoration = 0;
+ pFrame->maGeometry.nTopDecoration = pFrame->mbCaption ? GetSystemMetrics( SM_CYCAPTION ) : 0;
+
+ aRect.top += pFrame->maGeometry.nTopDecoration;
+ pFrame->maGeometry.nX = aRect.left;
+ pFrame->maGeometry.nY = aRect.top;
+ pFrame->maGeometry.nWidth = aRect.right - aRect.left;
+ pFrame->maGeometry.nHeight = aRect.bottom - aRect.top;
+}
+
+static void UpdateFrameGeometry( HWND hWnd, WinSalFrame* pFrame )
+{
+ if( !pFrame )
+ return;
+
+ RECT aRect;
+ GetWindowRect( hWnd, &aRect );
+ memset(&pFrame->maGeometry, 0, sizeof(SalFrameGeometry) );
+
+ if ( IsIconic( hWnd ) )
+ return;
+
+ POINT aPt;
+ aPt.x=0;
+ aPt.y=0;
+ ClientToScreen(hWnd, &aPt);
+ int cx = aPt.x - aRect.left;
+ pFrame->maGeometry.nTopDecoration = aPt.y - aRect.top;
+
+ pFrame->maGeometry.nLeftDecoration = cx;
+ pFrame->maGeometry.nRightDecoration = cx;
+
+ pFrame->maGeometry.nX = aPt.x;
+ pFrame->maGeometry.nY = aPt.y;
+
+ RECT aInnerRect;
+ GetClientRect( hWnd, &aInnerRect );
+ if( aInnerRect.right )
+ {
+ // improve right decoration
+ aPt.x=aInnerRect.right;
+ aPt.y=aInnerRect.top;
+ ClientToScreen(hWnd, &aPt);
+ pFrame->maGeometry.nRightDecoration = aRect.right - aPt.x;
+ }
+ if( aInnerRect.bottom ) // may be zero if window was not shown yet
+ pFrame->maGeometry.nBottomDecoration += aRect.bottom - aPt.y - aInnerRect.bottom;
+ else
+ // bottom border is typically the same as left/right
+ pFrame->maGeometry.nBottomDecoration = pFrame->maGeometry.nLeftDecoration;
+
+ int nWidth = aRect.right - aRect.left
+ - pFrame->maGeometry.nRightDecoration - pFrame->maGeometry.nLeftDecoration;
+ int nHeight = aRect.bottom - aRect.top
+ - pFrame->maGeometry.nBottomDecoration - pFrame->maGeometry.nTopDecoration;
+ // clamp to zero
+ pFrame->maGeometry.nHeight = nHeight < 0 ? 0 : nHeight;
+ pFrame->maGeometry.nWidth = nWidth < 0 ? 0 : nWidth;
+ pFrame->updateScreenNumber();
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplCallMoveHdl( HWND hWnd )
+{
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ pFrame->CallCallback( SALEVENT_MOVE, 0 );
+ // Um doppelte Paints von VCL und SAL zu vermeiden
+ //if ( IsWindowVisible( hWnd ) && !pFrame->mbInShow )
+ // UpdateWindow( hWnd );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplCallClosePopupsHdl( HWND hWnd )
+{
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ pFrame->CallCallback( SALEVENT_CLOSEPOPUPS, 0 );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleMoveMsg( HWND hWnd )
+{
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ UpdateFrameGeometry( hWnd, pFrame );
+
+ if ( GetWindowStyle( hWnd ) & WS_VISIBLE )
+ pFrame->mbDefPos = FALSE;
+
+ // Gegen moegliche Rekursionen sichern
+ if ( !pFrame->mbInMoveMsg )
+ {
+ // Fenster im FullScreenModus wieder einpassen
+ pFrame->mbInMoveMsg = TRUE;
+ if ( pFrame->mbFullScreen )
+ ImplSalFrameFullScreenPos( pFrame );
+ pFrame->mbInMoveMsg = FALSE;
+ }
+
+ // Status merken
+ ImplSaveFrameState( pFrame );
+
+ // Call Hdl
+ //#93851 if we call this handler, VCL floating windows are not updated correctly
+ ImplCallMoveHdl( hWnd );
+
+ }
+
+ ImplSalYieldMutexRelease();
+ }
+ else
+ ImplPostMessage( hWnd, SAL_MSG_POSTMOVE, 0, 0 );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplCallSizeHdl( HWND hWnd )
+{
+ // Da Windows diese Messages auch senden kann, muss hier auch die
+ // Solar-Semaphore beruecksichtigt werden
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ pFrame->CallCallback( SALEVENT_RESIZE, 0 );
+ // Um doppelte Paints von VCL und SAL zu vermeiden
+ if ( IsWindowVisible( hWnd ) && !pFrame->mbInShow )
+ UpdateWindow( hWnd );
+ }
+
+ ImplSalYieldMutexRelease();
+ }
+ else
+ ImplPostMessage( hWnd, SAL_MSG_POSTCALLSIZE, 0, 0 );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleSizeMsg( HWND hWnd, WPARAM wParam, LPARAM lParam )
+{
+ if ( (wParam != SIZE_MAXSHOW) && (wParam != SIZE_MAXHIDE) )
+ {
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ UpdateFrameGeometry( hWnd, pFrame );
+
+ pFrame->mnWidth = (int)LOWORD(lParam);
+ pFrame->mnHeight = (int)HIWORD(lParam);
+ // Status merken
+ ImplSaveFrameState( pFrame );
+ // Call Hdl
+ ImplCallSizeHdl( hWnd );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleFocusMsg( HWND hWnd )
+{
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame && !WinSalFrame::mbInReparent )
+ {
+ // Query the actual status
+ if ( ::GetFocus() == hWnd )
+ {
+ if ( IsWindowVisible( hWnd ) && !pFrame->mbInShow )
+ UpdateWindow( hWnd );
+
+ // Feststellen, ob wir IME unterstuetzen
+ if ( pFrame->mbIME && pFrame->mhDefIMEContext )
+ {
+ UINT nImeProps = ImmGetProperty( GetKeyboardLayout( 0 ), IGP_PROPERTY );
+
+ pFrame->mbSpezIME = (nImeProps & IME_PROP_SPECIAL_UI) != 0;
+ pFrame->mbAtCursorIME = (nImeProps & IME_PROP_AT_CARET) != 0;
+ pFrame->mbHandleIME = !pFrame->mbSpezIME;
+ }
+
+ pFrame->CallCallback( SALEVENT_GETFOCUS, 0 );
+ }
+ else
+ {
+ pFrame->CallCallback( SALEVENT_LOSEFOCUS, 0 );
+ }
+ }
+
+ ImplSalYieldMutexRelease();
+ }
+ else
+ ImplPostMessage( hWnd, SAL_MSG_POSTFOCUS, 0, 0 );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleCloseMsg( HWND hWnd )
+{
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ pFrame->CallCallback( SALEVENT_CLOSE, 0 );
+ }
+
+ ImplSalYieldMutexRelease();
+ }
+ else
+ ImplPostMessage( hWnd, WM_CLOSE, 0, 0 );
+}
+
+// -----------------------------------------------------------------------
+
+static long ImplHandleShutDownMsg( HWND hWnd )
+{
+ ImplSalYieldMutexAcquireWithWait();
+ long nRet = 0;
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ nRet = pFrame->CallCallback( SALEVENT_SHUTDOWN, 0 );
+ }
+ ImplSalYieldMutexRelease();
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleSettingsChangeMsg( HWND hWnd, UINT nMsg,
+ WPARAM wParam, LPARAM lParam )
+{
+ USHORT nSalEvent = SALEVENT_SETTINGSCHANGED;
+
+ if ( nMsg == WM_DEVMODECHANGE )
+ nSalEvent = SALEVENT_PRINTERCHANGED;
+ else if ( nMsg == WM_DISPLAYCHANGE )
+ nSalEvent = SALEVENT_DISPLAYCHANGED;
+ else if ( nMsg == WM_FONTCHANGE )
+ nSalEvent = SALEVENT_FONTCHANGED;
+ else if ( nMsg == WM_TIMECHANGE )
+ nSalEvent = SALEVENT_DATETIMECHANGED;
+ else if ( nMsg == WM_WININICHANGE )
+ {
+ if ( lParam )
+ {
+ if ( aSalShlData.mbWNT )
+ {
+ if ( ImplSalWICompareAscii( (const wchar_t*)lParam, "devices" ) == 0 )
+ nSalEvent = SALEVENT_PRINTERCHANGED;
+ }
+ else
+ {
+ if ( stricmp( (const char*)lParam, "devices" ) == 0 )
+ nSalEvent = SALEVENT_PRINTERCHANGED;
+ }
+ }
+ }
+
+ if ( nMsg == WM_SETTINGCHANGE )
+ {
+ if ( wParam == SPI_SETWHEELSCROLLLINES )
+ aSalShlData.mnWheelScrollLines = ImplSalGetWheelScrollLines();
+ else if( wParam == SPI_SETWHEELSCROLLCHARS )
+ aSalShlData.mnWheelScrollChars = ImplSalGetWheelScrollChars();
+ }
+
+ if ( WM_SYSCOLORCHANGE == nMsg && GetSalData()->mhDitherPal )
+ ImplUpdateSysColorEntries();
+
+ ImplSalYieldMutexAcquireWithWait();
+
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ if ( (nMsg == WM_DISPLAYCHANGE) || (nMsg == WM_WININICHANGE) )
+ {
+ if ( pFrame->mbFullScreen )
+ ImplSalFrameFullScreenPos( pFrame );
+ }
+
+ pFrame->CallCallback( nSalEvent, 0 );
+ }
+
+ ImplSalYieldMutexRelease();
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleUserEvent( HWND hWnd, LPARAM lParam )
+{
+ ImplSalYieldMutexAcquireWithWait();
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ pFrame->CallCallback( SALEVENT_USEREVENT, (void*)lParam );
+ }
+ ImplSalYieldMutexRelease();
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleForcePalette( HWND hWnd )
+{
+ SalData* pSalData = GetSalData();
+ HPALETTE hPal = pSalData->mhDitherPal;
+ if ( hPal )
+ {
+ if ( !ImplSalYieldMutexTryToAcquire() )
+ {
+ ImplPostMessage( hWnd, SAL_MSG_FORCEPALETTE, 0, 0 );
+ return;
+ }
+
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame && pFrame->mpGraphics )
+ {
+ WinSalGraphics* pGraphics = pFrame->mpGraphics;
+ if ( pGraphics && pGraphics->mhDefPal )
+ {
+ SelectPalette( pGraphics->mhDC, hPal, FALSE );
+ if ( RealizePalette( pGraphics->mhDC ) )
+ {
+ InvalidateRect( hWnd, NULL, FALSE );
+ UpdateWindow( hWnd );
+ pFrame->CallCallback( SALEVENT_DISPLAYCHANGED, 0 );
+ }
+ }
+ }
+
+ ImplSalYieldMutexRelease();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static LRESULT ImplHandlePalette( BOOL bFrame, HWND hWnd, UINT nMsg,
+ WPARAM wParam, LPARAM lParam, int& rDef )
+{
+ SalData* pSalData = GetSalData();
+ HPALETTE hPal = pSalData->mhDitherPal;
+ if ( !hPal )
+ return 0;
+
+ rDef = FALSE;
+ if ( pSalData->mbInPalChange )
+ return 0;
+
+ if ( (nMsg == WM_PALETTECHANGED) || (nMsg == SAL_MSG_POSTPALCHANGED) )
+ {
+ if ( (HWND)wParam == hWnd )
+ return 0;
+ }
+
+ BOOL bReleaseMutex = FALSE;
+ if ( (nMsg == WM_QUERYNEWPALETTE) || (nMsg == WM_PALETTECHANGED) )
+ {
+ // Da Windows diese Messages auch sendet, muss hier auch die
+ // Solar-Semaphore beruecksichtigt werden
+ if ( ImplSalYieldMutexTryToAcquire() )
+ bReleaseMutex = TRUE;
+ else if ( nMsg == WM_QUERYNEWPALETTE )
+ ImplPostMessage( hWnd, SAL_MSG_POSTQUERYNEWPAL, wParam, lParam );
+ else /* ( nMsg == WM_PALETTECHANGED ) */
+ ImplPostMessage( hWnd, SAL_MSG_POSTPALCHANGED, wParam, lParam );
+ }
+
+ WinSalVirtualDevice*pTempVD;
+ WinSalFrame* pTempFrame;
+ WinSalGraphics* pGraphics;
+ HDC hDC;
+ HPALETTE hOldPal;
+ UINT nCols;
+ BOOL bStdDC;
+ BOOL bUpdate;
+
+ pSalData->mbInPalChange = TRUE;
+
+ // Alle Paletten in VirDevs und Frames zuruecksetzen
+ pTempVD = pSalData->mpFirstVD;
+ while ( pTempVD )
+ {
+ pGraphics = pTempVD->mpGraphics;
+ if ( pGraphics->mhDefPal )
+ {
+ SelectPalette( pGraphics->mhDC,
+ pGraphics->mhDefPal,
+ TRUE );
+ }
+ pTempVD = pTempVD->mpNext;
+ }
+ pTempFrame = pSalData->mpFirstFrame;
+ while ( pTempFrame )
+ {
+ pGraphics = pTempFrame->mpGraphics;
+ if ( pGraphics && pGraphics->mhDefPal )
+ {
+ SelectPalette( pGraphics->mhDC,
+ pGraphics->mhDefPal,
+ TRUE );
+ }
+ pTempFrame = pTempFrame->mpNextFrame;
+ }
+
+ // Palette neu realizen
+ WinSalFrame* pFrame = NULL;
+ if ( bFrame )
+ pFrame = GetWindowPtr( hWnd );
+ if ( pFrame && pFrame->mpGraphics )
+ {
+ hDC = pFrame->mpGraphics->mhDC;
+ bStdDC = TRUE;
+ }
+ else
+ {
+ hDC = GetDC( hWnd );
+ bStdDC = FALSE;
+ }
+ UnrealizeObject( hPal );
+ hOldPal = SelectPalette( hDC, hPal, TRUE );
+ nCols = RealizePalette( hDC );
+ bUpdate = nCols != 0;
+ if ( !bStdDC )
+ {
+ SelectPalette( hDC, hOldPal, TRUE );
+ ReleaseDC( hWnd, hDC );
+ }
+
+ // Alle Paletten in VirDevs und Frames neu setzen
+ pTempVD = pSalData->mpFirstVD;
+ while ( pTempVD )
+ {
+ pGraphics = pTempVD->mpGraphics;
+ if ( pGraphics->mhDefPal )
+ {
+ SelectPalette( pGraphics->mhDC, hPal, TRUE );
+ RealizePalette( pGraphics->mhDC );
+ }
+ pTempVD = pTempVD->mpNext;
+ }
+ pTempFrame = pSalData->mpFirstFrame;
+ while ( pTempFrame )
+ {
+ if ( pTempFrame != pFrame )
+ {
+ pGraphics = pTempFrame->mpGraphics;
+ if ( pGraphics && pGraphics->mhDefPal )
+ {
+ SelectPalette( pGraphics->mhDC, hPal, TRUE );
+ if ( RealizePalette( pGraphics->mhDC ) )
+ bUpdate = TRUE;
+ }
+ }
+ pTempFrame = pTempFrame->mpNextFrame;
+ }
+
+ // Wenn sich Farben geaendert haben, dann die Fenster updaten
+ if ( bUpdate )
+ {
+ pTempFrame = pSalData->mpFirstFrame;
+ while ( pTempFrame )
+ {
+ pGraphics = pTempFrame->mpGraphics;
+ if ( pGraphics && pGraphics->mhDefPal )
+ {
+ InvalidateRect( pTempFrame->mhWnd, NULL, FALSE );
+ UpdateWindow( pTempFrame->mhWnd );
+ pTempFrame->CallCallback( SALEVENT_DISPLAYCHANGED, 0 );
+ }
+ pTempFrame = pTempFrame->mpNextFrame;
+ }
+ }
+
+ pSalData->mbInPalChange = FALSE;
+
+ if ( bReleaseMutex )
+ ImplSalYieldMutexRelease();
+
+ if ( nMsg == WM_PALETTECHANGED )
+ return 0;
+ else
+ return nCols;
+}
+
+// -----------------------------------------------------------------------
+
+static int ImplHandleMinMax( HWND hWnd, LPARAM lParam )
+{
+ int bRet = FALSE;
+
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ MINMAXINFO* pMinMax = (MINMAXINFO*)lParam;
+
+ if ( pFrame->mbFullScreen )
+ {
+ int nX;
+ int nY;
+ int nDX;
+ int nDY;
+ ImplSalCalcFullScreenSize( pFrame, nX, nY, nDX, nDY );
+
+ if ( pMinMax->ptMaxPosition.x > nX )
+ pMinMax->ptMaxPosition.x = nX;
+ if ( pMinMax->ptMaxPosition.y > nY )
+ pMinMax->ptMaxPosition.y = nY;
+
+ if ( pMinMax->ptMaxSize.x < nDX )
+ pMinMax->ptMaxSize.x = nDX;
+ if ( pMinMax->ptMaxSize.y < nDY )
+ pMinMax->ptMaxSize.y = nDY;
+ if ( pMinMax->ptMaxTrackSize.x < nDX )
+ pMinMax->ptMaxTrackSize.x = nDX;
+ if ( pMinMax->ptMaxTrackSize.y < nDY )
+ pMinMax->ptMaxTrackSize.y = nDY;
+
+ pMinMax->ptMinTrackSize.x = nDX;
+ pMinMax->ptMinTrackSize.y = nDY;
+
+ bRet = TRUE;
+ }
+
+ if ( pFrame->mnMinWidth || pFrame->mnMinHeight )
+ {
+ int nWidth = pFrame->mnMinWidth;
+ int nHeight = pFrame->mnMinHeight;
+
+ ImplSalAddBorder( pFrame, nWidth, nHeight );
+
+ if ( pMinMax->ptMinTrackSize.x < nWidth )
+ pMinMax->ptMinTrackSize.x = nWidth;
+ if ( pMinMax->ptMinTrackSize.y < nHeight )
+ pMinMax->ptMinTrackSize.y = nHeight;
+ }
+
+ if ( pFrame->mnMaxWidth || pFrame->mnMaxHeight )
+ {
+ int nWidth = pFrame->mnMaxWidth;
+ int nHeight = pFrame->mnMaxHeight;
+
+ ImplSalAddBorder( pFrame, nWidth, nHeight );
+
+ if( nWidth > 0 && nHeight > 0 ) // protect against int overflow due to INT_MAX initialisation
+ {
+ if ( pMinMax->ptMaxTrackSize.x > nWidth )
+ pMinMax->ptMaxTrackSize.x = nWidth;
+ if ( pMinMax->ptMaxTrackSize.y > nHeight )
+ pMinMax->ptMaxTrackSize.y = nHeight;
+ }
+ }
+ }
+
+ ImplSalYieldMutexRelease();
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+// retrieves the SalMenuItem pointer from a hMenu
+// the pointer is stored in every item, so if no position
+// is specified we just use the first item (ie, pos=0)
+// if bByPosition is FALSE then nPos denotes a menu id instead of a position
+static WinSalMenuItem* ImplGetSalMenuItem( HMENU hMenu, UINT nPos, BOOL bByPosition=TRUE )
+{
+ DWORD err=0;
+
+ MENUITEMINFOW mi;
+ memset(&mi, 0, sizeof(mi));
+ mi.cbSize = sizeof( mi );
+ mi.fMask = MIIM_DATA;
+ if( !GetMenuItemInfoW( hMenu, nPos, bByPosition, &mi) )
+ err = GetLastError();
+
+ return (WinSalMenuItem *) mi.dwItemData;
+}
+
+// returns the index of the currently selected item if any or -1
+static int ImplGetSelectedIndex( HMENU hMenu )
+{
+ DWORD err=0;
+
+ MENUITEMINFOW mi;
+ memset(&mi, 0, sizeof(mi));
+ mi.cbSize = sizeof( mi );
+ mi.fMask = MIIM_STATE;
+ int n = GetMenuItemCount( hMenu );
+ if( n != -1 )
+ {
+ for(int i=0; i<n; i++ )
+ {
+ if( !GetMenuItemInfoW( hMenu, i, TRUE, &mi) )
+ err = GetLastError();
+ else
+ {
+ if( mi.fState & MFS_HILITE )
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
+static int ImplMenuChar( HWND, WPARAM wParam, LPARAM lParam )
+{
+ int nRet = MNC_IGNORE;
+ HMENU hMenu = (HMENU) lParam;
+ String aMnemonic;
+ aMnemonic.AssignAscii("&");
+ aMnemonic.Append( (sal_Unicode) LOWORD(wParam) );
+ aMnemonic.ToLowerAscii(); // we only have ascii mnemonics
+
+ // search the mnemonic in the current menu
+ int nItemCount = GetMenuItemCount( hMenu );
+ int nFound = 0;
+ int idxFound = -1;
+ int idxSelected = ImplGetSelectedIndex( hMenu );
+ int idx = idxSelected != -1 ? idxSelected+1 : 0; // if duplicate mnemonics cycle through menu
+ for( int i=0; i< nItemCount; i++, idx++ )
+ {
+ WinSalMenuItem* pSalMenuItem = ImplGetSalMenuItem( hMenu, idx % nItemCount );
+ if( !pSalMenuItem )
+ continue;
+ String aStr = pSalMenuItem->mText;
+ aStr.ToLowerAscii();
+ if( aStr.Search( aMnemonic ) != STRING_NOTFOUND)
+ {
+ if( idxFound == -1 )
+ idxFound = idx % nItemCount;
+ if( nFound++ )
+ break; // duplicate found
+ }
+ }
+ if( nFound == 1 )
+ nRet = MAKELRESULT( idxFound, MNC_EXECUTE );
+ else
+ // duplicate mnemonics, just select the next occurence
+ nRet = MAKELRESULT( idxFound, MNC_SELECT );
+
+ return nRet;
+}
+
+static int ImplMeasureItem( HWND hWnd, WPARAM wParam, LPARAM lParam )
+{
+ int nRet = 0;
+ if( !wParam )
+ {
+ // request was sent by a menu
+ nRet = 1;
+ MEASUREITEMSTRUCT *pMI = (LPMEASUREITEMSTRUCT) lParam;
+ if( pMI->CtlType != ODT_MENU )
+ return 0;
+
+ WinSalMenuItem *pSalMenuItem = (WinSalMenuItem *) pMI->itemData;
+ if( !pSalMenuItem )
+ return 0;
+
+ HDC hdc = GetDC( hWnd );
+ SIZE strSize;
+
+ NONCLIENTMETRICS ncm;
+ memset( &ncm, 0, sizeof(ncm) );
+ ncm.cbSize = sizeof( ncm );
+ SystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, (PVOID) &ncm, 0 );
+
+ // Assume every menu item can be default and printed bold
+ //ncm.lfMenuFont.lfWeight = FW_BOLD;
+
+ HFONT hfntOld = (HFONT) SelectObject(hdc, (HFONT) CreateFontIndirect( &ncm.lfMenuFont ));
+
+ // menu text and accelerator
+ String aStr(pSalMenuItem->mText.GetBuffer() );
+ if( pSalMenuItem->mAccelText.Len() )
+ {
+ aStr.AppendAscii(" ");
+ aStr.Append( pSalMenuItem->mAccelText );
+ }
+ GetTextExtentPoint32W( hdc, (LPWSTR) aStr.GetBuffer(),
+ aStr.Len(), &strSize );
+
+ // image
+ Size bmpSize( 16, 16 );
+ //if( !!pSalMenuItem->maBitmap )
+ // bmpSize = pSalMenuItem->maBitmap.GetSizePixel();
+
+ // checkmark
+ Size checkSize( GetSystemMetrics( SM_CXMENUCHECK ), GetSystemMetrics( SM_CYMENUCHECK ) );
+
+ pMI->itemWidth = checkSize.Width() + 3 + bmpSize.Width() + 3 + strSize.cx;
+ pMI->itemHeight = Max( Max( checkSize.Height(), bmpSize.Height() ), strSize.cy );
+ pMI->itemHeight += 4;
+
+ DeleteObject( SelectObject(hdc, hfntOld) );
+ ReleaseDC( hWnd, hdc );
+ }
+
+ return nRet;
+}
+
+static int ImplDrawItem(HWND, WPARAM wParam, LPARAM lParam )
+{
+ int nRet = 0;
+ DWORD err = 0;
+ if( !wParam )
+ {
+ // request was sent by a menu
+ nRet = 1;
+ DRAWITEMSTRUCT *pDI = (LPDRAWITEMSTRUCT) lParam;
+ if( pDI->CtlType != ODT_MENU )
+ return 0;
+
+ WinSalMenuItem *pSalMenuItem = (WinSalMenuItem *) pDI->itemData;
+ if( !pSalMenuItem )
+ return 0;
+
+ COLORREF clrPrevText, clrPrevBkgnd;
+ HFONT hfntOld;
+ HBRUSH hbrOld;
+ BOOL fChecked = (pDI->itemState & ODS_CHECKED) ? TRUE : FALSE;
+ BOOL fSelected = (pDI->itemState & ODS_SELECTED) ? TRUE : FALSE;
+ BOOL fDisabled = (pDI->itemState & (ODS_DISABLED | ODS_GRAYED)) ? TRUE : FALSE;
+
+ // Set the appropriate foreground and background colors.
+ RECT aRect = pDI->rcItem;
+
+ clrPrevBkgnd = SetBkColor( pDI->hDC, GetSysColor( COLOR_MENU ) );
+
+ if ( fDisabled )
+ clrPrevText = SetTextColor( pDI->hDC, GetSysColor( COLOR_GRAYTEXT ) );
+ else
+ clrPrevText = SetTextColor( pDI->hDC, GetSysColor( fSelected ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT ) );
+
+ DWORD colBackground = GetSysColor( fSelected ? COLOR_HIGHLIGHT : COLOR_MENU );
+ if ( fSelected )
+ clrPrevBkgnd = SetBkColor( pDI->hDC, colBackground );
+ else
+ clrPrevBkgnd = SetBkColor( pDI->hDC, colBackground );
+
+ hbrOld = (HBRUSH)SelectObject( pDI->hDC, CreateSolidBrush( GetBkColor( pDI->hDC ) ) );
+
+ // Fill background
+ if(!PatBlt( pDI->hDC, aRect.left, aRect.top, aRect.right-aRect.left, aRect.bottom-aRect.top, PATCOPY ))
+ err = GetLastError();
+
+ int lineHeight = aRect.bottom-aRect.top;
+
+ int x = aRect.left;
+ int y = aRect.top;
+
+ int checkWidth = GetSystemMetrics( SM_CXMENUCHECK );
+ int checkHeight = GetSystemMetrics( SM_CYMENUCHECK );
+ if( fChecked )
+ {
+ RECT r;
+ r.left = 0;
+ r.top = 0;
+ r.right = checkWidth;
+ r.bottom = checkWidth;
+ HDC memDC = CreateCompatibleDC( pDI->hDC );
+ HBITMAP memBmp = CreateCompatibleBitmap( pDI->hDC, checkWidth, checkHeight );
+ HBITMAP hOldBmp = (HBITMAP) SelectObject( memDC, memBmp );
+ DrawFrameControl( memDC, &r, DFC_MENU, DFCS_MENUCHECK );
+ BitBlt( pDI->hDC, x, y+(lineHeight-checkHeight)/2, checkWidth, checkHeight, memDC, 0, 0, SRCAND );
+ DeleteObject( SelectObject( memDC, hOldBmp ) );
+ DeleteDC( memDC );
+ }
+ x += checkWidth+3;
+
+ //Size bmpSize = aBitmap.GetSizePixel();
+ Size bmpSize(16, 16);
+ if( !!pSalMenuItem->maBitmap )
+ {
+ Bitmap aBitmap( pSalMenuItem->maBitmap );
+
+ // set transparent pixels to background color
+ if( fDisabled )
+ colBackground = RGB(255,255,255);
+ aBitmap.Replace( Color( COL_LIGHTMAGENTA ),
+ Color( GetRValue(colBackground),GetGValue(colBackground),GetBValue(colBackground) ), 0);
+
+ WinSalBitmap* pSalBmp = static_cast<WinSalBitmap*>(aBitmap.ImplGetImpBitmap()->ImplGetSalBitmap());
+ HGLOBAL hDrawDIB = pSalBmp->ImplGethDIB();
+
+ if( hDrawDIB )
+ {
+ PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( hDrawDIB );
+ PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) pBI;
+ PBYTE pBits = (PBYTE) pBI + *(DWORD*) pBI +
+ pSalBmp->ImplGetDIBColorCount( hDrawDIB ) * sizeof( RGBQUAD );
+
+ HBITMAP hBmp = CreateDIBitmap( pDI->hDC, pBIH, CBM_INIT, pBits, pBI, DIB_RGB_COLORS );
+ GlobalUnlock( hDrawDIB );
+
+ HBRUSH hbrIcon = CreateSolidBrush( GetSysColor( COLOR_GRAYTEXT ) );
+ DrawStateW( pDI->hDC, (HBRUSH)hbrIcon, (DRAWSTATEPROC)NULL, (LPARAM)hBmp, (WPARAM)0,
+ x, y+(lineHeight-bmpSize.Height())/2, bmpSize.Width(), bmpSize.Height(),
+ DST_BITMAP | (fDisabled ? (fSelected ? DSS_MONO : DSS_DISABLED) : DSS_NORMAL) );
+
+ DeleteObject( hbrIcon );
+ DeleteObject( hBmp );
+ }
+
+ }
+ x += bmpSize.Width() + 3;
+ aRect.left = x;
+
+ NONCLIENTMETRICS ncm;
+ memset( &ncm, 0, sizeof(ncm) );
+ ncm.cbSize = sizeof( ncm );
+ SystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, (PVOID) &ncm, 0 );
+
+ // Print default menu entry with bold font
+ //if ( pDI->itemState & ODS_DEFAULT )
+ // ncm.lfMenuFont.lfWeight = FW_BOLD;
+
+ hfntOld = (HFONT) SelectObject(pDI->hDC, (HFONT) CreateFontIndirect( &ncm.lfMenuFont ));
+
+ SIZE strSize;
+ String aStr( pSalMenuItem->mText.GetBuffer() );
+ GetTextExtentPoint32W( pDI->hDC, (LPWSTR) aStr.GetBuffer(),
+ aStr.Len(), &strSize );
+
+ if(!DrawStateW( pDI->hDC, (HBRUSH)NULL, (DRAWSTATEPROC)NULL,
+ (LPARAM)(LPWSTR) aStr.GetBuffer(),
+ (WPARAM)0, aRect.left, aRect.top + (lineHeight - strSize.cy)/2, 0, 0,
+ DST_PREFIXTEXT | (fDisabled && !fSelected ? DSS_DISABLED : DSS_NORMAL) ) )
+ err = GetLastError();
+
+ if( pSalMenuItem->mAccelText.Len() )
+ {
+ SIZE strSizeA;
+ aStr = pSalMenuItem->mAccelText;
+ GetTextExtentPoint32W( pDI->hDC, (LPWSTR) aStr.GetBuffer(),
+ aStr.Len(), &strSizeA );
+ TEXTMETRIC tm;
+ GetTextMetrics( pDI->hDC, &tm );
+
+ // position the accelerator string to the right but leave space for the
+ // (potential) submenu arrow (tm.tmMaxCharWidth)
+ if(!DrawStateW( pDI->hDC, (HBRUSH)NULL, (DRAWSTATEPROC)NULL,
+ (LPARAM)(LPWSTR) aStr.GetBuffer(),
+ (WPARAM)0, aRect.right-strSizeA.cx-tm.tmMaxCharWidth, aRect.top + (lineHeight - strSizeA.cy)/2, 0, 0,
+ DST_TEXT | (fDisabled && !fSelected ? DSS_DISABLED : DSS_NORMAL) ) )
+ err = GetLastError();
+ }
+
+ // Restore the original font and colors.
+ DeleteObject( SelectObject( pDI->hDC, hbrOld ) );
+ DeleteObject( SelectObject( pDI->hDC, hfntOld) );
+ SetTextColor(pDI->hDC, clrPrevText);
+ SetBkColor(pDI->hDC, clrPrevBkgnd);
+ }
+ return nRet;
+}
+
+static int ImplHandleMenuActivate( HWND hWnd, WPARAM wParam, LPARAM )
+{
+ // Menu activation
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( !pFrame )
+ return 0;
+
+ HMENU hMenu = (HMENU) wParam;
+ // WORD nPos = LOWORD (lParam);
+ // BOOL bWindowMenu = (BOOL) HIWORD(lParam);
+
+ // Send activate and deactivate together, so we have not keep track of opened menues
+ // this will be enough to have the menues updated correctly
+ SalMenuEvent aMenuEvt;
+ WinSalMenuItem *pSalMenuItem = ImplGetSalMenuItem( hMenu, 0 );
+ if( pSalMenuItem )
+ aMenuEvt.mpMenu = pSalMenuItem->mpMenu;
+ else
+ aMenuEvt.mpMenu = NULL;
+
+ long nRet = pFrame->CallCallback( SALEVENT_MENUACTIVATE, &aMenuEvt );
+ if( nRet )
+ nRet = pFrame->CallCallback( SALEVENT_MENUDEACTIVATE, &aMenuEvt );
+ if( nRet )
+ pFrame->mLastActivatedhMenu = hMenu;
+
+ return (nRet!=0);
+}
+
+static int ImplHandleMenuSelect( HWND hWnd, WPARAM wParam, LPARAM lParam )
+{
+ // Menu selection
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( !pFrame )
+ return 0;
+
+ WORD nId = LOWORD(wParam); // menu item or submenu index
+ WORD nFlags = HIWORD(wParam);
+ HMENU hMenu = (HMENU) lParam;
+
+ // check if we have to process the message
+ if( !GetSalData()->IsKnownMenuHandle( hMenu ) )
+ return 0;
+
+ BOOL bByPosition = FALSE;
+ if( nFlags & MF_POPUP )
+ bByPosition = TRUE;
+
+ long nRet = 0;
+ if ( hMenu && !pFrame->mLastActivatedhMenu )
+ {
+ // we never activated a menu (ie, no WM_INITMENUPOPUP has occured yet)
+ // which means this must be the menubar -> send activation/deactivation
+ SalMenuEvent aMenuEvt;
+ WinSalMenuItem *pSalMenuItem = ImplGetSalMenuItem( hMenu, nId, bByPosition );
+ if( pSalMenuItem )
+ aMenuEvt.mpMenu = pSalMenuItem->mpMenu;
+ else
+ aMenuEvt.mpMenu = NULL;
+
+ nRet = pFrame->CallCallback( SALEVENT_MENUACTIVATE, &aMenuEvt );
+ if( nRet )
+ nRet = pFrame->CallCallback( SALEVENT_MENUDEACTIVATE, &aMenuEvt );
+ if( nRet )
+ pFrame->mLastActivatedhMenu = hMenu;
+ }
+
+ if( !hMenu && nFlags == 0xFFFF )
+ {
+ // all menus are closed, reset activation logic
+ pFrame->mLastActivatedhMenu = NULL;
+ }
+
+ if( hMenu )
+ {
+ // hMenu must be saved, as it is not passed in WM_COMMAND which always occurs after a selection
+ // if a menu is closed due to a command selection then hMenu is NULL, but WM_COMMAND comes later
+ // so we must not overwrite it in this case
+ pFrame->mSelectedhMenu = hMenu;
+
+ // send highlight event
+ if( nFlags & MF_POPUP )
+ {
+ // submenu selected
+ // wParam now carries an index instead of an id -> retrieve id
+ MENUITEMINFOW mi;
+ memset(&mi, 0, sizeof(mi));
+ mi.cbSize = sizeof( mi );
+ mi.fMask = MIIM_ID;
+ if( GetMenuItemInfoW( hMenu, LOWORD(wParam), TRUE, &mi) )
+ nId = sal::static_int_cast<WORD>(mi.wID);
+ }
+
+ SalMenuEvent aMenuEvt;
+ aMenuEvt.mnId = nId;
+ WinSalMenuItem *pSalMenuItem = ImplGetSalMenuItem( hMenu, nId, FALSE );
+ if( pSalMenuItem )
+ aMenuEvt.mpMenu = pSalMenuItem->mpMenu;
+ else
+ aMenuEvt.mpMenu = NULL;
+
+ nRet = pFrame->CallCallback( SALEVENT_MENUHIGHLIGHT, &aMenuEvt );
+ }
+
+ return (nRet != 0);
+}
+
+static int ImplHandleCommand( HWND hWnd, WPARAM wParam, LPARAM )
+{
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( !pFrame )
+ return 0;
+
+ long nRet = 0;
+ if( !HIWORD(wParam) )
+ {
+ // Menu command
+ WORD nId = LOWORD(wParam);
+ if( nId ) // zero for separators
+ {
+ SalMenuEvent aMenuEvt;
+ aMenuEvt.mnId = nId;
+ WinSalMenuItem *pSalMenuItem = ImplGetSalMenuItem( pFrame->mSelectedhMenu, nId, FALSE );
+ if( pSalMenuItem )
+ aMenuEvt.mpMenu = pSalMenuItem->mpMenu;
+ else
+ aMenuEvt.mpMenu = NULL;
+
+ nRet = pFrame->CallCallback( SALEVENT_MENUCOMMAND, &aMenuEvt );
+ }
+ }
+ return (nRet != 0);
+}
+
+static int ImplHandleSysCommand( HWND hWnd, WPARAM wParam, LPARAM lParam )
+{
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( !pFrame )
+ return 0;
+
+ WPARAM nCommand = wParam & 0xFFF0;
+
+ if ( pFrame->mbFullScreen )
+ {
+ WIN_BOOL bMaximize = IsZoomed( pFrame->mhWnd );
+ WIN_BOOL bMinimize = IsIconic( pFrame->mhWnd );
+ if ( (nCommand == SC_SIZE) ||
+ (!bMinimize && (nCommand == SC_MOVE)) ||
+ (!bMaximize && (nCommand == SC_MAXIMIZE)) ||
+ (bMaximize && (nCommand == SC_RESTORE)) )
+ {
+ MessageBeep( 0 );
+ return TRUE;
+ }
+ }
+
+ if ( nCommand == SC_KEYMENU )
+ {
+ // do not process SC_KEYMENU if we have a native menu
+ // Windows should handle this
+ if( GetMenu( hWnd ) )
+ return FALSE;
+
+ // Hier verarbeiten wir nur KeyMenu-Events fuer Alt um
+ // den MenuBar zu aktivieren, oder wenn ein SysChild-Fenster
+ // den Focus hat, da diese Alt+Tasten-Kombinationen nur
+ // ueber diesen Event verarbeitet werden
+ if ( !LOWORD( lParam ) )
+ {
+ // Nur ausloesen, wenn keine weitere Taste gedrueckt ist. Im
+ // Gegensatz zur Doku wird in der X-Koordinaate der CharCode
+ // geliefert, der zusaetzlich gedrueckt ist
+ // Also 32 fuer Space, 99 fuer c, 100 fuer d, ...
+ // Da dies nicht dokumentiert ist, fragen wir vorsichtshalber
+ // auch den Status der Space-Taste ab
+ if ( GetKeyState( VK_SPACE ) & 0x8000 )
+ return 0;
+
+ // Damit nicht bei Alt+Maustaste auch der MenuBar aktiviert wird
+ if ( (GetKeyState( VK_LBUTTON ) & 0x8000) ||
+ (GetKeyState( VK_RBUTTON ) & 0x8000) ||
+ (GetKeyState( VK_MBUTTON ) & 0x8000) ||
+ (GetKeyState( VK_SHIFT ) & 0x8000) )
+ return 1;
+
+ SalKeyEvent aKeyEvt;
+ aKeyEvt.mnTime = GetMessageTime();
+ aKeyEvt.mnCode = KEY_MENU;
+ aKeyEvt.mnCharCode = 0;
+ aKeyEvt.mnRepeat = 0;
+ long nRet = pFrame->CallCallback( SALEVENT_KEYINPUT, &aKeyEvt );
+ pFrame->CallCallback( SALEVENT_KEYUP, &aKeyEvt );
+ return (nRet != 0);
+ }
+ else
+ {
+ // Testen, ob ein SysChild den Focus hat
+ HWND hFocusWnd = ::GetFocus();
+ if ( hFocusWnd && ImplFindSalObject( hFocusWnd ) )
+ {
+ char cKeyCode = (char)(unsigned char)LOWORD( lParam );
+ // LowerCase
+ if ( (cKeyCode >= 65) && (cKeyCode <= 90) )
+ cKeyCode += 32;
+ // Wir nehmen nur 0-9 und A-Z, alle anderen Tasten muessen durch
+ // den Hook vom SalObj verarbeitet werden
+ if ( ((cKeyCode >= 48) && (cKeyCode <= 57)) ||
+ ((cKeyCode >= 97) && (cKeyCode <= 122)) )
+ {
+ USHORT nModCode = 0;
+ if ( GetKeyState( VK_SHIFT ) & 0x8000 )
+ nModCode |= KEY_SHIFT;
+ if ( GetKeyState( VK_CONTROL ) & 0x8000 )
+ nModCode |= KEY_MOD1;
+ nModCode |= KEY_MOD2;
+
+ SalKeyEvent aKeyEvt;
+ aKeyEvt.mnTime = GetMessageTime();
+ if ( (cKeyCode >= 48) && (cKeyCode <= 57) )
+ aKeyEvt.mnCode = KEY_0+(cKeyCode-48);
+ else
+ aKeyEvt.mnCode = KEY_A+(cKeyCode-97);
+ aKeyEvt.mnCode |= nModCode;
+ aKeyEvt.mnCharCode = cKeyCode;
+ aKeyEvt.mnRepeat = 0;
+ long nRet = pFrame->CallCallback( SALEVENT_KEYINPUT, &aKeyEvt );
+ pFrame->CallCallback( SALEVENT_KEYUP, &aKeyEvt );
+ return (nRet != 0);
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleInputLangChange( HWND hWnd, WPARAM, LPARAM lParam )
+{
+ ImplSalYieldMutexAcquireWithWait();
+
+ // Feststellen, ob wir IME unterstuetzen
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame && pFrame->mbIME && pFrame->mhDefIMEContext )
+ {
+ HKL hKL = (HKL)lParam;
+ UINT nImeProps = ImmGetProperty( hKL, IGP_PROPERTY );
+
+ pFrame->mbSpezIME = (nImeProps & IME_PROP_SPECIAL_UI) != 0;
+ pFrame->mbAtCursorIME = (nImeProps & IME_PROP_AT_CARET) != 0;
+ pFrame->mbHandleIME = !pFrame->mbSpezIME;
+ }
+
+ // trigger input language and codepage update
+ UINT nLang = pFrame->mnInputLang;
+ ImplUpdateInputLang( pFrame );
+
+ // notify change
+ if( nLang != pFrame->mnInputLang )
+ pFrame->CallCallback( SALEVENT_INPUTLANGUAGECHANGE, 0 );
+
+ ImplSalYieldMutexRelease();
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplUpdateIMECursorPos( WinSalFrame* pFrame, HIMC hIMC )
+{
+ COMPOSITIONFORM aForm;
+ memset( &aForm, 0, sizeof( aForm ) );
+
+ // Cursor-Position ermitteln und aus der die Default-Position fuer
+ // das Composition-Fenster berechnen
+ SalExtTextInputPosEvent aPosEvt;
+ pFrame->CallCallback( SALEVENT_EXTTEXTINPUTPOS, (void*)&aPosEvt );
+ if ( (aPosEvt.mnX == -1) && (aPosEvt.mnY == -1) )
+ aForm.dwStyle |= CFS_DEFAULT;
+ else
+ {
+ aForm.dwStyle |= CFS_POINT;
+ aForm.ptCurrentPos.x = aPosEvt.mnX;
+ aForm.ptCurrentPos.y = aPosEvt.mnY;
+ }
+ ImmSetCompositionWindow( hIMC, &aForm );
+
+ // Because not all IME's use this values, we create
+ // a Windows caret to force the Position from the IME
+ if ( GetFocus() == pFrame->mhWnd )
+ {
+ CreateCaret( pFrame->mhWnd, 0,
+ aPosEvt.mnWidth, aPosEvt.mnHeight );
+ SetCaretPos( aPosEvt.mnX, aPosEvt.mnY );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplHandleIMEStartComposition( HWND hWnd )
+{
+ BOOL bDef = TRUE;
+
+ ImplSalYieldMutexAcquireWithWait();
+
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ HIMC hIMC = ImmGetContext( hWnd );
+ if ( hIMC )
+ {
+ ImplUpdateIMECursorPos( pFrame, hIMC );
+ ImmReleaseContext( hWnd, hIMC );
+ }
+
+ if ( pFrame->mbHandleIME )
+ {
+ if ( pFrame->mbAtCursorIME )
+ bDef = FALSE;
+ }
+ }
+
+ ImplSalYieldMutexRelease();
+
+ return bDef;
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplHandleIMECompositionInput( WinSalFrame* pFrame,
+ HIMC hIMC, LPARAM lParam )
+{
+ BOOL bDef = TRUE;
+
+ // Init Event
+ SalExtTextInputEvent aEvt;
+ aEvt.mnTime = GetMessageTime();
+ aEvt.mpTextAttr = NULL;
+ aEvt.mnCursorPos = 0;
+ aEvt.mnDeltaStart = 0;
+ aEvt.mbOnlyCursor = FALSE;
+ aEvt.mnCursorFlags = 0;
+
+ // If we get a result string, then we handle this input
+ if ( lParam & GCS_RESULTSTR )
+ {
+ bDef = FALSE;
+
+ LONG nTextLen = ImmGetCompositionStringW( hIMC, GCS_RESULTSTR, 0, 0 ) / sizeof( WCHAR );
+ if ( nTextLen >= 0 )
+ {
+ WCHAR* pTextBuf = new WCHAR[nTextLen];
+ ImmGetCompositionStringW( hIMC, GCS_RESULTSTR, pTextBuf, nTextLen*sizeof( WCHAR ) );
+ aEvt.maText = XubString( reinterpret_cast<const xub_Unicode*>(pTextBuf), (xub_StrLen)nTextLen );
+ delete [] pTextBuf;
+ }
+
+ aEvt.mnCursorPos = aEvt.maText.Len();
+ pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&aEvt );
+ pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, (void*)NULL );
+ ImplUpdateIMECursorPos( pFrame, hIMC );
+ }
+
+ // If the IME doesn't support OnSpot input, then there is nothing to do
+ if ( !pFrame->mbAtCursorIME )
+ return !bDef;
+
+ // If we get new Composition data, then we handle this new input
+ if ( (lParam & (GCS_COMPSTR | GCS_COMPATTR)) ||
+ ((lParam & GCS_CURSORPOS) && !(lParam & GCS_RESULTSTR)) )
+ {
+ bDef = FALSE;
+
+ USHORT* pSalAttrAry = NULL;
+ LONG nTextLen = ImmGetCompositionStringW( hIMC, GCS_COMPSTR, 0, 0 ) / sizeof( WCHAR );
+ if ( nTextLen > 0 )
+ {
+ WCHAR* pTextBuf = new WCHAR[nTextLen];
+ ImmGetCompositionStringW( hIMC, GCS_COMPSTR, pTextBuf, nTextLen*sizeof( WCHAR ) );
+ aEvt.maText = XubString( reinterpret_cast<const xub_Unicode*>(pTextBuf), (xub_StrLen)nTextLen );
+ delete [] pTextBuf;
+
+ WIN_BYTE* pAttrBuf = NULL;
+ LONG nAttrLen = ImmGetCompositionStringW( hIMC, GCS_COMPATTR, 0, 0 );
+ if ( nAttrLen > 0 )
+ {
+ pAttrBuf = new WIN_BYTE[nAttrLen];
+ ImmGetCompositionStringW( hIMC, GCS_COMPATTR, pAttrBuf, nAttrLen );
+ }
+
+ if ( pAttrBuf )
+ {
+ xub_StrLen nTextLen = aEvt.maText.Len();
+ pSalAttrAry = new USHORT[nTextLen];
+ memset( pSalAttrAry, 0, nTextLen*sizeof( USHORT ) );
+ for ( xub_StrLen i = 0; (i < nTextLen) && (i < nAttrLen); i++ )
+ {
+ WIN_BYTE nWinAttr = pAttrBuf[i];
+ USHORT nSalAttr;
+ if ( nWinAttr == ATTR_TARGET_CONVERTED )
+ {
+ nSalAttr = SAL_EXTTEXTINPUT_ATTR_BOLDUNDERLINE;
+ aEvt.mnCursorFlags |= SAL_EXTTEXTINPUT_CURSOR_INVISIBLE;
+ }
+ else if ( nWinAttr == ATTR_CONVERTED )
+ nSalAttr = SAL_EXTTEXTINPUT_ATTR_DASHDOTUNDERLINE;
+ else if ( nWinAttr == ATTR_TARGET_NOTCONVERTED )
+ nSalAttr = SAL_EXTTEXTINPUT_ATTR_HIGHLIGHT;
+ else if ( nWinAttr == ATTR_INPUT_ERROR )
+ nSalAttr = SAL_EXTTEXTINPUT_ATTR_REDTEXT | SAL_EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE;
+ else /* ( nWinAttr == ATTR_INPUT ) */
+ nSalAttr = SAL_EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE;
+ pSalAttrAry[i] = nSalAttr;
+ }
+
+ aEvt.mpTextAttr = pSalAttrAry;
+ delete [] pAttrBuf;
+ }
+ }
+
+ // Only when we get new composition data, we must send this event
+ if ( (nTextLen > 0) || !(lParam & GCS_RESULTSTR) )
+ {
+ // End the mode, if the last character is deleted
+ if ( !nTextLen && !pFrame->mbCandidateMode )
+ {
+ pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&aEvt );
+ pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, (void*)NULL );
+ }
+ else
+ {
+ // Because Cursor-Position and DeltaStart never updated
+ // from the korean input engine, we must handle this here
+ if ( lParam & CS_INSERTCHAR )
+ {
+ aEvt.mnCursorPos = nTextLen;
+ if ( aEvt.mnCursorPos && (lParam & CS_NOMOVECARET) )
+ aEvt.mnCursorPos--;
+ }
+ else
+ aEvt.mnCursorPos = LOWORD( ImmGetCompositionStringW( hIMC, GCS_CURSORPOS, 0, 0 ) );
+
+ if ( pFrame->mbCandidateMode )
+ aEvt.mnCursorFlags |= SAL_EXTTEXTINPUT_CURSOR_INVISIBLE;
+ if ( lParam & CS_NOMOVECARET )
+ aEvt.mnCursorFlags |= SAL_EXTTEXTINPUT_CURSOR_OVERWRITE;
+
+ pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&aEvt );
+ }
+ ImplUpdateIMECursorPos( pFrame, hIMC );
+ }
+
+ if ( pSalAttrAry )
+ delete [] pSalAttrAry;
+ }
+
+ return !bDef;
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplHandleIMEComposition( HWND hWnd, LPARAM lParam )
+{
+ BOOL bDef = TRUE;
+ ImplSalYieldMutexAcquireWithWait();
+
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame && (!lParam || (lParam & GCS_RESULTSTR)) )
+ {
+ // Wir restaurieren den Background-Modus bei jeder Texteingabe,
+ // da einige Tools wie RichWin uns diesen hin- und wieder umsetzen
+ if ( pFrame->mpGraphics &&
+ pFrame->mpGraphics->mhDC )
+ SetBkMode( pFrame->mpGraphics->mhDC, TRANSPARENT );
+ }
+
+ if ( pFrame && pFrame->mbHandleIME )
+ {
+ if ( !lParam )
+ {
+ SalExtTextInputEvent aEvt;
+ aEvt.mnTime = GetMessageTime();
+ aEvt.mpTextAttr = NULL;
+ aEvt.mnCursorPos = 0;
+ aEvt.mnDeltaStart = 0;
+ aEvt.mbOnlyCursor = FALSE;
+ aEvt.mnCursorFlags = 0;
+ pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&aEvt );
+ pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, (void*)NULL );
+ }
+ else if ( lParam & (GCS_RESULTSTR | GCS_COMPSTR | GCS_COMPATTR | GCS_CURSORPOS) )
+ {
+ HIMC hIMC = ImmGetContext( hWnd );
+ if ( hIMC )
+ {
+ if ( ImplHandleIMECompositionInput( pFrame, hIMC, lParam ) )
+ bDef = FALSE;
+
+ ImmReleaseContext( hWnd, hIMC );
+ }
+ }
+ }
+
+ ImplSalYieldMutexRelease();
+ return bDef;
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL ImplHandleIMEEndComposition( HWND hWnd )
+{
+ BOOL bDef = TRUE;
+
+ ImplSalYieldMutexAcquireWithWait();
+
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame && pFrame->mbHandleIME )
+ {
+ if ( pFrame->mbAtCursorIME )
+ bDef = FALSE;
+ }
+
+ ImplSalYieldMutexRelease();
+
+ return bDef;
+}
+
+// -----------------------------------------------------------------------
+
+static boolean ImplHandleAppCommand( HWND hWnd, LPARAM lParam )
+{
+ sal_Int16 nCommand = 0;
+ switch( GET_APPCOMMAND_LPARAM(lParam) )
+ {
+ case APPCOMMAND_MEDIA_CHANNEL_DOWN: nCommand = MEDIA_COMMAND_CHANNEL_DOWN; break;
+ case APPCOMMAND_MEDIA_CHANNEL_UP: nCommand = MEDIA_COMMAND_CHANNEL_UP; break;
+ case APPCOMMAND_MEDIA_NEXTTRACK: nCommand = MEDIA_COMMAND_NEXTTRACK; break;
+ case APPCOMMAND_MEDIA_PAUSE: nCommand = MEDIA_COMMAND_PAUSE; break;
+ case APPCOMMAND_MEDIA_PLAY: nCommand = MEDIA_COMMAND_PLAY; break;
+ case APPCOMMAND_MEDIA_PLAY_PAUSE: nCommand = MEDIA_COMMAND_PLAY_PAUSE; break;
+ case APPCOMMAND_MEDIA_PREVIOUSTRACK: nCommand = MEDIA_COMMAND_PREVIOUSTRACK; break;
+ case APPCOMMAND_MEDIA_RECORD: nCommand = MEDIA_COMMAND_RECORD; break;
+ case APPCOMMAND_MEDIA_REWIND: nCommand = MEDIA_COMMAND_REWIND; break;
+ case APPCOMMAND_MEDIA_STOP: nCommand = MEDIA_COMMAND_STOP; break;
+ case APPCOMMAND_MIC_ON_OFF_TOGGLE: nCommand = MEDIA_COMMAND_MIC_ON_OFF_TOGGLE; break;
+ case APPCOMMAND_MICROPHONE_VOLUME_DOWN: nCommand = MEDIA_COMMAND_MICROPHONE_VOLUME_DOWN; break;
+ case APPCOMMAND_MICROPHONE_VOLUME_MUTE: nCommand = MEDIA_COMMAND_MICROPHONE_VOLUME_MUTE; break;
+ case APPCOMMAND_MICROPHONE_VOLUME_UP: nCommand = MEDIA_COMMAND_MICROPHONE_VOLUME_UP; break;
+ case APPCOMMAND_VOLUME_DOWN: nCommand = MEDIA_COMMAND_VOLUME_DOWN; break;
+ case APPCOMMAND_VOLUME_MUTE: nCommand = MEDIA_COMMAND_VOLUME_MUTE; break;
+ case APPCOMMAND_VOLUME_UP: nCommand = MEDIA_COMMAND_VOLUME_UP; break;
+ break;
+ default:
+ return false;
+ }
+
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ Window *pWindow = pFrame ? pFrame->GetWindow() : NULL;
+
+ if( pWindow )
+ {
+ const Point aPoint;
+ CommandEvent aCEvt( aPoint, COMMAND_MEDIA, FALSE, &nCommand );
+ NotifyEvent aNCmdEvt( EVENT_COMMAND, pWindow, &aCEvt );
+
+ if ( !ImplCallPreNotify( aNCmdEvt ) )
+ {
+ pWindow->Command( aCEvt );
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+static void ImplHandleIMENotify( HWND hWnd, WPARAM wParam )
+{
+ if ( wParam == (WPARAM)IMN_OPENCANDIDATE )
+ {
+ ImplSalYieldMutexAcquireWithWait();
+
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame && pFrame->mbHandleIME &&
+ pFrame->mbAtCursorIME )
+ {
+ // Wir wollen den Cursor hiden
+ pFrame->mbCandidateMode = TRUE;
+ ImplHandleIMEComposition( hWnd, GCS_CURSORPOS );
+
+ HWND hWnd = pFrame->mhWnd;
+ HIMC hIMC = ImmGetContext( hWnd );
+ if ( hIMC )
+ {
+ LONG nBufLen = ImmGetCompositionStringW( hIMC, GCS_COMPSTR, 0, 0 );
+ if ( nBufLen >= 1 )
+ {
+ SalExtTextInputPosEvent aPosEvt;
+ pFrame->CallCallback( SALEVENT_EXTTEXTINPUTPOS, (void*)&aPosEvt );
+
+ // Vertical !!!
+ CANDIDATEFORM aForm;
+ aForm.dwIndex = 0;
+ aForm.dwStyle = CFS_EXCLUDE;
+ aForm.ptCurrentPos.x = aPosEvt.mnX;
+ aForm.ptCurrentPos.y = aPosEvt.mnY+1;
+ aForm.rcArea.left = aPosEvt.mnX;
+ aForm.rcArea.top = aPosEvt.mnY;
+ aForm.rcArea.right = aForm.rcArea.left+aPosEvt.mnExtWidth+1;
+ aForm.rcArea.bottom = aForm.rcArea.top+aPosEvt.mnHeight+1;
+ ImmSetCandidateWindow( hIMC, &aForm );
+ }
+
+ ImmReleaseContext( hWnd, hIMC );
+ }
+ }
+
+ ImplSalYieldMutexRelease();
+ }
+ else if ( wParam == (WPARAM)IMN_CLOSECANDIDATE )
+ {
+ ImplSalYieldMutexAcquireWithWait();
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ pFrame->mbCandidateMode = FALSE;
+ ImplSalYieldMutexRelease();
+ }
+}
+
+// -----------------------------------------------------------------------
+#if WINVER >= 0x0500
+
+static LRESULT ImplHandleIMEReconvertString( HWND hWnd, LPARAM lParam )
+{
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ LPRECONVERTSTRING pReconvertString = (LPRECONVERTSTRING) lParam;
+ LRESULT nRet = 0;
+ SalSurroundingTextRequestEvent aEvt;
+ aEvt.maText = UniString();
+ aEvt.mnStart = aEvt.mnEnd = 0;
+
+ UINT nImeProps = ImmGetProperty( GetKeyboardLayout( 0 ), IGP_SETCOMPSTR );
+ if( (nImeProps & SCS_CAP_SETRECONVERTSTRING) == 0 )
+ {
+ // This IME does not support reconversion.
+ return 0;
+ }
+
+ if( !pReconvertString )
+ {
+ // The first call for reconversion.
+ pFrame->CallCallback( SALEVENT_STARTRECONVERSION, (void*)NULL );
+
+ // Retrieve the surrounding text from the focused control.
+ pFrame->CallCallback( SALEVENT_SURROUNDINGTEXTREQUEST, (void*)&aEvt );
+
+ if( aEvt.maText.Len() == 0 )
+ {
+ return 0;
+ }
+
+ nRet = sizeof(RECONVERTSTRING) + (aEvt.maText.Len() + 1) * sizeof(WCHAR);
+ }
+ else
+ {
+ // The second call for reconversion.
+
+ // Retrieve the surrounding text from the focused control.
+ pFrame->CallCallback( SALEVENT_SURROUNDINGTEXTREQUEST, (void*)&aEvt );
+ nRet = sizeof(RECONVERTSTRING) + (aEvt.maText.Len() + 1) * sizeof(WCHAR);
+
+ pReconvertString->dwStrOffset = sizeof(RECONVERTSTRING);
+ pReconvertString->dwStrLen = aEvt.maText.Len();
+ pReconvertString->dwCompStrOffset = aEvt.mnStart * sizeof(WCHAR);
+ pReconvertString->dwCompStrLen = aEvt.mnEnd - aEvt.mnStart;
+ pReconvertString->dwTargetStrOffset = pReconvertString->dwCompStrOffset;
+ pReconvertString->dwTargetStrLen = pReconvertString->dwCompStrLen;
+
+ memcpy( (LPWSTR)(pReconvertString + 1), aEvt.maText.GetBuffer(), (aEvt.maText.Len() + 1) * sizeof(WCHAR) );
+ }
+
+ // just return the required size of buffer to reconvert.
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+static LRESULT ImplHandleIMEConfirmReconvertString( HWND hWnd, LPARAM lParam )
+{
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ LPRECONVERTSTRING pReconvertString = (LPRECONVERTSTRING) lParam;
+ SalSurroundingTextRequestEvent aEvt;
+ aEvt.maText = UniString();
+ aEvt.mnStart = aEvt.mnEnd = 0;
+
+ pFrame->CallCallback( SALEVENT_SURROUNDINGTEXTREQUEST, (void*)&aEvt );
+
+ ULONG nTmpStart = pReconvertString->dwCompStrOffset / sizeof(WCHAR);
+ ULONG nTmpEnd = nTmpStart + pReconvertString->dwCompStrLen;
+
+ if( nTmpStart != aEvt.mnStart || nTmpEnd != aEvt.mnEnd )
+ {
+ SalSurroundingTextSelectionChangeEvent aSelEvt;
+ aSelEvt.mnStart = nTmpStart;
+ aSelEvt.mnEnd = nTmpEnd;
+
+ pFrame->CallCallback( SALEVENT_SURROUNDINGTEXTSELECTIONCHANGE, (void*)&aSelEvt );
+ }
+
+ return TRUE;
+}
+
+#endif // WINVER >= 0x0500
+
+// -----------------------------------------------------------------------
+
+void SalTestMouseLeave()
+{
+ SalData* pSalData = GetSalData();
+
+ if ( pSalData->mhWantLeaveMsg && !::GetCapture() )
+ {
+ POINT aPt;
+ GetCursorPos( &aPt );
+ if ( pSalData->mhWantLeaveMsg != WindowFromPoint( aPt ) )
+ ImplSendMessage( pSalData->mhWantLeaveMsg, SAL_MSG_MOUSELEAVE, 0, MAKELPARAM( aPt.x, aPt.y ) );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static int ImplSalWheelMousePos( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ,
+ LRESULT& rResult )
+{
+ POINT aPt;
+ POINT aScreenPt;
+ aScreenPt.x = (short)LOWORD( lParam );
+ aScreenPt.y = (short)HIWORD( lParam );
+ // Child-Fenster suchen, welches an der entsprechenden
+ // Position liegt
+ HWND hChildWnd;
+ HWND hWheelWnd = hWnd;
+ do
+ {
+ hChildWnd = hWheelWnd;
+ aPt = aScreenPt;
+ ScreenToClient( hChildWnd, &aPt );
+ hWheelWnd = ChildWindowFromPointEx( hChildWnd, aPt, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT );
+ }
+ while ( hWheelWnd && (hWheelWnd != hChildWnd) );
+ if ( hWheelWnd && (hWheelWnd != hWnd) &&
+ (hWheelWnd != ::GetFocus()) && IsWindowEnabled( hWheelWnd ) )
+ {
+ rResult = ImplSendMessage( hWheelWnd, nMsg, wParam, lParam );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+LRESULT CALLBACK SalFrameWndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, int& rDef )
+{
+ LRESULT nRet = 0;
+ static int bInWheelMsg = FALSE;
+ static int bInQueryEnd = FALSE;
+
+ // By WM_CRETAE we connect the frame with the window handle
+ if ( nMsg == WM_CREATE )
+ {
+ // Window-Instanz am Windowhandle speichern
+ // Can also be used for the W-Version, because the struct
+ // to access lpCreateParams is the same structure
+ CREATESTRUCTA* pStruct = (CREATESTRUCTA*)lParam;
+ WinSalFrame* pFrame = (WinSalFrame*)pStruct->lpCreateParams;
+ if ( pFrame != 0 )
+ {
+ SetWindowPtr( hWnd, pFrame );
+ // HWND schon hier setzen, da schon auf den Instanzdaten
+ // gearbeitet werden kann, wenn Messages waehrend
+ // CreateWindow() gesendet werden
+ pFrame->mhWnd = hWnd;
+ pFrame->maSysData.hWnd = hWnd;
+ }
+ return 0;
+ }
+
+ ImplSVData* pSVData = ImplGetSVData();
+ // #i72707# TODO: the mbDeInit check will not be needed
+ // once all windows that are not properly closed on exit got fixed
+ if( pSVData->mbDeInit )
+ return 0;
+
+ if ( WM_USER_SYSTEM_WINDOW_ACTIVATED == nMsg )
+ {
+ if (pSVData->mpIntroWindow)
+ pSVData->mpIntroWindow->Hide();
+
+ return 0;
+ }
+
+ bool bCheckTimers = false;
+
+ switch( nMsg )
+ {
+ case WM_MOUSEMOVE:
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_LBUTTONUP:
+ case WM_MBUTTONUP:
+ case WM_RBUTTONUP:
+ case WM_NCMOUSEMOVE:
+ case SAL_MSG_MOUSELEAVE:
+ ImplSalYieldMutexAcquireWithWait();
+ rDef = !ImplHandleMouseMsg( hWnd, nMsg, wParam, lParam );
+ ImplSalYieldMutexRelease();
+ break;
+
+ case WM_NCLBUTTONDOWN:
+ case WM_NCMBUTTONDOWN:
+ case WM_NCRBUTTONDOWN:
+ ImplSalYieldMutexAcquireWithWait();
+ ImplCallClosePopupsHdl( hWnd ); // close popups...
+ ImplSalYieldMutexRelease();
+ break;
+
+ case WM_MOUSEACTIVATE:
+ if ( LOWORD( lParam ) == HTCLIENT )
+ {
+ ImplSalYieldMutexAcquireWithWait();
+ nRet = ImplHandleMouseActivateMsg( hWnd );
+ ImplSalYieldMutexRelease();
+ if ( nRet )
+ {
+ nRet = MA_NOACTIVATE;
+ rDef = FALSE;
+ }
+ }
+ break;
+
+ case WM_KEYDOWN:
+ case WM_KEYUP:
+ case WM_DEADCHAR:
+ case WM_CHAR:
+ case WM_UNICHAR: // MCD, 2003-01-13, Support for WM_UNICHAR & Keyman 6.0
+ case WM_SYSKEYDOWN:
+ case WM_SYSKEYUP:
+ case WM_SYSCHAR:
+ ImplSalYieldMutexAcquireWithWait();
+ rDef = !ImplHandleKeyMsg( hWnd, nMsg, wParam, lParam, nRet );
+ ImplSalYieldMutexRelease();
+ break;
+
+ case WM_MOUSEWHEEL:
+ // FALLTHROUGH intended
+ case WM_MOUSEHWHEEL:
+ // Gegen Rekursion absichern, falls wir vom IE oder dem externen
+ // Fenster die Message wieder zurueckbekommen
+ if ( !bInWheelMsg )
+ {
+ bInWheelMsg++;
+ rDef = !ImplHandleWheelMsg( hWnd, nMsg, wParam, lParam );
+ // Wenn wir die Message nicht ausgewertet haben, schauen wir
+ // noch einmal nach, ob dort ein geplugtes Fenster steht,
+ // welches wir dann benachrichtigen
+ if ( rDef )
+ rDef = ImplSalWheelMousePos( hWnd, nMsg, wParam, lParam, nRet );
+ bInWheelMsg--;
+ }
+ break;
+
+ case WM_COMMAND:
+ ImplSalYieldMutexAcquireWithWait();
+ rDef = !ImplHandleCommand( hWnd, wParam, lParam );
+ ImplSalYieldMutexRelease();
+ break;
+
+ case WM_INITMENUPOPUP:
+ ImplSalYieldMutexAcquireWithWait();
+ rDef = !ImplHandleMenuActivate( hWnd, wParam, lParam );
+ ImplSalYieldMutexRelease();
+ break;
+
+ case WM_MENUSELECT:
+ ImplSalYieldMutexAcquireWithWait();
+ rDef = !ImplHandleMenuSelect( hWnd, wParam, lParam );
+ ImplSalYieldMutexRelease();
+ break;
+
+ case WM_SYSCOMMAND:
+ ImplSalYieldMutexAcquireWithWait();
+ nRet = ImplHandleSysCommand( hWnd, wParam, lParam );
+ ImplSalYieldMutexRelease();
+ if ( nRet )
+ rDef = FALSE;
+ break;
+
+ case WM_MENUCHAR:
+ nRet = ImplMenuChar( hWnd, wParam, lParam );
+ if( nRet )
+ rDef = FALSE;
+ break;
+
+ case WM_MEASUREITEM:
+ nRet = ImplMeasureItem(hWnd, wParam, lParam);
+ if( nRet )
+ rDef = FALSE;
+ break;
+
+ case WM_DRAWITEM:
+ nRet = ImplDrawItem(hWnd, wParam, lParam);
+ if( nRet )
+ rDef = FALSE;
+ break;
+
+ case WM_MOVE:
+ case SAL_MSG_POSTMOVE:
+ ImplHandleMoveMsg( hWnd );
+ rDef = FALSE;
+ break;
+ case WM_SIZE:
+ ImplHandleSizeMsg( hWnd, wParam, lParam );
+ rDef = FALSE;
+ break;
+ case SAL_MSG_POSTCALLSIZE:
+ ImplCallSizeHdl( hWnd );
+ rDef = FALSE;
+ break;
+
+ case WM_GETMINMAXINFO:
+ if ( ImplHandleMinMax( hWnd, lParam ) )
+ rDef = FALSE;
+ break;
+
+ case WM_ERASEBKGND:
+ nRet = 1;
+ rDef = FALSE;
+ break;
+ case WM_PAINT:
+ bCheckTimers = ImplHandlePaintMsg( hWnd );
+ rDef = FALSE;
+ break;
+ case SAL_MSG_POSTPAINT:
+ ImplHandlePaintMsg2( hWnd, (RECT*)wParam );
+ bCheckTimers = true;
+ rDef = FALSE;
+ break;
+
+ case SAL_MSG_FORCEPALETTE:
+ ImplHandleForcePalette( hWnd );
+ rDef = FALSE;
+ break;
+
+ case WM_QUERYNEWPALETTE:
+ case SAL_MSG_POSTQUERYNEWPAL:
+ nRet = ImplHandlePalette( TRUE, hWnd, nMsg, wParam, lParam, rDef );
+ break;
+
+ case WM_ACTIVATE:
+ // Wenn wir aktiviert werden, dann wollen wir auch unsere
+ // Palette setzen. Wir machen dieses in Activate,
+ // damit andere externe Child-Fenster auch unsere Palette
+ // ueberschreiben koennen. So wird unsere jedenfalls nur einmal
+ // gesetzt und nicht immer rekursiv, da an allen anderen Stellen
+ // diese nur als Background-Palette gesetzt wird
+ if ( LOWORD( wParam ) != WA_INACTIVE )
+ ImplSendMessage( hWnd, SAL_MSG_FORCEPALETTE, 0, 0 );
+ break;
+
+ case WM_ENABLE:
+ // #95133# a system dialog is opened/closed, using our app window as parent
+ {
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ Window *pWin = NULL;
+ if( pFrame )
+ pWin = pFrame->GetWindow();
+
+ if( !wParam )
+ {
+ ImplSVData* pSVData = ImplGetSVData();
+ pSVData->maAppData.mnModalMode++;
+
+ // #106431#, hide SplashScreen
+ if( pSVData->mpIntroWindow )
+ pSVData->mpIntroWindow->Hide();
+
+ if( pWin )
+ {
+ pWin->EnableInput( FALSE, TRUE, TRUE, NULL );
+ pWin->ImplIncModalCount(); // #106303# support frame based modal count
+ }
+ }
+ else
+ {
+ ImplGetSVData()->maAppData.mnModalMode--;
+ if( pWin )
+ {
+ pWin->EnableInput( TRUE, TRUE, TRUE, NULL );
+ pWin->ImplDecModalCount(); // #106303# support frame based modal count
+ }
+ }
+ }
+ break;
+
+ case WM_KILLFOCUS:
+ DestroyCaret();
+ case WM_SETFOCUS:
+ case SAL_MSG_POSTFOCUS:
+ ImplHandleFocusMsg( hWnd );
+ rDef = FALSE;
+ break;
+
+ case WM_CLOSE:
+ ImplHandleCloseMsg( hWnd );
+ rDef = FALSE;
+ break;
+
+ case WM_QUERYENDSESSION:
+ if( !bInQueryEnd )
+ {
+ // handle queryendsession only once
+ bInQueryEnd = TRUE;
+ nRet = !ImplHandleShutDownMsg( hWnd );
+ rDef = FALSE;
+
+ // Issue #16314#: ImplHandleShutDownMsg causes a PostMessage in case of allowing shutdown.
+ // This posted message was never processed and cause Windows XP to hang after log off
+ // if there are multiple sessions and the current session wasn't the first one started.
+ // So if shutdown is allowed we assume that a post message was done and retrieve all
+ // messages in the message queue and dispatch them before we return control to the system.
+
+ if ( nRet )
+ {
+ MSG msg;
+
+ while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
+ {
+ DispatchMessage( &msg );
+ }
+ }
+ }
+ else
+ {
+ ImplSalYieldMutexAcquireWithWait();
+ ImplSalYieldMutexRelease();
+ rDef = TRUE;
+ }
+ break;
+
+ case WM_ENDSESSION:
+ if( !wParam )
+ bInQueryEnd = FALSE; // no shutdown: allow query again
+ nRet = FALSE;
+ rDef = FALSE;
+ break;
+
+ case WM_DISPLAYCHANGE:
+ case WM_SETTINGCHANGE:
+ case WM_DEVMODECHANGE:
+ case WM_FONTCHANGE:
+ case WM_SYSCOLORCHANGE:
+ case WM_TIMECHANGE:
+ ImplHandleSettingsChangeMsg( hWnd, nMsg, wParam, lParam );
+ break;
+
+ case WM_THEMECHANGED:
+ GetSalData()->mbThemeChanged = TRUE;
+ break;
+
+ case SAL_MSG_USEREVENT:
+ ImplHandleUserEvent( hWnd, lParam );
+ rDef = FALSE;
+ break;
+
+ case SAL_MSG_CAPTUREMOUSE:
+ SetCapture( hWnd );
+ rDef = FALSE;
+ break;
+ case SAL_MSG_RELEASEMOUSE:
+ if ( ::GetCapture() == hWnd )
+ ReleaseCapture();
+ rDef = FALSE;
+ break;
+ case SAL_MSG_TOTOP:
+ ImplSalToTop( hWnd, (USHORT)wParam );
+ rDef = FALSE;
+ break;
+ case SAL_MSG_SHOW:
+ ImplSalShow( hWnd, (BOOL)wParam, (BOOL)lParam );
+ rDef = FALSE;
+ break;
+ case SAL_MSG_SETINPUTCONTEXT:
+ ImplSalFrameSetInputContext( hWnd, (const SalInputContext*)(void*)lParam );
+ rDef = FALSE;
+ break;
+ case SAL_MSG_ENDEXTTEXTINPUT:
+ ImplSalFrameEndExtTextInput( hWnd, (USHORT)(ULONG)(void*)wParam );
+ rDef = FALSE;
+ break;
+
+ case WM_INPUTLANGCHANGE:
+ ImplHandleInputLangChange( hWnd, wParam, lParam );
+ break;
+
+ case WM_IME_CHAR:
+ // #103487#, some IMEs (eg, those that do not work onspot)
+ // may send WM_IME_CHAR instead of WM_IME_COMPOSITION
+ // we just handle it like a WM_CHAR message - seems to work fine
+ ImplSalYieldMutexAcquireWithWait();
+ rDef = !ImplHandleKeyMsg( hWnd, WM_CHAR, wParam, lParam, nRet );
+ ImplSalYieldMutexRelease();
+ break;
+
+ case WM_IME_STARTCOMPOSITION:
+ rDef = ImplHandleIMEStartComposition( hWnd );
+ break;
+
+ case WM_IME_COMPOSITION:
+ rDef = ImplHandleIMEComposition( hWnd, lParam );
+ break;
+
+ case WM_IME_ENDCOMPOSITION:
+ rDef = ImplHandleIMEEndComposition( hWnd );
+ break;
+
+ case WM_IME_NOTIFY:
+ ImplHandleIMENotify( hWnd, wParam );
+ break;
+ case WM_APPCOMMAND:
+ if( ImplHandleAppCommand( hWnd, lParam ) )
+ {
+ rDef = false;
+ nRet = 1;
+ }
+ break;
+#if WINVER >= 0x0500
+ case WM_IME_REQUEST:
+ if ( PtrToInt( wParam ) == IMR_RECONVERTSTRING )
+ {
+ nRet = ImplHandleIMEReconvertString( hWnd, lParam );
+ rDef = FALSE;
+ }
+ else if( PtrToInt( wParam ) == IMR_CONFIRMRECONVERTSTRING )
+ {
+ nRet = ImplHandleIMEConfirmReconvertString( hWnd, lParam );
+ rDef = FALSE;
+ }
+ break;
+#endif // WINVER >= 0x0500
+ }
+
+ // WheelMouse-Message abfangen
+ if ( rDef && (nMsg == aSalShlData.mnWheelMsgId) && aSalShlData.mnWheelMsgId )
+ {
+ // Gegen Rekursion absichern, falls wir vom IE oder dem externen
+ // Fenster die Message wieder zurueckbekommen
+ if ( !bInWheelMsg )
+ {
+ bInWheelMsg++;
+ // Zuerst wollen wir die Message dispatchen und dann darf auch
+ // das SystemWindow drankommen
+ WORD nKeyState = 0;
+ if ( GetKeyState( VK_SHIFT ) & 0x8000 )
+ nKeyState |= MK_SHIFT;
+ if ( GetKeyState( VK_CONTROL ) & 0x8000 )
+ nKeyState |= MK_CONTROL;
+ // Mutex handling is inside from this call
+ rDef = !ImplHandleWheelMsg( hWnd,
+ WM_MOUSEWHEEL,
+ MAKEWPARAM( nKeyState, (WORD)wParam ),
+ lParam );
+ if ( rDef )
+ {
+ HWND hWheelWnd = ::GetFocus();
+ if ( hWheelWnd && (hWheelWnd != hWnd) )
+ {
+ nRet = ImplSendMessage( hWheelWnd, nMsg, wParam, lParam );
+ rDef = FALSE;
+ }
+ else
+ rDef = ImplSalWheelMousePos( hWnd, nMsg, wParam, lParam, nRet );
+ }
+ bInWheelMsg--;
+ }
+ }
+
+ if( bCheckTimers )
+ {
+ SalData* pSalData = GetSalData();
+ if( pSalData->mnNextTimerTime )
+ {
+ DWORD nCurTime = GetTickCount();
+ if( pSalData->mnNextTimerTime < nCurTime )
+ {
+ MSG aMsg;
+ if( ! ImplPeekMessage( &aMsg, 0, WM_PAINT, WM_PAINT, PM_NOREMOVE | PM_NOYIELD ) )
+ ImplPostMessage( pSalData->mpFirstInstance->mhComWnd, SAL_MSG_POSTTIMER, 0, nCurTime );
+ }
+ }
+ }
+
+ return nRet;
+}
+
+LRESULT CALLBACK SalFrameWndProcA( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
+{
+ int bDef = TRUE;
+ LRESULT nRet = 0;
+#ifdef __MINGW32__
+ jmp_buf jmpbuf;
+ __SEHandler han;
+ if (__builtin_setjmp(jmpbuf) == 0)
+ {
+ han.Set(jmpbuf, NULL, (__SEHandler::PF)EXCEPTION_EXECUTE_HANDLER);
+#else
+ __try
+ {
+#endif
+ nRet = SalFrameWndProc( hWnd, nMsg, wParam, lParam, bDef );
+ }
+#ifdef __MINGW32__
+ han.Reset();
+#else
+ __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))
+ {
+ }
+#endif
+ if ( bDef )
+ nRet = DefWindowProcA( hWnd, nMsg, wParam, lParam );
+ return nRet;
+}
+
+LRESULT CALLBACK SalFrameWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
+{
+ int bDef = TRUE;
+ LRESULT nRet = 0;
+#ifdef __MINGW32__
+ jmp_buf jmpbuf;
+ __SEHandler han;
+ if (__builtin_setjmp(jmpbuf) == 0)
+ {
+ han.Set(jmpbuf, NULL, (__SEHandler::PF)EXCEPTION_EXECUTE_HANDLER);
+#else
+ __try
+ {
+#endif
+ nRet = SalFrameWndProc( hWnd, nMsg, wParam, lParam, bDef );
+ }
+#ifdef __MINGW32__
+ han.Reset();
+#else
+ __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))
+ {
+ }
+#endif
+
+ if ( bDef )
+ nRet = DefWindowProcW( hWnd, nMsg, wParam, lParam );
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplHandleGlobalMsg( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, LRESULT& rlResult )
+{
+ // handle all messages concerning all frames so they get processed only once
+ // Must work for Unicode and none Unicode
+ BOOL bResult = FALSE;
+ if ( (nMsg == WM_PALETTECHANGED) || (nMsg == SAL_MSG_POSTPALCHANGED) )
+ {
+ int bDef = TRUE;
+ rlResult = ImplHandlePalette( FALSE, hWnd, nMsg, wParam, lParam, bDef );
+ bResult = (bDef != 0);
+ }
+ else if( nMsg == WM_DISPLAYCHANGE )
+ {
+ WinSalSystem* pSys = static_cast<WinSalSystem*>(ImplGetSalSystem());
+ if( pSys )
+ pSys->clearMonitors();
+ bResult = (pSys != NULL);
+ }
+ return bResult;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplWriteLastError( DWORD lastError, const char *szApiCall )
+{
+ static int first=1;
+ // if VCL_LOGFILE_ENABLED is set, Win32 API error messages can be written
+ // to %TMP%/vcl.log or %TEMP%/vcl.log
+ static char *logEnabled = getenv("VCL_LOGFILE_ENABLED");
+ if( logEnabled )
+ {
+ BOOL bSuccess = FALSE;
+ static char *szTmp = getenv("TMP");
+ if( !szTmp || !*szTmp )
+ szTmp = getenv("TEMP");
+ if( szTmp && *szTmp )
+ {
+ char fname[5000];
+ strcpy( fname, szTmp );
+ if( fname[strlen(fname) - 1] != '\\' )
+ strcat( fname, "\\");
+ strcat( fname, "vcl.log" );
+ FILE *fp = fopen( fname, "a" ); // always append
+ if( fp )
+ {
+ if( first )
+ {
+ first = 0;
+ fprintf( fp, "Process ID: %d (0x%x)\n", GetCurrentProcessId(), GetCurrentProcessId() );
+ }
+ time_t aclock;
+ time( &aclock ); // Get time in seconds
+ struct tm *newtime = localtime( &aclock ); // Convert time to struct tm form
+ fprintf( fp, asctime( newtime ) ); // print time stamp
+
+ fprintf( fp, "%s returned %u (0x%x)\n", szApiCall, lastError, lastError );
+ bSuccess = TRUE; // may be FormatMessage fails but we wrote at least the error code
+
+ LPVOID lpMsgBuf;
+ if (FormatMessageA(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ lastError,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (LPSTR) &lpMsgBuf,
+ 0,
+ NULL ))
+ {
+ fprintf( fp, " %s\n", (LPSTR)lpMsgBuf );
+ LocalFree( lpMsgBuf );
+ }
+
+ fclose( fp );
+ }
+ }
+ return bSuccess;
+ }
+ else
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
diff --git a/vcl/win/source/window/salmenu.cxx b/vcl/win/source/window/salmenu.cxx
new file mode 100644
index 000000000000..1eb75969ea38
--- /dev/null
+++ b/vcl/win/source/window/salmenu.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 <tools/svwin.h>
+#include <wincomp.hxx>
+#include <saldata.hxx>
+#include <salinst.h>
+#include <vcl/salgdi.hxx>
+#include <salmenu.h>
+#include <vcl/menu.hxx>
+#include <vcl/sysdata.hxx>
+#include <salframe.h>
+#include <vcl/impbmp.hxx>
+
+// uncomment the following line to have ownerdrawn menues, ie, with bitmaps
+// however, this is incompatible with OLE inplace editing
+// so it is not activated by default
+//#define OWNERDRAW
+
+static DWORD myerr=0;
+
+// =======================================================================
+
+BOOL SalData::IsKnownMenuHandle( HMENU hMenu )
+{
+ if( mhMenuSet.find( hMenu ) == mhMenuSet.end() )
+ return FALSE;
+ else
+ return TRUE;
+}
+
+// =======================================================================
+
+// WinSalInst factory methods
+
+SalMenu* WinSalInstance::CreateMenu( BOOL bMenuBar )
+{
+ WinSalMenu *pSalMenu = new WinSalMenu();
+
+ pSalMenu->mbMenuBar = bMenuBar;
+ pSalMenu->mhWnd = NULL;
+ if( bMenuBar )
+ pSalMenu->mhMenu = ::CreateMenu();
+ else
+ pSalMenu->mhMenu = ::CreatePopupMenu();
+
+ if( pSalMenu->mhMenu )
+ GetSalData()->mhMenuSet.insert( pSalMenu->mhMenu );
+
+ return pSalMenu;
+}
+
+void WinSalInstance::DestroyMenu( SalMenu* pSalMenu )
+{
+ delete pSalMenu;
+}
+
+
+SalMenuItem* WinSalInstance::CreateMenuItem( const SalItemParams* pItemData )
+{
+ if( !pItemData )
+ return NULL;
+
+ WinSalMenuItem *pSalMenuItem = new WinSalMenuItem();
+ memset( &pSalMenuItem->mInfo, 0, sizeof( MENUITEMINFOW ) );
+ pSalMenuItem->mInfo.cbSize = sizeof( MENUITEMINFOW );
+
+ if( pItemData->eType == MENUITEM_SEPARATOR )
+ {
+ // separator
+ pSalMenuItem->mInfo.fMask = MIIM_TYPE;
+ pSalMenuItem->mInfo.fType = MFT_SEPARATOR;
+ }
+ else
+ {
+ // item
+ pSalMenuItem->mText = pItemData->aText;
+ pSalMenuItem->mpMenu = pItemData->pMenu;
+ pSalMenuItem->maBitmap= !!pItemData->aImage ? pItemData->aImage.GetBitmapEx().GetBitmap() : Bitmap();
+ pSalMenuItem->mnId = pItemData->nId;
+
+ // 'translate' mnemonics
+ pSalMenuItem->mText.SearchAndReplace( '~', '&' );
+
+ pSalMenuItem->mInfo.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID | MIIM_DATA;
+ pSalMenuItem->mInfo.fType = MFT_STRING;
+#ifdef OWNERDRAW
+ if( pItemData->pMenu && !pItemData->pMenu->IsMenuBar() )
+ pSalMenuItem->mInfo.fType |= MFT_OWNERDRAW;
+ pSalMenuItem->mInfo.fState = MFS_ENABLED;
+#endif
+ pSalMenuItem->mInfo.dwTypeData = (LPWSTR) pSalMenuItem->mText.GetBuffer();
+ pSalMenuItem->mInfo.cch = pSalMenuItem->mText.Len();
+
+ pSalMenuItem->mInfo.wID = pItemData->nId;
+ pSalMenuItem->mInfo.dwItemData = (ULONG_PTR) pSalMenuItem; // user data
+ }
+
+ return pSalMenuItem;
+}
+
+void WinSalInstance::DestroyMenuItem( SalMenuItem* pSalMenuItem )
+{
+ delete pSalMenuItem;
+}
+
+
+// =======================================================================
+
+static void ImplDrawMenuBar( SalMenu *pMenu )
+{
+ if( pMenu->VisibleMenuBar() )
+ {
+ // redrawing the menubar all the time actually seems to be unnecessary (it just flickers)
+ /*
+ WinSalMenu *pMenuBar = ImplFindMenuBar( pMenu );
+ if( pMenuBar && pMenuBar->mhWnd )
+ ::DrawMenuBar( pMenuBar->mhWnd );
+ */
+ }
+}
+
+// =======================================================================
+
+
+/*
+ * WinSalMenu
+ */
+
+WinSalMenu::WinSalMenu()
+{
+ mhMenu = NULL;
+ mbMenuBar = FALSE;
+ mhWnd = NULL;
+ mpParentMenu = NULL;
+}
+
+WinSalMenu::~WinSalMenu()
+{
+ // only required if not associated to a window...
+ GetSalData()->mhMenuSet.erase( mhMenu );
+ ::DestroyMenu( mhMenu );
+}
+
+BOOL WinSalMenu::VisibleMenuBar()
+{
+ // The Win32 implementation never shows a native
+ // menubar. Thus, native menues are only visible
+ // when the menu is merged with an OLE container.
+ // The reason are missing tooltips, ownerdraw
+ // issues and accessibility which are better supported
+ // by VCL menues.
+ // Nevertheless, the native menues are always created
+ // and the application will properly react to all native
+ // menu messages.
+
+ return FALSE;
+}
+
+void WinSalMenu::SetFrame( const SalFrame *pFrame )
+{
+ if( pFrame )
+ mhWnd = static_cast<const WinSalFrame*>(pFrame)->mhWnd;
+ else
+ mhWnd = NULL;
+}
+
+void WinSalMenu::InsertItem( SalMenuItem* pSalMenuItem, unsigned nPos )
+{
+ if( pSalMenuItem )
+ {
+ WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
+ if( nPos == MENU_APPEND )
+ {
+ nPos = ::GetMenuItemCount( mhMenu );
+ if( nPos == -1 )
+ return;
+ }
+
+ if(!::InsertMenuItemW( mhMenu, nPos, TRUE, &pWItem->mInfo ))
+ myerr = GetLastError();
+ else
+ {
+ pWItem->mpSalMenu = this;
+ ImplDrawMenuBar( this );
+ }
+ }
+}
+
+void WinSalMenu::RemoveItem( unsigned nPos )
+{
+ int num = ::GetMenuItemCount( mhMenu );
+ if( num != -1 && nPos < (unsigned)num )
+ {
+ WinSalMenuItem *pSalMenuItem = NULL;
+
+ MENUITEMINFOW mi;
+ memset( &mi, 0, sizeof(mi) );
+ mi.cbSize = sizeof( mi );
+ mi.fMask = MIIM_DATA;
+ if( !GetMenuItemInfoW( mhMenu, nPos, TRUE, &mi) )
+ myerr = GetLastError();
+ else
+ pSalMenuItem = (WinSalMenuItem *) mi.dwItemData;
+
+ if( !::RemoveMenu( mhMenu, nPos, MF_BYPOSITION ) )
+ myerr = GetLastError();
+ else
+ {
+ if( pSalMenuItem )
+ pSalMenuItem->mpSalMenu = NULL;
+ ImplDrawMenuBar( this );
+ }
+ }
+}
+
+void ImplRemoveItemById( WinSalMenu *pSalMenu, unsigned nItemId )
+{
+ if( !pSalMenu )
+ return;
+
+ WinSalMenuItem *pSalMenuItem = NULL;
+
+ MENUITEMINFOW mi;
+ memset( &mi, 0, sizeof(mi) );
+ mi.cbSize = sizeof( mi );
+ mi.fMask = MIIM_DATA;
+ if( !GetMenuItemInfoW( pSalMenu->mhMenu, nItemId, FALSE, &mi) )
+ myerr = GetLastError();
+ else
+ pSalMenuItem = (WinSalMenuItem *) mi.dwItemData;
+
+ if( !::RemoveMenu( pSalMenu->mhMenu, nItemId, MF_BYCOMMAND ) )
+ myerr = GetLastError();
+ else
+ {
+ if( pSalMenuItem )
+ pSalMenuItem->mpSalMenu = NULL;
+ ImplDrawMenuBar( pSalMenu );
+ }
+}
+
+void WinSalMenu::SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos )
+{
+ if( pSalMenuItem )
+ {
+ WinSalMenuItem* pWMenuItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
+ WinSalMenu* pWSubMenu = static_cast<WinSalMenu*>(pSubMenu);
+ if( pWMenuItem->mInfo.hSubMenu )
+ {
+ GetSalData()->mhMenuSet.erase( pWMenuItem->mInfo.hSubMenu );
+ ::DestroyMenu( pWMenuItem->mInfo.hSubMenu );
+ }
+
+ pWMenuItem->mInfo.fMask |= MIIM_SUBMENU;
+ if( !pSubMenu )
+ pWMenuItem->mInfo.hSubMenu = NULL;
+ else
+ {
+ pWMenuItem->mInfo.hSubMenu = pWSubMenu->mhMenu;
+ pWSubMenu->mpParentMenu = this;
+ }
+
+ if(!::SetMenuItemInfoW( mhMenu, nPos, TRUE, &pWMenuItem->mInfo ) )
+ myerr = GetLastError();
+ else
+ ImplDrawMenuBar( this );
+ }
+}
+
+void WinSalMenu::CheckItem( unsigned nPos, BOOL bCheck )
+{
+ if( -1 != ::CheckMenuItem( mhMenu, nPos, MF_BYPOSITION|(bCheck ? MF_CHECKED : MF_UNCHECKED) ) )
+ ImplDrawMenuBar( this );
+}
+
+void WinSalMenu::EnableItem( unsigned nPos, BOOL bEnable )
+{
+ if( -1 != ::EnableMenuItem( mhMenu, nPos, MF_BYPOSITION|(bEnable ? MF_ENABLED : (MF_DISABLED|MF_GRAYED) ) ) )
+ ImplDrawMenuBar( this );
+}
+
+void WinSalMenu::SetItemImage( unsigned /*nPos*/, SalMenuItem* pSalMenuItem, const Image& rImage )
+{
+ if( pSalMenuItem )
+ {
+ WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
+ if( !!rImage )
+ pWItem->maBitmap = rImage.GetBitmapEx().GetBitmap();
+ else
+ pWItem->maBitmap = Bitmap();
+ }
+}
+
+void WinSalMenu::SetItemText( unsigned nPos, SalMenuItem* pSalMenuItem, const XubString& rText )
+{
+ if( pSalMenuItem )
+ {
+ WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
+ pWItem->mText = rText;
+ // 'translate' mnemonics
+ pWItem->mText.SearchAndReplace( '~', '&' );
+ pWItem->mInfo.fMask = MIIM_TYPE | MIIM_DATA;
+ pWItem->mInfo.fType = MFT_STRING;
+#ifdef OWNERDRAW
+ if( pWItem->mpMenu && !((Menu*) pWItem->mpMenu)->IsMenuBar() )
+ pWItem->mInfo.fType |= MFT_OWNERDRAW;
+#endif
+
+ // combine text and accelerator text
+ XubString aStr( pWItem->mText );
+ if( pWItem->mAccelText.Len() )
+ {
+ aStr.AppendAscii("\t");
+ aStr.Append( pWItem->mAccelText );
+ }
+ pWItem->mInfo.dwTypeData = (LPWSTR) aStr.GetBuffer();
+ pWItem->mInfo.cch = aStr.Len();
+
+ if(!::SetMenuItemInfoW( mhMenu, nPos, TRUE, &pWItem->mInfo ))
+ myerr = GetLastError();
+ else
+ ImplDrawMenuBar( this );
+ }
+}
+
+void WinSalMenu::SetAccelerator( unsigned nPos, SalMenuItem* pSalMenuItem, const KeyCode&, const XubString& rKeyName )
+{
+ if( pSalMenuItem )
+ {
+ WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
+ pWItem->mAccelText = rKeyName;
+ pWItem->mInfo.fMask = MIIM_TYPE | MIIM_DATA;
+ pWItem->mInfo.fType = MFT_STRING;
+#ifdef OWNERDRAW
+ if( pWItem->mpMenu && !((Menu*)pWItem->mpMenu)->IsMenuBar() )
+ pWItem->mInfo.fType |= MFT_OWNERDRAW;
+#endif
+ // combine text and accelerator text
+ XubString aStr( pWItem->mText );
+ if( pWItem->mAccelText.Len() )
+ {
+ aStr.AppendAscii("\t");
+ aStr.Append( pWItem->mAccelText );
+ }
+ pWItem->mInfo.dwTypeData = (LPWSTR) aStr.GetBuffer();
+ pWItem->mInfo.cch = aStr.Len();
+
+ if(!::SetMenuItemInfoW( mhMenu, nPos, TRUE, &pWItem->mInfo ))
+ myerr = GetLastError();
+ else
+ ImplDrawMenuBar( this );
+ }
+}
+
+void WinSalMenu::GetSystemMenuData( SystemMenuData* pData )
+{
+ if( pData )
+ pData->hMenu = mhMenu;
+}
+
+// =======================================================================
+
+/*
+ * SalMenuItem
+ */
+
+
+WinSalMenuItem::WinSalMenuItem()
+{
+ memset( &mInfo, 0, sizeof( MENUITEMINFOW ) );
+ mpMenu = NULL;
+ mnId = 0xFFFF;
+ mpSalMenu = NULL;
+}
+
+WinSalMenuItem::~WinSalMenuItem()
+{
+ if( mpSalMenu )
+ ImplRemoveItemById( mpSalMenu, mnId );
+}
+
+// -------------------------------------------------------------------
+
diff --git a/vcl/win/source/window/salobj.cxx b/vcl/win/source/window/salobj.cxx
new file mode 100644
index 000000000000..2f657968284f
--- /dev/null
+++ b/vcl/win/source/window/salobj.cxx
@@ -0,0 +1,838 @@
+/*************************************************************************
+ *
+ * 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 _SVWIN_HXX
+#include <tools/svwin.h>
+#endif
+#include <wincomp.hxx>
+#include <saldata.hxx>
+#include <salinst.h>
+#include <salframe.h>
+#include <salobj.h>
+#include <tools/debug.hxx>
+
+// =======================================================================
+
+static BOOL ImplIsSysWindowOrChild( HWND hWndParent, HWND hWndChild )
+{
+ if ( hWndParent == hWndChild )
+ return TRUE;
+
+ HWND hTempWnd = ::GetParent( hWndChild );
+ while ( hTempWnd )
+ {
+ // Ab nicht Child-Fenstern hoeren wir auf zu suchen
+ if ( !(GetWindowStyle( hTempWnd ) & WS_CHILD) )
+ return FALSE;
+ if ( hTempWnd == hWndParent )
+ return TRUE;
+ hTempWnd = ::GetParent( hTempWnd );
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+WinSalObject* ImplFindSalObject( HWND hWndChild )
+{
+ SalData* pSalData = GetSalData();
+ WinSalObject* pObject = pSalData->mpFirstObject;
+ while ( pObject )
+ {
+ if ( ImplIsSysWindowOrChild( pObject->mhWndChild, hWndChild ) )
+ return pObject;
+
+ pObject = pObject->mpNextObject;
+ }
+
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+WinSalFrame* ImplFindSalObjectFrame( HWND hWnd )
+{
+ WinSalFrame* pFrame = NULL;
+ WinSalObject* pObject = ImplFindSalObject( hWnd );
+ if ( pObject )
+ {
+ // Dazugehoerenden Frame suchen
+ HWND hWnd = ::GetParent( pObject->mhWnd );
+ pFrame = GetSalData()->mpFirstFrame;
+ while ( pFrame )
+ {
+ if ( pFrame->mhWnd == hWnd )
+ break;
+
+ pFrame = pFrame->mpNextFrame;
+ }
+ }
+
+ return pFrame;
+}
+
+// -----------------------------------------------------------------------
+
+LRESULT CALLBACK SalSysMsgProc( int nCode, WPARAM wParam, LPARAM lParam )
+{
+ // Used for Unicode and none Unicode
+ SalData* pSalData = GetSalData();
+
+ if ( (nCode >= 0) && lParam )
+ {
+ CWPSTRUCT* pData = (CWPSTRUCT*)lParam;
+ if ( (pData->message != WM_KEYDOWN) &&
+ (pData->message != WM_KEYUP) )
+ pSalData->mnSalObjWantKeyEvt = 0;
+
+ // Testen, ob wir Daten fuer ein SalObject-Fenster behandeln
+ // muessen
+ WinSalObject* pObject;
+ if ( pData->message == WM_SETFOCUS )
+ {
+ pObject = ImplFindSalObject( pData->hwnd );
+ if ( pObject )
+ {
+ pObject->mhLastFocusWnd = pData->hwnd;
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ pObject->CallCallback( SALOBJ_EVENT_GETFOCUS, 0 );
+ ImplSalYieldMutexRelease();
+ }
+ else
+ ImplPostMessage( pObject->mhWnd, SALOBJ_MSG_POSTFOCUS, 0, 0 );
+ }
+ }
+ else if ( pData->message == WM_KILLFOCUS )
+ {
+ pObject = ImplFindSalObject( pData->hwnd );
+ if ( pObject && !ImplFindSalObject( (HWND)pData->wParam ) )
+ {
+ // LoseFocus nur rufen, wenn wirklich kein ChildFenster
+ // den Focus bekommt
+ if ( !pData->wParam || !ImplFindSalObject( (HWND)pData->wParam ) )
+ {
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ pObject->CallCallback( SALOBJ_EVENT_LOSEFOCUS, 0 );
+ ImplSalYieldMutexRelease();
+ }
+ else
+ ImplPostMessage( pObject->mhWnd, SALOBJ_MSG_POSTFOCUS, 0, 0 );
+ }
+ else
+ pObject->mhLastFocusWnd = (HWND)pData->wParam;
+ }
+ }
+ }
+
+ return CallNextHookEx( pSalData->mhSalObjMsgHook, nCode, wParam, lParam );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplSalPreDispatchMsg( MSG* pMsg )
+{
+ // Used for Unicode and none Unicode
+ SalData* pSalData = GetSalData();
+ WinSalObject* pObject;
+
+ if ( (pMsg->message == WM_LBUTTONDOWN) ||
+ (pMsg->message == WM_RBUTTONDOWN) ||
+ (pMsg->message == WM_MBUTTONDOWN) )
+ {
+ ImplSalYieldMutexAcquireWithWait();
+ pObject = ImplFindSalObject( pMsg->hwnd );
+ if ( pObject && !pObject->IsMouseTransparent() )
+ ImplPostMessage( pObject->mhWnd, SALOBJ_MSG_TOTOP, 0, 0 );
+ ImplSalYieldMutexRelease();
+ }
+
+ if ( (pMsg->message == WM_KEYDOWN) ||
+ (pMsg->message == WM_KEYUP) )
+ {
+ // KeyEvents wollen wir nach Moeglichkeit auch abarbeiten,
+ // wenn das Control diese nicht selber auswertet
+ // SysKeys werden als WM_SYSCOMMAND verarbeitet
+ // Char-Events verarbeiten wir nicht, da wir nur
+ // Accelerator relevante Keys verarbeiten wollen
+ BOOL bWantedKeyCode = FALSE;
+ // A-Z, 0-9 nur in Verbindung mit Control-Taste
+ if ( ((pMsg->wParam >= 65) && (pMsg->wParam <= 90)) ||
+ ((pMsg->wParam >= 48) && (pMsg->wParam <= 57)) )
+ {
+ if ( GetKeyState( VK_CONTROL ) & 0x8000 )
+ bWantedKeyCode = TRUE;
+ }
+ else if ( ((pMsg->wParam >= VK_F1) && (pMsg->wParam <= VK_F24)) ||
+ ((pMsg->wParam >= VK_SPACE) && (pMsg->wParam <= VK_HELP)) ||
+ (pMsg->wParam == VK_BACK) || (pMsg->wParam == VK_TAB) ||
+ (pMsg->wParam == VK_CLEAR) || (pMsg->wParam == VK_RETURN) ||
+ (pMsg->wParam == VK_ESCAPE) )
+ bWantedKeyCode = TRUE;
+ if ( bWantedKeyCode )
+ {
+ ImplSalYieldMutexAcquireWithWait();
+ pObject = ImplFindSalObject( pMsg->hwnd );
+ if ( pObject )
+ pSalData->mnSalObjWantKeyEvt = pMsg->wParam;
+ ImplSalYieldMutexRelease();
+ }
+ }
+ // Hier WM_SYSCHAR abfangen, um mit Alt+Taste evtl. Menu zu aktivieren
+ else if ( pMsg->message == WM_SYSCHAR )
+ {
+ pSalData->mnSalObjWantKeyEvt = 0;
+
+ USHORT nKeyCode = LOWORD( pMsg->wParam );
+ // Nur 0-9 und A-Z
+ if ( ((nKeyCode >= 48) && (nKeyCode <= 57)) ||
+ ((nKeyCode >= 65) && (nKeyCode <= 90)) ||
+ ((nKeyCode >= 97) && (nKeyCode <= 122)) )
+ {
+ BOOL bRet = FALSE;
+ ImplSalYieldMutexAcquireWithWait();
+ pObject = ImplFindSalObject( pMsg->hwnd );
+ if ( pObject )
+ {
+ if ( pMsg->hwnd == ::GetFocus() )
+ {
+ WinSalFrame* pFrame = ImplFindSalObjectFrame( pMsg->hwnd );
+ if ( pFrame )
+ {
+ if ( ImplHandleSalObjSysCharMsg( pFrame->mhWnd, pMsg->wParam, pMsg->lParam ) )
+ bRet = TRUE;
+ }
+ }
+ }
+ ImplSalYieldMutexRelease();
+ if ( bRet )
+ return TRUE;
+ }
+ }
+ else
+ pSalData->mnSalObjWantKeyEvt = 0;
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplSalPostDispatchMsg( MSG* pMsg, LRESULT /* nDispatchResult */ )
+{
+ // Used for Unicode and none Unicode
+ SalData* pSalData = GetSalData();
+ WinSalFrame* pFrame;
+
+ if ( (pMsg->message == WM_KEYDOWN) || (pMsg->message == WM_KEYUP) )
+ {
+ if ( pSalData->mnSalObjWantKeyEvt == pMsg->wParam )
+ {
+ pSalData->mnSalObjWantKeyEvt = 0;
+ if ( pMsg->hwnd == ::GetFocus() )
+ {
+ ImplSalYieldMutexAcquireWithWait();
+ pFrame = ImplFindSalObjectFrame( pMsg->hwnd );
+ if ( pFrame )
+ ImplHandleSalObjKeyMsg( pFrame->mhWnd, pMsg->message, pMsg->wParam, pMsg->lParam );
+ ImplSalYieldMutexRelease();
+ }
+ }
+ }
+
+ pSalData->mnSalObjWantKeyEvt = 0;
+}
+
+// =======================================================================
+
+LRESULT CALLBACK SalSysObjWndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, int& rDef )
+{
+ WinSalObject* pSysObj;
+ LRESULT nRet = 0;
+
+ switch( nMsg )
+ {
+ case WM_ERASEBKGND:
+ nRet = 1;
+ rDef = FALSE;
+ break;
+ case WM_PAINT:
+ {
+ PAINTSTRUCT aPs;
+ BeginPaint( hWnd, &aPs );
+ EndPaint( hWnd, &aPs );
+ rDef = FALSE;
+ }
+ break;
+
+ case WM_PARENTNOTIFY:
+ {
+ UINT nNotifyMsg = LOWORD( wParam );
+ if ( (nNotifyMsg == WM_LBUTTONDOWN) ||
+ (nNotifyMsg == WM_RBUTTONDOWN) ||
+ (nNotifyMsg == WM_MBUTTONDOWN) )
+ {
+ ImplSalYieldMutexAcquireWithWait();
+ pSysObj = GetSalObjWindowPtr( hWnd );
+ if ( pSysObj && !pSysObj->IsMouseTransparent() )
+ pSysObj->CallCallback( SALOBJ_EVENT_TOTOP, 0 );
+ ImplSalYieldMutexRelease();
+ }
+ }
+ break;
+
+ case WM_MOUSEACTIVATE:
+ {
+ ImplSalYieldMutexAcquireWithWait();
+ pSysObj = GetSalObjWindowPtr( hWnd );
+ if ( pSysObj && !pSysObj->IsMouseTransparent() )
+ ImplPostMessage( hWnd, SALOBJ_MSG_TOTOP, 0, 0 );
+ ImplSalYieldMutexRelease();
+ }
+ break;
+
+ case SALOBJ_MSG_TOTOP:
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ pSysObj = GetSalObjWindowPtr( hWnd );
+ pSysObj->CallCallback( SALOBJ_EVENT_TOTOP, 0 );
+ ImplSalYieldMutexRelease();
+ rDef = FALSE;
+ }
+ else
+ ImplPostMessage( hWnd, SALOBJ_MSG_TOTOP, 0, 0 );
+ break;
+
+ case SALOBJ_MSG_POSTFOCUS:
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ pSysObj = GetSalObjWindowPtr( hWnd );
+ HWND hFocusWnd = ::GetFocus();
+ USHORT nEvent;
+ if ( hFocusWnd && ImplIsSysWindowOrChild( hWnd, hFocusWnd ) )
+ nEvent = SALOBJ_EVENT_GETFOCUS;
+ else
+ nEvent = SALOBJ_EVENT_LOSEFOCUS;
+ pSysObj->CallCallback( nEvent, 0 );
+ ImplSalYieldMutexRelease();
+ }
+ else
+ ImplPostMessage( hWnd, SALOBJ_MSG_POSTFOCUS, 0, 0 );
+ rDef = FALSE;
+ break;
+
+ case WM_SIZE:
+ {
+ HWND hWndChild = GetWindow( hWnd, GW_CHILD );
+ if ( hWndChild )
+ {
+ SetWindowPos( hWndChild,
+ 0, 0, 0, (int)LOWORD( lParam ), (int)HIWORD( lParam ),
+ SWP_NOZORDER | SWP_NOACTIVATE );
+ }
+ }
+ rDef = FALSE;
+ break;
+
+ case WM_CREATE:
+ {
+ // Window-Instanz am Windowhandle speichern
+ // Can also be used for the W-Version, because the struct
+ // to access lpCreateParams is the same structure
+ CREATESTRUCTA* pStruct = (CREATESTRUCTA*)lParam;
+ pSysObj = (WinSalObject*)pStruct->lpCreateParams;
+ SetSalObjWindowPtr( hWnd, pSysObj );
+ // HWND schon hier setzen, da schon auf den Instanzdaten
+ // gearbeitet werden kann, wenn Messages waehrend
+ // CreateWindow() gesendet werden
+ pSysObj->mhWnd = hWnd;
+ rDef = FALSE;
+ }
+ break;
+ }
+
+ return nRet;
+}
+
+LRESULT CALLBACK SalSysObjWndProcA( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
+{
+ int bDef = TRUE;
+ LRESULT nRet = SalSysObjWndProc( hWnd, nMsg, wParam, lParam, bDef );
+ if ( bDef )
+ nRet = DefWindowProcA( hWnd, nMsg, wParam, lParam );
+ return nRet;
+}
+
+LRESULT CALLBACK SalSysObjWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
+{
+ int bDef = TRUE;
+ LRESULT nRet = SalSysObjWndProc( hWnd, nMsg, wParam, lParam, bDef );
+ if ( bDef )
+ nRet = DefWindowProcW( hWnd, nMsg, wParam, lParam );
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+LRESULT CALLBACK SalSysObjChildWndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, int& rDef )
+{
+ LRESULT nRet = 0;
+
+ switch( nMsg )
+ {
+ // Wegen PlugIn's loeschen wir erstmal den Hintergrund
+ case WM_ERASEBKGND:
+ {
+ WinSalObject* pSysObj = GetSalObjWindowPtr( ::GetParent( hWnd ) );
+
+ if( pSysObj && !pSysObj->IsEraseBackgroundEnabled() )
+ {
+ // do not erase background
+ nRet = 1;
+ rDef = FALSE;
+ }
+ }
+ break;
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT aPs;
+ BeginPaint( hWnd, &aPs );
+ EndPaint( hWnd, &aPs );
+ rDef = FALSE;
+ }
+ break;
+
+ case WM_MOUSEMOVE:
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_LBUTTONUP:
+ case WM_MBUTTONUP:
+ case WM_RBUTTONUP:
+ {
+ WinSalObject* pSysObj;
+ pSysObj = GetSalObjWindowPtr( ::GetParent( hWnd ) );
+
+ if( pSysObj && pSysObj->IsMouseTransparent() )
+ {
+ // forward mouse events to parent frame
+ HWND hWndParent = ::GetParent( pSysObj->mhWnd );
+
+ // transform coordinates
+ POINT pt;
+ pt.x = (long) LOWORD( lParam );
+ pt.y = (long) HIWORD( lParam );
+ MapWindowPoints( hWnd, hWndParent, &pt, 1 );
+ lParam = MAKELPARAM( (WORD) pt.x, (WORD) pt.y );
+
+ nRet = ImplSendMessage( hWndParent, nMsg, wParam, lParam );
+ rDef = FALSE;
+ }
+ }
+ break;
+ }
+
+ return nRet;
+}
+
+LRESULT CALLBACK SalSysObjChildWndProcA( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
+{
+ int bDef = TRUE;
+ LRESULT nRet = SalSysObjChildWndProc( hWnd, nMsg, wParam, lParam, bDef );
+ if ( bDef )
+ nRet = DefWindowProcA( hWnd, nMsg, wParam, lParam );
+ return nRet;
+}
+
+LRESULT CALLBACK SalSysObjChildWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
+{
+ int bDef = TRUE;
+ LRESULT nRet = SalSysObjChildWndProc( hWnd, nMsg, wParam, lParam, bDef );
+ if ( bDef )
+ nRet = DefWindowProcW( hWnd, nMsg, wParam, lParam );
+ return nRet;
+}
+
+// =======================================================================
+
+SalObject* ImplSalCreateObject( WinSalInstance* pInst, WinSalFrame* pParent )
+{
+ SalData* pSalData = GetSalData();
+
+ // Hook installieren, wenn es das erste SalObject ist
+ if ( !pSalData->mpFirstObject )
+ {
+ if ( aSalShlData.mbWNT )
+ {
+ pSalData->mhSalObjMsgHook = SetWindowsHookExW( WH_CALLWNDPROC,
+ SalSysMsgProc,
+ pSalData->mhInst,
+ pSalData->mnAppThreadId );
+ }
+ else
+ {
+ pSalData->mhSalObjMsgHook = SetWindowsHookExA( WH_CALLWNDPROC,
+ SalSysMsgProc,
+ pSalData->mhInst,
+ pSalData->mnAppThreadId );
+ }
+ }
+
+ if ( !pSalData->mbObjClassInit )
+ {
+ // #95301# shockwave plugin has bug; expects ASCII functions to be used
+ if ( false )//aSalShlData.mbWNT )
+ {
+ WNDCLASSEXW aWndClassEx;
+ aWndClassEx.cbSize = sizeof( aWndClassEx );
+ aWndClassEx.style = 0;
+ aWndClassEx.lpfnWndProc = SalSysObjWndProcW;
+ aWndClassEx.cbClsExtra = 0;
+ aWndClassEx.cbWndExtra = SAL_OBJECT_WNDEXTRA;
+ aWndClassEx.hInstance = pSalData->mhInst;
+ aWndClassEx.hIcon = 0;
+ aWndClassEx.hIconSm = 0;
+ aWndClassEx.hCursor = LoadCursor( 0, IDC_ARROW );
+ aWndClassEx.hbrBackground = 0;
+ aWndClassEx.lpszMenuName = 0;
+ aWndClassEx.lpszClassName = SAL_OBJECT_CLASSNAMEW;
+ if ( RegisterClassExW( &aWndClassEx ) )
+ {
+ // Wegen PlugIn's loeschen wir erstmal den Hintergrund
+ aWndClassEx.cbWndExtra = 0;
+ aWndClassEx.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
+ aWndClassEx.lpfnWndProc = SalSysObjChildWndProcW;
+ aWndClassEx.lpszClassName = SAL_OBJECT_CHILDCLASSNAMEW;
+ if ( RegisterClassExW( &aWndClassEx ) )
+ pSalData->mbObjClassInit = TRUE;
+ }
+ }
+ else
+ {
+ WNDCLASSEXA aWndClassEx;
+ aWndClassEx.cbSize = sizeof( aWndClassEx );
+ aWndClassEx.style = 0;
+ aWndClassEx.lpfnWndProc = SalSysObjWndProcA;
+ aWndClassEx.cbClsExtra = 0;
+ aWndClassEx.cbWndExtra = SAL_OBJECT_WNDEXTRA;
+ aWndClassEx.hInstance = pSalData->mhInst;
+ aWndClassEx.hIcon = 0;
+ aWndClassEx.hIconSm = 0;
+ aWndClassEx.hCursor = LoadCursor( 0, IDC_ARROW );
+ aWndClassEx.hbrBackground = 0;
+ aWndClassEx.lpszMenuName = 0;
+ aWndClassEx.lpszClassName = SAL_OBJECT_CLASSNAMEA;
+ if ( RegisterClassExA( &aWndClassEx ) )
+ {
+ // Wegen PlugIn's loeschen wir erstmal den Hintergrund
+ aWndClassEx.cbWndExtra = 0;
+ aWndClassEx.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
+ aWndClassEx.lpfnWndProc = SalSysObjChildWndProcA;
+ aWndClassEx.lpszClassName = SAL_OBJECT_CHILDCLASSNAMEA;
+ if ( RegisterClassExA( &aWndClassEx ) )
+ pSalData->mbObjClassInit = TRUE;
+ }
+ }
+ }
+
+ if ( pSalData->mbObjClassInit )
+ {
+ WinSalObject* pObject = new WinSalObject;
+
+ // #135235# Clip siblings of this
+ // SystemChildWindow. Otherwise, DXCanvas (using a hidden
+ // SystemChildWindow) clobbers applets/plugins during
+ // animations .
+ HWND hWnd = CreateWindowExA( 0, SAL_OBJECT_CLASSNAMEA, "",
+ WS_CHILD | WS_CLIPSIBLINGS, 0, 0, 0, 0,
+ pParent->mhWnd, 0,
+ pInst->mhInst, (void*)pObject );
+
+ HWND hWndChild = 0;
+ if ( hWnd )
+ {
+ // #135235# Explicitely stack SystemChildWindows in
+ // the order they're created - since there's no notion
+ // of zorder.
+ SetWindowPos(hWnd,HWND_TOP,0,0,0,0,
+ SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOSIZE);
+ hWndChild = CreateWindowExA( 0, SAL_OBJECT_CHILDCLASSNAMEA, "",
+ WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE,
+ 0, 0, 0, 0,
+ hWnd, 0,
+ pInst->mhInst, NULL );
+ }
+
+ if ( !hWndChild )
+ {
+ delete pObject;
+ return NULL;
+ }
+
+ if ( hWnd )
+ {
+ pObject->mhWnd = hWnd;
+ pObject->mhWndChild = hWndChild;
+ pObject->maSysData.hWnd = hWndChild;
+ return pObject;
+ }
+ }
+
+ return NULL;
+}
+
+// =======================================================================
+
+WinSalObject::WinSalObject()
+{
+ SalData* pSalData = GetSalData();
+
+ mhWnd = 0;
+ mhWndChild = 0;
+ mhLastFocusWnd = 0;
+ maSysData.nSize = sizeof( SystemEnvData );
+ mpStdClipRgnData = NULL;
+
+ // Insert object in objectlist
+ mpNextObject = pSalData->mpFirstObject;
+ pSalData->mpFirstObject = this;
+}
+
+// -----------------------------------------------------------------------
+
+WinSalObject::~WinSalObject()
+{
+ SalData* pSalData = GetSalData();
+
+ // remove frame from framelist
+ if ( this == pSalData->mpFirstObject )
+ {
+ pSalData->mpFirstObject = mpNextObject;
+
+ // Wenn letztes SalObject, dann Hook wieder entfernen
+ if ( !pSalData->mpFirstObject )
+ UnhookWindowsHookEx( pSalData->mhSalObjMsgHook );
+ }
+ else
+ {
+ WinSalObject* pTempObject = pSalData->mpFirstObject;
+ while ( pTempObject->mpNextObject != this )
+ pTempObject = pTempObject->mpNextObject;
+
+ pTempObject->mpNextObject = mpNextObject;
+ }
+
+ // Cache-Daten zerstoeren
+ if ( mpStdClipRgnData )
+ delete mpStdClipRgnData;
+
+ HWND hWndParent = ::GetParent( mhWnd );
+
+ if ( mhWndChild )
+ DestroyWindow( mhWndChild );
+ if ( mhWnd )
+ DestroyWindow( mhWnd );
+
+ // Palette wieder zuruecksetzen, wenn kein externes Child-Fenster
+ // mehr vorhanden ist, da diese unsere Palette ueberschrieben haben
+ // koennen
+ if ( hWndParent &&
+ ::GetActiveWindow() == hWndParent &&
+ !GetWindow( hWndParent, GW_CHILD ) )
+ ImplSendMessage( hWndParent, SAL_MSG_FORCEPALETTE, 0, 0 );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalObject::ResetClipRegion()
+{
+ SetWindowRgn( mhWnd, 0, TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT WinSalObject::GetClipRegionType()
+{
+ return SAL_OBJECT_CLIP_INCLUDERECTS;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalObject::BeginSetClipRegion( ULONG nRectCount )
+{
+ ULONG nRectBufSize = sizeof(RECT)*nRectCount;
+ if ( nRectCount < SAL_CLIPRECT_COUNT )
+ {
+ if ( !mpStdClipRgnData )
+ mpStdClipRgnData = (RGNDATA*)new BYTE[sizeof(RGNDATA)-1+(SAL_CLIPRECT_COUNT*sizeof(RECT))];
+ mpClipRgnData = mpStdClipRgnData;
+ }
+ else
+ mpClipRgnData = (RGNDATA*)new BYTE[sizeof(RGNDATA)-1+nRectBufSize];
+ mpClipRgnData->rdh.dwSize = sizeof( RGNDATAHEADER );
+ mpClipRgnData->rdh.iType = RDH_RECTANGLES;
+ mpClipRgnData->rdh.nCount = nRectCount;
+ mpClipRgnData->rdh.nRgnSize = nRectBufSize;
+ SetRectEmpty( &(mpClipRgnData->rdh.rcBound) );
+ mpNextClipRect = (RECT*)(&(mpClipRgnData->Buffer));
+ mbFirstClipRect = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalObject::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
+{
+ RECT* pRect = mpNextClipRect;
+ RECT* pBoundRect = &(mpClipRgnData->rdh.rcBound);
+ long nRight = nX + nWidth;
+ long nBottom = nY + nHeight;
+
+ if ( mbFirstClipRect )
+ {
+ pBoundRect->left = nX;
+ pBoundRect->top = nY;
+ pBoundRect->right = nRight;
+ pBoundRect->bottom = nBottom;
+ mbFirstClipRect = FALSE;
+ }
+ else
+ {
+ if ( nX < pBoundRect->left )
+ pBoundRect->left = (int)nX;
+
+ if ( nY < pBoundRect->top )
+ pBoundRect->top = (int)nY;
+
+ if ( nRight > pBoundRect->right )
+ pBoundRect->right = (int)nRight;
+
+ if ( nBottom > pBoundRect->bottom )
+ pBoundRect->bottom = (int)nBottom;
+ }
+
+ pRect->left = (int)nX;
+ pRect->top = (int)nY;
+ pRect->right = (int)nRight;
+ pRect->bottom = (int)nBottom;
+ mpNextClipRect++;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalObject::EndSetClipRegion()
+{
+ HRGN hRegion;
+
+ // Aus den Region-Daten muessen wir jetzt eine ClipRegion erzeugen
+ if ( mpClipRgnData->rdh.nCount == 1 )
+ {
+ RECT* pRect = &(mpClipRgnData->rdh.rcBound);
+ hRegion = CreateRectRgn( pRect->left, pRect->top,
+ pRect->right, pRect->bottom );
+ }
+ else
+ {
+ ULONG nSize = mpClipRgnData->rdh.nRgnSize+sizeof(RGNDATAHEADER);
+ hRegion = ExtCreateRegion( NULL, nSize, mpClipRgnData );
+ if ( mpClipRgnData != mpStdClipRgnData )
+ delete [] (BYTE*)mpClipRgnData;
+ }
+
+ DBG_ASSERT( hRegion, "SalObject::EndSetClipRegion() - Can't create ClipRegion" );
+ SetWindowRgn( mhWnd, hRegion, TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalObject::SetPosSize( long nX, long nY, long nWidth, long nHeight )
+{
+ ULONG nStyle = 0;
+ BOOL bVisible = (GetWindowStyle( mhWnd ) & WS_VISIBLE) != 0;
+ if ( bVisible )
+ {
+ ShowWindow( mhWnd, SW_HIDE );
+ nStyle |= SWP_SHOWWINDOW;
+ }
+ SetWindowPos( mhWnd, 0,
+ (int)nX, (int)nY, (int)nWidth, (int)nHeight,
+ SWP_NOZORDER | SWP_NOACTIVATE | nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalObject::Show( BOOL bVisible )
+{
+ if ( bVisible )
+ ShowWindow( mhWnd, SW_SHOWNORMAL );
+ else
+ ShowWindow( mhWnd, SW_HIDE );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalObject::Enable( BOOL bEnable )
+{
+ EnableWindow( mhWnd, bEnable );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalObject::GrabFocus()
+{
+ if ( mhLastFocusWnd &&
+ IsWindow( mhLastFocusWnd ) &&
+ ImplIsSysWindowOrChild( mhWndChild, mhLastFocusWnd ) )
+ ::SetFocus( mhLastFocusWnd );
+ else
+ ::SetFocus( mhWndChild );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalObject::SetBackground()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalObject::SetBackground( SalColor )
+{
+}
+
+// -----------------------------------------------------------------------
+
+const SystemEnvData* WinSalObject::GetSystemData() const
+{
+ return &maSysData;
+}
diff --git a/vcl/workben/makefile.mk b/vcl/workben/makefile.mk
new file mode 100644
index 000000000000..67c0289cc24f
--- /dev/null
+++ b/vcl/workben/makefile.mk
@@ -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.
+#
+#*************************************************************************
+
+PRJ=..
+
+PRJNAME=vcl
+TARGET=svdem
+LIBTARGET=NO
+TARGETTYPE=GUI
+
+ENABLE_EXCEPTIONS=TRUE
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+
+# --- Files --------------------------------------------------------
+
+OBJFILES= \
+ $(OBJ)$/svdem.obj \
+ $(OBJ)$/vcldemo.obj \
+ $(OBJ)$/outdevgrind.obj
+
+# --- Targets ------------------------------------------------------
+
+# svdem
+
+APP1NOSAL= TRUE
+APP1TARGET= $(TARGET)
+APP1OBJS= \
+ $(OBJ)$/svdem.obj
+
+APP1STDLIBS= $(CPPULIB) \
+ $(UNOTOOLSLIB) \
+ $(CPPUHELPERLIB) \
+ $(COMPHELPERLIB) \
+ $(TOOLSLIB) \
+ $(SALLIB) \
+ $(VOSLIB) \
+ $(SOTLIB) \
+ $(VCLLIB)
+
+# outdevgrind
+
+APP2TARGET= outdevgrind
+APP2OBJS= \
+ $(OBJ)$/outdevgrind.obj $(OBJ)$/salmain.obj
+
+APP2NOSAL= TRUE
+APP2STDLIBS=$(TOOLSLIB) \
+ $(COMPHELPERLIB) \
+ $(CPPULIB) \
+ $(CPPUHELPERLIB) \
+ $(UCBHELPERLIB) \
+ $(SALLIB) \
+ $(VCLLIB)
+
+# vcldemo
+
+APP3NOSAL=TRUE
+APP3TARGET=vcldemo
+APP3OBJS= \
+ $(OBJ)$/vcldemo.obj
+
+APP3STDLIBS= $(CPPULIB) \
+ $(UNOTOOLSLIB) \
+ $(CPPUHELPERLIB) \
+ $(COMPHELPERLIB) \
+ $(TOOLSLIB) \
+ $(SALLIB) \
+ $(VOSLIB) \
+ $(SOTLIB) \
+ $(VCLLIB)
+
+
+# --- Targets ------------------------------------------------------
+.IF "$(GUIBASE)" == "unx"
+
+APP4NOSAL= TRUE
+APP4TARGET= svptest
+APP4OBJS= $(OBJ)$/svptest.obj
+
+APP4STDLIBS= $(CPPULIB) \
+ $(CPPUHELPERLIB) \
+ $(COMPHELPERLIB) \
+ $(VCLLIB) \
+ $(TOOLSLIB) \
+ $(SALLIB) \
+ $(VOSLIB) \
+ $(SOTLIB) \
+ $(VCLLIB)
+
+APP5NOSAL= TRUE
+APP5TARGET= svpclient
+APP5OBJS= $(OBJ)$/svpclient.obj
+
+APP5STDLIBS= $(CPPULIB) \
+ $(CPPUHELPERLIB) \
+ $(COMPHELPERLIB) \
+ $(UCBHELPERLIB) \
+ $(VCLLIB) \
+ $(TOOLSLIB) \
+ $(SALLIB) \
+ $(VOSLIB) \
+ $(SOTLIB) \
+ $(VCLLIB)
+
+.IF "$(OS)" == "SOLARIS"
+APP5STDLIBS+=-lsocket
+.ENDIF
+
+.ENDIF
+
+.INCLUDE : target.mk
+.IF "$(L10N_framework)"==""
+
+ALLTAR : $(BIN)$/applicat.rdb
+
+
+$(BIN)$/applicat.rdb : makefile.mk $(UNOUCRRDB)
+ rm -f $@
+ $(GNUCOPY) $(UNOUCRRDB) $@
+ cd $(BIN) && \
+ $(REGCOMP) -register -r applicat.rdb \
+ -c i18nsearch.uno$(DLLPOST) \
+ -c i18npool.uno$(DLLPOST)
+.ENDIF
diff --git a/vcl/workben/outdevgrind.cxx b/vcl/workben/outdevgrind.cxx
new file mode 100755
index 000000000000..9122a1addc0a
--- /dev/null
+++ b/vcl/workben/outdevgrind.cxx
@@ -0,0 +1,974 @@
+/*************************************************************************
+ *
+ * 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"
+
+// bootstrap stuff
+#include <rtl/bootstrap.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/regpathhelper.hxx>
+#include <cppuhelper/servicefactory.hxx>
+#include <cppuhelper/bootstrap.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/registry/XSimpleRegistry.hpp>
+
+#include <ucbhelper/contentbroker.hxx>
+#include <ucbhelper/configurationkeys.hxx>
+
+#include <vcl/svapp.hxx>
+#include <vcl/dialog.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/hatch.hxx>
+#include <vcl/bitmap.hxx>
+#include <vcl/wall.hxx>
+#include <vcl/image.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/metaact.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/gradient.hxx>
+#include <vcl/lineinfo.hxx>
+#include <tools/string.hxx>
+
+#include <osl/time.h>
+
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
+
+#include <stdio.h>
+#include <unistd.h>
+
+using namespace ::com::sun::star;
+
+
+namespace
+{
+
+class GrindApp : public Application
+{
+public:
+ virtual void Main();
+ virtual USHORT Exception( USHORT nError );
+};
+
+class TestWindow : public Dialog
+{
+ public:
+ TestWindow() : Dialog( (Window *) NULL )
+ {
+ SetText( rtl::OUString::createFromAscii( "OutDev grinding" ) );
+ SetSizePixel( Size( 1024, 1024 ) );
+ EnablePaint( true );
+ Show();
+ }
+
+ virtual ~TestWindow() {}
+ virtual void Paint( const Rectangle& rRect );
+};
+
+//----------------------------------------------------------------------------------
+
+typedef boost::function1<void, OutputDevice*> functor_type;
+typedef std::vector< std::pair<const char*,
+ functor_type> > functor_vector_type;
+
+template< typename Functor > void add( functor_vector_type& res,
+ const char* pStr,
+ const Functor& func )
+{
+ res.push_back( std::make_pair(pStr,functor_type(func)) );
+}
+
+void setupMethodStubs( functor_vector_type& res )
+{
+ const Color aWhiteColor( COL_WHITE );
+ const Color aBlackColor( COL_BLACK );
+
+ const Point aPt1(10,10);
+ const Point aPt2(500,500);
+ const Point aPt3(0,0);
+ const Point aPt4(450,450);
+
+ const Rectangle aRect(aPt1,aPt2);
+ const Rectangle aRect2(aPt3,aPt4);
+ const Polygon aPoly(aRect);
+ const Polygon aPoly2(aRect2);
+ PolyPolygon aPolyPoly(aPoly);
+ aPolyPoly.Insert( aPoly2 );
+ Polygon aPoly3(aPoly2);
+ aPoly3.Rotate( aPoly3.GetBoundRect().Center(),
+ 900 );
+
+ const String aString( ByteString("This is a test"),
+ RTL_TEXTENCODING_ASCII_US );
+ const LineInfo aLineInfo(LINE_SOLID,5);
+
+ // unfortunately, VDevs have inaccessible copy constructors
+ static VirtualDevice aVDev;
+ static VirtualDevice aVDevBW(1);
+
+ const Size aVDevSize;
+ aVDev.SetOutputSizePixel(aVDevSize);
+ aVDevBW.SetOutputSizePixel(aVDevSize);
+
+ const Bitmap aBitmap( aVDev.GetBitmap(aPt1,aVDevSize) );
+ const Bitmap aBitmapBW( aVDevBW.GetBitmap(aPt1,aVDevSize) );
+ const Bitmap aBitmapAlien( aVDevSize, 8 );
+
+ const BitmapEx aBitmapEx( aBitmap, aBitmapBW );
+ const BitmapEx aBitmapExBW( aBitmapBW, aBitmapBW );
+ const BitmapEx aBitmapExAlien( aBitmapAlien, aBitmapBW );
+ const BitmapEx aBitmapExAlpha( aBitmap, aBitmapAlien );
+ const BitmapEx aBitmapExAlphaAlien( aBitmapAlien, aBitmapAlien );
+
+ const Image aImage( aBitmapEx );
+ const Gradient aGradient(GRADIENT_ELLIPTICAL,aBlackColor,aWhiteColor);
+ const Hatch aHatch(HatchStyle_TRIPLE,aBlackColor,4,450);
+ const Wallpaper aWallpaper( aWhiteColor );
+
+ GDIMetaFile aMtf;
+ aMtf.AddAction( new MetaFillColorAction(Color(COL_RED),TRUE) );
+ aMtf.AddAction( new MetaRectAction(aRect) );
+
+ /* void DrawText( const Point& rStartPt, const XubString& rStr,
+ xub_StrLen nIndex = 0, xub_StrLen nLen = STRING_LEN,
+ MetricVector* pVector = NULL, String* pDisplayText = NULL );
+ */
+// add(res,
+// "DrawText",
+// boost::bind(
+// &OutputDevice::DrawText,
+// _1,
+// aPt1, aString, (USHORT)0, aString.Len(), (MetricVector*)0, (String*)0, (vcl::ITextLayout*)0 ));
+
+ /* void DrawTextArray( const Point& rStartPt, const XubString& rStr,
+ const sal_Int32* pDXAry = NULL,
+ xub_StrLen nIndex = 0,
+ xub_StrLen nLen = STRING_LEN );
+ */
+ add(res,
+ "DrawTextArray",
+ boost::bind(
+ &OutputDevice::DrawTextArray,
+ _1,
+ aPt1, aString, (const sal_Int32*)0, (USHORT)0, aString.Len() ));
+
+ /* void DrawPixel( const Point& rPt, const Color& rColor ); */
+ add(res,
+ "DrawPixel",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&, const Color& ))(
+ &OutputDevice::DrawPixel),
+ _1,
+ aPt1, aBlackColor ));
+
+ /* void DrawLine( const Point& rStartPt, const Point& rEndPt ); */
+ add(res,
+ "DrawLine",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&, const Point& ))(
+ &OutputDevice::DrawLine),
+ _1,
+ aPt1, aPt2 ));
+
+ /* void DrawLine( const Point& rStartPt, const Point& rEndPt,
+ const LineInfo& rLineInfo );
+ */
+ add(res,
+ "DrawLine(LineInfo)",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&, const Point&,const LineInfo& ))(
+ &OutputDevice::DrawLine),
+ _1,
+ aPt1, aPt2, aLineInfo ));
+
+ /* void DrawPolyLine( const Polygon& rPoly ); */
+ add(res,
+ "DrawPolyLine",
+ boost::bind(
+ (void (OutputDevice::*)( const Polygon& ))(
+ &OutputDevice::DrawPolyLine),
+ _1,
+ aPoly ));
+
+ /* void DrawPolyLine( const Polygon& rPoly,
+ const LineInfo& rLineInfo );
+ */
+ add(res,
+ "DrawPolyLine(LineInfo)",
+ boost::bind(
+ (void (OutputDevice::*)( const Polygon&, const LineInfo& ))(
+ &OutputDevice::DrawPolyLine),
+ _1,
+ aPoly, aLineInfo ));
+
+ /* void DrawPolygon( const Polygon& rPoly ); */
+ add(res,
+ "DrawPolygon",
+ boost::bind(
+ (void (OutputDevice::*)( const Polygon& ))
+ &OutputDevice::DrawPolygon,
+ _1,
+ aPoly ));
+
+ /* void DrawPolyPolygon( const PolyPolygon& rPolyPoly ); */
+ add(res,
+ "DrawPolyPolygon",
+ boost::bind(
+ (void (OutputDevice::*)( const PolyPolygon& ))
+ &OutputDevice::DrawPolyPolygon,
+ _1,
+ aPolyPoly ));
+
+ /* void DrawRect( const Rectangle& rRect ); */
+ add(res,
+ "DrawRect",
+ boost::bind(
+ (void (OutputDevice::*)( const Rectangle& ))(
+ &OutputDevice::DrawRect),
+ _1,
+ aRect ));
+
+ /* void DrawRect( const Rectangle& rRect,
+ ULONG nHorzRount, ULONG nVertRound );
+ */
+ add(res,
+ "DrawRect(round corners)",
+ boost::bind(
+ (void (OutputDevice::*)( const Rectangle&, ULONG nHorzRount, ULONG nVertRound ))(
+ &OutputDevice::DrawRect),
+ _1,
+ aRect2,
+ 4,4));
+
+ /* void DrawEllipse( const Rectangle& rRect ); */
+ add(res,
+ "DrawEllipse",
+ boost::bind(
+ &OutputDevice::DrawEllipse,
+ _1,
+ aRect ));
+
+ /* void DrawArc( const Rectangle& rRect,
+ const Point& rStartPt, const Point& rEndPt );
+ */
+ add(res,
+ "DrawArc",
+ boost::bind(
+ &OutputDevice::DrawArc,
+ _1,
+ aRect,aPt1,aPt2 ));
+
+ /* void DrawPie( const Rectangle& rRect,
+ const Point& rStartPt, const Point& rEndPt );
+ */
+ add(res,
+ "DrawPie",
+ boost::bind(
+ &OutputDevice::DrawPie,
+ _1,
+ aRect2,aPt3,aPt4 ));
+
+ /* void DrawChord( const Rectangle& rRect,
+ const Point& rStartPt, const Point& rEndPt );
+ */
+ add(res,
+ "DrawChord",
+ boost::bind(
+ &OutputDevice::DrawChord,
+ _1,
+ aRect2,aPt3,aPt4 ));
+
+ /* void DrawOutDev( const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPt, const Size& rSrcSize );
+ */
+ add(res,
+ "DrawOutDev",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&, const Size&,
+ const Point&, const Size& ))(
+ &OutputDevice::DrawOutDev),
+ _1,
+ aRect2.TopLeft(), aRect2.GetSize(),
+ aRect.TopLeft(), aRect.GetSize()));
+
+ /* void DrawOutDev( const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPt, const Size& rSrcSize,
+ const OutputDevice& rOutDev );
+ */
+ add(res,
+ "DrawOutDev(foreign source)",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&, const Size&,
+ const Point&, const Size&,
+ const OutputDevice& ))(
+ &OutputDevice::DrawOutDev),
+ _1,
+ aRect2.TopLeft(), aRect2.GetSize(),
+ aRect.TopLeft(), aRect.GetSize(),
+ boost::cref(aVDevBW) ));
+
+ /* void DrawOutDev( const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPt, const Size& rSrcSize,
+ const OutputDevice& rOutDev );
+ */
+ add(res,
+ "DrawOutDev(foreign source, scaled)",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&, const Size&,
+ const Point&, const Size&,
+ const OutputDevice& ))(
+ &OutputDevice::DrawOutDev),
+ _1,
+ aRect2.TopLeft(), aRect2.GetSize(),
+ aRect.TopLeft(), aRect.GetSize(),
+ boost::cref(aVDev) ));
+
+ /* void CopyArea( const Point& rDestPt,
+ const Point& rSrcPt, const Size& rSrcSize,
+ USHORT nFlags = 0 );
+ */
+ add(res,
+ "CopyArea",
+ boost::bind(
+ &OutputDevice::CopyArea,
+ _1,
+ aPt1,aPt3,aRect2.GetSize(),(USHORT)0 ));
+
+ /* void DrawBitmap( const Point& rDestPt,
+ const Bitmap& rBitmap );
+ */
+ add(res,
+ "DrawBitmap(alien source)",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&,
+ const Bitmap& ))(
+ &OutputDevice::DrawBitmap),
+ _1,
+ aPt1,aBitmapAlien ));
+
+ /* void DrawBitmap( const Point& rDestPt,
+ const Bitmap& rBitmap );
+ */
+ add(res,
+ "DrawBitmap",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&,
+ const Bitmap& ))(
+ &OutputDevice::DrawBitmap),
+ _1,
+ aPt1,aBitmap ));
+
+ /* void DrawBitmap( const Point& rDestPt, const Size& rDestSize,
+ const Bitmap& rBitmap );
+ */
+ add(res,
+ "DrawBitmap(scaled,alien source)",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&,
+ const Size&,
+ const Bitmap& ))(
+ &OutputDevice::DrawBitmap),
+ _1,
+ aPt1,aRect.GetSize(),aBitmapAlien ));
+
+ /* void DrawBitmap( const Point& rDestPt, const Size& rDestSize,
+ const Bitmap& rBitmap );
+ */
+ add(res,
+ "DrawBitmap(scaled)",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&,
+ const Size&,
+ const Bitmap& ))(
+ &OutputDevice::DrawBitmap),
+ _1,
+ aPt1,aRect.GetSize(),aBitmap ));
+
+ /* void DrawBitmap( const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPtPixel, const Size& rSrcSizePixel,
+ const Bitmap& rBitmap );
+ */
+ add(res,
+ "DrawBitmap(scaled subset,alien source)",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&,
+ const Size&,
+ const Point&,
+ const Size&,
+ const Bitmap& ))(
+ &OutputDevice::DrawBitmap),
+ _1,
+ aPt1,aRect.GetSize(),aPt3,aRect2.GetSize(),aBitmapAlien ));
+
+ /* void DrawBitmap( const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPtPixel, const Size& rSrcSizePixel,
+ const Bitmap& rBitmap );
+ */
+ add(res,
+ "DrawBitmap(scaled subset)",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&,
+ const Size&,
+ const Point&,
+ const Size&,
+ const Bitmap& ))(
+ &OutputDevice::DrawBitmap),
+ _1,
+ aPt1,aRect.GetSize(),aPt3,aRect2.GetSize(),aBitmap ));
+
+ /* void DrawBitmapEx( const Point& rDestPt,
+ const BitmapEx& rBitmapEx );
+ */
+ add(res,
+ "DrawBitmapEx(alien source)",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&,
+ const BitmapEx& ))(
+ &OutputDevice::DrawBitmapEx),
+ _1,
+ aPt1,aBitmapExAlien ));
+
+ /* void DrawBitmapEx( const Point& rDestPt,
+ const BitmapEx& rBitmapEx );
+ */
+ add(res,
+ "DrawBitmapEx",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&,
+ const BitmapEx& ))(
+ &OutputDevice::DrawBitmapEx),
+ _1,
+ aPt1,aBitmapEx ));
+
+ /* void DrawBitmapEx( const Point& rDestPt,
+ const BitmapEx& rBitmapEx );
+ */
+ add(res,
+ "DrawBitmapEx(alpha)",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&,
+ const BitmapEx& ))(
+ &OutputDevice::DrawBitmapEx),
+ _1,
+ aPt1,aBitmapExAlpha ));
+
+ /* void DrawBitmapEx( const Point& rDestPt,
+ const BitmapEx& rBitmapEx );
+ */
+ add(res,
+ "DrawBitmapEx(alpha, alien source)",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&,
+ const BitmapEx& ))(
+ &OutputDevice::DrawBitmapEx),
+ _1,
+ aPt1,aBitmapExAlphaAlien ));
+
+ /* void DrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
+ const BitmapEx& rBitmapEx );
+ */
+ add(res,
+ "DrawBitmapEx(scaled,alien source)",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&,
+ const Size&,
+ const BitmapEx& ))(
+ &OutputDevice::DrawBitmapEx),
+ _1,
+ aPt1,aRect.GetSize(),aBitmapExAlien ));
+
+ /* void DrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
+ const BitmapEx& rBitmapEx );
+ */
+ add(res,
+ "DrawBitmapEx(scaled)",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&,
+ const Size&,
+ const BitmapEx& ))(
+ &OutputDevice::DrawBitmapEx),
+ _1,
+ aPt1,aRect.GetSize(),aBitmapEx ));
+
+ /* void DrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
+ const BitmapEx& rBitmapEx );
+ */
+ add(res,
+ "DrawBitmapEx(scaled alpha)",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&,
+ const Size&,
+ const BitmapEx& ))(
+ &OutputDevice::DrawBitmapEx),
+ _1,
+ aPt1,aRect.GetSize(),aBitmapExAlpha ));
+
+ /* void DrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
+ const BitmapEx& rBitmapEx );
+ */
+ add(res,
+ "DrawBitmapEx(scaled alpha, alien source)",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&,
+ const Size&,
+ const BitmapEx& ))(
+ &OutputDevice::DrawBitmapEx),
+ _1,
+ aPt1,aRect.GetSize(),aBitmapExAlphaAlien ));
+
+ /* void DrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPtPixel, const Size& rSrcSizePixel,
+ const BitmapEx& rBitmapEx );
+ */
+ add(res,
+ "DrawBitmapEx(scaled subset,alien source)",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&,
+ const Size&,
+ const Point&,
+ const Size&,
+ const BitmapEx& ))(
+ &OutputDevice::DrawBitmapEx),
+ _1,
+ aPt1,aRect.GetSize(),aPt3,aRect2.GetSize(),aBitmapExAlien ));
+
+ /* void DrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPtPixel, const Size& rSrcSizePixel,
+ const BitmapEx& rBitmapEx );
+ */
+ add(res,
+ "DrawBitmapEx(scaled subset)",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&,
+ const Size&,
+ const Point&,
+ const Size&,
+ const BitmapEx& ))(
+ &OutputDevice::DrawBitmapEx),
+ _1,
+ aPt1,aRect.GetSize(),aPt3,aRect2.GetSize(),aBitmapEx ));
+
+ /* void DrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPtPixel, const Size& rSrcSizePixel,
+ const BitmapEx& rBitmapEx );
+ */
+ add(res,
+ "DrawBitmapEx(scaled subset, alpha)",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&,
+ const Size&,
+ const Point&,
+ const Size&,
+ const BitmapEx& ))(
+ &OutputDevice::DrawBitmapEx),
+ _1,
+ aPt1,aRect.GetSize(),aPt3,aRect2.GetSize(),aBitmapExAlpha ));
+
+ /* void DrawBitmapEx( const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPtPixel, const Size& rSrcSizePixel,
+ const BitmapEx& rBitmapEx );
+ */
+ add(res,
+ "DrawBitmapEx(scaled subset, alpha alien source)",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&,
+ const Size&,
+ const Point&,
+ const Size&,
+ const BitmapEx& ))(
+ &OutputDevice::DrawBitmapEx),
+ _1,
+ aPt1,aRect.GetSize(),aPt3,aRect2.GetSize(),aBitmapExAlphaAlien ));
+
+ /* void DrawMask( const Point& rDestPt,
+ const Bitmap& rBitmap, const Color& rMaskColor );
+ */
+ add(res,
+ "DrawMask(alien source)",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&,
+ const Bitmap&,
+ const Color& ))(
+ &OutputDevice::DrawMask),
+ _1,
+ aPt1,aBitmapAlien,aBlackColor ));
+
+ /* void DrawMask( const Point& rDestPt,
+ const Bitmap& rBitmap, const Color& rMaskColor );
+ */
+ add(res,
+ "DrawMask",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&,
+ const Bitmap&,
+ const Color& ))(
+ &OutputDevice::DrawMask),
+ _1,
+ aPt1,aBitmap,aBlackColor ));
+
+ /* void DrawMask( const Point& rDestPt, const Size& rDestSize,
+ const Bitmap& rBitmap, const Color& rMaskColor );
+ */
+ add(res,
+ "DrawMask(scaled,alien source)",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&,
+ const Size&,
+ const Bitmap&,
+ const Color& ))(
+ &OutputDevice::DrawMask),
+ _1,
+ aPt1,aRect.GetSize(),aBitmapAlien, aBlackColor ));
+
+ /* void DrawMask( const Point& rDestPt, const Size& rDestSize,
+ const Bitmap& rBitmap, const Color& rMaskColor );
+ */
+ add(res,
+ "DrawMask(scaled)",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&,
+ const Size&,
+ const Bitmap&,
+ const Color& ))(
+ &OutputDevice::DrawMask),
+ _1,
+ aPt1,aRect.GetSize(),aBitmap,aBlackColor ));
+
+ /* void DrawMask( const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPtPixel, const Size& rSrcSizePixel,
+ const Bitmap& rBitmap, const Color& rMaskColor );
+ */
+ add(res,
+ "DrawMask(scaled subset,alien source)",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&,
+ const Size&,
+ const Point&,
+ const Size&,
+ const Bitmap&,
+ const Color& ))(
+ &OutputDevice::DrawMask),
+ _1,
+ aPt1,aRect.GetSize(),aPt3,aRect2.GetSize(),aBitmapAlien,aBlackColor ));
+
+ /* void DrawMask( const Point& rDestPt, const Size& rDestSize,
+ const Point& rSrcPtPixel, const Size& rSrcSizePixel,
+ const Bitmap& rBitmap, const Color& rMaskColor );
+ */
+ add(res,
+ "DrawMask(scaled subset)",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&,
+ const Size&,
+ const Point&,
+ const Size&,
+ const Bitmap&,
+ const Color& ))(
+ &OutputDevice::DrawMask),
+ _1,
+ aPt1,aRect.GetSize(),aPt3,aRect2.GetSize(),aBitmap,aBlackColor ));
+
+ /* void DrawImage( const Point& rPos,
+ const Image& rImage, USHORT nStyle = 0 );
+ */
+ add(res,
+ "DrawImage",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&,
+ const Image&,
+ USHORT nStyle ))(
+ &OutputDevice::DrawImage),
+ _1,
+ aPt1,aImage,(USHORT)0 ));
+
+ /* void DrawImage( const Point& rPos, const Size& rSize,
+ const Image& rImage, USHORT nStyle = 0 );
+ */
+ add(res,
+ "DrawImage(scaled)",
+ boost::bind(
+ (void (OutputDevice::*)( const Point&,
+ const Size&,
+ const Image&,
+ USHORT nStyle ))(
+ &OutputDevice::DrawImage),
+ _1,
+ aPt1,aRect.GetSize(),aImage,(USHORT)0 ));
+
+ /* void DrawGradient( const Rectangle& rRect, const Gradient& rGradient ); */
+ add(res,
+ "DrawGradient",
+ boost::bind(
+ (void (OutputDevice::*)( const Rectangle&, const Gradient& ))(
+ &OutputDevice::DrawGradient),
+ _1,
+ aRect,aGradient ));
+
+ /* void DrawGradient( const PolyPolygon& rPolyPoly, const Gradient& rGradient ); */
+ add(res,
+ "DrawGradient(polygon)",
+ boost::bind(
+ (void (OutputDevice::*)( const PolyPolygon&, const Gradient& ))(
+ &OutputDevice::DrawGradient),
+ _1,
+ aPoly3,aGradient ));
+
+ /* void DrawHatch( const PolyPolygon& rPolyPoly, const Hatch& rHatch ); */
+ add(res,
+ "DrawHatch",
+ boost::bind(
+ &OutputDevice::DrawHatch,
+ _1,
+ aPoly3,aHatch ));
+
+ /* void DrawWallpaper( const Rectangle& rRect, const Wallpaper& rWallpaper ); */
+ add(res,
+ "DrawWallpaper",
+ boost::bind(
+ &OutputDevice::DrawWallpaper,
+ _1,
+ aRect2,aWallpaper ));
+
+ /* void DrawWaveLine( const Point& rStartPos, const Point& rEndPos, USHORT nStyle ); */
+ add(res,
+ "DrawWaveLine",
+ boost::bind(
+ &OutputDevice::DrawWaveLine,
+ _1,
+ aPt1,aPt2,(USHORT)WAVE_NORMAL ));
+
+ /* void DrawGrid( const Rectangle& rRect, const Size& rDist, ULONG nFlags ); */
+ add(res,
+ "DrawGrid",
+ boost::bind(
+ &OutputDevice::DrawGrid,
+ _1,
+ aRect,Size(10,20),GRID_HORZLINES|GRID_VERTLINES ));
+
+ /* void DrawTransparent( const PolyPolygon& rPolyPoly,
+ USHORT nTransparencePercent );
+ */
+ add(res,
+ "DrawTransparent",
+ boost::bind(
+ (void (OutputDevice::*)( const PolyPolygon&, USHORT ))(
+ &OutputDevice::DrawTransparent),
+ _1,
+ aPoly3,(USHORT)50 ));
+
+ /* void DrawTransparent( const GDIMetaFile& rMtf,
+ const Point& rPos, const Size& rSize,
+ const Gradient& rTransparenceGradient );
+ */
+ add(res,
+ "DrawTransparent(metafile)",
+ boost::bind(
+ (void (OutputDevice::*)( const GDIMetaFile&,
+ const Point&,
+ const Size&,
+ const Gradient& ))(
+ &OutputDevice::DrawTransparent),
+ _1,
+ aMtf,aPt1,aRect.GetSize(),aGradient ));
+
+ /* void Erase(); */
+ add(res,
+ "Erase",
+ boost::bind(
+ &OutputDevice::Erase,
+ _1 ));
+
+}
+
+//----------------------------------------------------------------------------------
+
+void grindFunc( OutputDevice& rTarget,
+ functor_vector_type::const_iterator iter,
+ sal_Int32 nTurns,
+ const char* pMsg )
+{
+ const sal_uInt32 nStartTime( osl_getGlobalTimer() );
+
+ for( sal_Int32 i=0; i<nTurns; ++i )
+ iter->second(&rTarget);
+
+ if( rTarget.GetOutDevType() == OUTDEV_WINDOW )
+ static_cast<Window&>(rTarget).Sync();
+
+ fprintf( stdout,
+ "Duration: %d ms (%d repetitions)\tOperation: %s\tSetup: %s\n",
+ (int)(osl_getGlobalTimer() - nStartTime),
+ (int)(nTurns),
+ iter->first,
+ pMsg );
+}
+
+//----------------------------------------------------------------------------------
+
+/** Call OutputDevice render methods repeatedly, and output elapsed
+ time to stdout
+ */
+void outDevGrind( OutputDevice& rTarget, sal_Int32 nTurns=100 )
+{
+ // TODO(F1): also profile pure complex clip setup times!
+
+ // State: fill/line color, draw mode, w/o clip, rect clip, complex clip
+ functor_vector_type aMethods;
+ setupMethodStubs( aMethods );
+
+ const Rectangle aClipRect(10,10,1000,1000);
+ const Polygon aPoly1( aClipRect );
+ Polygon aPoly2( aClipRect );
+ aPoly2.Rotate(aClipRect.Center(),450);
+ PolyPolygon aClipPoly(aPoly1);
+ aClipPoly.Insert(aPoly2);
+
+ functor_vector_type::const_iterator iter = aMethods.begin();
+ const functor_vector_type::const_iterator end = aMethods.end();
+ while( iter != end )
+ {
+ rTarget.SetLineColor( Color(COL_BLACK) );
+ rTarget.SetFillColor( Color(COL_GREEN) );
+ rTarget.SetRasterOp( ROP_OVERPAINT );
+ rTarget.SetClipRegion();
+ grindFunc( rTarget, iter, nTurns, "w/o clip, w/o xor" );
+
+ rTarget.SetLineColor( Color(COL_BLACK) );
+ rTarget.SetFillColor( Color(COL_GREEN) );
+ rTarget.SetRasterOp( ROP_OVERPAINT );
+ rTarget.SetClipRegion( aClipRect );
+ grindFunc( rTarget, iter, nTurns, "with rect clip, w/o xor" );
+
+ rTarget.SetLineColor( Color(COL_BLACK) );
+ rTarget.SetFillColor( Color(COL_GREEN) );
+ rTarget.SetRasterOp( ROP_OVERPAINT );
+ rTarget.SetClipRegion( aClipPoly );
+ grindFunc( rTarget, iter, nTurns, "with complex clip, w/o xor" );
+
+ rTarget.SetLineColor( Color(COL_BLACK) );
+ rTarget.SetFillColor( Color(COL_GREEN) );
+ rTarget.SetRasterOp( ROP_XOR );
+ rTarget.SetClipRegion();
+ grindFunc( rTarget, iter, nTurns, "w/o clip, with xor" );
+
+ rTarget.SetLineColor( Color(COL_BLACK) );
+ rTarget.SetFillColor( Color(COL_GREEN) );
+ rTarget.SetRasterOp( ROP_XOR );
+ rTarget.SetClipRegion( aClipRect );
+ grindFunc( rTarget, iter, nTurns, "with rect clip, with xor" );
+
+ rTarget.SetLineColor( Color(COL_BLACK) );
+ rTarget.SetFillColor( Color(COL_GREEN) );
+ rTarget.SetRasterOp( ROP_XOR );
+ rTarget.SetClipRegion( aClipPoly );
+ grindFunc( rTarget, iter, nTurns, "with complex clip, with xor" );
+
+ ++iter;
+ }
+}
+
+//----------------------------------------------------------------------------------
+
+void TestWindow::Paint( const Rectangle& )
+{
+ outDevGrind( *this );
+ fflush( stdout );
+}
+
+USHORT GrindApp::Exception( USHORT nError )
+{
+ switch( nError & EXC_MAJORTYPE )
+ {
+ case EXC_RSCNOTLOADED:
+ Abort( String::CreateFromAscii(
+ "Error: could not load language resources.\nPlease check your installation.\n" ) );
+ break;
+ }
+ return 0;
+}
+
+void GrindApp::Main()
+{
+ bool bHelp = false;
+
+ for( USHORT i = 0; i < GetCommandLineParamCount(); i++ )
+ {
+ ::rtl::OUString aParam = GetCommandLineParam( i );
+
+ if( aParam.equalsAscii( "--help" ) ||
+ aParam.equalsAscii( "-h" ) )
+ bHelp = true;
+ }
+
+ if( bHelp )
+ {
+ printf( "outdevgrind - Profile OutputDevice\n" );
+ return;
+ }
+
+ //-------------------------------------------------
+ // create the global service-manager
+ //-------------------------------------------------
+ uno::Reference< lang::XMultiServiceFactory > xFactory;
+ try
+ {
+ uno::Reference< uno::XComponentContext > xCtx = ::cppu::defaultBootstrap_InitialComponentContext();
+ xFactory = uno::Reference< lang::XMultiServiceFactory >( xCtx->getServiceManager(),
+ uno::UNO_QUERY );
+ if( xFactory.is() )
+ ::comphelper::setProcessServiceFactory( xFactory );
+ }
+ catch( uno::Exception& )
+ {
+ }
+
+ if( !xFactory.is() )
+ {
+ fprintf( stderr,
+ "Could not bootstrap UNO, installation must be in disorder. Exiting.\n" );
+ exit( 1 );
+ }
+
+ // Create UCB.
+ uno::Sequence< uno::Any > aArgs( 2 );
+ aArgs[ 0 ] <<= rtl::OUString::createFromAscii( UCB_CONFIGURATION_KEY1_LOCAL );
+ aArgs[ 1 ] <<= rtl::OUString::createFromAscii( UCB_CONFIGURATION_KEY2_OFFICE );
+ ::ucbhelper::ContentBroker::initialize( xFactory, aArgs );
+
+ TestWindow pWindow;
+ pWindow.Execute();
+
+ // clean up UCB
+ ::ucbhelper::ContentBroker::deinitialize();
+}
+
+} // namespace
+
+GrindApp aGrindApp;
diff --git a/vcl/workben/svdem.cxx b/vcl/workben/svdem.cxx
new file mode 100644
index 000000000000..5822f4024a59
--- /dev/null
+++ b/vcl/workben/svdem.cxx
@@ -0,0 +1,148 @@
+/*************************************************************************
+ *
+ * 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/main.h>
+#include <tools/extendapplicationenvironment.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+
+#include <vcl/event.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/wrkwin.hxx>
+#include <vcl/msgbox.hxx>
+
+#include <comphelper/processfactory.hxx>
+#include <cppuhelper/servicefactory.hxx>
+#include <cppuhelper/bootstrap.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+// -----------------------------------------------------------------------
+
+// Forward declaration
+void Main();
+
+// -----------------------------------------------------------------------
+
+SAL_IMPLEMENT_MAIN()
+{
+ tools::extendApplicationEnvironment();
+
+ Reference< XMultiServiceFactory > xMS;
+ xMS = cppu::createRegistryServiceFactory( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "applicat.rdb" ) ), sal_True );
+
+ InitVCL( xMS );
+ ::Main();
+ DeInitVCL();
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+class MyWin : public WorkWindow
+{
+public:
+ MyWin( Window* pParent, WinBits nWinStyle );
+
+ void MouseMove( const MouseEvent& rMEvt );
+ void MouseButtonDown( const MouseEvent& rMEvt );
+ void MouseButtonUp( const MouseEvent& rMEvt );
+ void KeyInput( const KeyEvent& rKEvt );
+ void KeyUp( const KeyEvent& rKEvt );
+ void Paint( const Rectangle& rRect );
+ void Resize();
+};
+
+// -----------------------------------------------------------------------
+
+void Main()
+{
+ MyWin aMainWin( NULL, WB_APP | WB_STDWORK );
+ aMainWin.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "VCL - Workbench" ) ) );
+ aMainWin.Show();
+
+ Application::Execute();
+}
+
+// -----------------------------------------------------------------------
+
+MyWin::MyWin( Window* pParent, WinBits nWinStyle ) :
+ WorkWindow( pParent, nWinStyle )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::MouseMove( const MouseEvent& rMEvt )
+{
+ WorkWindow::MouseMove( rMEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ WorkWindow::MouseButtonDown( rMEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ WorkWindow::MouseButtonUp( rMEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::KeyInput( const KeyEvent& rKEvt )
+{
+ WorkWindow::KeyInput( rKEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::KeyUp( const KeyEvent& rKEvt )
+{
+ WorkWindow::KeyUp( rKEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::Paint( const Rectangle& rRect )
+{
+ WorkWindow::Paint( rRect );
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::Resize()
+{
+ WorkWindow::Resize();
+}
diff --git a/vcl/workben/svpclient.cxx b/vcl/workben/svpclient.cxx
new file mode 100644
index 000000000000..61ed22ca95e7
--- /dev/null
+++ b/vcl/workben/svpclient.cxx
@@ -0,0 +1,346 @@
+/*************************************************************************
+ *
+ * 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 <sal/main.h>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/awt/ImageScaleMode.hpp>
+
+#include <vcl/event.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/wrkwin.hxx>
+#include <vcl/button.hxx>
+#include <vcl/lstbox.hxx>
+#include <vcl/imgctrl.hxx>
+#include <vcl/bitmapex.hxx>
+#include <tools/extendapplicationenvironment.hxx>
+#include <tools/stream.hxx>
+
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+
+#include <math.h>
+
+#include <comphelper/processfactory.hxx>
+#include <cppuhelper/servicefactory.hxx>
+#include <cppuhelper/bootstrap.hxx>
+#include "ucbhelper/contentbroker.hxx"
+#include "ucbhelper/configurationkeys.hxx"
+
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+
+using namespace rtl;
+using namespace cppu;
+using namespace comphelper;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+// -----------------------------------------------------------------------
+
+// Forward declaration
+void Main();
+
+// -----------------------------------------------------------------------
+
+SAL_IMPLEMENT_MAIN()
+{
+ tools::extendApplicationEnvironment();
+
+ //-------------------------------------------------
+ // create the global service-manager
+ //-------------------------------------------------
+ Reference< XMultiServiceFactory > xFactory;
+ try
+ {
+ Reference< XComponentContext > xCtx = defaultBootstrap_InitialComponentContext();
+ xFactory = Reference< XMultiServiceFactory >( xCtx->getServiceManager(), UNO_QUERY );
+ if( xFactory.is() )
+ setProcessServiceFactory( xFactory );
+ }
+ catch( com::sun::star::uno::Exception& rExc)
+ {
+ }
+
+ if( ! xFactory.is() )
+ {
+ fprintf( stderr, "Could not bootstrap UNO, installation must be in disorder. Exiting.\n" );
+ exit( 1 );
+ }
+
+ /*
+ * Create UCB.
+ */
+ Sequence< Any > aArgs( 2 );
+ aArgs[ 0 ] <<= OUString::createFromAscii( UCB_CONFIGURATION_KEY1_LOCAL );
+ aArgs[ 1 ] <<= OUString::createFromAscii( UCB_CONFIGURATION_KEY2_OFFICE );
+#if OSL_DEBUG_LEVEL > 1
+ sal_Bool bSuccess =
+#endif
+ ::ucbhelper::ContentBroker::initialize( xFactory, aArgs );
+
+#if OSL_DEBUG_LEVEL > 1
+ if ( !bSuccess )
+ {
+ fprintf( stderr, "Error creating UCB, installation must be in disorder. Exiting.\n" );
+ exit( 1 );
+ }
+#endif
+
+ InitVCL( xFactory );
+ ::Main();
+ DeInitVCL();
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+class MyWin : public WorkWindow
+{
+ PushButton m_aListButton;
+ ListBox m_aSvpBitmaps;
+ ImageControl m_aImage;
+ PushButton m_aQuitButton;
+public:
+ MyWin( Window* pParent, WinBits nWinStyle );
+
+ void MouseMove( const MouseEvent& rMEvt );
+ void MouseButtonDown( const MouseEvent& rMEvt );
+ void MouseButtonUp( const MouseEvent& rMEvt );
+ void KeyInput( const KeyEvent& rKEvt );
+ void KeyUp( const KeyEvent& rKEvt );
+ void Paint( const Rectangle& rRect );
+ void Resize();
+
+ BOOL Close();
+
+ void parseList( const rtl::OString& rList );
+ rtl::OString processCommand( const rtl::OString& rCommand );
+
+ DECL_LINK( ListHdl, Button* );
+ DECL_LINK( SelectHdl, ListBox* );
+ DECL_LINK( QuitHdl, Button* );
+};
+
+// -----------------------------------------------------------------------
+
+void Main()
+{
+ MyWin aMainWin( NULL, WB_STDWORK );
+ aMainWin.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "SvpClient" ) ) );
+ aMainWin.Show();
+
+ Application::Execute();
+}
+
+// -----------------------------------------------------------------------
+
+MyWin::MyWin( Window* pParent, WinBits nWinStyle ) :
+ WorkWindow( pParent, nWinStyle ),
+ m_aListButton( this, 0 ),
+ m_aSvpBitmaps( this, WB_BORDER ),
+ m_aImage( this, WB_BORDER ),
+ m_aQuitButton( this, 0 )
+{
+ m_aListButton.SetPosSizePixel( Point( 10, 10 ), Size( 120, 25 ) );
+ m_aListButton.SetText( String( RTL_CONSTASCII_USTRINGPARAM( "List Elements" ) ) );
+ m_aListButton.SetClickHdl( LINK( this, MyWin, ListHdl ) );
+ m_aListButton.Show();
+
+ m_aSvpBitmaps.SetPosSizePixel( Point( 10, 40 ), Size( 150, 150 ) );
+ m_aSvpBitmaps.SetSelectHdl( LINK( this, MyWin, SelectHdl ) );
+ m_aSvpBitmaps.Show();
+
+ m_aImage.SetPosSizePixel( Point( 170, 10 ), Size( 400, 400 ) );
+ m_aImage.SetScaleMode( com::sun::star::awt::ImageScaleMode::None );
+ m_aImage.Show();
+
+ m_aQuitButton.SetPosSizePixel( Point( 10, 300 ), Size( 120,25 ) );
+ m_aQuitButton.SetText( String( RTL_CONSTASCII_USTRINGPARAM( "Quit SVP server" ) ) );
+ m_aQuitButton.SetClickHdl( LINK( this, MyWin, QuitHdl ) );
+ m_aQuitButton.Show();
+}
+
+BOOL MyWin::Close()
+{
+ BOOL bRet = WorkWindow::Close();
+ if( bRet )
+ Application::Quit();
+ return bRet;
+}
+
+void MyWin::parseList( const rtl::OString& rList )
+{
+ sal_Int32 nTokenPos = 0;
+ rtl::OUString aElementType;
+ m_aSvpBitmaps.Clear();
+ while( nTokenPos >= 0 )
+ {
+ rtl::OString aLine = rList.getToken( 0, '\n', nTokenPos );
+ if( ! aLine.getLength() || *aLine.getStr() == '#' )
+ continue;
+
+ if( aLine.compareTo( "ElementType: ", 13 ) == 0 )
+ aElementType = rtl::OStringToOUString( aLine.copy( 13 ), RTL_TEXTENCODING_ASCII_US );
+ else
+ {
+ rtl::OUStringBuffer aNewElement( 64 );
+ aNewElement.append( aElementType );
+ aNewElement.appendAscii( ": " );
+ aNewElement.append( rtl::OStringToOUString( aLine, RTL_TEXTENCODING_ASCII_US ) );
+ m_aSvpBitmaps.InsertEntry( aNewElement.makeStringAndClear() );
+ }
+ }
+}
+
+rtl::OString MyWin::processCommand( const rtl::OString& rCommand )
+{
+ static const char* pEnv = getenv("SVP_LISTENER_PORT");
+ rtl::OStringBuffer aAnswer;
+ int nPort = (pEnv && *pEnv) ? atoi(pEnv) : 8000;
+ int nSocket = socket( PF_INET, SOCK_STREAM, 0 );
+ if( nSocket >= 0)
+ {
+ struct sockaddr_in addr;
+ memset(&addr, 0, sizeof(struct sockaddr_in));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(nPort);
+ addr.sin_addr.s_addr = INADDR_ANY;
+ if( connect( nSocket, (const sockaddr*)&addr, sizeof(addr) ) )
+ {
+ perror( "SvpElementContainer: connect() failed" );
+ close(nSocket);
+ }
+ else
+ {
+ write( nSocket, rCommand.getStr(), rCommand.getLength() );
+ write( nSocket, "\n", 1 );
+ char buf[256];
+ ssize_t nBytes = 0;
+ do
+ {
+ nBytes = read( nSocket, buf, sizeof(buf) );
+ aAnswer.append( buf, nBytes );
+ } while( nBytes == sizeof( buf ) );
+ }
+ }
+ else
+ perror( "SvpElementContainer: socket() failed\n" );
+ return aAnswer.makeStringAndClear();
+}
+
+IMPL_LINK( MyWin, ListHdl, Button*, )
+{
+ parseList( processCommand( "list" ) );
+ return 0;
+}
+
+IMPL_LINK( MyWin, QuitHdl, Button*, )
+{
+ processCommand( "quit" );
+ return 0;
+}
+
+IMPL_LINK( MyWin, SelectHdl, ListBox*, )
+{
+ String aEntry = m_aSvpBitmaps.GetSelectEntry();
+ USHORT nPos = aEntry.SearchAscii( ": " );
+ if( nPos != STRING_NOTFOUND )
+ {
+ OStringBuffer aCommand( 64 );
+ aCommand.append( "get " );
+ aCommand.append( rtl::OUStringToOString( aEntry.Copy( nPos+2 ), RTL_TEXTENCODING_ASCII_US ) );
+ OString aAnswer( processCommand( aCommand.makeStringAndClear() ) );
+ SvMemoryStream aStream( aAnswer.getLength() );
+ aStream.Write( aAnswer.getStr(), aAnswer.getLength() );
+ aStream.Seek( STREAM_SEEK_TO_BEGIN );
+ Bitmap aBitmap;
+ aStream >> aBitmap;
+ fprintf( stderr, "got bitmap of size %ldx%ld\n",
+ sal::static_int_cast< long >(aBitmap.GetSizePixel().Width()),
+ sal::static_int_cast< long >(aBitmap.GetSizePixel().Height()));
+ Size aFixedSize( aBitmap.GetSizePixel() );
+ aFixedSize.Width() += 10;
+ aFixedSize.Height() += 10;
+ m_aImage.SetSizePixel( aFixedSize );
+ m_aImage.SetBitmap( BitmapEx( aBitmap ) );
+ }
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::MouseMove( const MouseEvent& rMEvt )
+{
+ WorkWindow::MouseMove( rMEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ WorkWindow::MouseButtonDown( rMEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ WorkWindow::MouseButtonUp( rMEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::KeyInput( const KeyEvent& rKEvt )
+{
+ WorkWindow::KeyInput( rKEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::KeyUp( const KeyEvent& rKEvt )
+{
+ WorkWindow::KeyUp( rKEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::Paint( const Rectangle& rRect )
+{
+ WorkWindow::Paint( rRect );
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::Resize()
+{
+ WorkWindow::Resize();
+}
diff --git a/vcl/workben/svptest.cxx b/vcl/workben/svptest.cxx
new file mode 100644
index 000000000000..cc7c0f2b0cce
--- /dev/null
+++ b/vcl/workben/svptest.cxx
@@ -0,0 +1,379 @@
+/*************************************************************************
+ *
+ * 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 <sal/main.h>
+#include <tools/extendapplicationenvironment.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+
+#include <vcl/event.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/wrkwin.hxx>
+#include <vcl/gradient.hxx>
+#include <vcl/lineinfo.hxx>
+#include <vcl/bitmap.hxx>
+#include <vcl/bmpacc.hxx>
+#include <vcl/metric.hxx>
+
+#include <rtl/ustrbuf.hxx>
+
+#include <math.h>
+
+#include <comphelper/processfactory.hxx>
+#include <cppuhelper/servicefactory.hxx>
+#include <cppuhelper/bootstrap.hxx>
+
+using namespace rtl;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+// -----------------------------------------------------------------------
+
+// Forward declaration
+void Main();
+
+// -----------------------------------------------------------------------
+
+SAL_IMPLEMENT_MAIN()
+{
+ tools::extendApplicationEnvironment();
+
+ Reference< XMultiServiceFactory > xMS;
+ xMS = cppu::createRegistryServiceFactory( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "applicat.rdb" ) ), sal_True );
+
+ InitVCL( xMS );
+ ::Main();
+ DeInitVCL();
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+class MyWin : public WorkWindow
+{
+ Bitmap m_aBitmap;
+public:
+ MyWin( Window* pParent, WinBits nWinStyle );
+
+ void MouseMove( const MouseEvent& rMEvt );
+ void MouseButtonDown( const MouseEvent& rMEvt );
+ void MouseButtonUp( const MouseEvent& rMEvt );
+ void KeyInput( const KeyEvent& rKEvt );
+ void KeyUp( const KeyEvent& rKEvt );
+ void Paint( const Rectangle& rRect );
+ void Resize();
+};
+
+// -----------------------------------------------------------------------
+
+void Main()
+{
+ MyWin aMainWin( NULL, WB_APP | WB_STDWORK );
+ aMainWin.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "VCL - Workbench" ) ) );
+ aMainWin.Show();
+
+ Application::Execute();
+}
+
+// -----------------------------------------------------------------------
+
+MyWin::MyWin( Window* pParent, WinBits nWinStyle ) :
+ WorkWindow( pParent, nWinStyle ),
+ m_aBitmap( Size( 256, 256 ), 32 )
+{
+ // prepare an alpha mask
+ BitmapWriteAccess* pAcc = m_aBitmap.AcquireWriteAccess();
+ for( int nX = 0; nX < 256; nX++ )
+ {
+ for( int nY = 0; nY < 256; nY++ )
+ {
+ double fRed = 255.0-1.5*sqrt((double)(nX*nX+nY*nY));
+ if( fRed < 0.0 )
+ fRed = 0.0;
+ double fGreen = 255.0-1.5*sqrt((double)(((255-nX)*(255-nX)+nY*nY)));
+ if( fGreen < 0.0 )
+ fGreen = 0.0;
+ double fBlue = 255.0-1.5*sqrt((double)((128-nX)*(128-nX)+(255-nY)*(255-nY)));
+ if( fBlue < 0.0 )
+ fBlue = 0.0;
+ pAcc->SetPixel( nX, nY, BitmapColor( sal_uInt8(fRed), sal_uInt8(fGreen), sal_uInt8(fBlue) ) );
+ }
+ }
+ m_aBitmap.ReleaseAccess( pAcc );
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::MouseMove( const MouseEvent& rMEvt )
+{
+ WorkWindow::MouseMove( rMEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ WorkWindow::MouseButtonDown( rMEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ WorkWindow::MouseButtonUp( rMEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::KeyInput( const KeyEvent& rKEvt )
+{
+ WorkWindow::KeyInput( rKEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::KeyUp( const KeyEvent& rKEvt )
+{
+ WorkWindow::KeyUp( rKEvt );
+}
+
+// -----------------------------------------------------------------------
+
+static Point project( const Point& rPoint )
+{
+ const double angle_x = M_PI / 6.0;
+ const double angle_z = M_PI / 6.0;
+
+ // transform planar coordinates to 3d
+ double x = rPoint.X();
+ double y = rPoint.Y();
+ //double z = 0;
+
+ // rotate around X axis
+ double x1 = x;
+ double y1 = y * cos( angle_x );
+ double z1 = y * sin( angle_x );
+
+ // rotate around Z axis
+ double x2 = x1 * cos( angle_z ) + y1 * sin( angle_z );
+ //double y2 = y1 * cos( angle_z ) - x1 * sin( angle_z );
+ double z2 = z1;
+
+ return Point( (sal_Int32)x2, (sal_Int32)z2 );
+}
+
+static Color approachColor( const Color& rFrom, const Color& rTo )
+{
+ Color aColor;
+ UINT8 nDiff;
+ // approach red
+ if( rFrom.GetRed() < rTo.GetRed() )
+ {
+ nDiff = rTo.GetRed() - rFrom.GetRed();
+ aColor.SetRed( rFrom.GetRed() + ( nDiff < 10 ? nDiff : 10 ) );
+ }
+ else if( rFrom.GetRed() > rTo.GetRed() )
+ {
+ nDiff = rFrom.GetRed() - rTo.GetRed();
+ aColor.SetRed( rFrom.GetRed() - ( nDiff < 10 ? nDiff : 10 ) );
+ }
+ else
+ aColor.SetRed( rFrom.GetRed() );
+
+ // approach Green
+ if( rFrom.GetGreen() < rTo.GetGreen() )
+ {
+ nDiff = rTo.GetGreen() - rFrom.GetGreen();
+ aColor.SetGreen( rFrom.GetGreen() + ( nDiff < 10 ? nDiff : 10 ) );
+ }
+ else if( rFrom.GetGreen() > rTo.GetGreen() )
+ {
+ nDiff = rFrom.GetGreen() - rTo.GetGreen();
+ aColor.SetGreen( rFrom.GetGreen() - ( nDiff < 10 ? nDiff : 10 ) );
+ }
+ else
+ aColor.SetGreen( rFrom.GetGreen() );
+
+ // approach blue
+ if( rFrom.GetBlue() < rTo.GetBlue() )
+ {
+ nDiff = rTo.GetBlue() - rFrom.GetBlue();
+ aColor.SetBlue( rFrom.GetBlue() + ( nDiff < 10 ? nDiff : 10 ) );
+ }
+ else if( rFrom.GetBlue() > rTo.GetBlue() )
+ {
+ nDiff = rFrom.GetBlue() - rTo.GetBlue();
+ aColor.SetBlue( rFrom.GetBlue() - ( nDiff < 10 ? nDiff : 10 ) );
+ }
+ else
+ aColor.SetBlue( rFrom.GetBlue() );
+
+ return aColor;
+}
+
+#define DELTA 5.0
+void MyWin::Paint( const Rectangle& rRect )
+{
+ WorkWindow::Paint( rRect );
+
+ Push( PUSH_ALL );
+ MapMode aMapMode( MAP_100TH_MM );
+
+ SetMapMode( aMapMode );
+
+ Size aPaperSize = GetOutputSize();
+ Point aCenter( aPaperSize.Width()/2-300,
+ (aPaperSize.Height() - 8400)/2 + 8400 );
+ Point aP1( aPaperSize.Width()/48, 0), aP2( aPaperSize.Width()/40, 0 ), aPoint;
+
+ DrawRect( Rectangle( Point( 0,0 ), aPaperSize ) );
+ DrawRect( Rectangle( Point( 100,100 ),
+ Size( aPaperSize.Width()-200,
+ aPaperSize.Height()-200 ) ) );
+ DrawRect( Rectangle( Point( 200,200 ),
+ Size( aPaperSize.Width()-400,
+ aPaperSize.Height()-400 ) ) );
+ DrawRect( Rectangle( Point( 300,300 ),
+ Size( aPaperSize.Width()-600,
+ aPaperSize.Height()-600 ) ) );
+
+ // AllSettings aSettings( Application::GetSettings() );
+
+ const int nFontCount = GetDevFontCount();
+ const int nFontSamples = (nFontCount<15) ? nFontCount : 15;
+ for( int i = 0; i < nFontSamples; ++i )
+ {
+#if 0
+ Font aFont( GetFont() );
+ aFont.SetName( String( RTL_CONSTASCII_USTRINGPARAM( "Courier" ) ) );
+ aFont.SetWeight( WEIGHT_NORMAL );
+ aFont.SetItalic( ITALIC_NONE );
+#else
+ FontInfo aFont = GetDevFont( (i*nFontCount) / nFontSamples );
+ aFont.SetHeight( 400 + (i%7) * 100 );
+ aFont.SetOrientation( i * (3600 / nFontSamples) );
+#endif
+ SetFont( aFont );
+
+ sal_uInt8 nRed = (i << 6) & 0xC0;
+ sal_uInt8 nGreen = (i << 4) & 0xC0;
+ sal_uInt8 nBlue = (i << 2) & 0xC0;
+ SetTextColor( Color( nRed, nGreen, nBlue ) );
+
+ OUStringBuffer aPrintText(1024);
+ long nMaxWidth = 0;
+
+ aPrintText.appendAscii( "SVP test program" );
+
+ DrawText( Rectangle( Point( (aPaperSize.Width() - 4000) / 2, 2000 ),
+ Size( aPaperSize.Width() - 2100 - nMaxWidth,
+ aPaperSize.Height() - 4000 ) ),
+ aPrintText.makeStringAndClear(),
+ TEXT_DRAW_MULTILINE );
+ }
+
+ SetFillColor();
+ DrawRect( Rectangle( Point( aPaperSize.Width() - 4000, 1000 ),
+ Size( 3000,3000 ) ) );
+ DrawBitmap( Point( aPaperSize.Width() - 4000, 1000 ),
+ Size( 3000,3000 ),
+ m_aBitmap );
+
+ Color aWhite( 0xff, 0xff, 0xff );
+ Color aBlack( 0, 0, 0 );
+ Color aLightRed( 0xff, 0, 0 );
+ Color aDarkRed( 0x40, 0, 0 );
+ Color aLightBlue( 0, 0, 0xff );
+ Color aDarkBlue( 0,0,0x40 );
+ Color aLightGreen( 0, 0xff, 0 );
+ Color aDarkGreen( 0, 0x40, 0 );
+
+ Gradient aGradient( GRADIENT_LINEAR, aBlack, aWhite );
+ aGradient.SetAngle( 900 );
+ DrawGradient( Rectangle( Point( 1000, 4500 ),
+ Size( aPaperSize.Width() - 2000,
+ 500 ) ), aGradient );
+ aGradient.SetStartColor( aDarkRed );
+ aGradient.SetEndColor( aLightBlue );
+ DrawGradient( Rectangle( Point( 1000, 5300 ),
+ Size( aPaperSize.Width() - 2000,
+ 500 ) ), aGradient );
+ aGradient.SetStartColor( aDarkBlue );
+ aGradient.SetEndColor( aLightGreen );
+ DrawGradient( Rectangle( Point( 1000, 6100 ),
+ Size( aPaperSize.Width() - 2000,
+ 500 ) ), aGradient );
+ aGradient.SetStartColor( aDarkGreen );
+ aGradient.SetEndColor( aLightRed );
+ DrawGradient( Rectangle( Point( 1000, 6900 ),
+ Size( aPaperSize.Width() - 2000,
+ 500 ) ), aGradient );
+
+
+
+ LineInfo aLineInfo( LINE_SOLID, 200 );
+ double sind = sin( DELTA*M_PI/180.0 );
+ double cosd = cos( DELTA*M_PI/180.0 );
+ double factor = 1 + (DELTA/1000.0);
+ int n=0;
+ Color aLineColor( 0, 0, 0 );
+ Color aApproachColor( 0, 0, 200 );
+ while ( aP2.X() < aCenter.X() && n++ < 680 )
+ {
+ aLineInfo.SetWidth( n/3 );
+ aLineColor = approachColor( aLineColor, aApproachColor );
+ SetLineColor( aLineColor );
+
+ // switch aproach color
+ if( aApproachColor.IsRGBEqual( aLineColor ) )
+ {
+ if( aApproachColor.GetRed() )
+ aApproachColor = Color( 0, 0, 200 );
+ else if( aApproachColor.GetGreen() )
+ aApproachColor = Color( 200, 0, 0 );
+ else
+ aApproachColor = Color( 0, 200, 0 );
+ }
+
+ DrawLine( project( aP1 ) + aCenter,
+ project( aP2 ) + aCenter,
+ aLineInfo );
+ aPoint.X() = (int)((((double)aP1.X())*cosd - ((double)aP1.Y())*sind)*factor);
+ aPoint.Y() = (int)((((double)aP1.Y())*cosd + ((double)aP1.X())*sind)*factor);
+ aP1 = aPoint;
+ aPoint.X() = (int)((((double)aP2.X())*cosd - ((double)aP2.Y())*sind)*factor);
+ aPoint.Y() = (int)((((double)aP2.Y())*cosd + ((double)aP2.X())*sind)*factor);
+ aP2 = aPoint;
+ }
+ Pop();
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::Resize()
+{
+ WorkWindow::Resize();
+}
diff --git a/vcl/workben/vcldemo.cxx b/vcl/workben/vcldemo.cxx
new file mode 100644
index 000000000000..41ca76144e5c
--- /dev/null
+++ b/vcl/workben/vcldemo.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 <sal/main.h>
+#include <tools/extendapplicationenvironment.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+
+#include <vcl/event.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/wrkwin.hxx>
+#include <vcl/msgbox.hxx>
+#include <vcl/introwin.hxx>
+#include <vcl/msgbox.hxx>
+
+#include <comphelper/processfactory.hxx>
+#include <cppuhelper/servicefactory.hxx>
+#include <cppuhelper/bootstrap.hxx>
+
+#include <unistd.h>
+#include <stdio.h>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+// -----------------------------------------------------------------------
+
+// Forward declaration
+void Main();
+
+// -----------------------------------------------------------------------
+
+SAL_IMPLEMENT_MAIN()
+{
+ tools::extendApplicationEnvironment();
+
+ Reference< XMultiServiceFactory > xMS;
+ xMS = cppu::createRegistryServiceFactory( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "applicat.rdb" ) ), sal_True );
+
+ InitVCL( xMS );
+ ::Main();
+ DeInitVCL();
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+class MyWin : public WorkWindow
+{
+public:
+ MyWin( Window* pParent, WinBits nWinStyle );
+
+ void MouseMove( const MouseEvent& rMEvt );
+ void MouseButtonDown( const MouseEvent& rMEvt );
+ void MouseButtonUp( const MouseEvent& rMEvt );
+ void KeyInput( const KeyEvent& rKEvt );
+ void KeyUp( const KeyEvent& rKEvt );
+ void Paint( const Rectangle& rRect );
+ void Resize();
+};
+
+// -----------------------------------------------------------------------
+
+void Main()
+{
+ /*
+ IntroWindow splash;
+ splash.Show();
+ sleep(5);
+ splash.Hide();
+ */
+
+ MyWin aMainWin( NULL, WB_APP | WB_STDWORK );
+ aMainWin.SetText( XubString( RTL_CONSTASCII_USTRINGPARAM( "VCLDemo - VCL Workbench" ) ) );
+ aMainWin.Show();
+
+ /*
+ InfoBox ib(NULL, String((sal_Char*)"Test", sizeof("Test")));
+ ib.Execute();
+ */
+
+ Application::Execute();
+}
+
+// -----------------------------------------------------------------------
+
+MyWin::MyWin( Window* pParent, WinBits nWinStyle ) :
+ WorkWindow( pParent, nWinStyle )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::MouseMove( const MouseEvent& rMEvt )
+{
+ WorkWindow::MouseMove( rMEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ Rectangle aRect(0,0,4,4);
+ aRect.SetPos( rMEvt.GetPosPixel() );
+ SetFillColor(Color(COL_RED));
+ DrawRect( aRect );
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ WorkWindow::MouseButtonUp( rMEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::KeyInput( const KeyEvent& rKEvt )
+{
+ WorkWindow::KeyInput( rKEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::KeyUp( const KeyEvent& rKEvt )
+{
+ WorkWindow::KeyUp( rKEvt );
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::Paint( const Rectangle& rRect )
+{
+ fprintf(stderr, "MyWin::Paint(%ld,%ld,%ld,%ld)\n", rRect.getX(), rRect.getY(), rRect.getWidth(), rRect.getHeight());
+
+ Size aSz(GetSizePixel());
+ Point aPt;
+ Rectangle r(aPt, aSz);
+
+ SetFillColor(Color(COL_BLUE));
+ SetLineColor(Color(COL_YELLOW));
+
+ DrawRect( r );
+
+ for(int i=0; i<aSz.Height(); i+=15)
+ DrawLine( Point(r.nLeft, r.nTop+i), Point(r.nRight, r.nBottom-i) );
+ for(int i=0; i<aSz.Width(); i+=15)
+ DrawLine( Point(r.nLeft+i, r.nBottom), Point(r.nRight-i, r.nTop) );
+
+ SetTextColor( Color( COL_WHITE ) );
+ Font aFont( String( RTL_CONSTASCII_USTRINGPARAM( "Times" ) ), Size( 0, 25 ) );
+ SetFont( aFont );
+ DrawText( Point( 20, 30 ), String( RTL_CONSTASCII_USTRINGPARAM( "Just a simple test text" ) ) );
+}
+
+// -----------------------------------------------------------------------
+
+void MyWin::Resize()
+{
+ WorkWindow::Resize();
+}